# Path: h11/_util.py
# class LocalProtocolError(ProtocolError):
#     def _reraise_as_remote_protocol_error(self) -> NoReturn:
#         # After catching a LocalProtocolError, use this method to re-raise it
#         # as a RemoteProtocolError. This method must be called from inside an
#         # except: block.
#         #
#         # An easy way to get an equivalent RemoteProtocolError is just to
#         # modify 'self' in place.
#         self.__class__ = RemoteProtocolError  # type: ignore
#         # But the re-raising is somewhat non-trivial -- you might think that
#         # now that we've modified the in-flight exception object, that just
#         # doing 'raise' to re-raise it would be enough. But it turns out that
#         # this doesn't work, because Python tracks the exception type
#         # (exc_info[0]) separately from the exception object (exc_info[1]),
#         # and we only modified the latter. So we really do need to re-raise
#         # the new type explicitly.
#         # On py3, the traceback is part of the exception object, so our
#         # in-place modification preserved it and we can just re-raise:
#         raise self
# 
# class Sentinel(type):
#     def __new__(
#         cls: Type[_T_Sentinel],
#         name: str,
#         bases: Tuple[type, ...],
#         namespace: Dict[str, Any],
#         **kwds: Any
#     ) -> _T_Sentinel:
#         assert bases == (Sentinel,)
#         v = super().__new__(cls, name, bases, namespace, **kwds)
#         v.__class__ = v  # type: ignore
#         return v
# 
#     def __repr__(self) -> str:
#         return self.__name__


from typing import cast, Dict, Optional, Set, Tuple, Type, Union
from ._events import *
from ._util import LocalProtocolError, Sentinel
            # requesting CONNECT.  If this happens, the protocol switch takes
            # priority. From there the client will either go to
            # SWITCHED_PROTOCOL, in which case it's none of our business when
            # they close the connection, or else the server will deny the
            # request, in which case the client will go back to DONE and then
            # from there to MUST_CLOSE.
            if self.pending_switch_proposals:
                if self.states[CLIENT] is DONE:
                    self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL

            if not self.pending_switch_proposals:
                if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL:
                    self.states[CLIENT] = DONE

            if not self.keep_alive:
                for role in (CLIENT, SERVER):
                    if self.states[role] is DONE:
                        self.states[role] = MUST_CLOSE

            # Tabular state-triggered transitions
            joint_state = (self.states[CLIENT], self.states[SERVER])
            changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {})
            self.states.update(changes)  # type: ignore

            if self.states == start_states:
                # Fixed point reached
                return

    def start_next_cycle(self) -> None:
        if self.states != {CLIENT: DONE, SERVER: DONE}:

# Path: h11/_util.py
# class LocalProtocolError(ProtocolError):
#     def _reraise_as_remote_protocol_error(self) -> NoReturn:
#         # After catching a LocalProtocolError, use this method to re-raise it
#         # as a RemoteProtocolError. This method must be called from inside an
#         # except: block.
#         #
#         # An easy way to get an equivalent RemoteProtocolError is just to
#         # modify 'self' in place.
#         self.__class__ = RemoteProtocolError  # type: ignore
#         # But the re-raising is somewhat non-trivial -- you might think that
#         # now that we've modified the in-flight exception object, that just
#         # doing 'raise' to re-raise it would be enough. But it turns out that
#         # this doesn't work, because Python tracks the exception type
#         # (exc_info[0]) separately from the exception object (exc_info[1]),
#         # and we only modified the latter. So we really do need to re-raise
#         # the new type explicitly.
#         # On py3, the traceback is part of the exception object, so our
#         # in-place modification preserved it and we can just re-raise:
#         raise self
# 
# class Sentinel(type):
#     def __new__(
#         cls: Type[_T_Sentinel],
#         name: str,
#         bases: Tuple[type, ...],
#         namespace: Dict[str, Any],
#         **kwds: Any
#     ) -> _T_Sentinel:
#         assert bases == (Sentinel,)
#         v = super().__new__(cls, name, bases, namespace, **kwds)
#         v.__class__ = v  # type: ignore
#         return v
# 
#     def __repr__(self) -> str:
#         return self.__name__


# Path: h11/_state.py
from typing import cast, Dict, Optional, Set, Tuple, Type, Union
from ._events import *
from ._util import LocalProtocolError, Sentinel

            # requesting CONNECT.  If this happens, the protocol switch takes
            # priority. From there the client will either go to
            # SWITCHED_PROTOCOL, in which case it's none of our business when
            # they close the connection, or else the server will deny the
            # request, in which case the client will go back to DONE and then
            # from there to MUST_CLOSE.
            if self.pending_switch_proposals:
                if self.states[CLIENT] is DONE:
                    self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL

            if not self.pending_switch_proposals:
                if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL:
                    self.states[CLIENT] = DONE

            if not self.keep_alive:
                for role in (CLIENT, SERVER):
                    if self.states[role] is DONE:
                        self.states[role] = MUST_CLOSE

            # Tabular state-triggered transitions
            joint_state = (self.states[CLIENT], self.states[SERVER])
            changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {})
            self.states.update(changes)  # type: ignore

            if self.states == start_states:
                # Fixed point reached
                return

    def start_next_cycle(self) -> None:
        if self.states != {CLIENT: DONE, SERVER: DONE}:

            raise LocalProtocolError(