
    ip                     H   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Zd dlmZ d dl	m
Z
mZ d dlmZmZ d dlZd dlZd dlZd dlZd dlmZmZ d dlmZ d dlmZ 	 d dlZ ej8                         dk7  rd dlZ e       r,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'm(Z(m)Z)m*Z*m+Z+ d dl,m-Z- dddZ. e/ej`                  ejb                  z         Z2 e/ej`                  ejf                  z   ejb                  z   dz         Z4ddiddiddiddiddiddiddidZ5dZ6ddjo                  e5jq                                dZ9 G d  d!      Z: G d" d#      Z;d$e<dz  d%efd&Z=d'e>e<   dz  d%e?fd(Z@d3d)e<dz  d%e>e?   fd*ZAd+e<d,e>e?   d-e?d%e<fd.ZBd%e<fd/ZCeDd0k(  r
 e;d12       yy# e$ r Y Dw xY w)4    N)AsyncIterator)	AnnotatedAny)urljoinurlparse)AsyncInferenceClientChatCompletionStreamOutput)GenerationConfig)is_rich_availableWindows)filesize)Console)Live)Markdown)	BarColumnProgressProgressColumn
TextColumnTimeElapsedColumn)Text	localhosti@  )hostnameportz .!\"#$%&'()*+,\-/:<=>?@[]^_`{|}~textz5There is a Llama in my lawn, how can I get rid of it?zyWrite a Python function that integrates any Python function f(x) numerically over an arbitrary interval [x_start, x_end].z4How many helicopters can a human eat in one sitting?z4Count to 10 but skip every number ending with an 'e'zWhy aren't birds real?z2Why is it important to eat socks after meditating?z$Which number is larger, 9.9 or 9.11?)llamacode
helicopternumbersbirdssocksnumbers2a  

**TRANSFORMERS CHAT INTERFACE**

Chat interface to try out a model. Besides chatting with the model, here are some basic commands:
- **!help**: shows all available commands (set generation settings, save chat, etc.)
- **!status**: shows the current status of the model and generation settings
- **!clear**: clears the current conversation and starts a new one
- **!exit**: closes the interface
am  

**TRANSFORMERS CHAT INTERFACE HELP**

Full command list:
- **!help**: shows this help message
- **!clear**: clears the current conversation and starts a new one
- **!status**: shows the current status of the model and generation settings
- **!example {NAME}**: loads example named `{NAME}` from the config and uses it as the user input.
Available example names: `z`, `a#  `
- **!set {ARG_1}={VALUE_1} {ARG_2}={VALUE_2}** ...: changes the system prompt or generation settings (multiple
settings are separated by a space). Accepts the same flags and format as the `generate_flags` CLI argument.
If you're a new user, check this basic flag guide: https://huggingface.co/docs/transformers/llm_tutorial#common-options
- **!save {SAVE_NAME} (optional)**: saves the current chat and settings to file by default to
`./chat_history/{MODEL_ID}/chat_{DATETIME}.yaml` or `{SAVE_NAME}` if provided
- **!exit**: closes the interface
c                       e Zd ZdededefdZdee   deeeez  dz  f   fdZ	defd	Z
d
 ZdefdZdedefdZddededefdZddefdZdefdZdefdZy)RichInterfacemodel_iduser_idbase_urlc                 L    t               | _        || _        || _        || _        y N)r   _consoler$   r%   r&   )selfr$   r%   r&   s       f/var/www/vps2.regionflexible.com/Desarrollo/venv/lib/python3.12/site-packages/transformers/cli/chat.py__init__zRichInterface.__init__k   s     	      streamreturnNc           	      P  K   | j                   j                  d| j                   d       t        | j                   d      5 }d}d}t	        j                         }d }| d {   2 3 d {   }|j
                  d   j                  j                  }t        |j
                  d   d|      }t        |dd       }	|	t        |	d	|      }|set        j                  d
d|      }||z  }g }
|j                         D ]G  }|
j                  |       |j                  d      r|
j                  d       7|
j                  d       I t        dj                  |
      j!                         d      }|j#                  |d       7 !7 6 	 d d d        n# 1 sw Y   nxY wt	        j                         z
  }|dkD  rKdkD  rF||z  }| j                   j                          | j                   j                  d| d|dd|dd       | j                   j                          fS w)Nz[bold blue]<z>:   )consolerefresh_per_second r   finish_reasonusagecompletion_tokensz<(/*)(\w*)>z\<\1\2\>z```
z  
zgithub-dark)
code_themeT)refreshz[dim]z tokens in z.1fzs (z tok/s)[/dim])r)   printr$   r   timechoicesdeltacontentgetattrresub
splitlinesappend
startswithr   joinstripupdate)r*   r.   liver   r7   
start_timer5   tokenoutputsr6   lineslinemarkdownelapsedtok_per_secs                  r+   stream_outputzRichInterface.stream_outputq   s    l4==/<=$--A> .	4$D !J(,M%+| )4 )4e--*0088 'a(8/= Yw5$(/7JL](^% &&gF  OO- -DLL&u- T*V,- $BGGEN$8$8$:}U Hd3S  , )4|.	4 .	4 .	4` ))+
*Q;,q0+g5KMM!MM%(9':+gc]RUVabeUffs tu]""sP   AH& F#F$F(F
,F-F
0DFF

F	H&FBH&c                     | j                   j                  d| j                   d      }| j                   j                          |S )z!Gets user input from the console.[bold red]<z>:
)r)   inputr%   r;   )r*   rU   s     r+   rU   zRichInterface.input   s8    ##k$,,t$DEr-   c                 8    | j                   j                          y)zClears the console.N)r)   clear)r*   s    r+   rW   zRichInterface.clear   s    r-   r   c                     | j                   j                  d| j                   d|        | j                   j                          y)z%Prints a user message to the console.rT   z>:[/ bold red]
N)r)   r;   r%   )r*   r   s     r+   print_user_messagez RichInterface.print_user_message   s6    k$,,7GvNOr-   colorc                 z    | j                   j                  d| d|        | j                   j                          y)z,Prints text in a given color to the console.z[bold ]N)r)   r;   )r*   r   rZ   s      r+   print_colorzRichInterface.print_color   s1    fUG1TF34r-   messagedefaultc                     |rdnd}| j                   j                  d| d| d      }| j                   j                          |j                         j	                         }|s|S |dv S )zFDisplays a yes/no prompt to the user, returning True for confirmation.zY/nzy/Nz[bold yellow]z (z): >   yyes)r)   rU   r;   rG   lower)r*   r^   r_   default_hintresponses        r+   confirmzRichInterface.confirm   sf     'uU==&&wir,s'ST>>#))+N<''r-   minimalc                     | j                   j                  t        |rt        nt                     | j                   j                          y)z'Prints the help message to the console.N)r)   r;   r   HELP_STRING_MINIMALHELP_STRING)r*   rg   s     r+   
print_helpzRichInterface.print_help   s.    HG%8UVr-   modelc           
         t        j                  | j                  j                  d       ddid      }|j	                           G d dt
              }dd	d
dd| j                  j                  t              dz   dz   k\  fd}t        t        d      t        d       |       t               | j                        }|j                   |d      d       }d}t        || j                  d      5  |j                         D ]  }|r|j!                  d      st#        j$                  |dd        }	|	j'                  d      }
|
dk(  r|	j'                  dd      } n|
dk(  rt)        |	j'                  dd            |
d k(  s|	j'                  d!      }|	j'                  d"      } ||      }|r2|d#k(  rd$nd%}|j+                  |||d&   |j'                  d'      |(       |j+                  ||d)d *        d d d        |r)| j                  j-                  t/        d+ d,             n(| j                  j-                  t/        d+ d-             | j                  j-                          y # 1 sw Y   wxY w).N/z/load_modelrl   T)jsonr.   c                       e Zd Zd Zy)3RichInterface.print_model_load.<locals>.StatsColumnc                    |j                   st        d      S |j                  j                  d      dk(  rt	        j
                  t        |j                              }t	        j
                  t        |j                               }|j                  r,dt	        j
                  t        |j                               dnd}|j                  6dt        |j                  dz         dt        |j                  dz        d}nd}t        | d	| | | d
      S t        t        |j                         d	t        |j                                S )Nr4   unitbytesz  z/s<   :02drn   zprogress.download)style)
totalr   fieldsgetr   decimalint	completedspeedtime_remaining)r*   taskdonetotr   etas         r+   renderz:RichInterface.print_model_load.<locals>.StatsColumn.render   s   zz8O;;??6*g5#++C,?@D"**3tzz?;CJN**b!1!1#djj/!B C2FZ\E**6 "3t':':b'@#A"B!CH[H[^`H`DabeCfg 4&#ugcU ;CVWWs4>>231S_4EFGGr-   N)__name__
__module____qualname__r    r-   r+   StatsColumnrq      s    Hr-   r   zLoading processorzLoading configzDownloading fileszLoading into memory)	processorconfigdownloadweights   F   c                 >    j                  | |       }r d| S |S )Nu     →  )r{   )	stage_key
stage_textrl   show_model_prefixstage_labelss     r+   _labelz.RichInterface.print_model_load.<locals>._label   s/    %)))Y?J 
|44r-   z[bold]{task.description}(   )	bar_width)r2   r   )ry   F)r2   	transients   data:    statusreadycachederrorr^   zUnknown errorloadingstageprogressr   rt   itemscurrentry   )descriptionr~   ry   rs   r   )r   r~   ry   z_*z was already loaded.*_z is warm.*_)requestspostr&   rstripraise_for_statusr   r)   widthlenr   r   r   r   add_taskr   
iter_linesrE   ro   loadsr{   RuntimeErrorrH   r;   r   )r*   rl   re   r   r   r   task_idr   rN   eventr   r   proglabelrs   r   r   s    `             @@r+   print_model_loadzRichInterface.print_model_load   sd   ==DMM$8$8$=#>k!JRY[`Qajno!!#	H. 	H& -&+,	
 !MM//3u:>B3FF	 12#MMM
 ##F;$7t#D(DMMTB 	] ++- ]4??9#=

48,8,W$"YYx7FW$&uyyO'LMMY&!IIg.E 99Z0D"5ME*/:*=w7 #$y/Y]YaYabiYjqu (  !UaW[\1]	]6 MM2eW4J)K LMMM2eWK)@ AB?	] 	]s   <BI7A5I77J r   c                     | j                   j                  d| j                   d       | j                   j                  d|        | j                   j                          y)zFPrints the status of the model and generation settings to the console.z[bold blue]Model: r8   z[bold blue]N)r)   r;   r$   )r*   r   s     r+   print_statuszRichInterface.print_status#  sK    0rBCk&23r-   )F)r   r   r   strr,   r   r	   tupler   rR   rU   rW   rY   r]   boolrf   rk   r   r
   r   r   r-   r+   r#   r#   j   s    ! !s !c !9#-8R*S 9#X]^acfilcloscs^sXt 9#vs s 
 C 

(s 
(T 
(d 
($ 
Pc Pd#3 r-   r#   c                   N   e Zd ZdZded    ded    ddddddfdee ej                  d	
      f   deedz   ej                  d
      f   dee	e   dz   ej                  d
      f   deedz   ej                  d
      f   deedz   ej                  d
      f   dee ej                  d
      f   deedz   ej                  d
      f   deedz   ej                  d
      f   ddfdZed        Zdededeeeeef   f   ded e	e   dee	e   ef   fd!Zd" Zy)#Chat(Chat with a model from the command line.zhttp://r   rv   r   Nz./chat_history/r$   z9ID of the model to use (e.g. 'HuggingFaceTB/SmolLM3-3B').)helpr&   z7Base url to connect to (e.g. http://localhost:8000/v1).generate_flagsa  Flags to pass to `generate`, using a space as a separator between flags. Accepts booleans, numbers, and lists of integers, more advanced parameterization should be set through --generation-config. Example: `transformers chat <base_url> <model_id> max_new_tokens=100 do_sample=False eos_token_id=[1,2]`. If you're a new user, check this basic flag guide: https://huggingface.co/docs/transformers/llm_tutorial#common-optionsuserzKUsername to display in chat interface. Defaults to the current user's name.system_promptzSystem prompt.save_folderzFolder to save chat history.examples_pathz"Path to a yaml file with examples.generation_configzPath to a local generation config file or to a HuggingFace repo containing a `generation_config.json` file. Other generation settings passed as CLI arguments will be applied on top of this generation config.r/   c	                    || _         t        | j                         }	|	j                  t        d   k(  r1|	j                  t        d   k(  r| j                  | j                          || _        || _        || _        t        |      }
|
j                  dd        |
j                  d	i t        |       |
| _        ||| j                  j                         d| _        ||n	t               | _        |r/t#        |      5 }t%        j&                  |      | _        ddd       nt*        | _        t-               st/        d      t1        j2                  | j5                                y# 1 sw Y   BxY w)
r   r   r   T   )	do_samplemax_new_tokens)r&   r$   r   NzHYou need to install rich to use the chat interface. (`pip install rich`)r   )r&   r   r   DEFAULT_HTTP_ENDPOINTr   check_healthr$   r   r   load_generation_configrH   parse_generate_flagsr   to_dictsettingsget_usernamer   openyaml	safe_loadexamplesDEFAULT_EXAMPLESr   ImportErrorasynciorun
_inner_run)r*   r$   r&   r   r   r   r   r   r   parsedr   fs               r+   r,   zChat.__init__/  s:   F !$--(??3J??FKKShioSpDpdmm, *& ((9:S9=,^<=%-8t{{ObObOde !,D,.	 m$ 2 $q 12 2 -DM !"hii 	DOO%&2 2s   <E$$E-c                     t        | dz   d      }	 t        j                  |      }|j                  dk7  rt	        d|  d|j                   d      	 y	# t        j
                  $ r t	        d|  d      w xY w)
Nrn   health   zThe server running on z returned status code z on health check (/health).zNo server currently running on z. To run a local server, please run `transformers serve` in aseparate shell. Find more information here: https://huggingface.co/docs/transformers/servingT)r   httpxr{   status_code
ValueErrorConnectError)url
health_urloutputs      r+   r   zChat.check_healthu  s    S3Y1

	YYz*F!!S( ,SE1GHZHZG[[vw  )  !! 	1# 7o p 	s   A A #A6
user_input	interfacer   r   chatc                    d}|dk(  r't        | j                        }|j                          nV|dk(  r|j                          n?|j	                  d      rt        |j                               dk  r|j                         }t        |      dk(  r|d   nKt        j                  j                  | j                  | j                  dt        j                  d       d	      }t        ||| j                  
       |j!                  d| dd       nr|j	                  d      rd|dd j#                         }	|	j                         }	|	D ]   }
d|
vs|j!                  d|
 dd        n  |j$                  d"i t'        |	       n|j	                  d      rt        |j                               dk(  r|j                         d   }||v rD|j                          g }|j)                  ||   d          |j+                  d||   d   d       nud| dt-        |j/                                d}|j!                  |d       nA|dk(  r|j1                  |       n)d}|j!                  d | d!d       |j                          |||fS )#z
        Handles all user commands except for `!exit`. May update the chat history (e.g. reset it) or the
        generation config (e.g. set a new flag).
        T!clear!help!save      chat_%Y-%m-%d_%H-%M-%S.jsonfilenamer   r   Chat saved to !greenr   rZ   !setr1   N=(Invalid flag format, missing `=` after `;`. Please use the format `arg_1=value_1 arg_2=value_2 ...`.red!exampler   r   roler?   Example * not found in list of available examples: .!statusr   F'/' is not a valid command. Showing help message.r   )new_chat_historyr   rW   rk   rE   r   splitospathrF   r   r$   r<   strftime	save_chatr   r]   rG   rH   r   rY   rD   listkeysr   )r*   r   r   r   r   r   valid_commandsplit_inputr   new_generate_flagsflagexample_nameexample_errors                r+   handle_non_exit_user_commandsz"Chat.handle_non_exit_user_commands  s    !#D$6$67DOO7"  """7+J4D4D4F0G!0K$**,K {#q( AWW\\$"2"2DMMU4==YlKmJnnsCtu 
 xdT]]K!!z'C7!S""6* ",AB!5!5!7!3!9!9!;* Jd?))Ftf MA A $ *  J I 45G HI"":.3z7G7G7I3Ja3O%++-a0Lx'!,,Xl-CF-KLV8Nv8VWX |n,VW[\d\i\i\kWlVmmno  %%=%F9$""&"1 "M!!:,6e'fns!t  "]F**r-   c           	      
	  K   t        | j                  | j                  | j                        }|j	                          t        | j                        }|j                  d       |j                  | j                         | j                  }t        | j                        4 d {   }d }	 	 ||}d }|j                  |       n|j                         }|dk(  rnh|dk(  r&t        | j                        }|j	                          \|dk(  r|j                          r|j                  d      rt        |j                               d	k  r|j                         }t        |      d	k(  r|d
   nKt         j"                  j%                  | j&                  | j                  dt)        j*                  d       d      }t-        ||| j.                         |j1                  d| dd       ?|j                  d      rd|dd  j3                         }	|	j                         }	|	D ]  }
d|
vs|j1                  d|
 dd        n  |j4                  d,i t7        |	       |j                  d      rt        |j                               d	k(  r|j                         d
   }|| j8                  v rX|j	                          g }|j                  | j8                  |   d          |j;                  d| j8                  |   d   d       nd| dt=        | j8                  j?                                d}|j1                  |d       ng|d k(  r|jA                  |!       |j                  d      r)|j1                  d"| d#d       |j                          |j;                  d|d       |jC                         | j                  d$}|jE                  |d| j                  |%      }|jG                  |       d {   \  }}|j;                  d&|d       |d'k(  r'|j1                  d(d)       |jI                  d*      rd+}d d d       d {    y 7 7 ]# tJ        $ r Y !w xY w7 # 1 d {  7  sw Y   y xY ww)-N)r$   r%   r&   T)rg   )r&   z!exitr   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  )r   rl   )r.   rl   
extra_body	assistantlengthz2Generation stopped after reaching the token limit.yellowzContinue generating?u'   Please continue. Do not repeat text.”r   )&r#   r$   r   r&   rW   r  r   rk   r   r   r   rY   rU   rE   r   r  r  r  rF   r   r<   r  r	  r   r]   rG   rH   r   r   rD   r
  r  r   to_json_stringchat_completionrR   rf   KeyboardInterrupt)r*   r   r   r   clientpending_user_inputr   r  r   r  r  r  r  r  r.   model_outputr5   s                    r+   r   zChat._inner_run  s    !4==$))VZVcVcd	 2 23 	T*""4==1'? i	 i	6-1f)5%7
-1*!44Z@%.__%6
 "W,#x//0B0BC!) #w.!,,. #..w7C
@P@P@R<SVW<W&0&6&6&8  #;/14 (N!# $ 0 0$--5WjIkHllqAr" ! "8$W!--^H:Q3OW^-_ #..v6 .8^-A-A-C*-?-E-E-G*$6 VD"$ ) 5 5*RSWRX YM )M +0 !6 !" !&V *FMMU,@AS,TU #..z:s:CSCSCU?VZ[?['1'7'7'9!'<'4==8%OO-#%D%88|9TU[9\] KKDMMR^D_`fDg(hi.6|nDnostx  uB  uB  uG  uG  uI  pJ  oK  KL  -MM%11}E1R#y0!..f.= #..s3!--#$ZL0_!`hm .  ",,.  V
$KL .4-B-B-D!%"J
 $33#"mm#-	 4 F 9B8O8OPV8W2W/L-KK NO$0!--.bdlm$,,-CD1Z.$K i	 i	 i	~ 3X ) Qi	 i	 i	 i	s   B%R'Q(R+Q.0-QQ.*Q	Q.
QQ. CQ+Q.-=Q+5Q Q."C;QQ.8QQ.A$Q=Q>AQQ.RQ,RQ	Q)&Q.(Q))Q.,R.R 4Q75R <R)r   r   r   __doc__r   r   r   typerArgumentr
  Optionr,   staticmethodr   r#   dictr
   r   r  r   r   r-   r+   r   r   *  s   2 +J78:OPV:W9XY 
 TXYjhl AD'C5p!qqrD' $J,eff
D' "IENN[	
D'& $JELLkln
'D'. !t\U\\?O-P!PQ/D'0 sLELL6T$UUV1D'2 !t\U\\?c-d!de3D'6 %$JELL g
7D'B 
CD'L   H+H+ !H+ sDcN*+	H+
 !H+ 4jH+ 
tDz++	,H+Ttr-   r   r   r/   c                     | 
t               S d| v rTt        j                  j                  |       }t        j                  j	                  |       }t        j
                  ||      S t        j
                  |       S )Nr   )r
   r  r  dirnamebasenamefrom_pretrained)r   r%  r   s      r+   r   r   G  sg     !!##''//"3477##$56//BB//0ABBr-   r   c           	         | t        |       dk(  ri S | D ci c]/  }d|j                  d      d   z   dz   |j                  d      d   1 }}|j                         D ci c]*  \  }}||j                         dv r|j                         n|, }}}|j                         D ci c]  \  }}||dk(  rdn| }}}dt        d	t
        fd
}|j                         D ci c]  \  }}| ||      sd| dn| }}}dj                  |j                         D cg c]  \  }}| d|  c}}      }d|z   dz   }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }	 t        j                  |      }|S c c}w c c}}w c c}}w c c}}w c c}}w # t        j                  $ r t        d      w xY w)zUParses the generate flags from the user input into a dictionary of `generate` kwargs.r   "r   r   )truefalseNonenullsr/   c                 f    | j                  d      } | j                  ddd      j                         S )N-r   r4   r   )removeprefixreplaceisdigit)r.  s    r+   	is_numberz'parse_generate_flags.<locals>.is_numbere  s,    NN3yyb!$,,..r-   z, z: {}z"null"z"true"r*  z"false"r+  z"[[z]"r\   rv   zFailed to convert `generate_flags` into a valid JSON object.
`generate_flags` = {generate_flags}
Converted JSON string = {generate_flags_string})r   r  r   rc   r   r   rF   r2  ro   r   JSONDecodeErrorr   )r   r  generate_flags_as_dictkvr4  generate_flags_stringprocessed_generate_flagss           r+   r   r   S  sC   ^!4!9	
 ^llUYcDJJsOA$66<djjoa>PPll
 KaJfJfJhBF!Q	%661779A=  KaJfJfJhi$!Qa1;A=ii/S /T /
 RhQmQmQopAa11QCq1Dpp
 !II?U?[?[?]&^tq!!Bqc{&^_  "77#= 299(FK199(FK199)WM199$D199$D 299#sC
#'::.C#D  $#W m j q
 '_"  
@
 	

s)   4G  /G%GGG
)G G<r   c                     | rd| dgS g S )z Returns a new chat conversation.systemr   r   )r   s    r+   r  r    s    =JX-89RPRRr-   r   r   r   c                     t        j                  t         j                  j                  |       d       t	        | d      5 }t        j                  ||d|d       ddd       t         j                  j                  |       S # 1 sw Y   (xY w)z!Saves the chat history to a file.T)exist_okw)r   chat_historyr1   )indentN)r  makedirsr  r%  r   ro   dumpabspath)r   r   r   r   s       r+   r	  r	    sj    KK)D9	h	 M		x>!LM77??8$$M Ms   BBc                      t        j                         dk(  rt        j                         S t	        j
                  t        j                               j                  S )z)Returns the username of the current user.r   )platformr?  r  getloginpwdgetpwuidgetuidpw_namer   r-   r+   r   r     s8    I%{{}||BIIK(000r-   __main__z meta-llama/Llama-3.2-3b-Instruct)r$   r(   )Er   ro   r  rI  rA   stringr<   collections.abcr   typingr   r   urllib.parser   r   r   r   r  r   huggingface_hubr   r	   transformersr
   transformers.utilsr   readliner   r?  rK  richr   rich.consoler   	rich.liver   rich.markdownr   rich.progressr   r   r   r   r   	rich.textr   r   setascii_letters
whitespaceALLOWED_KEY_CHARSdigitsALLOWED_VALUE_CHARSr   ri   rF   r  rj   r#   r   r   r   r
  r#  r   r  r	  r   r   r   r-   r+   <module>rd     s     	  	   ) ! *     L ) 0	
 8??	!$&``%0$? ,,v/@/@@A 
6==(6+<+<<?bb 
 MN) QRNO./JK?@  	 	 ";;'7'<'<'>?@ A&} }@Z Zz	CcDj 	C=M 	C3$cT)9 3$d 3$lSC$J S$t* S
% %4: % %# %1c 1 z45 s  		s   F F! F!