from collections.abc import MutableSequence
from typing import List, Optional, Union
import sanic

class BlueprintGroup(MutableSequence):

    __slots__ = ("_blueprints", "_url_prefix", "_version", "_strict_slashes")

    def __init__(self, url_prefix=None, version=None, strict_slashes=None):
        """
        Create a new Blueprint Group

        :param url_prefix: URL: to be prefixed before all the Blueprint Prefix
        :param version: API Version for the blueprint group. This will be
            inherited by each of the Blueprint
        :param strict_slashes: URL Strict slash behavior indicator
        """
        self._blueprints = []
        self._url_prefix = url_prefix
        self._version = version
        self._strict_slashes = strict_slashes

    def insert(self, index: int, item: "sanic.Blueprint") -> None:
        """
        The Abstract class `MutableSequence` leverages this insert method to
        perform the `BlueprintGroup.append` operation.

        :param index: Index to use for removing a new Blueprint item
        :param item: New `Blueprint` object.
        :return: None
        """
        self._blueprints.insert(index, self._sanitize_blueprint(item))


from collections.abc import MutableSequence
from typing import List, Optional, Union
import sanic

class BlueprintGroup(MutableSequence):

    __slots__ = ("_blueprints", "_url_prefix", "_version", "_strict_slashes")

    def __init__(self, url_prefix=None, version=None, strict_slashes=None):
        """
        Create a new Blueprint Group

        :param url_prefix: URL: to be prefixed before all the Blueprint Prefix
        :param version: API Version for the blueprint group. This will be
            inherited by each of the Blueprint
        :param strict_slashes: URL Strict slash behavior indicator
        """
        self._blueprints = []
        self._url_prefix = url_prefix
        self._version = version
        self._strict_slashes = strict_slashes

    def middleware(self, *args, **kwargs):
        """
        A decorator that can be used to implement a Middleware plugin to
        all of the Blueprints that belongs to this specific Blueprint Group.

        In case of nested Blueprint Groups, the same middleware is applied
        across each of the Blueprints recursively.

        :param args: Optional positional Parameters to be use middleware
        :param kwargs: Optional Keyword arg to use with Middleware
        :return: Partial function to apply the middleware
        """

        def register_middleware_for_blueprints(fn):
            for blueprint in self.blueprints:
                blueprint.middleware(fn, *args, **kwargs)

        if args and callable(args[0]):
            fn = args[0]
            args = list(args)[1:]
            return register_middleware_for_blueprints(fn)
        return register_middleware_for_blueprints


import re
import string
from datetime import datetime
from typing import Dict

DEFAULT_MAX_AGE = 0
_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
_UnescapedChars = _LegalChars + " ()/<=>?@[]{}"
_Translator = {
    n: "\\%03o" % n for n in set(range(256)) - set(map(ord, _UnescapedChars))
}
_is_legal_key = re.compile("[%s]+" % re.escape(_LegalChars)).fullmatch

class Cookie(dict):

    _keys = {
        "expires": "expires",
        "path": "Path",
        "comment": "Comment",
        "domain": "Domain",
        "max-age": "Max-Age",
        "secure": "Secure",
        "httponly": "HttpOnly",
        "version": "Version",
        "samesite": "SameSite",
    }

    _flags = {"secure", "httponly"}

    def __init__(self, key, value):
        if key in self._keys:
            raise KeyError("Cookie name is a reserved word")
        if not _is_legal_key(key):
            raise KeyError("Cookie key contains illegal characters")
        self.key = key
        self.value = value
        super().__init__()

class CookieJar(dict):

    def __init__(self, headers):
        super().__init__()
        self.headers: Dict[str, str] = headers
        self.cookie_headers: Dict[str, str] = {}
        self.header_key: str = "Set-Cookie"

    def __setitem__(self, key, value):
        # If this cookie doesn't exist, add it to the header keys
        if not self.cookie_headers.get(key):
            cookie = Cookie(key, value)
            cookie["path"] = "/"
            self.cookie_headers[key] = self.header_key
            self.headers.add(self.header_key, cookie)
            return super().__setitem__(key, cookie)
        else:
            self[key].value = value


import re
import string
from datetime import datetime
from typing import Dict

DEFAULT_MAX_AGE = 0
_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
_UnescapedChars = _LegalChars + " ()/<=>?@[]{}"
_Translator = {
    n: "\\%03o" % n for n in set(range(256)) - set(map(ord, _UnescapedChars))
}
_is_legal_key = re.compile("[%s]+" % re.escape(_LegalChars)).fullmatch

class CookieJar(dict):

    def __init__(self, headers):
        super().__init__()
        self.headers: Dict[str, str] = headers
        self.cookie_headers: Dict[str, str] = {}
        self.header_key: str = "Set-Cookie"

    def __delitem__(self, key):
        if key not in self.cookie_headers:
            self[key] = ""
            self[key]["max-age"] = 0
        else:
            cookie_header = self.cookie_headers[key]
            # remove it from header
            cookies = self.headers.popall(cookie_header)
            for cookie in cookies:
                if cookie.key != key:
                    self.headers.add(cookie_header, cookie)
            del self.cookie_headers[key]
            return super().__delitem__(key)


import re
import string
from datetime import datetime
from typing import Dict

DEFAULT_MAX_AGE = 0
_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
_UnescapedChars = _LegalChars + " ()/<=>?@[]{}"
_Translator = {
    n: "\\%03o" % n for n in set(range(256)) - set(map(ord, _UnescapedChars))
}
_is_legal_key = re.compile("[%s]+" % re.escape(_LegalChars)).fullmatch

class Cookie(dict):

    _keys = {
        "expires": "expires",
        "path": "Path",
        "comment": "Comment",
        "domain": "Domain",
        "max-age": "Max-Age",
        "secure": "Secure",
        "httponly": "HttpOnly",
        "version": "Version",
        "samesite": "SameSite",
    }

    _flags = {"secure", "httponly"}

    def __init__(self, key, value):
        if key in self._keys:
            raise KeyError("Cookie name is a reserved word")
        if not _is_legal_key(key):
            raise KeyError("Cookie key contains illegal characters")
        self.key = key
        self.value = value
        super().__init__()

    def __setitem__(self, key, value):
        if key not in self._keys:
            raise KeyError("Unknown cookie property")
        if value is not False:
            if key.lower() == "max-age":
                if not str(value).isdigit():
                    raise ValueError("Cookie max-age must be an integer")
            elif key.lower() == "expires":
                if not isinstance(value, datetime):
                    raise TypeError(
                        "Cookie 'expires' property must be a datetime"
                    )
            return super().__setitem__(key, value)


import re
import string
from datetime import datetime
from typing import Dict

DEFAULT_MAX_AGE = 0
_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
_UnescapedChars = _LegalChars + " ()/<=>?@[]{}"
_Translator = {
    n: "\\%03o" % n for n in set(range(256)) - set(map(ord, _UnescapedChars))
}
_is_legal_key = re.compile("[%s]+" % re.escape(_LegalChars)).fullmatch

class Cookie(dict):

    _keys = {
        "expires": "expires",
        "path": "Path",
        "comment": "Comment",
        "domain": "Domain",
        "max-age": "Max-Age",
        "secure": "Secure",
        "httponly": "HttpOnly",
        "version": "Version",
        "samesite": "SameSite",
    }

    _flags = {"secure", "httponly"}

    def __init__(self, key, value):
        if key in self._keys:
            raise KeyError("Cookie name is a reserved word")
        if not _is_legal_key(key):
            raise KeyError("Cookie key contains illegal characters")
        self.key = key
        self.value = value
        super().__init__()

    def encode(self, encoding):
        """
        Encode the cookie content in a specific type of encoding instructed
        by the developer. Leverages the :func:`str.encode` method provided
        by python.

        This method can be used to encode and embed ``utf-8`` content into
        the cookies.

        :param encoding: Encoding to be used with the cookie
        :return: Cookie encoded in a codec of choosing.
        :except: UnicodeEncodeError
        """
        return str(self).encode(encoding)


import re
import string
from datetime import datetime
from typing import Dict

DEFAULT_MAX_AGE = 0
_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~:"
_UnescapedChars = _LegalChars + " ()/<=>?@[]{}"
_Translator = {
    n: "\\%03o" % n for n in set(range(256)) - set(map(ord, _UnescapedChars))
}
_is_legal_key = re.compile("[%s]+" % re.escape(_LegalChars)).fullmatch

class Cookie(dict):

    _keys = {
        "expires": "expires",
        "path": "Path",
        "comment": "Comment",
        "domain": "Domain",
        "max-age": "Max-Age",
        "secure": "Secure",
        "httponly": "HttpOnly",
        "version": "Version",
        "samesite": "SameSite",
    }

    _flags = {"secure", "httponly"}

    def __init__(self, key, value):
        if key in self._keys:
            raise KeyError("Cookie name is a reserved word")
        if not _is_legal_key(key):
            raise KeyError("Cookie key contains illegal characters")
        self.key = key
        self.value = value
        super().__init__()

    def __str__(self):
        """Format as a Set-Cookie header value."""
        output = ["%s=%s" % (self.key, _quote(self.value))]
        for key, value in self.items():
            if key == "max-age":
                try:
                    output.append("%s=%d" % (self._keys[key], value))
                except TypeError:
                    output.append("%s=%s" % (self._keys[key], value))
            elif key == "expires":
                output.append(
                    "%s=%s"
                    % (self._keys[key], value.strftime("%a, %d-%b-%Y %T GMT"))
                )
            elif key in self._flags and self[key]:
                output.append(self._keys[key])
            else:
                output.append("%s=%s" % (self._keys[key], value))

        return "; ".join(output)


from typing import Optional, Union
from sanic.helpers import STATUS_CODES

_sanic_exceptions = {}

class SanicException(Exception):

    def __init__(self, message, status_code=None, quiet=None):
        super().__init__(message)

        if status_code is not None:
            self.status_code = status_code

        # quiet=None/False/True with None meaning choose by status
        if quiet or quiet is None and status_code not in (None, 500):
            self.quiet = True

def add_status_code(code, quiet=None):
    """
    Decorator used for adding exceptions to :class:`SanicException`.
    """

    def class_decorator(cls):
        cls.status_code = code
        if quiet or quiet is None and code != 500:
            cls.quiet = True
        _sanic_exceptions[code] = cls
        return cls

    return class_decorator


from typing import Optional, Union
from sanic.helpers import STATUS_CODES

_sanic_exceptions = {}

class SanicException(Exception):

    def __init__(self, message, status_code=None, quiet=None):
        super().__init__(message)

        if status_code is not None:
            self.status_code = status_code

        # quiet=None/False/True with None meaning choose by status
        if quiet or quiet is None and status_code not in (None, 500):
            self.quiet = True

def abort(status_code: int, message: Optional[Union[str, bytes]] = None):
    """
    Raise an exception based on SanicException. Returns the HTTP response
    message appropriate for the given status code, unless provided.

    STATUS_CODES from sanic.helpers for the given status code.

    :param status_code: The HTTP status code to return.
    :param message: The HTTP response body. Defaults to the messages in
    """
    if message is None:
        msg: bytes = STATUS_CODES[status_code]
        # These are stored as bytes in the STATUS_CODES dict
        message = msg.decode("utf8")
    sanic_exception = _sanic_exceptions.get(status_code, SanicException)
    raise sanic_exception(message=message, status_code=status_code)


import re
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES

HeaderIterable = Iterable[Tuple[str, Any]]
HeaderBytesIterable = Iterable[Tuple[bytes, bytes]]
Options = Dict[str, Union[int, str]]
OptionsIterable = Iterable[Tuple[str, str]]
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_param = re.compile(fr";\s*{_token}=(?:{_token}|{_quoted})", re.ASCII)
_firefox_quote_escape = re.compile(r'\\"(?!; |\s*$)')
_ipv6 = "(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}"
_ipv6_re = re.compile(_ipv6)
_host_re = re.compile(
    r"((?:\[" + _ipv6 + r"\])|[a-zA-Z0-9.\-]{1,253})(?::(\d{1,5}))?"
)
_rparam = re.compile(f"(?:{_token}|{_quoted})={_token}\\s*($|[;,])", re.ASCII)
_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]

def parse_content_header(value: str) -> Tuple[str, Options]:
    """Parse content-type and content-disposition header values.

    E.g. 'form-data; name=upload; filename=\"file.txt\"' to
    ('form-data', {'name': 'upload', 'filename': 'file.txt'})

    Mostly identical to cgi.parse_header and werkzeug.parse_options_header
    but runs faster and handles special characters better. Unescapes quotes.
    """
    value = _firefox_quote_escape.sub("%22", value)
    pos = value.find(";")
    if pos == -1:
        options: Dict[str, Union[int, str]] = {}
    else:
        options = {
            m.group(1).lower(): m.group(2) or m.group(3).replace("%22", '"')
            for m in _param.finditer(value[pos:])
        }
        value = value[:pos]
    return value.strip().lower(), options


import re
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES

HeaderIterable = Iterable[Tuple[str, Any]]
HeaderBytesIterable = Iterable[Tuple[bytes, bytes]]
Options = Dict[str, Union[int, str]]
OptionsIterable = Iterable[Tuple[str, str]]
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_param = re.compile(fr";\s*{_token}=(?:{_token}|{_quoted})", re.ASCII)
_firefox_quote_escape = re.compile(r'\\"(?!; |\s*$)')
_ipv6 = "(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}"
_ipv6_re = re.compile(_ipv6)
_host_re = re.compile(
    r"((?:\[" + _ipv6 + r"\])|[a-zA-Z0-9.\-]{1,253})(?::(\d{1,5}))?"
)
_rparam = re.compile(f"(?:{_token}|{_quoted})={_token}\\s*($|[;,])", re.ASCII)
_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]

def parse_forwarded(headers, config) -> Optional[Options]:
    """Parse RFC 7239 Forwarded headers.
    The value of `by` or `secret` must match `config.FORWARDED_SECRET`
    :return: dict with keys and values, or None if nothing matched
    """
    header = headers.getall("forwarded", None)
    secret = config.FORWARDED_SECRET
    if header is None or not secret:
        return None
    header = ",".join(header)  # Join multiple header lines
    if secret not in header:
        return None
    # Loop over <separator><key>=<value> elements from right to left
    sep = pos = None
    options: List[Tuple[str, str]] = []
    found = False
    for m in _rparam.finditer(header[::-1]):
        # Start of new element? (on parser skips and non-semicolon right sep)
        if m.start() != pos or sep != ";":
            # Was the previous element (from right) what we wanted?
            if found:
                break
            # Clear values and parse as new element
            del options[:]
        pos = m.end()
        val_token, val_quoted, key, sep = m.groups()
        key = key.lower()[::-1]
        val = (val_token or val_quoted.replace('"\\', '"'))[::-1]
        options.append((key, val))
        if key in ("secret", "by") and val == secret:
            found = True
        # Check if we would return on next round, to avoid useless parse
        if found and sep != ";":
            break
    # If secret was found, return the matching options in left-to-right order
    return fwd_normalize(reversed(options)) if found else None


import re
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES

HeaderIterable = Iterable[Tuple[str, Any]]
HeaderBytesIterable = Iterable[Tuple[bytes, bytes]]
Options = Dict[str, Union[int, str]]
OptionsIterable = Iterable[Tuple[str, str]]
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_param = re.compile(fr";\s*{_token}=(?:{_token}|{_quoted})", re.ASCII)
_firefox_quote_escape = re.compile(r'\\"(?!; |\s*$)')
_ipv6 = "(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}"
_ipv6_re = re.compile(_ipv6)
_host_re = re.compile(
    r"((?:\[" + _ipv6 + r"\])|[a-zA-Z0-9.\-]{1,253})(?::(\d{1,5}))?"
)
_rparam = re.compile(f"(?:{_token}|{_quoted})={_token}\\s*($|[;,])", re.ASCII)
_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]

def parse_xforwarded(headers, config) -> Optional[Options]:
    """Parse traditional proxy headers."""
    real_ip_header = config.REAL_IP_HEADER
    proxies_count = config.PROXIES_COUNT
    addr = real_ip_header and headers.get(real_ip_header)
    if not addr and proxies_count:
        assert proxies_count > 0
        try:
            # Combine, split and filter multiple headers' entries
            forwarded_for = headers.getall(config.FORWARDED_FOR_HEADER)
            proxies = [
                p
                for p in (
                    p.strip() for h in forwarded_for for p in h.split(",")
                )
                if p
            ]
            addr = proxies[-proxies_count]
        except (KeyError, IndexError):
            pass
    # No processing of other headers if no address is found
    if not addr:
        return None

    def options():
        yield "for", addr
        for key, header in (
            ("proto", "x-scheme"),
            ("proto", "x-forwarded-proto"),  # Overrides X-Scheme if present
            ("host", "x-forwarded-host"),
            ("port", "x-forwarded-port"),
            ("path", "x-forwarded-path"),
        ):
            yield key, headers.get(header)

    return fwd_normalize(options())


import re
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES

HeaderIterable = Iterable[Tuple[str, Any]]
HeaderBytesIterable = Iterable[Tuple[bytes, bytes]]
Options = Dict[str, Union[int, str]]
OptionsIterable = Iterable[Tuple[str, str]]
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_param = re.compile(fr";\s*{_token}=(?:{_token}|{_quoted})", re.ASCII)
_firefox_quote_escape = re.compile(r'\\"(?!; |\s*$)')
_ipv6 = "(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}"
_ipv6_re = re.compile(_ipv6)
_host_re = re.compile(
    r"((?:\[" + _ipv6 + r"\])|[a-zA-Z0-9.\-]{1,253})(?::(\d{1,5}))?"
)
_rparam = re.compile(f"(?:{_token}|{_quoted})={_token}\\s*($|[;,])", re.ASCII)
_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]

def fwd_normalize(fwd: OptionsIterable) -> Options:
    """Normalize and convert values extracted from forwarded headers."""
    ret: Dict[str, Union[int, str]] = {}
    for key, val in fwd:
        if val is not None:
            try:
                if key in ("by", "for"):
                    ret[key] = fwd_normalize_address(val)
                elif key in ("host", "proto"):
                    ret[key] = val.lower()
                elif key == "port":
                    ret[key] = int(val)
                elif key == "path":
                    ret[key] = unquote(val)
                else:
                    ret[key] = val
            except ValueError:
                pass
    return ret


import re
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES

HeaderIterable = Iterable[Tuple[str, Any]]
HeaderBytesIterable = Iterable[Tuple[bytes, bytes]]
Options = Dict[str, Union[int, str]]
OptionsIterable = Iterable[Tuple[str, str]]
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_param = re.compile(fr";\s*{_token}=(?:{_token}|{_quoted})", re.ASCII)
_firefox_quote_escape = re.compile(r'\\"(?!; |\s*$)')
_ipv6 = "(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}"
_ipv6_re = re.compile(_ipv6)
_host_re = re.compile(
    r"((?:\[" + _ipv6 + r"\])|[a-zA-Z0-9.\-]{1,253})(?::(\d{1,5}))?"
)
_rparam = re.compile(f"(?:{_token}|{_quoted})={_token}\\s*($|[;,])", re.ASCII)
_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]

def fwd_normalize_address(addr: str) -> str:
    """Normalize address fields of proxy headers."""
    if addr == "unknown":
        raise ValueError()  # omit unknown value identifiers
    if addr.startswith("_"):
        return addr  # do not lower-case obfuscated strings
    if _ipv6_re.fullmatch(addr):
        addr = f"[{addr}]"  # bracket IPv6
    return addr.lower()


import re
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from urllib.parse import unquote
from sanic.helpers import STATUS_CODES

HeaderIterable = Iterable[Tuple[str, Any]]
HeaderBytesIterable = Iterable[Tuple[bytes, bytes]]
Options = Dict[str, Union[int, str]]
OptionsIterable = Iterable[Tuple[str, str]]
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_token, _quoted = r"([\w!#$%&'*+\-.^_`|~]+)", r'"([^"]*)"'
_param = re.compile(fr";\s*{_token}=(?:{_token}|{_quoted})", re.ASCII)
_firefox_quote_escape = re.compile(r'\\"(?!; |\s*$)')
_ipv6 = "(?:[0-9A-Fa-f]{0,4}:){2,7}[0-9A-Fa-f]{0,4}"
_ipv6_re = re.compile(_ipv6)
_host_re = re.compile(
    r"((?:\[" + _ipv6 + r"\])|[a-zA-Z0-9.\-]{1,253})(?::(\d{1,5}))?"
)
_rparam = re.compile(f"(?:{_token}|{_quoted})={_token}\\s*($|[;,])", re.ASCII)
_HTTP1_STATUSLINES = [
    b"HTTP/1.1 %d %b\r\n" % (status, STATUS_CODES.get(status, b"UNKNOWN"))
    for status in range(1000)
]

def parse_host(host: str) -> Tuple[Optional[str], Optional[int]]:
    """Split host:port into hostname and port.
    :return: None in place of missing elements
    """
    m = _host_re.fullmatch(host)
    if not m:
        return None, None
    host, port = m.groups()
    return host.lower(), int(port) if port is not None else None


from importlib import import_module
from inspect import ismodule
from typing import Dict

STATUS_CODES: Dict[int, bytes] = {
    100: b"Continue",
    101: b"Switching Protocols",
    102: b"Processing",
    103: b"Early Hints",
    200: b"OK",
    201: b"Created",
    202: b"Accepted",
    203: b"Non-Authoritative Information",
    204: b"No Content",
    205: b"Reset Content",
    206: b"Partial Content",
    207: b"Multi-Status",
    208: b"Already Reported",
    226: b"IM Used",
    300: b"Multiple Choices",
    301: b"Moved Permanently",
    302: b"Found",
    303: b"See Other",
    304: b"Not Modified",
    305: b"Use Proxy",
    307: b"Temporary Redirect",
    308: b"Permanent Redirect",
    400: b"Bad Request",
    401: b"Unauthorized",
    402: b"Payment Required",
    403: b"Forbidden",
    404: b"Not Found",
    405: b"Method Not Allowed",
    406: b"Not Acceptable",
    407: b"Proxy Authentication Required",
    408: b"Request Timeout",
    409: b"Conflict",
    410: b"Gone",
    411: b"Length Required",
    412: b"Precondition Failed",
    413: b"Request Entity Too Large",
    414: b"Request-URI Too Long",
    415: b"Unsupported Media Type",
    416: b"Requested Range Not Satisfiable",
    417: b"Expectation Failed",
    418: b"I'm a teapot",
    422: b"Unprocessable Entity",
    423: b"Locked",
    424: b"Failed Dependency",
    426: b"Upgrade Required",
    428: b"Precondition Required",
    429: b"Too Many Requests",
    431: b"Request Header Fields Too Large",
    451: b"Unavailable For Legal Reasons",
    500: b"Internal Server Error",
    501: b"Not Implemented",
    502: b"Bad Gateway",
    503: b"Service Unavailable",
    504: b"Gateway Timeout",
    505: b"HTTP Version Not Supported",
    506: b"Variant Also Negotiates",
    507: b"Insufficient Storage",
    508: b"Loop Detected",
    510: b"Not Extended",
    511: b"Network Authentication Required",
}
_ENTITY_HEADERS = frozenset(
    [
        "allow",
        "content-encoding",
        "content-language",
        "content-length",
        "content-location",
        "content-md5",
        "content-range",
        "content-type",
        "expires",
        "last-modified",
        "extension-header",
    ]
)
_HOP_BY_HOP_HEADERS = frozenset(
    [
        "connection",
        "keep-alive",
        "proxy-authenticate",
        "proxy-authorization",
        "te",
        "trailers",
        "transfer-encoding",
        "upgrade",
    ]
)

def has_message_body(status):
    """
    According to the following RFC message body and length SHOULD NOT
    be included in responses status 1XX, 204 and 304.
    https://tools.ietf.org/html/rfc2616#section-4.4
    https://tools.ietf.org/html/rfc2616#section-4.3
    """
    return status not in (204, 304) and not (100 <= status < 200)


from importlib import import_module
from inspect import ismodule
from typing import Dict

STATUS_CODES: Dict[int, bytes] = {
    100: b"Continue",
    101: b"Switching Protocols",
    102: b"Processing",
    103: b"Early Hints",
    200: b"OK",
    201: b"Created",
    202: b"Accepted",
    203: b"Non-Authoritative Information",
    204: b"No Content",
    205: b"Reset Content",
    206: b"Partial Content",
    207: b"Multi-Status",
    208: b"Already Reported",
    226: b"IM Used",
    300: b"Multiple Choices",
    301: b"Moved Permanently",
    302: b"Found",
    303: b"See Other",
    304: b"Not Modified",
    305: b"Use Proxy",
    307: b"Temporary Redirect",
    308: b"Permanent Redirect",
    400: b"Bad Request",
    401: b"Unauthorized",
    402: b"Payment Required",
    403: b"Forbidden",
    404: b"Not Found",
    405: b"Method Not Allowed",
    406: b"Not Acceptable",
    407: b"Proxy Authentication Required",
    408: b"Request Timeout",
    409: b"Conflict",
    410: b"Gone",
    411: b"Length Required",
    412: b"Precondition Failed",
    413: b"Request Entity Too Large",
    414: b"Request-URI Too Long",
    415: b"Unsupported Media Type",
    416: b"Requested Range Not Satisfiable",
    417: b"Expectation Failed",
    418: b"I'm a teapot",
    422: b"Unprocessable Entity",
    423: b"Locked",
    424: b"Failed Dependency",
    426: b"Upgrade Required",
    428: b"Precondition Required",
    429: b"Too Many Requests",
    431: b"Request Header Fields Too Large",
    451: b"Unavailable For Legal Reasons",
    500: b"Internal Server Error",
    501: b"Not Implemented",
    502: b"Bad Gateway",
    503: b"Service Unavailable",
    504: b"Gateway Timeout",
    505: b"HTTP Version Not Supported",
    506: b"Variant Also Negotiates",
    507: b"Insufficient Storage",
    508: b"Loop Detected",
    510: b"Not Extended",
    511: b"Network Authentication Required",
}
_ENTITY_HEADERS = frozenset(
    [
        "allow",
        "content-encoding",
        "content-language",
        "content-length",
        "content-location",
        "content-md5",
        "content-range",
        "content-type",
        "expires",
        "last-modified",
        "extension-header",
    ]
)
_HOP_BY_HOP_HEADERS = frozenset(
    [
        "connection",
        "keep-alive",
        "proxy-authenticate",
        "proxy-authorization",
        "te",
        "trailers",
        "transfer-encoding",
        "upgrade",
    ]
)

def remove_entity_headers(headers, allowed=("content-location", "expires")):
    """
    Removes all the entity headers present in the headers given.
    According to RFC 2616 Section 10.3.5,
    Content-Location and Expires are allowed as for the
    "strong cache validator".
    https://tools.ietf.org/html/rfc2616#section-10.3.5

    returns the headers without the entity headers
    """
    allowed = set([h.lower() for h in allowed])
    headers = {
        header: value
        for header, value in headers.items()
        if not is_entity_header(header) or header.lower() in allowed
    }
    return headers


from importlib import import_module
from inspect import ismodule
from typing import Dict

STATUS_CODES: Dict[int, bytes] = {
    100: b"Continue",
    101: b"Switching Protocols",
    102: b"Processing",
    103: b"Early Hints",
    200: b"OK",
    201: b"Created",
    202: b"Accepted",
    203: b"Non-Authoritative Information",
    204: b"No Content",
    205: b"Reset Content",
    206: b"Partial Content",
    207: b"Multi-Status",
    208: b"Already Reported",
    226: b"IM Used",
    300: b"Multiple Choices",
    301: b"Moved Permanently",
    302: b"Found",
    303: b"See Other",
    304: b"Not Modified",
    305: b"Use Proxy",
    307: b"Temporary Redirect",
    308: b"Permanent Redirect",
    400: b"Bad Request",
    401: b"Unauthorized",
    402: b"Payment Required",
    403: b"Forbidden",
    404: b"Not Found",
    405: b"Method Not Allowed",
    406: b"Not Acceptable",
    407: b"Proxy Authentication Required",
    408: b"Request Timeout",
    409: b"Conflict",
    410: b"Gone",
    411: b"Length Required",
    412: b"Precondition Failed",
    413: b"Request Entity Too Large",
    414: b"Request-URI Too Long",
    415: b"Unsupported Media Type",
    416: b"Requested Range Not Satisfiable",
    417: b"Expectation Failed",
    418: b"I'm a teapot",
    422: b"Unprocessable Entity",
    423: b"Locked",
    424: b"Failed Dependency",
    426: b"Upgrade Required",
    428: b"Precondition Required",
    429: b"Too Many Requests",
    431: b"Request Header Fields Too Large",
    451: b"Unavailable For Legal Reasons",
    500: b"Internal Server Error",
    501: b"Not Implemented",
    502: b"Bad Gateway",
    503: b"Service Unavailable",
    504: b"Gateway Timeout",
    505: b"HTTP Version Not Supported",
    506: b"Variant Also Negotiates",
    507: b"Insufficient Storage",
    508: b"Loop Detected",
    510: b"Not Extended",
    511: b"Network Authentication Required",
}
_ENTITY_HEADERS = frozenset(
    [
        "allow",
        "content-encoding",
        "content-language",
        "content-length",
        "content-location",
        "content-md5",
        "content-range",
        "content-type",
        "expires",
        "last-modified",
        "extension-header",
    ]
)
_HOP_BY_HOP_HEADERS = frozenset(
    [
        "connection",
        "keep-alive",
        "proxy-authenticate",
        "proxy-authorization",
        "te",
        "trailers",
        "transfer-encoding",
        "upgrade",
    ]
)

def import_string(module_name, package=None):
    """
    import a module or class by string path.

    :module_name: str with path of module or path to import and
    instanciate a class
    :returns: a module object or one instance from class if
    module_name is a valid path to class

    """
    module, klass = module_name.rsplit(".", 1)
    module = import_module(module, package=package)
    obj = getattr(module, klass)
    if ismodule(obj):
        return obj
    return obj()


from typing import Set
from sanic.models.futures import FutureException

class ExceptionMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_exceptions: Set[FutureException] = set()

    def exception(self, *exceptions, apply=True):
        """
        This method enables the process of creating a global exception
        handler for the current blueprint under question.

        :param args: List of Python exceptions to be caught by the handler
        :param kwargs: Additional optional arguments to be passed to the
            exception handler

        :return a decorated method to handle global exceptions for any
            route registered under this blueprint.
        """

        def decorator(handler):
            nonlocal apply
            nonlocal exceptions

            if isinstance(exceptions[0], list):
                exceptions = tuple(*exceptions)

            future_exception = FutureException(handler, exceptions)
            self._future_exceptions.add(future_exception)
            if apply:
                self._apply_exception_handler(future_exception)
            return handler

        return decorator


from functools import partial
from typing import List
from sanic.models.futures import FutureMiddleware

class MiddlewareMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_middleware: List[FutureMiddleware] = []

    def middleware(
        self, middleware_or_request, attach_to="request", apply=True
    ):
        """
        Decorate and register middleware to be called before a request.
        Can either be called as *@app.middleware* or
        *@app.middleware('request')*

        `See user guide re: middleware
        <https://sanicframework.org/guide/basics/middleware.html>`__

        :param: middleware_or_request: Optional parameter to use for
            identifying which type of middleware is being registered.
        """

        def register_middleware(middleware, attach_to="request"):
            nonlocal apply

            future_middleware = FutureMiddleware(middleware, attach_to)
            self._future_middleware.append(future_middleware)
            if apply:
                self._apply_middleware(future_middleware)
            return middleware

        # Detect which way this was called, @middleware or @middleware('AT')
        if callable(middleware_or_request):
            return register_middleware(
                middleware_or_request, attach_to=attach_to
            )
        else:
            return partial(
                register_middleware, attach_to=middleware_or_request
            )


from functools import partial
from typing import List
from sanic.models.futures import FutureMiddleware

class MiddlewareMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_middleware: List[FutureMiddleware] = []

    def on_request(self, middleware=None):
        if callable(middleware):
            return self.middleware(middleware, "request")
        else:
            return partial(self.middleware, attach_to="request")


from functools import partial
from typing import List
from sanic.models.futures import FutureMiddleware

class MiddlewareMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_middleware: List[FutureMiddleware] = []

    def on_response(self, middleware=None):
        if callable(middleware):
            return self.middleware(middleware, "response")
        else:
            return partial(self.middleware, attach_to="response")


from functools import partial, wraps
from inspect import signature
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from re import sub
from time import gmtime, strftime
from typing import Iterable, List, Optional, Set, Union
from urllib.parse import unquote
from sanic_routing.route import Route
from sanic.compat import stat_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE, HTTP_METHODS
from sanic.exceptions import (
    ContentRangeError,
    FileNotFound,
    HeaderNotFound,
    InvalidUsage,
)
from sanic.handlers import ContentRangeHandler
from sanic.log import error_logger
from sanic.models.futures import FutureRoute, FutureStatic
from sanic.response import HTTPResponse, file, file_stream
from sanic.views import CompositionView

class RouteMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_routes: Set[FutureRoute] = set()
        self._future_statics: Set[FutureStatic] = set()
        self.name = ""
        self.strict_slashes: Optional[bool] = False

    def route(
        self,
        uri: str,
        methods: Optional[Iterable[str]] = None,
        host: Optional[str] = None,
        strict_slashes: Optional[bool] = None,
        stream: bool = False,
        version: Optional[int] = None,
        name: Optional[str] = None,
        ignore_body: bool = False,
        apply: bool = True,
        subprotocols: Optional[List[str]] = None,
        websocket: bool = False,
        unquote: bool = False,
        static: bool = False,
    ):
        """
        Decorate a function to be registered as a route

        :param uri: path of the URL
        :param methods: list or tuple of methods allowed
        :param host: the host, if required
        :param strict_slashes: whether to apply strict slashes to the route
        :param stream: whether to allow the request to stream its body
        :param version: route specific versioning
        :param name: user defined route name for url_for
        :param ignore_body: whether the handler should ignore request
            body (eg. GET requests)
        :return: tuple of routes, decorated function
        """

        # Fix case where the user did not prefix the URL with a /
        # and will probably get confused as to why it's not working
        if not uri.startswith("/") and (uri or hasattr(self, "router")):
            uri = "/" + uri

        if strict_slashes is None:
            strict_slashes = self.strict_slashes

        if not methods and not websocket:
            methods = frozenset({"GET"})

        def decorator(handler):
            nonlocal uri
            nonlocal methods
            nonlocal host
            nonlocal strict_slashes
            nonlocal stream
            nonlocal version
            nonlocal name
            nonlocal ignore_body
            nonlocal subprotocols
            nonlocal websocket
            nonlocal static

            if isinstance(handler, tuple):
                # if a handler fn is already wrapped in a route, the handler
                # variable will be a tuple of (existing routes, handler fn)
                _, handler = handler

            name = self._generate_name(name, handler)

            if isinstance(host, str):
                host = frozenset([host])
            elif host and not isinstance(host, frozenset):
                try:
                    host = frozenset(host)
                except TypeError:
                    raise ValueError(
                        "Expected either string or Iterable of host strings, "
                        "not %s" % host
                    )

            if isinstance(subprotocols, (list, tuple, set)):
                subprotocols = frozenset(subprotocols)

            route = FutureRoute(
                handler,
                uri,
                None if websocket else frozenset([x.upper() for x in methods]),
                host,
                strict_slashes,
                stream,
                version,
                name,
                ignore_body,
                websocket,
                subprotocols,
                unquote,
                static,
            )

            self._future_routes.add(route)

            args = list(signature(handler).parameters.keys())
            if websocket and len(args) < 2:
                handler_name = handler.__name__

                raise ValueError(
                    f"Required parameter `request` and/or `ws` missing "
                    f"in the {handler_name}() route?"
                )
            elif not args:
                handler_name = handler.__name__

                raise ValueError(
                    f"Required parameter `request` missing "
                    f"in the {handler_name}() route?"
                )

            if not websocket and stream:
                handler.is_stream = stream

            if apply:
                self._apply_route(route)

            return route, handler

        return decorator


from functools import partial, wraps
from inspect import signature
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from re import sub
from time import gmtime, strftime
from typing import Iterable, List, Optional, Set, Union
from urllib.parse import unquote
from sanic_routing.route import Route
from sanic.compat import stat_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE, HTTP_METHODS
from sanic.exceptions import (
    ContentRangeError,
    FileNotFound,
    HeaderNotFound,
    InvalidUsage,
)
from sanic.handlers import ContentRangeHandler
from sanic.log import error_logger
from sanic.models.futures import FutureRoute, FutureStatic
from sanic.response import HTTPResponse, file, file_stream
from sanic.views import CompositionView

class RouteMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_routes: Set[FutureRoute] = set()
        self._future_statics: Set[FutureStatic] = set()
        self.name = ""
        self.strict_slashes: Optional[bool] = False

    def add_route(
        self,
        handler,
        uri: str,
        methods: Iterable[str] = frozenset({"GET"}),
        host: Optional[str] = None,
        strict_slashes: Optional[bool] = None,
        version: Optional[int] = None,
        name: Optional[str] = None,
        stream: bool = False,
    ):
        """A helper method to register class instance or
        functions as a handler to the application url
        routes.

        :param handler: function or class instance
        :param uri: path of the URL
        :param methods: list or tuple of methods allowed, these are overridden
                        if using a HTTPMethodView
        :param host:
        :param strict_slashes:
        :param version:
        :param name: user defined route name for url_for
        :param stream: boolean specifying if the handler is a stream handler
        :return: function or class instance
        """
        # Handle HTTPMethodView differently
        if hasattr(handler, "view_class"):
            methods = set()

            for method in HTTP_METHODS:
                _handler = getattr(handler.view_class, method.lower(), None)
                if _handler:
                    methods.add(method)
                    if hasattr(_handler, "is_stream"):
                        stream = True

        # handle composition view differently
        if isinstance(handler, CompositionView):
            methods = handler.handlers.keys()
            for _handler in handler.handlers.values():
                if hasattr(_handler, "is_stream"):
                    stream = True
                    break

        if strict_slashes is None:
            strict_slashes = self.strict_slashes

        self.route(
            uri=uri,
            methods=methods,
            host=host,
            strict_slashes=strict_slashes,
            stream=stream,
            version=version,
            name=name,
        )(handler)
        return handler


from functools import partial, wraps
from inspect import signature
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from re import sub
from time import gmtime, strftime
from typing import Iterable, List, Optional, Set, Union
from urllib.parse import unquote
from sanic_routing.route import Route
from sanic.compat import stat_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE, HTTP_METHODS
from sanic.exceptions import (
    ContentRangeError,
    FileNotFound,
    HeaderNotFound,
    InvalidUsage,
)
from sanic.handlers import ContentRangeHandler
from sanic.log import error_logger
from sanic.models.futures import FutureRoute, FutureStatic
from sanic.response import HTTPResponse, file, file_stream
from sanic.views import CompositionView

class RouteMixin:

    def __init__(self, *args, **kwargs) -> None:
        self._future_routes: Set[FutureRoute] = set()
        self._future_statics: Set[FutureStatic] = set()
        self.name = ""
        self.strict_slashes: Optional[bool] = False

    def static(
        self,
        uri,
        file_or_directory: Union[str, bytes, PurePath],
        pattern=r"/?.+",
        use_modified_since=True,
        use_content_range=False,
        stream_large_files=False,
        name="static",
        host=None,
        strict_slashes=None,
        content_type=None,
        apply=True,
    ):
        """
        Register a root to serve files from. The input can either be a
        file or a directory. This method will enable an easy and simple way
        to setup the :class:`Route` necessary to serve the static files.

        :param uri: URL path to be used for serving static content
        :param file_or_directory: Path for the Static file/directory with
            static files
        :param pattern: Regex Pattern identifying the valid static files
        :param use_modified_since: If true, send file modified time, and return
            not modified if the browser's matches the server's
        :param use_content_range: If true, process header for range requests
            and sends the file part that is requested
        :param stream_large_files: If true, use the
            :func:`StreamingHTTPResponse.file_stream` handler rather
            than the :func:`HTTPResponse.file` handler to send the file.
            If this is an integer, this represents the threshold size to
            switch to :func:`StreamingHTTPResponse.file_stream`
        :param name: user defined name used for url_for
        :param host: Host IP or FQDN for the service to use
        :param strict_slashes: Instruct :class:`Sanic` to check if the request
            URLs need to terminate with a */*
        :param content_type: user defined content type for header
        :return: routes registered on the router
        :rtype: List[sanic.router.Route]
        """

        name = self._generate_name(name)

        if strict_slashes is None and self.strict_slashes is not None:
            strict_slashes = self.strict_slashes

        if not isinstance(file_or_directory, (str, bytes, PurePath)):
            raise ValueError(
                f"Static route must be a valid path, not {file_or_directory}"
            )

        static = FutureStatic(
            uri,
            file_or_directory,
            pattern,
            use_modified_since,
            use_content_range,
            stream_large_files,
            name,
            host,
            strict_slashes,
            content_type,
        )
        self._future_statics.add(static)

        if apply:
            self._apply_static(static)


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class BaseHTTPResponse:

    _dumps = json_dumps

    def __init__(self):
        self.asgi: bool = False
        self.body: Optional[bytes] = None
        self.content_type: Optional[str] = None
        self.stream: Http = None
        self.status: int = None
        self.headers = Header({})
        self._cookies: Optional[CookieJar] = None

class HTTPResponse(BaseHTTPResponse):

    __slots__ = ("body", "status", "content_type", "headers", "_cookies")

    def __init__(
        self,
        body: Optional[AnyStr] = None,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: Optional[str] = None,
    ):
        super().__init__()

        self.content_type: Optional[str] = content_type
        self.body = self._encode_body(body)
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

def json(
    body: Any,
    status: int = 200,
    headers: Optional[Dict[str, str]] = None,
    content_type: str = "application/json",
    dumps: Optional[Callable[..., str]] = None,
    **kwargs,
) -> HTTPResponse:
    """
    Returns response object with body in json format.

    :param body: Response data to be serialized.
    :param status: Response code.
    :param headers: Custom Headers.
    :param kwargs: Remaining arguments that are passed to the json encoder.
    """
    if not dumps:
        dumps = BaseHTTPResponse._dumps
    return HTTPResponse(
        dumps(body, **kwargs),
        headers=headers,
        status=status,
        content_type=content_type,
    )


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class HTTPResponse(BaseHTTPResponse):

    __slots__ = ("body", "status", "content_type", "headers", "_cookies")

    def __init__(
        self,
        body: Optional[AnyStr] = None,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: Optional[str] = None,
    ):
        super().__init__()

        self.content_type: Optional[str] = content_type
        self.body = self._encode_body(body)
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

def text(
    body: str,
    status: int = 200,
    headers: Optional[Dict[str, str]] = None,
    content_type: str = "text/plain; charset=utf-8",
) -> HTTPResponse:
    """
    Returns response object with body in text format.

    :param body: Response data to be encoded.
    :param status: Response code.
    :param headers: Custom Headers.
    :param content_type: the content type (string) of the response
    """
    if not isinstance(body, str):
        raise TypeError(
            f"Bad body type. Expected str, got {type(body).__name__})"
        )

    return HTTPResponse(
        body, status=status, headers=headers, content_type=content_type
    )


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class HTTPResponse(BaseHTTPResponse):

    __slots__ = ("body", "status", "content_type", "headers", "_cookies")

    def __init__(
        self,
        body: Optional[AnyStr] = None,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: Optional[str] = None,
    ):
        super().__init__()

        self.content_type: Optional[str] = content_type
        self.body = self._encode_body(body)
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

def html(
    body: Union[str, bytes, HTMLProtocol],
    status: int = 200,
    headers: Optional[Dict[str, str]] = None,
) -> HTTPResponse:
    """
    Returns response object with body in html format.

    :param body: str or bytes-ish, or an object with __html__ or _repr_html_.
    :param status: Response code.
    :param headers: Custom Headers.
    """
    if not isinstance(body, (str, bytes)):
        if hasattr(body, "__html__"):
            body = body.__html__()
        elif hasattr(body, "_repr_html_"):
            body = body._repr_html_()

    return HTTPResponse(  # type: ignore
        body,
        status=status,
        headers=headers,
        content_type="text/html; charset=utf-8",
    )


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class HTTPResponse(BaseHTTPResponse):

    __slots__ = ("body", "status", "content_type", "headers", "_cookies")

    def __init__(
        self,
        body: Optional[AnyStr] = None,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: Optional[str] = None,
    ):
        super().__init__()

        self.content_type: Optional[str] = content_type
        self.body = self._encode_body(body)
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

async def file(
    location: Union[str, PurePath],
    status: int = 200,
    mime_type: Optional[str] = None,
    headers: Optional[Dict[str, str]] = None,
    filename: Optional[str] = None,
    _range: Optional[Range] = None,
) -> HTTPResponse:
    """Return a response object with file data.

    :param location: Location of file on system.
    :param mime_type: Specific mime_type.
    :param headers: Custom Headers.
    :param filename: Override filename.
    :param _range:
    """
    headers = headers or {}
    if filename:
        headers.setdefault(
            "Content-Disposition", f'attachment; filename="{filename}"'
        )
    filename = filename or path.split(location)[-1]

    async with await open_async(location, mode="rb") as f:
        if _range:
            await f.seek(_range.start)
            out_stream = await f.read(_range.size)
            headers[
                "Content-Range"
            ] = f"bytes {_range.start}-{_range.end}/{_range.total}"
            status = 206
        else:
            out_stream = await f.read()

    mime_type = mime_type or guess_type(filename)[0] or "text/plain"
    return HTTPResponse(
        body=out_stream,
        status=status,
        headers=headers,
        content_type=mime_type,
    )


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class StreamingHTTPResponse(BaseHTTPResponse):

    __slots__ = (
        "streaming_fn",
        "status",
        "content_type",
        "headers",
        "_cookies",
    )

    def __init__(
        self,
        streaming_fn: StreamingFunction,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: str = "text/plain; charset=utf-8",
        chunked="deprecated",
    ):
        if chunked != "deprecated":
            warn(
                "The chunked argument has been deprecated and will be "
                "removed in v21.6"
            )

        super().__init__()

        self.content_type = content_type
        self.streaming_fn = streaming_fn
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

class HTTPResponse(BaseHTTPResponse):

    __slots__ = ("body", "status", "content_type", "headers", "_cookies")

    def __init__(
        self,
        body: Optional[AnyStr] = None,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: Optional[str] = None,
    ):
        super().__init__()

        self.content_type: Optional[str] = content_type
        self.body = self._encode_body(body)
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

async def file_stream(
    location: Union[str, PurePath],
    status: int = 200,
    chunk_size: int = 4096,
    mime_type: Optional[str] = None,
    headers: Optional[Dict[str, str]] = None,
    filename: Optional[str] = None,
    chunked="deprecated",
    _range: Optional[Range] = None,
) -> StreamingHTTPResponse:
    """Return a streaming response object with file data.

    :param location: Location of file on system.
    :param chunk_size: The size of each chunk in the stream (in bytes)
    :param mime_type: Specific mime_type.
    :param headers: Custom Headers.
    :param filename: Override filename.
    :param chunked: Deprecated
    :param _range:
    """
    if chunked != "deprecated":
        warn(
            "The chunked argument has been deprecated and will be "
            "removed in v21.6"
        )

    headers = headers or {}
    if filename:
        headers.setdefault(
            "Content-Disposition", f'attachment; filename="{filename}"'
        )
    filename = filename or path.split(location)[-1]
    mime_type = mime_type or guess_type(filename)[0] or "text/plain"
    if _range:
        start = _range.start
        end = _range.end
        total = _range.total

        headers["Content-Range"] = f"bytes {start}-{end}/{total}"
        status = 206

    async def _streaming_fn(response):
        async with await open_async(location, mode="rb") as f:
            if _range:
                await f.seek(_range.start)
                to_send = _range.size
                while to_send > 0:
                    content = await f.read(min((_range.size, chunk_size)))
                    if len(content) < 1:
                        break
                    to_send -= len(content)
                    await response.write(content)
            else:
                while True:
                    content = await f.read(chunk_size)
                    if len(content) < 1:
                        break
                    await response.write(content)

    return StreamingHTTPResponse(
        streaming_fn=_streaming_fn,
        status=status,
        headers=headers,
        content_type=mime_type,
    )


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class StreamingHTTPResponse(BaseHTTPResponse):

    __slots__ = (
        "streaming_fn",
        "status",
        "content_type",
        "headers",
        "_cookies",
    )

    def __init__(
        self,
        streaming_fn: StreamingFunction,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: str = "text/plain; charset=utf-8",
        chunked="deprecated",
    ):
        if chunked != "deprecated":
            warn(
                "The chunked argument has been deprecated and will be "
                "removed in v21.6"
            )

        super().__init__()

        self.content_type = content_type
        self.streaming_fn = streaming_fn
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

class HTTPResponse(BaseHTTPResponse):

    __slots__ = ("body", "status", "content_type", "headers", "_cookies")

    def __init__(
        self,
        body: Optional[AnyStr] = None,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: Optional[str] = None,
    ):
        super().__init__()

        self.content_type: Optional[str] = content_type
        self.body = self._encode_body(body)
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

def stream(
    streaming_fn: StreamingFunction,
    status: int = 200,
    headers: Optional[Dict[str, str]] = None,
    content_type: str = "text/plain; charset=utf-8",
    chunked="deprecated",
):
    """Accepts an coroutine `streaming_fn` which can be used to
    write chunks to a streaming response. Returns a `StreamingHTTPResponse`.

    Example usage::

        @app.route("/")
        async def index(request):
            async def streaming_fn(response):
                await response.write('foo')
                await response.write('bar')

            return stream(streaming_fn, content_type='text/plain')

    :param streaming_fn: A coroutine accepts a response and
        writes content to that response.
    :param mime_type: Specific mime_type.
    :param headers: Custom Headers.
    :param chunked: Deprecated
    """
    if chunked != "deprecated":
        warn(
            "The chunked argument has been deprecated and will be "
            "removed in v21.6"
        )

    return StreamingHTTPResponse(
        streaming_fn,
        headers=headers,
        content_type=content_type,
        status=status,
    )


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class BaseHTTPResponse:

    _dumps = json_dumps

    def __init__(self):
        self.asgi: bool = False
        self.body: Optional[bytes] = None
        self.content_type: Optional[str] = None
        self.stream: Http = None
        self.status: int = None
        self.headers = Header({})
        self._cookies: Optional[CookieJar] = None

    async def send(
        self,
        data: Optional[Union[AnyStr]] = None,
        end_stream: Optional[bool] = None,
    ) -> None:
        """
        Send any pending response headers and the given data as body.

        :param data: str or bytes to be written
        :param end_stream: whether to close the stream after this block
        """
        if data is None and end_stream is None:
            end_stream = True
        if end_stream and not data and self.stream.send is None:
            return
        data = (
            data.encode()  # type: ignore
            if hasattr(data, "encode")
            else data or b""
        )
        await self.stream.send(data, end_stream=end_stream)


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class StreamingHTTPResponse(BaseHTTPResponse):

    __slots__ = (
        "streaming_fn",
        "status",
        "content_type",
        "headers",
        "_cookies",
    )

    def __init__(
        self,
        streaming_fn: StreamingFunction,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: str = "text/plain; charset=utf-8",
        chunked="deprecated",
    ):
        if chunked != "deprecated":
            warn(
                "The chunked argument has been deprecated and will be "
                "removed in v21.6"
            )

        super().__init__()

        self.content_type = content_type
        self.streaming_fn = streaming_fn
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class StreamingHTTPResponse(BaseHTTPResponse):

    __slots__ = (
        "streaming_fn",
        "status",
        "content_type",
        "headers",
        "_cookies",
    )

    def __init__(
        self,
        streaming_fn: StreamingFunction,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: str = "text/plain; charset=utf-8",
        chunked="deprecated",
    ):
        if chunked != "deprecated":
            warn(
                "The chunked argument has been deprecated and will be "
                "removed in v21.6"
            )

        super().__init__()

        self.content_type = content_type
        self.streaming_fn = streaming_fn
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

    async def write(self, data):
        """Writes a chunk of data to the streaming response.

        :param data: str or bytes-ish data to be written.
        """
        await super().send(self._encode_body(data))


from functools import partial
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from typing import (
    Any,
    AnyStr,
    Callable,
    Coroutine,
    Dict,
    Iterator,
    Optional,
    Tuple,
    Union,
)
from urllib.parse import quote_plus
from warnings import warn
from sanic.compat import Header, open_async
from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE
from sanic.cookies import CookieJar
from sanic.helpers import has_message_body, remove_entity_headers
from sanic.http import Http
from sanic.models.protocol_types import HTMLProtocol, Range

StreamingFunction = Callable[[BaseHTTPResponse], Coroutine[Any, Any, None]]

class StreamingHTTPResponse(BaseHTTPResponse):

    __slots__ = (
        "streaming_fn",
        "status",
        "content_type",
        "headers",
        "_cookies",
    )

    def __init__(
        self,
        streaming_fn: StreamingFunction,
        status: int = 200,
        headers: Optional[Union[Header, Dict[str, str]]] = None,
        content_type: str = "text/plain; charset=utf-8",
        chunked="deprecated",
    ):
        if chunked != "deprecated":
            warn(
                "The chunked argument has been deprecated and will be "
                "removed in v21.6"
            )

        super().__init__()

        self.content_type = content_type
        self.streaming_fn = streaming_fn
        self.status = status
        self.headers = Header(headers or {})
        self._cookies = None

    async def send(self, *args, **kwargs):
        if self.streaming_fn is not None:
            await self.streaming_fn(self)
            self.streaming_fn = None
        await super().send(*args, **kwargs)


from functools import lru_cache
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from sanic_routing import BaseRouter
from sanic_routing.exceptions import NoMethod
from sanic_routing.exceptions import (
    NotFound as RoutingNotFound,  # type: ignore
)
from sanic_routing.route import Route
from sanic.constants import HTTP_METHODS
from sanic.exceptions import MethodNotSupported, NotFound, SanicException
from sanic.models.handler_types import RouteHandler

ROUTER_CACHE_SIZE = 1024
ALLOWED_LABELS = ("__file_uri__",)

class Router(BaseRouter):

    DEFAULT_METHOD = "GET"

    ALLOWED_METHODS = HTTP_METHODS

    def add(  # type: ignore
        self,
        uri: str,
        methods: Iterable[str],
        handler: RouteHandler,
        host: Optional[Union[str, Iterable[str]]] = None,
        strict_slashes: bool = False,
        stream: bool = False,
        ignore_body: bool = False,
        version: Union[str, float, int] = None,
        name: Optional[str] = None,
        unquote: bool = False,
        static: bool = False,
    ) -> Union[Route, List[Route]]:
        """
        Add a handler to the router

        :param uri: the path of the route
        :type uri: str
        :param methods: the types of HTTP methods that should be attached,
            example: ``["GET", "POST", "OPTIONS"]``
        :type methods: Iterable[str]
        :param handler: the sync or async function to be executed
        :type handler: RouteHandler
        :param host: host that the route should be on, defaults to None
        :type host: Optional[str], optional
        :param strict_slashes: whether to apply strict slashes, defaults
            to False
        :type strict_slashes: bool, optional
        :param stream: whether to stream the response, defaults to False
        :type stream: bool, optional
        :param ignore_body: whether the incoming request body should be read,
            defaults to False
        :type ignore_body: bool, optional
        :param version: a version modifier for the uri, defaults to None
        :type version: Union[str, float, int], optional
        :param name: an identifying name of the route, defaults to None
        :type name: Optional[str], optional
        :return: the route object
        :rtype: Route
        """
        if version is not None:
            version = str(version).strip("/").lstrip("v")
            uri = "/".join([f"/v{version}", uri.lstrip("/")])

        params = dict(
            path=uri,
            handler=handler,
            methods=methods,
            name=name,
            strict=strict_slashes,
            unquote=unquote,
        )

        if isinstance(host, str):
            hosts = [host]
        else:
            hosts = host or [None]  # type: ignore

        routes = []

        for host in hosts:
            if host:
                params.update({"requirements": {"host": host}})

            route = super().add(**params)  # type: ignore
            route.ctx.ignore_body = ignore_body
            route.ctx.stream = stream
            route.ctx.hosts = hosts
            route.ctx.static = static

            routes.append(route)

        if len(routes) == 1:
            return routes[0]
        return routes


from functools import lru_cache
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union
from sanic_routing import BaseRouter
from sanic_routing.exceptions import NoMethod
from sanic_routing.exceptions import (
    NotFound as RoutingNotFound,  # type: ignore
)
from sanic_routing.route import Route
from sanic.constants import HTTP_METHODS
from sanic.exceptions import MethodNotSupported, NotFound, SanicException
from sanic.models.handler_types import RouteHandler

ROUTER_CACHE_SIZE = 1024
ALLOWED_LABELS = ("__file_uri__",)

class Router(BaseRouter):

    DEFAULT_METHOD = "GET"

    ALLOWED_METHODS = HTTP_METHODS

    def finalize(self, *args, **kwargs):
        super().finalize(*args, **kwargs)

        for route in self.dynamic_routes.values():
            if any(
                label.startswith("__") and label not in ALLOWED_LABELS
                for label in route.labels
            ):
                raise SanicException(
                    f"Invalid route: {route}. Parameter names cannot use '__'."
                )


import types
from importlib.util import module_from_spec, spec_from_file_location
from os import environ as os_environ
from pathlib import Path
from re import findall as re_findall
from typing import Union
from sanic.exceptions import LoadFileException, PyFileError
from sanic.helpers import import_string

def str_to_bool(val: str) -> bool:
    """Takes string and tries to turn it into bool as human would do.

    If val is in case insensitive (
        "y", "yes", "yep", "yup", "t",
        "true", "on", "enable", "enabled", "1"
    ) returns True.
    If val is in case insensitive (
        "n", "no", "f", "false", "off", "disable", "disabled", "0"
    ) returns False.
    Else Raise ValueError."""

    val = val.lower()
    if val in {
        "y",
        "yes",
        "yep",
        "yup",
        "t",
        "true",
        "on",
        "enable",
        "enabled",
        "1",
    }:
        return True
    elif val in {"n", "no", "f", "false", "off", "disable", "disabled", "0"}:
        return False
    else:
        raise ValueError(f"Invalid truth value {val}")


import types
from importlib.util import module_from_spec, spec_from_file_location
from os import environ as os_environ
from pathlib import Path
from re import findall as re_findall
from typing import Union
from sanic.exceptions import LoadFileException, PyFileError
from sanic.helpers import import_string

def load_module_from_file_location(
    location: Union[bytes, str, Path], encoding: str = "utf8", *args, **kwargs
):  # noqa
    """Returns loaded module provided as a file path.

    :param args:
        Coresponds to importlib.util.spec_from_file_location location
        parameters,but with this differences:
        - It has to be of a string or bytes type.
        - You can also use here environment variables
          in format ${some_env_var}.
          Mark that $some_env_var will not be resolved as environment variable.
    :encoding:
        If location parameter is of a bytes type, then use this encoding
        to decode it into string.
    :param args:
        Coresponds to the rest of importlib.util.spec_from_file_location
        parameters.
    :param kwargs:
        Coresponds to the rest of importlib.util.spec_from_file_location
        parameters.

    For example You can:

        some_module = load_module_from_file_location(
            "some_module_name",
            "/some/path/${some_env_var}"
        )
    """
    if isinstance(location, bytes):
        location = location.decode(encoding)

    if isinstance(location, Path) or "/" in location or "$" in location:

        if not isinstance(location, Path):
            # A) Check if location contains any environment variables
            #    in format ${some_env_var}.
            env_vars_in_location = set(re_findall(r"\${(.+?)}", location))

            # B) Check these variables exists in environment.
            not_defined_env_vars = env_vars_in_location.difference(
                os_environ.keys()
            )
            if not_defined_env_vars:
                raise LoadFileException(
                    "The following environment variables are not set: "
                    f"{', '.join(not_defined_env_vars)}"
                )

            # C) Substitute them in location.
            for env_var in env_vars_in_location:
                location = location.replace(
                    "${" + env_var + "}", os_environ[env_var]
                )

        location = str(location)
        if ".py" in location:
            name = location.split("/")[-1].split(".")[
                0
            ]  # get just the file name without path and .py extension
            _mod_spec = spec_from_file_location(
                name, location, *args, **kwargs
            )
            module = module_from_spec(_mod_spec)
            _mod_spec.loader.exec_module(module)  # type: ignore

        else:
            module = types.ModuleType("config")
            module.__file__ = str(location)
            try:
                with open(location) as config_file:
                    exec(  # nosec
                        compile(config_file.read(), location, "exec"),
                        module.__dict__,
                    )
            except IOError as e:
                e.strerror = "Unable to load configuration file (e.strerror)"
                raise
            except Exception as e:
                raise PyFileError(location) from e

        return module
    else:
        try:
            return import_string(location)
        except ValueError:
            raise IOError("Unable to load configuration %s" % str(location))


import os
from typing import Callable
from semantic_release.errors import CiVerificationError

def checker(func: Callable) -> Callable:
    """
    A decorator that will convert AssertionErrors into
    CiVerificationError.

    :param func: A function that will raise AssertionError
    :return: The given function wrapped to raise a CiVerificationError on AssertionError
    """

    def func_wrapper(*args, **kwargs):
        try:
            func(*args, **kwargs)
            return True
        except AssertionError:
            raise CiVerificationError(
                "The verification check for the environment did not pass."
            )

    return func_wrapper


import os
from typing import Callable
from semantic_release.errors import CiVerificationError

def check(branch: str = "master"):
    """
    Detects the current CI environment, if any, and performs necessary
    environment checks.

    :param branch: The branch that should be the current branch.
    """
    if os.environ.get("TRAVIS") == "true":
        travis(branch)
    elif os.environ.get("SEMAPHORE") == "true":
        semaphore(branch)
    elif os.environ.get("FRIGG") == "true":
        frigg(branch)
    elif os.environ.get("CIRCLECI") == "true":
        circle(branch)
    elif os.environ.get("GITLAB_CI") == "true":
        gitlab(branch)
    elif os.environ.get("JENKINS_URL") is not None:
        jenkins(branch)
    elif "BITBUCKET_BUILD_NUMBER" in os.environ:
        bitbucket(branch)


import logging
from invoke import run
from .settings import config

logger = logging.getLogger(__name__)

def should_build():
    upload_pypi = config.get("upload_to_pypi")
    upload_release = config.get("upload_to_release")
    build_command = config.get("build_command")
    build_command = build_command if build_command != "false" else False
    return bool(build_command and (upload_pypi or upload_release))


import logging
from invoke import run
from .settings import config

logger = logging.getLogger(__name__)

def should_remove_dist():
    remove_dist = config.get("remove_dist")
    return bool(remove_dist and should_build())


import functools
from typing import Union
from requests import Session
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

def build_requests_session(
    raise_for_status=True, retry: Union[bool, int, Retry] = True
) -> Session:
    """
    Create a requests session.
    :param raise_for_status: If True, a hook to invoke raise_for_status be installed
    :param retry: If true, it will use default Retry configuration. if an integer, it will use default Retry
    configuration with given integer as total retry count. if Retry instance, it will use this instance.
    :return: configured requests Session
    """
    session = Session()
    if raise_for_status:
        session.hooks = {"response": [lambda r, *args, **kwargs: r.raise_for_status()]}
    if retry:
        if isinstance(retry, bool):
            retry = Retry()
        elif isinstance(retry, int):
            retry = Retry(retry)
        elif not isinstance(retry, Retry):
            raise ValueError("retry should be a bool, int or Retry instance.")
        adapter = HTTPAdapter(max_retries=retry)
        session.mount("http://", adapter)
        session.mount("https://", adapter)
    return session


import functools
from typing import Union
from requests import Session
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

class LoggedFunction:

    def __init__(self, logger):
        self.logger = logger

    def __call__(self, func):
        @functools.wraps(func)
        def logged_func(*args, **kwargs):
            # Log function name and arguments
            self.logger.debug(
                "{function}({args}{kwargs})".format(
                    function=func.__name__,
                    args=", ".join([format_arg(x) for x in args]),
                    kwargs="".join(
                        [f", {k}={format_arg(v)}" for k, v in kwargs.items()]
                    ),
                )
            )

            # Call function
            result = func(*args, **kwargs)

            # Log result
            if result is not None:
                self.logger.debug(f"{func.__name__} -> {result}")
            return result

        return logged_func


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class TokenAuth(AuthBase):

    def __init__(self, token):
        self.token = token

    def __call__(self, r):
        r.headers["Authorization"] = f"token {self.token}"
        return r


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class Github(Base):

    DEFAULT_DOMAIN = "github.com"

    @staticmethod
    def domain() -> str:
        """Github domain property

        :return: The Github domain
        """
        hvcs_domain = config.get("hvcs_domain")
        domain = hvcs_domain if hvcs_domain else Github.DEFAULT_DOMAIN
        return domain


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class Github(Base):

    DEFAULT_DOMAIN = "github.com"

    @staticmethod
    def api_url() -> str:
        """Github api_url property

        :return: The Github API URL
        """
        # not necessarily prefixed with api in the case of a custom domain, so
        # can't just default DEFAULT_DOMAIN to github.com
        hvcs_domain = config.get("hvcs_domain")
        hostname = hvcs_domain if hvcs_domain else "api." + Github.DEFAULT_DOMAIN
        return f"https://{hostname}"


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class TokenAuth(AuthBase):

    def __init__(self, token):
        self.token = token

class Github(Base):

    DEFAULT_DOMAIN = "github.com"

    @staticmethod
    def auth() -> Optional[TokenAuth]:
        """Github token property

        :return: The Github token environment variable (GH_TOKEN) value
        """
        token = Github.token()
        if not token:
            return None
        return TokenAuth(token)


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class Github(Base):

    DEFAULT_DOMAIN = "github.com"

    @staticmethod
    @LoggedFunction(logger)
    def check_build_status(owner: str, repo: str, ref: str) -> bool:
        """Check build status

        https://docs.github.com/rest/reference/repos#get-the-combined-status-for-a-specific-reference

        :param owner: The owner namespace of the repository
        :param repo: The repository name
        :param ref: The sha1 hash of the commit ref

        :return: Was the build status success?
        """
        url = "{domain}/repos/{owner}/{repo}/commits/{ref}/status"
        try:
            response = Github.session().get(
                url.format(domain=Github.api_url(), owner=owner, repo=repo, ref=ref)
            )
            return response.json().get("state") == "success"
        except HTTPError as e:
            logger.warning(f"Build status check on Github has failed: {e}")
            return False


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class Gitlab(Base):

    @staticmethod
    def domain() -> str:
        """Gitlab domain property

        :return: The Gitlab instance domain
        """
        domain = config.get("hvcs_domain", os.environ.get("CI_SERVER_HOST"))
        return domain if domain else "gitlab.com"


import logging
import mimetypes
import os
from typing import Optional, Union
import gitlab
from requests import HTTPError, Session
from requests.auth import AuthBase
from urllib3 import Retry
from .errors import ImproperConfigurationError
from .helpers import LoggedFunction, build_requests_session
from .settings import config

logger = logging.getLogger(__name__)

class Gitlab(Base):

    @staticmethod
    @LoggedFunction(logger)
    def check_build_status(owner: str, repo: str, ref: str) -> bool:
        """Check last build status

        :param owner: The owner namespace of the repository. It includes all groups and subgroups.
        :param repo: The repository name
        :param ref: The sha1 hash of the commit ref

        :return: the status of the pipeline (False if a job failed)
        """
        gl = gitlab.Gitlab(Gitlab.api_url(), private_token=Gitlab.token())
        gl.auth()
        jobs = gl.projects.get(owner + "/" + repo).commits.get(ref).statuses.list()
        for job in jobs:
            if job["status"] not in ["success", "skipped"]:
                if job["status"] == "pending":
                    logger.debug(
                        f"check_build_status: job {job['name']} is still in pending status"
                    )
                    return False
                elif job["status"] == "failed" and not job["allow_failure"]:
                    logger.debug(f"check_build_status: job {job['name']} failed")
                    return False
        return True


import configparser
import importlib
import logging
import os
from collections import UserDict
from functools import wraps
from os import getcwd
from typing import Callable, List
import tomlkit
from tomlkit.exceptions import TOMLKitError
from .errors import ImproperConfigurationError

logger = logging.getLogger(__name__)
config = _config()

def current_commit_parser() -> Callable:
    """Get the currently-configured commit parser

    :raises ImproperConfigurationError: if ImportError or AttributeError is raised
    :returns: Commit parser
    """

    try:
        # All except the last part is the import path
        parts = config.get("commit_parser").split(".")
        module = ".".join(parts[:-1])
        # The final part is the name of the parse function
        return getattr(importlib.import_module(module), parts[-1])
    except (ImportError, AttributeError) as error:
        raise ImproperConfigurationError(f'Unable to import parser "{error}"')


import configparser
import importlib
import logging
import os
from collections import UserDict
from functools import wraps
from os import getcwd
from typing import Callable, List
import tomlkit
from tomlkit.exceptions import TOMLKitError
from .errors import ImproperConfigurationError

logger = logging.getLogger(__name__)
config = _config()

def current_changelog_components() -> List[Callable]:
    """Get the currently-configured changelog components

    :raises ImproperConfigurationError: if ImportError or AttributeError is raised
    :returns: List of component functions
    """
    component_paths = config.get("changelog_components").split(",")
    components = list()

    for path in component_paths:
        try:
            # All except the last part is the import path
            parts = path.split(".")
            module = ".".join(parts[:-1])
            # The final part is the name of the component function
            components.append(getattr(importlib.import_module(module), parts[-1]))
        except (ImportError, AttributeError) as error:
            raise ImproperConfigurationError(
                f'Unable to import changelog component "{path}"'
            )

    return components


import configparser
import importlib
import logging
import os
from collections import UserDict
from functools import wraps
from os import getcwd
from typing import Callable, List
import tomlkit
from tomlkit.exceptions import TOMLKitError
from .errors import ImproperConfigurationError

logger = logging.getLogger(__name__)
config = _config()

def overload_configuration(func):
    """This decorator gets the content of the "define" array and edits "config"
    according to the pairs of key/value.
    """

    @wraps(func)
    def wrap(*args, **kwargs):
        if "define" in kwargs:
            for defined_param in kwargs["define"]:
                pair = defined_param.split("=", maxsplit=1)
                if len(pair) == 2:
                    config[str(pair[0])] = pair[1]
        return func(*args, **kwargs)

    return wrap


import binascii
import os
import random
import string
from typing import Generator
from uuid import uuid4
from .manipulation import roman_encode

__all__ = [
    'uuid',
    'random_string',
    'secure_random_hex',
    'roman_range',
]

def roman_range(stop: int, start: int = 1, step: int = 1) -> Generator:
    """
    Similarly to native Python's `range()`, returns a Generator object which generates a new roman number
    on each iteration instead of an integer.

    *Example:*

    >>> for n in roman_range(7): print(n)
    >>> # prints: I, II, III, IV, V, VI, VII
    >>> for n in roman_range(start=7, stop=1, step=-1): print(n)
    >>> # prints: VII, VI, V, IV, III, II, I

    :param stop: Number at which the generation must stop (must be <= 3999).
    :param start: Number at which the generation must start (must be >= 1).
    :param step: Increment of each generation step (default to 1).
    :return: Generator of roman numbers.
    """

    def validate(arg_value, arg_name, allow_negative=False):
        msg = '"{}" must be an integer in the range 1-3999'.format(arg_name)

        if not isinstance(arg_value, int):
            raise ValueError(msg)

        if allow_negative:
            arg_value = abs(arg_value)

        if arg_value < 1 or arg_value > 3999:
            raise ValueError(msg)

    def generate():
        current = start

        # generate values for each step
        while current != stop:
            yield roman_encode(current)
            current += step

        # last value to return
        yield roman_encode(current)

    # checks each single argument value
    validate(stop, 'stop')
    validate(start, 'start')
    validate(step, 'step', allow_negative=True)

    # checks if the provided configuration leads to a feasible iteration with respect to boundaries or not
    forward_exceed = step > 0 and (start > stop or start + step > stop)
    backward_exceed = step < 0 and (start < stop or start + step < stop)
    if forward_exceed or backward_exceed:
        raise OverflowError('Invalid start/stop/step configuration')

    return generate()


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def reverse(input_string: str) -> str:
    """
    Returns the string with its chars reversed.

    *Example:*

    >>> reverse('hello') # returns 'olleh'

    :param input_string: String to revert.
    :type input_string: str
    :return: Reversed string.
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    return input_string[::-1]


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def camel_case_to_snake(input_string, separator='_'):
    """
    Convert a camel case string into a snake case one.
    (The original string is returned if is not a valid camel case string)

    *Example:*

    >>> camel_case_to_snake('ThisIsACamelStringTest') # returns 'this_is_a_camel_case_string_test'

    :param input_string: String to convert.
    :type input_string: str
    :param separator: Sign to use as separator.
    :type separator: str
    :return: Converted string.
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    if not is_camel_case(input_string):
        return input_string

    return CAMEL_CASE_REPLACE_RE.sub(lambda m: m.group(1) + separator, input_string).lower()


import base64
import random
import unicodedata
import zlib
from typing import Union
from uuid import uuid4
from ._regex import *
from .errors import InvalidInputError
from .validation import is_snake_case, is_full_string, is_camel_case, is_integer, is_string

__all__ = [
    'camel_case_to_snake',
    'snake_case_to_camel',
    'reverse',
    'shuffle',
    'strip_html',
    'prettify',
    'asciify',
    'slugify',
    'booleanize',
    'strip_margin',
    'compress',
    'decompress',
    'roman_encode',
    'roman_decode',
]

def snake_case_to_camel(input_string: str, upper_case_first: bool = True, separator: str = '_') -> str:
    """
    Convert a snake case string into a camel case one.
    (The original string is returned if is not a valid snake case string)

    *Example:*

    >>> snake_case_to_camel('the_snake_is_green') # returns 'TheSnakeIsGreen'

    :param input_string: String to convert.
    :type input_string: str
    :param upper_case_first: True to turn the first letter into uppercase (default).
    :type upper_case_first: bool
    :param separator: Sign to use as separator (default to "_").
    :type separator: str
    :return: Converted string
    """
    if not is_string(input_string):
        raise InvalidInputError(input_string)

    if not is_snake_case(input_string, separator):
        return input_string

    tokens = [s.title() for s in input_string.split(separator) if is_full_string(s)]

    if not upper_case_first:
        tokens[0] = tokens[0].lower()

    out = ''.join(tokens)

    return out