
    ^iT              K       &   S SK r S SKrS SKrS SKrS SKrS SKrS SKrS SKrS SKr	S SK
r
S SKrS SKJr  SSKJrJrJrJr  S\S\	R&                  \	R(                  \S4      4S jr " S	 S
\R,                  5      r " S S\R0                  \R2                     5      r " S S\5      rS\S\	R&                  \   4S jrS\S\S\	R&                  \   S\4S jrS\4S jr  " S S\RB                  5      r" " S S\RF                  5      r$\ RJ                  " 5       S\	RL                  \\	RN                  4   4S j5       r(                                  SGS\S\	RR                  \\4   S\S\	RT                  \   S\S \S!\	RT                  \   S"\	RT                  \   S#\	RT                  \   S$\	RT                  \   S%\	RT                  \   S&\	RT                  \   S'\	RT                  \   S(\	RT                  \	R&                  \      S)\	RT                  \	R&                  \      S*\	RT                  \   S+\	RT                  \   S,\	RT                  \   S-\S.\	RT                  \   S/\	RT                  \   S0\	RT                  \   S1\	RT                  \   S2\	RT                  \   S3\	RT                  \   S4\	RT                  \   S5\	RT                  \   S6\	RT                  \   S7\	RT                  \	RR                  \+\4      S8\S9\S:\+S;\	RT                  \   S<\	RT                  \	RL                  \\	RN                  4      S=\	RT                  \	RX                  \      S>\+S\4JS? jjr-S@\.S\4SA jr/SB\SC\	RN                  S\4SD jr0SE\	R&                  \   S\4SF jr1g)H    N)Path   )corejob_environmentloggerutilsjob_idreturn.c           	      t   Sn[         R                  " X5      nUb`  UR                  S5      nUR                  S5      R                  S5      nU Vs/ s H!  n[	        U/UR                  S5      -   5      PM#     sn$ U R                  SS5      tpgU(       d  U4/$ [        [        US   5      5      nXh4/$ s  snf )	zdReads formated job id and returns a tuple with format:
(main_id, [array_index, [final_array_index])
z:(?P<main_id>\d+)_\[(?P<arrays>(\d+(-\d+)?(,)?)+)(\%\d+)?\]main_idarrays,-_   r   )researchgroupsplittuplestrint)	r	   patternmatchmainarray_rangesarray_ranger   array_id	array_nums	            Q/mnt/rpi/tmp/demucs-venv-sys/lib/python3.13/site-packages/submitit/slurm/slurm.pyread_job_idr!      s     LGIIg&E{{9%{{8,2237JVW,;tf{00556,WW#\\#q1J<HQK()	$%% Xs   (B5c                       \ rS rSrS\R
                  \R                  \      4S jrSS\S\S\4S jjr	S\R                  \\4   S\R                  \\R                  \\4   4   4S jrS	rg
)SlurmInfoWatcher*   r
   c                     U R                   U R                  -
   Vs1 s H  oR                  S5      S   iM     nnU(       d  g / SQnU H  nUR                  S[	        U5      /5        M!     U$ s  snf )Nr   r   )sacctz-ozJobID,State,NodeListz--parsable2z-j)_registered	_finishedr   extendr   )selfxto_checkcommandjids        r    _make_commandSlurmInfoWatcher._make_command+   sh     .2-=-=-NO-NGGCLO-NOHCNND#c(+,  Ps   A.r	   modec                 T    U R                  XS9nUR                  S5      =(       d    S$ )a  Returns the state of the job
State of finished jobs are cached (use watcher.clear() to remove all cache)

Parameters
----------
job_id: int
    id of the job on the cluster
mode: str
    one of "force" (forces a call), "standard" (calls regularly) or "cache" (does not call)
)r1   StateUNKNOWN)get_infoget)r*   r	   r1   infos       r    	get_stateSlurmInfoWatcher.get_state6   s(     }}V}/xx -I-    stringc           	         [        U[        5      (       d  UR                  5       nUR                  5       n[	        U5      S:  a  0 $ US   R                  S5      n0 nUSS  H  n[        X5R                  S5      5       VVs0 s H  u  pgXgR                  5       _M     nnnUS   n	U	(       a  SU	;   a  MS   [        U	5      n
U
 He  nUUS
R                  USS 5      '   [	        U5      S:  d  M+  [        [        US   5      [        US   5      S-   5       H  nXUS    S
U 3'   M     Mg     M     U$ s  snnf ! [         a-  n[        R                  " SU	 S	U 3[        5         SnAGM  SnAff = f)zNReads the output of sacct and returns a dictionary containing main informationr   r   |r   NJobID.zCould not interpret z# correctly (please open an issue):
r      )
isinstancer   decode
splitlineslenr   zipstripr!   	ExceptionwarningswarnDeprecationWarningjoinranger   )r*   r;   linesnames	all_statsliner+   ystatsr	   multi_split_job_idesplit_job_idindexs                 r    	read_infoSlurmInfoWatcher.read_infoD   sr   &#&&]]_F!!#u:>Ias#57	!"ID.1%C.IJ.IdaQ	\.IEJ7^FSF]%0%8" !3 #((<#345 |$)!&s<?';Sa=QTU=U!VBG\!_$5Qug">? "W !3 * ) K  *6(2VWXVYZ\n s   D26D88
E/!E**E/ N)standard)__name__
__module____qualname____firstlineno__tpOptionalListr   r/   r8   UnionbytesDictrW   __static_attributes__rY   r:   r    r#   r#   *   su    	r{{2773<8 	. .3 . . 4 bggcSVhFWAW9X r:   r#   c                   :    \ rS rSrSr\" SS9rS
S\SS4S jjrS	r	g)SlurmJobf   scanceliX  )delay_stimeoutr
   Nc                     SU R                   S/nU(       d  [        R                  " US/-   5        [        R                  " U[        R                  /-   5        g)zSends preemption or timeout signal to the job (for testing purpose)

Parameter
---------
timeout: bool
    Whether to trigger a job time-out (if False, it triggers preemption)
ri   z--signalSIGTERMN)r	   
subprocess
check_callSlurmJobEnvironmentUSR_SIG)r*   rk   cmds      r    
_interruptSlurmJob._interruptj   sI     $++z2!!#"34c%8%@%@$AABr:   rY   )F)
r[   r\   r]   r^   _cancel_commandr#   watcherboolrs   re   rY   r:   r    rg   rg   f   s-    Os+GC$ C4 C Cr:   rg   c                       \ rS rSrSrg)SlurmParseExceptiony   rY   N)r[   r\   r]   r^   re   rY   r:   r    ry   ry   y   s    r:   ry   suffix_partsc                 $   / nU R                  S5       Hx  nSU;   a^  UR                  S5      u  p4[        U5      n[        [        U5      [        U5      S-   5       H  nUR	                  USU 3 5        M     Mg  UR	                  U5        Mz     U$ )zWParse the a suffix formatted like "1-3,5,8" into
the list of numeric values 1,2,3,5,8.
r   r   r   0)r   rD   rL   r   append)r{   suffixessuffix_partlowhigh
int_lengthnums          r    _expand_id_suffixr   }   s     H#))#.+#))#.ICSJSXs4y1}53qn"57 6 OOK( / Or:   	node_listposparsedc                    S/nU[        U 5      :  a  X   nUS:X  a  UR                  U5        US-   $ US:X  aG  U R                  SU5      n[        XS-   U 5      nU VVs/ s H  ov  H  oU-   PM	     M     nnnUS-   nO[	        U5       H  u  pXt-   X9'   M     US-  nU[        U 5      :  a  M  UR                  U5        U$ s  snnf )zrParse a node group of the form PREFIX[1-3,5,8] and return
the position in the string at which the parsing stopped
 r   r   [])rD   r)   rV   r   	enumerate)
r   r   r   prefixesclast_posr   prefixsuffixis
             r    _parse_node_groupr      s     tH
I
N8MM(#7N8 sC0H(7X)FGH6>VhFX6XhHVQ,C&x0	$j 11HC I
 MM(J Ws    Cc                      Sn/ nU[        U 5      :  a  [        XU5      nU[        U 5      :  a  M  U$ ! [         a  n[        SU  S3U5      UeS nAff = f)Nr   z-Unrecognized format for SLURM_JOB_NODELIST: '')rD   r   
ValueErrorry   )r   r   r   rT   s       r    _parse_node_listr      sm    j!C	N"#IF;C C	N" j!$QR[Q\\]"^`abhiijs   .4 4 
AAAc            
       p    \ rS rSrSSSSSSSS	S
S.	rS\SS4S jr\S\R                  \
   4S j5       rSrg)rp      SLURM_JOB_IDSLURM_NTASKSSLURM_JOB_NUM_NODESSLURM_NODEIDSLURM_JOB_NODELISTSLURM_PROCIDSLURM_LOCALIDSLURM_ARRAY_JOB_IDSLURM_ARRAY_TASK_ID)	r	   	num_tasks	num_nodesnodenodesglobal_rank
local_rankarray_job_idarray_task_id	countdownr
   Nc                     U R                   n[        R                  " SSU/SS9  [        R                  " 5       R                  SU SU S35        g )Nscontrolrequeue<   )rk   zRequeued job z (z remaining timeouts))r	   rn   ro   r   
get_loggerr7   )r*   r   r.   s      r    _requeueSlurmJobEnvironment._requeue   sI    kkz9c:BG  =R	{BV!WXr:   c                     [         R                  R                  U R                  S   S5      nU(       d  U R                  /$ [        U5      $ )a  Parse the content of the "SLURM_JOB_NODELIST" environment variable,
which gives access to the list of hostnames that are part of the current job.

In SLURM, the node list is formatted NODE_GROUP_1,NODE_GROUP_2,...,NODE_GROUP_N
where each node group is formatted as: PREFIX[1-3,5,8] to define the hosts:
[PREFIX1, PREFIX2, PREFIX3, PREFIX5, PREFIX8].

Link: https://hpcc.umd.edu/hpcc/help/slurmenv.html
r   r   )osenvironr6   _envhostnamer   )r*   r   s     r    	hostnamesSlurmJobEnvironment.hostnames   s;     JJNN499W#5r:	MM?"	**r:   rY   )r[   r\   r]   r^   r   r   r   propertyr_   ra   r   r   re   rY   r:   r    rp   rp      s]     #*%%%,.
DY# Y$ Y
 +2773< + +r:   rp   c                     ^  \ rS rSrSr\r   SS\R                  \	\
4   S\S\S\R                  \	   SS4
U 4S	 jjjr\S\R"                  4S
 j5       r\S\R&                  \	   4S j5       rS\R*                  \	\R,                  4   S\R*                  \	\R,                  4   4U 4S jjrS\R,                  SS4U 4S jjrS\R2                  \R6                     S\R2                  \R8                  \R,                        4U 4S jjr\S\	4S j5       rS\	S\	S\	4S jr S\4S jr!S\
S\R2                  \	   4S jr"\#S\R                  \$\	4   S\	4S j5       r%\S\4S j5       r&Sr'U =r($ )SlurmExecutor   a  Slurm job executor
This class is used to hold the parameters to run a job on slurm.
In practice, it will create a batch file in the specified directory for each job,
and pickle the task function and parameters. At completion, the job will also pickle
the output. Logs are also dumped in the same directory.

Parameters
----------
folder: Path/str
    folder for storing job submission/output and logs.
max_num_timeout: int
    Maximum number of time the job can be requeued after timeout (if
    the instance is derived from helpers.Checkpointable)
python: Optional[str]
    Command to launch python. This allow to use singularity for example.
    Caller is responsible to provide a valid shell command here.
    By default reuse the current python executable

Note
----
- be aware that the log/output folder will be full of logs and pickled objects very fast,
  it may need cleaning.
- the folder needs to point to a directory shared through the cluster. This is typically
  not the case for your tmp! If you try to use it, slurm will fail silently (since it
  will not even be able to log stderr.
- use update_parameters to specify custom parameters (n_gpus etc...). If you
  input erroneous parameters, an error will print all parameters available for you.
Nfoldermax_num_timeoutmax_pickle_size_gbpythonr
   c                    > [         TU ]  UUUS9  Uc$  [        R                  " [        R
                  5      OUU l        U R                  5       S:  d  [        S5      eg )N)r   r   r   z;Could not detect "srun", are you indeed on a slurm cluster?)	super__init__shlexquotesys
executabler   affinityRuntimeError)r*   r   r   r   r   	__class__s        r    r   SlurmExecutor.__init__   s[     	+1 	 	

 6<^ekk#..1}}"\]] #r:   c                     SSSSSSSS.$ )	Njob_nametimememr   cpus_per_taskgpus_per_nodentasks_per_node)nametimeout_minmem_gbr   r   r   tasks_per_noderY   clss    r    _equivalence_dictSlurmExecutor._equivalence_dict  s#     !,,/
 	
r:   c                 (    [        [        5       5      $ )4Parameters that can be set through update_parameters)set_get_default_parametersr   s    r    _valid_parametersSlurmExecutor._valid_parameters  s     *,--r:   paramsc                 T   > [         TU ]  U5      nSU;   a  [        US   5      US'   U$ )Nr   )r   _convert_parameters_convert_mem)r*   r   r   s     r    r   !SlurmExecutor._convert_parameters  s0    ,V4F?(7F5Mr:   kwargsc                 8  > [        5       n[        [        U5      [        U5      -
  5      nU(       a@  SR                  S [        UR	                  5       5       5       5      n[        SU SU 35      e[        SSU R                  S.UD6  [        TU ]$  " S0 UD6  g)	aM  Updates sbatch submission file parameters

Parameters
----------
See slurm documentation for most parameters.
Most useful parameters are: time, mem, gpus_per_node, cpus_per_task, partition
Below are the parameters that differ from slurm documentation:

signal_delay_s: int
    delay between the kill signal and the actual kill of the slurm job.
setup: list
    a list of command to run in sbatch befure running srun
array_parallelism: int
    number of map tasks that will be executed in parallel

Raises
------
ValueError
    In case an erroneous keyword argument is added, a list of all eligible parameters
    is printed, with their default values

Note
----
Best practice (as far as Quip is concerned): cpus_per_task=2x (number of data workers + gpus_per_task)
You can use cpus_per_gpu=2 (requires using gpus_per_task and not gpus_per_node)
z
  - c              3   H   #    U  H  u  pU S [        U5       S3v   M     g7f)z (default: )N)repr).0r+   rQ   s      r    	<genexpr><SlurmExecutor._internal_update_parameters.<locals>.<genexpr>9  s%     "dKc41aSDG9A#>Kcs    "zUnavailable parameter(s): z
Valid parameters are:
  - znothing to dor-   r   NrY   )
r   sortedr   rK   itemsr   _make_sbatch_stringr   r   _internal_update_parameters)r*   r   defaultsin_valid_parametersr;   r   s        r    r   )SlurmExecutor._internal_update_parameters  s    6 +,$S[3x=%@A]]"d6RZR`R`RbKc"ddF,-@,AA^_e^fg  	RODKKR6R+5f5r:   delayed_submissionsc           	        > [        U5      S:X  a  [        TU ]	  U5      $ [        R                  R                  U R                  5      nUR                  SSS9  U R                  R                  SS5      n/ nU He  nU[        R                  " 5       R                   S3-  nUR                  X0R                  5        UR                  U5        UR!                  U5        Mg     [        U5      n[#        U R                  U R                  5      nUR$                  " S0 U R                  D6  XxR                  S'   U R'                  5         UR)                  U R*                  5      n	[-        [/        U	R0                  5      5      n
[/        U5       Vs/ s H'  n[3        U R                  U	R4                   SU 3U
S	9PM)     nn[7        X5       H!  u  pUR8                  R;                  US
5        M#     U$ s  snf )Nr   T)parentsexist_okr      z.pkl	map_countr   )r   r	   taskssubmitted_picklerY   )rD   r   _internal_process_submissionsr   JobPathsget_first_id_independent_folderr   mkdir
parametersr6   uuiduuid4hexset_timeoutr   dumpr~   r   update_parameters	_throttle_submit_command_submitit_command_strlistrL   r   rg   r	   rE   pathsmove_temporary_file)r*   r   r   r   pickle_pathsdpickle_pathnarray_ex	first_job	tasks_idsajobsjobr   s                 r    r   +SlurmExecutor._internal_process_submissionsA  s    "#q(789LMM??LTD1oo))&!4$A djjl&6&6%7t#<<KMM+';';<FF;,	 %
 #$ !d.B.BC""5T__5+,K(&.&>&>t?Y?Y&Z	y2234	ejklem+
em`aHDKK93C3C2DAaS0IQZ[em 	 +
 !$D 7CII))+7IJ !8+
s   .G/c           	          SR                  U R                  S[        R                  " [	        U R
                  5      5      /5      $ )N z-u -m submitit.core._submit)rK   r   r   r   r   r   )r*   s    r    r  #SlurmExecutor._submitit_command_stra  s3    xx&CU[[QTUYU`U`QaEbcddr:   r-   uidc                 D    [        SXR                  S.U R                  D6$ )Nr   rY   )r   r   r  )r*   r-   r  s      r    _make_submission_file_text(SlurmExecutor._make_submission_file_texte  s    "Z7;;Z$//ZZr:   c                     U R                   R                  SS5      n[        SU R                   R                  SS5      5      nX-  $ )Nr   r   r   )r  r6   max)r*   r   r   s      r    
_num_tasksSlurmExecutor._num_tasksh  s?    __((!4!!T__%8%89JA%NO%%r:   submission_file_pathc                     S[        U5      /$ )Nsbatch)r   )r*   r'  s     r    _make_submission_command&SlurmExecutor._make_submission_commandm  s    #2344r:   r;   c                     [        U [        5      (       d  U R                  5       n [        R                  " SU 5      nUc  [
        R                  " SU  S35      eUR                  S5      $ )z3Returns the job ID from the output of sbatch stringzjob (?P<id>[0-9]+)z'Could not make sense of sbatch output "zg"
Job instance will not be able to fetch status
(you may however set the job job_id manually if needed)id)rA   r   rB   r   r   r   FailedSubmissionErrorr   )r;   outputs     r    #_get_job_id_from_submission_command1SlurmExecutor._get_job_id_from_submission_commandp  sj     &#&&]]_F0&9>--9& BJ J 
 ||D!!r:   c                 8    [         R                  " S5      c  S$ S$ )Nsrunr   )shutilwhichr   s    r    r   SlurmExecutor.affinity~  s    \\&)1r8q8r:   )r   )r@   g      ?N))r[   r\   r]   r^   __doc__rg   	job_classr_   rb   r   r   r   floatr`   r   classmethodr   EquivalenceDictr   Setr   rd   Anyr   r   ra   r   DelayedSubmissionJobr   r   r  r!  r%  r*  staticmethodrc   r0  r   re   __classcell__)r   s   @r    r   r      s   : I
  !$'#'^d#^ ^ "	^
 C ^ 
^ ^  	
$"6"6 	
 	
 ."&&+ . ."''#rvv+*> 2773PRPVPV;CW $6BFF $6t $6L#%775+B+B#C	"&&!	"@ es e e[# [C [C [&C &
5T 5bggcl 5 "BHHUCZ4H "S " " 9 9 9r:   r   c                      [         R                  " [        5      n [        U R                  [        U R                  5      * S U R                  5      nU VVs0 s H  u  p#US;  d  M  X#_M     snn$ s  snnf )r   N>   r   r-   r   )inspectgetfullargspecr   rE   argsrD   r   )specszippedkeyvals       r    r   r     sc     ""#67ES0023U^^DF%+]Vs:\/\HCHV]]]s   A1'A1r-   r   r   	partitionr   r   r   r   cpus_per_gpunum_gpusr   gpus_per_taskqossetupteardownr   mem_per_gpumem_per_cpusignal_delay_scomment
constraintexcludeaccountgres	mail_type	mail_usernodelist
dependency	exclusivearray_parallelismwckeystderr_to_stdoutr   additional_parameters	srun_argsuse_srunc$                 v   / SQn$[        5       R                  5        V%V&s0 s H  u  n%n&U&c  M  U%U$;  d  M  U%U&_M     n'n%n&[        R                   SU 3U'S'   U	b+  [        R
                  " S5        U'R                  SS5      U'S'   SU';   a  S	U';  a  [        R
                  " S
5        [        R                  " US9n([        U(R                  5      n)[        U(R                  5      n*U bZ  [        U [        5      (       a  U (       d   eSU S-
   S[        U U5       3U'S'   U)R                  SS5      n)U*R                  SS5      n*U)R                  SS5      U'S'   U(       d  U*R                  SS5      U'S'   SU'S'   U!b  U'R!                  U!5        / SQn+[#        U'5       H!  n%U+R%                  ['        U%U'U%   5      5        M#     Ub
  U+SS/U-   -  n+U#(       a8  U(       a  / OSU*/n,U"c  / n"[)        SSSU)/U,QU"Q5      n-SR+                  U-U 45      n U+SS S!U S/-  n+Ub
  U+SS"/U-   -  n+S#R+                  U+5      $ s  sn&n%f )$a1  Creates the content of an sbatch file with provided parameters

Parameters
----------
See slurm sbatch documentation for most parameters:
https://slurm.schedmd.com/sbatch.html

Below are the parameters that differ from slurm documentation:

folder: str/Path
    folder where print logs and error logs will be written
signal_delay_s: int
    delay between the kill signal and the actual kill of the slurm job.
setup: list
    a list of command to run in sbatch before running srun
teardown: list
    a list of command to run in sbatch after running srun
map_size: int
    number of simultaneous map/array jobs allowed
additional_parameters: dict
    Forces any parameter to a given value in sbatch. This can be useful
    to add parameters which are not currently available in submitit.
    Eg: {"mail-user": "blublu@fb.com", "mail-type": "BEGIN"}
srun_args: List[str]
    Add each argument in the list to the srun call

Raises
------
ValueError
    In case an erroneous keyword argument is added, a list of all eligible parameters
    is printed, with their default values
)nonslurmr   r-   r   r_  rb  rP  rQ  rT  ra  rc  rd  @signalzY"num_gpus" is deprecated, please use "gpus_per_node" instead (overwritting with num_gpus)rM  r   r   rL  rN  zP"cpus_per_gpu" requires to set "gpus_per_task" to work (and not "gpus_per_node"))r   z0-r   %arrayz%jz%A_%az%tr}   r/  errorr~   z	open-mode)z#!/bin/bashr   z# Parametersr   z# setupz--errorr3  z--unbufferedz--outputr  z	# commandzexport SUBMITIT_EXECUTOR=slurmz
# teardown
)localsr   rp   rq   rH   rI   popr   r  r   stdoutstderrrA   r   minreplaceupdater   r~   _as_sbatch_flag_shlex_joinrK   ).r-   r   r   rK  r   r   r   r   rL  rM  r   rN  rO  rP  rQ  r   rR  rS  rT  rU  rV  rW  rX  rY  rZ  r[  r\  r]  r^  r_  r`  ra  r   rb  rc  rd  rf  kvr  r  ro  rp  rM   stderr_flagssrun_cmds.                                                 r    r   r     sb   LH $*8>>#3[#341aq$RZIZ$!Q$#3J[199:!N;KLJxg	
 '1nnZ&C
?##z(IhiNN&)EFF)S))i77 "9q=/3yBS3T2UV
7g.g.!>>$4Jx$nnT37
7&J{(/0/EJ_Q
167   "i5((  .rIv3FI
Ff\f\efg((Hg./	
(
 E "l#h..99Uu \s   
H5H5H5r   c                 ^    U [        U 5      :X  a  [        U 5       S3$ [        U S-  5       S3$ )NGBi   MB)r   )r   s    r    r   r     s6    Vf+b!!&4- !$$r:   rI  valuec                     U R                  SS5      n USL a  SU  3$ [        R                  " [        U5      5      nSU  SU 3$ )Nr   r   Tz
#SBATCH --=)rr  r   r   r   )rI  r}  s     r    rt  rt  #  sK    
++c3
C}C5!!KKE
#EuAeW%%r:   split_commandc                 2    SR                  S U  5       5      $ )z9Same as shlex.join, but that was only added in Python 3.8r  c              3   N   #    U  H  n[         R                  " U5      v   M     g 7f)N)r   r   )r   args     r    r   _shlex_join.<locals>.<genexpr>.  s     >EKK$$s   #%)rK   )r  s    r    ru  ru  ,  s    88>>>>r:   )"submititNr   r   NNNNNNNNNNNNZ   NNNNNNNNNN   r  FNNNT)2	functoolsrD  r   r   r   r5  rn   r   typingr_   r  rH   pathlibr   r   r   r   r   r   ra   Tupler!   InfoWatcherr#   r@  Rrg   rG   ry   r   r   r   r   JobEnvironmentrp   PicklingExecutorr   	lru_cacherd   r>  r   rb   r`   rw   Iterabler   r:  r   rt  ru  rY   r:   r    <module>r     s     	 	    
     7 7& &c(: ; &&9t'' 9xCtxx C&	) 	C BGGCL   3   .j j!+/88 !+Hm9D)) m9` ^bff!5 ^ ^ "&(,&*%)!%&*&* '+*. $($( $#' $ $!"&"&!%#'26 ""&?C/3INNHHS$YN N {{3	N
 N N [[%N ;;s#N ++c"N kk#N ;;s#N ;;s#N 
S	N ;;rwws|$N kk"''#,'N  
S	!N" S!#N$ S!%N& 'N( [[)N* C +N, [[-N. [[/N0 ++c
1N2 {{33N4 {{35N6 kk#7N8 C 9N: {{288D#I./;N< =N> ?N@ ANB {{3CND ;;rwwsBFF{';<ENF {{2;;s+,GNH INJ 	KNb% %3 %& &RVV & &?rwws| ? ?r:   