
    &`i,^                     J   d dl Z d dlmZ d dlmZmZmZmZmZm	Z	m
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 d dlmZ d dlmZmZmZmZmZmZmZ  edd	          Zd
eej                  fdZ!	 	 	 d,dej"        dee
ee#         eee#                  f                  dee
ej$        eej$                 f                  de%d
e
ej&        eej&                 f         f
dZ'	 	 	 d-dej(        deej$                 dee
e#df                  de%d
ej&        f
dZ)	 	 	 d-de
ej(        ee#ej(        f         f         dee
ej$        ee#ej$        f         f                  dee
e#df                  de%d
e
ej&        ee#ej&        f         f         f
dZ*	 d.de
ej+        j,        ef         deej+        j,                 d
ej+        j,        fdZ-d Z.dee#ef         d e#d
ee#ef         fd!Z/	 	 	 d-dee#eej(                 f         dee
ej$        ee#ej$        f         f                  dee
e#df                  de%d
ee#eej&                 f         f
d"Z0	 	 	 	 d/d#ej1        dee
ej$        ee#ej$        f         f                  d$e%de%d%ee         d
e
ee#ej&        f         ee#eej&                 f         f         fd&Z2 ej3                    defd'eej&                 dee
e#df                  d(e%d
ej&        fd)            Z4d#ed
e#fd*Z5 ej3                    defd#edee
e#df                  d(e%d
efd+            Z6dS )0    N)ThreadPoolExecutor)AnyDictListOptionalSequenceTupleUnion)env_bool)#get_torch_device_manager_by_context)%_unwrap_ndarray_object_type_if_needed)TensorBatchReturnTypeTensorBatchType_is_nested_tensor_sequence
_is_tensor_is_tensor_mapping_is_tensor_sequence_is_tensor_sequence_mapping,RAY_AIR_DEFAULT_TENSOR_NON_BLOCKING_TRANSFERTreturnc                  B    t                                                      S )a  Gets the correct torch device list configured for this process.

    Returns a list of torch accelerator (GPU, HPU, NPU...) devices allocated for
    the current worker.
    If no accelerators are assigned, then it returns a list with a single CPU device.
    )r   get_devices     q/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/ray/air/_internal/torch_utils.pyr   r      s     /00<<>>>r   
data_batchcolumnscolumn_dtypes	unsqueezec                     |o!t          |d         t          t          f          }|s<|r:t          |t          j                  s t          dt          |           d          |r|ng }fd fd|rLt          |          t          t          fvr|gt          |          z  }fdt          ||          D             S  ||          S )a.  Converts a Pandas dataframe to a torch Tensor or list of torch Tensors.

    The format of the return type will match the format of ``columns``. If a
    list of columns is provided, the return type will be a single tensor. If
    ``columns`` is a list of lists, then the return type will be a list of
    tensors.

    Args:
        data_batch: The pandas dataframe to convert to a
            torch tensor.
        columns:
            The names of the columns in the dataframe to include in the
            torch tensor. If this arg is a List[List[str]], then the return
            type will be a List of tensors. This is useful for multi-input
            models. If None, then use all columns in the ``data_batch``.
        column_dtype: The
            torch dtype to use for the tensor. If set to None,
            then automatically infer the dtype.
        unsqueeze: If set to True, the tensors
            will be unsqueezed (reshaped to (N, 1)) before being concatenated into
            the final tensor. Otherwise, they will be left as is, that is
            (N, ). Defaults to True.

    Returns:
        Either a torch tensor of size (N, len(columns)) where N is the
        number of rows in the ``data_batch`` Dataframe, or a list of
        tensors, where the size of item i is (N, len(columns[i])).

    r   z^If `columns` is a list of strings, `column_dtypes` must be None or a single `torch.dtype`.Got z	 instead.c                 b   t          | t          j        j        j                  r|                                 } | j        j        t          j	        u rHfd| D             }	 t          j        |          S # t          $ r t          j        |          cY S w xY wt          j        |           S )zcThis recursive function allows to convert pyarrow List dtypes
        to multi-dimensional tensors.c                 (    g | ]} |          S r   r   ).0xdtype	tensorizes     r   
<listcomp>zEconvert_pandas_to_torch_tensor.<locals>.tensorize.<locals>.<listcomp>d   s%    999qyyE**999r   r%   )
isinstancepdapi
extensionsExtensionArrayto_numpyr%   typenpobject_torchstackRuntimeErrornested_tensor	as_tensor)valsr%   tensorsr&   s    ` r   r&   z1convert_pandas_to_torch_tensor.<locals>.tensorizeW   s     dBF-<== 	#
 ==??D:?bj(( :9999D999G4{7+++ 4 4 4 *733333	4 ?4u5555s   #A7 7BBc           	         g }| r		|          }n	}|j         D ]s}||         j        }	  
||          }n)# t          $ r}t          d| d| d          |d }~ww xY wr|                    d          }|                    |           tt          |          dk    rt          j        |d          }n|d         }|S )Nr(   zFailed to convert column z to a Torch Tensor of dtype z2. See above exception chain for the exact failure.   )dimr   )	r   values	Exception
ValueErrorr   appendlenr2   cat)r   r%   feature_tensorsbatchcolcol_valstefeature_tensorr   r&   r   s            r   get_tensor_for_columnsz>convert_pandas_to_torch_tensor.<locals>.get_tensor_for_columnso   s!    	w'EEE= 	& 	&CSz(HIhe444    Q Q QQ Q Q  
  #KKNN""1%%%%!##"YA>>>NN,Q/Ns   6
A AAc                 0    g | ]\  }} ||           S )r   r%   r   )r#   
subcolumnsr%   rI   s      r   r'   z2convert_pandas_to_torch_tensor.<locals>.<listcomp>   s=     
 
 
!
E #":UCCC
 
 
r   rK   )	r)   listtupler2   r%   	TypeErrorr/   r@   zip)r   r   r   r   multi_inputrI   r&   s   `  ` @@r   convert_pandas_to_torch_tensorrR   (   sE   H Ez'!*tUmDDK 
= 
M5;1W1W 
2&&2 2 2
 
 	
 !(ggbG6 6 6 6 60      6  LtUm33*Oc'll:M
 
 
 
%(-%@%@
 
 
 	

 &%g]KKKKr   Fndarrayr%   deviceztorch.device
pin_memoryc                    t          |           } | j        j        t          j        u rt          d          t          j                    5  t          j        d           t          j
        | ||          }ddd           n# 1 swxY w Y   |r:|j        j        dk    sJ d|j         d| d            |                                }|S )	a  Convert a NumPy ndarray to a Torch Tensor.

    Args:
        ndarray: A NumPy ndarray that we wish to convert to a Torch Tensor.
        dtype: A Torch dtype for the created tensor; if None, the dtype will be
            inferred from the NumPy ndarray data.
        device: The device on which the tensor(s) should be placed; if None, the Torch
            tensor(s) will be constructed on the CPU.
        pin_memory: Whether to pin the memory of the created tensors.

    Returns: A Torch Tensor.
    a<  Numpy array of object dtype cannot be converted to a Torch Tensor. This may because the numpy array is a ragged tensor--it contains items of different sizes. If using `iter_torch_batches()` API, you can pass in a `collate_fn` argument to specify custom logic to convert the Numpy array batch to a Torch tensor batch.ignorer%   rT   Ncpuz:Pin memory is only supported for CPU tensors. Got device: z and pin_memory: .)r   r%   r/   r0   r1   r4   warningscatch_warningssimplefilterr2   r6   rT   rU   )rS   r%   rT   rU   results        r   convert_ndarray_to_torch_tensorr_      sF   $ 4G<<G }RZ''-
 
 	
 
	 	"	" F Fh'''fEEEF F F F F F F F F F F F F F F  %}!U***I!=I I;EI I I +** ""$$Ms   
,BB	Bndarraysdtypesc                 |   t          | t          j                  r|t          t                    rSt	                    dk    rt          d           t          t                                                              t          |           }n"fd| 
                                D             }|S )a,  Convert a NumPy ndarray batch to a Torch Tensor batch.

    Args:
        ndarray: A (dict of) NumPy ndarray(s) that we wish to convert to a Torch Tensor.
        dtype: A (dict of) Torch dtype(s) for the created tensor; if None, the dtype
            will be inferred from the NumPy ndarray data.
        device: The device on which the tensor(s) should be placed; if None, the Torch
            tensor(s) will be constructed on the CPU.
        pin_memory: Whether to pin the memory of the created tensors.

    Returns: A (dict of) Torch Tensor(s).
    r:   z[When constructing a single-tensor batch, only a single dtype should be given, instead got: r%   rT   rU   c           
      x    i | ]6\  }}|t          |t          t                    r|         n           7S )rc   )r_   r)   dict)r#   col_namecol_ndarrayrT   ra   rU   s      r   
<dictcomp>z?convert_ndarray_batch_to_torch_tensor_batch.<locals>.<dictcomp>   sf     
 
 
 &+ 5*4VT*B*BNfX&&%	  
 
 
r   )r)   r0   rS   re   r@   r>   nextiterr<   r_   items)r`   ra   rT   rU   rC   s    ``` r   +convert_ndarray_batch_to_torch_tensor_batchrl      s    $ (BJ'' 
fd## 	16{{a >5;> >   $v}}//00F/!	
 
 

 
 
 
 
 
 *2)9)9
 
 
 Lr   saved_modelmodel_definitionc                     t          | t          j        j                  r| S t          | t                    r(|st          d          |                    |            |S t          dt          |            d          )zLoads a PyTorch model from the provided ``saved_model``.

    ``model_definition`` is only used when ``saved_model`` is
    a torch state dict, which will be loaded into ``model_definition``.
    Otherwise, ``model_definition`` is discarded.
    zYAttempting to load torch model from a state_dict, but no `model_definition` was provided.zSaved model is of type zt. The model saved in the checkpoint is expected to be of type `torch.nn.Module`, or a model state dict of type dict.)r)   r2   nnModulere   r>   load_state_dictr/   )rm   rn   s     r   load_torch_modelrs      s     +ux// 
	K	&	& 
 	  
 	((555(d;&7&7 ( ( (
 
 	
r   c                 L   t          | t          j                  rdS t          | t                    r?|                                 D ])\  }}t          |          r dS t          |          r dS *n3t          | t          t          f          r| D ]}t          |          r dS dS )NTF)r)   r2   Tensorre   rk   contains_tensorrM   rN   )objkvs      r   rv   rv     s    #u|$$ t	C		 	IIKK 	 	DAqq!! ttq!! tt	
 
C$	'	'  	 	Aq!! tt5r   
state_dictprefixc                    d}| D ]^}|                     |          rG|t          |          d         }|s|                                 } d}|                     |          | |<   _d| v rm| d                                         | d<   | d         }|D ]E}t          |          dk    r|t          |          d         }|                    |          ||<   F| S )aS  Strip the prefix in state_dict, if any and return a new dict.

    Adapted from https://github.com/pytorch/pytorch/blob/c18da597e0bb1c1aecc97c77a73fed1849057fa4/torch/nn/modules/utils.py
    The original method modified the dict in-place.

    Args:
        state_dict: a state-dict to be loaded to the model.
        prefix: prefix.

    FNT	_metadatar   )
startswithr@   copypop)rz   r{   copiedkeynewkeymetadatas         r   4consume_prefix_in_state_dict_if_present_not_in_placer   '  s     F 	5 	5>>&!! 	5V'F  (__..
!+!4!4Jvj  ",["9">">"@"@
;k* 	1 	1C3xx1}}V'F'||C00HVr   c                 L    fd|                                  D             S )a~  Convert a dict mapping column names to lists of ndarrays to Torch Tensors.

    Args:
        ndarrays: A dict mapping column names to lists of ndarrays that we wish to convert
            to Torch Tensors.
        dtypes: A (dict of) Torch dtype(s) for the created tensors; if None, the dtype
            will be inferred from the NumPy ndarray data.
        device: The device on which the tensor(s) should be placed; if None, the Torch
            tensor(s) will be constructed on the CPU.
        pin_memory: Whether to pin the memory of the created tensors.

    Returns:
        A dict mapping column names to lists of Tensors.
    c                 <    i | ]\  }fd |D             S )c           	      p    g | ]2}t          |t          t                    r         n           3S ))ra   rT   rU   rl   r)   re   )r#   rS   rf   rT   ra   rU   s     r   r'   zHconvert_ndarray_list_to_torch_tensor_list.<locals>.<dictcomp>.<listcomp>c  s_     
 
 
  8+5fd+C+COvh''%	  
 
 
r   r   )r#   col_ndarraysrf   rT   ra   rU   s     @r   rh   z=convert_ndarray_list_to_torch_tensor_list.<locals>.<dictcomp>b  sg        #Hl 	 
 
 
 
 
 
 
 (
 
 
  r   )rk   )r`   ra   rT   rU   s    ```r   )convert_ndarray_list_to_torch_tensor_listr   N  sF    (      '/nn&6&6   r   rC   combine_chunks
threadpoolc                    ddl m} ddlm} |r ||                               d          }t          |          }|dk    r||zdt          t          t          j	        f         dt          t          t          j        f         ffd	}	|                    |	|                                          }
t          |
          S fd
|                                D             S |                    |           }t!          d |                                D                       }t          |          }|dk    r|dt          t          t$          t          j	        f         dt          t          t$          t          j        f         ffd}d |                                D             }t'          |                    ||                    }d |                                D             }|D ]\  }}}|||         |<   |S t)          |          S )a  Convert PyArrow batch to PyTorch tensors.

    Args:
        batch: PyArrow batch to convert
        dtypes: A (dict of) Torch dtype(s) for the created tensors; if None, the dtype
            will be inferred from the NumPy ndarray data.
        combine_chunks: If True, combine chunks in Arrow batch before converting to
            tensors.
        pin_memory: Whether to pin the memory of the created tensors.
        threadpool: Optional ThreadPoolExecutor for parallel processing. If provided,
            columns/arrays will be processed in parallel. If None, processing is
            sequential.

    Returns:
        When combine_chunks=True: A dictionary of column name to single tensor.
        When combine_chunks=False: A dictionary of column name to list of tensors.
    r   )ArrowBlockAccessor)transform_pyarrownumpyr:   Ncol_name_col_arrayr   c                 p    | \  }}|t          |t          t                    r|         n          fS Nra   rU   r   )r   rf   	col_arrayra   rU   s      r   process_columnz.arrow_batch_to_tensors.<locals>.process_column  sP     '9#)!L/9&$/G/GS6(++V)" " "  r   c           
      v    i | ]5\  }}|t          |t          t                    r|         n           6S )r   r   )r#   rf   r   ra   rU   s      r   rh   z*arrow_batch_to_tensors.<locals>.<dictcomp>  sc        (Hi E/9&$/G/GS6(++V)    r   c              3   4   K   | ]}t          |          V  d S Nr@   )r#   arrayss     r   	<genexpr>z)arrow_batch_to_tensors.<locals>.<genexpr>  s(      II63v;;IIIIIIr   
array_itemc           	      t    | \  }}}||t          |t          t                    r|         n          fS r   r   )r   rf   array_indexarrayra   rU   s       r   process_arrayz-arrow_batch_to_tensors.<locals>.process_array  sV     0:,+u?3=fd3K3KWvh//QW#-   r   c                 H    g | ]\  }}t          |          D ]
\  }}|||f S r   )	enumerate)r#   rf   r   idxr   s        r   r'   z*arrow_batch_to_tensors.<locals>.<listcomp>  sV       $Hf"+F"3"3  C 3&   r   c                 <    i | ]\  }}|d gt          |          z  S r   r   )r#   rf   r   s      r   rh   z*arrow_batch_to_tensors.<locals>.<dictcomp>  s;     5 5 5$Hf 4&3v;;.5 5 5r   r   )ray.data._internal.arrow_blockr   ray.data._internal.arrow_opsr   to_batch_formatr@   r	   strr0   rS   r2   ru   maprk   re   table_to_numpy_dict_chunkedsumr<   intrM   r   )rC   ra   r   rU   r   r   r   numpy_batchnum_columnsr   processed_cols
numpy_listtotal_arraysr   array_itemsprocessed_arraysr^   rf   r   tensors    ` `                r   arrow_batch_to_tensorsr   p  s   0 BAAAAA>>>>>> Q((//??HH+&&??z5$)#rz/$:sEL()       (^^NK<M<M<O<OPPN'''     ,7+<+<+>+>    'BB
 

 IIZ5F5F5H5HIIIII*oo!
 6!#sBJ"67sC-.       (2(8(8(:(:  K  $JNN=+$N$NOO5 5(2(8(8(:(:5 5 5F 2B 7 7-+v06x --M =%   r   tensor_sequencenon_blockingc                 N   | sJ d|              t          d | D                       s$J dt          d | D                       z               t          |           dk    r-|#| d         j        t	          j        |          k    r| d         S | d         j        t          fd| D                       sJ d	 d
d | D                          | d         j        dd         t          fd| D                       sJ d d
d | D                          | d         }|j        }|j        dd         }t          d | D                       }t	          j        |g|R ||          }d}| D ]3}	||	j        d         z   }
|||
         	                    |	|           |
}4|S )aq  Stack sequence of tensors into a contiguous GPU tensor.

    Args:
        tensor_sequence: Sequence of tensors to stack
        device: The device to move tensors to. If None, tensors are not moved.
        non_blocking: If True, perform device transfer without forcing a
            synchronization.

    Returns:
        A contiguous tensor on the target device
    z2Cannot stack empty sequence of tensors. Received: c              3   J   K   | ]}t          |t          j                  V  d S r   )r)   r2   ru   r#   rF   s     r   r   z+concat_tensors_to_device.<locals>.<genexpr>  s?        ()
1el##     r   z5All items must be torch.Tensor. Found invalid types: c                 `    g | ]+}t          |t          j                  t          |          ,S r   )r)   r2   ru   r/   r   s     r   r'   z,concat_tensors_to_device.<locals>.<listcomp>  s/    MMMQAu|1L1LMaMMMr   r:   Nr   c              3   .   K   | ]}|j         k    V  d S r   r(   )r#   rF   first_dtypes     r   r   z+concat_tensors_to_device.<locals>.<genexpr>  s*      ??!qw+%??????r   z0All tensors must have the same dtype. Expected: z, got: c                     g | ]	}|j         
S r   r(   r   s     r   r'   z,concat_tensors_to_device.<locals>.<listcomp>  s    )K)K)Ka!')K)K)Kr   c              3   >   K   | ]}|j         d d         k    V  dS r:   Nshape)r#   rF   first_shapes     r   r   z+concat_tensors_to_device.<locals>.<genexpr>  s2      CCaqwqrr{k)CCCCCCr   z4All tensors must have the same shape[1:]. Expected: c                 ,    g | ]}|j         d d         S r   r   r   s     r   r'   z,concat_tensors_to_device.<locals>.<listcomp>
  s"    )O)O)O!!'!""+)O)O)Or   c              3   0   K   | ]}|j         d          V  dS )r   Nr   r   s     r   r   z+concat_tensors_to_device.<locals>.<genexpr>  s(      99AQWQZ999999r   rX   r   )
allr   r@   rT   r2   r%   r   r   emptycopy_)r   rT   r   firstr%   
shape_tail
total_rowsr^   	row_startrF   row_endr   r   s              @@r   concat_tensors_to_devicer     s   & 	N NMOMMN N   -<      >MM/MMMB B    ?q  /!,3u|F7K7KKKq!!!!$*K?????????  	N 	N 	N)K)K?)K)K)K	N 	N ?
 "!$*122.KCCCC?CCCCC  	R 	R 	R)O)O)O)O)O	R 	R C
 AEKEQRRJ9999999J [*2z22%OOOFI  agaj(y !'''EEE		Mr   c                    t          |           j        }t          | t          t          f          r5d                    t          d | D                                 }| d| d}n^t          | t                    rGd                    t          d |                                 D                                 }| d| d}n|}|S )a  Get a string representation of the possibly nested type of the batch.

    >>> import torch
    >>> _get_type_str([1, 2, "???"])
    'list[int | str]'
    >>> _get_type_str({"a": [1, 2, 3], "b": 4})
    'dict[str, int | list[int]]'
    >>> _get_type_str({"a": torch.tensor(1), "b": [torch.tensor(2)]})
    'dict[str, Tensor | list[Tensor]]'
    >>> _get_type_str({"a": torch.tensor(1), "b": {"c": torch.tensor(2)}})
    'dict[str, Tensor | dict[str, Tensor]]'
    z | c                 ,    h | ]}t          |          S r   _get_type_strr#   ry   s     r   	<setcomp>z _get_type_str.<locals>.<setcomp>-  s     &G&G&GA}Q'7'7&G&G&Gr   []c                 ,    h | ]}t          |          S r   r   r   s     r   r   z _get_type_str.<locals>.<setcomp>0  s     &P&P&PA}Q'7'7&P&P&Pr   z[str, )	r/   __name__r)   rM   rN   joinsortedre   r<   )rC   	curr_type	val_typesinvalid_type_strs       r   r   r     s     U$I%$'' %JJv&G&G&G&G&GHHII	'66)666	E4	 	  %JJv&P&P&P&P&PQQRR	';;y;;;$r   c                 *   | S t          |           r|                               S t          |           r% t          |           fd| D                       S t	          |           r% t          |           fd| D                       S t          |           r!fd|                                 D             S t          |           r!fd|                                 D             S t          dt          |            d          )	a  Move tensors to the specified device.

    Concatenate nested lists/tuples of tensors along the first (batch) dimension.
    For example, for the input
    ((feature_0_chunk_0,), (feature_1_chunk_0, feature_1_chunk_1))
    the output will be (feature_0_chunk_0, feature_1_chunk_0+1)
    where each feature is concatenated along the batch dimension.

    Args:
        batch: A tensor or collection of tensors to move to device. Can be:
            - A single tensor
            - A sequence of tensors
            - A sequence of sequences of tensors. The inner sequence of tensors is
              combined during GPU transfer.
            - A mapping (e.g., dict) of keys to tensors or sequences of tensors. The
              sequence of tensors is combined during GPU transfer.
        device: The device to move tensors to. If None, tensors are not moved.
        non_blocking: If True, perform device transfer without forcing a
            synchronization.

    Returns:
        The input tensors moved to the specified device
    Nr   c                 >    g | ]}|                                S r   tor#   rF   rT   r   s     r   r'   z*move_tensors_to_device.<locals>.<listcomp>Z  s)    SSSADDlDCCSSSr   c                 2    g | ]}t          |          S r   r   r   s     r   r'   z*move_tensors_to_device.<locals>.<listcomp>]  s&    NNN1%a>>NNNr   c                 F    i | ]\  }}||                                S r   r   )r#   rx   rF   rT   r   s      r   rh   z*move_tensors_to_device.<locals>.<dictcomp>`  s/    UUUtq!144\4::UUUr   c                 :    i | ]\  }}|t          |          S r   r   )r#   rx   ry   rT   r   s      r   rh   z*move_tensors_to_device.<locals>.<dictcomp>b  s<     
 
 
1 '6<@@
 
 
r   zInvalid input type: z.
Expected one of the following: torch.Tensor, List/Tuple[torch.Tensor], Dict[str, torch.Tensor], Mapping[str, List/Tuple[torch.Tensor]])
r   r   r   r/   r   r   rk   r   r>   r   )rC   rT   r   s    ``r   move_tensors_to_devicer   7  si   : ~% 
xx\x:::	U	#	# 
tE{{SSSSSUSSSTTT	#E	*	* 
tE{{NNNNNNNN
 
 	
 
E	"	" 
UUUUUu{{}}UUUU	$U	+	+ 

 
 
 
 

 
 
 	

 5=#7#7 5 5 5
 
 	
r   )NNT)NNFr   )NFFN)7r[   concurrent.futuresr   typingr   r   r   r   r   r	   r
   r   r0   pandasr*   pyarrowr2   ray._private.ray_constantsr    ray.air._internal.device_managerr   "ray.air.util.data_batch_conversionr   ray.data.collate_fnr   r   r   r   r   r   r   $DEFAULT_TENSOR_NON_BLOCKING_TRANSFERrT   r   	DataFramer   r%   boolru   rR   rS   r_   rl   rp   rq   rs   rv   r   r   Tabler   no_gradr   r   r   r   r   r   <module>r      s    1 1 1 1 1 1 D D D D D D D D D D D D D D D D D D           / / / / / / P P P P P P T T T T T T                  (0x2( ( $?T%,' ? ? ? ? <@EI	jL jLjLeDItDI678jL E%+tEK/@"@ABjL 	jL
 5<el++,jL jL jL jL^ $(37	. .Z.EK . U3./0. 	.
 \. . . .f DH37	- -BJS"*_ 556-U5;S%+-=(>>?@- U3./0- 	-
 5<c5</001- - - -d 37
 
ux,-
ux/
 X_
 
 
 
<  &$S#X$(+$	#s(^$ $ $ $R DH37	 3RZ(()U5;S%+-=(>>?@ U3./0 	
 
#tEL!
!"   H DH /3l l=lU5;S%+-=(>>?@l l 	l
 +,l 4U\!"Dd5<.@)@$AABl l l l^  48=; ;el+;U3./0; ; \	; ; ; ;|     2  48=6
 6
6
U3./06
 6
 	6
 6
 6
 6
 6
 6
r   