📄 tools.cpython-312.pyc
/home/palash/git/local-ai/server/features/__pycache__/tools.cpython-312.pyc
Language: pyc • Lines: 896
�

xq�j�]����dZddlZddlZddlZddlZddlmZddlmZm	Z	ddl
Z
ddlmZdZ
dZdZd	Zd
ZdZdZd
ZdZd�Zd�Zd�Zdd�Zd�Zd�Zd�Zd�Zdd�Zd�Zdd�Z d�Z!d�Z"y)zJLLM tool implementations: web search, page fetching, image tools dispatch.�N)�datetime)�	urlencode�urlparse)�M�
�ip�)z	text/htmlz
text/plainzapplication/xhtmlzapplication/jsonzapplication/xmli Ni��g�?c�z�dD]}	|j|�cS|jdd��S#t$rY�6wxYw)N)z	utf-8-sig�utf-8�latin-1r
�replace��errors)�decode�UnicodeDecodeError)�raw�encs  �2/home/palash/git/local-ai/server/features/tools.py�_decode_response_textr,sM��0���	��:�:�c�?�"��
�:�:�i�	�:�2�2��"�	��	�s�.�	:�:c��tjjt|�j�dj	�}|xsdjd�dj
�j	�}|dk(s|dk(s|jd�ry|d	k(s|d
k(ry|dk(s|jd
�ry|dvs|dvry|dk(r|dvr|dk(rdS|d
k(rdSdSy)axClassify fetched content as ``pdf``/``csv``/``excel`` or ``None``.

    Content-Type is trusted first, then the URL extension, then magic bytes.
    Anything unrecognized returns ``None`` so :func:`fetch_page` declines it as
    binary instead of trying to read it. Legacy ``.xls`` (OLE2 compound
    documents) is detected separately since no parser is available for it.
    ���;rzapplication/pdf�.pdfs%PDF-�pdfztext/csv�.csv�csvz.xlss��ࡱ��excel_xls_unsupported)zAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetzapplication/vnd.ms-excelzapplication/excel)�.xlsx�.xlsm�.xltm�.xltx�excelzapplication/octet-stream)rrr r!r"r#N)�os�path�splitextr�lower�split�strip�
startswith)�url�content_typer�ext�ctypes     r�_detect_doc_typer05s���
�'�'�
�
�8�C�=�-�-�
.�q�
1�
7�
7�
9�C�
�
�R�&�&�s�+�A�.�4�4�6�<�<�>�E��!�!�S�F�]�c�n�n�X�6N���
��c�V�m��
�f�}����'J�K�&����

�4�	4��
�*�*�s�7�0��v�
�u�P�S�F�]�E�P��P��c��t|�|kr|gStdt|�|�D�cgc]
}||||z��c}Scc}w)z8Split ``text`` into chunks of up to ``size`` characters.r)�len�range)�text�size�is   r�_chunk_pagesr8^sA��
�4�y�D���v�
�(-�a��T��D�(A�B�1�D��Q��X��B�B��Bs�<c	��|xsdj�xsd}t||�}tdt|dz
t	|�dz
��}||}|r|dz
}|||d�}	|r||	d<t	|�dkDrP|dz|	d<t	|�|	d	<|dzt	|�kr|d
znd|	d<|	drd
t	|��d|d
z�d�nd|	d<tj|	d��S)a�Build the ``fetch_page`` JSON payload.

    Long text is split into chunks of up to ``max_chars`` chars and only chunk
    number ``chunk`` is returned; the payload exposes ``total_chunks`` and
    ``next_chunk`` so the agent can page through the rest by calling
    ``fetch_page`` again with ``chunk=2,3,...``. ``page_images`` (rendered PDF
    pages) are attached alongside so a multimodal model can read scanned pages.
    rz$(No readable text content extracted)rru�

[This PDF has no extractable text — the pages below were rendered as images. Use the read_image tool on each URL to view a page.])r,�title�content�page_images�chunk�total_chunksrN�
next_chunkzPage content is split across z* chunks. Call fetch_page again with chunk=z to read the next chunk.zEnd of page content.�noteF)�ensure_ascii)r*r8�max�minr3�json�dumps)
�	final_urlr:r5�	max_charsr=r<�pages�idx�body�payloads
          r�_doc_resultrLes��
�J�B����I�#I�D���y�)�E�

�a��U�Q�Y��E�
�Q��/�
0�C���:�D���
N�	
�� �%�D�A�G��!,��
��
�5�z�A�~���7����"%�e�*����+.��7�S��Z�+?��a��T�����|�$�,�C��J�<�8 � #�a��y�(@�
B�(�		����:�:�g�E�2�2r1c���ddl}|j|jdd���j�dd}tj
j
tjd�}	t	j|d�	�g}t|�D]�\}}|tk\r|S	ddl}	|j|	j!t"t"���}
|�d|d
z�d�}|
j%tj
j
||��|j'd|�����|S#t$r}td
|���gcYd}~Sd}~wwxYw#t($r }td|d
z�d|���Yd}~|Sd}~wwxYw)a/Render image-only PDF pages (scanned) to PNG files the model can view.

    Rendered files land under ``IMG_PATH/pdf_pages`` and are returned as
    ``/output/pdf_pages/...`` URLs so ``read_image`` / ``resolve_image_path``
    can resolve them. Returns an empty list when nothing could be rendered.
    rNrrr��	pdf_pagesT)�exist_okz)[fetch_page] PDF page render dir failed: )�matrixz-prz.pngz/output/pdf_pages/z[fetch_page] PDF page z render failed: )�hashlib�md5�encode�	hexdigestr%r&�joinr�IMG_PATH�makedirs�OSError�print�	enumerate�PDF_PAGE_IMAGE_LIMIT�fitz�
get_pixmap�Matrix�PDF_PAGE_IMAGE_ZOOM�save�append�	Exception)�docr,rR�slug�outdir�e�urlsr7�pager]�pix�fnames            r�_render_pdf_pagesrl�sb����;�;�s�z�z�'�)�z�<�=�G�G�I�#�2�N�D�
�W�W�\�\�!�*�*�k�
2�F��
���F�T�*��D��S�>����4��$�$���K�	���/�/��{�{�#6�8K�L�"��C��f�B�q�1�u�g�T�*�E��H�H�R�W�W�\�\�&�%�0�1��K�K�,�U�G�4�5���K��'��
�9�!��=�>��	���� �	��*�1�q�5�'�1A�!��E�F���K��	�s7�'D�A<E�	E�'D<�6E�<E�	E-�
E(�(E-c�2�tjjt|�j�xsd}	ddl}|j|d��}g}d}|D]N}|j
d�}|j|�|t|�z
}|tkDs�=|jd�ndj|�j�}	g}
|	st||�}
d	}	|j�|	||
fS#t$r!}td
|���d|�d�|gfcYd}~Sd}~wwxYw)
aExtract text from a PDF via PyMuPDF.

    Returns ``(text, title, page_images)``. If the PDF has no extractable text
    (scanned pages) the first ``PDF_PAGE_IMAGE_LIMIT`` pages are rendered to PNG
    files and returned as ``/output/pdf_pages/...`` URLs.
    zPDF documentrNr)�stream�filetyper5z
...[truncated by size]�
uE(No extractable text in PDF — the pages are likely scanned images.)z[fetch_page] PDF parse failed: z'(Could not extract text from this PDF: �))r%r&�basenamerr]�open�get_textrbr3�PARSE_PDF_CHARSrVr*rl�closercrZ)rr,�	doc_titler]rd�parts�total_charsrir5rJr<rgs            r�
_parse_pdfrz�s����� � ��#��!3�!3�4�F��I�M���i�i�s�U�i�3�������	�D��=�=��(�D��L�L����3�t�9�$�K��_�,����7�8��
	��y�y���%�%�'�����+�C��5�K�Z�D��	�	���Y��+�+���M�
�/��s�3�4�8���1�=�y�"�L�L��M�s%�AC,�AC,�,	D�5D�D�Dc�(�ddl}ddl}tjj	t|�j�xsd}	|j
|jt|���}g}t|�D]H\}}|tk\r|jd�n)|jdjd�|D����Jdj|�j�xsd}	|	|fS#t$r }
td	|
���d
|
�d�|fcYd}
~
Sd}
~
wwxYw)zCParse CSV text into pipe-separated rows. Returns ``(text, title)``.rNzCSV document�...[truncated by row limit]� | c3�DK�|]}|�dn|j����y�w�Nr�r*)�.0�cs  r�	<genexpr>z_parse_csv.<locals>.<genexpr>�s����"O�a���2����	�#A�"O�s� rpz(Empty CSV)z[fetch_page] CSV parse failed: z(Could not parse this CSV: rq)r�ior%r&rrr�reader�StringIOrr[�PARSE_ROW_LIMITrbrVr*rcrZ)rr,rr�rwr��rowsr7�rowrJrgs           r�
_parse_csvr��s����
���� � ��#��!3�!3�4�F��I�=����B�K�K�(=�c�(B�C�D������'�	Q�F�A�s��O�#����9�:���K�K��
�
�"O�3�"O�O�P�		Q�
�y�y���$�$�&�7�-���Y�����=�
�/��s�3�4�,�Q�C�q�1�9�<�<��=�s�B'C(�(	D�1D�D�Dc��ddl}ddlm}tjjt
|�j�xsd}	||j|�dd��}g}|jD]�}|jd|j���t|jd���D]H\}}	|tk\r|jd	��^|jd
jd�|	D����J��|j�dj|�j!�xsd
}
|
|fS#t"$r }t%d|���d|�d�|fcYd}~Sd}~wwxYw)zMExtract every sheet of an .xlsx workbook as text rows. Returns (text, title).rN)�
load_workbookzExcel spreadsheetT)�	read_only�	data_onlyz### Sheet: )�values_onlyr|r}c3�:K�|]}|�dn
t|����y�wr)�str)r��vs  rr�z_parse_excel.<locals>.<genexpr>�s����(R��q�y��c�!�f�)D�(R�s�rpz(Empty spreadsheet)z![fetch_page] Excel parse failed: z#(Could not parse this spreadsheet: rq)r��openpyxlr�r%r&rrr�BytesIO�
worksheetsrbr:r[�	iter_rowsr�rVrvr*rcrZ)rr,r�r�rw�wb�blocks�sheet�row_idxr�rJrgs            r�_parse_excelr��s9��
�&���� � ��#��!3�!3�4�K�8K�I�E�
�2�:�:�c�?�d�d�
K�����]�]�	T�E��M�M�K����}�5�6� )�%�/�/�d�/�*K� L�
T�����o�-��M�M�"?�@���
�
�e�j�j�(R�c�(R�R�S�	
T�	T�	���
��y�y�� �&�&�(�A�,A���Y�����E�
�1�!��5�6�4�Q�C�q�9�9�D�D��E�s�C'D*�*	E�3E�E�Ec
�X�tj�}|j�}|dd�}tj�dt|���}t
d|�	tjtj|d��}|j�t
d�|j�}|jdg�dt}
g}|
D][}|j!|jdd
�|jdd
�|jdd
�xs|jdd
�d���]t#|�}
tj|
|jd	�||d��S#t$rK}	t
d|	���tjg|jd	�||t|	�d
��cYd}	~	Sd}	~	wwxYw)NrD)�q�format�?zPerforming web searchr)�params�timeoutzWeb-search completedzWeb-search failed: z%Y-%m-%d %A)�results�search_date�query�
search_url�errorr�r:rr,r;�snippet)r:r,r�)r�r�r�r�)r�nowr*r�SEARXNG_URLrrZ�requests�get�raise_for_statusrDrcrE�strftimer��WEB_SEARCH_RESULT_LIMITrb�_enrich_top_results)r��current_time�current_location�ts�clean_queryr�r��r�datargr��	formatted�x�enricheds              r�
web_searchr��s���	����B��+�+�-�K��&�
1�F��M�M�?�!�I�f�$5�#6�7�J�	�
!�:�.�
��L�L����v�r�B��	����
�$�%��v�v�x���h�h�y�"�%�&>�'>�?�G��I�
�
��������w��+��u�u�U�B�'��5�5��B�/�G�1�5�5��B�3G�
�	
�
�#�9�-�H��:�:���;�;�}�5��$�		
����)��
�#�A�3�'�(��z�z���;�;�}�5��$���V�
��	���s �AE�	F)�AF$�F)�$F)c�.�|dt}|s|Sd�}tjjt	|���}|D�cgc]}|j||���}}tjj
|t��|jd��|Scc}w)a_Attach the full page text to the top results.

    The top ``WEB_SEARCH_ENRICH_TOP`` results are fetched concurrently (their
    body is stored as ``full_content``) so the LLM does not have to make a
    separate ``fetch_page`` call for every promising link. Fetch failures are
    recorded as ``fetch_error`` and never break the search response.
    Nc��|jdd�}|j�jd�sy	tjtj|t���}|jd�r|d|d<|jdd�|d<y|jd	�r	|d	|d
<yy#t$r}t|�|d
<Yd}~yd}~wwxYw)Nr,r)zhttp://zhttps://)rGr;�full_contentr:�
page_titler��fetch_error)
r�r(r+rD�loadsr�
fetch_page�WEB_SEARCH_ENRICH_CHARSrcr�)�entryr,rirgs    r�_onez!_enrich_top_results.<locals>._one.s����i�i��r�"���y�y�{�%�%�&=�>��
	*��:�:����S�,C�D��D��x�x�	�"�(,�Y���n�%�&*�h�h�w��&;��l�#����'�"�'+�G�}��m�$�#���	*�#&�q�6�E�-� ��	*�s�AB,�B,�,	C
�5C�C
)�max_workers�r�F)�wait)	�WEB_SEARCH_ENRICH_TOP�
concurrent�futures�ThreadPoolExecutorr3�submitr��WEB_SEARCH_ENRICH_TIMEOUT�shutdown)r��targetsr��executorr��futss      rr�r�"s����,�,�-�G����*� �!�!�4�4��W��4�N�H�6=�>�U�H�O�O�D�%�(�>�D�>������D�*C��D����5��!��N��?s�Bc���ddl}ddl}ddlm}|st	j
ddd��S	t
dt|xsd��}	t|�}|jdvrt	j
|dd��S|jxsd}|j|�}|j|�}	|	js|	j s|	j"rt	j
|d	d��S	ddd
d�}	t'j(||dd��}|j+�t-|dd�}
|
�|j.j1dd��}
|j2j)dd�j5��t7|�|
�}|dk(r*t9|
|�\}}}t;|j<|||||�S|dk(r(t?|
|�\}}t;|j<||||�S|dk(r(tA|
|�\}}t;|j<||||�S|dk(rt	j
|�dd��StC�fd�tDD��st	j
|�dd��S|jFs|jH|_#||j.d�}|gd ��D]}|jK��|jLr|jLjOd�!�nd}|jQd"�xs(|jQd#�xs|jQd$�xs|}|jOd%d�&�}d%jSd'�|jU�D��}t;|j<||||�S#ttf$rd}Y��&wxYw#t$$r%}
t	j
|d
|
��d��cYd}
~
Sd}
~
wwxYw#t$$r3}
tWd(|
���t	j
|d)|
��d��cYd}
~
Sd}
~
wwxYw)*Nr)�
BeautifulSouprzNo URL provided.�r,r�r)�http�httpsz#Only http/https URLs are supported.z4Access to private/internal addresses is not allowed.z
Invalid URL: zaMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36z:text/html,application/xhtml+xml,text/plain;q=0.9,*/*;q=0.8zen-US,en;q=0.9)z
User-Agent�AcceptzAccept-Language�T)�headersr��allow_redirectsr;rrrzContent-Typerrr$rzpThis is a legacy .xls spreadsheet, which is not supported. Please retry with a .xlsx or CSV version of the file.)r,r-r�c3�&�K�|]}|�v���
y�w�N�)r��tr/s  �rr�zfetch_page.<locals>.<genexpr>~s�����6�!�1��:�6�s�zASkipped: page is not readable text content (likely binary/media).zhtml.parser)	�script�style�noscript�svg�nav�footer�header�aside�formr��main�articlerJrp)�	separatorr*c3�^K�|]%}|j�s�|j����'y�wr�r�)r��lines  rr�zfetch_page.<locals>.<genexpr>�s����T�$�t�z�z�|�����T�s�-�-z[fetch_page] Failed: zFailed to fetch page: ),�	ipaddress�socket�bs4r�rDrErB�int�	TypeError�
ValueErrorr�scheme�hostname�
gethostbyname�
ip_address�
is_private�is_loopback�
is_link_localrcr�r�r��getattrr5rTr�r(r0rzrLr,r�r��any�_TEXTISH_TYPES�encoding�apparent_encoding�	decomposer:rt�findrV�
splitlinesrZ)r,rGr=r�r�r��parsed�host�ip�addrrgr�r�r�kindr5rwr<�soup�tagr:r�r/s                      @rr�r�Es������!���z�z�"�/A�B�C�C���A�s�5�:�A��'��
F��#����=�=� 1�1��:�:�c�4Y�Z�[�[����$�"��
�
!�
!�$�
'���#�#�B�'���?�?�d�.�.�$�2D�2D��:�:�c�4j�k�l�l�3E�z�N�+��G�
*O��L�L��g�r�4�P��	�����a��D�)���;��&�&�-�-��	�-�:�C��	�	�
�
�n�b�1�7�7�9����U�C�0���5�=�+5�c�3�+?�(�D�)�[��q�u�u�i��y�%��U�U��5�=�(��c�2�O�D�)��q�u�u�i��y�%�H�H��7�?�*�3��4�O�D�)��q�u�u�i��y�%�H�H��*�*��:�:��$)�L���
��6�~�6�6��:�:�c�5�LO�P�Q�
Q��z�z��,�,�A�J��Q�V�V�]�3���j�k�	�C��M�M�O�	�37�:�:��
�
�#�#�$�#�/�2���y�y�� �U�D�I�I�i�$8�U�D�I�I�f�<M�U�QU���}�}�t�4�}�8���y�y�T�$�/�/�2C�T�T���1�5�5�%��y�%�@�@��u
�z�"�������F��z�z�#�-��s�0C�D�E�E��F��`�O�
�%�a�S�)�*��z�z�#�2H���0L�M�N�N��O�st�M�0M.�6A-M.�,B:N�',N�,N�N�0N�DN�M+�*M+�.	N�7N�N�N�	O�((O�O�Oc
�,�|dd}	tj||||||�y#t$re}td|�d|�d|���tjd||jdd�t
jd	d
|�d|��i�|||��Yd}~yd}~wwxYw)
N�function�namez[tool_worker] Tool 'z' crashed for task �: �tool_ok�idrr�zTool z	 failed: ��tc_id�result�sid�round�
tool_index)r�_dispatch_toolrcrZ�_event_postr�rDrE)�task_idr�tc�	image_b64�	round_numr�	tool_namergs        r�_tool_workerr�s����:��v�&�I�
�	����#�r�9�i��L���

�
�$�Y�K�/B�7�)�2�a�S�Q�R�	�
�
����&�&��r�"��:�:�w�%�	�{�)�A�3�(G�H�I���!�	
�	
��

�s�%�	B�AB�Bc���|dd}	tj|dd�}tj5ttjj|i�jdg��}ddd�dv}	|dk(r�tjrtj}
n�tj�}|tj|<tj|d�|jd�	�tjj|d�tjrtjnd
}
tjd||d|
|||�
�y|dk(�r6|jdd�}t j"j%t'|�j"�}
t j"j)t j"j+tj,|
��}|j/t j"j)tj,��rFt j"j1|�r'tj2|�}|r	d|�d|��}
nd|�d�}
nd|��}
tjd||d|
|||�
�y|dk(r}|jdd�}tj4|�}|�tj6dd|��d��}
ntj6d|d��}
tjd||d|
|||�
�y|dk(�r�tj|d|jd��d ��tj5tjj|i�jd!�}ddd�	tj8|d|jd"�|jd#��$�}
t;d(|�d&|
dd)�d ��tj5tjj|�}|rV|j?dg�jA|�	|j?d*g�jAtj|
��ddd�d+|jd��d,|
��}t;d-|�d&|dd.�d ��tjd||d||||�
�y|d/k(�r�tj|d0|jdd��d ��	tjB|jdd�|jd1d2��3�}
t;d6|�d&|
dd)�d ��tj5tjj|�}|r�|j?dg�jA|�	tj|
�}|j?d*g�jAd/|jd|jdd��|jd7d�|jd8d�|jd9d�d:��ddd�d;|jd��d<|
��}tjd||d||||�
�y|d=k(rtjD|||||||�y|dk(rU|	r7tj6d9d>i�}
tjd||d|
|||�
�ytjD|||||||�y|d?k(r�|jd8d�}d}tj5tjj|�}|r|jd@d�}ddd�|r1tjF||�t;dA|�dBtI|��dC��tj6dDtK|�dE��}
tjd||d|
|||�
�y|dFk(r�d}tj5tjj|�}|r|jd@d�}ddd�|stj6ddGd��}
ntjL||�}
tjd||d|
|||�
�y|dHk(r�d}tj5tjj|�}|r|jd@d�}ddd�|stj6ddGd��}
ntjN||�}
tjd||d|
|||�
�ytj6d9dI|��i�}
tjd||d|
|||�
�y#t$ri}Y�	�
wxYw#1swY���xYw#1swY���xYw#t$rM}t;d%|�d&|���tj6g|jd�t=|�d'��}
Yd}~���d}~wwxYw#t$rY��WwxYw#1swY��]xYw#t$rM}t;d4|�d&|���tj6|jdd�t=|�d5��}
Yd}~���d}~wwxYw#t$rY��wxYw#1swY��"xYw#1swY��xYw#1swY��^xYw#1swY���xYw)JNr	r
�	arguments�_tools_used�generate_image�get_user_location�location_needed�<r�zUser denied location accessrr
r�	read_file�file_urlrzContent of z:

zCould not extract text from z#. The file may contain only images.zFile not found: �
read_imager,FzImage not found: )�okr�T)r&�	image_urlr�zSearching web for: r�z...�_client_timestampr�r�)r�r�z*[web_search] Unhandled exception for task r)r�r�r�z![web_search] RAW result for task i,�_search_detailszWeb search results for query 'zj'. Analyze these search results thoroughly and provide a clear, accurate response based on the findings:

zC[web_search] LLM-bound result (with analysis instruction) for task i�r�zFetching page: r=r)r=z*[fetch_page] Unhandled exception for task r�z[fetch_page] Result for task r:r;r�)�toolr,r:r;r�zPage content fetched from URL 'z�'. Use this content to answer the user's question accurately. If the content is insufficient or was truncated, you may fetch another page or fall back to the search results:

�
edit_imagez/Image generation limit reached for this prompt.�update_user_context�_userz$[context] Updated context for user 'z' (z chars)r&)�status�saved�manage_taskszUser not found�track_themezUnknown tool: )(rDr�rcr�
_data_lock�list�tasksr��_client_location�	threading�Event�_location_events�
set_statusr��poprr%r&rrr�abspathrV�UPLOADS_DIRr+�exists�read_file_text�resolve_image_pathrEr�rZr��
setdefaultrbr��_enqueue_image_job�write_user_contextr3�bool�handle_task_tool�handle_theme_tool)rrrrrrr�args�tu�has_generated_imager�evr$�filename�fpathr5r,�	client_tsrgr��
llm_result�resr;�users                        rrr�s�	���:��v�&�I���z�z�"�Z�.��5�6��
���C�
�!�'�'�+�+�g�r�*�.�.�}�b�A�
B��C�*�b�0���'�'�����'�'�F����"�B�*,�A���w�'�
�L�L��"3�4��G�G�B�G��
���"�"�7�D�1�+,�+=�+=�Q�'�'�C`�F�	�
�
�i���4���S�Xa�nx�y���K���8�8�J��+���7�7�#�#�H�X�$6�$;�$;�<������������Q�]�]�H� E�F�����B�G�G�O�O�A�M�M�:�;������u�@U��#�#�E�*�D��&�x�j��d�V�<��7��z�Ad�e��'��z�2�F�	�
�
�i���4���S�Xa�nx�y���L� ��h�h�u�b�!���$�$�S�)���=��Z�Z�u�9J�3�%�7P� Q�R�F��Z�Z�t�#� >�?�F�	�
�
�i���4���S�Xa�nx�y���L� �	���W� 3�D�H�H�W�4E�3F�c�J�K�
�\�\�	J������G�R�0�4�4�5H�I�I�	J�	^��\�\��W�
�!�X�X�n�5�!%���*<�!=��F�	�1�'��"�V�D�S�\�N�#�N�O�
�\�\�	������G�$�A�����]�B�/�6�6�y�A���L�L�!2�B�7�>�>�t�z�z�&�?Q�R�	�-�T�X�X�g�->�,?�@x�x~�w�
A�	�	�S�T[�S\�\^�_i�jn�kn�_o�^p�ps�t�u�	�
�
����T�(����!�	
�
�l�	"�	���W�������0C�/D�C�H�I�	O��\�\�$�(�(�5�"�"5�T�X�X�g�q�=Q�R�F�	�-�g�Y�b������c�J�K�
�\�\�	������G�$�A�����]�B�/�6�6�y�A�
��*�*�V�,�C��L�L�!2�B�7�>�>� ,�"�w�w�u�d�h�h�u�b�.A�B�!$����"�!5�#&�7�7�9�b�#9�!$����"�!5�@��
	� .�d�h�h�u�o�->�?B�CI�BJ�
K�	�
	
�
�
����T�(����!�	
�
�l�	"�	���W�c�9�d�B�	�:�V��	�&�	&���Z�Z��K�L��F�
�M�M�����h����%�
�	�
� � ��#�y�$��I�z�Z��	�+�	+��(�(�9�b�)����
�\�\�	*������G�$�A���u�u�W�b�)��	*��
� � ��w�/��8���c�#�g�,��w�W�X����t�d�4�j�A�B��	�
�
����T�(����!�	
�
�n�	$���
�\�\�	*������G�$�A���u�u�W�b�)��	*���Z�Z�u�7G� H�I�F��'�'��d�3�F�	�
�
����T�(����!�	
�
�m�	#���
�\�\�	*������G�$�A���u�u�W�b�)��	*���Z�Z�u�7G� H�I�F��(�(��t�4�F�	�
�
����T�(����!�	
����W��y�k�&B�C�D��	�
�
����T�(����!�	
��S������C�C��X	J�	J���	^��>�w�i�r�!��M�N��Z�Z�B����'�9J�UX�YZ�U[� \�]�F��	^��!�����
	�	��6�	O��>�w�i�r�!��M�N��Z�Z������(;�c�!�f� M�N�F��	O��"!�����	�	��l	*�	*��&	*�	*��&	*�	*�s��d$�:d6�0e�9e�&Af9�*4f)�#7g�?Ah/�Bh�24h<�94i	�4i�$d3�2d3�6e�e
�	f&�Af!�!f&�)	f6�2f9�5f6�6f9�9g�	h�Ah�h�	h,�(h/�+h,�,h/�/h9�<i�	i�i )rN)NN)i�]r)#�__doc__�concurrent.futuresr�rDr%r6r�urllib.parserrr��server.features.staterr�r�r�r�r�r�rur\r`rr0r8rLrlrzr�r�r�r�r�rrr�r1r�<module>rTs���P���	���,��#�
������������������3�&�RC�3�D �FM�B=�*E�2&�R �FGO�T
�"U
r1