# 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
    # Protocol negotiation
    (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL},
    # Socket shutdown
    (CLOSED, DONE): {SERVER: MUST_CLOSE},
    (CLOSED, IDLE): {SERVER: MUST_CLOSE},
    (ERROR, DONE): {SERVER: MUST_CLOSE},
    (DONE, CLOSED): {CLIENT: MUST_CLOSE},
    (IDLE, CLOSED): {CLIENT: MUST_CLOSE},
    (DONE, ERROR): {CLIENT: MUST_CLOSE},
}


class ConnectionState:
    def __init__(self) -> None:
        # Extra bits of state that don't quite fit into the state model.

        # If this is False then it enables the automatic DONE -> MUST_CLOSE
        # transition. Don't set this directly; call .keep_alive_disabled()
        self.keep_alive = True

        # This is a subset of {UPGRADE, CONNECT}, containing the proposals
        # made by the client for switching protocols.
        self.pending_switch_proposals: Set[Type[Sentinel]] = set()

        self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE}

    def process_error(self, role: Type[Sentinel]) -> None:
        self.states[role] = ERROR
        self._fire_state_triggered_transitions()


# 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

    # Protocol negotiation
    (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL},
    # Socket shutdown
    (CLOSED, DONE): {SERVER: MUST_CLOSE},
    (CLOSED, IDLE): {SERVER: MUST_CLOSE},
    (ERROR, DONE): {SERVER: MUST_CLOSE},
    (DONE, CLOSED): {CLIENT: MUST_CLOSE},
    (IDLE, CLOSED): {CLIENT: MUST_CLOSE},
    (DONE, ERROR): {CLIENT: MUST_CLOSE},
}


class ConnectionState:
    def __init__(self) -> None:
        # Extra bits of state that don't quite fit into the state model.

        # If this is False then it enables the automatic DONE -> MUST_CLOSE
        # transition. Don't set this directly; call .keep_alive_disabled()
        self.keep_alive = True

        # This is a subset of {UPGRADE, CONNECT}, containing the proposals
        # made by the client for switching protocols.
        self.pending_switch_proposals: Set[Type[Sentinel]] = set()

        self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE}

    def process_error(self, role: Type[Sentinel]) -> None:
        self.states[role] = ERROR
        self._fire_state_triggered_transitions()


    def process_keep_alive_disabled(self) -> None: