
    ga                        d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	m
Z
mZ ddlmZ ddlmZmZmZmZ dd	lmZmZmZmZmZmZmZmZmZ  G d
 dej:                        Z G d de      Z G d dej@                        Z! G d dej@                        Z"eedee   eee#df   ef   eee#df   eee#ef   f   eee#df   eee#ef   e#f   f      Z$ G d de      Z% G d dee%      Z& G d de'      Z( G d de'      Z) G d de)      Z* G d de)      Z+ G d de)      Z, G d  d!e)      Z- G d" d#e(      Z.ed$e#d%e/fd&       Z0ed)d'       Z0d$ee#   d%ee/   fd(Z0y)*ap  Flexible routing implementation.

Tornado routes HTTP requests to appropriate handlers using `Router`
class implementations. The `tornado.web.Application` class is a
`Router` implementation and may be used directly, or the classes in
this module may be used for additional flexibility. The `RuleRouter`
class can match on more criteria than `.Application`, or the `Router`
interface can be subclassed for maximum customization.

`Router` interface extends `~.httputil.HTTPServerConnectionDelegate`
to provide additional routing capabilities. This also means that any
`Router` implementation can be used directly as a ``request_callback``
for `~.httpserver.HTTPServer` constructor.

`Router` subclass must implement a ``find_handler`` method to provide
a suitable `~.httputil.HTTPMessageDelegate` instance to handle the
request:

.. code-block:: python

    class CustomRouter(Router):
        def find_handler(self, request, **kwargs):
            # some routing logic providing a suitable HTTPMessageDelegate instance
            return MessageDelegate(request.connection)

    class MessageDelegate(HTTPMessageDelegate):
        def __init__(self, connection):
            self.connection = connection

        def finish(self):
            self.connection.write_headers(
                ResponseStartLine("HTTP/1.1", 200, "OK"),
                HTTPHeaders({"Content-Length": "2"}),
                b"OK")
            self.connection.finish()

    router = CustomRouter()
    server = HTTPServer(router)

The main responsibility of `Router` implementation is to provide a
mapping from a request to `~.httputil.HTTPMessageDelegate` instance
that will handle this request. In the example above we can see that
routing is possible even without instantiating an `~.web.Application`.

For routing to `~.web.RequestHandler` implementations we need an
`~.web.Application` instance. `~.web.Application.get_handler_delegate`
provides a convenient way to create `~.httputil.HTTPMessageDelegate`
for a given request and `~.web.RequestHandler`.

Here is a simple example of how we can we route to
`~.web.RequestHandler` subclasses by HTTP method:

.. code-block:: python

    resources = {}

    class GetResource(RequestHandler):
        def get(self, path):
            if path not in resources:
                raise HTTPError(404)

            self.finish(resources[path])

    class PostResource(RequestHandler):
        def post(self, path):
            resources[path] = self.request.body

    class HTTPMethodRouter(Router):
        def __init__(self, app):
            self.app = app

        def find_handler(self, request, **kwargs):
            handler = GetResource if request.method == "GET" else PostResource
            return self.app.get_handler_delegate(request, handler, path_args=[request.path])

    router = HTTPMethodRouter(Application())
    server = HTTPServer(router)

`ReversibleRouter` interface adds the ability to distinguish between
the routes and reverse them to the original urls using route's name
and additional arguments. `~.web.Application` is itself an
implementation of `ReversibleRouter` class.

`RuleRouter` and `ReversibleRuleRouter` are implementations of
`Router` and `ReversibleRouter` interfaces and can be used for
creating rule-based routing configurations.

Rules are instances of `Rule` class. They contain a `Matcher`, which
provides the logic for determining whether the rule is a match for a
particular request and a target, which can be one of the following.

1) An instance of `~.httputil.HTTPServerConnectionDelegate`:

.. code-block:: python

    router = RuleRouter([
        Rule(PathMatches("/handler"), ConnectionDelegate()),
        # ... more rules
    ])

    class ConnectionDelegate(HTTPServerConnectionDelegate):
        def start_request(self, server_conn, request_conn):
            return MessageDelegate(request_conn)

2) A callable accepting a single argument of `~.httputil.HTTPServerRequest` type:

.. code-block:: python

    router = RuleRouter([
        Rule(PathMatches("/callable"), request_callable)
    ])

    def request_callable(request):
        request.write(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK")
        request.finish()

3) Another `Router` instance:

.. code-block:: python

    router = RuleRouter([
        Rule(PathMatches("/router.*"), CustomRouter())
    ])

Of course a nested `RuleRouter` or a `~.web.Application` is allowed:

.. code-block:: python

    router = RuleRouter([
        Rule(HostMatches("example.com"), RuleRouter([
            Rule(PathMatches("/app1/.*"), Application([(r"/app1/handler", Handler)])),
        ]))
    ])

    server = HTTPServer(router)

In the example below `RuleRouter` is used to route between applications:

.. code-block:: python

    app1 = Application([
        (r"/app1/handler", Handler1),
        # other handlers ...
    ])

    app2 = Application([
        (r"/app2/handler", Handler2),
        # other handlers ...
    ])

    router = RuleRouter([
        Rule(PathMatches("/app1.*"), app1),
        Rule(PathMatches("/app2.*"), app2)
    ])

    server = HTTPServer(router)

For more information on application-level routing see docs for `~.web.Application`.

.. versionadded:: 4.5

    N)partial)httputil)_CallableAdapter)
url_escapeurl_unescapeutf8)app_log)basestring_typeimport_objectre_unescapeunicode_type)	AnyUnionOptional	AwaitableListDictPatternTupleoverloadc                       e Zd ZdZdej
                  dedeej                     fdZ	de
dej                  dej                  fdZy	)
RouterzAbstract router interface.requestkwargsreturnc                     t               )a  Must be implemented to return an appropriate instance of `~.httputil.HTTPMessageDelegate`
        that can serve the request.
        Routing implementations may pass additional kwargs to extend the routing logic.

        :arg httputil.HTTPServerRequest request: current HTTP request.
        :arg kwargs: additional keyword arguments passed by routing implementation.
        :returns: an instance of `~.httputil.HTTPMessageDelegate` that will be used to
            process the request.
        NotImplementedError)selfr   r   s      D/var/www/openai/venv/lib/python3.12/site-packages/tornado/routing.pyfind_handlerzRouter.find_handler   s     "##    server_connrequest_connc                     t        | ||      S N)_RoutingDelegate)r   r#   r$   s      r    start_requestzRouter.start_request   s      k<@@r"   N)__name__
__module____qualname____doc__r   HTTPServerRequestr   r   HTTPMessageDelegater!   objectHTTPConnectionr(    r"   r    r   r      s`    $$11$=@$	(..	/$A!A191H1HA		%	%Ar"   r   c                   *    e Zd ZdZdededee   fdZy)ReversibleRouterzxAbstract router interface for routers that can handle named routes
    and support reversing them to original urls.
    nameargsr   c                     t               )a  Returns url string for a given route name and arguments
        or ``None`` if no match is found.

        :arg str name: route name.
        :arg args: url parameters.
        :returns: parametrized url string for a given route name (or ``None``).
        r   )r   r4   r5   s      r    reverse_urlzReversibleRouter.reverse_url   s     "##r"   N)r)   r*   r+   r,   strr   r   r7   r1   r"   r    r3   r3      s%    $ $C $HSM $r"   r3   c                       e Zd Zdededej                  ddfdZdeej                  ej                  f   dej                  deed      fd	Zd
edeed      fdZddZddZy)r'   routerr#   r$   r   Nc                 <    || _         || _        d | _        || _        y r&   )r#   r$   delegater:   )r   r:   r#   r$   s       r    __init__z_RoutingDelegate.__init__   s"     '(r"   
start_lineheadersc                    t        |t        j                        sJ t        j                  | j                  | j
                  ||      }| j                  j                  |      | _        | j                  Et        j                  d|j                  |j                         t        | j                        | _        | j                  j                  ||      S )N)
connectionserver_connectionr>   r?   z$Delegate for %s %s request not found)
isinstancer   RequestStartLiner-   r$   r#   r:   r!   r<   r	   debugmethodpath_DefaultMessageDelegateheaders_received)r   r>   r?   r   s       r    rI   z!_RoutingDelegate.headers_received   s    
 *h&?&?@@@,,(("..!	
 009== MM6!!
 4D4E4EFDM}}--j'BBr"   chunkc                 T    | j                   J | j                   j                  |      S r&   )r<   data_received)r   rJ   s     r    rL   z_RoutingDelegate.data_received  s'    }}(((}}**511r"   c                 T    | j                   J | j                   j                          y r&   )r<   finishr   s    r    rN   z_RoutingDelegate.finish
  s"    }}(((r"   c                 T    | j                   J | j                   j                          y r&   )r<   on_connection_closerO   s    r    rQ   z$_RoutingDelegate.on_connection_close  s"    }}((())+r"   r   N)r)   r*   r+   r   r/   r   r0   r=   r   rD   ResponseStartLineHTTPHeadersr   r   rI   bytesrL   rN   rQ   r1   r"   r    r'   r'      s    +1AIAXAX	C(33X5O5OOPC %%C 
)D/	"	C025 2Xio-F 2,r"   r'   c                   8    e Zd Zdej                  ddfdZddZy)rH   rA   r   Nc                     || _         y r&   )rA   )r   rA   s     r    r=   z _DefaultMessageDelegate.__init__  s	    $r"   c                     | j                   j                  t        j                  ddd      t        j                                | j                   j                          y )NzHTTP/1.1i  z	Not Found)rA   write_headersr   rS   rT   rN   rO   s    r    rN   z_DefaultMessageDelegate.finish  sD    %%&&z3D  "	
 	 r"   rR   )r)   r*   r+   r   r0   r=   rN   r1   r"   r    rH   rH     s     %8#:#: %t %!r"   rH   RuleMatcherc            	           e Zd ZdZddee   ddfdZdeddfdZddZde	j                  d	edee	j                     fd
Zdede	j                  dedee	j                     fdZy)
RuleRouterz!Rule-based router implementation.Nrulesr   c                 :    g | _         |r| j                  |       yy)aI  Constructs a router from an ordered list of rules::

            RuleRouter([
                Rule(PathMatches("/handler"), Target),
                # ... more rules
            ])

        You can also omit explicit `Rule` constructor and use tuples of arguments::

            RuleRouter([
                (PathMatches("/handler"), Target),
            ])

        `PathMatches` is a default matcher, so the example above can be simplified::

            RuleRouter([
                ("/handler", Target),
            ])

        In the examples above, ``Target`` can be a nested `Router` instance, an instance of
        `~.httputil.HTTPServerConnectionDelegate` or an old-style callable,
        accepting a request argument.

        :arg rules: a list of `Rule` instances or tuples of `Rule`
            constructor arguments.
        N)r^   	add_rules)r   r^   s     r    r=   zRuleRouter.__init__/  s    6 
NN5! r"   c                    |D ]  }t        |t        t        f      rFt        |      dv sJ t        |d   t              rt        t        |d         g|dd  }nt        | }| j                  j                  | j                  |              y)zAppends new rules to the router.

        :arg rules: a list of Rule instances (or tuples of arguments, which are
            passed to Rule constructor).
        )         r      N)
rC   tuplelistlenr
   rZ   PathMatchesr^   appendprocess_rule)r   r^   rules      r    r`   zRuleRouter.add_rulesN  s     D$.4yI---d1g7DG 4@tABx@D;DJJd//56 r"   c                     |S )zOverride this method for additional preprocessing of each rule.

        :arg Rule rule: a rule to be processed.
        :returns: the same or modified Rule instance.
        r1   )r   rl   s     r    rk   zRuleRouter.process_rule^  s	     r"   r   r   c                     | j                   D ]_  }|j                  j                  |      }|!|j                  r|j                  |d<    | j                  |j
                  |fi |}|]|c S  y )Ntarget_kwargs)r^   matchermatchro   get_target_delegatetarget)r   r   r   rl   target_paramsr<   s         r    r!   zRuleRouter.find_handlerf  sz     JJD LL..w7M(%%595G5GM/23433KK,9 '#O  r"   rs   rt   c                 X   t        |t              r |j                  |fi |S t        |t        j                        r4|j
                  J |j                  |j                  |j
                        S t        |      r.|j
                  J t        t        |fi ||j
                        S y)a  Returns an instance of `~.httputil.HTTPMessageDelegate` for a
        Rule's target. This method is called by `~.find_handler` and can be
        extended to provide additional target types.

        :arg target: a Rule's target.
        :arg httputil.HTTPServerRequest request: current request.
        :arg target_params: additional parameters that can be useful
            for `~.httputil.HTTPMessageDelegate` creation.
        N)rC   r   r!   r   HTTPServerConnectionDelegaterA   r(   rB   callabler   r   )r   rs   r   rt   s       r    rr   zRuleRouter.get_target_delegatex  s     ff%&6&&w@-@@ E EF%%111''(A(A7CUCUVVf%%111#0-0'2D2D  r"   r&   rl   rZ   r   rZ   )r)   r*   r+   r,   r   	_RuleListr=   r`   rk   r   r-   r   r.   r!   rr   r1   r"   r    r]   r]   ,  s    +"hy1 "T ">7y 7T 7 11=@	(..	/$$,$>$>QT	(..	/r"   r]   c                   Z     e Zd ZdZd
dee   ddf fdZd fdZdede	dee   fd	Z
 xZS )ReversibleRuleRoutera  A rule-based router that implements ``reverse_url`` method.

    Each rule added to this router may have a ``name`` attribute that can be
    used to reconstruct an original uri. The actual reconstruction takes place
    in a rule's matcher (see `Matcher.reverse`).
    Nr^   r   c                 2    i | _         t        | 	  |       y r&   )named_rulessuperr=   )r   r^   	__class__s     r    r=   zReversibleRuleRouter.__init__  s    r"   c                     t         |   |      }|j                  rQ|j                  | j                  v r t	        j
                  d|j                         || j                  |j                  <   |S )Nz4Multiple handlers named %s; replacing previous value)r~   rk   r4   r}   r	   warning)r   rl   r   s     r    rk   z!ReversibleRuleRouter.process_rule  s[    w#D)99yyD,,,JDII +/DTYY'r"   r4   r5   c                 
   || j                   v r& | j                   |   j                  j                  | S | j                  D ]@  }t	        |j
                  t              s |j
                  j                  |g| }|>|c S  y r&   )r}   rp   reverser^   rC   rs   r3   r7   )r   r4   r5   rl   reversed_urls        r    r7   z ReversibleRuleRouter.reverse_url  s}    4###94##D)11994@@JJD$++'786t{{66tCdC+''	  r"   r&   rx   )r)   r*   r+   r,   r   ry   r=   rk   r8   r   r7   __classcell__r   s   @r    r{   r{     sC     hy1  T  

 
C 
HSM 
r"   r{   c                   j    e Zd ZdZ	 	 ddddedeeeef      dee   ddf
d	Zd
edee   fdZ	defdZ
y)rZ   zA routing rule.Nrp   r[   rs   ro   r4   r   c                 z    t        |t              rt        |      }|| _        || _        |r|ni | _        || _        y)ad  Constructs a Rule instance.

        :arg Matcher matcher: a `Matcher` instance used for determining
            whether the rule should be considered a match for a specific
            request.
        :arg target: a Rule's target (typically a ``RequestHandler`` or
            `~.httputil.HTTPServerConnectionDelegate` subclass or even a nested `Router`,
            depending on routing implementation).
        :arg dict target_kwargs: a dict of parameters that can be useful
            at the moment of target instantiation (for example, ``status_code``
            for a ``RequestHandler`` subclass). They end up in
            ``target_params['target_kwargs']`` of `RuleRouter.get_target_delegate`
            method.
        :arg str name: the name of the rule that can be used to find it
            in `ReversibleRouter.reverse_url` implementation.
        N)rC   r8   r   rp   rs   ro   r4   )r   rp   rs   ro   r4   s        r    r=   zRule.__init__  s;    . fc" #6*F.;]	r"   r5   c                 4     | j                   j                  | S r&   )rp   r   r   r5   s     r    r   zRule.reverse  s    #t||##T**r"   c           
          | j                   j                  d| j                  d| j                  d| j                  d| j
                  d
S N(z, z	, kwargs=z, name=))r   r)   rp   rs   ro   r4   rO   s    r    __repr__zRule.__repr__  s7    NN##LLKKII
 	
r"   NN)r)   r*   r+   r,   r   r   r   r8   r=   r   r   r1   r"   r    rZ   rZ     sw     37"   S#X/	
 sm 
B+S +Xc] +
# 
r"   c                   Z    e Zd ZdZdej
                  deeee	f      fdZ
de	dee   fdZy)r[   z*Represents a matcher for request features.r   r   c                     t               )a1  Matches current instance against the request.

        :arg httputil.HTTPServerRequest request: current HTTP request
        :returns: a dict of parameters to be passed to the target handler
            (for example, ``handler_kwargs``, ``path_args``, ``path_kwargs``
            can be passed for proper `~.web.RequestHandler` instantiation).
            An empty dict is a valid (and common) return value to indicate a match
            when the argument-passing features are not used.
            ``None`` must be returned to indicate that there is no match.r   r   r   s     r    rq   zMatcher.match  s     "##r"   r5   c                      y)zEReconstructs full url from matcher instance and additional arguments.Nr1   r   s     r    r   zMatcher.reverse  s    r"   N)r)   r*   r+   r,   r   r-   r   r   r8   r   rq   r   r1   r"   r    r[   r[     sB    4
$X77 
$HT#s(^<T 
$S Xc] r"   c                   D    e Zd ZdZdej
                  deeee	f      fdZ
y)
AnyMatcheszMatches any request.r   r   c                     i S r&   r1   r   s     r    rq   zAnyMatches.match  s    	r"   N)r)   r*   r+   r,   r   r-   r   r   r8   r   rq   r1   r"   r    r   r     s+    X77 HT#s(^<T r"   r   c                   ^    e Zd ZdZdeeef   ddfdZdej                  de
eeef      fdZy)HostMatchesz@Matches requests from hosts specified by ``host_pattern`` regex.host_patternr   Nc                     t        |t              r1|j                  d      s|dz  }t        j                  |      | _        y || _        y )N$)rC   r
   endswithrecompiler   )r   r   s     r    r=   zHostMatches.__init__  s=    lO4((-# "

< 8D ,Dr"   r   c                 R    | j                   j                  |j                        ri S y r&   )r   rq   	host_namer   s     r    rq   zHostMatches.match  s$    ""7#4#45Ir"   )r)   r*   r+   r,   r   r8   r   r=   r   r-   r   r   r   rq   r1   r"   r    r   r     sG    J-U3<%8 -T -X77 HT#s(^<T r"   r   c                   X    e Zd ZdZdededdfdZdej                  de	e
eef      fdZy)	DefaultHostMatcheszMatches requests from host that is equal to application's default_host.
    Always returns no match if ``X-Real-Ip`` header is present.
    applicationr   r   Nc                      || _         || _        y r&   )r   r   )r   r   r   s      r    r=   zDefaultHostMatches.__init__  s    &(r"   r   c                     d|j                   vr1| j                  j                  | j                  j                        ri S y )Nz	X-Real-Ip)r?   r   rq   r   default_hostr   s     r    rq   zDefaultHostMatches.match   s6    goo-  &&t'7'7'D'DE	r"   )r)   r*   r+   r,   r   r   r=   r   r-   r   r   r8   rq   r1   r"   r    r   r     sG    )C )w )4 )X77 HT#s(^<T r"   r   c                       e Zd ZdZdeeef   ddfdZdej                  de
eeef      fdZdede
e   fd	Zdee
e   e
e   f   fd
Zy)ri   z@Matches requests with paths specified by ``path_pattern`` regex.path_patternr   Nc                 x   t        |t              r1|j                  d      s|dz  }t        j                  |      | _        n|| _        t        | j
                  j                        d| j
                  j                  fv sJ d| j
                  j                  z         | j                         \  | _        | _        y )Nr   r   zDgroups in url regexes must either be all named or all positional: %r)rC   r
   r   r   r   regexrh   
groupindexgroupspattern_find_groups_path_group_count)r   r   s     r    r=   zPathMatches.__init__+  s    lO4((-#L1DJ%DJ4::(()a1B1B-CC 	
#zz112	
C
 )-(9(9(;%
D%r"   r   c                    | j                   j                  |j                        }|y | j                   j                  si S g }i }| j                   j                  r/t        d |j                         j                         D              }n&|j                         D cg c]  }t        |       }}t        ||      S c c}w )Nc              3   N   K   | ]  \  }}t        |      t        |      f  y wr&   )r8   _unquote_or_none).0kvs      r    	<genexpr>z$PathMatches.match.<locals>.<genexpr>I  s(      <U&1aQ)!,-<Us   #%)	path_argspath_kwargs)	r   rq   rG   r   r   dict	groupdictitemsr   )r   r   rq   r   r   ss         r    rq   zPathMatches.match:  s    

  .=zz  I	 ::   <AOO<M<S<S<U K 7<llnEn)!,nIEi[AA Fs   B=r5   c                    | j                   "t        d| j                  j                  z         t	        |      | j
                  k(  sJ d       t	        |      s| j                   S g }|D ]H  }t        |t        t        f      st        |      }|j                  t        t        |      d             J | j                   t        |      z  S )NzCannot reverse url regex z&required number of arguments not foundF)plus)r   
ValueErrorr   r   rh   r   rC   r   rU   r8   rj   r   r   rf   )r   r5   converted_argsas       r    r   zPathMatches.reverseQ  s    ::84::;M;MMNN4yD--- 	
7	
- 4y::Aa,!67F!!*T!W5"AB  zzE.111r"   c                 T   | j                   j                  }|j                  d      r|dd }|j                  d      r|dd }| j                   j                  |j                  d      k7  ryg }|j                  d      D ]a  }d|v r>|j                  d      }|d	k\  s	 t        ||dz   d       }|j                  d
|z          E	 t        |      }|j                  |       c dj                  |      | j                   j                  fS # t        $ r Y  yw xY w# t        $ r Y  yw xY w)zReturns a tuple (reverse string, group count) for a url.

        For example: Given the url pattern /([0-9]{4})/([a-z-]+)/, this method
        would return ('/%s/%s/', 2).
        ^re   Nr   r   r   r   r   z%s )r   r   
startswithr   r   countsplitindexr   r   rj   join)r   r   piecesfragment	paren_locunescaped_fragments         r    r   zPathMatches._find_groups`  s1    **$$c"abkGC crlG::c 22 c*Hh$NN3/	>,-8)a-/9R-S*
 MM$);";<()4X)>&
 01% +( wwv

 1 111 & ,  ,, " ( ((s$   D
D
	DD	D'&D')r)   r*   r+   r,   r   r8   r   r=   r   r-   r   r   r   rq   r   r   intr   r1   r"   r    ri   ri   (  s    J<U3<%8 <T <BX77 BHT#s(^<T B.2S 2Xc] 2&2eHSM8C=$@A &2r"   ri   c                   j     e Zd ZdZ	 	 d
deeef   dedee	eef      dee   ddf
 fdZ
defd	Z xZS )URLSpeczSpecifies mappings between URLs and handlers.

    .. versionchanged: 4.5
       `URLSpec` is now a subclass of a `Rule` with `PathMatches` matcher and is preserved for
       backwards compatibility.
    Nr   handlerr   r4   r   c                     t        |      }t        | 	  ||||       |j                  | _        | j                  | _        || _        y)a  Parameters:

        * ``pattern``: Regular expression to be matched. Any capturing
          groups in the regex will be passed in to the handler's
          get/post/etc methods as arguments (by keyword if named, by
          position if unnamed. Named and unnamed capturing groups
          may not be mixed in the same rule).

        * ``handler``: `~.web.RequestHandler` subclass to be invoked.

        * ``kwargs`` (optional): A dictionary of additional arguments
          to be passed to the handler's constructor.

        * ``name`` (optional): A name for this handler.  Used by
          `~.web.Application.reverse_url`.

        N)ri   r~   r=   r   rs   handler_classr   )r   r   r   r   r4   rp   r   s         r    r=   zURLSpec.__init__  s@    0 g&'648]]
![[r"   c           
          | j                   j                  d| j                  j                  d| j                  d| j
                  d| j                  d
S r   )r   r)   r   r   r   r   r4   rO   s    r    r   zURLSpec.__repr__  s=    NN##JJKKII
 	
r"   r   )r)   r*   r+   r,   r   r8   r   r   r   r   r=   r   r   r   s   @r    r   r     sk     ,0"sG|$  c3h(	
 sm 
>
# 
r"   r   r   r   c                      y r&   r1   r   s    r    r   r         r"   c                      y r&   r1   r   s    r    r   r     r   r"   c                 &    | | S t        | dd      S )zNone-safe wrapper around url_unescape to handle unmatched optional
    groups correctly.

    Note that args are passed as bytes so the handler can decide what
    encoding to use.
    NF)encodingr   )r   r   s    r    r   r     s     	yDu55r"   )r   Nr   N)1r,   r   	functoolsr   tornador   tornado.httpserverr   tornado.escaper   r   r   tornado.logr	   tornado.utilr
   r   r   r   typingr   r   r   r   r   r   r   r   r   rv   r   r3   r.   r'   rH   r8   ry   r]   r{   r/   rZ   r[   r   r   r   ri   r   rU   r   r1   r"   r    <module>r      s  aF 
   / 9 9  R R X X XAX22 A.$v $ +,x33 +,\	!h:: 	! 	S	eCN#S()eCN#S$sCx.89eCN#S$sCx.#=>		@	e eP"+Z "J.
6 .
bf ( ' $ "^2' ^2B.
d .
b 
	 	 	 
	 
	 
		6 	6(5/ 	6r"   