+
    Kib                     "  a  R4 t50 t R 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It^ RIHt ]P$                  ! ]4      tRtR] R2tRtR R ltR	 R
 ltR R ltRs] ^ k RtRs] ^k ]P<                  ! 4       tRs ] ^k Rt!R R lt"R R lt#R R lt$R R lt%R5R R llt&R t'R R lt(R R lt)R6R R  llt*R! R" lt+R# R$ lt,R%R&/R' R( llt-R) R* lt.R+ R, lt/R%R&/R- R. llt0R%R&/R/ R0 llt1^2t2R1t3R2 R3 lt4R# )7u  Tirith pre-exec security scanning wrapper.

Runs the tirith binary as a subprocess to scan commands for content-level
threats (homograph URLs, pipe-to-interpreter, terminal injection, etc.).

Exit code is the verdict source of truth:
  0 = allow, 1 = block, 2 = warn

JSON stdout enriches findings/summary but never overrides the verdict.
Operational failures (spawn error, timeout, unknown exit code) respect
the fail_open config setting. Programming errors propagate.

Auto-install: if tirith is not found on PATH or at the configured path,
it is automatically downloaded from GitHub releases to $HERMES_HOME/bin/tirith.
The download always verifies SHA-256 checksums.  When cosign is available on
PATH, provenance verification (GitHub Actions workflow signature) is also
performed.  If cosign is not installed, the download proceeds with SHA-256
verification only — still secure via HTTPS + checksum, just without supply
chain provenance proof.  Installation runs in a background thread so startup
never blocks.
N)get_hermes_homezsheeki03/tirithz^https://github.com/z,/\.github/workflows/release\.yml@refs/tags/vz+https://token.actions.githubusercontent.comc                <    V ^8  d   QhR\         R\        R\        /#    keydefaultreturnstrbool)formats   "2/home/ubuntu/hermes-agent/tools/tirith_security.py__annotate__r   3   s!     / /3 / /$ /    c                 `    \         P                  ! V 4      pVf   V# VP                  4       R9   # )N)1trueyes)osgetenvlowerr   r   vals   && r   	_env_boolr   3   s+    
))C.C
{99;...r   c                <    V ^8  d   QhR\         R\        R\        /# r   r
   int)r   s   "r   r   r   :   s!      #   r   c                 x    \         P                  ! V 4      pVf   V#  \        V4      #   \         d    Tu # i ; i)N)r   r   r   
ValueErrorr   s   && r   _env_intr   :   s;    
))C.C
{3x s   
) 99c                $    V ^8  d   QhR\         /# r   r   )dict)r   s   "r   r   r   D   s      t r   c                    RRRRR^RR/p  ^ RI Hp V! 4       P                  R/ 4      ;'       g    / pR\	        R	VP                  RV R,          4      4      R\
        P                  ! R
VP                  RV R,          4      4      R\        RVP                  RV R,          4      4      R\	        RVP                  RV R,          4      4      /#   \         d    / p Li ; i)z@Load security settings from config.yaml, with env var overrides.tirith_enabledTtirith_pathtirithtirith_timeouttirith_fail_open)load_configsecurityTIRITH_ENABLED
TIRITH_BINTIRITH_TIMEOUTTIRITH_FAIL_OPEN)hermes_cli.configr)   get	Exceptionr   r   r   r   )defaultsr)   cfgs      r   _load_security_configr4   D   s     	$x!D	H1m
B/552
 	)$4cgg>NPXYiPj6klryysww}h}F]/^_(#3SWW=MxXhOi5jkI&8#''BTV^_qVr:st	   s   #C C CCF iQ c                $    V ^8  d   QhR\         /# r!   r
   )r   s   "r   r   r   l   s     " "# "r   c                 (    \        \        4       4      # )zAReturn the Hermes home directory, respecting HERMES_HOME env var.)r
   r    r   r   _get_hermes_homer:   l   s     !!r   c                $    V ^8  d   QhR\         /# r!   r7   )r   s   "r   r   r   q   s     F Fc Fr   c                 R    \         P                  P                  \        4       R4      # )z3Return the path to the install-failure marker file.z.tirith-install-failed)r   pathjoinr:   r9   r   r   _failure_marker_pathr?   q   s    77<<(*,DEEr   c                2    V ^8  d   QhR\         R,          /# r   r   Nr7   )r   s   "r   r   r   v   s      cDj r   c                 j    \        4       p \        P                  P                  V 4      p\        P                  ! 4       V,
          \
        8  d   R# \        V R4      ;_uu_ 4       pVP                  4       P                  4       uuRRR4       #   + '       g   i     R# ; i  \         d     R# i ; i)zRead the failure reason from the disk marker.

Returns the reason string, or None if the marker doesn't exist or is
older than _MARKER_TTL.
Nr)
r?   r   r=   getmtimetime_MARKER_TTLopenreadstripOSError)pmtimefs      r   _read_failure_reasonrN   v   ss     "  #IIK%K/!S\\Q668>># \\\ s6   AB# B# &B
B# B 	B#  B# #B21B2c                $    V ^8  d   QhR\         /# r!   r   )r   s   "r   r   r      s      D r   c                     \        4       p V f   R# V R8X  d)   \        P                  ! R4      '       d   \        4        R# R# )zCheck if a recent install failure was persisted to disk.

Returns False (allowing retry) when:
- No marker exists
- Marker is older than _MARKER_TTL (24h)
- Marker reason is 'cosign_missing' and cosign is now on PATH
Fcosign_missingcosignT)rN   shutilwhich_clear_install_failed)reasons    r   _is_install_failed_on_diskrX      s7     "#F~!!fll8&<&<r   c                $    V ^8  d   QhR\         /# )r   rW   r7   )r   s   "r   r   r      s       r   c                .    \        4       p\        P                  ! \        P                  P	                  V4      RR7       \        VR4      ;_uu_ 4       pVP                  V 4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i)a  Persist install failure to disk to avoid retry on next process.

Args:
    reason: Short tag identifying the failure cause. Use "cosign_missing"
            when cosign is not on PATH so the marker can be auto-cleared
            once cosign becomes available.
Texist_okwN)r?   r   makedirsr=   dirnamerG   writerJ   )rW   rK   rM   s   &  r   _mark_install_failedra      s_     "
BGGOOA&6!S\\QGGFO \\\ s0   AB A1'B 1B	<B B BBc                 h     \         P                  ! \        4       4       R#   \         d     R# i ; i)z3Remove the failure marker after successful install.N)r   unlinkr?   rJ   r9   r   r   rV   rV      s)    
		&() s   " 11c                $    V ^8  d   QhR\         /# r!   r7   )r   s   "r   r   r      s       r   c                     \         P                  P                  \        4       R4      p \         P                  ! V RR7       V # )z/Return $HERMES_HOME/bin, creating it if needed.binTr[   )r   r=   r>   r:   r^   )ds    r   _hermes_bin_dirrh      s-    
%'/AKKD!Hr   c                2    V ^8  d   QhR\         R,          /# rA   r7   )r   s   "r   r   r      s      d
 r   c                     \         P                  ! 4       p \         P                  ! 4       P                  4       pV R8X  d   RpMV R8X  d   RpMR# VR	9   d   RpMVR
9   d   RpMR# V RV 2# )z@Return the Rust target triple for the current platform, or None.Darwinzapple-darwinLinuxzunknown-linux-gnuNx86_64aarch64-)rm   amd64)rn   arm64)platformsystemmachiner   )rs   rt   platarchs       r   _detect_targetrw      sr    __F &&(G	7	"%%	(	(V1TFr   c                <    V ^8  d   QhR\         R\         R\        /# )r   urldesttimeoutr   )r   s   "r   r   r      s!     $ $ $3 $ $r   c           	        \         P                  P                  V 4      p\        P                  ! R4      pV'       d   VP                  RRV 24       \         P                  P                  W2R7      ;_uu_ 4       p\        VR4      ;_uu_ 4       p\        P                  ! WV4       RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i)zDownload a URL to a local file.GITHUB_TOKENAuthorizationztoken )r{   wbN)
urllibrequestRequestr   r   
add_headerurlopenrG   rT   copyfileobj)ry   rz   r{   reqtokenresprM   s   &&&    r   _download_filer      s    
..
 
 
%CIIn%E&(89					5	5tD$?O?OST4# @P	5	5?O?O	5	5	5s$   ;CB9	'C9C	CC	c          	      V    V ^8  d   QhR\         R\         R\         R\        R,          /# )r   checksums_pathsig_path	cert_pathr   Nr	   )r   s   "r   r   r      s-     % %3 %# %# %$QU+ %r   c                   \         P                  ! R4      pV'       g   \        P                  R4       R#  \        P
                  ! VRRVRVR\        R\        V .R	R	^R
7      pVP                  ^ 8X  d   \        P                  R4       R	# \        P                  RVP                  VP                  P                  4       4       R#   \        \        P                  3 d"   p\        P                  RT4        Rp?R# Rp?ii ; i)uO  Verify cosign provenance signature on checksums.txt.

Returns:
    True  — cosign verified successfully
    False — cosign found but verification failed
    None  — cosign not available (not on PATH, or execution failed)

The caller treats both False and None as "abort auto-install" — only
True allows the install to proceed.
rS   zcosign not found on PATHNzverify-blobz--certificatez--signaturez--certificate-identity-regexpz--certificate-oidc-issuerTcapture_outputtextr{   z%cosign provenance verification passedz(cosign verification failed (exit %d): %sFzcosign execution failed: %s)rT   rU   loggerinfo
subprocessrun_COSIGN_IDENTITY_REGEXP_COSIGN_ISSUER
returncodewarningstderrrI   rJ   TimeoutExpired)r   r   r   rS   resultexcs   &&&   r   _verify_cosignr      s     \\(#F./]iH,.E(.  

 !KK?@NNE ++V]]-@-@-BDZ../ 4c:s   AC 9C D"C>>Dc                H    V ^8  d   QhR\         R\         R\         R\        /# )r   archive_pathr   archive_namer   r	   )r   s   "r   r   r      s)      3  3 SW r   c                  a	 Rp\        V4      ;_uu_ 4       o	S	 FN  pVP                  4       P                  R^4      p\        V4      ^8X  g   K5  V^,          V8X  g   KE  V^ ,          p M	  RRR4       V'       g   \        P                  RV4       R# \        P                  ! 4       p\        V R4      ;_uu_ 4       o	\        V	3R lR4       F  pVP                  V4       K  	  RRR4       VP                  4       pW8w  d   \        P                  RW84       R# R	#   + '       g   i     L; i  + '       g   i     LS; i)
z4Verify SHA-256 of the archive against checksums.txt.Nz  zNo checksum entry for %sFrbc                  &   < S P                  R 4      # )i    )rH   )rM   s   r   <lambda>"_verify_checksum.<locals>.<lambda>  s    !&&,r   r   z&Checksum mismatch: expected %s, got %sT)rG   rI   splitlenr   r   hashlibsha256iterupdate	hexdigest)
r   r   r   expectedlinepartsshachunkactualrM   s
   &&&      @r   _verify_checksumr      s    H	n		DJJL&&tQ/E5zQ58|#; 8  
 1<@
..
C	lD	!	!Q.4EJJu 5 
" ]]_F?R' 
	 
"	!s#   3DDD=)D1D.	1E	log_failuresTc                `    V ^8  d   QhR\         R\        \        R,          \        3,          /# )r   r   r   N)r   tupler
   )r   s   "r   r   r     s+     Z2 Z2T Z2U3:s?5K Z2r   c                B	   V '       d   \         P                  M\         P                  p\        4       pV'       g@   \         P	                  R\
        P                  ! 4       \
        P                  ! 4       4       R## RV R2pR\         R2p\        P                  ! RR7      p \        P                  P                  WS4      p\        P                  P                  VR	4      p\        P                  P                  VR
4      p\        P                  P                  VR4      p	\         P	                  RV4        \        V RV 2V4       \        V R2V4       Rp\         P$                  ! R4      '       ds    \        T R2T4       \        T R2T	4       \'        YxT	4      pTRJ d   RpMSTRJ d#   T! R4       R%\         P"                  ! TRR7       # \         P	                  R4       M\         P	                  R4       \)        YgT4      '       g   R&\         P"                  ! TRR7       # \*        P,                  ! TR4      ;_uu_ 4       pTP/                  4        Fb  pTP0                  R8X  g$   TP0                  P3                  R4      '       g   K7  RTP0                  9   d   KJ  RTn        TP5                  Y4        M.	  T! R4       R'uuRRR4       \         P"                  ! TRR7       #  RRR4       \        P                  P                  TR4      p\        P                  P                  \7        4       R4      p\         P8                  ! TT4       \        P:                  ! T\        P<                  ! T4      P>                  \<        P@                  ,          \<        PB                  ,          \<        PD                  ,          4       T'       d   RMR p\         P	                  R!TT4       TR"3\         P"                  ! TRR7       #   \         d.   p
T! RT
4       R$u Rp
?
\         P"                  ! TRR7       # Rp
?
ii ; i  \         d"   p
\         P	                  RT
4        Rp
?
ELkRp
?
ii ; i  + '       g   i     EL; i  \         P"                  ! TRR7       i ; i)(aJ  Download and install tirith to $HERMES_HOME/bin/tirith.

Verifies provenance via cosign and SHA-256 checksum.
Returns (installed_path, failure_reason).  On success failure_reason is "".
failure_reason is a short tag used by the disk marker to decide if the
failure is retryable (e.g. "cosign_missing" clears when cosign appears).
z/tirith auto-install: unsupported platform %s/%sNztirith-z.tar.gzzhttps://github.com/z/releases/latest/downloadztirith-install-)prefixzchecksums.txtzchecksums.txt.sigzchecksums.txt.pemu9   tirith not found — downloading latest release for %s.../z/checksums.txtztirith download failed: %sT)ignore_errorsFrS   z/checksums.txt.sigz/checksums.txt.pemz=tirith install aborted: cosign provenance verification failedz5cosign execution failed, proceeding with SHA-256 onlyz?cosign artifacts unavailable (%s), proceeding with SHA-256 onlyu{   cosign not on PATH — installing tirith with SHA-256 verification only (install cosign for full supply chain verification)zr:gzr&   z/tirithz..z"tirith binary not found in archivezcosign + SHA-256zSHA-256 onlyztirith installed to %s (%s)r5   )Nunsupported_platform)Ndownload_failed)Ncosign_verification_failed)Nchecksum_failed)Nbinary_not_in_archive)#r   r   debugrw   r   rr   rs   rt   _REPOtempfilemkdtempr   r=   r>   r   r1   rT   rmtreerU   r   r   tarfilerG   
getmembersnameendswithextractrh   movechmodstatst_modeS_IXUSRS_IXGRPS_IXOTH)r   logtargetr   base_urltmpdirr   r   r   r   r   cosign_verifiedcosign_resulttarmembersrcrz   verifications   $                 r   _install_tirithr     s    )&..fllCFE__&(8(8(:	<++VHG,L$UG+DEH%67FF2ww||F9fo>77<<(;<GGLL)<=	OQWX	+hZq7FhZ~6G  <<!!Y(+=>I(+=>	J !/~ S D(&*O"e+ WX=F 	fD1? KK WXKK N O  lKK*2 	fD1/ \\,//3..*;;(*fkk.B.B9.M.Mv{{* "*FKKK/ + 894 0/. 	fD1  0 ggll68,ww||O-x8C
rwwt},,t||;dllJT\\YZ-<).14FRx 	fD1w  	+,c2**r 	fD1w	+  d]_bccd, 0//. 	fD1s   "BR 8 P R 7Q $R >R )R AQ08Q0
R ,DR P>
P9P>R 9P>>R Q-Q("R (Q--R 0R	;	R Rc                0    V ^8  d   QhR\         R\        /# r   configured_pathr   r	   )r   s   "r   r   r   v  s     ' 's 't 'r   c                    V R8g  # )zHReturn True if the user explicitly configured a non-default tirith path.r&   r9   )r   s   &r   _is_explicit_pathr   v  s    h&&r   c                0    V ^8  d   QhR\         R\         /# r   r7   )r   s   "r   r   r   {  s     ` `# `# `r   c                   \         e   \         \        Jd   \         # \        P                  P	                  V 4      p\        V 4      p\         \        J pV'       d   \        P                  P                  V4      '       d0   \        P                  ! V\        P                  4      '       d   Vs V# \        P                  ! V4      pV'       d   Vs V# \        P                  RV 4       \        s RsV# \        P                  ! R4      pV'       d   Vs Rs\        4        V# \        P                  P                  \!        4       R4      p\        P                  P                  V4      '       d<   \        P                  ! V\        P                  4      '       d   Vs Rs\        4        V# V'       d;   \        R8X  d.   \        P                  ! R4      '       d   Rs Rs\        4        RpMV# \"        e   \"        P%                  4       '       d   V# \'        4       pVe   \)        4       '       d   \        s VsV# \+        4       w  rxV'       d   Vs Rs\        4        V# \        s Vs\-        V4       V# )	u  Resolve the tirith binary path, auto-installing if necessary.

If the user explicitly set a path (anything other than the bare "tirith"
default), that path is authoritative — we never fall through to
auto-download a different binary.

For the default "tirith":
1. PATH lookup via shutil.which
2. $HERMES_HOME/bin/tirith (previously auto-installed)
3. Auto-install from GitHub releases → $HERMES_HOME/bin/tirith

Failed installs are cached for the process lifetime (and persisted to
disk for 24h) to avoid repeated network attempts.
Nz6Configured tirith path %r not found; scanning disabledexplicit_path_missingr&   r5   rR   rS   F)_resolved_path_INSTALL_FAILEDr   r=   
expanduserr   isfileaccessX_OKrT   rU   r   r   _install_failure_reasonrV   r>   rh   _install_threadis_aliverN   rX   r   ra   )	r   expandedexplicitinstall_failedfound
hermes_bindisk_reason	installedrW   s	   &        r   _resolve_tirith_pathr   {  s   $ !nO&Kww!!/2H 1H#6N 77>>(##		(BGG(D(D%NOX&"NLOQ`a("9
 LL"E"$o/:J	ww~~j!!bii
BGG&D&D#"$
 "&666<<;Q;Q!N&(#!#"NO
 "'?'?'A'A
 '(K#=#?#?("-')I""$ %N$ Or   c                $    V ^8  d   QhR\         /# r   r   rP   )r   s   "r   r   r     s     ) ) )r   c                Z   \         ;_uu_ 4        \        e    RRR4       R# \        P                  ! R4      pV'       d   VsRs RRR4       R# \
        P                  P                  \        4       R4      p\
        P                  P                  V4      '       d;   \
        P                  ! V\
        P                  4      '       d   VsRs RRR4       R# \        V R7      w  r4V'       d   VsRs\        4        M\        sVs\        V4       RRR4       R#   + '       g   i     R# ; i)z6Background thread target: download and install tirith.Nr&   r5   )r   )_install_lockr   rT   rU   r   r   r=   r>   rh   r   r   r   r   rV   r   ra   )r   r   r   r   rW   s   $    r   _background_installr     s     
% 
 X&"N&(# 
 WW\\/"3X>
77>>*%%"))J*H*H'N&(#! 
$ ,F	&N&(#!#,N&,# (5 
s)   
DDDA7DD8DD*	c                $    V ^8  d   QhR\         /# r   rP   )r   s   "r   r   r     s     O Od Or   c                   \        4       pVR,          '       g   R# \        ei   \        \        Jd[   \        p\        P                  P                  V4      '       d.   \        P                  ! V\        P                  4      '       d   V# R# VR,          p\        V4      p\        P                  P                  V4      pV'       d   \        P                  P                  V4      '       d0   \        P                  ! V\        P                  4      '       d   VsV# \        P                  ! V4      pV'       d   VsV# \        sRsR# \        P                  ! R4      pV'       d   VsRs\        4        V# \        P                  P                  \        4       R4      p\        P                  P                  V4      '       d<   \        P                  ! V\        P                  4      '       d   VsRs\        4        V# \        \        J d9   \        R8X  d,   \        P                  ! R4      '       d   RsRs\        4        MR# \!        4       pVe   \#        4       '       d   \        sVsR# \$        e   \$        P'                  4       '       g4   \(        P*                  ! \,        R	V /R
R7      s\$        P/                  4        R# )a  Ensure tirith is available, downloading in background if needed.

Quick PATH/local checks are synchronous; network download runs in a
daemon thread so startup never blocks. Safe to call multiple times.
Returns the resolved path immediately if available, or None.
r$   Nr%   r   r&   r5   rR   rS   r   T)r   kwargsdaemon)r4   r   r   r   r=   r   r   r   r   r   rT   rU   r   rV   r>   rh   rN   rX   r   r   	threadingThreadr   start)	r   r3   r=   r   r   r   r   r   r   s	   $        r   ensure_installedr    s     
!C   !nO&K77>>$BIIdBGG$<$<K-(O 1Hww!!/2H 77>>(##		(BGG(D(D%NOX&"NL("9 LL"E"$o/:J	ww~~j!!bii
BGG&D&D#"$ ("&666<<;Q;Q!N&(#!#
 '(K#=#?#?("- o&>&>&@&@#**&"L1

 	r   i  c                0    V ^8  d   QhR\         R\        /# )r   commandr   )r
   r"   )r   s   "r   r   r   X  s"     FH FHC FHD FHr   c           
     v   \        4       pVR,          '       g	   RRR. RR/# \        VR,          4      pVR,          pVR	,          p \        P                  ! VR
RRRRRV .RRVR7      pTP                  pT^ 8X  d   RpMJT^8X  d   RpM@T^8X  d   RpM6\
        P                  RT4       T'       d   RRR. RRT R2/# RRR. RRT R2/# . p	Rp
 TP                  P                  4       '       d!   \        P                  ! TP                  4      M/ pTP                  R. 4      pTR\         p	TP                  RR4      ;'       g    RR\         p
RTRT	RT
/#   \         dD   p\
        P                  RT4       T'       d   RRR. RRT 2/u Rp?# RRR. RRT 2/u Rp?# Rp?i\        P                   d8    \
        P                  RT4       T'       d   RRR. RRT R2/u # RRR. RR/u # i ; i  \        P                   \"        3 d-    \
        P%                  R 4       TR8X  d   R!p
 LTR8X  d   R"p
 Li ; i)#a(  Run tirith security scan on a command.

Exit code determines action (0=allow, 1=block, 2=warn). JSON enriches
findings/summary. Spawn failures and timeouts respect fail_open config.
Programming errors propagate.

Returns:
    {"action": "allow"|"warn"|"block", "findings": [...], "summary": str}
r$   actionallowfindingssummaryr5   r%   r'   r(   checkz--jsonz--non-interactivez--shellposixz--Tr   ztirith spawn failed: %sztirith unavailable: Nblockz#tirith spawn failed (fail-closed): ztirith timed out after %dsztirith timed out (zs)ztirith timed out (fail-closed)warnz'tirith returned unexpected exit code %dztirith exit code z (fail-open)z (fail-closed)z.tirith JSON parse failed, using exit code onlyz-security issue detected (details unavailable)z/security warning detected (details unavailable))r4   r   r   r   rJ   r   r   r   r   stdoutrI   jsonloadsr0   _MAX_FINDINGS_MAX_SUMMARY_LENJSONDecodeErrorAttributeErrorr   )r  r3   r%   r{   	fail_openr   r   	exit_coder  r  r	  dataraw_findingss   &            r   check_command_securityr  X  s     
!C  ':r9bAA&s='9:K"#G&'I`'8-@w0
( !!IA~	a	a 	@)Lgz2yDUV_U``lBmnn':r9@QR[Q\\j>kll HGH,2MM,?,?,A,Atzz&--(rxx
B//88Ir*00b2C3CD fj(IwGGW  k0#6gz2yDXY\X]B^__':r9@cdgch>ijj$$ `3W=gz2yDVW^V__aBbcc':r9>^__	`:   .1 HEFWEGvGGHsg   "E G1 .AG1 
G1 G.!(F	G.
FG.G.6G.G.#G.-G.19H8,	H87H8c                    V ^8  d   Qh/ ^ \         9   d   \        R,          \        ,          ;R&   ^\         9   d
   \        ;R&   ^\         9   d   \        P                  R,          ;R&   # )r   Nr   r   r   )__conditional_annotations__r
   r   r   r   )r   s   "r   r   r      s\      ~ ) (d
T! (B " ! !CJ 0 /!!D( /Kr   )r5   )
   )6r  __doc__r   r  loggingr   rr   rT   r   r   r   r   r   rE   urllib.requestr   hermes_constantsr   	getLogger__name__r   r   r   r   r   r   r4   r   r   r   Lockr   r   rF   r:   r?   rN   rX   ra   rV   rh   rw   r   r   r   r   r   r   r   r  r  r  r  r   )r  s   @r   <module>r$     s+  ,    	          ,			8	$ 17ef >/8 %) (!  !  +/ / "
F
""",$%P2Z2D Z2z'
`F) )@OT Ol  FHr   