
    )j|v                        d Z ddlZddlZddlZddlZddlZddl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  ej                    dk    Z ej        e          Zdedefd	Zdedefd
ZdZ edh          ZdefdZ e            ZdeddfdZd!dedz  dedz  defdZ defdZ!e!Z"dZ#dedefdZ$dededz  fdZ%dedefdZ&de'e(e         e)f         fdZ*de(e         fdZ+dede(e         defdZ, G d d e          Z-dS )"uE   Local execution environment — spawn-per-call with session snapshot.    N)Path)BaseEnvironment_pipe_stdin)windows_hide_flagsWindowscwdreturnc                    t           r| s| S t          j        d|           }|s| S |                    d                                          }|                    d          pd                    dd          }| d|pt          d           S )	u  Translate a Git Bash / MSYS-style POSIX path (``/c/Users/x``) to the
    native Windows form (``C:\Users\x``) so ``os.path.isdir`` and
    ``subprocess.Popen(..., cwd=...)`` can find it.

    No-ops on non-Windows hosts or for paths that aren't in MSYS form.
    Returns the input unchanged when no translation applies. This is
    idempotent — calling it on an already-Windows path returns it as-is.
    z^/([a-zA-Z])(/.*)?$       /\:\   )_IS_WINDOWSrematchgroupupperreplacechr)r   mdrivetails       =/home/ubuntu/.hermes/hermes-agent/tools/environments/local.py_msys_to_windows_pathr      s      c 

'--A 
GGAJJEGGAJJ"%%c400D''doc"gg'''    c                 ~   t           rt          |           n| } | r!t          j                            |           r| S | rt          j                            |           nd}|rKt          j                            |          r|S t          j                            |          }||k    rn|}|Kt          j                    S )ut  Return ``cwd`` if it exists as a directory, else the nearest existing
    ancestor.  Falls back to ``tempfile.gettempdir()`` only if walking up the
    path can't find any existing directory (effectively never on a healthy
    filesystem, but cheap belt-and-braces).

    On Windows, also normalizes Git Bash / MSYS-style POSIX paths
    (``/c/Users/x``) to native Windows form before the isdir check so a
    perfectly valid ``pwd -P`` result from bash doesn't get rejected as
    "missing" (see ``_msys_to_windows_path``).

    Used by ``_run_bash`` to recover when the configured cwd is gone — most
    commonly because a previous tool call deleted its own working directory
    (issue #17558).  Without this guard, ``subprocess.Popen(..., cwd=...)``
    raises ``FileNotFoundError`` before bash starts, wedging every subsequent
    terminal call until the gateway restarts.
    r   )r   r   ospathisdirdirnametempfile
gettempdir)r   parentnext_parents      r   _resolve_safe_cwdr(   *   s    " )4
<

$
$
$C
 rw}}S!! 
%(0RW__S!!!bF
 7==   	Mgoof--&         r   _HERMES_FORCE_AWS_BEARER_TOKEN_BEDROCKc                     t                      } 	 ddlm} |                                D ]b}|                     |j                   |j        dk    r|                     t                     |j        r| 	                    |j                   cn# t          $ r Y nw xY w	 ddlm} |                                D ]d\  }}|                    d          }|dv r| 	                    |           4|dk    r*|                    d          r| 	                    |           en# t          $ r Y nw xY w|                     h d	           t          |           S )
z=Derive the blocklist from provider, tool, and gateway config.r   )PROVIDER_REGISTRYaws_sdk)OPTIONAL_ENV_VARScategory>   tool	messagingsettingpassword><   GH_TOKENHASS_URL	LLM_MODEL
HASS_TOKENXAI_API_KEYGROQ_API_KEYEMAIL_ADDRESSGITHUB_APP_IDOPENAI_ORG_IDWHATSAPP_MODECOHERE_API_KEYEMAIL_PASSWORDGOOGLE_API_KEYMODAL_TOKEN_IDOPENAI_API_KEYSIGNAL_ACCOUNTANTHROPIC_TOKENDAYTONA_API_KEYEMAIL_IMAP_HOSTEMAIL_SMTP_HOSTMISTRAL_API_KEYOPENAI_API_BASEOPENAI_BASE_URLSIGNAL_HTTP_URLDEEPSEEK_API_KEYHELICONE_API_KEYPARALLEL_API_KEYTOGETHER_API_KEYWHATSAPP_ENABLEDFIRECRAWL_API_KEYFIRECRAWL_API_URLFIREWORKS_API_KEYANTHROPIC_BASE_URLEMAIL_HOME_ADDRESSMODAL_TOKEN_SECRETOPENROUTER_API_KEYPERPLEXITY_API_KEYSLACK_HOME_CHANNELDISCORD_AUTO_THREADOPENAI_ORGANIZATIONSIGNAL_HOME_CHANNELSLACK_ALLOWED_USERSDISCORD_HOME_CHANNELSIGNAL_ALLOWED_USERSGATEWAY_ALLOWED_USERSSIGNAL_IGNORE_STORIESTELEGRAM_HOME_CHANNELWHATSAPP_ALLOWED_USERSCLAUDE_CODE_OAUTH_TOKENDISCORD_REQUIRE_MENTIONEMAIL_HOME_ADDRESS_NAMESLACK_HOME_CHANNEL_NAMESIGNAL_HOME_CHANNEL_NAMEDISCORD_HOME_CHANNEL_NAMEGITHUB_APP_INSTALLATION_IDSIGNAL_GROUP_ALLOWED_USERSTELEGRAM_HOME_CHANNEL_NAMEGITHUB_APP_PRIVATE_KEY_PATHDISCORD_FREE_RESPONSE_CHANNELSHERMES_DASHBOARD_SESSION_TOKEN)sethermes_cli.authr,   valuesupdateapi_key_env_vars	auth_type_AWS_SDK_CREDENTIAL_ENV_VARSbase_url_env_varaddImportErrorhermes_cli.configr.   itemsget	frozenset)blockedr,   pconfigr.   namemetadatar/   s          r   _build_provider_env_blocklistr   d   s   G	555555(//11 	6 	6GNN73444 I--;<<<' 6G4555	6    	777777/5577 	" 	"ND(||J//H000D!!!!Y&&8<<
+C+C&D!!!	"     NN = = = = = =| Ws%   A=B 
BBA?D 
D,+D,envc                 \    	 ddl m}  |            }|r|| d<   dS dS # t          $ r Y dS w xY w)zBBridge the context-local Hermes home override into subprocess env.r   )get_hermes_home_overrideHERMES_HOMEN)hermes_constantsr   	Exception)r   r   values      r   _inject_context_hermes_homer      sk    ======((** 	'!&C	' 	'   s    
++base_env	extra_envc                    	 ddl m} n# t          $ r d }Y nw xY wi }| pi                                 D ]9\  }}|                    t
                    r |t          vs ||          r|||<   :|pi                                 D ]Z\  }}|                    t
                    r"|t          t
                    d         }|||<   A|t          vs ||          r|||<   [t          |           ddl	m
}  |            }|r||d<   |S )z<Filter Hermes-managed secrets from a subprocess environment.r   is_env_passthroughc                     dS NF _s    r   <lambda>z*_sanitize_subprocess_env.<locals>.<lambda>       E r   Nget_subprocess_homeHOME)tools.env_passthroughr   r   r{   
startswith!_HERMES_PROVIDER_ENV_FORCE_PREFIX_HERMES_PROVIDER_ENV_BLOCKLISTlenr   r   r   )	r   r   _is_passthrough	sanitizedkeyr   real_keyr   _profile_homes	            r   _sanitize_subprocess_envr      st   *OOOOOOO * * *)/* !#I~2,,.. # #
U>>;<< 	4448L8L4"IcN B--// # #
U>>;<< 	#3@AABBCH"'Ih666//#:N:N6"IcN	*** 544444''))M *)	&s   	 c            	         t           s{t          j        d          pft          j                            d          rdndpCt          j                            d          rdndp t          j                            d          pdS t          j                            d          } | r!t          j                            |           r| S t          j                            dd	          }|r!t          j                            |d
d          nd	}|rit          j                            |dd          t          j                            |ddd          fD ]%}t          j                            |          r|c S &t          j        d          }|r|S t          j                            t          j                            dd          ddd          t          j                            t          j                            dd          ddd          t          j                            |dddd          fD ]'}|r#t          j                            |          r|c S (t          d          )z Find bash for command execution.bashz/usr/bin/bashNz	/bin/bashSHELLz/bin/shHERMES_GIT_BASH_PATHLOCALAPPDATAr   hermesgitbinzbash.exeusrProgramFileszC:\Program FilesGitzProgramFiles(x86)zC:\Program Files (x86)ProgramszGit Bash not found. Hermes Agent requires Git for Windows on Windows.
Install it from: https://git-scm.com/download/win
Or set HERMES_GIT_BASH_PATH to your bash.exe location.)
r   shutilwhichr    r!   isfileenvironr|   joinRuntimeError)custom_local_appdata_hermes_portable_git	candidatefounds        r   
_find_bashr      sB    
L   #%7>>/#B#BL!w~~k::D z~~g&& 	
 Z^^233F "'..((  Z^^NB77NLZb27<<%HHH`b !GLL-ujAAGLL-ueZHH
 	! 	!I w~~i(( !    ! L  E  	RZ^^N4GHH%QVXbcc
RZ^^$79RSSUZ\acmnn
^ZzJJ  	
  		22 	
	A  r   za/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binexisting_pathc                    t           r| S d t                              d          D             }| sd                    |          S t	                      }g }|                     d          D ]3}|r||v r	|                    |           |                    |           4|D ]}||vr|                    |           d                    |          S )u  Return a normalised POSIX PATH with missing sane entries appended.

    On POSIX the caller-supplied PATH is rewritten (not merely appended to):
    empty entries and duplicate entries are dropped, preserving
    first-occurrence order, then each missing ``_SANE_PATH`` entry is appended
    once at the end so existing entries keep their precedence.

    Two intentional normalisations beyond the bare "add Homebrew dirs" fix:

    - **Empty entries are stripped.** A leading/trailing/double ``:`` encodes
      an empty PATH element, which POSIX shells interpret as the current
      working directory — a mild foot-gun in a default terminal environment.
      We drop these rather than carry them through.
    - **Duplicates are collapsed** (first occurrence wins), so a caller PATH
      that already contains repeats is not propagated verbatim.

    For a well-formed PATH (no empties, no duplicates) the leading segment is
    byte-identical to the input and ordering is preserved; only the missing
    sane entries are appended. On Windows this is a no-op passthrough (the
    separator is ``;`` and the native PATH must not be touched).
    c                     g | ]}||S r   r   ).0entrys     r   
<listcomp>z5_append_missing_sane_path_entries.<locals>.<listcomp>H  s    FFFeFEFFFr   r   )r   
_SANE_PATHsplitr   rp   rx   append)r   sane_entriesseenordered_entriesr   s        r   !_append_missing_sane_path_entriesr   /  s    ,  FFz'7'7'<'<FFFL &xx%%% UUD!#O$$S)) & & 	u%%%%  * *""5)))88O$$$r   run_envc                 Z    t           sdS | D ]}|                                dk    r|c S dS )a  Return the PATH env key to update without altering Windows casing.

    Note: this is deliberately a *second* Windows guard, distinct from the
    early-return in ``_append_missing_sane_path_entries``. Its job is to pick
    the correctly-cased key (``Path`` vs ``PATH``) so completion writes back to
    the key the caller already used; the helper's guard makes that helper safe
    to call standalone (it is, e.g. in the Windows unit tests). Both are
    intentional.
    PATHN)r   r   )r   r   s     r   _path_env_keyr   _  sF      v  99;;&  JJJ !4r   c                    	 ddl m} n# t          $ r d }Y nw xY wt          t          j        | z            }i }|                                D ]Z\  }}|                    t                    r"|t          t                    d         }|||<   A|t          vs ||          r|||<   [t          |          }|&t          |                    |d                    ||<   t          |           ddlm}  |            }	|	r|	|d<   	 ddlm}
m} |                                D ]$\  }}|                                }||
ur|r|||<   %n# t          $ r Y nw xY w|S )	zDBuild a run environment with a sane PATH and provider-var stripping.r   r   c                     dS r   r   r   s    r   r   z_make_run_env.<locals>.<lambda>v  r   r   Nr   r   r   )_UNSET_VAR_MAP)r   r   r   dictr    r   r{   r   r   r   r   r   r   r|   r   r   r   gateway.session_contextr   r   )r   r   mergedr   kvr   path_keyr   r   r   r   var_namevarr   s                  r   _make_run_envr   q  s   *OOOOOOO * * *)/* "*s"##FG  1<<9:: 	>??@@AH !GH4448J8J4GAJW%%H=gkk(TV>W>WXX(((
 544444''))M ('<<<<<<<<%^^-- 	* 	*MHcGGIIEF""u"$)!	*     Ns   	 AE	 	
EEc                  <   	 ddl m}   |             pi }|                    d          pi }|                    d          pg }t          |t                    sg }t          |                    dd                    }d |D             |fS # t          $ r g dfcY S w xY w)u   Return (shell_init_files, auto_source_bashrc) from config.yaml.

    Best-effort — returns sensible defaults on any failure so terminal
    execution never breaks because the config file is unreadable.
    r   )load_configterminalshell_init_filesauto_source_bashrcTc                 0    g | ]}|t          |          S r   )str)r   fs     r   r   z4_read_terminal_shell_init_config.<locals>.<listcomp>  s#    +++1+A+++r   )rz   r   r|   
isinstancelistboolr   )r   cfgterminal_cfgfilesauto_bashrcs        r    _read_terminal_shell_init_configr     s    111111kmm!rwwz**0b  !344:%&& 	E<++,@$GGHH+++++[88   4xs   BB
 
BBc                     t                      \  } }g }| r|                    |            n |rt          s|                    g d           g }|D ]}	 t          j                            t          j                            |                    }n# t          $ r Y Lw xY w|r4t          j                            |          r|	                    |           |S )uh  Resolve the list of files to source before the login-shell snapshot.

    Expands ``~`` and ``${VAR}`` references and drops anything that doesn't
    exist on disk, so a missing ``~/.bashrc`` never breaks the snapshot.
    The ``auto_source_bashrc`` path runs only when the user hasn't supplied
    an explicit list — once they have, Hermes trusts them.
    )z
~/.profilez~/.bash_profilez	~/.bashrc)
r   extendr   r    r!   
expandvars
expanduserr   r   r   )explicitr   
candidatesresolvedrawr!   s         r   _resolve_shell_init_filesr     s     =>>HkJ J(####	 J[ J  	HHHIIIH " "	7%%bg&8&8&=&=>>DD 	 	 	H	 	"BGNN4(( 	"OOD!!!Os   <B
BB
cmd_stringr   c                     |s| S dg}|D ]4}|                     dd          }|                    d| d| d           5d                    |          dz   }|| z   S )a  Prepend ``source <file>`` lines (guarded + silent) to a bash script.

    Each file is wrapped so a failing rc file doesn't abort the whole
    bootstrap: ``set +e`` keeps going on errors, ``2>/dev/null`` hides
    noisy prompts, and ``|| true`` neutralises the exit status.
    zset +e'z'\''z[ -r 'z
' ] && . 'z' 2>/dev/null || true
)r   r   r   )r   r   prelude_partsr!   safepreludes         r   _prepend_shell_initr     s      JM S S ||C))QdQQdQQQRRRRii&&-GZr   c                        e Zd ZdZddededef fdZd	efd
Zdddddede	dededz  d	e
j        f
dZd ZdefdZdef fdZd Z xZS )LocalEnvironmentzRun commands directly on the host machine.

    Spawn-per-call: every execute() spawns a fresh bash process.
    Session snapshot preserves env vars across calls.
    CWD persists via file-based read after each command.
    r   <   Nr   timeoutr   c                     |rt           j                            |          }t                                          |pt          j                    ||           |                                  d S )N)r   r   r   )r    r!   r   super__init__getcwdinit_session)selfr   r   r   	__class__s       r   r  zLocalEnvironment.__init__  sb     	*'$$S))CS/BIKKcJJJr   r	   c                    t           r	 ddlm}  |            dz  dz  }n3# t          $ r& t	          t          j                              dz  }Y nw xY w|                    dd           t          |          	                    dd	          S d
D ]k}| j
                            |          pt          j                            |          }|r.|                    d	          r|                    d	          pd	c S lt          j                            d          r.t          j        dt          j        t          j        z            rdS t          j                    }|                    d	          r|                    d	          pd	S dS )u  Return a shell-safe writable temp dir for local execution.

        Termux does not provide /tmp by default, but exposes a POSIX TMPDIR.
        Prefer POSIX-style env vars when available, keep using /tmp on regular
        Unix systems, and only fall back to tempfile.gettempdir() when it also
        resolves to a POSIX path.

        Check the environment configured for this backend first so callers can
        override the temp root explicitly (for example via terminal.env or a
        custom TMPDIR), then fall back to the host process environment.

        **Windows:** hardcoded ``/tmp`` is wrong in two ways — native Python
        can't open the path, and the Windows default temp (``%TEMP%``) often
        contains spaces (``C:\Users\Some Name\AppData\Local\Temp``) that
        break unquoted bash interpolations.  Use a dedicated cache dir under
        ``HERMES_HOME`` instead — single-word path, guaranteed to exist, same
        string resolves in both Git Bash and native Python.
        r   )get_hermes_homecacher   hermes_terminalT)parentsexist_okr   r   )TMPDIRTMPTEMPz/tmp)r   r   r  r   r   r$   r%   mkdirr   r   r   r|   r    r   r   rstripr!   r"   accessW_OKX_OK)r  r  	cache_direnv_varr   s        r   get_temp_dirzLocalEnvironment.get_temp_dir  s   &  	5L<<<<<<+O--7*D		 L L L !4!6!677:KK			LOOD4O888y>>))$4440 	4 	4GW--H1H1HI 4Y11#66 4 '',,33337==   	RYvrw7H%I%I 	6'))	$$ 	0##C((/C/vs     -AAFx   )loginr   
stdin_datar   r  r  c                   t                      }|r t                      }|rt          ||          }|r|dd|gn|d|g}t          | j                  }t          | j                  }	|	| j        k    rPt          rt          | j                  n| j        }
|	|
k    r!t          
                    d| j        |	           |	| _        | j        }t          rdt                      ini }t          j        |fd|ddt          j        t          j        |t          j        nt          j        t          rd nt"          j        |d	|}t          s0	 t#          j        |j                  |_        n# t,          $ r Y nw xY w|t/          ||           |S )	Nz-lz-czaLocalEnvironment cwd %r is missing on disk; falling back to %r so terminal commands keep working.creationflagsTutf-8r   )	textr   encodingerrorsstdoutstderrstdin
preexec_fnr   )r   r   r   r   r   r(   r   r   r   loggerwarningr   
subprocessPopenPIPESTDOUTDEVNULLr    setsidgetpgidpid_hermes_pgidProcessLookupErrorr   )r  r   r  r   r  r   
init_filesargsr   safe_cwd
normalized
_popen_cwd_popen_kwargsprocs                 r   	_run_bashzLocalEnvironment._run_bash-  s    ||  	I244J I0ZHH
16TdD*--T4<T)) %TX..tx =HU.tx888TXJ:%%LH	    DHX
CNV*<*>*>??TV
?$%/%;*//AS*9tt	
 
 
 
  	$&Jtx$8$8!!%    !j)))s   E# #
E0/E0c                    dt           dt          fddt           dt          dt          ffd}	 t          r                                 dS 	 t          j        j                  }n$# t          $ r t          dd          }| Y nw xY w	 t          j
        |t          j                   n# t          $ r Y dS w xY w ||d          rdS 	 t          j
        |t          j                   n# t          $ r Y dS w xY w ||d	           	                     d
           dS # t          j        t"          f$ r Y dS w xY w# t          t$          t"          f$ r+ 	                                  Y dS # t(          $ r Y Y dS w xY ww xY w)z-Kill the entire process group (all children).pgidr	   c                 l    	 t          j        | d           dS # t          $ r Y dS t          $ r Y dS w xY w)Nr   TF)r    killpgr0  PermissionError)r:  s    r   _group_alivez4LocalEnvironment._kill_process.<locals>._group_alivev  sY    	$"""t%   uu"   tts    
3	33r   c                 ~   t          j                    |z   }t          j                    |k     r^	                                  n# t          $ r Y nw xY w |           sdS t          j        d           t          j                    |k     ^	                                  n# t          $ r Y nw xY w |            S )NTg?)time	monotonicpollr   sleep)r:  r   deadliner>  r7  s      r   _wait_for_group_exitz<LocalEnvironment._kill_process.<locals>._wait_for_group_exit  s    ~'''1H.""X--IIKKKK    D#|D))  4
4    .""X--		   #|D))))s#   A 
AAB# #
B0/B0r/  Ng      ?g       @g?)r   )intr   floatr   	terminater    r-  r.  r0  getattrr<  signalSIGTERMSIGKILLwaitr'  TimeoutExpiredOSErrorr=  killr   )r  r7  rE  r:  r>  s    `  @r   _kill_processzLocalEnvironment._kill_processs  s&   		s 		t 		 		 		 			*s 	*U 	*t 	* 	* 	* 	* 	* 	* 	*$$	      :dh//DD)   "4>>D| $|
IdFN3333)   FF ('c22 FIdFN3333)   FF$$T3///IIcI*****"17;   DD"OW= 	 	 			   	s   E A* )E *BE 
BE B/ .E /
B=9E <B==E C/ .E /
C=9E <C==E D% %D?;E >D??E FE11
F ;F?F  Fresultc                    	 t          | j        d          5 }|                                                                }ddd           n# 1 swxY w Y   t          rt          |          }|r&t          j                            |          r|| _	        n# t          t          f$ r Y nw xY w|                     |           dS )u  Read CWD from temp file (local-only, no round-trip needed).

        Skip the assignment when the path no longer exists as a directory —
        ``pwd -P`` on a deleted cwd can leave a stale value in the marker
        file, and propagating it would re-wedge the next ``Popen``.  The
        ``_run_bash`` recovery path will resolve a safe fallback if needed.

        On Windows, the value written by Git Bash's ``pwd -P`` is in
        MSYS form (``/c/Users/x``). Translate it to native Windows form
        before validating with ``os.path.isdir`` and before storing on
        ``self.cwd``; otherwise the isdir check rejects every valid
        result and ``_run_bash`` later prints a misleading "cwd is
        missing" warning on every command.
        r  )r  N)open	_cwd_filereadstripr   r   r    r!   r"   r   rO  FileNotFoundError_extract_cwd_from_output)r  rR  r   cwd_paths       r   _update_cwdzLocalEnvironment._update_cwd  s   	dnw777 ,16688>>++, , , , , , , , , , , , , , , ;0:: $BGMM(33 $#*+ 	 	 	D	 	%%f-----s4   B 'AB AB AAB B)(B)c                    | j         }t                                          |           | j         |k    rUt          rt	          | j                   n| j         }|r(t
          j                            |          r	|| _         dS || _         dS dS )u  Same semantics as the base class, but on Windows the value
        emitted by ``pwd -P`` inside Git Bash is in MSYS form
        (``/c/Users/x``). Normalize to native Windows form and validate
        the directory exists before assigning to ``self.cwd`` — otherwise
        ``_run_bash``'s safe-cwd recovery would warn on every subsequent
        command.

        Always defers to the base class for stripping the marker text from
        ``result["output"]`` so output formatting is identical.
        N)r   r  rY  r   r   r    r!   r"   )r  rR  prev_cwdr4  r  s       r   rY  z)LocalEnvironment._extract_cwd_from_output  s     8((0008x<GU.tx888TXJ $bgmmJ77 $% $  r   c                 r    | j         | j        fD ]'}	 t          j        |           # t          $ r Y $w xY wdS )zClean up temp files.N)_snapshot_pathrU  r    unlinkrO  )r  r   s     r   cleanupzLocalEnvironment.cleanup  sY    %t~6 	 	A	!   	 	s   '
44)r   r   N)__name__
__module____qualname____doc__r   rF  r   r  r  r   r'  r(  r8  rQ  r[  rY  ra  __classcell__)r  s   @r   r   r     sB         C s d      .c . . . .` ;@!$+/D D DC D4 DD!DjD4>4DD D D DLD D DL.$ . . . .8$t $ $ $ $ $ $0      r   r   )N).re  loggingr    platformr   r   rJ  r'  r$   r@  pathlibr   tools.environments.baser   r   hermes_cli._subprocess_compatr   systemr   	getLoggerrb  r%  r   r   r(   r   r}   rv   r   r   r   r   r   r   _find_shellr   r   r   r   tupler   r   r   r   r   r   r   r   r   <module>rp     s   K K  				  				               @ @ @ @ @ @ @ @ < < < < < <ho9,		8	$	$(s (s ( ( ( ((!3 !3 ! ! ! !D %5 !&  )y*     
Xy X X X Xv "?!>!@!@ 	T 	d 	 	 	 	 td{ td{ VZ    B2C 2 2 2 2l 
C -%S -%S -% -% -% -%`4 C$J    $(t ( ( ( ( (V%S	4*@    ('49 ' ' ' 'T C  S	  c        *D D D D D D D D D Dr   