
    VhU^                     ,   d 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Z	ddl
mc mZ ddlmZ ddlmZmZmZm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m Z m!Z!m"Z" ddlm#Z#m$Z$m%Z%m&Z&m'Z'm(Z( ddl)m*Z* ddl+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4m5Z5 ddl6m7Z7 erddl8m9Z9 ejt                  ejv                  ejx                  ejz                  ej|                  ej~                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  gZPej                  ej                  ej                  ej                  ej                  ej                  gZWej                  gZYej                  ej                  ej                  ej                  ej                  gZ_ej                  ej                  ej                  ej                  ej                  gZei afi Zgd Zh eh         e       D  cg c]   }  e'|       r| j                  j                  " c} Zk ej                  d      d        Zm G d d      Zn en       Zo G d d      Zp G d de*      Zq G d de.      Zrd  Zsd! Ztd" Zud+d#Zvd+d$Zwd% Zxd+d&Zyd+d'Zzd+d(Z{ G d) d*e5      Z|yc c} w ),a  TorchDynamo support for __torch_function__ tensor subclasses.

This module implements support for tensor subclasses with __torch_function__ overrides.
A tensor subclass instance is represented as a TensorWithTFOverrideVariable, which handles
dispatching __torch_function__ on attribute accesses, method calls, and torch API calls.

Unsupported features:
- Triggering __torch_function__ on tensor subclass non-tensor custom attributes
- Graph breaking on mutating guardable tensor properties within a __torch_function__ context
  (can cause excessive recompiles in certain cases)
- Matching exact eager behavior of ignoring __torch_function__ objects in non-tensor
  argument positions of Torch API calls

Supported features:
- Static method implementations of __torch_function__ on custom objects (triggers on torch
  API calls with the object as any argument)
- Triggering __torch_function__ on torch API calls with tensor subclass arguments
- __torch_function__ calls on base tensor attribute access and method calls for tensor
  subclass instances
- Matches dispatch ordering behavior of eager __torch_function__ with subclass/object
  arguments in any position

See https://docs.google.com/document/d/1WBxBSvW3NXhRp9ncmtokJloMLCtF4AYNhJaffvHe8Kw/edit#heading=h.vacn73lozd9w
for more information on the design.

To enable subclass behavior, add your tensor subclass type to traceable_tensor_subclasses
in torch/_dynamo/config.py
    N)TYPE_CHECKING)Source)_get_overloaded_argsBaseTorchFunctionModeget_default_nowrap_functionsTorchFunctionMode)DeviceContext   )unimplemented)GuardBuilderinstall_guard)NoEnterTorchFunctionMode)
AttrSourceGlobalSourceTorchFunctionModeStackSource
TypeSource)class_has_getattributeclear_torch_function_mode_stackget_safe_global_namehas_torch_functionis_tensor_base_attr_getterset_torch_function_mode_stack   )VariableTracker)ConstantVariable)GenericContextWrappingVariable)LazyVariableTracker)TupleVariable)TensorSubclassVariableTensorVariable)UserDefinedObjectVariable)InstructionTranslatorc                    	
 d  G fddt               } t        j                  d      t        j                  d      	t        j                  dt        j                        t        j                  dt        j                        
 |        5  fdt        ffdt
        f	fdt        f
fdt        ffd	t        fg}|D ]!  \  }}|D ]  } ||       J t        |<    # 	fd
t        f
fdt        ffdt        fg}t        j                  t        j                  t        j                  h}|D ]3  \  }}|D ])  }||v r ||       J t        |   k7  s!t        |<   + 5 	 d d d        y # 1 sw Y   y xY w)Nc                       e Zd ZdZd fd	Zy)8populate_builtin_to_tensor_fn_map.<locals>.GetMethodModez
        Mode to extract the correct methods from torch function invocations
        (Used to get the correct torch.Tensor methods from builtins)
        Nc                 $    |xs i }| ||i |S N )selffunctypesargskwargsmost_recent_funcs        V/home/dcms/DCMS/lib/python3.12/site-packages/torch/_dynamo/variables/torch_function.py__torch_function__zKpopulate_builtin_to_tensor_fn_map.<locals>.GetMethodMode.__torch_function__   s"    \rF#(((    )r(   N)__name__
__module____qualname____doc__r0   )r.   s   r/   GetMethodModer%      s    	
	)r1   r6   r   )dtypec                      |       S r'   r(   )oinp0s    r/   <lambda>z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   s    qw r1   c                      |       S r'   r(   r9   inp0_ints    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   s    q{ r1   c                      |       S r'   r(   )r9   r:   inp1s    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   s    qt} r1   c                      |       S r'   r(   )r9   r>   inp1_ints    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   s    q8, r1   c                      | d      S Nr   r(   r=   s    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   s    q1~ r1   c                      | d      S Nr   r(   )r9   r@   s    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   s    !At* r1   c                      | d      S rF   r(   )r9   rB   s    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>       qH~ r1   c                      | d      S rD   r(   r=   s    r/   r;   z3populate_builtin_to_tensor_fn_map.<locals>.<lambda>   rH   r1   )r   torchonesint32un_ops
un_int_opsbin_opsbin_int_opstensor_and_int_opsBUILTIN_TO_TENSOR_FN_MAPoperatormatmulimatmulgetitemBUILTIN_TO_TENSOR_RFN_MAP)r6   setups_and_oplistssetup_fnop_listoprsetups_and_oplistsrskipsr:   r>   r@   rB   r.   s          @@@@@r/   !populate_builtin_to_tensor_fn_mapr^      s    
)- 
) ::a=D::a=Dzz!5;;/Hzz!5;;/H	  E'"J/$g.,k:%'9:
 "4 	@Hg @'333/?(,@	@ % &{3%'9:
 //8#3#3X5E5EF!4 	EHg E<'333#'?'CC4D-b1E	E3 E  E  Es   CF+FFc                      ddl m}   | d      S )Nr
   	unique_id!___prev_torch_function_mode_stack)bytecode_transformationra   r`   s    r/   get_prev_stack_var_namerd      s    3899r1   c                   B    e Zd Zd Zd Zd Zej                  d        Zy)"TorchFunctionModeStackStateManagerc                     g | _         y r'   )stackr)   s    r/   __init__z+TorchFunctionModeStackStateManager.__init__   s	    
r1   c                 ^    t         j                  j                         | _        t	                y r'   )rJ   	overrides _get_current_function_mode_stackrh   r   ri   s    r/   	__enter__z,TorchFunctionModeStackStateManager.__enter__   s    __EEG
')r1   c                 <    t        | j                         g | _        y r'   )r   rh   )r)   exc_type	exc_value	tracebacks       r/   __exit__z+TorchFunctionModeStackStateManager.__exit__   s    %djj1
r1   c              #      K   t         j                  j                         }t        | j                         	 d  t        |       y # t        |       w xY wwr'   )rJ   rl   rm   r   rh   )r)   prevs     r/   temp_restore_stackz5TorchFunctionModeStackStateManager.temp_restore_stack   s=     ??A%djj1	0)$/)$/s   4AA AAAN)	r2   r3   r4   rj   rn   rs   
contextlibcontextmanagerrv   r(   r1   r/   rf   rf      s+    * 0 0r1   rf   c                   N    e Zd Zd Zd Zd Zd Zd Zej                  d        Z
y)SymbolicTorchFunctionStatec           	         t         j                  j                         | _        t         j                  j	                          | _        d | _        t        j                          t        j                         | _        t        |      D ]>  \  }}| j                  j                  t        j                  |t!        |                   @ y Nsource)rJ   _C_is_torch_function_enabledtorch_function_subclass_enabled_is_torch_function_all_disabledtorch_function_mode_enabledcur_modeTorchFunctionModeStackVariableresetcollectionsdeque
mode_stack	enumerateappendr   creater   )r)   py_stackivals       r/   rj   z#SymbolicTorchFunctionState.__init__   s     05xx/R/R/T, 88:: 	( &,,.  	  ) 	FAsOO""#**37STU7VW	r1   c                 2    t        | j                        dkD  S rD   )lenr   ri   s    r/   in_torch_function_modez1SymbolicTorchFunctionState.in_torch_function_mode  s    4??#a''r1   c                 6    | j                   j                         S r'   )r   popri   s    r/   pop_torch_function_modez2SymbolicTorchFunctionState.pop_torch_function_mode  s    ""$$r1   c                 :    | j                   j                  |       y r'   )r   r   )r)   mode_vars     r/   push_torch_function_modez3SymbolicTorchFunctionState.push_torch_function_mode  s    x(r1   c                 x    | j                         5 }|j                  |||||      cd d d        S # 1 sw Y   y xY wr'   )_pop_mode_for_inliningcall_torch_function)r)   txfnr+   r,   r-   r   s          r/   call_torch_function_modez3SymbolicTorchFunctionState.call_torch_function_mode  s?    ((* 	Mh//BtVL	M 	M 	Ms   09c              #     K   | j                   }| j                         | _         	 | j                    | j                   }|| _         | j                  |       y # | j                   }|| _         | j                  |       w xY wwr'   )r   r   r   )r)   old_modemodes      r/   r   z1SymbolicTorchFunctionState._pop_mode_for_inlining  sm     ==446	0--==D$DM))$/ ==D$DM))$/s   "BA %B&A>>BN)r2   r3   r4   rj   r   r   r   r   rw   rx   r   r(   r1   r/   rz   rz      s7    #J(%)M 0 0r1   rz   c                       e Zd ZdZ e       ZdZd Zed        Z	edd       Z
edd       Zedd       Zed        Zed	        Zy
)r   z_Fake VT to use as a dummy object, indicating the presence of torch function mode stack mutationr   c                      || _         || _        y r'   r~   symbolic_stack)r)   r~   r   s      r/   rj   z'TorchFunctionModeStackVariable.__init__;  s    ,r1   c                     d| _         y rD   offset)clss    r/   r   z$TorchFunctionModeStackVariable.reset?  s	    
r1   c                 @   | j                   |j                  j                  vr| | t               |j                  j
                        }|j                  j                  j                  | j                   |       |j                  j                  j                  |       y y )Nr   )stack_value_singletonoutputside_effectsr   symbolic_torch_function_stater   track_mutablemutation)r   r   vars      r/   register_mutationz0TorchFunctionModeStackVariable.register_mutationC  sx    $$BII,B,BBx!??JJC II""001J1JCPII""++C0 Cr1   c           	          |j                   j                  }|r| j                  |d         ry | xj                  dz  c_        |j	                  dt        d t        | j                                      y )Nr   r   r}   )r   r   is_device_contextr   insertTorchFunctionModeVariabler   r   r   rh   s      r/   !register_device_context_insertionz@TorchFunctionModeStackVariable.register_device_context_insertionM  s_    00;;S**584JJ!OJLL)!=szzk!Jr1   c                     |j                   j                  }|r;| j                  |d         r&|j                          | xj                  dz  c_        y y y )Nr   r   )r   r   r   popleftr   r   s      r/   clear_default_devicez3TorchFunctionModeStackVariable.clear_default_device[  sD    00;;S**584MMOJJ!OJ 55r1   c                 V    t        | j                  t              xs | j                  d u S r'   )
isinstancevaluer	   r   s    r/   r   z0TorchFunctionModeStackVariable.is_device_contextb  s!    #))]3HsyyD7HHr1   c                      || j                   z   S r'   r   )r   inds     r/   get_mode_indexz-TorchFunctionModeStackVariable.get_mode_indexf  s    SZZr1   Nr   r"   )r2   r3   r4   r5   objectr   r   rj   classmethodr   r   r   r   staticmethodr   r   r(   r1   r/   r   r   *  s    i #H F-   1 1     I I    r1   r   c                   p     e Zd Zed        Zd fd	Zd Zd Zd Zd Z	ddZ
d Zdd	Zd
 Zd Zd Z xZS )r   c                     t        | t        t        f      xs^ t        |        xrP t	        j
                  | d      t        j                  k(  xr' t	        j
                  | d      t        j                  k(  S )Nrn   rs   )	
issubclassr   r	   r   inspectgetattr_staticr   rn   rs   )tys    r/    is_supported_torch_function_modez:TorchFunctionModeVariable.is_supported_torch_function_model  sm     "7GH 
&r** U&&r;7;L;V;VVU&&r:6:K:T:TT	
r1   c                 T    |t        |   |fi | || _        || _        || _        y r'   )superrj   r   cm_objr~   )r)   r   r~   r-   	__class__s       r/   rj   z"TorchFunctionModeVariable.__init__|  s0    GU-f-
r1   c                 V    | j                   sJ | j                   j                  |       y r'   )r~   reconstruct)r)   codegens     r/   r   z%TorchFunctionModeVariable.reconstruct  s     {{{(r1   c                 .    | j                   j                  S r'   )r   r3   ri   s    r/   module_namez%TorchFunctionModeVariable.module_name  s    zz$$$r1   c                 @    t        | j                        j                  S r'   )typer   r2   ri   s    r/   fn_namez!TorchFunctionModeVariable.fn_name  s    DJJ(((r1   c                 ,    t        | j                        S r'   )r   r   ri   s    r/   python_typez%TorchFunctionModeVariable.python_type  s    DJJr1   c           	      b    t        || t        || j                  | j                        ||||      S r'   )r   build_torch_function_fnr   r~   r)   r   r   r+   r,   r-   s         r/   r   z-TorchFunctionModeVariable.call_torch_function  s5    "#B

DKK@
 	
r1   c                     ddl m} t        | j                  t              rt        j                  d       S  |t         j                  j                        j                  || gi        t        j                  d       S Nr   )TorchInGraphFunctionVariable)
rJ   r   r   r   r   r   r   r   _push_on_torch_function_stackcall_function)r)   r   r   s      r/   enterzTorchFunctionModeVariable.enter  s[    7djj":;#**400$HH22	

-TFB
'&&t,,r1   c                     ddl m}  |t         j                  j                        j	                  |g i        t        j                  d       S r   )rJ   r   r   _pop_torch_function_stackr   r   r   )r)   r   r,   r   s       r/   exitzTorchFunctionModeVariable.exit  s<    7$UXX%G%GHVVB	
  &&t,,r1   c                     t         } |t        |j                  j                  |j                        |j
                               y r'   )r   r   r   import_sourcer3   r2   )r)   r   r   s      r/   reconstruct_typez*TorchFunctionModeVariable.reconstruct_type  s4    %

((7	
r1   c                      y)NTr(   ri   s    r/   supports_graph_breaksz/TorchFunctionModeVariable.supports_graph_breaks  s    r1   c                      y)NFr(   ri   s    r/   exit_on_graph_breakz-TorchFunctionModeVariable.exit_on_graph_break  s    r1   r'   r   )r2   r3   r4   r   r   rj   r   r   r   r   r   r   r   r   r   r   __classcell__r   s   @r/   r   r   k  sL    
 
)
%) 	
	--
r1   r   c                 >    t        t        j                  | i |      S r'   )_flatten_vtspytreearg_tree_leaves)r,   r-   s     r/   _get_all_argsr     s    ..??@@r1   c                    ddl m} ddlm} ddlm}  ||       } g }| r| j                         }|j                         s1|j                         t        t        t        fv r|j                          |j                         r]t        ||      r| j                  |j                         n5t        ||      r)| j                  |j                  j!                                |j#                  |       | r|S )Nr   )r   r   )ConstDictVariable)ListVariable)r   r   dictsr   listsr   r   is_realized	peek_typedictlisttuplerealizer   extenditemsvaluesr   )vtsr   r   r   r   vts         r/   r   r     s    !(#
*CF
WWY~~BLLNtT56I$IJJL>>"l+

288$B 12

288??,-b  Mr1   c                 R    t        | t        t        f      sJ | j                         S r'   )r   TensorWithTFOverrideVariabler!   r   r   s    r/   _get_subclass_typer    s&    c8:STUUU??r1   c                 &   t        |t        t        f      sJ t        |t              r|j                  |       S t        |t              rH|j                  xr t        |j                        }t        j                  | |j                         |      S y r'   )	r   r  r!   class_type_varr~   r   r   buildr   )r   r   r~   s      r/   _get_subclass_type_varr    sx    c8:STUUU#34!!"%%	C2	36
3:: 6$$R):FCC 
4r1   c                     dd l }d}	 t        j                  |j                         |      }||t	        |j
                  |      k7  z  }|S # t        $ r Y |S w xY w)Nr   F)rJ   r   r   r   getattrTensorAttributeError)r   r   namerJ   
overriddenattr_vals         r/   _is_attr_overiddenr    sd    J))#//*;TBh'%,,"===
   s   A A
 
	AAc           	          |||t        j                  | t        |            t        j                  | |      f}| j                  ||i       S r'   )r   r  r   inline_user_function_return)r   torch_function_typetorch_function_varr   r+   r,   r-   tf_argss           r/   r   r     sP     	
b%+.b&)G ))*<grJJr1   c                     ddl m} |j                  j                  }t	        ||      st        d       |xr t        t        |d      d      }t        j                  | ||      S )Nr   )FunctionTypez.Builtin/C++ torch function implementations NYIr0   __func__)	r+   r  r0   r  r   r   r   r   r  )r   r   r~   r  r*   s        r/   r   r     sW    "##,,DdL)FGX
:f6J#KZXF  T622r1   c                     t        d t        ||      D              }| j                  }|xr |j                  xs |j                  xr |j                         S )Nc              3   2   K   | ]  }t        |        y wr'   )r   ).0args     r/   	<genexpr>z.can_dispatch_torch_function.<locals>.<genexpr>  s      $'3s   )anyr   r   r   r   r   )r   r,   r-   has_overridden_argstf_states        r/   can_dispatch_torch_functionr%    s]     +8v+F  //HLH$L$L ,,R1P1P1Rr1   c           	      2   t        ||      }t        |D cg c]  }t        |      s| c}t              }t	        |D cg c]  }t        | |       c}      }| j                  j                         rC| j                  j                  | ||||      }t        |t              r|j                  t        u s|S |D ]=  }|j                  | ||||      }t        |t              r|j                  t        u r;|c S  t        d| d| d| d       yc c}w c c}w )zsGathers all args that are TensorWithTFOverrideVariable and dispatches based on the ordering in _get_overloaded_argsz*All __torch_function__ overrides for call z with args z and kwargs z returned NotImplementedN)r   r   r   r  r   r  r   r   r   r   r   r   NotImplementedr   r   )	r   r   r,   r-   all_argsr   overloaded_argsr+   ress	            r/   dispatch_torch_functionr+    s    T6*H* <$6s$;<O
 oVs1"c:VWE	''>>@..GGE4
 3 01cii>6QJ 
%%
 3 01cii>6QJ
 
4RDD6V\U]]uv3 	= Ws   DD Dc                   x     e Zd ZdZd fdZed        Zd Zd Zd Z	d Z
d fdZdd	Z	 	 	 	 	 	 d fd
Z xZS )r  zS
    Represents a tensor subclass instance with a __torch_function__ override.
    c                 P    |j                  d      | _        t        |   |i | y )Ntorch_function_fn)r   r.  r   rj   )r)   r,   r-   r   s      r/   rj   z%TensorWithTFOverrideVariable.__init__E  s'    !',?!@$)&)r1   c                     dd l }t        |j                        }|j                  d      |j                  u sJ d        | d||d|}|j                  |       |S )Nr   
class_typezBinvalid class type in TensorWithTFOverrideVariable.from_tensor_var)r.  r0  r(   )rJ   r   __dict__r   r  install_global)r   r   
tensor_varr0  r.  rJ   r-   r   s           r/   from_tensor_varz,TensorWithTFOverrideVariable.from_tensor_varI  se    j))*zz,'5<<7 	
P	
7 W$5*WPVW2
r1   c                     | j                  |      |j                  j                  vr6|j                  j                  | j                  |      | j                         y y r'   )global_mangled_class_namer   global_scopeinstall_global_unsafer0  r)   r   s     r/   r2  z+TensorWithTFOverrideVariable.install_globalU  sM     ))"-RYY5K5KKII++..r2DOO Lr1   c                     | j                   S r'   )r0  ri   s    r/   r   z(TensorWithTFOverrideVariable.python_type_  s    r1   c                 `    t        | j                  t        | j                  |                  S r|   )r   r0  r   r6  r9  s     r/   r
  z+TensorWithTFOverrideVariable.class_type_varb  s)    %OOL1O1OPR1S$T
 	
r1   c                 ^    t        |d| j                  j                   | j                        S )N__subclass_)r   r0  r2   r9  s     r/   r6  z6TensorWithTFOverrideVariable.global_mangled_class_nameg  s,    #+doo6678$//
 	
r1   c           	      T   dd l }|t        v rt        d| d       t        || |      rt        d| d       |j                  j
                  rt        |j                  |      r| j                  rFt        t        t        | j                  d      |      j                  t        j                               t        j                  |t!        |j                  |      j"                        }| j%                  ||t'        | j)                  |      g      | gi       S t*        | Y  ||      S )Nr   z
Accessing I on a tensor subclass with a __torch_function__ override is not supportedz&Accessing overridden method/attribute r   )rJ   banned_attrsr   r  r   torch_function_enabledhasattrr  r~   r   r   
make_guardr   FUNCTION_MATCHr   r  r  __get__r   r   r
  r   var_getattr)r)   r   r  rJ   get_fnr   s        r/   rF  z(TensorWithTFOverrideVariable.var_getattrl  s    	<TF"kl b$-8 ?P P
 99++d0K{{z$++{CTJUU$33
 %**2wu||T/J/R/RSF++t222678  7&r400r1   c           	      V    t        || j                  |      | j                  ||||      S r'   )r   r
  r.  r   s         r/   r   z0TensorWithTFOverrideVariable.call_torch_function  s5    "#""
 	
r1   c                    |j                   j                  rdd l}t        || |      rt	        d| d       | j
                  rEt        t        | j
                  d      |      }t        j                  | j                         |      }nd }t        |j                  |      }t        j                  |||      }t        ||| g|z   |      S t        	| A  ||||      S )Nr   zCalling overridden method r?  r   )r   rA  rJ   r  r   r~   r   r   r   r   r  r  r   r  r+  r   call_method)
r)   r   r  r,   r-   rJ   r~   r   func_varr   s
            r/   rJ  z(TensorWithTFOverrideVariable.call_method  s     99++!"dD10 7T T {{#Jt{{K$H$O..t/?/?/A4Hd3&,,R?H*2x$$OO7&r4v>>r1   )returnNr   )r,   zlist[VariableTracker]r-   zdict[str, VariableTracker]rL  r   )r2   r3   r4   r5   rj   r   r4  r2  r   r
  r6  rF  r   rJ  r   r   s   @r/   r  r  @  sh    * 	 	



!1F	
? &	?
 -? 
? ?r1   r  r   )}r5   r   rw   	functoolsr   rS   typingr   torch._CrJ   torch.utils._pytreeutils_pytreer   torch._guardsr   torch.overridesr   r   r   r   torch.utils._devicer	   excr   guardsr   r   	polyfillsr   r~   r   r   r   r   r   r   r   r   r   r   baser   constantr   ctx_managerr   lazyr   r   r   tensorr   r    user_definedr!   torch._dynamo.symbolic_convertr"   powmulrT   floordivtruedivmodaddltgtgeleneeqsubipowimulrU   	ifloordivitruedivimodiaddisubrO   and_or_xoriandixoriorrP   invertrN   lshiftrshiftilshiftirshiftrV   rQ   absposnegnot_length_hintrM   rR   rW   r^   __self__r2   r@  	lru_cacherd   rf   #torch_function_mode_stack_state_mgrrz   r   r   r   r   r  r  r  r   r   r%  r+  r  )r   s   0r/   <module>r     s  :         $ $    .  0 0 W W  " & 7 %   : 3 D LLLLOOLLLLKKKKKKKKKKKKLLMMMMMMMMMM-4 MMLLLLMMMMLL oo
 OOOO  LLLLLLMM
    5Ep " # +,
!"% KK T: :0 0, 'I&J #<0 <0~> _ > BQ > QhA4
D
K	3 Fy?> y?{s   4%L