o
    0 ix`                     @  s8  d Z ddlmZ ddlZddlZddlmZ ddlmZm	Z	m
Z
mZmZmZmZmZmZmZmZ ddlZddlmZmZ zddlmZ dd	lmZ dd
lmZ ddlmZ W n eyq   G dd dZ e  Ze  Ze  Ze!Z"Y nw dCddZ#dDddZ$G dd de%eZ&G dd deZ'edZ(G dd deZ)G d d! d!e)Z*G d"d# d#eZ+G d$d% d%e%eZ,G d&d' d'eZ-G d(d) d)eZ.G d*d+ d+e)Z/G d,d- d-e)Z0G d.d/ d/eZ1G d0d1 d1eZ2G d2d3 d3eZ3G d4d5 d5eZ4G d6d7 d7Z5G d8d9 d9eZ6G d:d; d;Z7dEd>d?ZG d@dA dAe%eZ8g dBZ9dS )Fu  Python wrapper around the Rust implementation of *harmony*.

The heavy lifting (tokenisation, rendering, parsing, …) is implemented in
Rust.  The thin bindings are available through the private ``openai_harmony``
extension module which is compiled via *maturin* / *PyO3*.

This package provides a small, typed convenience layer that mirrors the public
API of the Rust crate so that it can be used from Python code in an
idiomatic way (``dataclasses``, ``Enum``s, …).
    )annotationsN)Enum)AbstractSetAny
CollectionDictListLiteralOptionalPatternSequenceTypeVarUnion)	BaseModelField   HarmonyError)PyHarmonyEncoding)PyStreamableParser)load_harmony_encodingc                   @  s   e Zd ZdddZdS )	_StubnamestrreturnNonec                 C  s   t d)NzThe compiled harmony bindings are not available. Make sure to build the project with `maturin develop` before running this code.)RuntimeError)selfr    r   c/home/app/PaddleOCR-VL-test/.venv_paddleocr/lib/python3.10/site-packages/openai_harmony/__init__.py__getattr__6   s   z_Stub.__getattr__N)r   r   r   r   )__name__
__module____qualname__r    r   r   r   r   r   5       r   tokensfrozenset[str]r   Pattern[str]c                 C  s&   d dd | D }td| dS )N|c                 s  s    | ]}t |V  qd S N)reescape).0tokenr   r   r   	<genexpr>D   s    z'_special_token_regex.<locals>.<genexpr>())joinr*   compile)r%   innerr   r   r   _special_token_regexC   s   r4   r-   r   r   c                 C  s   t d| d|  d|  d)Nz;Encountered text corresponding to disallowed special token zp.
If you want this text to be encoded as a special token, pass it to `allowed_special`, e.g. `allowed_special={'z', ...}`.
If you want this text to be encoded as normal text, disable the check for this token by passing `disallowed_special=(enc.special_tokens_set - {'zR'})`.
To disable this check for all special tokens, pass `disallowed_special=()`.
r   )r-   r   r   r   raise_disallowed_special_tokenH   s   r5   c                   @  s2   e Zd ZdZdZdZdZdZdZe	dddZ
dS )Rolez6The role of a message author (mirrors ``chat::Role``).userZ	assistantsystemZ	developerZtoolvalueobjectr   'Role'c                 C  s   t d|)NzUnknown role: )
ValueError)clsr9   r   r   r   	_missing_b      zRole._missing_N)r9   r:   r   r;   )r!   r"   r#   __doc__USERZ	ASSISTANTZSYSTEMZ	DEVELOPERZTOOLclassmethodr>   r   r   r   r   r6   Y   s    r6   c                   @  s0   e Zd ZU ded< dZded< edd	d
ZdS )Authorr6   roleNOptional[str]r   r   r   'Author'c                 C  s   | ||dS )NrD   r   r   )r=   rD   r   r   r   r   newk      z
Author.new)rD   r6   r   r   r   rF   )r!   r"   r#   __annotations__r   rB   rH   r   r   r   r   rC   g   s
   
 rC   Tc                   @  s   e Zd ZdddZdS )Contentr   Dict[str, Any]c                 C  s   t r)   )NotImplementedErrorr   r   r   r   to_dictw   s   zContent.to_dictNr   rM   )r!   r"   r#   rP   r   r   r   r   rL   v   r$   rL   c                   @  s    e Zd ZU ded< dddZdS )	TextContentr   textr   rM   c                 C  s   d| j dS )NrS   typerS   rS   rO   r   r   r   rP   ~   s   zTextContent.to_dictNrQ   )r!   r"   r#   rJ   rP   r   r   r   r   rR   {   s   
 rR   c                   @  s<   e Zd ZU ded< ded< dZded< e	ddd	d
ZdS )ToolDescriptionr   r   descriptionNOptional[dict]
parametersr   'ToolDescription'c                 C  s   | |||dS )N)r   rX   rZ   r   )r=   r   rX   rZ   r   r   r   rH      s   zToolDescription.newr)   )r   r   rX   r   rZ   rY   r   r[   )r!   r"   r#   rJ   rZ   rB   rH   r   r   r   r   rW      s   
 rW   c                   @     e Zd ZdZdZdZdS )ReasoningEffortZLowZMediumZHighN)r!   r"   r#   ZLOWMEDIUMZHIGHr   r   r   r   r]          r]   c                   @  s,   e Zd ZU ded< ded< eddd	Zd
S )ChannelConfig	List[str]valid_channelsboolchannel_requiredchannelsr   'ChannelConfig'c                 C  s   | |ddS )NT)rb   rd   r   )r=   re   r   r   r   require_channels   rI   zChannelConfig.require_channelsN)re   ra   r   rf   )r!   r"   r#   rJ   rB   rg   r   r   r   r   r`      s
   
 r`   c                   @  sF   e Zd ZU ded< dZded< ded< edd
dZedddZdS )ToolNamespaceConfigr   r   NrE   rX   zList[ToolDescription]toolsr   'ToolNamespaceConfig'c                  C  "   ddl m}  | d}tdi |S )Nr   get_tool_namespace_configbrowserr   openai_harmonyrm   rh   Z_get_tool_namespace_configcfgr   r   r   rn         zToolNamespaceConfig.browserc                  C  rk   )Nr   rl   pythonr   ro   rq   r   r   r   rt      rs   zToolNamespaceConfig.python)r   rj   )r!   r"   r#   rJ   rX   staticmethodrn   rt   r   r   r   r   rh      s   
 rh   c                   @  s   e Zd ZU dZded< ejZded< dZded< dZ	ded	< e
d
d dZded< dZded< ed4ddZd5ddZd6ddZd7ddZd8ddZd9d d!Zd:d$d%Zd;d(d)Zd4d*d+Zd4d,d-Zd<d/d0Zed=d2d3ZdS )>SystemContentz:You are ChatGPT, a large language model trained by OpenAI.rE   model_identityzOptional[ReasoningEffort]reasoning_effortNconversation_start_datez2024-06knowledge_cutoffc                   C  s   t g dS )N)ZanalysisZ
commentaryfinal)r`   rg   r   r   r   r   <lambda>   s    zSystemContent.<lambda>default_factoryzOptional[ChannelConfig]channel_config(Optional[dict[str, ToolNamespaceConfig]]ri   r   'SystemContent'c                 C     |  S r)   r   r=   r   r   r   rH         zSystemContent.newr   c                 C  
   || _ | S r)   )rw   )r   rw   r   r   r   with_model_identity      z!SystemContent.with_model_identityr]   c                 C  r   r)   )rx   )r   rx   r   r   r   with_reasoning_effort      z#SystemContent.with_reasoning_effortc                 C  r   r)   )ry   )r   ry   r   r   r   with_conversation_start_date   r   z*SystemContent.with_conversation_start_datec                 C  r   r)   )rz   )r   rz   r   r   r   with_knowledge_cutoff   r   z#SystemContent.with_knowledge_cutoffr`   c                 C  r   r)   )r   )r   r   r   r   r   with_channel_config   r   z!SystemContent.with_channel_configre   	list[str]c                 C  s   t || _| S r)   )r`   rg   r   )r   re   r   r   r   with_required_channels      z$SystemContent.with_required_channels	ns_configrh   c                 C      | j d u ri | _ || j |j< | S r)   ri   r   r   r   r   r   r   
with_tools      
zSystemContent.with_toolsc                 C     |  t S r)   )r   rh   rn   rO   r   r   r   with_browser_tool      zSystemContent.with_browser_toolc                 C  r   r)   )r   rh   rt   rO   r   r   r   with_python_tool   r   zSystemContent.with_python_tooldictc                 C     | j dd}d|d< |S )NTZexclude_nonesystem_contentrU   
model_dumpr   outr   r   r   rP         zSystemContent.to_dictrawc                 C     | di |S Nr   r   r=   r   r   r   r   	from_dict   r?   zSystemContent.from_dict)r   r   )rw   r   r   r   )rx   r]   r   r   )ry   r   r   r   )rz   r   r   r   )r   r`   r   r   )re   r   r   r   )r   rh   r   r   r   r   )r   r   r   r   )r!   r"   r#   rw   rJ   r]   r^   rx   ry   rz   r   r   ri   rB   rH   r   r   r   r   r   r   r   r   r   rP   r   r   r   r   r   rv      s0   
 










rv   c                   @  sj   e Zd ZU dZded< dZded< eddd	ZdddZdddZ	dddZ
dddZedddZdS ) DeveloperContentNrE   instructionsr   ri   r   'DeveloperContent'c                 C  r   r)   r   r   r   r   r   rH      r   zDeveloperContent.newr   c                 C  r   r)   )r   )r   r   r   r   r   with_instructions  r   z"DeveloperContent.with_instructionsr   rh   c                 C  r   r)   r   r   r   r   r   r     r   zDeveloperContent.with_toolsSequence[ToolDescription]c                 C  s   |  tdd t|dS )NZ	functions)r   rX   ri   )r   rh   list)r   ri   r   r   r   with_function_tools  s   z$DeveloperContent.with_function_toolsr   c                 C  r   )NTr   developer_contentrU   r   r   r   r   r   rP     r   zDeveloperContent.to_dictr   c                 C  r   r   r   r   r   r   r   r     r?   zDeveloperContent.from_dict)r   r   )r   r   r   r   )r   rh   r   r   )ri   r   r   r   r   )r   r   r   r   )r!   r"   r#   r   rJ   ri   rB   rH   r   r   r   rP   r   r   r   r   r   r      s   
 



r   c                   @  s   e Zd ZU ded< eedZded< dZded< dZded	< dZ	ded
< e
d)ddZe
d*ddZe
d+ddZd,ddZd-ddZd.ddZd/dd Zd0d"d#Zd1d$d%Ze
d2d'd(ZdS )3MessagerC   authorr}   zList[Content]contentNrE   channel	recipientcontent_typeUnion[str, Content]r   	'Message'c                 C  s"   t |tr
t|d}| ||gdS )NrV   r   r   )
isinstancer   rR   )r=   r   r   r   r   r   from_author_and_content,  s   

zMessage.from_author_and_contentrD   r6   c                 C  s   |  t|d|S )NrD   )r   rC   )r=   rD   r   r   r   r   from_role_and_content4  s   zMessage.from_role_and_contentcontentsSequence[Content]c                 C  s   | t |dt|dS )Nr   r   )rC   r   )r=   rD   r   r   r   r   from_role_and_contents:  s   zMessage.from_role_and_contentsc                 C  s$   t |tr
t|d}| j| | S )NrV   )r   r   rR   r   append)r   r   r   r   r   adding_contentD  s   

zMessage.adding_contentr   c                 C  r   r)   )r   )r   r   r   r   r   with_channelJ  r   zMessage.with_channelc                 C  r   r)   )r   )r   r   r   r   r   with_recipientN  r   zMessage.with_recipientc                 C  r   r)   )r   )r   r   r   r   r   with_content_typeR  r   zMessage.with_content_typerM   c                 C  sb   i | j  ddd | jD i}| jd ur| j|d< | jd ur%| j|d< | jd ur/| j|d< |S )Nr   c                 S     g | ]}|  qS r   rP   )r,   cr   r   r   
<listcomp>]      z#Message.to_dict.<locals>.<listcomp>r   r   r   )r   r   r   r   r   r   r   r   r   r   rP   Z  s   





zMessage.to_dictc                 C     t |  S r)   jsondumpsrP   rO   r   r   r   to_jsong  r   zMessage.to_jsondatac                 C  s   t |d }t||dd}g }|d }t|tr d|dg}|D ]>}|ddkr6|tdi | q"|ddkrH|tdi | q"|dd	krZ|tdi | q"t	d
| | ||d}|d|_
|d|_|d|_|S )NrD   r   rG   r   rS   rT   rU   r   r   zUnknown content variant: r   r   r   r   r   )r6   rC   getr   r   r   rR   rv   r   r<   r   r   r   )r=   r   rD   r   r   Zraw_contentr   msgr   r   r   r   j  s&   
zMessage.from_dict)r   rC   r   r   r   r   )rD   r6   r   r   r   r   )rD   r6   r   r   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   r   )r   r   r   r   rQ   r   r   )r   rM   r   r   )r!   r"   r#   rJ   r   r   r   r   r   r   rB   r   r   r   r   r   r   r   rP   r   r   r   r   r   r   r   !  s(   
 
	




r   c                   @  sX   e Zd ZU eedZded< edddZd	d
 Z	dddZ
dddZedddZdS )Conversationr}   List[Message]messagesSequence[Message]r   'Conversation'c                 C  s   | t |dS )Nr   )r   )r=   r   r   r   r   from_messages  r?   zConversation.from_messagesc                 C  
   t | jS r)   )iterr   rO   r   r   r   __iter__     
zConversation.__iter__rM   c                 C  s   ddd | j D iS )Nr   c                 S  r   r   r   r,   mr   r   r   r     r   z(Conversation.to_dict.<locals>.<listcomp>r   rO   r   r   r   rP     s   zConversation.to_dictr   c                 C  r   r)   r   rO   r   r   r   r     r   zConversation.to_jsonpayloadc                 C  s"   t |}| dd |d D dS )Nc                 S     g | ]}t |qS r   r   r   r   r   r   r   r         z*Conversation.from_json.<locals>.<listcomp>r   r   )r   loads)r=   r   r   r   r   r   	from_json  s   
zConversation.from_jsonN)r   r   r   r   rQ   r   )r   r   r   r   )r!   r"   r#   r   r   r   rJ   rB   r   r   rP   r   r   r   r   r   r   r     s   
 

r   c                   @     e Zd ZU dZded< dS )RenderConversationConfigTrc   auto_drop_analysisN)r!   r"   r#   r   rJ   r   r   r   r   r        
 r   c                   @  r   )RenderOptionsFrc   conversation_has_function_toolsN)r!   r"   r#   r   rJ   r   r   r   r   r     r   r   c                   @  s   e Zd ZdZdDddZedEdd	ZejdFddZ		dGdHddZ
	dGdIddZ	dGdIddZ	dGdJdd Z	dGd!d"dKd*d+ZdLd,d-Ze d.d/dMd6d7ZdNdOd:d;ZdPd>d?ZdQd@dAZdQdBdCZdS )RHarmonyEncodingz?High-level wrapper around the Rust ``PyHarmonyEncoding`` class.r3   _PyHarmonyEncodingc                 C  s
   || _ d S r)   )_inner)r   r3   r   r   r   __init__  r   zHarmonyEncoding.__init__r   r   c                 C     | j jS r)   )r   r   rO   r   r   r   r        zHarmonyEncoding.nameset[str]c                 C  s   t | j S r)   )setr   Zspecial_tokensrO   r   r   r   special_tokens_set  r?   z"HarmonyEncoding.special_tokens_setNconversationr   next_turn_roler6   config"Optional[RenderConversationConfig]	List[int]c                 C  s8   |du r	ddi}nd|j i}| jj| t|j|dS )z
        Render a conversation for completion.
        Args:
            conversation: Conversation object
            next_turn_role: Role for the next turn
            config: Optional RenderConversationConfig (default auto_drop_analysis=True)
        Nr   T)conversation_jsonr   r   )r   r   "render_conversation_for_completionr   r   r9   )r   r   r   r   config_dictr   r   r   r     s   

z2HarmonyEncoding.render_conversation_for_completionc                 C  0   |du r	ddi}nd|j i}| jj| |dS )z3Render a conversation without appending a new role.Nr   Tr   r   )r   r   render_conversationr   r   r   r   r   r   r   r   r        

z#HarmonyEncoding.render_conversationc                 C  r   )z#Render a conversation for training.Nr   Tr   )r   r    render_conversation_for_trainingr   r  r   r   r   r    r  z0HarmonyEncoding.render_conversation_for_trainingmessager   render_optionsOptional[RenderOptions]c                 C  r   )z$Render a single message into tokens.Nr   F)Zmessage_jsonr  )r   r   renderr   )r   r  r  Zrender_options_dictr   r   r   r    s   
zHarmonyEncoding.renderTstrictr%   Sequence[int]rD   Optional[Role] | Noner	  rc   r   c                C  s:   | j t||d u rd nt|j|}dd t|D S )Nc                 S  r   r   r   r   r   r   r   r     r   zIHarmonyEncoding.parse_messages_from_completion_tokens.<locals>.<listcomp>)r   %parse_messages_from_completion_tokensr   r   r9   r   r   )r   r%   rD   r	  Zraw_jsonr   r   r   r  
  s   z5HarmonyEncoding.parse_messages_from_completion_tokensc                 C  s   | j t|S )zDecode a list of tokens into a UTF-8 string. Will raise an error if the tokens result in invalid UTF-8. Use decode if you want to replace invalid UTF-8 with the unicode replacement character.)r   decode_utf8r   )r   r%   r   r   r   r    s   zHarmonyEncoding.decode_utf8all)allowed_specialdisallowed_specialrS   r  !Literal['all'] | AbstractSet[str]r   Literal['all'] | Collection[str]	list[int]c                C  s   |dkr| j }|dkr| j t| }|r,t|tst|}t|| }r,t|  z
| j	|t
|W S  tyR   |	dddd}| j	|t
| Y S w )aH  Encodes a string into tokens.

        Special tokens are artificial tokens used to unlock capabilities from a model,
        such as fill-in-the-middle. So we want to be careful about accidentally encoding special
        tokens, since they can be used to trick a model into doing something we don't want it to do.

        Hence, by default, encode will raise an error if it encounters text that corresponds
        to a special token. This can be controlled on a per-token level using the `allowed_special`
        and `disallowed_special` parameters. In particular:
        - Setting `disallowed_special` to () will prevent this function from raising errors and
          cause all text corresponding to special tokens to be encoded as natural text.
        - Setting `allowed_special` to "all" will cause this function to treat all text
          corresponding to special tokens to be encoded as special tokens.

        ```
        >>> enc.encode("hello world")
        [31373, 995]
        >>> enc.encode("<|endoftext|>", allowed_special={"<|endoftext|>"})
        [50256]
        >>> enc.encode("<|endoftext|>", allowed_special="all")
        [50256]
        >>> enc.encode("<|endoftext|>")
        # Raises ValueError
        >>> enc.encode("<|endoftext|>", disallowed_special=())
        [27, 91, 437, 1659, 5239, 91, 29]
        ```
        r  zutf-16surrogatepassreplace)r   r   r   	frozensetr4   searchr5   groupr   encoder   UnicodeEncodeErrordecode)r   rS   r  r  matchr   r   r   r    s   "
zHarmonyEncoding.encoder  errorsc                 C  s"   t | jt|}|jd|dS )aS  Decodes a list of tokens into a string.

        WARNING: the default behaviour of this function is lossy, since decoded bytes are not
        guaranteed to be valid UTF-8. You can use `decode_utf8` if you want to raise an error on invalid UTF-8.

        ```
        >>> enc.decode([31373, 995])
        'hello world'
        ```
        zutf-8)r  )bytesr   Zdecode_bytesr   r  )r   r%   r  r   r   r   r   r  N  s   zHarmonyEncoding.decoder-   intc                 C  s   | j |S )z1Returns if an individual token is a special token)r   is_special_tokenr   r-   r   r   r   r   \  rI   z HarmonyEncoding.is_special_tokenc                 C  
   | j  S r)   )r   stop_tokensrO   r   r   r   r#  b  r   zHarmonyEncoding.stop_tokensc                 C  r"  r)   )r   !stop_tokens_for_assistant_actionsrO   r   r   r   r$  e  r   z1HarmonyEncoding.stop_tokens_for_assistant_actions)r3   r   r   )r   r   r)   )r   r   r   r6   r   r   r   r   )r   r   r   r   r   r   )r  r   r  r  r   r   )r%   r
  rD   r  r	  rc   r   r   )r%   r
  r   r   )rS   r   r  r  r  r  r   r  )r  )r%   r
  r  r   r   r   )r-   r  r   rc   r   r   )r!   r"   r#   r@   r   propertyr   	functoolscached_propertyr   r   r   r  r  r  r  r   r  r  r   r#  r$  r   r   r   r   r     s6    
	
2

r   c                   @  r\   )StreamStateZExpectStartHeaderrL   N)r!   r"   r#   ZEXPECT_STARTHEADERZCONTENTr   r   r   r   r)  i  r_   r)  c                   @  s   e Zd ZdZddd1ddZd2ddZd3ddZed4ddZed5ddZ	ed6ddZ
ed6ddZed7d!d"Zed8d$d%Zed9d'd(Zed:d*d+Zed6d,d-Zed6d.d/Zd0S );StreamableParserz*Incremental parser over completion tokens.Tr  encodingr   rD   Role | Noner	  rc   r   r   c                C  s*   |d ur	t |jnd }t|j||| _d S r)   )r   r9   _PyStreamableParserr   )r   r-  rD   r	  Zrole_strr   r   r   r   r  s   zStreamableParser.__init__r-   r  'StreamableParser'c                 C  s   | j | | S r)   )r   processr!  r   r   r   r1  |  r   zStreamableParser.processc                 C  s   | j   | S r)   )r   process_eosrO   r   r   r   r2    s   
zStreamableParser.process_eosr   c                 C  r   r)   )r   current_contentrO   r   r   r   r3    r   z StreamableParser.current_contentOptional[Role]c                 C  s   | j j}|d urt|S d S r)   )r   current_roler6   r   r   r   r   r   r5       zStreamableParser.current_rolerE   c                 C  r   r)   )r   current_content_typerO   r   r   r   r8    r   z%StreamableParser.current_content_typec                 C  r   r)   )r   last_content_deltarO   r   r   r   r9    r   z#StreamableParser.last_content_deltar   c                 C  s   | j j}dd t|D S )Nc                 S  r   r   r   r   r   r   r   r     r   z-StreamableParser.messages.<locals>.<listcomp>)r   r   r   r   r6  r   r   r   r     r7  zStreamableParser.messagesr   c                 C  r   r)   )r   r%   rO   r   r   r   r%     r   zStreamableParser.tokensrM   c                 C  s   t | jjS )z>Return a JSON string representing the parser's internal state.)r   r   r   staterO   r   r   r   
state_data  s   zStreamableParser.state_datar)  c                 C  s   | j }t|d S )Nr:  )r;  r)  )r   r   r   r   r   r:    s   zStreamableParser.statec                 C  r   r)   )r   current_recipientrO   r   r   r   r<    r   z"StreamableParser.current_recipientc                 C  r   r)   )r   current_channelrO   r   r   r   r=    r   z StreamableParser.current_channelN)r-  r   rD   r.  r	  rc   r   r   )r-   r  r   r0  )r   r0  r   )r   r4  )r   rE   )r   r   r%  rQ   )r   r)  )r!   r"   r#   r@   r   r1  r2  r&  r3  r5  r8  r9  r   r%   r;  r:  r<  r=  r   r   r   r   r,  o  s4    


r,  r   str | 'HarmonyEncodingName'c                 C  s"   t | ts	t| } t| }t|S )zBLoad an encoding by *name* (delegates to the Rust implementation).)r   r   _load_harmony_encodingr   )r   r3   r   r   r   r     s   
r   c                   @  s   e Zd ZdZdddZdS )HarmonyEncodingNameZHarmonyGptOssr   r   c                 C  r   r)   )r   r9   rO   r   r   r   __str__  r   zHarmonyEncodingName.__str__Nr   )r!   r"   r#   ZHARMONY_GPT_OSSrA  r   r   r   r   r@    s    r@  )r6   rC   rL   rR   r   rW   rv   r   r   r   r@  r   r,  r)  r   )r%   r&   r   r'   )r-   r   r   r   )r   r>  r   r   ):r@   
__future__r   r'  r   enumr   typingr   r   r   r   r   r	   r
   r   r   r   r   r*   Zpydanticr   r   rp   r   r   r   r   r/  r   r?  ModuleNotFoundErrorr   r   Z_HarmonyErrorr4   r5   r   r6   rC   rK   rL   rR   rW   r]   r`   rh   rv   r   r   r   r   r   r   r)  r,  r@  __all__r   r   r   r   <module>   sX    4

	F&j :
E