
    bIgng                       d dl mZ d dlmZ d dlmZmZmZmZm	Z	m
Z
mZ 	 d	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd	Z	 d	 	 	 	 	 	 	 dd
Z	 d	 	 	 	 	 	 	 ddZy)    )annotations)MutableMapping)AttributeProto
GraphProto
ModelProtoTensorProtocheckerhelperutilsNc                   t        |       t        urt        d      t        |      t        urt        d      dd}ddd}g }|sg }|D ch c]  }|d   	 }} | ||        |||            }|r|j                  d|f        || j                  D 	cg c]  }	|	j
                   c}	|j                  D 	cg c]  }	|	j
                   c}	      }|r|j                  d|f        || j                  D 	cg c]  }	|	j
                   c}	|j                  D 	cg c]  }	|	j
                   c}	      }|r|j                  d	|f        || j                  D 	cg c]  }	|	j                  j
                   c}	|j                  D 	cg c]  }	|	j                  j
                   c}	       || j                  D 	cg c]  }	|	j                  j
                   c}	|j                  D 	cg c]  }	|	j                  j
                   c}	      z   }|r|j                  d
|f       |S c c}w c c}	w c c}	w c c}	w c c}	w c c}	w c c}	w c c}	w c c}	w )a  Checks whether there are name collisions between two graphs

    Returns a list of tuples where the first element represents the member containing overlapping names
    (One of: "node", "edge", "value_info", "initializer", "sparse_initializer"), and the
    second element contains a list of names that appear in both graphs on that category.

    Optionally, it takes an io_map, representing the output/inputs to be connected. It provided, overlapping
    present in the io_map argument will be ignored.
     g1 argument is not an ONNX graph g2 argument is not an ONNX graphc                B    t        t        |       t        |      z        S N)listset)c1c2s     I/var/www/html/answerous/venv/lib/python3.12/site-packages/onnx/compose.py_overlappingz-check_overlapping_names.<locals>._overlapping$   s    CGc"g%&&    c                    |
t               }g }| j                  D ]\  }|j                  D ]  }|dk7  s	||vs|j                  |         |j                  D ]  }|dk7  s	||vs|j                  |         ^ |S )N )r   nodeinputappendoutput)graphexcludeedgesnios         r   _edge_namesz,check_overlapping_names.<locals>._edge_names'   s    ?eG 	$AWW $7q/LLO$ XX $7q/LLO$		$ r      )r   edge
value_infoinitializersparse_initializer)r   	list[str]r   r*   returnr*   r   )r   r   r   zset[str] | Noner+   r*   )
typer   
ValueErrorr   r'   namer(   r)   valuesindices)
g1g2io_mapr   r$   resultelemio_map_inputsoverlapes
             r   check_overlapping_namesr9      s    Bxz!;<<Bxz!;<<' F)/0T!W0M0 ;r?KM,RSGvw'('A'"--)HQ!&&)HG |W-.(A(2>>*Ja166*JG }g./ " 5 5616 " 5 5616 	!#!6!67A7!#!6!67A7	G +W56M; 1 	()H 	)*J 	7677s6   H$H)9H.
8H3H8
H=I
:I
'Ic	                >  &' t        |       t        urt        d      t        |      t        urt        d      |s|r|r*t               }	|	j                  |        |	} t	        | |      } |r*t               }
|
j                  |       |
}t	        ||      }|D cg c]   }|r||d   z   n|d   |r||d   z   n|d   f" }}|D ch c]  }|d   	 }}|D ch c]  }|d   	 }}|D ci c]  \  }}||
 c}}'| j
                  D ch c]  }|j                   }}|j                  D ch c]  }|j                   }}|s|r|sG| j                  D cg c]  }|j                   }}|j                  D cg c]  }|j                   }}n|t        |      }| j                  D cg c]  }|j                  |v s|j                   }}|j                  D cg c]*  }|j                  |v s|j                  |v r|j                  , }}|sG| j
                  D cg c]  }|j                   }}|j
                  D cg c]  }|j                   }}n|t        |      }| j
                  D cg c]*  }|j                  |v s|j                  |v r|j                  , }}|j
                  D cg c]  }|j                  |v s|j                   }}t        |      t        | j                        k  s!t        |      t        | j
                        k  rDt        j                  t        j                  |             }|j                  ||      j                  } t        |      t        |j                        k  s!t        |      t        |j
                        k  rDt        j                  t        j                  |            }|j                  ||      j                  }|D ]+  \  }}||vrt        d| d      ||vst        d| d	       t!        | ||      }t        |      dkD  r/|d   \  }} t        d
| ddj#                  |       z   dz   dz         t               }!|!j$                  j'                  | j$                         t        |!j$                        }"|!j$                  j'                  |j$                         t        |!j$                        }#d&'fd& &|!|"|#       |rt        |      }|!j                  j'                  | j                  D cg c]  }|j                  |v s| c}       |!j                  j'                  |j                  D cg c]  }|j                  |v s| c}       ng|!j                  j'                  | j                         |!j                  j'                  |j                  D cg c]  }|j                  |vs| c}       |rt        |      }|!j
                  j'                  | j
                  D cg c]  }|j                  |v s| c}       |!j
                  j'                  |j
                  D cg c]  }|j                  |v s| c}       ng|!j
                  j'                  | j
                  D cg c]  }|j                  |vs| c}       |!j
                  j'                  |j
                         |!j(                  j'                  | j(                         |!j(                  j'                  |j(                  D $cg c]  }$|$j                  |vs|$ c}$       |!j*                  j'                  | j*                         |!j*                  j'                  |j*                  D $cg c]  }$|$j,                  j                  |vr|$ c}$       |!j.                  j'                  | j.                         |!j.                  j'                  |j.                  D %cg c]  }%|%j                  |vs|% c}%       ||n&dj#                  | j                  |j                  g      |!_        |Zd| j                   d|j                   d| j                  z   dz   | j0                  z   dz   |j                  z   dz   |j0                  z   }||!_        |!S c c}w c c}w c c}w c c}}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}w c c}$w c c}$w c c}%w )a  Combines two ONNX graphs into a single one.

    The combined graph is defined by connecting the specified set of outputs/inputs. Those inputs/outputs
    not specified in the io_map argument will remain as inputs/outputs of the combined graph.

    Arguments:
        g1 (GraphProto): First graph
        g2 (GraphProto): Second graph
        io_map (list of pairs of string): The pairs of names [(out0, in0), (out1, in1), ...]
                                          representing outputs of the first graph and inputs of the second
                                          to be connected
        inputs (list of string): Optional list of inputs to be included in the combined graph
                                 By default, all inputs not present in the ``io_map`` argument will be
                                 included in the combined model
        outputs (list of string): Optional list of outputs to be included in the combined graph
                                  By default, all outputs not present in the ``io_map`` argument will be
                                  included in the combined model
        prefix1 (string): Optional prefix to be added to all names in g1
        prefix2 (string): Optional prefix to be added to all names in g2
        name (string): Optional name for the combined graph
                       By default, the name is g1.name and g2.name concatenated with an undescore delimiter
        doc_string (string): Optional docstring for the combined graph
                             If not provided, a default docstring with the concatenation of g1 and g2 docstrings is used

    Returns:
        GraphProto
    r   r   prefixr   r%   zOutput z is not present in g1zInput z is not present in g2z=Cant merge two graphs with overlapping names. Found repeated z names: , 
zYConsider using ``onnx.compose.add_prefix`` to add a prefix to names in one of the graphs.c           	     n   t        ||      D ]  }| j                  |   }|j                  D ]Q  }|j                  t        j
                  k(  s! |j                  dt        |j                  j                               S t        |j                        D ]  \  }}|	v s	|   |j                  |<     y Nr   )
ranger   	attributer,   r   GRAPHglen	enumerater   )
	sub_graphstartendnode_idxr   attrindexname_
connect_ioreversed_io_maps
           r   rN   z merge_graphs.<locals>.connect_io   s    eS) 	?H>>(+D <99 4 44tvvq#dffkk*:;< !*$** 5 ?uO+(7(>DJJu%?	?r   _zGraph combining  and z

)rG   r   rH   intrI   rR   r+   None)r,   r   r-   CopyFromadd_prefix_graphr   r.   r   r   rE   r   	Extractorr
   
make_modelextract_modelr   r9   joinr   extendr(   r)   r/   r'   
doc_string)(r1   r2   r3   inputsoutputsprefix1prefix2r.   r[   g1_copyg2_copyioio_map_g1_outsio_map_g2_insout_namein_namer#   g1_outsr"   g2_ins	g1_inputs	g2_inputs	input_set
g1_outputs
g2_outputs
output_sete1e2g1_out_name
g2_in_nameoverlapping_namescategorynamesrD   g2_nodes_beging2_nodes_endinitvirN   rO   s(                                         @@r   merge_graphsrz   X   s   L Bxz!;<<Bxz!;<< ' lGR B!"W5B lGR B!"W5B 

  $+"Q%1#*"Q%1
 
 '--be-N-%+,rRU,M,BHI->Xww(IO!yy)!qvv)G) hh'aff'F' )+2A2I2)+2A2I2FI)+IAQVVy5HIII 66Y&!&&M*A I  *,))4Q!&&4J4*,))4Q!&&4J4WJ 66Z'166^+C J 
 +-))LQqvv7K!&&LJLy>CM)S_s299~-M!2!22!67B!!)Z8>>By>CM)S_s299~-M!2!22!67B!!)Z8>>B $* IZg%w{m3HIJJV#vj\1FGHH	I 0B?
!+A.%&Zx1ii  j	j
 	
 	AFFMM"''[NFFMM"''qvv;L	? q.,/K		288Caqvv/BCD	288Caqvv/BCD	rxx 	288Kaqvv]/JKL\
	BIIFq:1EFG	BIIFq:1EFG	BIINq~1MNO			"MM(MM..K$DII],JK  5 56 --	
{{}4 	
 LL&LLbmmTrwwm7STU%T388RWWbgg4F+GAFrwwiuRWWIR8gg mm 	
 gg  mm 	 ALHS
 .,I)'
 32 J 54
 Mj DC L GFN
 	L
	
 Us   %b+b0b5+b:
c -cc
:c)c=c/cc?c#./c(-c-c-c2*c2c7,c7 c<c<d#dd%dd(d d4d!d7ddc           
        t        |       t        urt        d      t        |      t        urt        d      | j                  |j                  k7  r&t        d| j                   d|j                   d      | j                  }i }t	        | j
                        t	        |j
                        z   }|D ]m  }|j                  |v rD||j                     }|j                  |k7  s0t        d| j
                   d|j
                         |j                  ||j                  <   o |s|r|r*t               }|j                  |        |} t        | |      } |r*t               }|j                  |       |}t        ||      }|D cg c]   }|r||d	   z   n|d	   |r||d
   z   n|d
   f" }}t        | j                  |j                  |||||      }t        j                  ||	|
||||      }i }| j                  D ]  }|j                  ||j                   <    |j                  D ]q  }|j                   |v rH||j                      }||j                  k7  s0t        d|j                    d| d|j                   d      |j                  ||j                   <   s t        j"                  ||       t	        | j$                  D ch c]  }|j&                   c}|j$                  D ch c]  }|j&                   c}z        }|rt        ddj)                  |      z         |j$                  j+                  | j$                         |j$                  j+                  |j$                         t-        j.                  |       |S c c}w c c}w c c}w )a=  Combines two ONNX models into a single one.

    The combined model is defined by connecting the specified set of outputs/inputs.
    Those inputs/outputs not specified in the io_map argument will remain as
    inputs/outputs of the combined model.

    Both models should have the same IR version, and same operator sets imported.

    Arguments:
        m1 (ModelProto): First model
        m2 (ModelProto): Second model
        io_map (list of pairs of string): The pairs of names [(out0, in0), (out1, in1), ...]
                                          representing outputs of the first graph and inputs of the second
                                          to be connected
        inputs (list of string): Optional list of inputs to be included in the combined graph
                                 By default, all inputs not present in the ``io_map`` argument will be
                                 included in the combined model
        outputs (list of string): Optional list of outputs to be included in the combined graph
                                  By default, all outputs not present in the ``io_map`` argument will be
                                  included in the combined model
        prefix1 (string): Optional prefix to be added to all names in m1
        prefix2 (string): Optional prefix to be added to all names in m2
        name (string): Optional name for the combined graph
                       By default, the name is g1.name and g2.name concatenated with an undescore delimiter
        doc_string (string): Optional docstring for the combined graph
                             If not provided, a default docstring with the concatenation of g1 and g2 docstrings is used
        producer_name (string): Optional producer name for the combined model. Default: 'onnx.compose'
        producer_version (string): Optional producer version for the combined model. Default: "1.0"
        domain (string): Optional domain of the combined model. Default: ""
        model_version (int): Optional version of the graph encoded. Default: 1

    Returns:
        ModelProto
    z m1 argument is not an ONNX modelz m2 argument is not an ONNX modelzIR version mismatch z != z-. Both models should have the same IR versionzPCan't merge two models with different operator set ids for a given domain. Got: rQ   r;   r   r%   )r\   r]   r.   r[   )producer_nameproducer_versiondomainmodel_versionopset_imports
ir_versionzaCan't merge models with different values for the same model metadata property. Found: property = z, with values .zPCan't merge models with overlapping local function names. Found in both graphs: r=   )r,   r   r-   r   r   opset_importr~   versionrT   
add_prefixrz   r   r
   rW   metadata_propsvaluekeyset_model_props	functionsr.   rY   	MergeFromr	   check_model)m1m2r3   r\   r]   r^   r_   r.   r[   r|   r}   r~   r   r   opset_import_mapr   entryfound_versionm1_copym2_copyrb   r   modelmodel_props
meta_entryr   ffunction_overlaps                               r   merge_modelsr     s   b Bxz!;<<Bxz!;<<	}}%"2==/bmm_ E; ;
 	
 J13)D,AAM 	;<<++,U\\:M}}- OO,E"//1BD 
 .3]]U\\*	; ' lGR BBw/B lGR BBw/B 

  $+"Q%1#*"Q%1
 
 

E #)##E K'' 7
&0&6&6JNN#7'' 	;
>>[(
/E
((( **4..)9weT^TdTdSeefh 
 +5*:*:K
'	; 5+. &A&",,)GQ!&&)GG &(,		2B(CD
 	
 
OObll+	OObll+Lq
Z 	')Gs   %N N$N

c
                `   t        |       t        urt        d      |st               }
|
j                  |        n| }
dd}|	i }	|rK|
j                  D ]<  }|j
                  D ]  } |||      |	|<    |j                  D ]  } |||      |	|<    > |r1|
j
                  D ]"  } |||j                        |	|j                  <   $ |r1|
j                  D ]"  } |||j                        |	|j                  <   $ |r`|
j                  D ]Q  } |||j                        |_        |j                  D ](  }|j                  st        |j                  |d|	       * S |r|
j                  D ]"  } |||j                        |	|j                  <   $ |
j                  D ]j  } |||j                  j                        |	|j                  j                  <    |||j                  j                        |	|j                  j                  <   l |r1|
j                  D ]"  } |||j                        |	|j                  <   $ |
j                  D ]  }t!        |j                        D ])  \  }}|j                  |   |	v s|	|   |j                  |<   + t!        |j
                        D ])  \  }}|j
                  |   |	v s|	|   |j
                  |<   +  |
j
                  D ]%  }|j                  |	v s|	|j                     |_        ' |
j                  D ]%  }|j                  |	v s|	|j                     |_        ' |
j                  D ]%  }|j                  |	v s|	|j                     |_        ' |
j                  D ]  }|j                  j                  |	v r(|	|j                  j                     |j                  _        |j                  j                  |	v s\|	|j                  j                     |j                  _         |
j                  D ]%  }|j                  |	v s|	|j                     |_        ' |
S )a  Adds a prefix to names of elements in a graph: nodes, edges, inputs, outputs,
    initializers, sparse initializer, value infos.

    It can be used as a utility before merging graphs that have overlapping names.
    Empty names are not prefixed.

    Arguments:
        graph (GraphProto): Graph
        prefix (str): Prefix to be added to each name in the graph
        rename_nodes (bool): Whether to prefix node names
        rename_edges (bool): Whether to prefix node edge names
        rename_inputs (bool): Whether to prefix input names
        rename_outputs (bool): Whether to prefix output names
        rename_initializers (bool): Whether to prefix initializer and sparse initializer names
        rename_value_infos (bool): Whether to prefix value info names
        inplace (bool): If True, mutates the graph directly.
                        Otherwise, a copy will be created
        name_map: (Dict): shared name_map in subgraph

    Returns:
        GraphProto
    #graph argument is not an ONNX graphc                ,    t        |      dkD  r| |z   S |S r@   )rE   )r<   r.   s     r   	_prefixedz#add_prefix_graph.<locals>._prefixed  s     #D	Av}747r   T)inplacename_map)r<   strr.   r   r+   r   )r,   r   r-   rT   r   r   r   r.   rB   rD   rU   r(   r)   r/   r0   r'   rF   )r   r<   rename_nodesrename_edgesrename_inputsrename_outputsrename_initializersrename_value_infosr   r   rD   r   r!   r8   r   rB   rx   sparse_initr"   r   input_in_descout_descr(   r)   r'   s                             r   rU   rU     s   D E{*$>??L	

58  	3AWW 3'23XX 3'23	3 WW 	AE#,VUZZ#@HUZZ 	AXX 	AE#,VUZZ#@HUZZ 	A  	Avqvv.AF[[ 	;;$!VTH	 MM 	?D"+FDII">HTYY	?// 	K09**//1H['',,- 2;++002H[((--.		 \\ 	AE#,VUZZ#@HUZZ 	A VV ."188, 	/IAvxx{h&&v.	/ #177+ 	.IAvwwqzX%%f-
	.	. 77 2<<8##GLL1GL2 HH 4==H$$X]]3HM4 }} :x''(8(89K:  22 X$$))X5-56H6O6O6T6T-U%%*%%**h6.67I7Q7Q7V7V.W&&+	X ll 8
??h&&z7JO8 Hr   c
                2   t        |       t        urt        d      |	st               }
|
j                  |        |
} t	        | j
                  |||||||d	       |ri }| j                  D ]'  }||j                  z   }|||j                  <   ||_        ) | j                  D ]6  }|j                  D ]%  }|j                  |v s||j                     |_	        ' 8 | j
                  j                  D ]%  }|j                  |v s||j                     |_	        ' | S )a  Adds a prefix to names of elements in a graph: nodes, edges, inputs, outputs,
    initializers, sparse initializer, value infos, and local functions.

    It can be used as a utility before merging graphs that have overlapping names.
    Empty names are not _prefixed.

    Arguments:
        model (ModelProto): Model
        prefix (str): Prefix to be added to each name in the graph
        rename_nodes (bool): Whether to prefix node names
        rename_edges (bool): Whether to prefix node edge names
        rename_inputs (bool): Whether to prefix input names
        rename_outputs (bool): Whether to prefix output names
        rename_initializers (bool): Whether to prefix initializer and sparse initializer names
        rename_value_infos (bool): Whether to prefix value info nanes
        rename_functions (bool): Whether to prefix local function names
        inplace (bool): If True, mutates the model directly.
                        Otherwise, a copy will be created

    Returns:
        ModelProto
    #model argument is not an ONNX modelT)r   r   r   r   r   r   r   )
r,   r   r-   rT   rU   r   r   r.   r   op_type)r   r<   r   r   r   r   r   r   rename_functionsr   m
f_name_mapr   
new_f_namer!   s                  r   r   r   "  s    D E{*$>??L	

5!!#%/-
 
 	 A!&&J!+JqvvAF	   	6AVV 699
* *199 5AI6	6
 !! 	2AyyJ&&qyy1		2 Lr   c                H   t        |       t        urt        d      |st               }|j                  |        n| }|j                  D cg c]  }|j
                   }}|j                  D ]p  }t        |j                        D ]  \  }}||v s|d| z   |j                  |<   ! t        |j                        D ]  \  }}	|	|v s|	d| z   |j                  |<   ! r |j
                  dz   }
|j                  j                  t        j                  dg |
g|
 dt        j                  |
 dt        j                  dg|g      	             t        t!        |j                              D ]'  }|j                  j#                  d
      }|j
                  d| z   }|j                  j                  t        j                  d||
g|j
                  gd|j
                                |j                   j$                  j&                  j(                  D cg c]  }|j*                   }}|j-                  |d       |j                  j                  t        j.                  |j
                  |j                   j$                  j0                  |             * |S c c}w c c}w )aE  Inserts an extra dimension with extent 1 to each output in the graph.

    Inserts an Unsqueeze node for each output. It can be used as a utility before merging graphs,
    for example when the second one expects a batch dimension.

    Arguments:
        graph (GraphProto): Graph
        dim_idx (int): Index of the dimension to be inserted.
                       A negative value means counting dimensions from the back.
        inplace (bool): If True, mutates the model directly.
                        Otherwise, a copy will be created

    Returns:
        GraphProto
    r   _collapsed_dim__expand_out_dim_idxConstantz	-constantz-valuer%   )r.   	data_typedimsvals)r\   r]   r.   r   r   	Unsqueezez
unsqueeze-)r\   r]   r.   )r,   r   r-   rT   r   r.   r   rF   r   r   r
   	make_nodemake_tensorr   INT64rA   rE   poptensor_typeshapedim	dim_valueinsertmake_tensor_value_info	elem_type)r   dim_idxr   rD   r   orig_out_namesr!   r"   outinpexpand_dim_krP   r#   prev_outputd	new_shapes                   r   expand_out_dim_graphr   l  sj   ( E{*$>??L	

5019ffkk9N9VV ?) 	@FAsn$!ogY$??	@  ( 	?FAsn$ _WI#>>
	?	? 6611LFFMM!N >+$$$~V,%++ 		
& 3qxx=! 
HHLLOff	::	#\2!!&&*		
 +,&&*<*<*B*B*F*FGQQ[[G	G!$	))**44i	

$ Ha :R Hs   JJc                    t        |       t        urt        d      |st               }|j                  |        |} t	        | j
                  |d       | S )aE  Inserts an extra dimension with extent 1 to each output in the graph.

    Inserts an Unsqueeze node for each output. It can be used as a utility before merging graphs,
    for example when the second one expects a batch dimension.

    Arguments:
        model (ModelProto): Model
        dim_idx (int): Index of the dimension to be inserted.
                       A negative value means counting dimensions from the back.
        inplace (bool): If True, mutates the model directly.
                        Otherwise, a copy will be created

    Returns:
        ModelProto
    r   T)r   )r,   r   r-   rT   r   r   )r   r   r   r   s       r   expand_out_dimr     sS    ( E{*$>??L	

5
 Lr   r   )r1   r   r2   r   r3   zlist[tuple[str, str]] | Noner+   zlist[tuple[str, list[str]]])NNNNNN)r1   r   r2   r   r3   list[tuple[str, str]]r\   list[str] | Noner]   r   r^   
str | Noner_   r   r.   r   r[   r   r+   r   )
NNNNNNzonnx.compose.merge_modelsz1.0r   r%   )r   r   r   r   r3   r   r\   r   r]   r   r^   r   r_   r   r.   r   r[   r   r|   r   r}   r   r~   r   r   z
int | Noner+   r   )TTTTTTFN)r   r   r<   r   r   bool | Noner   r   r   r   r   r   r   r   r   r   r   r   r   zdict[str, str] | Noner+   r   )TTTTTTTF)r   r   r<   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r+   r   )F)r   r   r   rR   r   r   r+   r   )r   r   r   rR   r   r   r+   r   )
__future__r   typingr   onnxr   r   r   r   r	   r
   r   r9   rz   r   rU   r   r   r    r   r   <module>r      s   # !   LPBB"B,HB BR  $ $!@@@ "@ 	@
 @ @ @ @ @ @N  $ $! ;#( !OOO "O 	O
 O O O O O O !O O O Oj !% $!%"&'+&* &*rrr r 	r
 r  r %r $r r $r rp !% $!%"&'+&*$( GGG G 	G
 G  G %G $G "G G GZ !MMM M 	Mf !!!! ! 	!r   