+
    WjN                      a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t^ RIt^ RIt^ RIt^ RIt^ RItRtR/tRt^t/ tR]R&   R R ltR	 R
 ltR R ltR R ltR R ltR R ltR0R R lltR R ltR R ltR R lt R R lt!R R lt"R R  lt#R! R" lt$R# R$ lt%R% R& lt&R' R( lt'R) R* lt(R+ R, lt)R- R. lt*R# )1uf  Cross-source person / company lookup for the jarvis-tools service (Railway).

Ahmed's leads live in three scattered places and he does NOT want a Supabase
restructure — so this is the bridge that searches all of them at once and merges
the answer. One tool, `person_lookup(query)`, takes a phone number (any Saudi
format) or a name/company and asks EVERY source Ahmed keeps people in:

  A. the memory graph  (MEMORY_API_URL /entity + /search — reuses the same env
     the whole fleet already uses; no new creds)
  B. the Ultron master DB  (leads table, via ultron_db.query() — SQL built
     server-side, phone matched digits-only so raw input never reaches SQL)
  C. the Jarvis Drive / shared-storage sheets  (CSV + XLSX under 5MB, via the
     drive.py + storage.py primitives; parsed sheets cached in-process so repeat
     lookups are instant, whole scan capped at ~8s)

Everything degrades gracefully: a missing credential or an unreachable source is
reported ("checked X: not configured"), never raised, so Ahmed can trust a miss.
Output is readable prose because the consumers are LLMs (Jarvis voice + Claude).
)annotationsNg       @i@ z&dict[str, tuple[str, list[list[str]]]]_SHEET_CACHEc                   V ^8  d   QhRR/#    returnstr )formats   "	lookup.py__annotate__r   0   s     < <# <    c                 `    \         P                  P                  R R4      P                  R4      # )MEMORY_API_URL /)osenvirongetrstripr	   r   r   _mem_urlr   0   s#    ::>>*B/66s;;r   c                   V ^8  d   QhRR/# r   r	   )r
   s   "r   r   r   4   s     0 0# 0r   c                 B    \         P                  P                  R R4      # )MEMORY_API_KEYr   r   r   r   r	   r   r   _mem_keyr   4   s    ::>>*B//r   c                   V ^8  d   QhRR/# r   r	   )r
   s   "r   r   r   8   s     3 3 3r   c                 B    \         P                  P                  R R4      # )MEMORY_GROUPahmedr   r	   r   r   _groupr    8   s    ::>>.'22r   c                   V ^8  d   QhRR/# r   r	   )r
   s   "r   r   r   ?   s     + +# +r   c                X    \         P                  ! R R\        T ;'       g    R4      4      # )z\Dr   )resubr   ss   &r   _digitsr'   ?   s    66%Sb\**r   c                   V ^8  d   QhRR/# r   r	   )r
   s   "r   r   r   C   s     ( (c (r   c                F    \        V 4      p\        V4      ^	8  d   VRR # T# )u   Any Saudi format → the trailing 9 digits (5XXXXXXXX), so 0501234567,
+966501234567, 966501234567 and '050 123 4567' all normalise to the same
key and match each other.Ni)r'   len)r&   ds   & r   _norm_phoner,   C   s(     	
AVq[1RS6'a'r   c                    V ^8  d   QhRRRR/# )r   qr   r   boolr	   )r
   s   "r   r   r   K   s     / / / /r   c                    \        T ;'       g    R4      P                  4       p \        P                  ! RRV 4      pVR8H  ;'       d    \	        \        V 4      4      ^8  # )u   True when the query is only digits + phone punctuation (space/-/+/()/.),
with at least 7 digits — otherwise it's a name/company.r   z[\d\s\-\+\(\).])r   stripr#   r$   r*   r'   )r.   rests   & r   _looks_like_phoner3   K   sN     	AGGA66$b!,D2:..#gaj/Q..r   c               (    V ^8  d   QhRRRRRRRR/# )r   pathr   paramsdicttimeoutfloatr   r	   )r
   s   "r   r   r   V   s(     	* 	*3 	* 	*u 	*t 	*r   c                   \        4       V ,           R ,           \        P                  P                  V4      ,           p\        P                  P                  VRR7      p\        4       pV'       d   VP                  RRV 24       VP                  RR4       \        P                  P                  WBR7      ;_uu_ 4       pVP                  4       pRRR4       X'       d   \        P                  ! V4      # / #   + '       g   i     L0; i)	?GET)methodAuthorizationzBearer Acceptapplication/json)r8   N)r   urllibparse	urlencoderequestRequestr   
add_headerurlopenreadjsonloads)r5   r6   r8   urlreqkeyrraws   &&&     r   _mem_getrP   V   s    
*t
c
!FLL$:$:6$B
BC
..
 
 U
 
3C
*C
'#8NN8/0					5	5ffh 
6!4::c?)r) 
6	5s   ?C88D	c               (    V ^8  d   QhRRRRRRRR/# r   r.   r   is_phoner/   normr   r7   r	   )r
   s   "r   r   r   b   s(     9 9c 9T 9 9 9r   c                   R RRRR. RRRRR	R/p\        4       '       g   R
VR&   V#  V'       d   \        RRV R^R\        4       /4      P                  R. 4      pV'       g3   V'       d+   \        RRVR^R\        4       /4      P                  R. 4      pVR,           FU  pVP                  R4      ;'       g    RP	                  4       pV'       g   K6  VR,          P                  RV,           4       KW  	  VR,          '       d   RVR	&   EM\        RR V R\        4       /4      P                  R. 4      pVR,           EF  pVP                  R 4      ;'       g    VP                  R4      p	VR,          P                  RT	 RVP                  R4      ;'       g    R R24       VP                  R4      ;'       g    VP                  R4      ;'       g    RP	                  4       p
V
'       d'   VR,          P                  RV
R,          ,           4       VP                  R4      ;'       g    . R ,           FU  pVP                  R4      ;'       g    RP	                  4       pV'       g   K6  VR,          P                  R!V,           4       KW  	  VP                  R"4      ;'       g    . pV'       g   EKw  VR,          P                  R#R$P                  R% VR&,           4       4      ,           4       EK  	  V'       dB   V^ ,          P                  R 4      ;'       g    V^ ,          P                  R4      VR&   RVR	&   M\        RRV R^R\        4       /4      P                  R. 4      pVR,           FU  pVP                  R4      ;'       g    RP	                  4       pV'       g   K6  VR,          P                  RV,           4       KW  	  VR,          '       d   RVR	&   \        VR,          4      VR&   VR,          '       d   R'\        VR,          4       R(2MR)VR&   V#   \         d$   pR*\        T4      R+,           2TR&    Rp?T# Rp?ii ; i),namezMEMORY GRAPHfoundFlinesstatusr   	candidateNtagnot configuredz/searchr.   kgroupfactsN   Nfact- zmemory graphz/entityentities:Nr   NrM    (typething)summaryrH     :N   N:N   N     • 	relationsz  ~ , c              3     "   T F4  pVP                  R 4      ;'       g    R RVP                  R4       2x  K6  	  R# 5i)rtyperelated otherN)r   .0rN   s   & r   	<genexpr>!_source_memory.<locals>.<genexpr>   s<      ;+!)A 55>66Y7qw8HI!)s   >>:N   Nok (z hit(s))zok (no hits)error: Nd   N)r   rP   r    r   r1   appendjoinr/   r*   	Exceptionr   )r.   rS   rT   resr_   ftentsenmgistfctrelss   &&&          r   _source_memoryr   b   s   >7E7BRdE27C::(H
21Yaa)0&()< ==@S"=M T S$Q-4fh-@ AADWbAQ 2YYUU6]((b//11L''q1  7|| ,E
I(/(; <<?C
B<O "XXUU6]22aeeElG##bBquuV}/G/G.H$JKi(??AEE&M??RFFHL''tDz(9:EE'N00b"55C..B557AqG++HqL9 6 uu[)//R4L'' ;+!%b;+ 2+ )+ ,  #'7;;v#6#L#L$q'++e:LK +E
 S!S!-4fh-@ AADWbAQ rAv,,"335AqG++D1H5 # w<<!/CJCL)G>A'll$s3w<01: 	H J  1!#a&,0HJ1s   P 9P )AP 7P 1P AP ?P !P :P P ,=P *$P P *:P %P 3AP <P A/P P &1P AP Q)QQc                    V ^8  d   QhRRRR/# )r   r&   r   r   r	   )r
   s   "r   r   r      s            r   c                    \        V 4      P                  RR4      P                  RR4      P                  RR4      p V P                  RR4      # )	zEscape for an ILIKE pattern literal: neutralise LIKE wildcards, then
double single-quotes so the value can't break out of the string literal.\z\\%z\%_z\_'z'')r   replacer%   s   &r   	_esc_liker      sC     	AtV$,,S%8@@eLA99S$r   c                    V ^8  d   QhRRRR/# )r   textr   r   z
list[dict]r	   )r
   s   "r   r   r      s      C J r   c           	     2   V P                  R4      P                  R4       Uu. uF  qP                  4       '       g   K  VNK  	  pp\        V4      ^8  d   . # V^ ,          P                  R4       Uu. uF  q3P                  4       NK  	  pp. pVR,           Fl  pVP                  R4      '       d   K  VP                  R4       Uu. uF  qfP                  4       NK  	  ppVP	                  \        \        WG4      4      4       Kn  	  V# u upi u upi u upi )zultron_db.query() prints 'col | col\n---\nval | val'. We control the
SELECT column order, so this round-trips cleanly back into dicts.
z | :r   NN)   …-)r1   splitr*   
startswithr~   r7   zip)r   lnrX   ccolsrowsvvalss   &       r   _parse_query_rowsr      s     **T*006E6B((*RR6EE
5zA~	$Qx~~e454!GGI4D5DBii==&&#%88E?3?a	?3DT)*	 
 K F 6
 4s   D
D
3DDc               (    V ^8  d   QhRRRRRRRR/# rR   r	   )r
   s   "r   r   r      s(     + +c +T + + +r   c                   R RRRR. RRRRR	R/p\         P                  ! 4       '       g   R
VR&   V# V'       d   \        V4      pRV RV RV RV R2	pM\        V 4      pRV RV RV R2pRV R2p \	        \         P
                  ! V4      4      pT'       g   RTR&   T# T F  p
T
P                  R4      ;'       g    R.pR( F3  pT
P                  T4      '       g   K  TP                  Y,          4       K5  	  T
P                  R4      '       d   TP                  RT
R,           24       TR,          P                  RRP                  T4      ,           4       T
P                  R 4      '       g   K  TR,          P                  R!T
R ,          ,           4       K  	  T^ ,          pTP                  R4      ;'       g    TP                  R4      ;'       g    RpTP                  R4      ;'       g    RP                  4       ;'       g    RTR&   R"TR&   R#\        T4       R$2TR&   R%T'       d   R&T R'2MR 2TR	&   T#   \         d%   p	R\        T	4      R,           2TR&   Tu Rp	?	# Rp	?	ii ; i))rV   zULTRON LEADS DBrW   FrX   rY   r   rZ   Nr[   r\   z5right(regexp_replace(coalesce(phone,''),'\D','','g'),z)='z=' or right(regexp_replace(coalesce(whatsapp,''),'\D','','g'),r   zcompany ilike '%z%' or email ilike '%z%%' or coalesce(instagram,'') ilike '%z%'zQselect company, phone, email, city, category, rating, maps_url from leads where (z,) order by last_seen desc nulls last limit 5r{   r|   zok (0 rows)companyz	(unnamed)categorycityratingzrating rc       · maps_urlrj   Trz   z row(s))zUltron leads DBre   rh   )r   r   phoneemail)	ultron_db
configuredr*   r   r   queryr   r   r   r~   r   r1   )r.   rS   rT   r   ncondpatsqlr   r   rN   partsrM   firstwheres   &&&            r   _source_ultronr      sp   $gugrRdE27C!!(H
I I3tf UPPQs SF! l"3%';C5 A558E=  $v%QSC !56 %H
y!00[19CuuSzzQV$ : 55??LL71X;-01GD6;;u#55655Lq} 45  GEIIf<<:!6<<"E		),2299;CCtCCL3t9+X.CM"ERwa=r"BCCJJ-  !#a&,0H
s   2H? ?I.
I)#I.)I.c                   V ^8  d   QhRR/# )r   rV   r   r	   )r
   s   "r   r   r      s      # r   c                    V P                  4       pVP                  R 4      '       d   R# VP                  R4      '       d   R# VP                  R4      '       d   R# R# )z.csvcsvz.xlsxxlsxz.xlsxlsN)lowerendswith)rV   lows   & r   _ext_ofr      sF    
**,C
||F
||G
||Fr   c                   V ^8  d   QhRR/# r   r   zlist[dict] | Noner	   )r
   s   "r   r   r      s        -  r   c                   a  \         P                  ! 4       o\         P                  ! 4       p SP	                  4       P                  RT  R2RRRR7      P                  4       P                  R. 4      p. pT F  pTP                  R	R
4      pTP                  RR
4      pTR8H  pT'       d   RM
\        T4      pT'       g   KK  TP                  R4      '       d   \        TR,          4      MRpTR,          TP                  R4      ;'       g    R
\        T4      ,           rY3T3R llpTP                  RRR	TRRT	,           RT
RTRTRT/4       K  	  T#   \         d     R# i ; i)z{Sheet-like files in the Google 'Jarvis Drive' folder, or None if the
Drive service account isn't configured on this deploy.Nr   z' in parents and trashed=falsedrivezmodifiedTime descz)files(id,name,mimeType,size,modifiedTime))r.   spacesorderByfieldsfilesrV   r   mimeTypez'application/vnd.google-apps.spreadsheetr   sizeidmodifiedTimec                   < V'       d0   SP                  4       P                  V R R7      P                  4       # SP                  4       P                  V R7      P                  4       # )ztext/csv)fileIdr   )r   )r   exportexecute	get_media)fid_gsheetsvcs   &&r   _fetch"_list_drive_sheets.<locals>._fetch  sT    yy{))3= * ??FwyI99;(((5==??r   storerM   zdrive:versionextfetch)r   _service
_folder_idr   r   listr   r   r   intr   r~   )fidr   outr   rV   mimer   r   r   r   verr   r   s               @r   _list_drive_sheetsr      sT   nn  IIKcU0
1'#:   giGR 	 

 CuuVR uuZ$BBe74=!"vs1V9~DdGaeeN399rSYFc 	@ 	

GWfdE8d?sFD%gvO 	P! $ J5  s   *E E#"E#c                   V ^8  d   QhRR/# r   r	   )r
   s   "r   r   r     s     $ $/ $r   c                 "   \         P                  ! 4       '       g   R#  \         P                  ! RR\         P                   2\        P
                  ! RRRRRR	R
RR//4      P                  4       RR/4      p \        P                  ! V 4      p. pT EFg  pTP                  R
4      pT'       g   K  \         P                  ! T4      p\        T4      pT'       g   KJ  TP                  R4      ;'       g    / pTP                  R4      p\        T;'       g    R4      P                  4       '       d   \        T4      MRp\        TP                  R4      ;'       g    TP                  R4      ;'       g    R4      \        TP                  R4      ;'       g    TP                  R4      ;'       g    R4      ,           \        T4      ,           p	T3R lp
TP                  RRR
TRRT,           RT	RTRTRT
/4       EKj  	  T#   \         d     R# i ; i)zeSheet-like files in the writable shared Supabase-storage bucket, or None
if storage isn't configured.NPOSTz/object/list/prefixr   limiti  sortBycolumnrV   orderasczContent-Typer@   metadatar   lastModified
updated_ateTagetagc                    \         P                  ! R R\         P                   R\        P                  P                  V RR7       24      # )r<   z/object/r   )safe)storage_doBUCKETrA   rB   quote)rM   s   &r   r   $_list_storage_sheets.<locals>._fetch5  sB    ;;'..!1 ,,,,Ss,;<>? ?r   r   r   rM   zstorage:r   r   r   )r   r   r   r   rI   dumpsencoderJ   r   r   	_dec_namer   r   isdigitr   r~   )dataitemsr   irM   rV   r   metar   r   r   s              r   _list_storage_sheetsr    s    {{mGNN#34JJ"gt 8VWe"DF GGMvx/0	2
 

4  CeeFm  %dmuuZ &&Bxx

O3355s4y4488N+KKtxx/EKKLTXXf%??&)9??R@ACFt9M  	?
 	

GYeZ#=MsFD%gvO 	P' * J1  s   A.G? ?HHc               $    V ^8  d   QhRRRRRR/# )r   r   bytesr   r   r   list[list[str]]r	   )r
   s   "r   r   r   ?  s!     1 15 1s 1 1r   c           
        VR 8X  d   V P                  RR4      p. p\        P                  ! \        P                  ! V4      4       FD  pTP                  V Uu. uF  p\        V4      NK  	  up4       \        V4      \        8  g   KC   V# 	  V# VR8X  d   ^ RI	pVP                  \        P                  ! V 4      RRR7      p. p VP                   Fw  pVP                  RR7       FH  pTP                  V Uu. uF  qUf   RM
\        V4      NK  	  up4       \        V4      \        8  g   KH   M	  \        V4      \        8  g   Kw   M	  VP                  4        V# \        R	V: 24      hu upi u upi   TP                  4        i ; i)
r   z	utf-8-sigignorer   NT)	read_only	data_only)values_onlyr   zunsupported ext )decoder   readerioStringIOr~   r   r*   _MAX_SHEET_ROWSopenpyxlload_workbookBytesIO
worksheets	iter_rowsclose
ValueError)	r   r   txtr   rN   r   r  wbwss	   &&       r   _rows_from_bytesr  ?  sQ   
e|kk+x0BKK,-AKK+AQ+,4yO+	 . 
f}##BJJt$4.2 $ 4		mm$7AKKa Hayc!f!<a HI4yO3 8 t9/ $ HHJ
'w/
00) , !I HHJs0   E.
3E8 9E3E8 /E8 	E8 3E8 8F
c                    V ^8  d   QhRRRR/# )r   r   r7   r   r  r	   )r
   s   "r   r   r   [  s       / r   c                    \         P                  V R ,          4      pV'       d   V^ ,          V R,          8X  d
   V^,          # \        V R,          ! 4       V R,          4      pV R,          V3\         V R ,          &   V# )rM   r   r   r   )r   r   r  )r   cachedr   s   &  r   	_get_rowsr  [  sd    ah'F&)q|+ayAgJL!E(3D	lD1L5Kr   c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
r   r   r  rS   r/   rT   r   q_lowerr   z!tuple[list[str], list[list[str]]]r	   )r
   s   "r   r   r   d  s1      o  S !Br   c                  a V '       g   . . 3# V ^ ,          p\        V 4      ^8  d
   V R,          MT p. pV F  pV'       d<   \        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      pM"VRP                  V4      P                  4       9   pV'       g   Kr  VP	                  V4       \        V4      \
        8  g   K   WF3# 	  WF3# )zReturn (header, matched_rows[:_HITS_PER_FILE]). Assumes row 0 is a header
when there's more than one row (true for lead exports).:   NNc              3     <"   T FG  p\        \        V4      4      \        S4      8  ;'       d    \        V4      P                  S4      x  KI  	  R # 5i)N)r*   r'   r   )rv   r   rT   s   & r   rw   _match_rows.<locals>.<genexpr>o  sC      ! _D	1OOgaj6I6I$6OOs   AATFrs   )r*   anyr   r   r~   _HITS_PER_FILE)	r   rS   rT   r  headerbodyhitsrN   oks	   &&f&     r   _match_rowsr*  d  s     2v!WF4y1}48$DD !! !! !B CHHQK--//B2KKN4yN*<  <r   c               $    V ^8  d   QhRRRRRR/# )r   r&  z	list[str]rowr   r   r	   )r
   s   "r   r   r   z  s&     W WY WY W3 Wr   c                   . p\        V4       F  w  r4T;'       g    RP                  4       pV'       g   K)  V\        V 4      8  d3   W,          P                  4       '       d   W,          P                  4       MRV 2pVP                  V RV 24       \        V4      ^8  g   K   M	  V'       d   RRP	                  V4      ,           # RRP	                  VR,          4      ,           # )zDPair header labels with values (non-empty only) for a readable line.r   r   =rm   r   :N   N)	enumerater1   r*   r~   r   )r&  r,  pairsr   vallabels   &&    r   _fmt_hitr4  z  s    EC.yyb!%&V_9J9J	!RSTUSVPWwau%&u:? ! -28fkk%((Vx&++cRTgBV7VVr   c          
     ,    V ^8  d   QhRRRRRRRRRR	/# )
r   r.   r   rS   r/   rT   deadliner9   r   r7   r	   )r
   s   "r   r   r     s6     B Bc BT B B B$ Br   c                .   R RRRR. RRRRR	R/p. p. p\         R
3\        R33 F5  w  rx V! 4       p	V	f   VP                  V4       K$  VP	                  V	4       K7  	  V'       g,   RV'       d   RRP                  V4       R2MR,           VR&   V# V P                  4       p
. . rV EF  p\        P                  ! 4       V8  d"   VP                  VR ,          R,           4       K?  VR,          e0   VR,          \        8  d   VP                  VR ,           R24       Ky  VR,          R8X  d   VP                  VR ,           R24       K   \        V4      pTP                  TR ,          4       \        YY*4      w  ppT'       g   K  RTR&   TR,          P                  RTR ,           RTR,           R\        T4       R24       T F%  pTR,          P                  \        TT4      4       K'  	  TR,          e   EKX  T^ ,           Uu. uF]  pTP!                  4       '       g   K  \        \#        T4      4      \        TP!                  4       4      8  g   KM  TP!                  4       NK_  	  ppT'       d   T^ ,          R,          MTR ,          TR&   R TR ,           2TR	&   EK  	  R!\        V4       2.pV'       dS   T^ ;;,          RRP                  VR",          4      ,           \        V4      ^8  d   R#MR,           R,           ,          uu&   V'       d8   VP                  R$\        V4       RR%P                  VR",          4       R24       V'       d$   VP                  RP                  V4       R&24       R%P                  V4      VR&   V#   \         d    Rp	 ELmi ; i  \         d!    TP                  TR ,           R24        EK'  \         d;   pTP                  TR ,           R\        T4      R,           R24        Rp?EKf  Rp?ii ; iu upi )'rV   zJARVIS DRIVE SHEETSrW   FrX   rY   r   rZ   Nr[   zGoogle Drivezshared storagezno sheet files foundre   ro   z not configured)z (time budget)r   z (>5MB)r   r   z (.xls not supported)z (xlsx: openpyxl not installed)z (read error: :N(   Nrh   TzFILE r   z): z
 match(es):NP   Nzsheet zscanned r`   r   zskipped ; z not configured)r   r  r   r~   extendr   r   time	monotonic_MAX_SHEET_BYTESr  ImportErrorr   r*  r*   r4  r1   r'   )r.   rS   rT   r6  r   r   
stores_offlisterr3  gotr  scannedskippedr   r   r   r&  r(  hr   textishr   s   &&&&                  r   _source_sheetsrG    s   ('5'2RdE27CEJ-~>/1ABD	(C ;e$LLD /) !:!6 77GH/13H 
ggiG2W>>x'NN1V9'778V9 QvY1A%ANNai[01U8uNNai[(=>?	Q<D 	qy!"44A4CLL%&	{"QwZL#&t9+Z!9 :G##HVQ$78 ;'.21g Ngggi %,/
Oc!'')n,L %1779g N7>GAJsOAfIK %ai[1E
? B G~&'EaD499WR[11\A%E2/145 	5xG~R		'"+0F/GqIJ		*-.o>?IIe$CMJs  	C	6  	NNai[(GHI 	NNai[s1vc{m1EF	NsG   N	N!P$-PPNN!&PPP.P

Pc                    V ^8  d   QhRRRR/# )r   r   r   r   r	   )r
   s   "r   r   r     s     ) ) ) )r   c                   \        T ;'       g    R 4      P                  4       pV'       g   R# \        V4      pV'       d   \        V4      MR pV'       d   \	        V4      ^8  d	   RVRR  2MV'       d   RV 2MRV R2p\
        P                  ! 4       \        ,           p\        WV4      \        WV4      \        WW54      .pV Uu. uF  qwR,          '       g   K  VNK  	  ppRRP                  R	 V 4       4      ,           R
,           p	V'       g	   RV RV	 2# RV R\	        V4       R2R .p
V FD  pV
P                  VR,          4       V
P                  VR,          4       V
P                  R 4       KF  	  RpV F6  pVR,          '       g   K  VP                  R4      '       g   K-  VR,          p M	  V Uu. uF$  qwP                  R4      '       g   K  VR,          NK&  	  ppRT;'       g    T 2pV'       d    VRRP                  V4      ,           ,          pVR
,          pV
P                  V4       V
P                  V	4       RP                  V
4      # u upi u upi )r   zGperson_lookup: give me a name, a company, or a phone number to look up.u	   phone …Nzphone r   rW   u   Checked — r:  c              3  f   "   T F'  qR ,          P                  4        RVR,           2x  K)  	  R# 5i)rV   z: rY   N)r   ru   s   & r   rw    person_lookup.<locals>.<genexpr>  s-      )@7>!V9??
R(}-ws   /1.zNo match for z in any source.
z
FOUND for z in z source(s):rV   rX   rZ   r[   zBest guess: u    — seen in ro   r   )r   r1   r3   r,   r*   r<  r=  _SCAN_BUDGET_Sr   r   rG  r   r~   r;  r   )r   r.   rS   rT   subjectr6  resultsrN   r(  checkedr   besttags	synthesiss   &             r   person_lookuprU    s   EKKR A #H%;q>2D*2s4yA~49+&(0vdV_!Ah ~~.0Ha40a40a4:<G -w!G**AAwD-tyy )@7>)@  @ @BEFG wi'8	BBySYK{;R
@C

1V9

1W:

2  DW::!%%,,[>D  #3deeElHAeHHdD3tyyqk*I_tyy66	IJJyJJw99S>7 .( 4s   II;IIi  P )g      @)+__conditional_annotations____doc__
__future__r   r   r  rI   r   r#   r<  urllib.errorrA   urllib.parseurllib.requestr   r   r   rN  r>  r  r%  r   __annotations__r   r   r    r'   r,   r3   rP   r   r   r   r   r   r   r  r  r  r*  r4  rG  rU  )rV  s   @r   <module>r]     s   & # 
 	  	 	       "  8:4 9<03+(/	*9@  +b F$N18,WBP)r   