
    tGVj[L                       d Z ddlmZ ddlZddlZddlmZmZmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZmZ  G d d      Z G d	 d
      Zd ZdjdZdZdZdddddgdddddddddddddgd ed      dd d!d"dd#d$d%gd&dd'ddd(dd)d*ddd+ddd,dd-d.dgdd/d0 ed1      dd2d3d/d4 ed5      id2d6d7d8d9dgd: ee      d;d<d=d>d? ee      d;d2gd@d!gdAZ G dB dC      Z G dD dE      Z G dF dG      Z G dH dI      Z G dJ dK      Z G dL dM      Z edNdOdPdQd e edRS            T      ZdkdUZ dV Z!dW Z"dX Z#dY Z$dZ Z%d[ Z&d\ Z'd] Z(d^ Z)d_ Z*d` Z+da Z,db Z-dc Z.dlddZ/de Z0df Z1dg Z2 G dh di      Z3y)mu  Email reader card tests — the thread engine (voice/mail_view.py), the Gmail
thread reader (voice/gmail_control.py), the IMAP one (voice/email_control.py)
and the HUD→engine contract (control/email_action.json, applied by
ControlWatcher._email_action). The JSON payloads here are EXACTLY what the Mac
HUD's EmailPanel writes, so these tests pin the contract between the Swift card
and the Python engine. No network, no HUD, no audio (fakes throughout).

Run:  .venv/bin/python -m pytest test_mail_card.py -q
    )annotationsN)datetime	timedeltatimezone)EmailMessage)email_controlgmail_controlc                      e Zd Zd Zd Zy)	FakeInboxc                    g | _         y N)notesselfs    </Users/ahmed/devFolder/Ultron/claude-voice/test_mail_card.py__init__zFakeInbox.__init__   s	    
    c                :    | j                   j                  |       y r   )r   append)r   notes     r   
put_nowaitzFakeInbox.put_nowait   s    

$r   N)__name__
__module____qualname__r   r    r   r   r   r      s     r   r   c                      e Zd Zd Zy)FakeAppc                "    t               | _        y r   )r   inboxr   s    r   r   zFakeApp.__init__!   s    [
r   N)r   r   r   r   r   r   r   r   r       s    !r   r   c                 ~    t         j                  j                  t         j                        } t               | _        | S )uZ   A ControlWatcher with no __init__ side effects — just enough to drive
    _email_action.)controlControlWatcher__new__r   app)ws    r   make_watcherr&   %   s.     	&&w'='=>AIAEHr   c                    t        | t              r| j                         n| }t        j                  |      j                         j                  d      S )N=)
isinstancestrencodebase64urlsafe_b64encodedecoderstrip)sbs     r   _b64ur2   -   s=     C(
aA##A&--/66s;;r   s   PNG

-fake-s   %PDF-fake-quoteT1M21752400000000SENTz
text/plainFromz+Ahmed <ahmed.alrajeh@alrugaibfurniture.com>)namevalueToElie <elie@example.com>SubjectzRe: Statue quoteDatezSun, 13 Jul 2026 12:00:00 +0300	   
Looks goodsizedata)mimeTypeheadersbody)idthreadIdinternalDatelabelIdspayloadM11752300000000INBOXUNREADzmultipart/mixedzElie Haddad <elie@example.com>#ahmed.alrajeh@alrugaibfurniture.comCcsara@example.comStatue quotezSat, 12 Jul 2026 14:02:11 +0300
Message-IDz<m1@example.com>    zHi Ahmed, see)rC   filenamerE   z	text/htmlrB   z<div onclick="steal()">Hi <b>Ahmed</b><script>alert(1)</script><img src="cid:logo1"><img src="https://track.me/p.gif"><a href="javascript:evil()">x</a><a href="https://reval.studio">site</a></div>	image/pngzlogo.pngz
Content-IDz<logo1>ALOGO)attachmentIdrA   )rC   rV   rD   rE   application/pdfquote_v2.pdfAPDF)rC   rD   parts)rF   messagesc                      e Zd Zd Zd Zy)_Execc                    || _         y r   _d)r   rB   s     r   r   z_Exec.__init__n   s	    r   c                    | j                   S r   rb   r   s    r   executez_Exec.executeq   s    wwr   N)r   r   r   r   re   r   r   r   r`   r`   m   s    r   r`   c                      e Zd ZddZy)_AttsNc                b    t         t        d|   }t        t        |      t	        |      d      S )N)rX   r\   r@   )PNGPDFr`   lenr2   )r   userId	messageIdrF   blobs        r   getz	_Atts.getv   s)    c*2.c$it=>>r   NNNr   r   r   ro   r   r   r   rg   rg   u   s    ?r   rg   c                  0    e Zd Zd ZddZddZd Zd	dZy)
	_Messagesc                    || _         y r   svcr   rv   s     r   r   z_Messages.__init__|   	    r   Nc                n    | j                   j                  j                  |       t        ddddgi      S )Nr^   r4   r3   )rF   rG   )rv   queriesr   r`   )r   rl   q
maxResultss       r   listz_Messages.list   s2    "j$D#A"BCDDr   c                d    t         d   D ]  }|d   |k(  st        |      c S  t        d|       )Nr^   rF   zno message )THREADr`   RuntimeError)r   rl   rF   formatmetadataHeadersms         r   ro   z_Messages.get   s9    
#Aw"}Qx $ [-..r   c                    t               S r   )rg   r   s    r   attachmentsz_Messages.attachments   s	    wr   c                f    | j                   j                  j                  |       t        ddi      S )NrF   SENT1)rv   sentr   r`   )r   rl   rE   s      r   sendz_Messages.send   s'    T"dG_%%r   rp   )NNNN)NN)r   r   r   r   r}   ro   r   r   r   r   r   rs   rs   {   s    E/&r   rs   c                      e Zd ZddZy)_ThreadsNc                N    |t         d   k7  rt        d      t        t               S )NrF   znot a thread id)r   r   r`   )r   rl   rF   r   s       r   ro   z_Threads.get   s$    011V}r   rp   rq   r   r   r   r   r      s    r   r   c                  &    e Zd Zd Zd Zd ZddZy)_Usersc                    || _         y r   ru   rw   s     r   r   z_Users.__init__   rx   r   c                ,    t        | j                        S r   )rs   rv   r   s    r   r^   z_Users.messages   s    ""r   c                    t               S r   )r   r   s    r   threadsz_Users.threads   s
    zr   Nc                    t        ddi      S )NemailAddressrO   )r`   )r   rl   s     r   
getProfilez_Users.getProfile   s    n&KLMMr   r   )r   r   r   r   r^   r   r   r   r   r   r   r      s    #Nr   r   c                      e Zd Zd Zd Zy)	FakeGmailc                     g | _         g | _        y r   )r   rz   r   s    r   r   zFakeGmail.__init__   s    	r   c                    t        |       S r   )r   r   s    r   userszFakeGmail.users   s    d|r   N)r   r   r   r   r   r   r   r   r   r      s    r   r           
      )hourstzinfoc                   t               }|dft        j                  d<   t        j                  j                          t        j                  j                          g | j                  t        dfd       | j                  t        dd        | j                  dd       | j                  t        d	d
        || j                  t        d|dz         |fS )z>Fake Gmail service in the account cache + captured HUD events.rO   workemitc                *    j                  | |f      S r   r   )etyperB   eventss     r   <lambda>zfresh.<locals>.<lambda>   s    fmmUDM.Jr   _nowc                     t         S r   NOWr   r   r   r   zfresh.<locals>.<lambda>       3r   EMAIL_ADDRESSahmad@revalstudio.com_accountc                     y)Nr   r   )as    r   r   zfresh.<locals>.<lambda>   s    r   ATT_ROOTr   )	r   r	   _SVC	mail_view_THREADSclear_ORDERsetattrsetenv)monkeypatchtmp_pathrv   r   s      @r   freshr      s    
+C"%'L!MMvF	6JL	6;7(?@	:/?@Iz8m3KL;r   c                z   t        |       \  }}t        j                  dd      }|d   d   dk(  sJ |d   d   }|d   dk(  r|d   dk(  sJ |d	   d
k(  sJ |d   \  }}|d   |d   fdk(  sJ |d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   du sJ |d   du sJ |d   dk(  sJ |d   dk(  sJ |d   j                  d      sJ |d   D cg c]  }|d   |d   |d    |d!   f c}d"d#t	        t
              d$fgk(  sJ |d   d   d%   d&k(  sJ |d   g k(  sJ |d'   d$k(  r|d   d(k(  sJ d)|v rd*|v sJ y c c}w )+N	from:elier   r   email_thread   	thread_idr3   accountsubjectrR   r^   msg_id)rK   r4   	from_namezElie Haddad	from_addrelie@example.comccrQ   outgoingFTdatez2026-07-12T14:02:11+03:00
date_human	Sun 14:02	body_textzHi Ahmedr   rV   mimerA   pathr[   rZ   rT   att_idr\   	body_htmlr?   z
2 messagesz1 attachment)r   r   show
startswithrk   rj   )r   _svcr   outevm1m2r   s           r   ?test_thread_event_is_oldest_first_with_outgoing_and_attachmentsr      s    %LD&
..f
-C!9Q<>)))	1Bk?d"r)}'>>>i=N***
^FBxL"X,'<777k?m+++k?0000d8))))j>U"""j>T!!!f:4444l{***k?%%j111 &(& z]AfIqy!F)<&(	*CHb9,;; ; ; mQ)V333m"""k?b R_%DDD3>S#888#8(s   D8c                   | j                  t        dd        t        j                  }t        j                  t        ddddd|            d	k(  sJ t        j                  t        ddd
ddd|            dk(  sJ t        j                  t        ddddd|            dk(  sJ t        j                  t        dd
ddd|            dk(  sJ y)uB   The HUD just prints date_human — every bucket is formatted here.r   c                     t         S r   r   r   r   r   r   z=test_date_human_is_riyadh_and_pre_formatted.<locals>.<lambda>   r   r   r   r   r      r   r   z11:00         r   r         z03 Feb 09:30i  r   z01 Dec 2024N)r   r   r   utc_humanr   )r   r   s     r   +test_date_human_is_riyadh_and_pre_formattedr      s    	6;7
,,CHT1b!QsCDOOOq"b!R469DE E E q!Q3/14BC C C r1a3/14AB B Br   c                    t        |       \  }}t        j                  dd       |d   d   }|d   dk(  sJ |d   D cg c]  }|d   	 c}d	dgk(  sJ y
c c}w )u   The brain chains off gmail_search (a MESSAGE id) — threads().get 404s on
    it, so we resolve threadId first and still get the whole thread.r4   r   r   r   r   r3   r^   r   rK   N)r   r   show_id)r   r   r   r   r   s        r   0test_show_id_resolves_a_message_id_to_its_threadr      sm     %LD&dF#	1Bk?d"""!#J0AAhK0T4L@@@0s   Ac                r   t        |       \  }}t        j                  dd       |d   d   d   d   d   }d|vrd|vsJ d	|vsJ d
|vsJ d|vsJ |j                  d      dk(  sJ dt	        j
                  t              j                          |v sJ d|v sJ d|v sJ |d   d   d   d   d   dk(  sJ y )Nr   r   r   r   r^   r   z<scriptalert(1)onclickzjavascript:track.mezdata:image/gif;base64,R0lGODzdata:image/png;base64,z<a href="https://reval.studio">z<b>Ahmed</b>images_blocked)r   r   r   countr,   	b64encoderi   r.   )r   r   r   htmls       r   >test_sanitizer_strips_script_handlers_and_blocks_remote_imagesr     s    %LD&NN;'!9Q<
#A&{3DD Zt%;;;D   $$$T!!!::45:::#F$4$4S$9$@$@$B#CDLLL,444T!!!!9Q<
#A&'78A===r   c                     ddddi} t        j                  d| d      \  }}d|vrd	|vsJ d
|v sJ d|vsJ d|v sJ d|v sJ |dk(  sJ t        j                  di d      \  }}d|v r|dk(  sJ y )Nc1rW   AAA)r   b64z<p style="background:url(https://t.io/x.png)">hi</p><iframe src="https://evil.io"></iframe><img SRC="cid:c1"><img src="java
script:alert(1)"><style>a{color:red} b{background:url(https://t.io/y.png)}</style>T)block_remotez<iframezevil.iozsrc="data:image/png;base64,AAA"r   zurl(about:blank)za{color:red}r   z"<img src="https://track.me/p.gif">Fsrc="https://track.me/p.gif")r   sanitize_html)inliner   blockedhtml2blocked2s        r   test_sanitizer_unitsr     s    [78F++	L 	T#MD' D Yd%:::,444T!!!%%%T!!!a<<  --,buFOE8)U2x1}DD}r   c           	     b   t        |       \  }}t        j                  dd       d|d   d   d   d   d   vsJ t               }t	        j
                  |j                  ddd	d
d             |D cg c]  }|d   dk(  s| c}d   d   }d|d   d   d   v sJ |d   d   d   dk(  sJ y c c}w )Nr   r   r   r   r   r^   r   r3   imagesrK   )r   r   actionr   r   r   r   )r   r   r   r&   asynciorun_email_action)r   r   r   r%   er   s         r   )test_load_images_reemits_with_remote_srcsr  (  s    %LD&NN;'VAYq\*5a8EEEEAKKdv+3t!E F G	6Vqt~5!V	6r	:1	=B)R
^A->{-KKKKj>!-.!333 
7s   1B,?B,c                   t        | |      \  }}t        j                  dd       t               }t	        j
                  |j                  ddddddd             |D cg c]  }|d	   d
k(  s| c}d   d   }|d   du r|d   dk(  sJ |d   dk(  r|d   dk(  sJ |d   j                  d      sJ t        |d   d      5 }|j                         t        k(  sJ 	 d d d        t        j                  d       |D cg c]  }|d	   dk(  s| c}d   d   d   d	   d   d	   }|d   |d   k(  sJ y c c}w # 1 sw Y   \xY wc c}w )Nr   r   r3   
attachmentrK   r\   r[   )r   r   r  r   r   rV   r   email_attachmentr  r   okTerrorrT   r   r   r   z/T1/quote_v2.pdfrbr   r^   r   )r   r   r   r&   r  r  r  endswithopenreadrj   emit_thread)	r   r   r   r   r%   r  r   fhatts	            r   5test_email_action_attachment_downloads_and_emits_pathr  7  s}   h/LD&NN;'AKKf&n!F G H 	:Vqt'99!V	:2	>q	ABd8t7r 111k?d"r(|t';;;f:1222	bj$	2wwyC 
  $
7f! 61f
7
;A
>$&&')Cv;"V*$$$ 
; 
 	 8s$   D3-D3D8>EE8Ec                L   t        | |      \  }}t        j                  d      dk(  sJ t        j                  d      dk(  sJ t        j                  d      dk(  sJ t        j                  dd      }|j                  t        j
                  dz  k(  r|j                  dk(  sJ y )	Nz../../../etc/passwdpasswdza/b/../c.pdfzc.pdfrT   r
  r3   z../../etc/passwd)r   r   	safe_name	dest_pathparentr   r8   )r   r   r   _eventsps        r   .test_attachment_filename_cannot_escape_the_dirr  L  s    +x0MD'45AAA~.'999r"l222D"45A88y))D00QVVx5GGG5Gr   c           
        t        |       \  }}t        j                  dd       t               }t	        j
                  |j                  dddddd             |j                  d   }|d	   dk(  sJ t        j                  |d
   dz         j                         }d|v sJ d|v sJ d|v sJ d|v sJ d|v sJ dddddf|v sJ t        d |j                  j                  j                  D              sJ y )Nr   r   r3   replyrK   zSounds good, sending the PO.r   r   r  r   rE   r  rG   raw==z"To: Elie Haddad <elie@example.com>zSubject: Re: Statue quotezIn-Reply-To: <m1@example.com>zReferences: <m1@example.com>email_reply_sentTrT   )r   r  r  c              3  $   K   | ]  }d |v  
 yw)z[mail] Ahmed sent a replyNr   .0ns     r   	<genexpr>zKtest_email_action_reply_sends_in_thread_and_tells_jarvis.<locals>.<genexpr>g  s     K9JA*a/9J   )r   r   r   r&   r  r  r  r   r,   urlsafe_b64decoder.   anyr$   r   r   )r   rv   r   r%   rE   r!  s         r   8test_email_action_reply_sends_in_thread_and_tells_jarvisr,  U  s#   $KCNN;'AKKf >!@ A B 88B<D
t###

"
"4;#5
6
=
=
?C/3666&#---*c111)S000)S000d$*,!. /289 9 9K9J9JKKKKr   c           
     \   t        |       \  }}t        j                  dd       t               }t	        j
                  |j                  dddddd             t        j                  |j                  d   d	   d
z         j                         }d|v sJ d|j                  d      d   vsJ y )Nr   r   r3   	reply_allrK   zAll: noted.r   r  r!  r"  zCc: sara@example.comrO   z

r   )r   r   r   r&   r  r  r  r,   r*  r   r.   split)r   rv   r  r%   r!  s        r   )test_reply_all_keeps_the_other_recipientsr0  j  s    %LCNN;'AKKf!/ 0 1 
"
"388B<#6#=
>
E
E
GC!S(((0		&8I!8LLLLr   c           
        t        |       \  }}t        j                  dd       dd}| j                  t        d|       t               }t        j                  |j                  ddddd	d
             |D cg c]  }|d   dk(  s| c}d   d   }|d   du rd|d   v sJ t        d |j                  j                  j                  D              sJ y c c}w )Nr   r   Fc                    t        d      )N
gmail down)r   )labelmidrE   r.  s       r   boomz:test_reply_failure_is_reported_not_swallowed.<locals>.boomz  s    <((r   _replyr3   r  rK   hir   r   r#  r  r   r  r3  r  c              3  $   K   | ]  }d |v  
 yw)FAILEDNr   r%  s     r   r(  z?test_reply_failure_is_reported_not_swallowed.<locals>.<genexpr>  s     8&7x1}&7r)  )F)r   r   r   r   r	   r&   r  r  r  r+  r$   r   r   )r   r   r   r6  r%   r  r   s          r   ,test_reply_failure_is_reported_not_swallowedr;  v  s    %LD&NN;') x6AKKf!& ' ( 	:Vqt'99!V	:2	>q	ABd8uG!<<<8aeekk&7&78888 
;s   8CCc           
        t        | |      \  }}g | j                  t        j                  dfd       |dz  }|j	                  t
               t               }t        j                  |j                  ddt        |      d             rt        |      d   v sJ j                          t        j                  |j                  ddt        |dz        d             g k(  sJ y )	NPopenc                &    j                  |       S r   r   )argvkwopeneds     r   r   zBtest_email_action_open_attachment_opens_the_file.<locals>.<lambda>  s    6==+>r   z	quote.pdfr3   open_attachment)r   r  r   r  zgone.pdf)r   r   r   
subprocesswrite_bytesrj   r&   r  r  r  r*   r   )r   r   r   r  fr%   rA  s         @r   0test_email_action_open_attachment_opens_the_filerF    s    +x0MD'F	,,g>@;AMM#AKKd>O),Q!1 2 3c!fr
***
LLNKKd>O),X
-B)C!E F GR<<r   c                    t        |       \  }}t        j                  dd       t               }t	        j
                  |j                  ddd             dddif|v sJ dt        j                  vsJ y )Nr   r   r3   closer   r  
card_closedraft_id)r   r   r   r&   r  r  r  r   )r   r   r   r%   s       r   #test_close_drops_the_card_and_staterL    sk    %LD&NN;'AKKdg FGH:t,-777y)))))r   c                   t        |       \  }}t               }t        j                  |j	                  dddd             t        j                  |j	                  ddd             |j
                  j                  j                  g k(  sJ y)z8A stale card (engine restarted) must not crash or speak.GONEr  X)r   r  r   rH  rI  N)r   r&   r  r  r  r$   r   r   )r   r   r  r%   s       r   $test_unknown_thread_action_is_a_nooprP    sp    +&MD'AKKf+.!0 1 2KKf HIJ55;;"""r   c                     t               } d| d<   d| d<   d| d<   d| d<   d	| d
<   | j                  d       | j                  dd       | j                  t        ddd       | S )Nr;   r7   r   r:   Invoicer<   zSat, 12 Jul 2026 09:00:00 +0300r=   <abc@example.com>rS   
Plain bodyz<p>HTML <b>body</b></p>r   )subtypeapplicationpdfinv.pdf)maintyperU  rV   )r   set_contentadd_alternativeadd_attachmentrj   )r   s    r   	_imap_msgr]    sw    A)AfI%AdGAiL1AfI)AlOMM,/@S=%'  )Hr   c                 B   t        j                  t                     } | d   j                         dk(  sJ d| d   v sJ | d   }t	        |      dk(  sJ |d   d   d	k(  sJ |d   d
   dk(  sJ |d   d   t	        t
              k(  sJ |d   d   j                         sJ y )Nr   rT  z<b>body</b>r   r   r   r   rV   rX  r   rZ   rA   r   )r   	_parts_ofr]  striprk   rj   isdigit)r]   attss     r   8test_imap_message_parts_are_untruncated_with_attachmentsrc    s    ##IK0E##%555E+....Dt9>>7:)+++76?////76?c#h&&&78$$&&&r   c                 *   t               } t        j                  |       dk(  sJ t               }|j                  dd       d|d<   t        j                  |      dk(  sJ t        j                  d      dk(  sJ t        j                  d      d	k(  sJ y )
NrS  rS   z<def@example.com>z#<abc@example.com> <ccc@example.com>
ReferenceszSent|42)Sent42rg  )rM   rg  )r]  r   _root_idreplace_header_split_ident)r   r   s     r   !test_imap_root_id_and_ident_splitrk    s    A!!!$(;;;;	Bl$78<B|!!"%)<<<<%%i0NBBB%%d+>>>r   c                   dd l }g  G fdd      }| j                  |d|       | j                  dd       | j                  dd       | j                  t        d	d
        | j                  t        dd        t        j                  dd      }d   \  }}|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ d|d   v sJ |dgk(  sJ d|v sJ y )Nr   c                  4    e Zd ZddZd Zd Zd Zd fd	Zy)8test_imap_reply_sets_threading_headers.<locals>.FakeSMTPNc                     y r   r   )r   hostporttimeouts       r   r   zAtest_imap_reply_sets_threading_headers.<locals>.FakeSMTP.__init__      r   c                    | S r   r   r   s    r   	__enter__zBtest_imap_reply_sets_threading_headers.<locals>.FakeSMTP.__enter__  s    Kr   c                     y)NFr   )r   r   s     r   __exit__zAtest_imap_reply_sets_threading_headers.<locals>.FakeSMTP.__exit__  s    r   c                     y r   r   )r   userpws      r   loginz>test_imap_reply_sets_threading_headers.<locals>.FakeSMTP.login  rs  r   c                ,    j                  ||f       y r   r   )r   msgto_addrsr   s      r   send_messagezEtest_imap_reply_sets_threading_headers.<locals>.FakeSMTP.send_message  s    KKh(r   r   )r   r   r   r   ru  rw  r{  r  )r   s   r   FakeSMTPrn    s    					)r   r  SMTP_SSLr   r   EMAIL_PASSWORDrz  _imapc                     t               S r   )	_FakeIMAPr   r   r   r   z8test_imap_reply_sets_threading_headers.<locals>.<lambda>  s    	r   _fetchc                    t               S r   )r]  )r   folderuids      r   r   z8test_imap_reply_sets_threading_headers.<locals>.<lambda>  s    y{r   zINBOX|7zOn it.r  r:   r;   r<   zRe: InvoicezIn-Reply-TorS  re  r   z
Replied to)smtplibr   r   r   r  )r   r  r  r   r}  rcptsr   s         @r   &test_imap_reply_sets_threading_headersr    s    D) )  X6(?@'.w0CDx:< 

i
2CbJCt91111y>]***}!4444#l"3333'((((3r   c                      e Zd Zd Zd Zy)r  c                    ddgfS )NOK   1r   )r   r  s     r   selectz_FakeIMAP.select  s    tf~r   c                     y r   r   r   s    r   logoutz_FakeIMAP.logout  s    r   N)r   r   r   r  r  r   r   r   r  r    s    r   r  )r0   zstr | bytesreturnr*   r   )r  r   )4__doc__
__future__r   r  r,   r   r   r   email.messager   voice.controlr!   voice.mail_viewr   voicer   r	   r   r   r&   r2   ri   rj   rk   r   r`   rg   rs   r   r   r   r   r   r   r   r   r   r   r  r  r  r,  r0  r;  rF  rL  rP  r]  rc  rk  r  r  r   r   r   <module>r     s`   #   2 2 &  # .
   ! !
<
 !
  D/(#KM!,EF&1CD#.OP "#E,,?@
	
  D/ (+-#.NO!CE!,>?&@#.OP)4FG ".2&(%2HIK!,"$eI'J KL "-**6!K L.5s3xHJ "3.4c#hGI	
!03
l ? ?& &, N N  tQB(913E*FG&9<B"A>"E*
4%*HL*	M9"$*#	'?"J r   