
    Yjl                    `   d Z ddlm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
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mZmZ dd	lmZmZ 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& ddl'm(Z( ddl)m*Z*m+Z+m,Z, e	rddl-m.Z. ddl/m0Z0 ddl1m2Z2  ej3        e4          Z5 G d dee$          Z6dS )zSync Peer class for Honcho SDK.    )annotationsN)	Generator)TYPE_CHECKINGAnyLiteral)
ConfigDictFieldPrivateAttrvalidate_call   )MessageCreateParamsMessageResponsePeerCardResponse
PeerConfigPeerContextResponsePeerResponseRepresentationResponseSessionResponse)PeerBaseSessionBase)ConclusionScope)routes)Message)MetadataConfigMixin)SyncPage)DialecticStreamResponse)parse_datetimeparse_sse_stream
resolve_idPeerAio)HonchoSessionc                      e Zd ZU dZ ed          Zded<    ed          Zded<    e            Zded	<   e	dod            Z
e	dpd            Zd ZdqdZdqdZdrdZdsdZdtdZe edd          fdud            Ze	dvd            Z e ed !          "           edd#d$%           edd&          f edd'           edd(          d)dw fd.            Z e ed !          "           edd#d/%          fdddd0dxd9            Z e ed !          "           edd#d/%          fdddd0dyd;            Z	 dzd{d>Ze edd?d@%          f eddA           eddB           eddC          dDd|dJ            Ze edd#dK%           eddL           edMd#dNdOP          fd}dT            Z e ed !          "          	 dzd~dV            Z	 dzd~dWZ e ed !          "          	 dzddZ            Z e ed !          "          ddd edd#dN[           edd\d][          d edd#dN[          fddf            Z  e ed !          "          dd edd#dN[           edd\d][          d edd#dN[          fddh            Z!e	ddj            Z"ddlZ#dqdmZ$dqdnZ% xZ&S )Peera  
    Represents a peer in the Honcho system.

    Peers can send messages, participate in sessions, and maintain both global
    and local representations for contextual interactions. A peer represents
    an entity (user, assistant, etc.) that can communicate within the system.

    Attributes:
        id: Unique identifier for this peer
        workspace_id: Workspace ID for scoping operations
        metadata: Cached metadata for this peer. May be stale if not recently
            fetched. Call get_metadata() for fresh data.
        configuration: Cached configuration for this peer. May be stale if not
            recently fetched. Call get_configuration() for fresh data.
    N)defaultdict[str, object] | None	_metadataPeerConfig | None_configurationz'Honcho'_honchoreturnc                    | j         S )zOCached metadata for this peer. May be stale. Use get_metadata() for fresh data.)r)   selfs    R/home/ubuntu/.hermes/hermes-agent/venv/lib/python3.11/site-packages/honcho/peer.pymetadatazPeer.metadata>   s     ~    c                    | j         S )zYCached configuration for this peer. May be stale. Use get_configuration() for fresh data.)r+   r/   s    r1   configurationzPeer.configurationC   s     ""r3   c                L    | j                                          | j         j        S N)r,   _ensure_workspace_httpr/   s    r1   _get_http_clientzPeer._get_http_clientI   s!    &&(((|!!r3   strc                4    t          j        | j                  S r7   )r   peersworkspace_idr/   s    r1   _get_fetch_routezPeer._get_fetch_routeM   s    |D-...r3   c                @    t          j        | j        | j                  S r7   )r   peerr>   idr/   s    r1   _get_update_routezPeer._get_update_routeP   s    {4,dg666r3   dict[str, Any]c                    d| j         iS )NrB   rB   r/   s    r1   _get_fetch_bodyzPeer._get_fetch_bodyS   s    dgr3   data+tuple[dict[str, object], dict[str, object]]c                r    t          j        |          }|j        pi |j                            d          fS )NTexclude_none)r   model_validater2   r5   
model_dumpr0   rH   rA   s      r1   _parse_responsezPeer._parse_responseV   s:     *400}"D$6$A$At$A$T$TTTr3   r   c                8   | j                                          |                                                     |                                 |                                           }t          j        |          }|j        pi | _	        |j
        | _        | j        S )z
        Get configuration from the server and update the cache.

        Returns:
            A PeerConfig object containing the configuration settings.
        body)r,   r8   r:   postr?   rG   r   rM   r2   r)   r5   r+   rO   s      r1   get_configurationzPeer.get_configuration]   s     	&&((($$&&++!!##$*>*>*@*@ , 
 
 *400,""0""r3   .zConfiguration to set)descriptionr5   Nonec                    |                                                      |                                 d|                    d          i           || _        dS )z
        Set configuration on the server and update the cache.

        Args:
            configuration: A PeerConfig object with configuration settings.
        r5   TrK   rR   N)r:   putrC   rN   r+   )r0   r5   s     r1   set_configurationzPeer.set_configurationm   se     	##""$$!=#;#;#;#N#NO 	$ 	
 	
 	
 ,r3   	'PeerAio'c                $    ddl m}  ||           S )a  
        Access async versions of all Peer methods.

        Returns a PeerAio view that provides async versions of all methods
        while sharing state with this Peer instance.

        Example:
            ```python
            peer = honcho.peer("user-123")

            # Async operations
            await peer.aio.chat("query")
            await peer.aio.get_metadata()
            ```
        r   r    )aior!   )r0   r!   s     r1   r]   zPeer.aio~   s$    $ 	!     wt}}r3   T)arbitrary_types_allowed)configr   z4Unique identifier for this peer within the workspace)
min_lengthrV   zHoncho client instancezqOptional metadata dictionary to associate with this peer. If set, will get/create peer immediately with metadata.zaOptional configuration to set for this peer. If set, will get/create peer immediately with flags.)r2   r5   peer_idhonchor   r2   c                  t                                          ||j                   || _        || _        || _        ||| j                                         d|i}|||d<   ||                    d          |d<   |j        	                    t          j        |j                  |          }t          j        |          }|j        | _        |j        | _        dS dS )	aD  
        Initialize a new Peer.

        Provided metadata and configuration will overwrite any existing data in those
        locations if given.

        Args:
            peer_id: Unique identifier for this peer within the workspace
            honcho: Honcho client instance
            metadata: Optional metadata dictionary to associate with this peer.
                If set, will get/create peer immediately with metadata.
            configuration: Optional configuration to set for this peer.
                If set, will get/create peer immediately with flags.
        )rB   r>   NrB   r2   TrK   r5   rR   )super__init__r>   r,   r)   r+   r8   rN   r9   rT   r   r=   r   rM   r2   r5   )	r0   ra   rb   r2   r5   rS   rH   	peer_data	__class__s	           r1   re   zPeer.__init__   s    B 	, 	 	
 	
 	
 !+$(<L**,,,$('?D##+Z ((5(@(@d(@(S(S_%<$$V\&2E%F%FT$RRD$3D99I&/DN"+"9D )=(<r3   zThe natural language query)targetsessionreasoning_levelqueryrh   str | PeerBase | Noneri   str | SessionBase | Nonerj   9Literal['minimal', 'low', 'medium', 'high', 'max'] | None
str | Nonec               V   | j                                          t          |          }t          |          }|dd}|r||d<   |r||d<   |r||d<   | j         j                            t          j        | j        | j                  |          }|	                    d          }	|	sdS |	S )	a  
        Query the peer's representation with a natural language question.

        Makes an API call to the Honcho dialectic endpoint to query either the peer's
        global representation (all content associated with this peer) or their local
        representation of another peer (what this peer knows about the target peer).

        Args:
            query: The natural language question to ask.
            target: Optional target peer for local representation query. If provided,
                    queries what this peer knows about the target peer rather than
                    querying the peer's global representation. Can be a peer ID string
                    or a Peer object.
            session: Optional session to scope the query to. If provided, only
                     information from that session is considered. Can be a session
                     ID string or a Session object.
            reasoning_level: Optional reasoning level for the query: "minimal", "low", "medium",
                             "high", or "max". Defaults to "low" if not provided.

        Returns:
            Response string containing the answer, or None if no relevant information
        Frk   streamrh   
session_idrj   rR   contentN)
r,   r8   r   r9   rT   r   	peer_chatr>   rB   get)
r0   rk   rh   ri   rj   	target_idresolved_session_idrS   rH   rt   s
             r1   chatz	Peer.chat   s    @ 	&&(((v&&	(11).%@@ 	'&DN 	5!4D 	6&5D"#|!&&T.88 ' 
 
 ((9%% 	4r3   r   c                     j                                          t          |          }t          |          }|dd|r|d<   |r|d<   |r|d<   d	 fd}t           |                      S )
a  
        Query the peer's representation with a natural language question, streaming the response.

        Makes an API call to the Honcho dialectic endpoint to query either the peer's
        global representation (all content associated with this peer) or their local
        representation of another peer (what this peer knows about the target peer).

        Args:
            query: The natural language question to ask.
            target: Optional target peer for local representation query. If provided,
                    queries what this peer knows about the target peer rather than
                    querying the peer's global representation. Can be a peer ID string
                    or a Peer object.
            session: Optional session to scope the query to. If provided, only
                     information from that session is considered. Can be a session
                     ID string or a Session object.
            reasoning_level: Optional reasoning level for the query: "minimal", "low", "medium",
                             "high", or "max". Defaults to "low" if not provided.

        Returns:
            DialecticStreamResponse object that can be iterated over and provides final response
        Trq   rh   rs   rj   r-   Generator[str, None, None]c            	   3     K   t          j        j                            dt	          j        j        j                                       E d {V  d S )NPOSTrR   )r   r,   r9   rr   r   ru   r>   rB   )rS   r0   s   r1   stream_responsez)Peer.chat_stream.<locals>.stream_response,  sy      '"))$T%6@@ *            r3   )r-   r{   )r,   r8   r   r   )	r0   rk   rh   ri   rj   rw   rx   r~   rS   s	   `       @r1   chat_streamzPeer.chat_stream   s    @ 	&&(((v&&	(11).$?? 	'&DN 	5!4D 	6&5D"#	 	 	 	 	 	 	 ''8'8999r3   filters$SyncPage[SessionResponse, 'Session']c                      j                                          ddlm  j         j                            t          j         j         j	                  rdind          }d fd
d fdt          |t                    S )a  
        Get all sessions this peer is a member of.

        Makes an API call to retrieve all sessions where this peer is an active participant.
        Sessions are created when peers are added to them or send messages to them.

        Returns:
            A paginated list of Session objects this peer belongs to. Returns an empty
            list if the peer is not a member of any sessions
        r   r#   r   NrR   ri   r   r-   r$   c                0     | j         j                  S r7   )rB   r,   )ri   r$   r0   s    r1   	transformz Peer.sessions.<locals>.transformM  s    77:t|444r3   pageint"SyncPage[SessionResponse, Session]c                    j         j                            t          j        j        j                  rdind d| i          }t          |t                    S )Nr   r   rS   rk   )	r,   r9   rT   r   peer_sessions_listr>   rB   r   r   )r   	next_data
fetch_nextr   r0   r   s     r1   r   z!Peer.sessions.<locals>.fetch_nextP  sf    *//)$*;TWEE-4>i))$tn 0  I
 I	:NNNr3   )ri   r   r-   r$   )r   r   r-   r   )r,   r8   ri   r$   r9   rT   r   r   r>   rB   r   r   )r0   r   rH   r$   r   r   s   `` @@@r1   sessionszPeer.sessions7  s     	&&((($$$$$$|!&&%d&7AA)0:)W%%d ' 
 

	5 	5 	5 	5 	5 	5 	5	O 	O 	O 	O 	O 	O 	O 	O 	O oy*EEEr3   r   z The text content for the messagezOptional metadata dictionaryz?Optional configuration dictionary to associate with the messagezOptional created-at timestamp for the message. Accepts a datetime which will be converted to an ISO 8601 string, or a preformatted string.)r2   r5   
created_atrt   dict[str, Any] | Noner   datetime.datetime | str | Noner   c                   ddl m} |dk    r'|                                dk    rt          d          t	          |          }|r |di |nd}t          | j        ||||          S )a  
        Build a message object attributed to this peer (synchronous, no API call).

        This is a convenience method for creating message objects with this peer's ID
        already set. The returned object can then be passed to `session.add_messages()`.

        Note:
            This method is synchronous and does NOT send the message to Honcho.
            To actually create the message on the server, pass the returned object to
            `session.add_messages()`.

        Args:
            content: The text content for the message
            metadata: Optional metadata dictionary to associate with the message
            configuration: Optional configuration dictionary (e.g., reasoning settings)
            created_at: Optional created-at timestamp

        Returns:
            A MessageCreateParams object ready to be passed to `session.add_messages()`

        Example:
            ```python
            msg = peer.message("Hello!")
            await session.add_messages(msg)

            # Or batch multiple messages:
            await session.add_messages([
                alice.message("Hi Bob"),
                bob.message("Hey Alice!"),
            ])
            ```
        r   )MessageConfiguration z)Message content cannot be only whitespaceN)ra   rt   r5   r2   r    )	api_typesr   strip
ValueErrorr   r   rB   )r0   rt   r2   r5   r   r   created_at_dt
config_objs           r1   messagezPeer.messageZ  s    f 	433333b==W]]__22HIII&z22>KU))::M:::QU
"G$$
 
 
 	
r3   zThe search query to usezFilters to scope the search
   d   zNumber of results to return)r'   gelerV   limitr   list[Message]c                    | j                                          | j         j                            t	          j        | j        | j                  |||d          }d |D             S )a>  
        Search across all messages in the workspace with this peer as author.

        Makes an API call to search endpoint.

        Args:
            query: The search query to use
            filters: Filters to scope the search. See [search filters documentation](https://docs.honcho.dev/v3/documentation/core-concepts/features/using-filters).
            limit: Number of results to return (1-100, default: 10)

        Returns:
            A list of Message objects representing the search results.
            Returns an empty list if no messages are found.
        )rk   r   r   rR   c                Z    g | ](}t          j        t          j        |                    )S r   )r   from_api_responser   rM   ).0items     r1   
<listcomp>zPeer.search.<locals>.<listcomp>  s>     
 
 
 %o&DT&J&JKK
 
 
r3   )r,   r8   r9   rT   r   peer_searchr>   rB   )r0   rk   r   r   rH   s        r1   searchzPeer.search  sz    2 	&&(((|!&&t0$':: WuEE ' 
 

 

 
 
 	
r3   list[str] | Nonec                   | j                                          t          |          }|rd|ind}| j         j                            t          j        | j        | j                  |          }t          j
        |          }|j        S )a.  
        Get the peer card for this peer.

        Makes an API call to retrieve the peer card, which contains a representation
        of what this peer knows. If a target is provided, returns this peer's local
        representation of the target peer.

        Args:
            target: Optional target peer for local card. If provided, returns this
                    peer's card of the target peer. Can be a Peer object or peer ID string.

        Returns:
            A list of strings representing the peer card, or None if none is available
        rh   Nrk   )r,   r8   r   r9   rv   r   	peer_cardr>   rB   r   rM   )r0   rh   rw   rk   rH   responses         r1   get_cardzPeer.get_card  s    & 	&&(((v&&	)2<9%%|!%%T.88 & 
 
 $2488!!r3   c                f    t          j        dt          d           |                     |          S )z#Deprecated: use get_card() instead.z,card() is deprecated, use get_card() instead   )
stacklevel)rh   )warningswarnDeprecationWarningr   )r0   rh   s     r1   cardz	Peer.card  s<    
 	:	
 	
 	
 	

 }}F}+++r3   r   	list[str]c                   | j                                          t          |          }|rd|ind}| j         j                            t          j        | j        | j                  d|i|          }t          j
        |          }|j        S )a"  
        Set the peer card for this peer.

        Makes an API call to set the peer card. If a target is provided, sets this
        peer's local card of the target peer.

        Args:
            peer_card: A list of strings to set as the peer card.
            target: Optional target peer for local card. If provided, sets this
                    peer's card of the target peer. Can be a Peer object or peer ID string.

        Returns:
            A list of strings representing the updated peer card, or None if none is available
        rh   Nr   r   )r,   r8   r   r9   rY   r   r   r>   rB   r   rM   )r0   r   rh   rw   rk   rH   r   s          r1   set_cardzPeer.set_card  s    ( 	&&(((v&&	)2<9%%|!%%T.88y) & 
 

 $2488!!r3   )r   r   g        g      ?search_querysearch_top_k
int | Nonesearch_max_distancefloat | Noneinclude_most_frequentbool | Nonemax_conclusionsc                   | j                                          t          |          }t          |          }	i }
|r||
d<   |	r|	|
d<   |||
d<   |||
d<   |||
d<   |||
d<   |||
d<   | j         j                            t          j        | j        | j                  |
	          }t          j
        |          }|j        S )
a  
        Get a subset of the representation of the peer.

        Args:
            session: Optional session to scope the representation to.
            target: Optional target peer to get the representation of. If provided,
            returns the representation of the target from the perspective of this peer.
            search_query: Semantic search query to filter relevant conclusions
            search_top_k: Number of semantically relevant facts to return
            search_max_distance: Maximum semantic distance for search results (0.0-1.0)
            include_most_frequent: Whether to include the most frequent conclusions
            max_conclusions: Maximum number of conclusions to include

        Returns:
            A Representation string

        Example:
            ```python
            # Get global representation
            rep = peer.representation()
            print(rep)

            # Get representation scoped to a session
            session_rep = peer.representation(session='session-123')

            # Get representation with semantic search
            searched_rep = peer.representation(
                search_query='preferences',
                search_top_k=10,
                max_conclusions=50
            )
            ```
        rs   rh   Nr   r   r   r   r   rR   )r,   r8   r   r9   rT   r   peer_representationr>   rB   r   rM   representation)r0   ri   rh   r   r   r   r   r   rs   rw   rS   rH   r   s                r1   r   zPeer.representation  s    X 	&&(((((
v&&	! 	,!+D 	'&DN##/D ##/D **=D&' ,,AD()&&5D"#|!&&&t'8$'BB ' 
 
 *8>>&&r3   r   c                V   | j                                          t          |          }i }|r||d<   |||d<   |||d<   |||d<   |||d<   |||d<   | j         j                            t          j        | j        | j                  |r|nd          }	t          j
        |	          S )	a  
        Get context for this peer, including representation and peer card.

        This is a convenience method that retrieves both the working representation
        and peer card in a single API call.

        Args:
            target: Optional target peer to get context for. If provided, returns
                   the context for the target from this peer's perspective.
                   Can be a Peer object or peer ID string.
            search_query: Semantic search query to filter relevant conclusions
            search_top_k: Number of semantically relevant facts to return
            search_max_distance: Maximum semantic distance for search results (0.0-1.0)
            include_most_frequent: Whether to include the most frequent conclusions
            max_conclusions: Maximum number of conclusions to include

        Returns:
            A PeerContext object containing the representation and peer card

        Example:
            ```python
            # Get own context
            context = peer.context()
            print(context.representation)
            print(context.peer_card)

            # Get context for another peer
            context = peer.context(target='other-peer-id')

            # Get context with semantic search
            context = peer.context(
                search_query='preferences',
                search_top_k=10
            )
            ```
        rh   Nr   r   r   r   r   r   )r,   r8   r   r9   rv   r   peer_contextr>   rB   r   rM   )
r0   rh   r   r   r   r   r   rw   rk   rH   s
             r1   contextzPeer.contextS  s    \ 	&&(((v&&	 " 	('E(O#$0E.!#$0E.!*+>E'( ,-BE)*&'6E#$|!%% 147;; *%%d & 
 
 #1$777r3   r   c                N    t          | j        | j        | j        | j                  S )a  
        Access this peer's self-conclusions (where observer == observed == self).

        This property provides a convenient way to access conclusions that this peer
        has made about themselves. Use this for self-conclusion scenarios.

        Returns:
            A ConclusionScope scoped to this peer's self-conclusions

        Example:
            ```python
            # List self-conclusions
            obs_list = peer.conclusions.list()

            # Search self-conclusions
            results = peer.conclusions.query("preferences")

            # Delete a self-conclusion
            peer.conclusions.delete("obs-123")
            ```
        )r   r,   r>   rB   r/   s    r1   conclusionszPeer.conclusions  s!    . t|T->QQQr3   str | PeerBasec                    t          |t                    r|j        n|}t          | j        | j        | j        |          S )aQ  
        Access conclusions this peer has made about another peer.

        This method provides scoped access to conclusions where this peer is the
        observer and the target is the observed peer.

        Args:
            target: The target peer (either a Peer object or peer ID string)

        Returns:
            A ConclusionScope scoped to this peer's conclusions of the target

        Example:
            ```python
            # Get conclusions about another peer
            bob_conclusions = peer.conclusions_of("bob")

            # List conclusions
            obs_list = bob_conclusions.list()

            # Search conclusions
            results = bob_conclusions.query("work history")

            # Get the representation from these conclusions
            rep = bob_conclusions.get_representation()
            ```
        )
isinstancer   rB   r   r,   r>   )r0   rh   rw   s      r1   conclusions_ofzPeer.conclusions_of  s9    8 ",FH!=!=IFII6	t|T->SSSr3   c                    d| j          dS )z
        Return a string representation of the Peer.

        Returns:
            A string representation suitable for debugging
        z	Peer(id='z')rF   r/   s    r1   __repr__zPeer.__repr__  s     '47&&&&r3   c                    | j         S )zx
        Return a human-readable string representation of the Peer.

        Returns:
            The peer's ID
        rF   r/   s    r1   __str__zPeer.__str__  s     wr3   )r-   r(   )r-   r*   )r-   r;   )r-   rD   )rH   rD   r-   rI   )r-   r   )r5   r   r-   rW   )r-   r[   )
ra   r;   rb   r   r2   r(   r5   r*   r-   rW   )
rk   r;   rh   rl   ri   rm   rj   rn   r-   ro   )
rk   r;   rh   rl   ri   rm   rj   rn   r-   r   r7   )r   r(   r-   r   )
rt   r;   r2   r(   r5   r   r   r   r-   r   )rk   r;   r   r(   r   r   r-   r   )rh   rl   r-   r   )r   r   rh   rl   r-   r   )ri   rm   rh   rl   r   ro   r   r   r   r   r   r   r   r   r-   r;   )rh   rl   r   ro   r   r   r   r   r   r   r   r   r-   r   )r-   r   )rh   r   r-   r   )'__name__
__module____qualname____doc__r
   r)   __annotations__r+   r,   propertyr2   r5   r:   r?   rC   rG   rP   rU   r   r	   rZ   r]   r   re   ry   r   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__)rg   s   @r1   r&   r&   )   s           +6+d*C*C*CICCCC(3D(A(A(ANAAAA#G%%%%   X # # # X#
" " "/ / / /7 7 7 7   U U U U# # # #   %*E#;Q$R$R$R, , , , ],     X* ]**TBBBCCC uN
 
 

 eC-EFFF4: .3U L.
 .
 .
 ,15{,
 ,
 ,
4: 4: 4: 4: 4: 4: 4: DC4:l ]**TBBBCCC U31:VWWW2 )-,02 2 2 2 2 DC2h ]**TBBBCCC U31:VWWW4: )-,04: 4: 4: 4: 4: DC4:n 37!F !F !F !F !FF  uA+M
 
 
A
 .3U<.
 .
 .
 05uY0
 0
 0
 6;U e6
 6
 6
A
 A
 A
 A
 A
 ]A
F  U31:STTT,1E;-
 -
 -
 U12O
 
 
 
  
  
  
 ] 
D ]**TBBBCCC )-" " " " DC"@ )-
, 
, 
, 
, 
, ]**TBBBCCC )-" " " " DC"> ]**TBBBCCC -1(,#'#(5!#<#<#<,1E$33,G,G,G-1&+eDQ3&?&?&?D' D' D' D' DCD'L ]**TBBBCCC )-#'#(5!#<#<#<,1E$33,G,G,G-1&+eDQ3&?&?&?B8 B8 B8 B8 DCB8H R R R XR0T T T T>' ' ' '       r3   r&   )7r   
__future__r   datetimeloggingr   collections.abcr   typingr   r   r   pydanticr   r	   r
   r   r   r   r   r   r   r   r   r   r   baser   r   r   r   httpr   r   r   mixinsr   
paginationr   typesr   utilsr   r   r   r]   r!   clientr"   ri   r$   	getLoggerr   loggerr&   r   r3   r1   <module>r      s%   % % " " " " " "    % % % % % % . . . . . . . . . . B B B B B B B B B B B B	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ( ' ' ' ' ' ' ' ( ( ( ( ( (             ' ' ' ' ' '             * * * * * * ? ? ? ? ? ? ? ? ? ? !      		8	$	$w
 w
 w
 w
 w
8( w
 w
 w
 w
 w
r3   