
    h78jZ                     
   d Z ddlZddlZddlZddlmZ ddlmZmZ ddl	m
Z
 ddlmZ ddlmZmZ ddlmZ dd	lmZ  ej        ej        
            ej        e          Z eddddd          Ze                    e
dgddgdg           defd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" G d$ d%e          Z#e$                    d&e#'          de#fd(            Z%e$                    d)e#'          de#fd*            Z&e'                    d+e"'          d,ede"fd-            Z(e$                    d+e"'          	 	 	 	 	 	 dqd3e)d4e)d5e)d6e)dz  d7e*d8e*d9e)de"fd:            Z+e'                    d;e"'          d,ede"fd<            Z,e$                    d;e"'          	 	 	 	 	 	 	 	 	 	 	 drd3e)d4e)d5e)d6e)dz  d7e*d8e*d9e)d=e)dz  d>e)dz  d?e)dz  d@e)dz  dAe)dz  de"fdB            Z-e'                    dCe"'          d,ede"fdD            Z.e$                    dCe"'          	 	 	 	 	 	 dqd3e)d4e)d5e)d6e)dz  d7e*d8e*d9e)de"fdE            Z/e'                    dFe"'          d,ede"fdG            Z0e$                    dFe"'          	 	 	 	 	 	 	 	 	 dsd3e)d4e)d5e)d6e)dz  d7e*d8e*d9e)dHe)dz  dIe)dz  dJe)dz  de"fdK            Z1e'                    dLe"'          d,e de"fdM            Z2e$                    dLe"'          	 	 	 dtd3e)d7e*d8e*d9e)de"f
dN            Z3e'                    dO          d,e!de4e)e)e5z  f         fdP            Z6e$                    dO          dudRe)dSe)de4e)e)e5z  f         fdT            Z7	 ddlmZmZ  G dU dVe          Z8 G dW dXe          Z9e$                    dYe"'          dvd3e)d[e)de"fd\            Z:e'                    dYd]^          d,e8de4e)e)f         fd_            Z;e<                    dYd`^          dvd3e)d[e)ddfda            Z=e$                    dbe9'          de9fdc            Z>e$                    dde?e)         '          de?e)         fde            Z@e$                    dfe?e4e)ef                  '          de?e4e)ef                  fdg            ZAe$                    dh          de4e)ef         fdi            ZBe$                    dj          defdk            ZCeD                    dl           n# eE$ r Y nw xY wedmk    rddlFZF eFjG        edndop           dS dS )wz!FastAPI application for DDGS API.    N)Any)FastAPIHTTPException)CORSMiddleware)Response)	BaseModelField)DDGS)_expand_proxy_tb_alias)levelDDGS APIzFA FastAPI wrapper for the DDGS (Dux Distributed Global Search) library1.0.0z/docsz/redoc)titledescriptionversiondocs_url	redoc_url*T)allow_originsallow_credentialsallow_methodsallow_headersreturnc                  v    t          t          t          j                            d                              S )zACreate a DDGS instance with proxy configuration from environment.
DDGS_PROXY)proxy)r
   r   osenvironget     [/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/ddgs/api_server/api.py	_get_ddgsr#   '   s*    ,RZ^^L-I-IJJKKKKr!   c                      e Zd ZU dZ edd          Zeed<    edd          Zeed<    ed	d
          Z	eed<    edd          Z
edz  ed<    edd          Zedz  ed<    edd          Zeed<    edd          Zeed<   dS )TextSearchRequest$Request model for search operations..Search queryr   queryus-en-Region for search (e.g., us-en, uk-en, ru-ru)regionmoderate'Safe search setting (on, moderate, off)
safesearchN,Time limit (d, w, m, y) or custom date range	timelimit
   #Maximum number of results to returnmax_results   Page number of resultspageauto)Search backend (auto, or specific engine)backend__name__
__module____qualname____doc__r	   r)   str__annotations__r,   r/   r1   r4   intr7   r:   r    r!   r"   r%   r%   -            ..s777E3777%-\]]]FC]]]eJ4]^^^J^^^!E$4bcccIsTzccc#eB4YZZZKtZZZa%=>>>D#>>>5-XYYYGSYYYYYr!   r%   c                      e Zd ZU dZ edd          Zeed<    edd          Zeed<    ed	d
          Z	eed<    edd          Z
edz  ed<    edd          Zedz  ed<    edd          Zeed<    edd          Zeed<    edd          Zedz  ed<    edd          Zedz  ed<    edd          Zedz  ed<    edd          Zedz  ed<    edd           Zedz  ed!<   dS )"ImagesSearchRequestz*Request model for image search operations..zImage search queryr(   r)   r*   r+   r,   r-   r.   r/   Nr0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   z,Image size (Small, Medium, Large, Wallpaper)sizeziImage color (Monochrome, Red, Orange, Yellow, Green, Blue, Purple, Pink, Brown, Black, Gray, Teal, White)colorz3Image type (photo, clipart, gif, transparent, line)
type_imagez!Image layout (Square, Tall, Wide)layoutzQImage license (any, Public, Share, ShareCommercially, Modify, ModifyCommercially)license_image)r<   r=   r>   r?   r	   r)   r@   rA   r,   r/   r1   r4   rB   r7   r:   rF   rG   rH   rI   rJ   r    r!   r"   rE   rE   9   s        44s(<===E3===%-\]]]FC]]]eJ4]^^^J^^^!E$4bcccIsTzccc#eB4YZZZKtZZZa%=>>>D#>>>5-XYYYGSYYYuT/]^^^D#*^^^  E3:    #U45jkkkJd
kkkt1TUUUFC$JUUU %m! ! !M3:     r!   rE   c                      e Zd ZU dZ edd          Zeed<    edd          Zeed<    ed	d
          Z	eed<    edd          Z
edz  ed<    edd          Zedz  ed<    edd          Zeed<    edd          Zeed<   dS )NewsSearchRequestr&   .r'   r(   r)   r*   r+   r,   r-   r.   r/   Nr0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r    r!   r"   rL   rL   O   rC   r!   rL   c                      e Zd ZU dZ edd          Zeed<    edd          Zeed<    ed	d
          Z	eed<    edd          Z
edz  ed<    edd          Zedz  ed<    edd          Zeed<    edd          Zeed<    edd          Zedz  ed<    edd          Zedz  ed<    edd          Zedz  ed<   dS )VideosSearchRequestz*Request model for video search operations..zVideo search queryr(   r)   r*   r+   r,   r-   r.   r/   Nz)Time limit (d, w, m) or custom date ranger1   r2   r3   r4   r5   r6   r7   r8   r9   r:   z!Video resolution (high, standard)
resolutionz$Video duration (short, medium, long)durationz'Video license (creativeCommon, youtube)license_videos)r<   r=   r>   r?   r	   r)   r@   rA   r,   r/   r1   r4   rB   r7   r:   rO   rP   rQ   r    r!   r"   rN   rN   [   sl        44s(<===E3===%-\]]]FC]]]eJ4]^^^J^^^!E$4_```IsTz```#eB4YZZZKtZZZa%=>>>D#>>>5-XYYYGSYYY"U45XYYYJd
YYY 53YZZZHcDjZZZ!&t9b!c!c!cNC$Jcccccr!   rN   c                       e Zd ZU dZ edd          Zeed<    edd          Ze	dz  ed	<    ed
d          Z
e	ed<    edd          Zeed<   dS )BooksSearchRequestz)Request model for book search operations..zBooks search queryr(   r)   r2   r3   Nr4   r5   r6   r7   r8   r9   r:   )r<   r=   r>   r?   r	   r)   r@   rA   r4   rB   r7   r:   r    r!   r"   rS   rS   j   s         33s(<===E3===#eB4YZZZKtZZZa%=>>>D#>>>5-XYYYGSYYYYYr!   rS   c                   \    e Zd ZU dZ edd          Zeed<    edd          Zeed<   d	S )
ExtractRequestz)Request model for URL content extraction..zURL to extract content fromr(   urltext_markdownz;Format: text_markdown, text_plain, text_rich, text, contentformatN)	r<   r=   r>   r?   r	   rV   r@   rA   rX   r    r!   r"   rU   rU   s   sX         33uS&CDDDCDDD%5rsssFCsssssr!   rU   c                   :    e Zd ZU dZeeeef                  ed<   dS )SearchResponsez%Response model for search operations.resultsN)	r<   r=   r>   r?   listdictr@   r   rA   r    r!   r"   rZ   rZ   z   s1         //$sCx.!!!!!!r!   rZ   c                   2    e Zd ZU dZeed<   eed<   eed<   dS )HealthResponsez Response model for health check.statusr   serviceN)r<   r=   r>   r?   r@   rA   r    r!   r"   r_   r_      s1         **KKKLLLLLLLLr!   r_   /)response_modelc                  *   K   t          ddd          S )z-Root endpoint with basic service information.healthyr   r   r`   r   ra   r_   r    r!   r"   rootrh             GZPPPPr!   z/healthc                  *   K   t          ddd          S )zHealth check endpoint.re   r   r   rf   rg   r    r!   r"   health_checkrk      ri   r!   z/search/textrequestc                     K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)zPerform a text search.c            	          t                                           j         j         j         j         j         j         j                  S N)r)   r,   r/   r1   r4   r7   r:   )	r#   textr)   r,   r/   r1   r4   r7   r:   rl   s   r"   <lambda>zsearch_text.<locals>.<lambda>   F    IKK$$m~"-!+#/\ %   r!   Nr[   zError in text search: %s  Search failed: status_codedetailasyncio	to_threadrZ   	Exceptionloggerwarningr   rl   r[   es   `  r"   search_textr      s      T)   

 

 

 

 

 

 

 

 g.... T T T115554Ka4K4KLLLRSST   ,2 
A10A,,A1r*   r-   r2   r5   r8   r)   r,   r/   r1   r4   r7   r:   c           	          K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z&Perform a text search via GET request.c            	      T    t                                                     S ro   )r#   rp   r:   r4   r7   r)   r,   r/   r1   s   r"   rr   z!search_text_get.<locals>.<lambda>   5    IKK$$%#' %   r!   Nrt   zError in text search (GET): %sru   rv   rw   rz   	r)   r,   r/   r1   r4   r7   r:   r[   r   s	   ```````  r"   search_text_getr      s      T)         

 

 

 

 

 

 

 

 g.... T T T7;;;4Ka4K4KLLLRSST   2> 
A=0A88A=z/search/imagesc                     K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)zPerform an image search.c                      t                                           j         j         j         j         j         j         j         j	         j
         j         j         j                  S N)r)   r,   r/   r1   r4   r7   r:   rF   rG   rH   rI   rJ   )r#   imagesr)   r,   r/   r1   r4   r7   r:   rF   rG   rH   rI   rJ   rq   s   r"   rr   zsearch_images.<locals>.<lambda>   sa    IKK&&m~"-!+#/\\m"-~%3 '   r!   Nrt   zError in image search: %sru   Image search failed: rw   rz   r   s   `  r"   search_imagesr      s      Z)   
 
 
 
 
 
 
 
" g.... Z Z Z2A6664QA4Q4QRRRXYYZr   rF   rG   rH   rI   rJ   c                    	
K   	 t          j        
 	fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z(Perform an image search via GET request.c                  ^    t                                          
 	          S r   )r#   r   )r:   rG   rI   rJ   r4   r7   r)   r,   r/   rF   r1   rH   s   r"   rr   z#search_images_get.<locals>.<lambda>   sD    IKK&&%#'%+ '   r!   Nrt   zError in image search (GET): %sru   r   rw   rz   )r)   r,   r/   r1   r4   r7   r:   rF   rG   rH   rI   rJ   r[   r   s   ````````````  r"   search_images_getr      s       Z)              
 
 
 
 
 
 
 
" g.... Z Z Z8!<<<4QA4Q4QRRRXYYZs   7A 
B0BBz/search/newsc                     K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)zPerform a news search.c            	          t                                           j         j         j         j         j         j         j                  S ro   )	r#   newsr)   r,   r/   r1   r4   r7   r:   rq   s   r"   rr   zsearch_news.<locals>.<lambda>  rs   r!   Nrt   zError in news search: %sru   News search failed: rw   rz   r   s   `  r"   search_newsr     s      Y)   

 

 

 

 

 

 

 

 g.... Y Y Y115554P14P4PQQQWXXYr   c           	          K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z&Perform a news search via GET request.c            	      T    t                                                     S ro   )r#   r   r   s   r"   rr   z!search_news_get.<locals>.<lambda>.  r   r!   Nrt   zError in news search (GET): %sru   r   rw   rz   r   s	   ```````  r"   search_news_getr   !  s      Y)         

 

 

 

 

 

 

 

 g.... Y Y Y7;;;4P14P4PQQQWXXYr   z/search/videosc                     K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)zPerform a video search.c                      t                                           j         j         j         j         j         j         j         j	         j
         j        
  
        S N)
r)   r,   r/   r1   r4   r7   r:   rO   rP   rQ   )r#   videosr)   r,   r/   r1   r4   r7   r:   rO   rP   rQ   rq   s   r"   rr   zsearch_videos.<locals>.<lambda>D  sX    IKK&&m~"-!+#/\"- )&5 '   r!   Nrt   zError in video search: %sru   Video search failed: rw   rz   r   s   `  r"   search_videosr   ?  s      Z)   
 
 
 
 
 
 
 
 g.... Z Z Z2A6664QA4Q4QRRRXYYZr   rO   rP   rQ   c
                    	K   	 t          j        	 f
d           d{V }
t          |
          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z'Perform a video search via GET request.c                  Z   
 t                                          	 
  
        S r   )r#   r   )
r:   rP   rQ   r4   r7   r)   r,   rO   r/   r1   s
   r"   rr   z#search_videos_get.<locals>.<lambda>h  s>    IKK&&%#'%!- '   r!   Nrt   zError in video search (GET): %sru   r   rw   rz   )r)   r,   r/   r1   r4   r7   r:   rO   rP   rQ   r[   r   s   ``````````  r"   search_videos_getr   X  s      Z)            
 
 
 
 
 
 
 
 g.... Z Z Z8!<<<4QA4Q4QRRRXYYZs   5A 
B0A>>Bz/search/booksc                     K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)zPerform a book search.c                  v    t                                           j         j         j         j                  S N)r)   r4   r7   r:   )r#   booksr)   r4   r7   r:   rq   s   r"   rr   zsearch_books.<locals>.<lambda>  s5    IKK%%m#/\	 &   r!   Nrt   zError in book search: %sru   Book search failed: rw   rz   r   s   `  r"   search_booksr   |  s      Y)   
 
 
 
 
 
 
 
 g.... Y Y Y115554P14P4PQQQWXXYr   c                     K   	 t          j         fd           d{V }t          |          S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z&Perform a book search via GET request.c                  N    t                                                     S r   )r#   r   )r:   r4   r7   r)   s   r"   rr   z"search_books_get.<locals>.<lambda>  s,    IKK%%'	 &   r!   Nrt   zError in book search (GET): %sru   r   rw   rz   )r)   r4   r7   r:   r[   r   s   ````  r"   search_books_getr     s      Y)      
 
 
 
 
 
 
 
 g.... Y Y Y7;;;4P14P4PQQQWXXYs   /8 
A70A22A7z/extractc                     K   	 t          j         fd           d{V S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z Extract text content from a URL.c                  ^    t                                           j         j                  S N)rV   fmt)r#   extractrV   rX   rq   s   r"   rr   z!extract_content.<locals>.<lambda>  s*    IKK''KN (   r!   NzError extracting content: %sru   Extraction failed: rw   r{   r|   r}   r~   r   r   )rl   r   s   ` r"   extract_contentr     s      	X&   
 
 
 
 
 
 
 
 	
  X X X5q9994O!4O4OPPPVWWXs   " 
A!0AA!rW   rV   r   c                     K   	 t          j         fd           d{V S # t          $ r5}t                              d|           t          dd|          |d}~ww xY w)z0Extract text content from a URL via GET request.c                  J    t                                                     S r   )r#   r   )r   rV   s   r"   rr   z%extract_content_get.<locals>.<lambda>  s&    IKK'' (   r!   Nz"Error extracting content (GET): %sru   r   rw   r   )rV   r   r   s   `` r"   extract_content_getr     s      	X&    
 
 
 
 
 
 
 
 	
  X X X;Q???4O!4O4OPPPVWWXs   $ 
A#0AA#c                       e Zd ZU dZ edd          Zeed<    edd          Ze	e
eef                  ed<    edd	          Zeed
<   dS )CacheRequestz#Request model for cache operations..r'   r(   r)   zSearch results to cacher[   rp   zSearch categorycategoryN)r<   r=   r>   r?   r	   r)   r@   rA   r[   r\   r]   r   r   r    r!   r"   r   r     s         11U3N;;;s;;;(-c?X(Y(Y(Yd38n%YYYf2CDDD#DDDDDr!   r   c                       e Zd ZU dZeed<   eed<   edz  ed<   edz  ed<   eed<   eed<   eed	<   eed
<   eee	f         ed<   dS )DhtStatusResponsezResponse model for DHT status.running	connectedNpeer_idport
cache_sizecache_count
peer_countrouting_table_sizemetrics)
r<   r=   r>   r?   boolrA   r@   rB   r]   r   r    r!   r"   r   r     s         ,,tDjc3hr!   r   z
/dht/cacherp   r   c                    K   ddl m}  |            }|                    | |          }|t          dd          t	          |          S )zGet cached results from DHT.r   get_dht_serviceNi  zNot found in cacherw   rt   )ddgs.api_serverr   
get_cachedr   rZ   )r)   r   r   dhtr[   s        r"   r   r     sd       	433333o..11?C8LMMMMg....r!      )rx   c                 z   K   ddl m}  |            }|                    | j        | j        | j                   ddiS )zCache results to DHT.r   r   r`   ok)r   r   cacher)   r[   r   )rl   r   r   s      r"   cache_resultsr     sO       	433333o		'-'2BCCC$r!      c                    K   ddl m} ddlm}  |            } || |          }|j        r|j                            |           dS dS )zInvalidate cached results.r   r   )compute_query_hashN)r   r   ddgs.dht.typesr   _cachedelete)r)   r   r   r   r   
query_hashs         r"   invalidate_cacher     s{       	433333555555o''x88
: 	*Jj)))))	* 	*r!   z/dht/statusc                  f   K   ddl m}   |             }|                                }t          di |S )zGet DHT service status.r   r   r    )r   r   
get_statusr   )r   r   r`   s      r"   
dht_statusr     sJ       	433333o!! **6***r!   z
/dht/peersc                  N   K   ddl m}   |             }|                                S )z Get list of connected DHT peers.r   r   )r   r   	get_peersr   r   s     r"   	dht_peersr     s5       	433333o}}r!   z/dht/peers/detailedc                  j   K   ddl m}   |             }|j        r|j                                        ng S )z3Get detailed information about all connected peers.r   r   )r   r   _dhtget_neighborsr   s     r"   dht_peers_detailedr     sG       	433333o+.8;sx%%''';r!   z/dht/mapc                  4  K   ddl m}   |             }|j        sg g ddddS |j                                        }g }g }|                    |j        j        dt          |          d           |D ]]}|                    |d         d|d         |d	         d
           |                    |j        j        |d         |d	         d           ^t          d t          |j        j	                  D             d          }d|z  }|||t          |          |dS )zGet local DHT network map view as graph structure.

        Each node only sees its own routing table neighborhood.
        No global crawling, no gossip, zero additional network traffic.
        r   r   )nodesedgestotal_peers_estimatedlocal_view_sizebucket_depthself)idtypeconnectionsr   peerxor_distance
latency_ms)r   r   r   r   )sourcetargetr   c              3   ,   K   | ]\  }}|d k    |V  dS )r   Nr    ).0icounts      r"   	<genexpr>zdht_map.<locals>.<genexpr>E  s2      ff81e[`de[e[eQ[e[e[e[effr!         )
r   r   r   r   appendr   lennext	enumeratekbucket_distribution)r   r   peersr   r   r   r   estimated_sizes           r"   dht_mapr    s      	433333ox 	s"q]^pqrrr&&((  	h&"5zz 	
 	
 	
  	 	DLLy/"$($8"&|"4	    LL!h."9o"&|"4     ffy9V/W/WfffhkllL %3"5zz(
 
 	
r!   z/dht/metricsc                    K   ddl m}   |             }|                                }ddd|d         rdnd dd	d
|                    dd           ddd|d          ddd|d          ddd|d                             dd           ddd|d                             dd           dd d!|                    d"d           g}t	          d#                    |          d$%          S )&z%Get DHT metrics in Prometheus format.r   r   z6# HELP ddgs_dht_running Whether DHT service is runningz# TYPE ddgs_dht_running gaugezddgs_dht_running r   r5   zC# HELP ddgs_dht_connected_peers Number of currently connected peersz%# TYPE ddgs_dht_connected_peers gaugezddgs_dht_connected_peers r   z># HELP ddgs_dht_cache_entries Number of entries in local cachez## TYPE ddgs_dht_cache_entries gaugezddgs_dht_cache_entries r   z=# HELP ddgs_dht_cache_size_bytes Size of local cache in bytesz&# TYPE ddgs_dht_cache_size_bytes gaugezddgs_dht_cache_size_bytes r   z?# HELP ddgs_dht_query_success_rate DHT query success rate (0-1)z(# TYPE ddgs_dht_query_success_rate gaugezddgs_dht_query_success_rate r   query_success_rateg      ?zR# HELP ddgs_dht_average_query_latency_ms Average DHT query latency in millisecondsz.# TYPE ddgs_dht_average_query_latency_ms gaugez"ddgs_dht_average_query_latency_ms average_query_latency_msg        zI# HELP ddgs_dht_routing_table_size Number of entries in DHT routing tablez(# TYPE ddgs_dht_routing_table_size gaugezddgs_dht_routing_table_size r   
z
text/plain)
media_type)r   r   r   r   r   join)r   r   r`   r   s       r"   dht_metricsr
  P  s;      	433333o!! E+?VI%6 =A??Q3E

<(C(CEEL1=f]&;==K4?)=??M6]6)+<+@+@AUWZ+[+[]]`<i	1B1F1FGacf1g1giiW6P6::6JA+N+NPP+
0 		'**|DDDDr!   z3DHT endpoints enabled - distributed cache available__main__z0.0.0.0i@  )hostr   )r*   r-   Nr2   r5   r8   )r*   r-   Nr2   r5   r8   NNNNN)	r*   r-   Nr2   r5   r8   NNN)r2   r5   r8   )rW   )rp   )Hr?   r{   loggingr   typingr   fastapir   r   fastapi.middleware.corsr   fastapi.responsesr   pydanticr   r	   ddgsr
   
ddgs.utilsr   basicConfigINFO	getLoggerr<   r~   appadd_middlewarer#   r%   rE   rL   rN   rS   rU   rZ   r_   r   rh   rk   postr   r@   rB   r   r   r   r   r   r   r   r   r   r]   bytesr   r   r   r   r   r   r   r   r   r\   r   r   r  r
  infoImportErroruvicornrunr    r!   r"   <module>r      s   ' '   				       * * * * * * * * 2 2 2 2 2 2 & & & & & & % % % % % % % %       - - - - - -  ', ' ' ' '		8	$	$ g
X     %%%    L4 L L L L	Z 	Z 	Z 	Z 	Z	 	Z 	Z 	Z    )   ,	Z 	Z 	Z 	Z 	Z	 	Z 	Z 	Zd d d d d) d d dZ Z Z Z Z Z Z Zt t t t tY t t t" " " " "Y " " "    Y    ^,,QN Q Q Q -,Q
 >22QN Q Q Q 32Q
 .88T0 T^ T T T 98T* 77   T TTT T Tz	T
 T T T T T T 87T: 
>::Z!4 Z Z Z Z ;:Z4 	.99   ! $$Z $Z$Z$Z $Z Tz	$Z
 $Z $Z $Z *$Z :$Z d
$Z $J$Z :$Z $Z $Z $Z :9$ZN .88Y0 Y^ Y Y Y 98Y* 77   Y YYY Y Tz	Y
 Y Y Y Y Y Y 87Y: 
>::Z!4 Z Z Z Z ;:Z0 	.99   !!% Z  Z Z Z  Z Tz	 Z
  Z  Z  Z d
 Z Dj Z $J Z  Z  Z  Z :9 ZF /.99Y 2 Y~ Y Y Y :9Y$ 88 	Y YYY Y 	Y
 Y Y Y 98Y. *X> Xd3e;K6L X X X X X X3 XS XtCQTW\Q\L\G] X X X Xp	))))))))E E E E Ey E E E         I       	WW\.W99/ / /s / / / / :9/ 	XXlX,, \  d38n       -,  	ZZ#Z..* *c *S *d * * * /.* 	WW]+<W==+/ + + + >=+ 	WW\$s)W44T#Y    54 	WW"4S#X3GWHH<d4S>&: < < < IH< 	WWZ8
4S> 8
 8
 8
 8
t 	WW^Ex E E E EB KKEFFFF 	 	 	D	
 zNNNGK)$////// s   0FU U
	U
