
    `i&e                        d dl Z d dlZd dlZd dlZd dlmZmZ d dlmZ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mZ d dlmZ d dlmZmZ d dlmZ d d	lmZ d d
lm Z  d dl!m"Z"m#Z# ddl$m%Z%  ed          Z& ed          Z'e(ej)        df         Z*e(e+ej,                 e+ej)                 f         Z-ej.        /                    e0d          Z1d dlm2Z2m3Z3 erd dl4m5Z5m6Z6 dej)        deej)                 fdZ7dej)        deej)                 fdZ8dej)        de9ej)        e:f         deej)                 fdZ; e j<        d           G d d                      Z=edd d!ej)        d"ej)        d#ed         dee(e-e-f                  f
d$            Z>e	 dBdd d!ej)        d"ej)        d#ed%         de(e-e-f         f
d&            Z>	 dBdd d!ej)        d"ej)        d#e?dee(e-e-f                  f
d'Z> G d( d)          Z@ejA        d*k    r ejB        eCd+          ZDn$d,ee&         d-ee'         de	e(e&e'f                  fd.ZDd/e+ej,                 d0e+ej,                 d1e+ej,                 d2e+ej,                 d3e+e+ej)                          d4e+e+ee+ej)                 gej)        f                           de9ej,        ej)        f         fd5ZEd6ed         dee=         fd7ZFd8ej)        de9ej,        e:f         de:fd9ZGd:eej)        e:f         de:fd;ZH e j<        d           G d< d=                      ZI e j<        d           G d> d?                      ZJd@ed         deeJ         fdAZKdS )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                    |                                  rdS t          | t                    rdS t          | j                  dk    sJ t          t          | j                            }t          | t                    r:t          t          j
        | j        d         | j        d                   |          }n#t          t          j
        | d          |          }|r|d                                          sdS |d         S )zw
    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      p/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/torch/_inductor/tiling_utils.pysolve_for_zeror2   '   s    
  t	D(	#	# tt !!Q&&&&tD-..//K$(( 81ty|<<kJJq));77 c!f((** tq6M    c           	      n   t          | j                  dk    rdS t          t          | j                            dt          j        dt          t          j                 ffd}|                     t                    s%|                     t                    s ||           S g }g }t          j
                            |           D ]}t          |t          j                  rQd}|j        D ]A}t          |          }||                                sJ d}|                    |           B|s dS m|                    |           |sdS t%          |          }	 ddt          j        d	t          j        d
t          t          j                 dt          j        fd}	|                    t          |	                              t          |	          }
 ||
          }|rt)          ||i          dk    sdS |                    |           t          t+          |                    dk    r|d         S dS )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                 6   |                      t                    s|                      t                    rJ t          | j                  dk    rd S t          t          j        | d                    }|r|d                                         sd S |d         S )Nr   )	hasr   r   r(   r)   r   r,   r-   r&   )r"   r0   r/   s     r1   _solve_simple_exprz,solve_for_tiling.<locals>._solve_simple_exprM   s    88O,,GTXXh5G5GGGGt !!Q&&4q));77 	#a&,,.. 	41vr3   FTxyzc                     | |z  S N )r8   r9   r:   s      r1   indexing_div_repz*solve_for_tiling.<locals>.indexing_div_rep{   s    
 1u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_tilingrM   <   s    4""ttD-..//K 0D       88O$$ (TXXh-?-? (!!$'''O
 y""4(( ) )c59%% 	)D 8 , ,$W--;(((((&&s++++ tt ##C(((( t$%%I
 #' :: EJ 
	    %,,_>NOOWW"  
1
2
2C z)k3-?@@QFFt3
:o&&''1,,q!!4r3   index
var_rangesc                    t           j                            |           }|D ]
}||v r|c S i }| j        D ]}||v rd||<   t	          |          ||<   t          | |          }|                                D ]s}d||<   	 t          | |          }n,# t          $ r t          	                    d| |           Y Aw xY w||z
  dk    r d||<   t          | |          |z
  dk    r|c S d||<   tdS )z;
    Try to find the symbol which coalesces this index
    r   r   zzero division error %s %sr%   N)
r,   r@   rA   r)   get_hintr   keysZeroDivisionErrorloop_tiling_loginfo)rN   rO   top_level_termsv	variables
zero_indexnew_vals          r1   find_coalesced_varr[      sO    i))%00O  HHH   *,I ' '
??IaLL#A;;IaLLE9--J__  	!	 	22GG  	 	 	  !<eYOOOH	 Z1$$IaL 5),,w61<<	!4s   B&B;:B;T)frozenc                       e Zd ZU dZeej                 ed<   eej                 ed<   eej	        ee
         f         ed<   eej	        ee
         f         ed<   eej        ef         ed<   dS )FusedNormalizedReadsWriteszO
    Normalized reads and writes for nodes in the same FusedSchedulerNode.
    
index_varsreduce_varsreadswritesrO   N)__name__
__module____qualname____doc__r   r,   Symbol__annotations__dictr?   strintr=   r3   r1   r^   r^      s           5<((((EL))))
JsO+,,,,Z_,----U\3&''''''r3   r^   nr!   pointwise_numel	red_numelnone_if_not_divisiblec                     d S r<   r=   rl   rm   rn   ro   s       r1   get_pw_red_splitsrr      s	     58Cr3   Fc                     d S r<   r=   rq   s       r1   rr   rr      s	     +.#r3   c                 :   |                                  s#t          | j        j        d                   |k    r<| j        j        | j        j        d         f| j        j        | j        j        d         ffS t          | j        j        d                   ||z  k    sJ t          | j        j        d                   dz
  }d}|dk    r-|| j        j        d         |         z  }||k    rn|dz  }|dk    -|dk    rd| j        j        d         d|         }| j        j        d|         }| j        j        d         |d          }| j        j        |d          }	||f|	|ffS |rd S | j        j        | j        j        d         f| j        j        | j        j        d         ffS )Nr   r   )is_reductionr   _bodysizes	iter_varsr`   r(   )
rl   rm   rn   ro   iprod	pw_splitsrx   
red_splitsred_varss
             r1   rr   rr      s    	~~ 
=q)9::oMMWa 01W !'-"23
 	

 q)**o	.IIIIIAGM!!AD
q&&a ##9	Q	 q&& 	AvvGM!$QqS)	G%ac*	W]1%abb)
7$QRR(9%*'=== 
t Wa 01W !'-"23
 	
r3   c            	       v    e Zd ZdZded         fdZdeeef         fdZdedede	eeef                  fd	Z
d
S )NodeSplitGetterz_
    Finds a Pointwise, Reduction Split that compatible with all nodes in a SchedulerNode.
    noder   c                    || _         |j        d         d         | _        |j        d         d         | _        t	          t
                    | _        d| _        t                      | _        |j        d         }t          |
                                          D ]>}t          |t          j        j        j                  s(t!          || j        | j        d          }|%| j                            |j        j                   l|\  \  }}\  }}t          j        j        j        j                            |||f| j                  \  }}| j        t1          |                                       t3          |                     |dk    rt5          |          f| _        t3          |          t3          |          f}| j                            |           @t                      | _        d S )Nr   r   r=   T)ro   )r   grouprm   rn   r   r   pw_split_optionsreduction_splitall_node_sizesreversed	get_nodesr'   torch	_inductor	schedulerr!   rr   addrv   rw   codegensimd
SIMDKernelprepare_split_iteration_lengthsr(   tupler   seen_pw_splits)	selfr   fused_grouprl   maybe_splits_n_pw_splitsn_red_splitsn_sizes	            r1   __init__zNodeSplitGetter.__init__  s    	+/:a=+;%)Z]1%5>I*>U>U&(?I||jm$..**++ $	, $	,Aa!:!HII 
 -4't  L ##''6662>/Q/q, ',7WW+|!<dn  &K !#k"2"2377k8J8JKKK r!!(5l(C(C'E$K((%*=*=>F##F++++1;r3   r#   c                    t          | j                  dk    r!t          t          | j                            S t	          | j                                                  }t          |dd          D ]}| j        |         D ]%}|                     || j	                  x}r|c c S &| j        |         D ]}t          t          |          dz
            D ]p}t          |d|         t          |||dz                      fz   ||dz   d         z             }| j        t          |                                       |           q| j        f| j        ffS )zI
        Get a compatible pointwise, reduction split of the node
        r   r   r%   N)r(   r   r*   r+   maxr   rR   range	try_splitr   r   r   r   rm   rn   )r   max_pw_splitpw_split_lenpw_splitr0   ry   	new_splits          r1   get_node_splitszNodeSplitGetter.get_node_splits;  s   
 t"##q((T01122240557788!,266 	I 	IL 1,?  ..43GHHH3 JJJJJ !1,? I Is8}}q011 I IA % 1(!a!e))<==?@"1q577+,! !I
 )#i..9==iHHHHII %'$.):;;r3   pwredc                    ddl m}m} || j        v rdS | j                            |           | j        D ]\  }}	 ||z   }||f}|                    ||          \  }	}
n# |$ r Y  dS w xY wt          |
          dk    sJ |	dt          |                   }t          t          j
                            |                    }||k    r|                     ||          x}r|c S ||fS )zs
        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   zNodeSplitGetter.try_splitV  s:    	GFFFFFFF$$$4###. 	 	KD%c-","D"DVW"U"U   ttt w<<1$$$$$Ys2wwY/O
 #(	(E(Eo(V(V"W"W"b((..)<cBBB3 JJJ3ws   "AA('A(N)rc   rd   re   rf   r   r   r   Splitr   r	   r   r=   r3   r1   r   r      s         4>9:4> 4> 4> 4>l<ue|!4 < < < <6E  (5;N2O      r3   r   )   
   )strictit1it2c                     t          |           t          |          k    r/t          dt          |            dt          |                     t          | |          S )zP
        Zip two iterables, raising ValueError if their lengths differ.
        zLengths differ: z != )r(   
ValueErrorzip)r   r   s     r1   	zip_equalr   }  sT     s88s3xxHCHHc#hhHHIII3}}r3   rx   r}   norm_pw_varsnorm_red_vars
new_rangesreturn_getters_groupsc                    t          d |D                       }t          j        d|           d}t          |           dk    rt          |          dk    ri S t          |          t          ||z             k    sJ g }|D ]#}	|                    fd|	D                        $i }
t          t          || |f                    D ]s\  }\  }	}t          |	          t          |          k    r|dk    sJ t          |          dk    sJ F|
                    d t          |	|          D                        td}i t          |||z             D ]\  }}g }t          t          |                    D ]"}|                    |                    |dz  }#d}t          t          |          dz
  dd          D ]}||z  ||         <   ||         |z  }fd|

                                D             S )	zBMaps original variables to expressions using normalized variables.c              3   4   K   | ]}t          |          V  d S r<   )r(   ).0ss     r1   	<genexpr>z$apply_var_mapping.<locals>.<genexpr>  s(      ..a3q66......r3   zv_0:r   c                 &    g | ]} |          S r=   r=   )r   g	flat_varss     r1   
<listcomp>z%apply_var_mapping.<locals>.<listcomp>  s!    999aQQy\\999r3   r   c                     i | ]\  }}||	S r=   r=   )r   r   rW   s      r1   
<dictcomp>z%apply_var_mapping.<locals>.<dictcomp>  s    &N&N&N1q!&N&N&Nr3   r   c                 8    i | ]\  }}|t          |          S r=   r   )r   krW   flat_vars_to_new_varss      r1   r   z%apply_var_mapping.<locals>.<dictcomp>  s:       Aq 	
:a.//  r3   )rD   r,   symbolsr(   rC   	enumerater   updater   r   items)rx   r}   r   r   r   r   num_varscountapply_groupsr   iter_vars_to_flat_varsry   	var_group	new_rangenew_var
range_varsrz   r   r   s                    @@r1   apply_var_mappingr     st   . ..:.....H/X//00IE
9~~s8}}11	z??c,">??????L& ; ;99995999::::!*,)X!688" " 
P 
PE9
 u::Y''6666y>>Q&&&&%%&N&NE98M8M&N&N&NOOOOE'
L=4PQQ 	' 	'	7
s9~~&& 	 	Ai.///QJEEs9~~)2r22 	' 	'A3:T>!*Q-0Q<$&DD	'   *0022   r3   r   c           	      @  !"#$ t          t                    }t          t                    }|                                 }|                                 }t                      }t                      #|D ]R}t          j        j                            ||          r#                    |           =|                    |           St          #fd| j	        j
        D                       }| j        d         d         }| j        d         d         }	t          d ||	fD                       rdS t          |                                           \  }
}t          |
|d          \  \  }}!| } t!          |                                           D ]!}t%          |t&          j        j        j                  s(|j        }|j        r dS t          t                    }t          t                    }|D ]5}|                    |          D ]}||                             |           6|D ]5}|                    |          D ]}||                             |           6|s|st5          |||	          \  \  }}\  }}|
|z   }||f}t&          j        j        j        j                            |||	          }t&          j        j        j        j                            ||          \  }}tA          ||||||          $dtB          j"        d	tB          j"        fd
""$fd|#                                D             }"$fd|#                                D             }|#                                D ]\  }}||xx         |z  cc<   |#                                D ]\  }}||xx         |z  cc<   #!fd|#                                D             }!fd|#                                D             }tI          ||||!          } tJ          &                    d|            | S )zjExtracts index variables, reduce variables, read/write expressions, and variable ranges from a fused node.c              3   8   K   | ]}|j         v|j         V  d S r<   )name)r   depremoved_bufferss     r1   r   z1extract_normalized_read_writes.<locals>.<genexpr>  s:        cho6U6U6U6U6U6U r3   r   r   c              3   t   K   | ]3}t          |t          j                  o|                                 V  4d S r<   )r'   r,   r?   r&   )r   vars     r1   r   z1extract_normalized_read_writes.<locals>.<genexpr>  sT         
C	$	$	>S__->->)>     r3   Nrl   )prefixr"   r#   c                 :    |                      t          d           S )Nc                     | S r<   r=   )r8   s    r1   <lambda>zIextract_normalized_read_writes.<locals>.remove_identity.<locals>.<lambda>'  s    A r3   )rE   r   )r"   s    r1   remove_identityz7extract_normalized_read_writes.<locals>.remove_identity&  s    <<++666r3   c                 J    i | ]\  }}t           |                    | S r=   r   )r   readrW   r   var_maps      r1   r   z2extract_normalized_read_writes.<locals>.<dictcomp>)  s@     
 
 
>EdAJt,,g66
 
 
r3   c                 J    i | ]\  }}t           |                    | S r=   r   )r   writerW   r   r   s      r1   r   z2extract_normalized_read_writes.<locals>.<dictcomp>,  sC     
 
 
q u--w77
 
 
r3   c                 b    i | ]+\  }}t           j        j                            |          |,S r=   r   graphsizevarssimplify_with_ranges)r   rrW   rangess      r1   r   z2extract_normalized_read_writes.<locals>.<dictcomp>7  sA       @D1--a88!  r3   c                 b    i | ]+\  }}t           j        j                            |          |,S r=   r   )r   wrW   r   s      r1   r   z2extract_normalized_read_writes.<locals>.<dictcomp>:  sA       @D1--a88!  r3   zNormalized Fused reads: %s)'r   r   get_buffer_namesget_operation_namesr   r   r   $can_buffer_be_removed_through_fusionr   read_writesra   r   anyr   r   r   listr   r'   r   r   r!   rv   indirect_varsget_all_read_exprget_all_write_exprrr   r   r   r   r   r   r   r,   r?   r   r^   rT   rU   )%r   ra   rb   all_output_namesop_namesoutputsbuf_nameinputsrm   rn   r{   r|   r   r   rl   bodyn_readsn_writesinpr"   r0   rx   r   r}   r   r   r   r   r   n_reads_newn_writes_new	buf_names	fused_outr   r   r   r   s%                                    @@@@r1   extract_normalized_read_writesr    s    0;:/F/FE0;J0G0GF,,..''))H)||G'1||O$ " "7AA(HUU 	"))))KK!!!!     ,2    F #'*Q-"2O JqM!,I   #Y/      t+D11AACCIz -B:c- - -)!\=6 D$..""## E& E&!U_6DEE 	w  	445@5L5L6A*6M6M  	' 	'C..s33 ' '!!#&&&&'  	( 	(C//44 ( (""3''''(  	x 	=N	>
 >
: K":8\ Z'/O#(3SS  	 O#(3KK  	*
)
 $!
 
	7%* 	7 	7 	7 	7 	7
 
 
 
 
IP
 
 

 
 
 
 
$NN,,
 
 

  +0022 	% 	%OD)$KKK9$KKKK+1133 	& 	&OD)4LLLI%LLLL	&   HM  E   HN  F + I 5yAAAr3   addrc                 $   g }| j         D ]I}|                    |d          }t          |t          j                  s||                    |           Jddlm} |j        j	        
                    t          |          t          j                  S )z6
    Score addr according to its approximate size
    Nr   r   fallback)r)   getr   r   INDIRECTrC   virtualizedr   r   r   atomically_apply_size_hintr   r   unbacked_symint_fallback)r  rO   	var_sizesrW   v_sizer   s         r1   	get_scorer  I  s     I % %4((a// 	%F4FV$$$766i  6+J 7   r3   rW   c                     t          | t                    r| S t          j        j                            | t          j                  S )Nr  )r'   rk   r   r   r   	size_hintr   r  )rW   s    r1   rQ   rQ   \  s;    !S Ww))!f6U)VVVr3   c                   <    e Zd ZU dZej        ed<   eed<   eed<   dS )	VarTilingzm
    Tiling of a var by `tiling_factor` that yields additional coalesced mem accesses by `benefit_score`
    r   tiling_factorscoreN)rc   rd   re   rf   r,   rg   rh   rk   r=   r3   r1   r  r  c  s?           
JJJJJr3   r  c                   X    e Zd ZU eej        ef         ed<   eed<   dZ	e
e         ed<   dS )CoalesceVarAnalysiscoalesced_by_varnorm_read_writesNsuggested_split)rc   rd   re   ri   r,   r?   rk   rh   r^   r&  r	   r  r=   r3   r1   r#  r#  n  sL         
 5:s?++++0000+/OXi(/////r3   r#  
fused_nodec           	      v   t          |           }|dS |j        }|j        }|j        }t	                      }t	                      }t          j        d |                                D             d |                                D                       D ]\  }\  }}	t          |j	        |j        
                                z
            }
|
r9t          ||          }|dk    rPt          ||          }d}|	D ]2}t          j                            |          x}r||j        j        z  }3||rdndz  }|r||xx         ||z  z  cc<   ||xx         ||z  z  cc<   |st%          ||          S t'          t                    }|                                D ]\  }}t(                              |j	        d          }|j	        D ]}||vr|dk    r||= t-          ||          }d||<   t/          |          }||                                r|j        sSt5          |          }t          j        j                            |||                   sdt;          fd	|||         |z  fD                       s||         |xx         |z  cc<   Όt=          |          dk    rt%          ||          S d}d}|                                D ]+\  }}|                                D ]\  }}||k    r||f}|},|t%          ||          S t%          ||t?          |d         |d         |          
          S )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      K   | ]}d |fV  	dS )TNr=   r   items     r1   r   z,analyze_memory_coalescing.<locals>.<genexpr>  s&      00$$000000r3   c              3      K   | ]}d |fV  	dS )FNr=   r*  s     r1   r   z,analyze_memory_coalescing.<locals>.<genexpr>  s&      224%222222r3   r   r   r%   )r$  r%     c              3   b   K   | ])}t           j        j                            |          V  *d S r<   )r   r   r   statically_known_lt)r   blockMIN_TILING_BLOCKs     r1   r   z,analyze_memory_coalescing.<locals>.<genexpr>  sM          445EuMM     r3   )r$  r%  r&  ) r  ra   rb   rO   r   r   r   r   boolr)   rR   r  r[   r   r   try_get_bufferdtypeitemsizer#  r   ri   fromkeysr   rM   r&   
is_integerrk   r   r/  allr(   r  )r'  r%  ra   rb   rO   r$  uncoalesced_addrsis_readmemory_exprr  indirect_exprsizemaybe_coalesced_varbyte_multiplerr  buftiling_scoresuncoalesced_expr
addr_score	expr_subsrW   single_var_exprr   best_tilingbest_tiling_scorer   tiling_countertile
tile_scorer1  s                                @r1   analyze_memory_coalescingrK  z  sK     6jAAt"E$F!,J07		/6yy-6_00%++--000226<<>>222. . D D))+y
 $'7'B'G'G'I'II
 
  	j111990jII! 	5 	5Hg,,X666s 5#)"44 	w-!!A- 	D0111TN5JJ1111k***d^.CC**** 
"-@P
 
 
 	

 7B'6J6JM(9(?(?(A(A ": ":$*MM"2"?CC	!.  	:  	:A
""Q!()99EEOIaL,_==M%$0022 &$/ & ..M7#77zRS}UU 
  !    +Z]m-KL      !]+++z9++++A 	:D =Q"-@P
 
 
 	
 59K,2244 / /^ . 4 4 6 6 	/ 	/D*---"Dk$.!	/
 "-@P
 
 
 	
 ))!+a.+a.BST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   r?   r   r   rg   VarsAndRanges_logginggetArtifactLoggerrc   rT   r   r   torch._inductor.schedulerr    r!   r2   rM   ri   rk   r[   	dataclassr^   rr   r2  r   version_infopartialr   r   r   r  r  rQ   r  r#  rK  r=   r3   r1   <module>r`     s               



 , , , , , , , , . . . . . . . . W W W W W W W W W W W W W W W W W W   " " " " " " > > > > > > ; ; ; ; ; ; ; ; / / / / / / 1 1 1 1 1 1 . . . . . . : : : : : : : :       GCLLGCLL 	ej#od5<($uz*::; .228]KK B B B B B B B B  LKKKKKKKK (<    *V5: V(5:*> V V V Vr#:##'
C#8#ej# # # #L d###	( 	( 	( 	( 	( 	( 	( $#	( 
88Z8 z8 #4=	8
 eM=0128 8 8 
8 

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

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

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