
    2Vh}                        d dl Z d dlZ e j                  ej                  ej
                        Z e j                  ej                  ej                        Z e j                  ej                  ej                        Z
 e j                  ej                  ej                        Z e j                  ej                  ej                        ZddZd Zd Zd ZddZddZd	 Zd
 Zd Zd ZddZd Zd Zy)    Ndtypec                 Z   | j                   }|j                  dk(  r]| j                  j                   d   dk(  r!t        j                  || j
                        S t        j                  | j                  d      S t        j                  j                  | |      } | j                  |       | S )Nr   r    )default_value)
shaperankvaluestfconstantr   reshapesparseto_dense	set_shape)xr   x_shapes      S/home/dcms/DCMS/lib/python3.12/site-packages/keras/src/backend/tensorflow/sparse.pysparse_to_denser      s    ggG||q88>>!!;;}AGG<<::ahh++
		1M:AKKH    c                     | j                   }t        j                  | j                  || j                        } | j                  |       | S N)r   r   SparseTensorindicesdense_shaper   )r   r
   r   s      r   sparse_with_valuesr      s6    ggG
		61==9AKKHr   c                 |    t        j                  | |j                        }|j                  |j                         |S r   )r   broadcast_tor   r   r   )scalarr   outputs      r    broadcast_scalar_to_sparse_shaper        s/    __VV%7%78F
V\\"Mr   c                 4   t        |t        j                        rLt        j                  j	                  | t        j                  j                  t        j                  |            S t        j                  j	                  | t        j                  |            S )a>  Subtraction for `tf.SparseTensor`s.

    Either `x1` or `x2` or both can be `tf.SparseTensor`s.

    Args:
        x1: fist tensor to add.
        x2: second tensor to add.
    Returns:
        The sum of `x1` and `x2`, which is a `tf.SparseTensor` if and only if
        both `x1` or `x2` are `tf.SparseTensor`s.
    )
isinstancer   r   r   add
map_valuesnegativex1x2s     r   sparse_subtractr)   &   sY     "boo&yy}}R!5!5bkk2!FGGyy}}RR11r   c                 \   t        j                  |t        j                  t        j                  |      d   f| j                  j
                        | j                        }t         j                  j                  | |      }|t        j                  ||| j                        }t         j                  j                  t         j                  |       }t         j                  j                  ||      }|j                  |j                  |j                  fS |j                  |j                  dfS )a  Compute the indices for the union of the indices of the provided
    `tf.SparseTensor`s and another set of indices and return the modified values
    for these indices.

    Args:
        x: a `tf.SparseTensor`.
        indices: another set of indices in the `tf.SparseTensor` format.
    Returns: A tuple containing:
        - the indices for the union
        - `x1` values for the union indices (some zeros were added)
        - `x2` values for the union indices (some zeros were added) or `None` if
          `x2_values` was `None`.
    r   N)r   r   zerosr   r
   r   r   r   r#   r$   
zeros_liker   )r'   
x2_indices	x2_valueszeros2x1_for_unionr(   zeros1x2_for_unions           r   sparse_union_indices_and_valuesr3   8   s     __
"((:&q)+RYY__=
F
 99==V,L__ZBNNC%%bmmR8yy}}R0##\%8%8,:M:MMM##\%8%8$>>r   c                 :   	
  j                   d   t        j                   j                  d      t        j                  |d      t        j                        d   t        j                        d   t        j
                  t        f      f      }t        j
                  t        f      f      }t        j                  t        j                  t        j                  j                  ||            d      	t        j                  	      d   }	fd
t        j                  t        j                  |       fd
 fd      }5t        j                  t        j                  |      fd	
fd
      }nd}	||fS )a,  Compute the indices for the union of two `tf.IndexedSlices` and modify
    the values for these indices.

    Args:
        x1: the first `tf.IndexedSlices`.
        x2_indices: the indices for the second `tf.IndexedSlices`.
        x2_value: (optional) the values for the second `tf.IndexedSlices`.
    Returns: A tuple containing:
        - the indices for the union
        - `x1` values for the union indices (some zeros were added)
        - `x2` values for the union indices (some zeros were added) or `None` if
          `x2_values` was `None`.
    r      axisc                    t        j                  | t        j                  d|dz         f      }t        j                  |      }t        j                  t        j
                  |dd       |gd      }t        j                  ||      S )Nr5   r   r6   )r   
scatter_ndrangegatherconcatr,   )indices_expandedindices_countr
   indices_indicesto_union_indicesvalues_with_leading_zerosdim_0union_indicess         r   values_for_unionzAindexed_slices_union_indices_and_values.<locals>.values_for_union~   s|    --HHQ)*H

 99_mD$&II]]6!A;'0q%
! yy24DEEr   c                       j                   S r   r
   r'   s   r   <lambda>z9indexed_slices_union_indices_and_values.<locals>.<lambda>   s    		 r   c                  ,      j                         S r   rG   )rE   r'   x1_indices_countx1_indices_expandeds   r   rI   z9indexed_slices_union_indices_and_values.<locals>.<lambda>   s     !1299
 r   Nc                       S r   r   )r.   s   r   rI   z9indexed_slices_union_indices_and_values.<locals>.<lambda>   s    I r   c                              S r   r   )rE   x2_indices_countx2_indices_expandedr.   s   r   rI   z9indexed_slices_union_indices_and_values.<locals>.<lambda>   s    $#%5y r   )r   r   expand_dimsr   r   r:   	ones_boolsqueezewheremath
logical_orcondequal)r'   r-   r.   x1_indices_one_hotx2_indices_one_hotunion_indices_countx1_values_for_union_indicesx2_values_for_union_indicesrC   rD   rE   rK   rL   rO   rP   s   ` `     @@@@@@@r   'indexed_slices_union_indices_and_valuesr^   W   so     NN1E..!<..!<xx 34Q7xx 34Q7#%&	
 #%&	
 JJ
##$68JKLM ((=1!4
F #%''
!#67	
# &(ggHH%':;'
# '+# 	## r   c                     t         j                  j                  t               }t         j                  j                  t              }t         j                  j                  t         j                  j                  |d      t         j                  j                  |d             fd} fd}t        j                  t        j                  t        j                        d      ||      S )a  Compute the indices for the intersection of two `tf.SparseTensor`s and
    modify the values for these indices.

    Args:
        x1: the first `tf.SparseTensor`.
        x2: the second `tf.SparseTensor`.
    Returns: A tuple containing:
        - the indices for the intersection
        - `x1` values for the intersection indices (some values were removed)
        - `x2` values for the intersection indices (some values were removed)
    r8   r6   c                  $   t        j                  d j                  j                  ft         j                        t        j                  d j
                  j                        t        j                  dj
                  j                        fS )Nr   r   r   )r   r+   r   r	   int64r
   r   r&   s   r   empty_intersectionzBsparse_intersection_indices_and_values.<locals>.empty_intersection   sX    HHa'rxx8HHT1HHT1
 	
r   c            	         t         j                  j                  j                        } t         j                  j	                  t
              }t         j                  j	                  t
              }t         j                  j                  ||       }t         j                  j                  ||       }| j                  t         j                  j                  t        j                  |j                  t         j                              j                  t         j                  j                  t        j                  |j                  t         j                              j                  fS r   )r   r   r   r   r$   zeros_like_int8r#   r   retaincastr
   bool)intersectionr1   r/   mask1mask2intersection_extra_dimr'   r(   s        r   non_empty_intersectionzFsparse_intersection_indices_and_values.<locals>.non_empty_intersection   s    yy(()?P %%or:%%or:		fl3		fl3  IIRrww!?@GGIIRrww!?@GG
 	
r   r   )
r   r   r$   ones_like_int8setsri   rQ   rW   rX   size)r'   r(   ones1ones2rc   rm   rl   s   ``    @r   &sparse_intersection_indices_and_valuesrs      s     II  4EII  4E  WW11
		e"-
		e"-


 77
/0!4 r   c           	         	
  j                   d   t        j                   j                  d      
t        j                  j                  d      
j                  d   	j                  d   t        j
                  
t        	f      f      }t        j
                  t        f      f      }t        j                  t        j                  t        j                  j                  ||            d      t        j                        d    fd} 	
f	d}t        j                  t        j                  d      ||      S )a  Compute the indices for the intersection of two `tf.IndexedSlices` and
    modify the values for these indices.

    Args:
        x1: the first `tf.IndexedSlices`.
        x2: the second `tf.IndexedSlices`.
    Returns: A tuple containing:
        - the indices for the intersection
        - `x1` values for the intersection indices (some values were removed)
        - `x2` values for the intersection indices (some values were removed)
    r   r5   r6   r8   c                       t        j                  dj                  j                  dd  z   j                        t        j                  dj                  j                  dd  z   j                        fS )Nra   r5   )r   r+   r
   r   r   )intersection_indicesr'   r(   s   r   rc   zJindexed_slices_intersection_indices_and_values.<locals>.empty_intersection   s\     HHTBIIOOAB//:HHTBIIOOAB//:
 	
r   c                     	 fdt        j                  t        j                        fdfd      } t        j                  t        j                  
      	fd	
fd      }| |fS )Nc                     t        j                  | t        j                  |      f      }t        j                  |      }t        j                  ||      S r   )r   r:   r;   r<   )r>   r?   r
   r@   to_intersection_indicesrC   rv   s        r   values_for_intersectionzoindexed_slices_intersection_indices_and_values.<locals>.non_empty_intersection.<locals>.values_for_intersection  sP     mm 'O
 ')ii!5'# 99V%<==r   c                       j                   S r   rG   rH   s   r   rI   z`indexed_slices_intersection_indices_and_values.<locals>.non_empty_intersection.<locals>.<lambda>      BII r   c                  ,      j                         S r   rG   )rz   r'   rK   rL   s   r   rI   z`indexed_slices_intersection_indices_and_values.<locals>.non_empty_intersection.<locals>.<lambda>      +#%5ryy r   c                       j                   S r   rG   )r(   s   r   rI   z`indexed_slices_intersection_indices_and_values.<locals>.non_empty_intersection.<locals>.<lambda>  r|   r   c                  ,      j                         S r   rG   )rz   r(   rO   rP   s   r   rI   z`indexed_slices_intersection_indices_and_values.<locals>.non_empty_intersection.<locals>.<lambda>  r~   r   )r   rW   rX   )x1_values_for_intersectionx2_values_for_intersectionrz   rC   rv   intersection_indices_countr'   rK   rL   r(   rO   rP   s     @r   rm   zNindexed_slices_intersection_indices_and_values.<locals>.non_empty_intersection  so    		> &(WWHH%'AB&
" &(WWHH%'AB&
" !&&
 	
r   )r   r   rQ   r   r   r:   rR   rS   rT   rU   logical_andrW   rX   )r'   r(   rY   rZ   rc   rm   rC   rv   r   rK   rL   rO   rP   s   ``    @@@@@@@r   .indexed_slices_intersection_indices_and_valuesr      s*    NN1E..!<..!<*003*003#%&	
 #%&	
 ::
$$%79KLM "$*>!?!B
!
 !
F 77
+Q/ r   c                       fd}|S )a<  Decorator to add support for `tf.SparseTensor` and `tf.IndexedSlices` to
    a non-zero-preserving element-wise unary operator.

    There are requirements on the operator for this decorator to work correctly:

    - The operator must be element-wise
    - The operator must be unary (one input tensor and one output tensor)
    - The operator must return a tensor of the same shape.

    Additional arguments to the function (besides the input tensor) are
    supported. The returned result is a dense tensor and contains
    `default_value` outside of the indices of the input tensor.

    Args:
        default_value: The value to use outside of indices. It must be the value
        that the operator returns for zero values.
    Returns:
        Wrapped function that supports `tf.SparseTensor` and `tf.IndexedSlices`.
    c                 F     t        j                          fd       }|S )Nc                 >   t        | t        j                        rTt        |  | j                  g|i |      }t        |t        j                  |j                  j                              S t        | t        j                        r | j                  g|i |}t        j                  | j                  t        j                  |j                              }t        j                  |t        j                  | j                  d      |      S  | g|i |S )Nr5   )r"   r   r   r   r
   r   rg   r   IndexedSlicesfillr   tensor_scatter_nd_updaterQ   r   )r   argskwargssparse_outputsparse_output_valuesr   r   funcs         r   sparse_wrapperzGdensifying_unary.<locals>.wrap_densifying_unary.<locals>.sparse_wrapperB  s    !R__- 2tAHH6t6v6! '!GGM=+?+?+E+EF  Ar//0'+AHH'Ft'Fv'F$MMGGM+?+E+EF 22BNN199a8:N  +D+F++r   	functoolswraps)r   r   r   s   ` r   wrap_densifying_unaryz/densifying_unary.<locals>.wrap_densifying_unaryA  s&    			, 
	,( r   r   )r   r   s   ` r   densifying_unaryr   ,  s    *0 ! r   c                 B     t        j                          fd       }|S )a  Decorator to add support for `tf.SparseTensor` and `tf.IndexedSlices` to
    a zero-preserving element-wise unary operator.

    There are requirements on the operator for this decorator to work correctly:

    - The operator must be element-wise
    - The operator must be unary (one input tensor and one output tensor)
    - The operator must return a tensor of the same shape, and if it is a
      `tf.SparseTensor` or `tf.IndexedSlices`, the indices of the result must be
      the same. Therefore:
        - Reduction operations are not supported (e.g. `mean`).
        - Operations for which the result may be dense (e.g. `reciprocal`), or
          the sparse indices depend on the inputs are not supported (e.g.
          `clip`). This implies that `func(0)` must be 0.

    Additional arguments to the function (besides the input tensor) are
    supported as long as they cannot change the indices of the result. For
    instance,`round` is supported, but `clip` is not supported as
    `clip(x, 1.0, 2.0)` would always return a dense tensor.

    Note that if an input sparse tensor contains zero values, the indices and
    the zero values are preserved.

    Args:
        func: The function to wrap.
    Returns:
        Wrapped function that supports `tf.SparseTensor` and `tf.IndexedSlices`.
    c                 B   t        | t        j                        r t        |  | j                  g|i |      S t        | t        j
                        r?t        j
                   | j                  g|i || j                  | j                        S  | g|i |S r   )r"   r   r   r   r
   r   r   r   )r   r   r   r   s      r   r   z)elementwise_unary.<locals>.sparse_wrapperz  s    a)%aahh)H)H)HII2++,##QXX///AMM  +D+F++r   r   r   r   s   ` r   elementwise_unaryr   \  s(    < __T, , r   c                       fd}|S )a  Decorator to add support for `tf.SparseTensor` and `tf.IndexedSlices` to
    an element-wise binary operator such that the indices present in the result
    are the union of the indices in the two operand.

    The primary use case for this is the `add` and `subtract` operators.

    There are requirements on the operator for this decorator to work correctly:

    - The operator must be element-wise.
    - The operator must be binary (two input tensors and one output tensor).
    - Both inputs must be of the same shape or one input must be a scalar.
    - The output must be of the same shape as the (non scalar) inputs.
    - The indices of the output must be the union of the indices of the inputs.
      This implies that func(0, 0) must be 0. As a result, if one operand is
      dense or a scalar, then the result will be dense.

    Additional arguments to the function (besides the input tensors) are not
    supported.

    Note that if the result of the operation is zero at some indices, including
    because the operands were zero at these indices, the zeros and indices are
    preserved.

    Args:
        sparse_op: implementation of the operation for `tf.SparseTensor`. Must
            work if both of the operands are `tf.SparseTensor`s and can
            optionally work if one of the operand is a `tf.SparseTensor` and
            the other one is dense tensor, see `densify_mixed`.
        densify_mixed: if `True`, `sparse_op` does not support a mix of
            `tf.SparseTensor` and dense tensor or dense tensor with
            `tf.SparseTensor` and the `tf.SparseTensor` tensor is densified.
    Returns:
        Wrapped function that supports `tf.SparseTensor` and `tf.IndexedSlices`.
    c                 H     t        j                          fd       }|S )Nc                    t        | t        j                        rt        |t        j                        re| j                  |j                  u r't	        |  | j
                  |j
                              S  | |      }|j                  | j                         |S rt        |       } nt        |d      rt        |j                        dk(  rt        ||       } | |      S t        |t        j                        rHrt        |      }n]t        | d      rt        | j                        dk(  rt        | |      }  | |      S t        | t        j                        rt        |t        j                        r| j                  |j                  u rFt        j                   | j
                  |j
                        | j                  | j                        S t        | |j                  |j
                        \  }}}t        j                   ||      || j                        S t        j                  |       } n/t        |t        j                        rt        j                  |      } | |      S Nr   r   )r"   r   r   r   r   r
   r   r   r   hasattrlenr    r   r   r^   convert_to_tensor)	r'   r(   r   rD   x1_values_for_unionx2_values_for_uniondensify_mixedr   	sparse_ops	         r   r   zWelementwise_binary_union.<locals>.wrap_elementwise_binary_union.<locals>.sparse_wrapper  s   "boo.b"//2zzRZZ/1RYY		 :   "+2r!2((2% %,R0&r73s288}7I!A"b!IB(R00B0 (,B"2w/3rxx=A3E=b"E$R,,B 0 01b""2"23zzRZZ/!// BII6JJNN   D

BII	)//
  "//  3 3 *NN   --b1BB 0 01))"-B<r   r   )r   r   r   r   s   ` r   wrap_elementwise_binary_unionz?elementwise_binary_union.<locals>.wrap_elementwise_binary_union  s'    		?	  
?	 B r   r   )r   r   r   s   `` r   elementwise_binary_unionr     s    HCJ )(r   c                 B     t        j                          fd       }|S )a  Decorator to add support for `tf.SparseTensor` and `tf.IndexedSlices` to
    an element-wise binary operator such that the indices present in the result
    are the intersection of the indices in the two operand.

    The primary use case for this is the `multiply` operator.

    There are requirements on the operator for this decorator to work correctly:

    - The operator must be element-wise.
    - The operator must be binary (two input tensors and one output tensor).
    - Both inputs must be of the same shape or one input must be a scalar.
    - The output must be of the same shape as the (non scalar) inputs.
    - The indices of the output must be the intersection of the indices of the
      inputs. This implies that func(0, x) and func(x, 0) must be 0 for any x.
      As a result, if one operand is dense or a scalar, then the indices are the
      ones from the other operand.

    Additional arguments to the function (besides the input tensors) are not
    supported.

    Note that if the operands contains zero values at some common indices, the
    indices and the zero values are preserved.

    Args:
        func: The function to wrap.
    Returns:
        Wrapped function that supports `tf.SparseTensor` and `tf.IndexedSlices`.
    c           
      ~   t        | t        j                        r*t        |t        j                        r| j                  |j                  u r't	        |  | j
                  |j
                              S t        | |      \  }}}t        j                  | ||      | j                        }|j                  | j                         |S t        |d      rt        |j                        dk(  rt	        |  | j
                  |            S t	        |  | j
                  t        j                  || j                                    S t        |t        j                        r|t        | d      rt        | j                        dk(  rt	        | | |j
                              S t	        | t        j                  | |j                        |j
                              S t        | t        j                        rjt        |t        j                        r| j                  |j                  u rFt        j                   | j
                  |j
                        | j                  | j                        S t        | |      \  }}}t        j                   ||      || j                        S t        |d      rt        |j                        dk(  r<t        j                   | j
                  |      | j                  | j                        S t        j                   | j
                  t        j                  || j                              | j                  | j                        S t        |t        j                        rt        | d      rt        | j                        dk(  r<t        j                   | |j
                        |j                  |j                        S t        j                   t        j                  | |j                        |j
                        |j                  |j                        S  | |      S r   )r"   r   r   r   r   r
   rs   r   r   r   r   r   	gather_ndr   r   r<   )r'   r(   rv   r   r   r   r   s         r   r   z7elementwise_binary_intersection.<locals>.sparse_wrapper  sS   b"//*"boo.::+-b$ryy"))2LMM ?r2F	,22  __,66 F $$RXX.!M r7+s288}/A-b$ryy"2EFF .DBLLRZZ,HI  BOO,2w'3rxx=A+=)"d2ryy.ABB *R\\"bjj9299E  B,,-"b../::+++RYY		2BJJ  Gr2N	,22 ++66 -  r7+s288}/A++RYY+RZZ 
 ++RYY		"bjj(AB

 
 B,,-2w'3rxx=A+=''RYY'R^^ 
 ''2rzz2BII>JJNN  B|r   r   r   s   ` r   elementwise_binary_intersectionr     s+    < __T` `D r   c                 B     t        j                          fd       }|S )a  Decorator to add support for `tf.SparseTensor` and `tf.IndexedSlices` to
    element-wise binary division and related operators.

    This decorator is designed for operations related to the division of two
    operands (e.g. `divide`). It accepts `tf.SparseTensor` and
    `tf.IndexedSlices` for both the dividend and the divisor, but handles them
    differently based on whether they are the dividend or the divisor.

    - If the divisor is a `tf.SparseTensor` or `tf.IndexedSlices`, it is
      densified and the result is dense because the result contains Inf or Nan
      outside of the indices of the dividend.
    - If the dividend is a `tf.SparseTensor` or `tf.IndexedSlices` and the
      divisor is dense, it finds occurrences of zeros and NaNs in the divisor.
      The result may therefore have more indices than there were in the dividend
      to return correct values where the divisor was zero or NaN.
    - If the dividend is a `tf.SparseTensor` or `tf.IndexedSlices` and the
      divisor is a scalar, it does the division element-wise. Note that the
      result is incorrectly sparse if the scalar divisor is zero.

    Args:
        func: The function to wrap.
    Returns:
        Wrapped function that supports `tf.SparseTensor` and `tf.IndexedSlices`.
    c           	          t         t        j                        r(t        t        j                        rt                t              n t	        d      rt        j                        dk(  rt           j                              S t        j                  d      t        j                  j                        j                  s=t        j                  j                  t        j                  j                               fd} fd}t        j                   t        j"                        ||      S t        t        j                        rt              nt         t        j$                        rt        t        j$                        r,t        j&                          t        j&                        nt	        d      rt        j                        dk(  r<t        j$                    j                         j(                   j*                        S t        j                  d      t        j                  j                        j                  s=t        j                  j                  t        j                  j                              t        j"                  t-        t/        dj                  j0                                     fd} fd}t        j                   t        j"                        ||      S t        t        j$                        rt        j&                                S )	Nr   r   c            
      z    t          j                  t        j                  j                                    S r   )r   r
   r   r   r   r   r'   r(   s   r   func_for_x1_indiceszIelementwise_division.<locals>.sparse_wrapper.<locals>.func_for_x1_indices  s/    1RYYR0L M  r   c            
          t        j                        } t        |       \  }}}t        j                  | |t        j                  |            j
                        }|j                  j                         |S r   )r   rT   r3   r   r   r   r   r   )	x2_zeros_and_nan_indicesrD   r   _r   r   r'   r(   x2_zeros_and_nanss	        r   func_for_union_indiceszLelementwise_division.<locals>.sparse_wrapper.<locals>.func_for_union_indices  s    3588<M3N0
 < 8	)/ "$)  3 "R ? NN" ((2%r   r5   r6   c            	          t        j                    j                  t        j                  j                              j                  j
                        S r   )r   r   r
   r<   r   r   r   s   r   r   zIelementwise_division.<locals>.sparse_wrapper.<locals>.func_for_x1_indices  sA    !// BIIb"**,EFJJNN  r   c            	          t        j                  t        j                        d      } t        |       \  }}}t        j                   |t        j
                  |            |j                        S )Nr8   r6   )r   rS   rT   r^   r   r<   r   )r   rD   r   r   r   r'   r(   r   s       r   r   zLelementwise_division.<locals>.sparse_wrapper.<locals>.func_for_union_indices  sz    35::HH%67b40 D 8	)/  "//  3 "		"m < *NN  r   )r"   r   r   r   r   r   r   r   r
   rX   as_dtyper   
is_integerrU   rV   is_nanrW   
reduce_anyr   r   r   r   tupler;   r	   )r'   r(   r   r   r   r   s   ``  @r   r   z,elementwise_division.<locals>.sparse_wrapper  sf   b"//*"boo. %R($R( r7+s288}/A-b$ryy"2EFF )+Q%;;rxx0;;,.GG,>,>-rww~~b/A-)&* 77&78.+ 
 BOO, !$BB,,-"b../ ))"-))"- r7+s288}/A++RYY+RZZ 
 )+Q%;;rxx0;;,.GG,>,>-rww~~b/A-) )+)eArxx}}6M0N)%* 77&78.+ 
 B,,- %%b)BB|r   r   r   s   ` r   elementwise_divisionr   x  s+    4 __Ty yv r   r   )F)r   
tensorflowr   partialonesrh   rR   int8	ones_int8r+   
zeros_int8	ones_likern   r,   re   r   r   r    r)   r3   r^   rs   r   r   r   r   r   r   r   r   r   <module>r      s     IbggRWW5	IbggRWW5	Yrxxrww7
"""2<<rww?#)##BMMA
2$?>JZ1hQh-!`)Xi)XAHVr   