
    #ShS              I           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
Z
d dlZd dlmZ ddlmZmZmZmZ dede	j        e	j        edf                  fdZ G d	 d
ej                  Z G d dej        ej                           Z G d de          Zdede	j        e         fdZdedede	j        e         defdZdefdZ  G d dej!                  Z" G d dej#                  Z$ e j%                    de	j&        ee	j'        f         fd            Z(	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dMd"ed#e	j)        eef         d$ed%e	j*        e         d&ed'ed(e	j*        e         d)e	j*        e         d*e	j*        e         d+e	j*        e         d,e	j*        e         d-e	j*        e         d.e	j*        e         d/e	j*        e	j        e                  d0e	j*        e         d1e	j*        e         d2e	j*        e         d3ed4e	j*        e         d5e	j*        e         d6e	j*        e         d7e	j*        e         d8e	j*        e         d9e	j*        e         d:e	j*        e         d;e	j*        e         d<e	j*        e         d=e	j*        e	j)        e+ef                  d>ed?ed@e+dAe	j*        e         dBe	j*        e	j&        ee	j'        f                  dCe	j*        e	j,        e                  dDe+defHdEZ-dFe.defdGZ/dHedIe	j'        defdJZ0dKe	j        e         defdLZ1dS )N    N)Path   )corejob_environmentloggerutilsjob_idreturn.c                 V   d}t          j        ||           }|K|                    d          |                    d                              d          }fd|D             S |                     dd          ^}}|s|fgS t	          t          |d	                             }||fgS )
zlReads 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+)?\]Nmain_idarrays,c                 \    g | ](}t          g|                    d           z             )S )-)tuplesplit).0array_rangemains     Z/var/www/html/movieo_spanner_bot/venv/lib/python3.11/site-packages/submitit/slurm/slurm.py
<listcomp>zread_job_id.<locals>.<listcomp>    s6    WWW;tf{0055566WWW    _   r   )researchgroupr   strint)r	   patternmatcharray_rangesr   array_id	array_numr   s          @r   read_job_idr%      s     LGIgv&&E{{9%%{{8,,22377WWWW,WWWW#\\#q11( 	 J<HQK(())	)$%%r   c                       e Zd Zdej        ej        e                  fdZd
dededefdZdej	        e
ef         dej        eej        eef         f         fdZd	S )SlurmInfoWatcherr
   c                     d | j         | j        z
  D             }|sd S g d}|D ]&}|                    dt          |          g           '|S )Nc                 D    h | ]}|                     d           d         S )r   r   )r   )r   xs     r   	<setcomp>z1SlurmInfoWatcher._make_command.<locals>.<setcomp>.   s&    OOOAGGCLLOOOOr   )sacctz-ozJobID,State,NodeListz--parsable2z-j)_registered	_finishedextendr   )selfto_checkcommandjids       r   _make_commandzSlurmInfoWatcher._make_command+   sn     POT-=-NOOO 	4HHH 	- 	-CNND#c((+,,,,r   standardr	   modec                 ^    |                      ||          }|                    d          pdS )aS  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)
        )r6   StateUNKNOWN)get_infoget)r0   r	   r6   infos       r   	get_statezSlurmInfoWatcher.get_state6   s0     }}V$}//xx  -I-r   stringc           	         t          |t                    s|                                }|                                }t	          |          dk     ri S |d                             d          }i }|dd         D ]}d t          ||                    d                    D             }|d         }|rd|v r?	 t          |          }n7# t          $ r*}	t          j
        d	| d
|	 t                     Y d}	~	d}	~	ww xY w|D ]}
||d                    |
dd                   <   t	          |
          dk    rLt          t          |
d                   t          |
d                   dz             D ]}|||
d          d| <   |S )zNReads the output of sacct and returns a dictionary containing main informationr   r   |r   Nc                 >    i | ]\  }}||                                 S  )stripr   r*   ys      r   
<dictcomp>z.SlurmInfoWatcher.read_info.<locals>.<dictcomp>O   s&    JJJdaQ		JJJr   JobID.zCould not interpret z# correctly (please open an issue):
r      )
isinstancer   decode
splitlineslenr   zipr%   	ExceptionwarningswarnDeprecationWarningjoinranger   )r0   r>   linesnames	all_statslinestatsr	   multi_split_job_idesplit_job_idindexs               r   	read_infozSlurmInfoWatcher.read_infoD   s   &#&& 	%]]__F!!##u::>>Ias##57	!""I 	H 	HDJJc%C.I.IJJJE7^F SF]]%0%8%8""   Z6ZZWXZZ\n    !3 H H  HH\"1"-.. |$$))!&s<?';';Sa=Q=QTU=U!V!V H HBG	\!_">">u">">??H s   :C


C> C99C>N)r5   )__name__
__module____qualname__tpOptionalListr   r4   r=   UnionbytesDictr^   rB   r   r   r'   r'   *   s        	r{273<8 	 	 	 	. . .3 . . . . . 4 bgcSVhFWAW9X      r   r'   c                   <    e Zd ZdZ ed          Zd	deddfdZdS )
SlurmJobscanceliX  )delay_sFtimeoutr
   Nc                     d| j         dg}|st          j        |dgz              t          j        |t          j        gz              dS )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)
        rj   z--signalSIGTERMN)r	   
subprocess
check_callSlurmJobEnvironmentUSR_SIG)r0   rl   cmds      r   
_interruptzSlurmJob._interruptj   sU     $+z2 	5!#"3444c%8%@$AABBBBBr   )F)r_   r`   ra   _cancel_commandr'   watcherboolrt   rB   r   r   ri   ri   f   s\        Os+++GC C$ C4 C C C C C Cr   ri   c                       e Zd ZdS )SlurmParseExceptionN)r_   r`   ra   rB   r   r   ry   ry   y   s        Dr   ry   suffix_partsc                 P   g }|                      d          D ]}d|v rr|                     d          \  }}t          |          }t          t          |          t          |          dz             D ]}|                    |d|            x|                    |           |S )z_Parse 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   rM   rT   r   append)rz   suffixessuffix_partlowhigh
int_lengthnums          r   _expand_id_suffixr   }   s     H#))#.. ) )+#))#..ICSJSXXs4yy1}55 8 83 6 6 6 677778 OOK((((Or   	node_listposparsedc                    dg}|t          |           k     r| |         }|dk    r|                    |           |dz   S |dk    rD|                     d|          }t          | |dz   |                   fd|D             }|dz   }n"t	          |          D ]\  }}||z   ||<   |dz  }|t          |           k     |                    |           |S )zzParse 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   []c                 $    g | ]}D ]}||z   S rB   rB   )r   prefixsuffixr~   s      r   r   z%_parse_node_group.<locals>.<listcomp>   s*    VVVFXVV6VVVVr   )rM   r/   r]   r   	enumerate)	r   r   r   prefixesclast_posir   r~   s	           @r   _parse_node_groupr      s    tH
I

cN88MM(###7N88 sC00H(37X3E)FGGHVVVVhVVVHQ,CC&x00 ) )	6$qj1HC I

 MM(Jr   c                     	 d}g }|t          |           k     r$t          | ||          }|t          |           k     $|S # t          $ r}t          d|  d|          |d }~ww xY w)Nr   z-Unrecognized format for SLURM_JOB_NODELIST: '')rM   r   
ValueErrorry   )r   r   r   r[   s       r   _parse_node_listr      s    j!C	NN""#IsF;;C C	NN"" j j j!"^R["^"^"^`abbhiijs   <? 
A#	AA#c            
       h    e Zd Zddddddddd	d
	ZdeddfdZedej        e	         fd            Z
dS )rq   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                     | j         }t          j        dd|gd           t          j                                        d| d| d           d S )Nscontrolrequeue<   )rl   zRequeued job z (z remaining timeouts))r	   ro   rp   r   
get_loggerr<   )r0   r   r3   s      r   _requeuezSlurmJobEnvironment._requeue   s]    kz9c:BGGGG  !W!W!W	!W!W!WXXXXXr   c                     t           j                            | j        d         d          }|s| j        gS t          |          S )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environr;   _envhostnamer   )r0   r   s     r   	hostnameszSlurmJobEnvironment.hostnames   s@     JNN49W#5r::	 	#M?"	***r   )r_   r`   ra   r   r   r   propertyrb   rd   r   r   rB   r   r   rq   rq      s         #*%%%,.
 
DY# Y$ Y Y Y Y
 +273< + + + X+ + +r   rq   c                   h    e Zd ZdZeZ	 	 	 ddej        ee	f         de
dedej        e         d	df
 fd
Zed	ej        fd            Zed	ej        e         fd            Zdej        eej        f         d	ej        eej        f         f fdZdej        d	df fdZdej        ej                 d	ej        ej        ej                          f fdZed	efd            Zdeded	efdZd	e
fdZ de	d	ej        e         fdZ!e"dej        e#ef         d	efd            Z$ed	e
fd            Z% xZ&S )SlurmExecutoraP  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.
    rI         ?Nfoldermax_num_timeoutmax_pickle_size_gbpythonr
   c                     t                                          |||           |t          j        t          j                  n|| _        |                                 dk    st          d          d S )N)r   r   r   z;Could not detect "srun", are you indeed on a slurm cluster?)	super__init__shlexquotesys
executabler   affinityRuntimeError)r0   r   r   r   r   	__class__s        r   r   zSlurmExecutor.__init__   sw     	+1 	 	
 	
 	

 6<^ek#.111}}""\]]] #"r   c                     ddddddddS )	Njob_nametimememr   cpus_per_taskgpus_per_nodentasks_per_node)nametimeout_minmem_gbr   r   r   tasks_per_noderB   clss    r   _equivalence_dictzSlurmExecutor._equivalence_dict  s(     !,,/
 
 	
r   c                 8    t          t                                S )4Parameters that can be set through update_parameters)set_get_default_parametersr   s    r   _valid_parameterszSlurmExecutor._valid_parameters  s     *,,---r   paramsc                     t                                          |          }d|v rt          |d                   |d<   |S )Nr   )r   _convert_parameters_convert_mem)r0   r   r   s     r   r   z!SlurmExecutor._convert_parameters  s=    ,,V44F??(77F5Mr   kwargsc                    t                      }t          t          |          t          |          z
            }|rSd                    d t          |                                          D                       }t          d| d|           t          dd| j        d|  t                      j	        di | dS )	a  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   F   K   | ]\  }}| d t          |           dV  dS )z (default: )N)reprrD   s      r   	<genexpr>z<SlurmExecutor._internal_update_parameters.<locals>.<genexpr>9  s=      "d"d41aa#>#>DGG#>#>#>"d"d"d"d"d"dr   zUnavailable parameter(s): z
Valid parameters are:
  - znothing to dor2   r   NrB   )
r   sortedr   rS   itemsr   _make_sbatch_stringr   r   _internal_update_parameters)r0   r   defaultsin_valid_parametersr>   r   s        r   r   z)SlurmExecutor._internal_update_parameters  s    6 +,,$S[[3x==%@AA 	]]"d"d6RZR`R`RbRbKcKc"d"d"dddFg-@gg_egg   	RODKRR6RRR++55f55555r   delayed_submissionsc                     t          |          dk    r!t                                          |          S t          j                             j                  }|                    dd            j        	                    dd          }g }|D ]e}|t          j                    j         dz  }|                    | j                   |                    |           |                    |           ft          |          }t#           j         j                  } |j        d
i  j         ||j        d<                                     |                     j                  t-          t/          j                             fdt/          |          D             }	t3          |	|          D ] \  }
}|
j                            |d	           !|	S )Nr   T)parentsexist_okr      z.pkl	map_countc                 R    g | ]#}t          j        j         d |           $S )r   )r   r	   tasks)ri   r   r	   )r   a	first_jobr0   	tasks_idss     r   r   z?SlurmExecutor._internal_process_submissions.<locals>.<listcomp>Z  sI     +
 +
 +
`aHDK93C0I0Ia0I0IQZ[[[+
 +
 +
r   submitted_picklerB   )rM   r   _internal_process_submissionsr   JobPathsget_first_id_independent_folderr   mkdir
parametersr;   uuiduuid4hexset_timeoutr   dumpr}   r   update_parameters	_throttle_submit_command_submitit_command_strlistrT   r   rN   pathsmove_temporary_file)r0   r   r   r   pickle_pathsdpickle_pathnarray_exjobsjobr   r   r   s   `          @@r   r   z+SlurmExecutor._internal_process_submissionsA  s    "##q((77889LMMM??LLTD111o))&!44$ 	- 	-A djll&6#<#<#<<KMM+t';<<<FF;,,,,#$$ !d.BCC""55T_555+,K(&.&>&>t?Y&Z&Z	y23344	+
 +
 +
 +
 +
 +
ejklemem+
 +
 +
 !$D, 7 7 	K 	KCI))+7IJJJJr   c           	          d                     | j        dt          j        t	          | j                            g          S )N z-u -m submitit.core._submit)rS   r   r   r   r   r   )r0   s    r   r  z#SlurmExecutor._submitit_command_stra  s5    xx&CU[QTUYU`QaQaEbEbcdddr   r2   uidc                 4    t          d|| j        d| j        S )Nr   rB   )r   r   r   )r0   r2   r  s      r   _make_submission_file_textz(SlurmExecutor._make_submission_file_texte  s!    "Z74;ZZ$/ZZZr   c                     | j                             dd          }t          d| j                             dd                    }||z  S )Nr   r   r   )r   r;   max)r0   r   r   s      r   
_num_taskszSlurmExecutor._num_tasksh  sF    _((!44!!T_%8%89JA%N%NOO~%%r   submission_file_pathc                 $    dt          |          gS )Nsbatch)r   )r0   r  s     r   _make_submission_commandz&SlurmExecutor._make_submission_commandm  s    #23344r   r>   c                     t          | t                    s|                                 } t          j        d|           }|t          j        d|  d          |                    d          S )z3Returns the job ID from the output of sbatch stringzjob (?P<id>[0-9]+)Nz'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)rJ   r   rK   r   r   r   FailedSubmissionErrorr   )r>   outputs     r   #_get_job_id_from_submission_commandz1SlurmExecutor._get_job_id_from_submission_commandp  s}     &#&& 	%]]__F0&99>-J& J J J  
 ||D!!!r   c                 2    t          j        d          dndS )Nsrunr   )shutilwhichr   s    r   r   zSlurmExecutor.affinity~  s    \&))1rrq8r   )rI   r   N)'r_   r`   ra   __doc__ri   	job_classrb   re   r   r   r   floatrc   r   classmethodr   EquivalenceDictr   Setr   rg   Anyr   r   rd   r   DelayedSubmissionJobr   r   r  r  r  r  staticmethodrf   r"  r   __classcell__)r   s   @r   r   r      s        : I
  !$'#'^ ^d#^ ^ "	^
 C ^ 
^ ^ ^ ^ ^ ^  	
$"6 	
 	
 	
 [	
 ."&+ . . . [."'#rv+*> 273PRPV;CW      $6BF $6t $6 $6 $6 $6 $6 $6L#%75+B#C	"&!	"     @ es e e e Xe[# [C [C [ [ [ [&C & & & &
5T 5bgcl 5 5 5 5 "BHUCZ4H "S " " " \" 9 9 9 9 [9 9 9 9 9r   r   c                      t          j        t                    } t          | j        t          | j                   d         | j                  }d |D             S )r   Nc                 "    i | ]\  }}|d v	||S )>   r   r2   r   rB   )r   keyvals      r   rF   z+_get_default_parameters.<locals>.<dictcomp>  s)    ]]]cs:\/\/\C/\/\/\r   )inspectgetfullargspecr   rN   argsrM   r   )specszippeds     r   r   r     sT     "#677ES000223U^DDF]]V]]]]r   submititr   r   Z      FTr2   r   r   	partitionr   r   r   r   cpus_per_gpunum_gpusr   gpus_per_taskqossetupr   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#                 N  + g d++fdt                                                      D             }#t          j         d| |#d<   |	-t	          j        d           |#                    dd          |#d	<   d
|#v rd|#vrt	          j        d           t          j        |          }$t          |$j
                  }%t          |$j                  }&|at          |t                    r|sJ d|dz
   dt          ||           |#d<   |%                    dd          }%|&                    dd          }&|%                    dd          |#d<   |s|&                    dd          |#d<   d|#d<   | |#                    |            g d}'t#          |#          D ]+}(|'                    t'          |(|#|(                              ,|
|'ddg|z   z  }'|"r:|rg nd|&g})|!g }!t)          ddd |%g|)|!          }*d!                    |*| f          } |'dd"d#| dgz  }'d$                    |'          S )%aL  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
    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   r2   r   rR  rU  rD  rG  rT  rV  rW  c                 (    i | ]\  }}||v||S NrB   )r   kvrY  s      r   rF   z'_make_sbatch_string.<locals>.<dictcomp>  s.    [[[41aq}RZIZIZ!QIZIZIZr   @signalNzY"num_gpus" is deprecated, please use "gpus_per_node" instead (overwritting with num_gpus)rA  r   r   r@  rB  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--errorr$  z--unbufferedz--outputr  z	# commandzexport SUBMITIT_EXECUTOR=slurm
)localsr   rq   rr   rP   rQ   popr   r   r   stdoutstderrrJ   r   minreplaceupdater   r}   _as_sbatch_flag_shlex_joinrS   ),r2   r   r   r?  r   r   r   r   r@  rA  r   rB  rC  rD  r   rE  rF  rG  rH  rI  rJ  rK  rL  rM  rN  rO  rP  rQ  rR  rS  rT  r   rU  rV  rW  r   r	  rf  rg  rU   r\  stderr_flagssrun_cmdrY  s,                                              @r   r   r     s   F  H \[[[688>>#3#3[[[J19LLNLLJxg	
 	
 	
 '1nnZ&C&C
?###z(I(IhiiiN&)))EFF)S))7i777V9q=VV3yBS3T3TVV
7g..g..!>>$44Jx 8$nnT377
7&J{(/000///EJ 8 8_Q
1667777"i5((  0 .FrrIv3FI
Ff\f\efgg((Hg.//	
(
 E 99Ur   r   c                 v    | t          |           k    rt          |            dS t          | dz             dS )NGBi   MB)r   )r   s    r   r   r     sC    Vf++!!!!&4-  $$$$r   r5  valuec                     |                      dd          } |du rd|  S t          j        t          |                    }d|  d| S )Nr   r   Tz
#SBATCH --=)ri  r   r   r   )r5  rr  s     r   rk  rk    sW    
++c3

C}}!C!!!KE

##E%%%e%%%r   split_commandc                 @    d                     d | D                       S )z9Same as shlex.join, but that was only added in Python 3.8r  c              3   >   K   | ]}t          j        |          V  d S r[  )r   r   )r   args     r   r   z_shlex_join.<locals>.<genexpr>&  s,      >>EK$$>>>>>>r   )rS   )ru  s    r   rl  rl  $  s#    88>>>>>>>>r   )!r<  Nr   r   NNNNNNNNNNNr=  NNNNNNNNNNr>  r<  FNNNT)2	functoolsr7  r   r   r   r&  ro   r   typingrb   r   rP   pathlibr   r   r   r   r   r   rd   Tupler%   InfoWatcherr'   r0  Rri   rO   ry   r   r   r   r   JobEnvironmentrq   PicklingExecutorr   	lru_cacherg   r.  r   re   rc   rw   Iterabler   r*  r   rk  rl  rB   r   r   <module>r     s        				 				       



             7 7 7 7 7 7 7 7 7 7 7 7& &c(: ; & & & &&9 9 9 9 9t' 9 9 9xC C C C Ctx C C C&	 	 	 	 	) 	 	 	C BGCL      3      .j j j j j!+ !+ !+ !+ !+/8 !+ !+ !+Hm9 m9 m9 m9 m9D) m9 m9 m9` ^bf!5 ^ ^ ^ ^ "&(,&*%)!%&*&* '+ $($( $#' $ $!"&"&!%#'26 ""&?C/3GF FFHS$YF F {3	F
 F F [%F ;s#F +c"F k#F ;s#F ;s#F 
S	F ;rws|$F 
S	F  S!!F" S!#F$ %F& ['F( C )F* [+F, [-F. +c
/F0 {31F2 {33F4 k#5F6 C 7F8 {28D#I./9F: ;F< =F> ?F@ {3AFB ;rwsBF{';<CFD {2;s+,EFF GFH 	IF F F FR% %3 % % % %& &RV & & & & &?rws| ? ? ? ? ? ? ?r   