
    h_                     `   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	  S SK
Jr  S SKJrJ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r S SKJr  S SKJrJr  S S	KJ r J!r!J"r"J#r#J$r$  SMS
\%S\&SS4S jjr'S\RP                  S\RP                  S\)4S jr*S\RV                  RX                  S\)SS4S jr- " S S5      r. " S S5      r/ " S S5      r0S\\!\)4   S\!4S jr1S\)S\)S\)S\!4S jr2S \)S\!4S! jr3SNS"\\Rh                  \54   S\Rh                  4S# jjr6SOS$\5S%\5S\%4S& jjr7    SPS'\%S(\\5   S)\5S*\&S\4
S+ jjr8S,\ S-\Rr                  S.\Rr                  SS4S/ jr:S0\Rr                  S1\Rr                  SS4S2 jr;S3\RP                  S-\Rx                  S\&4S4 jr=S3\\%\RP                  4   S-\R|                  S\&4S5 jr?S3\RP                  S-\R                  S\&4S6 jrAS3\RP                  S-\R                  S\&4S7 jrCS3\RP                  S-\R                  S\&4S8 jrES3\\%\RP                  4   S-\Rr                  S\&4S9 jrFS:\\RP                  \G\4   S\)4S; jrHS<\R                  R                  S=\	\5   S\G\R                     4S> jrLS?\	S\	4S@ jrMSA\	\R                     SB\	\R                     SC\)SS4SD jrNSE\\RP                  \O\5\RP                  4   4   S"\Rh                  S\\R                  \"4   4SF jrPSG\#SH\%SI\%S\&4SJ jrQSQSK\&S\R\O\5\54   \54   4SL jjrSg! \ a    Sr GNf = f)R    N)deque)Iterable)zip_longest)OptionalUnion)spaces)SummaryWriter)Logger	configure)GymEnvSchedule
TensorDict	TrainFreqTrainFrequencyUnitseed
using_cudareturnc                 &   [         R                  " U 5        [        R                   R                  U 5        [        R                  " U 5        U(       a?  S[        R
                  R                  l        S[        R
                  R                  l        gg)zH
Seed the different random generators.

:param seed:
:param using_cuda:
TFN)	randomr   npthmanual_seedbackendscudnndeterministic	benchmark)r   r   s     X/home/james-whalen/.local/lib/python3.13/site-packages/stable_baselines3/common/utils.pyset_random_seedr      sX     KKIINN4NN4*.'&+#     y_predy_truec                     UR                   S:X  a  U R                   S:X  d   e[        R                  " U5      nUS:X  a  [        R                  $ [	        S[        R                  " X-
  5      U-  -
  5      $ )aZ  
Computes fraction of variance that ypred explains about y.
Returns 1 - Var[y-ypred] / Var[y]

interpretation:
    ev=0  =>  might as well have predicted zero
    ev=1  =>  perfect prediction
    ev<0  =>  worse than just predicting zero

:param y_pred: the prediction
:param y_true: the expected value
:return: explained variance of ypred and y
   r   )ndimr   varnanfloat)r    r!   var_ys      r   explained_variancer)   3   s]     ;;!q 000FF6NEaZ266OU1rvvfo/F/N+N%OOr   	optimizerlearning_ratec                 2    U R                    H  nXS'   M	     g)z
Update the learning rate for a given optimizer.
Useful when doing linear schedule.

:param optimizer: Pytorch optimizer
:param learning_rate: New learning rate value
lrN)param_groups)r*   r+   param_groups      r   update_learning_rater0   F   s     !--)D .r   c                   P    \ rS rSrSrS\\\4   4S jrS\S\4S jr	S\
4S jrS	rg
)FloatScheduleR   z
Wrapper that ensures the output of a Schedule is cast to float.
Can wrap either a constant value or an existing callable Schedule.

:param value_schedule: Constant value or callable schedule
        (e.g. LinearSchedule, ConstantSchedule)
value_schedulec                     [        U[        5      (       a  UR                  U l        g [        U[        [        45      (       a  [        [        U5      5      U l        g [        U5      (       d
   SU 35       eXl        g )Nz>The learning rate schedule must be a float or a callable, not )
isinstancer2   r4   r'   intConstantSchedulecallable)selfr4   s     r   __init__FloatSchedule.__init__[   sf    nm44,:,I,ID55"253H"IDN++~/mn|m}-~~+"0r   progress_remainingr   c                 6    [        U R                  U5      5      $ N)r'   r4   r:   r=   s     r   __call__FloatSchedule.__call__d   s     T(();<==r   c                 "    SU R                    S3$ )NzFloatSchedule()r4   r:   s    r   __repr__FloatSchedule.__repr__i   s     3 34A66r   rE   N)__name__
__module____qualname____firstlineno____doc__r   r   r'   r;   rA   strrG   __static_attributes__ r   r   r2   r2   R   s;    1uXu_'= 1>5 >U >
7# 7r   r2   c                   R    \ rS rSrSrS\S\S\SS4S jrS	\S\4S
 jrS\4S jr	Sr
g)LinearSchedulem   a  
LinearSchedule interpolates linearly between start and end
between ``progress_remaining`` = 1 and ``progress_remaining`` = ``end_fraction``.
This is used in DQN for linearly annealing the exploration fraction
(epsilon for the epsilon-greedy strategy).

:param start: value to start with if ``progress_remaining`` = 1
:param end: value to end with if ``progress_remaining`` = 0
:param end_fraction: fraction of ``progress_remaining``  where end is reached e.g 0.1
    then end is reached after 10% of the complete training process.
startendend_fractionr   Nc                 (    Xl         X l        X0l        g r?   rT   rU   rV   )r:   rT   rU   rV   s       r   r;   LinearSchedule.__init__z   s    
(r   r=   c                     SU-
  U R                   :  a  U R                  $ U R                  SU-
  U R                  U R                  -
  -  U R                   -  -   $ Nr#   )rV   rU   rT   r@   s     r   rA   LinearSchedule.__call__   sR    ""d&7&7788O::%7!7DHHtzz<Q RUYUfUf fffr   c                 V    SU R                    SU R                   SU R                   S3$ )NzLinearSchedule(start=z, end=z, end_fraction=rD   rX   rF   s    r   rG   LinearSchedule.__repr__   s.    &tzzl&
/RVRcRcQddeffr   )rU   rV   rT   rI   rJ   rK   rL   rM   r'   r;   rA   rN   rG   rO   rP   r   r   rR   rR   m   sL    
)e )% )u ) )
g5 gU gg# gr   rR   c                   F    \ rS rSrSrS\4S jrS\S\4S jrS\4S jr	S	r
g
)r8      z
Constant schedule that always returns the same value.
Useful for fixed learning rates or clip ranges.

:param val: constant value
valc                     Xl         g r?   rb   )r:   rb   s     r   r;   ConstantSchedule.__init__   s    r   _r   c                     U R                   $ r?   rd   )r:   rf   s     r   rA   ConstantSchedule.__call__   s    xxr   c                 "    SU R                    S3$ )NzConstantSchedule(val=rD   rd   rF   s    r   rG   ConstantSchedule.__repr__   s    &txxj22r   rd   Nr_   rP   r   r   r8   r8      s2    E % E 3# 3r   r8   r4   c                    ^  [         R                  " S5        [        T [        [        45      (       a  [        [        T 5      5      m O[        T 5      (       d   eU 4S j$ )z
Transform (if needed) learning rate and clip range (for PPO)
to callable.

:param value_schedule: Constant value of schedule function
:return: Schedule function (can return constant value)
zCget_schedule_fn() is deprecated, please use FloatSchedule() insteadc                 &   > [        T" U 5      5      $ r?   )r'   )r=   r4   s    r   <lambda>!get_schedule_fn.<locals>.<lambda>   s    eN;M,N&Or   )warningswarnr6   r'   r7   constant_fnr9   rE   s   `r   get_schedule_fnrr      sN     MMWX .5#,//$U>%:;'''' POr   rT   rU   rV   c                 d   ^ ^^ [         R                  " S5        S[        S[        4UUU 4S jjnU$ )aE  
Create a function that interpolates linearly between start and end
between ``progress_remaining`` = 1 and ``progress_remaining`` = ``end_fraction``.
This is used in DQN for linearly annealing the exploration fraction
(epsilon for the epsilon-greedy strategy).

:params start: value to start with if ``progress_remaining`` = 1
:params end: value to end with if ``progress_remaining`` = 0
:params end_fraction: fraction of ``progress_remaining``
    where end is reached e.g 0.1 then end is reached after 10%
    of the complete training process.
:return: Linear schedule function.
zBget_linear_fn() is deprecated, please use LinearSchedule() insteadr=   r   c                 <   > SU -
  T:  a  T$ TSU -
  TT-
  -  T-  -   $ r[   rP   )r=   rU   rV   rT   s    r   funcget_linear_fn.<locals>.func   s5    ""l2JA 22sU{ClRRRr   )ro   rp   r'   )rT   rU   rV   ru   s   ``` r   get_linear_fnrw      s5     MMVWS S5 S S Kr   rb   c                 @   ^  [         R                  " S5        U 4S jnU$ )z
Create a function that returns a constant
It is useful for learning rate schedule (to avoid code duplication)

:param val: constant value
:return: Constant schedule function.
zBconstant_fn() is deprecated, please use ConstantSchedule() insteadc                    > T$ r?   rP   )rf   rb   s    r   ru   constant_fn.<locals>.func   s    
r   )ro   rp   )rb   ru   s   ` r   rq   rq      s     MMVW Kr   devicec                    U S:X  a  Sn [         R                  " U 5      n U R                  [         R                  " S5      R                  :X  a9  [         R                  R	                  5       (       d  [         R                  " S5      $ U $ )z
Retrieve PyTorch device.
It checks that the requested device is available first.
For now, it supports only cpu and cuda.
By default, it tries to use the gpu.

:param device: One for 'auto', 'cuda', 'cpu'
:return: Supported Pytorch device
autocudacpu)r   r{   typer~   is_availabler{   s    r   
get_devicer      sb     YYvF {{bii',,,RWW5I5I5K5KyyMr   log_pathlog_namec                    Sn[         R                   " [        R                  R                  U [         R                  " U5       S35      5       H  nUR                  [        R                  5      S   nUR                  S5      S   nUSR                  UR                  S5      SS 5      :X  d  Mb  UR                  5       (       d  My  [        U5      U:  d  M  [        U5      nM     U$ )aJ  
Returns the latest run number for the given log name and log path,
by finding the greatest number in the directories.

:param log_path: Path to the log folder containing several runs.
:param log_name: Name of the experiment. Each run is stored
    in a folder named ``log_name_1``, ``log_name_2``, ...
:return: latest run number
r   z_[0-9]*rf   N)	globospathjoinescapesplitsepisdigitr7   )r   r   
max_run_idr   	file_nameexts         r   get_latest_run_idr      s     J		"'',,xDKK4I3J'1RSTJJrvv&r*	ooc"2&sxx	 4Sb 9::s{{}}QTUXQY\fQfSJ	 U
 r   verbosetensorboard_logtb_log_namereset_num_timestepsc                    SS/pTUb  [         c  [        S5      eUbT  [         bM  [        X5      nU(       d  US-  n[        R                  R                  X SUS-    35      nU S:  a  SS/nOS/nO	U S:X  a  S/n[        XES	9$ )
a
  
Configure the logger's outputs.

:param verbose: Verbosity level: 0 for no output, 1 for the standard output to be part of the logger outputs
:param tensorboard_log: the log location for tensorboard (if None, no logging)
:param tb_log_name: tensorboard log
:param reset_num_timesteps:  Whether the ``num_timesteps`` attribute is reset or not.
    It allows to continue a previous learning curve (``reset_num_timesteps=False``)
    or start from t=0 (``reset_num_timesteps=True``, the default).
:return: The logger object
NstdoutzCTrying to log data to tensorboard but tensorboard is not installed.r#   rf   tensorboardr    )format_strings)r	   ImportErrorr   r   r   r   r   )r   r   r   r   	save_pathr   latest_run_ids          r   configure_loggerr     s    " !%xj~"}'<_``"}'@)/G"QMGGLLM=STCTBU2VW	a<&6N+_N	AY>>r   envobservation_spaceaction_spacec                     XR                   :w  a  [        SU SU R                    35      eX R                  :w  a  [        SU SU R                   35      eg)ap  
Checks that the environment has same spaces as provided ones. Used by BaseAlgorithm to check if
spaces match after loading the model with given env.
Checked parameters:
- observation_space
- action_space

:param env: Environment to check for valid spaces
:param observation_space: Observation space to check against
:param action_space: Action space to check against
z!Observation spaces do not match:  != zAction spaces do not match: N)r   
ValueErrorr   )r   r   r   s      r   check_for_correct_spacesr   0  sd     111<=N<OtTWTiTiSjkll'''7~T#JZJZI[\]] (r   space1space2c                    [        U [        R                  5      (       Ga  [        U[        R                  5      (       d   S[        U 5       S[        U5       35       eU R                  R	                  5       UR                  R	                  5       :X  dO   S[        U R                  R	                  5       5       S[        UR                  R	                  5       5       35       eU R                  R	                  5        H)  n[        U R                  U   UR                  U   5        M+     g[        U [        R                  5      (       a<  U R                  UR                  :X  d!   SU R                   SUR                   35       egg)z
If the spaces are Box, check that they have the same shape.

If the spaces are Dict, it recursively checks the subspaces.

:param space1: Space
:param space2: Other space
z!spaces must be of the same type: r   z spaces must have the same keys: z!spaces must have the same shape: N)	r6   r   Dictr   keyslistcheck_shape_equalBoxshape)r   r   keys      r   r   r   B  s=    &&++&&&&++..t2STXY_T`Saaefjkqfres0tt.MM FMM$6$6$88	k-d6==3E3E3G.H-IdSYS`S`SeSeSgNhMij	k8==%%'CfmmC0&--2DE (	FFJJ	'	'||v||+q/PQWQ]Q]P^^bcicocobp-qq+ 
(r   observationc                 :   U R                   UR                   :X  a  gU R                   SS UR                   :X  a  g[        SU R                    S3SUR                    S3-   S	R                  S
R                  [	        [
        UR                   5      5      5      -   5      e)a  
For box observation type, detects and validates the shape,
then returns whether or not the observation is vectorized.

:param observation: the input observation to validate
:param observation_space: the observation space
:return: whether the given observation is vectorized or not
Fr#   NT$Error: Unexpected observation shape  for zBox environment, please use  z)or (n_env, {}) for the observation shape.z, )r   r   formatr   maprN   r   r   s     r   is_vectorized_box_observationr   V  s     -333			12	"3"9"9	92;3D3D2EUK,->-D-D,EQGH9@@3sTeTkTkKlAmno
 	
r   c                     [        U [        5      (       d  U R                  S:X  a  g[        U R                  5      S:X  a  g[	        SU R                   S3S-   5      e)a  
For discrete observation type, detects and validates the shape,
then returns whether or not the observation is vectorized.

:param observation: the input observation to validate
:param observation_space: the observation space
:return: whether the given observation is vectorized or not
rP   Fr#   Tr   r   zJDiscrete environment, please use () or (n_env,) for the observation shape.)r6   r7   r   lenr   r   s     r   "is_vectorized_discrete_observationr   k  s`     +s##{'8'8B'>	[	1	$2;3D3D2EUKZ[
 	
r   c                 f   U R                   [        UR                  5      4:X  a  g[        U R                   5      S:X  a'  U R                   S   [        UR                  5      :X  a  g[        SU R                    S3S[        UR                  5       S3-   S	[        UR                  5       S
3-   5      e)a$  
For multidiscrete observation type, detects and validates the shape,
then returns whether or not the observation is vectorized.

:param observation: the input observation to validate
:param observation_space: the observation space
:return: whether the given observation is vectorized or not
F   r#   Tr   z for MultiDiscrete zenvironment, please use (z,) or (n_env, ) for the observation shape.)r   r   nvecr   r   s     r   'is_vectorized_multidiscrete_observationr     s     S!2!7!78::	[	1	$):):1)=EVE[E[A\)\2;3D3D2EEXY)#.?.D.D*E)FfMN.33455QRS
 	
r   c                 H   U R                   UR                   :X  a  g[        U R                   5      [        UR                   5      S-   :X  a  U R                   SS UR                   :X  a  g[        SU R                    S3SUR                    S3-   S	UR                   S
3-   5      e)a"  
For multibinary observation type, detects and validates the shape,
then returns whether or not the observation is vectorized.

:param observation: the input observation to validate
:param observation_space: the observation space
:return: whether the given observation is vectorized or not
Fr#   NTr   z for MultiBinary zenvironment, please use z or r   r   )r   r   r   nr   s     r   %is_vectorized_multibinary_observationr     s     -333	[	3'8'>'>#?!#C	CHYHYZ[Z\H]araxaxHx2;3D3D2EEVW():)@)@(AFG*,,--IJK
 	
r   c           
         SnUR                   R                  5        H%  u  p4X   R                  UR                  :w  d  M#  Sn  O   U(       a  gSnUR                   R                  5        H(  u  p4X   R                  SS UR                  :w  d  M&  Sn  O   U(       a  gSn [        U W   UR                   U   5        [	        SU W   R                   SU SUR                   U    S	U 35      e! [         a  nU n SnANCSnAff = f)
a  
For dict observation type, detects and validates the shape,
then returns whether or not the observation is vectorized.

:param observation: the input observation to validate
:param observation_space: the observation space
:return: whether the given observation is vectorized or not
TFr#   Nr   zdThere seems to be a mix of vectorized and non-vectorized observations. Unexpected observation shape z	 for key z	 of type z. )r   itemsr   is_vectorized_observationr   )r   r   all_non_vectorizedr   subspaceall_vectorized	error_msges           r   is_vectorized_dict_observationr     s(    *11779 !!X^^3!& : N*11779!!!"%7"N :
  		%k#&68I8P8PQT8UV ,,7,<,B,B+C9SE R(//45R	{D
 	
  	#I	s   !C. .
D8D  Dc           
      R   [         R                  [        [         R                  [        [         R
                  [        [         R                  [        [         R                  [        0nUR                  5        H  u  p4[        X5      (       d  M  U" X5      s  $    [        SU S35      e)a  
For every observation type, detects and validates the shape,
then returns whether or not the observation is vectorized.

:param observation: the input observation to validate
:param observation_space: the observation space
:return: whether the given observation is vectorized or not
zMError: Cannot determine if the observation is vectorized with the space type .)r   r   r   Discreter   MultiDiscreter   MultiBinaryr   r   r   r   r6   r   )r   r   is_vec_obs_func_dict
space_typeis_vec_obs_funcs        r   r   r     s     	

1;EA3 (<'A'A'C#
'44";BB (D
 hizh{{|}~~r   arrc                 ~    [        U 5      S:X  a  [        R                  $ [        [        R                  " U 5      5      $ )z
Compute the mean of an array if there is at least one element.
For empty array, return NaN. It is used for logging only.

:param arr: Numpy array or list of values
:return:
r   )r   r   r&   r'   mean)r   s    r   	safe_meanr     s*     X]266;bggcl(;;r   modelincluded_namesc                     U R                  5       R                  5        VVVs/ s H,  u  p#[        U Vs/ s H  oDU;   PM	     sn5      (       d  M*  UPM.     snnn$ s  snf s  snnnf )a=  
Extract parameters from the state dict of ``model``
if the name contains one of the strings in ``included_names``.

:param model: the model where the parameters come from.
:param included_names: substrings of names to include.
:return: List of parameters values (Pytorch tensors)
    that matches the queried names.
)
state_dictr   any)r   r   nameparamr   s        r   get_parameters_by_namer     sQ     &+%5%5%7%=%=%?p%?kd3_mGn_mX[t_mGnCoE%?ppGnps   A A
A A A 	iterablesc               '   l   #    [        5       n[        U SU06 H  nX;   a  [        S5      eUv   M     g7f)z
``zip()`` function but enforces that iterables are of equal length.
Raises ``ValueError`` if iterables not of equal length.
Code inspired by Stackoverflow answer for question #32954486.

:param \*iterables: iterables to ``zip()``
	fillvaluez Iterables have different lengthsN)objectr   r   )r   sentinelcombos      r   
zip_strictr     s9      xHi<8<?@@ =s   24paramstarget_paramstauc           	      .   [         R                  " 5          [        X5       HW  u  p4UR                  R	                  SU-
  5        [         R
                  " UR                  UR                  X$R                  S9  MY     SSS5        g! , (       d  f       g= f)as  
Perform a Polyak average update on ``target_params`` using ``params``:
target parameters are slowly updated towards the main parameters.
``tau``, the soft update coefficient controls the interpolation:
``tau=1`` corresponds to copying the parameters to the target ones whereas nothing happens when ``tau=0``.
The Polyak update is done in place, with ``no_grad``, and therefore does not create intermediate tensors,
or a computation graph, reducing memory cost and improving performance.  We scale the target params
by ``1-tau`` (in-place), add the new weights, scaled by ``tau`` and store the result of the sum in the target
params (in place).
See https://github.com/DLR-RM/stable-baselines3/issues/93

:param params: parameters to use to update the target params
:param target_params: parameters to update
:param tau: the soft update coefficient ("Polyak update", between 0 and 1)
r#   )alphaoutN)r   no_gradr   datamul_add)r   r   r   r   target_params        r   polyak_updater     sb    ( 
#-f#DE""1s7+FF<$$ejjARARS $E 
s   A'B
Bobsc           
      <   [        U [        R                  5      (       a  [        R                  " XS9$ [        U [
        5      (       a8  U R                  5        VVs0 s H  u  p#U[        R                  " X1S9_M     snn$ [        S[        U 5       35      es  snnf )z
Moves the observation to the given device.

:param obs:
:param device: PyTorch device
:return: PyTorch tensor of the observation on a desired device.
r   z!Unrecognized type of observation )	r6   r   ndarrayr   	as_tensordictr   	Exceptionr   )r   r{   r   _obss       r   obs_as_tensorr   4  sy     #rzz""||C//	C		JM))+V+;CR\\$66+VV;DI;GHH Ws   !B
train_freqnum_collected_stepsnum_collected_episodesc                     U R                   [        R                  :X  a  XR                  :  $ U R                   [        R                  :X  a  X R                  :  $ [        SU R                    S35      e)a  
Helper used in ``collect_rollouts()`` of off-policy algorithms
to determine the termination condition.

:param train_freq: How much experience should be collected before updating the policy.
:param num_collected_steps: The number of already collected steps.
:param num_collected_episodes: The number of already collected episodes.
:return: Whether to continue or not collecting experience
    by doing rollouts of the current policy.
zgThe unit of the `train_freq` must be either TrainFrequencyUnit.STEP or TrainFrequencyUnit.EPISODE not 'z'!)unitr   STEP	frequencyEPISODEr   )r   r   r  s      r   should_collect_more_stepsr  D  sn     ,111"%9%999	.66	6%(<(<<< 22<//1B"F
 	
r   
print_infoc           	      r   [         R                  " SS[        R                  " 5        S[        R                  " 5        35      [        R                  " 5       [
        R                  [        R                  [        [        R                  R                  5       5      [        R                  [        R                  [        R                  S.n SSKnUR                  SUR                  05        SnUR!                  5        H  u  pEUS	U S
U S3-  nM     U (       a  [#        U5        X4$ ! [         a     NHf = f)z
Retrieve system and python env info for the current system.

:param print_info: Whether to print or not those infos
:return: Dictionary summing up the version for each relevant package
    and a formatted string.
z#(\d)z# \1r   )OSPythonzStable-Baselines3PyTorchzGPU EnabledNumpyCloudpickle	Gymnasiumr   Nz
OpenAI Gymr   z- z: 
)resubplatformversionpython_versionsb3__version__r   rN   r~   r   r   cloudpicklegymupdater   r   print)r  env_info
openai_gymenv_info_strr   values         r   get_system_infor   `  s     ffXw8+<+<+>*?qAQAQAS@T(UV))+ __>>277//12"..__H z'='=>? Lnn&
"SEE7"-- 'l!!  s   !D) )
D65D6)F)r}   )r   r   )r   Nr   T)T)Tr   r   r  r   r  ro   collectionsr   collections.abcr   	itertoolsr   typingr   r   r  	gymnasiumr  numpyr   torchr   r   stable_baselines3r  torch.utils.tensorboardr	   r   stable_baselines3.common.loggerr
   r   %stable_baselines3.common.type_aliasesr   r   r   r   r   r7   boolr   r   r'   r)   optim	Optimizerr0   r2   rR   r8   rr   rw   rq   r{   rN   r   r   r   Spacer   r   r   r   r   r   r   r   r   r   r   r   r   r   r   nnModuleTensorr   r   r   r   r   r  tupler   rP   r   r   <module>r4     sS    	   	   $ ! "      5 > m m,# ,4 ,D ,*Przz P2:: P% P&	*BHH$6$6 	*u 	*QU 	*7 76g g83 3.PE(E/$: Px P* U % H 2U x &uRYY^, ")) . C  ( %) $	"?"?c]"? "? 	"?
 "?J^& ^V\\ ^Y_YeYe ^jn ^$rfll rFLL rT r(
rzz 
fjj 
]a 
*
E#rzz/4J 
_e_n_n 
sw 
(
 
X^XlXl 
qu 
*
rzz 
V\VhVh 
mq 
*)


 )
v{{ )
_c )
X5bjj+A V\VbVb gk 4<5T501 <e <
q"%%,, 
q 
qRVWYW`W`Ra 
q8  $TRYYTBII&T 
T 
	T6IuRZZc2::o)>>? I IW\]_]f]fhr]rWs I 


  
 
	
8 "  "d38nc6I0J  "S  Ms   L! !L-,L-