
    7h&e                        S SK r S SKrS SKrS SKrS SKJrJr  S SKJrJ	r	  S SK
JrJrJrJrJrJrJr  S SKrS SKrS SKJr  S SKJr  S SKJrJ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$J%r%  \" S5      r&\" S5      r'\(\RR                  S4   r*\(\+\RX                     \+\RR                     4   r-\R\                  R_                  \0S5      r1S SKJ2r2J3r3  \(       a  S SK4J5r5J6r6  S\RR                  S\\RR                     4S jr7S\RR                  S\\RR                     4S jr8S\RR                  S\9\RR                  \:4   S\\RR                     4S jr;\ Rx                  " SS9 " S S5      5       r=\SS S!\RR                  S"\RR                  S#\S   S\\(\-\-4      4
S$ j5       r>\ SBSS S!\RR                  S"\RR                  S#\S%   S\(\-\-4   4
S& jj5       r> SBSS S!\RR                  S"\RR                  S#\?S\\(\-\-4      4
S' jjr> " S( S)5      r@\R                  S*:  a  \R                  " \CSS+9rDOS,\\&   S-\\'   S\	\(\&\'4      4S. jrDS/\+\RX                     S0\+\RX                     S1\+\RX                     S2\+\RX                     S3\+\+\RR                        S4\+\+\\+\RR                     /\RR                  4         S\9\RX                  \RR                  4   4S5 jrES6\S   S\\=   4S7 jrFS8\RR                  S\9\RX                  \:4   S\:4S9 jrGS:\\RR                  \:4   S\:4S; jrH\ Rx                  " SS9 " S< S=5      5       rI\ Rx                  " SS9 " S> S?5      5       rJS@\S   S\\J   4SA jrKg)C    N)Counterdefaultdict)IterableIterator)CallableLiteralOptionaloverloadTYPE_CHECKINGTypeVarUnion)config)index_vars_no_squeeze)sympy_product
sympy_subs)
OrderedSet)Identity)	try_solve)symbol_is_typeSymT   VTU.loop_tiling)FloorDivModularIndexingFusedSchedulerNodeSchedulerNodeexprreturnc                    U R                  5       (       a  g[        U [        5      (       a  g[        U R                  5      S:X  d   e[        [        U R                  5      5      n[        U [        5      (       a<  [        [        R                  " U R                  S   U R                  S   5      U5      nO![        [        R                  " U S5      U5      nU(       a  US   R                  5       (       d  gUS   $ )zk
Given an expr with a single free symbol, solve for a constant relation that would make
this expression 0.
Nr   r      )is_constant
isinstancer   lenfree_symbolsnextiterr   r   sympyEqargs)r"   free_symbolouts      V/var/www/fran/franai/venv/lib/python3.13/site-packages/torch/_inductor/tiling_utils.pysolve_for_zeror2   '   s    
 	D(	#	#t  !Q&&&tD--./K$((1tyy|<kJq);7c!f((**q6M    c           	      l  ^ [        U R                  5      S:X  a  g[        [        U R                  5      5      mS[        R
                  S[        [        R
                     4U4S jjnU R                  [        5      (       d"  U R                  [        5      (       d  U" U 5      $ / n/ n[        R                  R                  U 5       H  n[        U[        R                  5      (       aZ  SnUR                   H=  n[        U5      nUc  M  UR!                  5       (       d   eSnUR#                  U5        M?     U(       d    gM|  UR#                  U5        M     U(       d  g[%        U5      n SS[        R
                  S	[        R
                  S
[        [        R
                     S[        R
                  4S jjn	UR'                  [        U	5      R'                  [        U	5      n
U" U
5      nU(       a  [)        UTU05      S:X  d  gUR#                  U5        [        [+        U5      5      S:X  a  US   $ g)a  
Giving an expr with a single free symbol, try to find a tiling that would
make the expression coalesced with respect to that symbol.

Tiling an expression `x` by `y` means that the expression will now be indexed
by both the original (x) and by (x * y). So we are looking for a
multiplicative factor that will make ((x + 1) * y) - (x * y) == 1.

To simplify things for sympy, we'll try just x * y == 1, check x(1) and x(0).
r   Nr"   r#   c                 0  > U R                  [        5      (       d  U R                  [        5      (       a   e[        U R                  5      S:w  a  g [        [        R                  " U S5      T5      nU(       a  US   R                  5       (       d  g US   $ )Nr   )	hasr   r   r(   r)   r   r,   r-   r&   )r"   r0   r/   s     r1   _solve_simple_expr,solve_for_tiling.<locals>._solve_simple_exprM   st    88O,,TXXh5G5GGGt  !Q&q);7#a&,,..1vr3   FTxyzc                 
    X-  $ N )r9   r:   r;   s      r1   indexing_div_rep*solve_for_tiling.<locals>.indexing_div_rep{   s    
 ur3   r   r=   )r(   r)   r*   r+   r,   Exprr	   r6   r   r   Add	make_argsr'   Mulr.   r2   r&   appendsumreplacer   r   )r"   r7   required_valueseq_1_expressionsargseenmul_argr0   	eq_1_exprr?   eq_1_expr_simplifiedr/   s              @r1   solve_for_tilingrO   <   s    4"tD--./K 0D  88O$$TXXh-?-?!$''O
 yy""4(c599%%D 88$W-;((((&&s+ $   ##C(% )( $%I
 #':::: EJJ 
	 %,,_>NOWW" 1
2Cz)k3-?@QF3
:o&'1,q!!r3   index
var_rangesc                    [         R                  R                  U 5      nU H  nX2;   d  M
  Us  $    0 nU R                   H  nX1;   a  SXC'   M  [	        U5      XC'   M     [        X5      nUR                  5        H9  nSXC'    [        X5      nXe-
  S:X  a  SXC'   [        X5      U-
  S:X  a  Us  $ SXC'   M;     g! [         a    [        R                  SX5         Ma  f = f)z3
Try to find the symbol which coalesces this index
r   r   zzero division error %s %sr%   N)
r,   rB   rC   r)   get_hintr   keysZeroDivisionErrorloop_tiling_loginfo)rP   rQ   top_level_termsv	variables
zero_indexnew_vals          r1   find_coalesced_varr]      s     ii))%0OH 
 *,I?IL#A;IL	   E-J__		 2G 1$IL 5,w61<	   ! 	  !<eO	s   B88 CCT)frozenc                       \ rS rSr% Sr\\R                     \S'   \\R                     \S'   \	\R                  \\   4   \S'   \	\R                  \\   4   \S'   \	\R                  \4   \S'   Srg	)
FusedNormalizedReadsWrites   zG
Normalized reads and writes for nodes in the same FusedSchedulerNode.

index_varsreduce_varsreadswritesrQ   r>   N)__name__
__module____qualname____firstlineno____doc__r   r,   Symbol__annotations__dictrA   strint__static_attributes__r>   r3   r1   r`   r`      sk     5<<((ELL))

JsO+,,Z_,--U\\3&''r3   r`   nr!   pointwise_numel	red_numelnone_if_not_divisiblec                     g r=   r>   rq   rr   rs   rt   s       r1   get_pw_red_splitsrw      s     58r3   Fc                     g r=   r>   rv   s       r1   rw   rw      s     +.r3   c                    U R                  5       (       d&  [        U R                  R                  S   5      U:X  a^  U R                  R                  U R                  R                  S   4U R                  R
                  U R                  R                  S   44$ [        U R                  R                  S   5      X-  :X  d   e[        U R                  R                  S   5      S-
  nSnUS:  a1  XPR                  R                  S   U   -  nXR:X  a  OUS-  nUS:  a  M1  US:  ap  U R                  R                  S   SU nU R                  R                  SU nU R                  R                  S   US  nU R                  R                  US  n	Xv4X44$ U(       a  g U R                  R                  U R                  R                  S   4U R                  R
                  U R                  R                  S   44$ )Nr   r   )is_reductionr   _bodysizes	iter_varsrc   r(   )
rq   rr   rs   rt   iprod	pw_splitsr}   
red_splitsred_varss
             r1   rw   rw      s    	~~=q)9:oMWWa 01WW  !''--"23
 	

 q)*o.IIIIAGGMM!!AD
q&a ##	Q	 q& 	AvGGMM!$Qq)	GG%%a*	WW]]1%ab)
77$$QR(%'=== WWa 01WW  !''--"23
 	
r3   c            	       j    \ rS rSrSrS\S   4S jrS\\\4   4S jr	S\S	\S\
\\\4      4S
 jrSrg)NodeSplitGetter   zW
Finds a Pointwise, Reduction Split that compatible with all nodes in a SchedulerNode.
noder   c                    Xl         UR                  S   S   U l        UR                  S   S   U l        [	        [
        5      U l        SU l        [        5       U l        UR                  S   n[        UR                  5       5       GHY  n[        U[        R                  R                  R                  5      (       d  M9  [!        X0R                  U R                  SS9nUc1  U R                  R#                  UR$                  R&                  5        M  Uu  u  pVu  pW[        R                  R(                  R*                  R,                  R/                  X&U4U R                  5      u  pgU R                  [1        U5         R#                  [3        U5      5        US:w  a  [5        U5      4U l        [3        U5      [3        U5      4nU R                  R#                  U5        GM\     [        5       U l        g )Nr   r   r>   T)rt   )r   grouprr   rs   r   r   pw_split_optionsreduction_splitall_node_sizesreversed	get_nodesr'   torch	_inductor	schedulerr!   rw   addr{   r|   codegensimd
SIMDKernelprepare_split_iteration_lengthsr(   tupler   seen_pw_splits)	selfr   fused_grouprq   maybe_splits_n_pw_splitsn_red_splitsn_sizes	            r1   __init__NodeSplitGetter.__init__  s    	+/::a=+;%)ZZ]1%5>I*>U&(?I|jjm$..*+Aa!:!:!H!HII
 -''tL ###''62>/Q/q '',,77WW|!<dnn &K !!#k"2377k8JK r!(5l(C'E$K(%*=>F##F+I ,L 2<r3   r#   c                    [        U R                  5      S:X  a  [        [        U R                  5      5      $ [	        U R
                  R                  5       5      n[        USS5       H  nU R
                  U    H+  nU R                  X0R                  5      =n(       d  M'  Us  s  $    U R
                  U    Hp  n[        [        U5      S-
  5       HR  n[        USU [        X5US-    5      4-   X5S-   S -   5      nU R
                  [        U5         R                  U5        MT     Mr     M     U R                  4U R                  44$ )z9
Get a compatible pointwise, reduction split of the node
r   r   r%   N)r(   r   r*   r+   maxr   rT   range	try_splitr   r   r   r   rr   rs   )r   max_pw_splitpw_split_lenpw_splitr0   r~   	new_splits          r1   get_node_splitsNodeSplitGetter.get_node_splits;  s8   
 t""#q(T001224005578!,26L 11,?..3G3GHH3HJ @
 !11,?s8}q01A % 1(a!e)<=?@"q57+,!I
 ))#i.9==iH 2 @ 7  %%'$..):;;r3   pwredc                    SSK JnJn  XR                  ;   a  gU R                  R	                  U5        U R
                   H  u  pV X-   nXV4nUR                  Xx5      u  p[        U
5      S:X  d   eU	S[        U5       n[        [        R                  R                  U5      5      nX:w  d  Mn  U R                  X5      =n(       d  M  Us  $    X4$ ! U a       gf = f)z[
See if this split is compatible, and potentially returning a longer split
than the input.
r   )	CantSplitr   Nr%   )torch._inductor.codegen.simdr   r   r   r   r   _split_iteration_rangesr(   r   	itertoolschainfrom_iterabler   )r   r   r   r   r   n_pwn_redgroupslengthssplitsgetterspw_group_splitsflattened_pw_splitsr0   s                 r1   r   NodeSplitGetter.try_splitV  s     	G$$$#..KD-","D"DV"U w<1$$$$Ys2w/O
 #(	(E(Eo(V"W"(..)<BB3BJ# /& w  s   CCC)r   r   rr   r   rs   r   r   N)rf   rg   rh   ri   rj   r   r   r   Splitr   r	   r   rp   r>   r3   r1   r   r      sX    4>9:4>l<ue|!4 <6E  (5;N2O r3   r   )   
   )strictit1it2c                     [        U 5      [        U5      :w  a#  [        S[        U 5       S[        U5       35      e[        X5      $ )z@
Zip two iterables, raising ValueError if their lengths differ.
zLengths differ: z != )r(   
ValueErrorzip)r   r   s     r1   	zip_equalr   }  s?     s8s3x/Czc#hZHII3}r3   r}   r   norm_pw_varsnorm_red_vars
new_rangesreturn_getters_groupsc           	         [        S U 5       5      n[        R                  " SU 35      nSn[        U 5      S:X  a  [        U5      S:X  a  0 $ [        U5      [        X#-   5      :X  d   e/ n	U H*  n
U	R	                  U
 Vs/ s H
  o" U5      PM     sn5        M,     0 n[        [        XU45      5       Hj  u  nu  p[        U
5      [        U5      :w  a  US:X  d   e[        U5      S:X  d   eM;  UR                  [        X5       VVs0 s H  u  pX_M	     snn5        Ml     Sn0 n[        XBU-   5       Hp  u  nn/ n[        [        U5      5       H  nUR	                  Xx   5        US-  nM     Sn[        [        U5      S-
  SS5       H  nUU-  UUU   '   UU   U-  nM     Mr     UR                  5        VVs0 s H  u  nnU[        UU5      _M     snn$ s  snf s  snnf s  snnf )zBMaps original variables to expressions using normalized variables.c              3   8   #    U  H  n[        U5      v   M     g 7fr=   )r(   ).0ss     r1   	<genexpr>$apply_var_mapping.<locals>.<genexpr>  s     .:a3q66:s   zv_0:r   r   r   )rF   r,   symbolsr(   rE   	enumerater   updater   r   itemsr   )r}   r   r   r   r   r   num_vars	flat_varscountapply_groupsr   giter_vars_to_flat_varsr~   	var_grouprY   flat_vars_to_new_vars	new_rangenew_var
range_varsr   ks                         r1   apply_var_mappingr     s   . .:..HXJ/0IE
9~s8}1	z?c,">????L&595aQy\59: '  !*,X!68"E
 u:Y'6M6y>Q&&&%%E8M&N8Mqt8M&NO" E'
=4PQ	7
s9~&Ai./QJE ' s9~)2r2A3:T>!*Q-0Q<$&D 3 R +0022DAq 	
:a.//2 9 : 'Os    G
G;G$r   c           
      l	  ^) [        [        5      n[        [        5      nU R                  5       nU R                  5       n[        5       n[        5       m)U HU  n[        R
                  R                  R                  Xd5      (       a  T)R                  U5        MD  UR                  U5        MW     [        U)4S jU R                  R                   5       5      nU R                  S   S   nU R                  S   S   n	[        S X4 5       5      (       a  g[        U 5      R                  5       u  p[        XSS9u  u  pnU n [!        U R#                  5       5       GH|  n[%        U[&        R(                  R                  R*                  5      (       d  M9  UR,                  nUR.                  (       a    g[        [        5      n[        [        5      nU H/  nUR1                  U5       H  nUU   R                  U5        M     M1     U H/  nUR3                  U5       H  nUU   R                  U5        M     M1     U(       d	  U(       d  M  [5        XU	5      u  u  nnu  nnX-   nUU4n[&        R(                  R6                  R8                  R:                  R=                  UUU	5      n[&        R(                  R6                  R8                  R:                  R?                  UU5      u  nn[A        UUUUUU5      nS[B        RD                  S	[B        RD                  4S
 jnURG                  5        V V!s0 s H  u  n n![I        U" U 5      U5      U!_M     n"n n!URG                  5        V#V!s0 s H  u  n#n![I        U" U#5      U5      U!_M     n$n#n!U"RG                  5        H  u  nn%UU==   U%-  ss'   M     U$RG                  5        H  u  nn%UU==   U%-  ss'   M     GM     URG                  5        V&V!s0 s H1  u  n&n![        R
                  RJ                  RM                  U&U5      U!_M3     nn&n!URG                  5        V'V!s0 s H1  u  n'n![        R
                  RJ                  RM                  U'U5      U!_M3     nn'n![O        UUUUU5      n([P        RS                  SU(5        U($ s  sn!n f s  sn!n#f s  sn!n&f s  sn!n'f )zjExtracts index variables, reduce variables, read/write expressions, and variable ranges from a fused node.c              3   ^   >#    U  H"  oR                   T;  d  M  UR                   v   M$     g 7fr=   )name)r   depremoved_bufferss     r1   r   1extract_normalized_read_writes.<locals>.<genexpr>  s$      2Shho6U2s   --r   r   c              3      #    U  H;  n[        U[        R                  5      =(       a    UR                  5       (       + v   M=     g 7fr=   )r'   r,   rA   r&   )r   vars     r1   r   r     s4      /C 
C	$	>S__->)>	>/s   AANrq   )prefixr"   r#   c                 0    U R                  [        S 5      $ )Nc                     U $ r=   r>   )r9   s    r1   <lambda>Iextract_normalized_read_writes.<locals>.remove_identity.<locals>.<lambda>'  s    Ar3   )rG   r   )r"   s    r1   remove_identity7extract_normalized_read_writes.<locals>.remove_identity&  s    <<+66r3   zNormalized Fused reads: %s)*r   r   get_buffer_namesget_operation_namesr   graphr   $can_buffer_be_removed_through_fusionr   read_writesrd   r   anyr   r   r   listr   r'   r   r   r!   r{   indirect_varsget_all_read_exprget_all_write_exprrw   r   r   r   r   r   r   r,   rA   r   r   sizevarssimplify_with_rangesr`   rV   rW   )*r   rd   re   all_output_namesop_namesoutputsbuf_nameinputsrr   rs   r   r   r   r   rangesrq   bodyn_readsn_writesinpr"   r0   r}   r   r   r   r   r   r   r   var_mapr   readrY   n_reads_newwriten_writes_new	buf_namesrw	fused_outr   s*                                            @r1   extract_normalized_read_writesr    sg    0;:/FE0;J0GF,,.'')H)|G'1|O$77AA(UU)KK!	 %   ,,22 F #'**Q-"2O JJqM!,I  #/   +D1AACI -Bc-)!\6 D$.."#!U__66DDEEww 5@5L6A*6M C..s3!!#& 4  C//4""3' 5  x=N	>
: K":8\ '/OO##((33SS 	 OO##((33KK 	*
)
 $!
	7%** 	7 	7 JQ
IXgdAJt,g69 	 

 %NN,
,q u-w7:, 	 

  +002OD)$K9$K  3  ,113OD)4LI%L  4I $P INHU1--a8!; 
  IOHV1--a8!;   +I 5yA;

s   / R% R$.8R*<8R0addrc                 @   / nU R                    HL  nUR                  US5      n[        U[        R                  5      (       a  M6  Uc  M;  UR                  U5        MN     SSKJn  UR                  R                  R                  [        U5      [        R                  S9$ )z.
Score addr according to its approximate size
Nr   r   fallback)r)   getr   r   INDIRECTrE   virtualizedr   r   r   atomically_apply_size_hintr   r   unbacked_symint_fallback)r  rQ   	var_sizesrY   v_sizer   s         r1   	get_scorer  I  s     I4(a//F4FV$	 
 7766i 6+J+J 7  r3   rY   c                     [        U [        5      (       a  U $ [        R                  R                  R                  U [        R                  S9$ )Nr  )r'   ro   r   r   r   	size_hintr   r  )rY   s    r1   rS   rS   \  s:    !Sww))!f6U6U)VVr3   c                   L    \ rS rSr% Sr\R                  \S'   \\S'   \\S'   Sr	g)	VarTilingic  ze
Tiling of a var by `tiling_factor` that yields additional coalesced mem accesses by `benefit_score`
r   tiling_factorscorer>   N)
rf   rg   rh   ri   rj   r,   rk   rl   ro   rp   r>   r3   r1   r!  r!  c  s     
Jr3   r!  c                   \    \ rS rSr% \\R                  \4   \S'   \	\S'   Sr
\\   \S'   Srg)CoalesceVarAnalysisin  coalesced_by_varnorm_read_writesNsuggested_splitr>   )rf   rg   rh   ri   rm   r,   rA   ro   rl   r`   r(  r	   r!  rp   r>   r3   r1   r%  r%  n  s,    
 5::s?++00+/OXi(/r3   r%  
fused_nodec           	      Z  ^ [        U 5      nUc  gUR                  nUR                  nUR                  n[	        5       n[	        5       n[
        R                  " S UR                  5        5       S UR                  5        5       5       H  u  nu  p[        UR                  UR                  R                  5       -
  5      n
U
(       a  MA  [        X5      nUS:X  a  MT  [        X5      nSnU	 HC  n[        R                  R                  U5      =n(       d  M+  XR                   R"                  -  nME     X(       a  SOS-  nU(       a  X\==   X-  -  ss'   M  Xh==   X-  -  ss'   M     U(       d	  [%        XQS9$ ['        [        5      nUR                  5        GH	  u  nn[(        R+                  UR                  S5      nUR                   H  nUU;  a  M  US:X  a  M  UU	 [-        UU5      nSUU'   [/        U5      nUb&  UR1                  5       (       a  UR2                  (       d  M]  [5        U5      n[        R                  R6                  R9                  UUU   5      (       d  M  Sm[;        U4S	 jUUU   U-  4 5       5      (       d  M  UU   U==   U-  ss'   M     GM     [=        U5      S:X  a	  [%        XQS9$ SnSnUR                  5        H.  u  nnUR                  5        H  u  nnUU:  d  M  UU4nUnM     M0     Uc	  [%        XQS9$ [%        UU[?        US   US   U5      S
9$ )a?  
Find variables that coalesce the reads and writes and score the total size.

If uncoalesced memory expressions are found, look for additionally tiling of variables
which will coalesce memory accesses.

For instance - for the following expression:

(32*p0) // 2048

Tiling p0 by 64 will make this expression coalesced.
Nc              3   *   #    U  H	  nS U4v   M     g7f)TNr>   r   items     r1   r   ,analyze_memory_coalescing.<locals>.<genexpr>  s     0-$$-   c              3   *   #    U  H	  nS U4v   M     g7f)FNr>   r,  s     r1   r   r.    s     2>4%>r/  r   r   r%   )r&  r'     c              3   x   >#    U  H/  n[         R                  R                  R                  TU5      v   M1     g 7fr=   )r   r   r   statically_known_lt)r   blockMIN_TILING_BLOCKs     r1   r   r.    s3      LE   445EuMMLs   7:)r&  r'  r(  ) r  rd   re   rQ   r   r   r   r   boolr)   rT   r  r]   r   r   try_get_bufferdtypeitemsizer%  r   rm   fromkeysr   rO   r&   
is_integerro   r   r3  allr(   r!  )r)  r'  rd   re   rQ   r&  uncoalesced_addrsis_readmemory_exprr  indirect_exprsizemaybe_coalesced_varbyte_multiplerr  buftiling_scoresuncoalesced_expr
addr_score	expr_subsrY   single_var_exprr"  best_tilingbest_tiling_scorer   tiling_countertile
tile_scorer5  s                                @r1   analyze_memory_coalescingrO  z  s3     6jA""E$$F!,,J07	/6y-6__0%++-026<<>2.))+
 $$'7'B'B'G'G'II
 1190I!Hgg,,X66s6))"4"44 "
 	w!A-1T5JJ1*d.CC*;.> "-
 	

 7B'6JM(9(?(?(A$*MM"2"?"?C	!..A
"Q!()99EOIaL,_=M%$0022$//.M77##77zRS}UU
  ! +Z]m-KL   !]+z9+A / )BH =Q"-
 	
 59K,224^ . 4 4 6D*--"Dk$.! !7  5 "-
 	
 ))!+a.+a.BST r3   )F)Ldataclasses	functoolsr   syscollectionsr   r   collections.abcr   r   typingr   r   r	   r
   r   r   r   r,   r   torch._inductorr   torch._inductor.dependenciesr   torch._inductor.utilsr   r   torch.utils._ordered_setr   torch.utils._sympy.functionsr   torch.utils._sympy.solver   torch.utils._sympy.symbolr   r   r  r   r   r   r   rA   r   r   rk   VarsAndRanges_logginggetArtifactLoggerrf   rV   r   r   torch._inductor.schedulerr    r!   r2   rO   rm   ro   r]   	dataclassr`   rw   r6  r   version_infopartialr   r   r   r  r  rS   r!  r%  rO  r>   r3   r1   <module>rd     sJ      
 , . W W W   " > ; / 1 . :  CLCL 	ejj#od5<<($uzz*::; ..228]K B K (< *V5:: V(5::*> Vr#::##'

C#8#ejj#L d#	( 	( $	( 
88ZZ8 zz8 #4=	8
 eM=0128 
8 

 -2	..ZZ. zz. #5>	.
 =-'(. 
. #(	#
#
ZZ#
 zz#
  	#

 eM=012#
Lu up w!!#d3Ix{ ! %1+9N @ELL!@5<< @ u||$@ %	@
 T%**%&@  XtEJJ/?.@%**.L%M NO@ 
%,,


"#@F}
5
6}()}@EJJ Ds1B,C  &Wejj#o& W3 W d#  $ d#0 0 $0B;<B!"Br3   