
    `i]                     (   d dl Z d dlZd dlZd dlZd dlZd dlZd dlmZ d dlmZ d dl	m
Z
 d dl	mZ d dlmZ 	 d dlZd dlmZ n# e$ r dZY nw xY wddd	Zej        ej        z   Zd
 Zd Zd Zd ZddZd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%dS )    N)_accelerator)_util)_greedy_path)_optimal_path)_try_use_cutensornet)cutensorF)sum_ellipsisbroadcast_diagonalc                 &    g }g }|D ]\}|                     |r j        |d                  nd           t           fd|D                       }|                     |           ]                                                       ||dd            S )zTranspose and diagonal

    Args:
        a
        axeses (sequence of sequences of ints)

    Returns:
        ndarray: a with its axes permutated. A writeable view is returned
        whenever possible.
    r      c              3   2   K   | ]}j         |         V  d S N)strides.0axisas     g/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/cupy/linalg/_einsum.py	<genexpr>z _transpose_ex.<locals>.<genexpr>/   s)      66QYt_666666    T)appendshapesumview_set_shape_and_strides)r   axesesr   r   axesstrides   `     r   _transpose_exr      s     EG  4QWT!W%%1555666666666v	AUGT4888Hr   c                     d}| D ]Y}|t           u r|dz  }	 t          j        |          }n"# t          $ r}t          d          |d }~ww xY w|t          |         z  }Z|S )N @z=For this input type lists must contain either int or Ellipsis)Ellipsisoperatorindex	TypeErroreinsum_symbols)list_subscriptstr_subscriptses       r   _parse_int_subscriptr,   7   s    M 
/ 
/==S MM5N1%% 5 5 5-. .3455 ^A..MMs   ,
AAAc                    t          |           dk    rt          d          t          | d         t                    r| d         }t	          | dd                   }|D ]"}|dv r|t
          vrt          d|z            #|                    dd          }d	|v rt          d
          d|v sd|v r|                    d          dk    p|                    d          dk    }|                    d          }|st          |          dk    rt          d          |\  }}|                    dd          }n|}d}|                    dd                              d          }t          |          t          |          k    r6t          |          t          |          k    rdnd}t          |dz             nt	          |           } g }g }t          |           dk    rp|	                    | 
                    d                     |	                    t          | 
                    d                               t          |           dk    p| rt          | d                   }nd}|||fS )a  Parse einsum operands.

    This function is based on `numpy.core.einsumfunc._parse_einsum_input`
    function in NumPy 1.14.

    Parameters
    ----------
    args : tuple
        The non-keyword arguments to einsum

    Returns
    -------
    input_strings : str
        Parsed input strings
    output_string : str
        Parsed output string
    operands : list of array_like
        The operands to use in the contraction

    Examples
    --------
    The operand list is simplified to reduce printing:

    >>> a = np.random.rand(4, 4)
    >>> b = np.random.rand(4, 4, 4)
    >>> _parse_einsum_input(('...a,...a->...', a, b))
    (['@a, @a'], 'xz', [a, b])

    >>> _parse_einsum_input((a, [Ellipsis, 0], b, [Ellipsis, 0]))
    (['@a, @a'], 'xz', [a, b])
    r   zmust specify the einstein sum subscripts string and at least one operand, or at least one operand and its corresponding subscripts listr   Nz.,-> zTinvalid subscript '%s' in einstein sum subscripts string, subscripts must be lettersz...r"   .zUeinstein sum subscripts string contains a '.' that is not part of an ellipsis ('...')->z->   zKeinstein sum subscript string does not contain proper '->' output specified r!   ,morefewerzS operands provided to einstein sum function than specified in the subscripts string)len
ValueError
isinstancestrlistr'   replacecountsplitr   popr,   )args
subscriptsoperandsr*   invalidinput_subscriptsoutput_subscriptmsgs           r   _parse_einsum_inputrF   G   s   B 4yyA~~  	
 $q'3 5$!W
QRR>>  	> 	>AG||&& 9;<=> > > '  ''s33
*01 1 1
 :3*#4#4 &&s++a/L:3C3CC3H3H13LG#))$//J /#j//Q.. ./ / / 2<../77R@@  *#+33C<<BB3GG  CMM11MMC0@,A,AAA&&wC 5 56 6 6 2 Dzz$ii1nnOODHHQKK(((##$8!$E$EFFF $ii1nn  	$3DG<<#-x77r   c                 6    | dk     rd| z  S t          |           S )Nr   z...[%d])chr)labels    r   _chrrJ      s"    qyy5  5zzr   c                    |                      d          }t          |          dk    r`|\  }|Nt          |          |k    r;t          |          |k    rt          d||fz            t          d||fz            d |D             S t          |          dk    r|\  }}|"|t          |          t          |          z   z
  }|dk     rt          d	|||fz            g }|                    d
 |D                        |                    t	          | d                     |                    d |D                        |S t          d|dnd|z  z             )a  Parse a subscript that may contain ellipsis

    Args:
        subscript (str): An einsum subscript of an operand or an output. '...'
            should be replaced by '@'.
        idx (int or None): For error messages, give int idx for the idx-th
            operand or None for the output.
        ndim (int, optional): ndim of the operand
        ellipsis_len (int, optional): number of broadcast dimensions of the
            output.

    Returns:
        list of ints: The parsed subscript

    r"   r   NzMeinstein sum subscripts string %s contains too many subscripts for operand %dzoperand %d has more dimensions than subscripts string %s given in einstein sum, but no '...' ellipsis provided to broadcast the extra dimensions.c                 ,    g | ]}t          |          S  ordr   rI   s     r   
<listcomp>z-_parse_ellipsis_subscript.<locals>.<listcomp>   s    ,,,uE

,,,r   r1   r   zReinstein sum subscripts string %s...%s contains too many subscripts for operand %dc              3   4   K   | ]}t          |          V  d S r   rN   rP   s     r   r   z,_parse_ellipsis_subscript.<locals>.<genexpr>   s(      44%3u::444444r   c              3   4   K   | ]}t          |          V  d S r   rN   rP   s     r   r   z,_parse_ellipsis_subscript.<locals>.<genexpr>   s(      55%3u::555555r   zVeinstein sum subscripts string contains a '.' that is not part of an ellipsis ('...') zin the outputzfor operand %d)r=   r6   r7   extendrange)		subscriptidxndimellipsis_lensubssubleft_sub	right_subrets	            r   _parse_ellipsis_subscriptr_      s     ??3D
4yyA~~CD 0 03xx$ 036*=> > > 258#J?@ @ @ -,,,,,	Ta")3x==3y>>#ABL!,/7C.HIJ J J 

448444444

5,**+++

559555555
 - #__1AC1GIJ J 	Jr   c           	         t          t          |                     D ]b}| |         }||         t          t          |                    t          |          k     r!i }t          |          D ].\  }}|                    |g                               |           /t          |                                          }|D ]\  }}t          d         rfd|D             }fd|D             }t          |          dk    rK|	                                }	|	                                }
t          d|t          |          |	|
fz            t          | \  }}t          |          | |<   t          |          ||<   ddS )zGCompute diagonal for each operand

    This function mutates args.
    r
   c                 6    g | ]}j         |         d k    |S )r   r   r   r   arrs     r   rQ   z%_einsum_diagonals.<locals>.<listcomp>   s)    JJJTSYt_5I5ID5I5I5Ir   c                 *    h | ]}j         |         S rM   rb   rc   s     r   	<setcomp>z$_einsum_diagonals.<locals>.<setcomp>   s    999D	$999r   r1   zIdimensions in operand %d for collapsing index '%s' don't match (%d != %d)N)rU   r6   set	enumerate
setdefaultr   r:   itemsoptionsr>   r7   rJ   zipr   )rC   rA   rW   r[   r   r   rI   r   dimsdim0dim1rd   s              @r   _einsum_diagonalsrp      s   
 S)**++ 7 7s#sms3xx==3s88##F(~~ : :e!!%,,33D9999&,,..))F%  t/0 KJJJJTJJJD9999D999t99>>88::D88::D$OUT489   " v,KC$(IIS!)#v66HSM57 7r   c              #      K   | D ]f}t          d |D                       sJ t          |          dk    r6t          |d          }|d         |d         fV  |dd         D ]}d|fV  	gdS )	zDecompose path into binary path

    Args:
        path (sequence of tuples of ints)

    Yields:
        tuple of ints: pair (idx0, idx1) that represents the operation
            {pop(idx0); pop(idx1); append();}
    c              3   "   K   | ]
}|d k    V  dS r   NrM   )r   rW   s     r   r   z#_iter_path_pairs.<locals>.<genexpr>  s&      //3!8//////r   r1   T)reverser   r   N)allr6   sorted)pathindicesrW   s      r   _iter_path_pairsrz     s         //w////////w<<1Wd333G!*gaj((((qrr{  #g r   c                     g }g }|D ]8}|                     |           |                     fd|D                        9                     |                              t	          d |D                                 |fS )zTranspose and flatten each

    Args:
        a
        axeses (sequence of sequences of ints)

    Returns:
        aT: a with its axes permutated and flatten
        shapes: flattened shapes
    c                 *    g | ]}j         |         S rM   rb   r   s     r   rQ   z&_flatten_transpose.<locals>.<listcomp>(  s    666qwt}666r   c                 V    g | ]&}t           j        j                            |          'S rM   )cupy_coreinternalprod)r   r   s     r   rQ   z&_flatten_transpose.<locals>.<listcomp>+  s+    GGGu4:&++E22GGGr   )rT   r   	transposereshapetuple)r   r   transpose_axesshapesr   s   `    r   _flatten_transposer     s     NF 8 8d###66666667777	N##++GGGGGHH	J 	J r   c                     t          j        d          sdS | |k    rdS | t          j        t          j        t          j        t          j        fvrdS dS )NcontractionFT)r   check_availabilityr~   float32float64	complex64
complex128)dtype0sub0dtype1sub1
batch_dimscontract_dimss         r   _use_cutensorr   0  sW    &}55 uudlDLndo7 7 7u4r   c                 j    i t          | |z   ||z             D ]
\  }}||<   fd|D             }|S )Nc                      g | ]
}|         S rM   rM   )r   iextents     r   rQ   z"_get_out_shape.<locals>.<listcomp>?  s    ,,,q,,,r   )rl   )	shape0r   shape1r   sub_outsizer   	out_shaper   s	           @r   _get_out_shaper   ;  sW    Fvt44  aq		,,,,G,,,Ir   c                 R   t          |          }t          | j                  }g }|D ]X}||vr*|                    |           |                    d           |                    |                    |                     Yt	          j        |                     |          |          S )a  Return a reshaped and transposed array.

    The input array ``arr`` having ``mode`` as its modes is reshaped and
    transposed so that modes of the output becomes ``mode_out``.

    Example
        >>> import cupy
        >>> a = cupy.zeros((10, 20))
        >>> mode_a = ('A', 'B')
        >>> mode_out = ('B', 'C', 'A')
        >>> out = cupy.linalg.einsum._expand_dims_transpose(a, mode_a,
        ...                                                 mode_out)
        >>> out.shape
        (20, 1, 10)

    Args:
        arr (cupy.ndarray):
        mode (tuple or list): The modes of input array.
        mode_out (tuple or list): The modes of output array.

    Returns:
        cupy.ndarray: The reshaped and transposed array.

    r   )r:   r   r   r%   r~   r   r   )rd   modemode_outr   r   r   s         r   _expand_dims_transposer   C  s    2 ::DOOED # #D==KKNNNLLOOODJJqMM"""">#++e,,d333r   c                 B   t                    }t                    }t          |          t                    k    s
J d            t          |          t                    k    s
J d            t                    dk    st                    dk    r
| |z  z   fS t          |          }||z  }||z  }	||	z
  }
t          |	|
          \  }}}t          |	|
          \  }}}fd|D             }|fd|D             k    sJ fd|D             }fd|D             }||z   |z   }t          |          |k    s
J d            t          |
          dk    rKt          |          t          |          k    r|}t          | |          } t          ||          }| |z  |fS t	          j                    D ]}|t          j        k    rt          t          | j	        |j	        |	|
          rt          |          t          |          k    r|}t          | j        |j        |          }t          j        || j	                  }t          j        |           } t          j        |          }t          j        d	| |d
||          }||fc S t!          | |||g          \  }}t!          ||||g          \  }}|d         |d         z   |d         z   }|d         |d         k    sJ t          j        ||                              |          }||fS )Nz%operand 0 should be reduced: diagonalz%operand 1 should be reduced: diagonalr   c                      g | ]
}|         S rM   rM   r   r   r   s     r   rQ   z)reduced_binary_einsum.<locals>.<listcomp>x      (((DT$Z(((r   c                      g | ]
}|         S rM   rM   r   r   r   s     r   rQ   z)reduced_binary_einsum.<locals>.<listcomp>y  s    000DT$Z000r   c                      g | ]
}|         S rM   rM   r   s     r   rQ   z)reduced_binary_einsum.<locals>.<listcomp>z  r   r   c                      g | ]
}|         S rM   rM   r   s     r   rQ   z)reduced_binary_einsum.<locals>.<listcomp>{  r   r   z%operands should be reduced: unary sumg      ?g        r   r1   )rg   r6   _make_transpose_axesr   r   get_routine_acceleratorsACCELERATOR_CUTENSORr   r   dtyper   r   r~   emptyascontiguousarrayr   r   matmulr   )arr0r   arr1r   
sub_othersset0set1
set_otherssharedr   r   bs0cs0ts0bs1cs1ts1sub_bsub_lsub_rr   acceleratorr   arr_outtmp0shapes0tmp1shapes1
shapes_outs    ` `                         r   reduced_binary_einsumr   g  st   t99Dt99Dt99D		!!!#J!!!t99D		!!!#J!!!
4yyA~~Tad{D4K''ZJD[F*$JZ'M(z=IIMCc(z=IIMCc((((C(((E0000C0000000((((C(((E((((C(((Eeme#Gw<<:%%%'N%%%
=Qw<<3z??** G%dD'::%dD'::d{G###<>> ( (<<<<$TZtz4'8 8 (w<<3z??22(G*Jdj$A A	*Y
;;-d33-d33".$$W& & ''''&tc3_==MD'&tc3_==MD'gaj(71:5J1:####k$%%--j99GGr   c                 .   g }g }g }t          |           D ]T\  }}||v r|                    ||f           !||v r|                    ||f           =|                    ||f           Ut          |          t          |          t          |          fS r   )rh   r   _tuple_sorted_by_0)r[   b_dimsc_dimsbscstsr   rI   s           r   r   r     s    	B	B	B ~~ % %eF??IIudm$$$$f__IIudm$$$$IIudm$$$$222 r   c                 N    t          d t          |           D                       S )Nc              3       K   | ]	\  }}|V  
d S r   rM   )r   _r   s      r   r   z%_tuple_sorted_by_0.<locals>.<genexpr>  s&      **tq!******r   )r   rw   )zss    r   r   r     s%    **vbzz******r   c            	      L  !"#$%& t          | i |}||S t          |           \  }}} t          |t                    sJ t          | t                    sJ |                    dd          }i !|                    dd          }|du rd}|r1t          dt          |                                          z            |t          j        |  n|$d | D             } d	 t          t          ||                     D             }i "t          |          D ]\  }}| |         j        }	t          |          D ]r\  }
}|	|
         }|"                                v rJ"|         d
k    r|"|<   5|d
"|         fvr+"|         }t          dt          |          |||fz            m|"|<   s|Vt          t          j                            |                    &&fdt#          t%          &                    D             }nt&          d         sd|vrd"v rt          d          t)          |dt+          d "                                D                                 }t%          t          j                            |                    &|D ]%}|&vrt          dt          |          z            &t-          |          t-          t%          |                    k    r=|D ]:}|                    |          dk    rt          dt          |          z            ;t1          ||            t-          |           dk    r%t3          d | D                       r/t          j        t7          "fd|D                       $          S t9          t-          |                     D ]}| |         }d
|j        v rg }g }t          ||                   D ]A\  }
}|j        |
         d
k    r|                    |
           ,|                    |           B|||<   t          j        |t7          |                    | |<   | |         j        t-          ||                   k    sJ ~t-          |           d
k    }t          |          D ]\  }}tA          j         |          #|#|<   t%          t          j                            #                    #t7          #fdt          |          D                       %%r@d}%fdt          |          D             ||<   | |                             %$          | |<   |rd | D             } n!$fd| D             } tB          tD          d}|du r,t7          t9          t-          |                               g}n t-          |          r|d          d!k    r|d
d         }n	 t-          |          dk    rFt          |d
         tF          tH          f          r$||d                   }tG          |d
                   }n
||         }d"}n4# t
          tJ          f$ r  t          d#tM          |          z            w xY wd$ |D             }t%          |          } |||"|          }t3          d% |D                       rtO          j(        d&tR          j*                   tW          |          D ]\  }}|                     |          }|                    |          }|                     |          }|                    |          }t          t          j        |t          j                            |                              }tY          |||||          \  }}|                     |           |                    |           ~~| \  }|\  }g } |D ].}||v r(|                     |-                    |                     /|.                    |           /                    "fd'|D                       }|s|j0        $k    sJ |S )(a  einsum(subscripts, *operands, dtype=None, optimize=False)

    Evaluates the Einstein summation convention on the operands.
    Using the Einstein summation convention, many common multi-dimensional
    array operations can be represented in a simple fashion. This function
    provides a way to compute such summations.

    .. note::

       - Memory contiguity of the returned array is not always compatible with
         that of :func:`numpy.einsum`.
       - ``out``, ``order``, and ``casting`` options are not supported.
       - If :envvar:`CUPY_ACCELERATORS` includes ``cutensornet``, the `einsum`
         calculation will be performed by the cuTensorNet backend if possible.

           - The support of the ``optimize`` option is limited (currently, only
             `False`, 'cutensornet', or a custom path for pairwise contraction
             is supported, and the maximum intermediate size is ignored). If
             you need finer control for path optimization, consider replacing
             :func:`cupy.einsum` by :func:`cuquantum.contract` instead.
           - Requires `cuQuantum Python`_ (v22.03+).

       - If :envvar:`CUPY_ACCELERATORS` includes ``cutensor``, `einsum` will be
         accelerated by the cuTENSOR backend whenever possible.

    Args:
        subscripts (str): Specifies the subscripts for summation.
        operands (sequence of arrays): These are the arrays for the operation.
        dtype: If provided, forces the calculation to use the data type
            specified. Default is None.
        optimize: Valid options include {`False`, `True`, 'greedy', 'optimal'}.
            Controls if intermediate optimization should occur. No optimization
            will occur if `False`, and `True` will default to the 'greedy'
            algorithm. Also accepts an explicit contraction list from
            :func:`numpy.einsum_path`. Defaults to `False`. If a pair is
            supplied, the second argument is assumed to be the maximum
            intermediate size created.

    Returns:
        cupy.ndarray:
            The calculation based on the Einstein summation convention.

    .. seealso:: :func:`numpy.einsum`
    .. _cuQuantum Python: https://docs.nvidia.com/cuda/cuquantum/python/
    Nr   optimizeFTgreedyz+Did not understand the following kwargs: %sc                 6    g | ]}t          j        |          S rM   )r~   
asanyarrayr   rd   s     r   rQ   zeinsum.<locals>.<listcomp>   s2        	  r   c                 H    g | ]\  }\  }}t          |||j                    S ))rX   )r_   rX   )r   rW   r[   rd   s       r   rQ   zeinsum.<locals>.<listcomp>  sA       C#s 	"#s:::  r   r   zJSize of label '%s' for operand %d (%d) does not match previous terms (%d).c                 R    g | ]#}|d k     s                     |          dk    !|$S )r   r   )r<   )r   rI   tmp_subscriptss     r   rQ   zeinsum.<locals>.<listcomp>   sD     
 
 
qyyN00771<< <<<r   r	   r"   ru   zoutput has more dimensions than subscripts given in einstein sum, but no '...' ellipsis provided to broadcast the extra dimensions.c              3   "   K   | ]
}|d k     V  dS rs   rM   rP   s     r   r   zeinsum.<locals>.<genexpr>.  s&      JJ5UQYJJJJJJr   )rY   z^einstein sum subscripts string included output subscript '%s' which never appeared in an inputr1   zLeinstein sum subscripts string includes output subscript '%s' multiple timesc              3   ,   K   | ]}|j         d k    V  dS rs   )r   r   s     r   r   zeinsum.<locals>.<genexpr>D  s(      11sx1}111111r   c              3   (   K   | ]}|         V  d S r   rM   r   rI   dimension_dicts     r   r   zeinsum.<locals>.<genexpr>F  s(      JJnU+JJJJJJr   )r   )r   c              3   *   K   | ]\  }}|v	|V  d S r   rM   )r   r   rI   other_subscriptss      r   r   zeinsum.<locals>.<genexpr>c  s?       
 
e,,, ,,,,
 
r   c                 "    g | ]\  }}|v	|S rM   rM   )r   r   rI   sum_axess      r   rQ   zeinsum.<locals>.<listcomp>j  s2     % % %D%x'' '''r   )r   r   c                 6    g | ]}|                                 S rM   )r   )r   r   s     r   rQ   zeinsum.<locals>.<listcomp>t  s     ///AFFHH///r   c                 0    g | ]} |j         fd diS )copyF)astype)r   r   casting_kwargsresult_dtypes     r   rQ   zeinsum.<locals>.<listcomp>v  sB     
 
 
 AH\@@@@@
 
 
r   )r   optimalr   einsum_pathl        z*Did not understand the path (optimize): %sc                 ,    g | ]}t          |          S rM   )rg   )r   r[   s     r   rQ   zeinsum.<locals>.<listcomp>  s    ;;;3c#hh;;;r   c              3   <   K   | ]}t          |          d k    V  dS )r1   N)r6   )r   ry   s     r   r   zeinsum.<locals>.<genexpr>  s-      44Gs7||a444444r   z,memory efficient einsum is not supported yetc                      g | ]
}|         S rM   rM   r   s     r   rQ   zeinsum.<locals>.<listcomp>  s.     6 6 6 	u6 6 6r   )1r   rF   r8   r:   r>   r&   keysr~   result_typerh   rl   r   r7   rJ   	itertoolschainfrom_iterablerw   rg   rk   r_   r   r6   r<   rp   anyzerosr   rU   r   squeezerX   r   r   r   intfloatKeyErrorr9   warningswarnr   PerformanceWarningrz   r   r%   r   r   r   )'rA   kwargsoutrC   rD   r   r   rW   r[   shr   rI   dimdim_oldrd   squeeze_indicesreturns_viewoptimize_algorithmsrx   algomemory_limit
input_sets
output_setidx0idx1r   r   r   r   r   r   r   r   r   r   r   r   r   r   s'                                    @@@@@@r   einsumr    s	   \ 
3F
3
3C

 	H%% 1&&-----h%%%%%JJw%%E Nzz*e,,H4 /Ev{{}}--. / / 	/ 38-4#X..UL   H
 (-=x)H)HII   N.// , ,Sc] $S>> 	, 	,KD%T(C++----!%(A--,/N5))N5$9 :::,U3G$>;;S':;< < < ; ),u%%	, io;;<LMMNN
 
 
 
N 3 344
 
 
 ~& 	C***r^/C/C BC C C 5dJJN4G4G4I4IJJJJJ
 
 
 Y_::;KLLMM% 	M 	MEN** >@DULM M M +   C,<(=(=$>$>>>) I I#))%00A55$:<@KKHI I I 6
 &111 8}}1111111 	:JJJJ9IJJJJJ"    X'' 	 	C3-CCI~~"$#,-=c-B#C#C * *KD%y!++'..t4444

5))))(+ % $Su_7M7M N N N})S1A#1F-G-GGGGG x==A%L .// 3 3S9%566 0y<<=MNNOO 
 
 
 
(~~
 
 
 
 

  		3 L% % % %#,S>>% % %S! %SM--\ . 3 3HSM  
//h///
 
 
 
 

 
 
    5eCMM**++,	X *HQK=88|		-8}}!!j!sEl&K&K!*8A;7"8A;//*84&8$ 	- 	- 	-H!(mm, - - -	- <;*:;;;
)**
tJ
NLII44t44444 	*M>(* * * 't,,  
d||D!!##D))||D!!##D)))/O))*:;;= = > >
 1$dJ0 0   ((($$ EDEDN! 5 5D==!!$**U"3"3444nn^,,44 6 6 6 6%6 6 6  G 87=L8888Ns   A#X' '1Y)NN)&r   r   r$   stringr   r~   
cupy._corer   r   cupy.linalg._einsum_optr   r   cupy.linalg._einsum_cutnr    cupy_backends.cuda.libs.cutensorcupy_backendscupyxr   ImportErrorrk   ascii_uppercaseascii_lowercaser'   r   r,   rF   rJ   r_   rp   rz   r   r   r   r   r   r   r   r  rM   r   r   <module>r     s	            # # # # # #       0 0 0 0 0 0 1 1 1 1 1 1 9 9 9 9 9 9++++   HHH
   '&*@@  0   ^8 ^8 ^8B  /J /J /J /Jd7 7 7D  *  0    !4 !4 !4H< < <~  $+ + +y y y y ys   
A AA