
     @g`\                    F   d dl m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	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 ddlmZmZmZ ddlmZ d	d
lmZ  ej        d          Z ddZ! G d dej"                  Z# G d de          Z$ G d d          Z%dS )    )annotationsN   )AsyncNetworkStream)ConnectionNotAvailableLocalProtocolErrorRemoteProtocolError)OriginRequestResponse)	AsyncLockAsyncSemaphoreAsyncShieldCancellation)Trace   )AsyncConnectionInterfacezhttpcore.http2requestr
   returnboolc                >    t          d | j        D                       S )Nc              3  |   K   | ]7\  }}|                                 d k    p|                                 dk    V  8dS )s   content-length   transfer-encodingNlower.0kvs      I/var/www/piapp/venv/lib/python3.11/site-packages/httpcore/_async/http2.py	<genexpr>z#has_body_headers.<locals>.<genexpr>   s[        Aq 	
		&&K!''))7K*K         )anyheaders)r   s    r   has_body_headersr#      s2      O     r    c                      e Zd ZdZdZdZdS )HTTPConnectionStater   r      N)__name__
__module____qualname__ACTIVEIDLECLOSED r    r   r%   r%   $   s        FDFFFr    r%   c                  (   e Zd ZdZej                            d          Z	 d=d>dZd?dZ	d@dZ
dAdZdAdZdBdZdAdZdCdZdDdZdEd Z	 d=dFd"ZdGd%ZdHd&ZdId'ZdJd)Zd@d*ZdKd+ZdLd-ZdMd.ZdMd/ZdMd0ZdMd1ZdNd3ZdNd4ZdOd5Z 	 	 	 dPdQd<Z!dS )RAsyncHTTP2Connection   F)validate_inbound_headersNoriginr	   streamr   keepalive_expiryfloat | Nonec                   || _         || _        || _        t          j                            | j                  | _        t          j	        | _
        d | _        d| _        t                      | _        t                      | _        t                      | _        t                      | _        d| _        d| _        d| _        i | _        d | _        d | _        d | _        d S )N)configr   F)_origin_network_stream_keepalive_expiryh2
connectionH2ConnectionCONFIG	_h2_stater%   r+   _state
_expire_at_request_countr   
_init_lock_state_lock
_read_lock_write_lock_sent_connection_init_used_all_stream_ids_connection_error_events_connection_terminated_read_exception_write_exception)selfr2   r3   r4   s       r   __init__zAsyncHTTP2Connection.__init__.   s     %/?334;3GG).(,#++$;;#++$;;%*"$)!!&  	 NR#1526r    r   r
   r   r   c           	     	  K   |                      |j        j                  s$t          d|j        j         d| j                   | j        4 d {V  | j        t          j        t          j	        fv r)| xj
        dz  c_
        d | _        t          j        | _        nt                      	 d d d           d {V  n# 1 d {V swxY w Y   | j        4 d {V  | j        s	 d|i}t          dt           ||          4 d {V   | j        di | d {V  d d d           d {V  n# 1 d {V swxY w Y   nT# t$          $ rG}t'                      5  |                                  d {V  d d d            n# 1 swxY w Y   |d }~ww xY wd| _        d| _        | j        j        j        }t3          |          | _        t7          || j        z
            D ]!}| j                                         d {V  "d d d           d {V  n# 1 d {V swxY w Y   | j                                         d {V  	 | j                                        }g | j        |<   n=# t>          j         j!        $ r& d| _"        | xj
        dz  c_
        t                      w xY w	 ||d}t          dt           ||          4 d {V  | #                    ||           d {V  d d d           d {V  n# 1 d {V swxY w Y   t          d	t           ||          4 d {V  | $                    ||           d {V  d d d           d {V  n# 1 d {V swxY w Y   t          d
t           ||          4 d {V 	 }| %                    ||           d {V \  }}	||	f|_&        d d d           d {V  n# 1 d {V swxY w Y   tO          ||	tQ          | ||          d| j)        |d          S # t$          $ r}t'                      5  d|i}t          dt           ||          4 d {V  | *                    |           d {V  d d d           d {V  n# 1 d {V swxY w Y   d d d            n# 1 swxY w Y   tW          |t>          j         j,                  r*| j-        rt]          | j-                  t_          |          |d }~ww xY w)NzAttempted to send request to z on connection to r   r   send_connection_initTr   	stream_idsend_request_headerssend_request_bodyreceive_response_headersrS   s   HTTP/2)http_versionnetwork_streamrS   )statusr"   content
extensionsrS   response_closedr-   )0can_handle_requesturlr2   RuntimeErrorr8   rD   r@   r%   r*   r+   rB   rA   r   rC   rG   r   logger_send_connection_initBaseExceptionr   aclose_max_streamsr?   local_settingsmax_concurrent_streamsr   _max_streams_semaphorerangeacquireget_next_available_stream_idrJ   r;   
exceptionsNoAvailableStreamIDErrorrH   _send_request_headers_send_request_body_receive_responsereturn_valuer   HTTP2ConnectionByteStreamr9   _response_closed
isinstanceProtocolErrorrK   r   r   )
rN   r   kwargsexclocal_settings_max_streams_rS   tracerZ   r"   s
             r   handle_async_requestz)AsyncHTTP2Connection.handle_async_requestS   s
     &&w{'9:: 	
 %0B % %l% %  
 # 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/{29;N;STTT##q(##"&18,....	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ 	/ ? 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@- @'1F$%;VWfUU C C C C C C C C8d8BB6BBBBBBBBBC C C C C C C C C C C C C C C C C C C C C C C C C C C$   022 , ,"kkmm+++++++, , , , , , , , , , , , , , ,I
 .2* %&! N1H + /==W.X.X+9D<MMNN @ @A5==??????????/	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@ 	@2 )11333333333	+CCEEI&(DL##}5 	+ 	+ 	+(,D%1$(***	+
.	!(yAAF3VWfMM W W W W W W W W00I0VVVVVVVVVW W W W W W W W W W W W W W W W W W W W W W W W W W W0&'6JJ T T T T T T T T--g-SSSSSSSSST T T T T T T T T T T T T T T T T T T T T T T T T T T*FGV  7 7 7 7 7 7 7 7(,(>(>#y )? ) ) # # # # # # '-g%6"7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 1$9UUU$-&*&:!* 		 	 	 	  	 	 	(** E E%y1 !2FGVLL E E E E E E E E//)/DDDDDDDDDE E E E E E E E E E E E E E E E E E E E E E E E E E EE E E E E E E E E E E E E E E
 #r}:;; . . K-d.IJJJ )---I-	sk  AB==
C
C	H%!D>D,D>,
D6	6D>9D6	:D>=H>
FF
E=1F
=FF
FF

FA/H
HH#I% %:J#"O; K5#O; 5
K??O; K? O; #MO; 
MO;  M! O; *N>,O; >
OO; O.O; ;
SS"R5Q$R$
Q..R1Q.2R5SR	SR		ASSNonec           	       K   t           j                            dt           j        j        j        dt           j        j        j        dt           j        j        j        di          | j        _        | j        j        t           j        j        j	        = | j        
                                 | j                            d           |                     |           d{V  dS )z
        The HTTP/2 connection requires some initial setup before we can start
        using individual request/response streams on it.
        Tr   d   r0   )clientinitial_values   N)r;   settingsSettingsSettingCodesENABLE_PUSHMAX_CONCURRENT_STREAMSMAX_HEADER_LIST_SIZEr?   rf   ENABLE_CONNECT_PROTOCOLinitiate_connectionincrement_flow_control_window_write_outgoing_data)rN   r   s     r   rb   z*AsyncHTTP2Connection._send_connection_init   s       )+(<(< (4a(?(=u )= 
)
 
)
% N)K$<
 	**,,,44U;;;''00000000000r    rS   intc                r  K   t          |           }d |j        D             d         }d|j        fd|fd|j        j        fd|j        j        fgd |j        D             z   }| j                            |||           | j                            d	|
           | 	                    |           d{V  dS )z@
        Send the request headers to a given stream ID.
        c                H    g | ]\  }}|                                 d k    | S )   hostr   r   s      r   
<listcomp>z>AsyncHTTP2Connection._send_request_headers.<locals>.<listcomp>   s.    KKK41aaggii76J6JQ6J6J6Jr    r   s   :methods
   :authoritys   :schemes   :pathc                l    g | ]1\  }}|                                 d v|                                 |f2S ))r   r   r   r   s      r   r   z>AsyncHTTP2Connection._send_request_headers.<locals>.<listcomp>   sR     
 
 
1wwyy  WWYYN  r    )
end_streamr   rW   N)
r#   r"   methodr_   schemetargetr?   send_headersr   r   )rN   r   rS   r   	authorityr"   s         r   rn   z*AsyncHTTP2Connection._send_request_headers   s       *'222
 LK7?KKKAN	 (I&+,w{)*	


 

 
 

 	##Iw:#NNN44Ui4PPP''00000000000r    c                   K   t          |          sdS t          |j        t          j                  sJ |j        2 3 d{V }|                     |||           d{V  %6 |                     ||           d{V  dS )zP
        Iterate over the request body sending it to a given stream ID.
        N)r#   rt   r3   typingAsyncIterable_send_stream_data_send_end_stream)rN   r   rS   datas       r   ro   z'AsyncHTTP2Connection._send_request_body   s        (( 	F'.&*>?????!. 	C 	C 	C 	C 	C 	C 	C$(()TBBBBBBBBBB )##GY77777777777s   A!r   bytesc                  K   |r|                      ||           d{V }t          t          |          |          }|d|         ||d         }}| j                            ||           |                     |           d{V  |dS dS )zI
        Send a single chunk of data in one or more data frames.
        N)_wait_for_outgoing_flowminlenr?   	send_datar   )rN   r   rS   r   max_flow
chunk_sizechunks          r   r   z&AsyncHTTP2Connection._send_stream_data  s        	5!99'9MMMMMMMMHSYY11J{
{+T*++->4EN$$Y666++G444444444  	5 	5 	5 	5 	5r    c                t   K   | j                             |           |                     |           d{V  dS )z`
        Send an empty data frame on on a given stream ID with the END_STREAM flag set.
        N)r?   r   r   )rN   r   rS   s      r   r   z%AsyncHTTP2Connection._send_end_stream  sJ       	!!),,,''00000000000r    %tuple[int, list[tuple[bytes, bytes]]]c                Z  K   	 |                      ||           d{V }t          |t          j        j                  rn=d}g }|j        D ]\\  }}|dk    r%t          |                    dd                    }0|                    d          s|	                    ||f           ]||fS )	zT
        Return the response status code and headers for a given stream ID.
        TN   s   :statusasciiignore)errors   :)
_receive_stream_eventrt   r;   eventsResponseReceivedr"   r   decode
startswithappend)rN   r   rS   eventstatus_coder"   r   r   s           r   rp   z&AsyncHTTP2Connection._receive_response  s      	44WiHHHHHHHHE%!;<< 	
 M 	' 	'DAqJ!!((78("D"DEE\\$'' '1v&&&W%%r    typing.AsyncIterator[bytes]c               R  K   	 |                      ||           d{V }t          |t          j        j                  rH|j        }| j                            ||           |                     |           d{V  |j	        W V  n!t          |t          j        j
                  rdS )z]
        Iterator that returns the bytes of the response body for a given stream ID.
        TN)r   rt   r;   r   DataReceivedflow_controlled_lengthr?   acknowledge_received_datar   r   StreamEnded)rN   r   rS   r   amounts        r   _receive_response_bodyz+AsyncHTTP2Connection._receive_response_body0  s      	44WiHHHHHHHHE%!788 588KKK//888888888j     E29#899 	r    Kh2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEndedc                F  K   | j                             |          s6|                     ||           d{V  | j                             |          6| j         |                             d          }t	          |t
          j        j                  rt          |          |S )z
        Return the next available event for a given stream ID.

        Will read more data from the network if required.
        Nr   )	rJ   get_receive_eventspoprt   r;   r   StreamResetr   )rN   r   rS   r   s       r   r   z*AsyncHTTP2Connection._receive_stream_event@  s       ,""9-- 	;&&w	::::::::: ,""9-- 	;Y'++A..eRY233 	-%e,,,r    
int | Nonec           	       K   | j         4 d{V  | j        H| j        j        }|r&|r$||k    r| xj        dz  c_        t	                      t          | j                  || j                            |          sP|                     |           d{V }|D ]1}t          |t          j        j                  rdt          dt          |          4 d{V 	 }|                     |           d{V  ||_        ddd          d{V  n# 1 d{V swxY w Y   t          |t          j        j        t          j        j        t          j        j        t          j        j        f          r5|j        | j        v r%| j        |j                                     |           t          |t          j        j                  r|| _        3ddd          d{V  n# 1 d{V swxY w Y   |                     |           d{V  dS )zp
        Read some data from the network until we see one or more events
        for a given stream ID.
        Nr   receive_remote_settings)rE   rK   last_stream_idrB   r   r   rJ   r   _read_incoming_datart   r;   r   RemoteSettingsChangedr   ra   _receive_remote_settings_changerq   r   r   r   r   rS   r   ConnectionTerminatedr   )rN   r   rS   r   r   r   rz   s          r   r   z$AsyncHTTP2Connection._receive_eventsO  s8      ? %	< %	< %	< %	< %	< %	< %	< %	<*6!%!<!K 3 3I4N4N''1,''0222)$*EFFF  (8(8(C(C #77@@@@@@@@# < <E!%)HII <#(5vw$ $ 7 7 7 7 7 7 7 7""&"F"Fu"M"MMMMMMMM16E.	7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 $I6I2I1I1	  < !?dl:: L9@@GGG#E29+IJJ <6;3K%	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	< %	<N ''00000000000s7   CG#D<G
DGDB1G
G),G)r   h2.events.Eventc                  K   |j                             t          j        j        j                  }|rt          |j        | j        j	        j
                  }|r|| j        k    r|| j        k    r:| j                                         d {V  | xj        dz  c_        || j        k    :|| j        k     rB| j                                         d {V  | xj        dz  c_        || j        k     :d S d S d S d S d S )Nr   )changed_settingsr   r;   r   r   r   r   	new_valuer?   rf   rg   re   rh   releaserj   )rN   r   rg   new_max_streamss       r   r   z4AsyncHTTP2Connection._receive_remote_settings_change  sG     !&!7!;!;K$;"
 "
 " 	+!&0-D O  +?d6G#G#G%(9995==?????????%%*%% &(999 &(9995==?????????%%*%% &(99999	+ 	+
+ +#G#G :9r    c                  K   | j                                          d {V  | j        |= | j        4 d {V  | j        r"| j        s|                                  d {V  nw| j        t          j        k    rb| j        s[t          j	        | _        | j
        "t          j                    }|| j
        z   | _        | j        r|                                  d {V  d d d           d {V  d S # 1 d {V swxY w Y   d S N)rh   r   rJ   rD   rK   rd   r@   r%   r*   r+   r:   time	monotonicrA   rH   )rN   rS   nows      r   rs   z%AsyncHTTP2Connection._response_closed  s     )11333333333L## 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	(* 	(4< 	(kkmm######## 3 :::4<:16)5.**C&)D,B&BDO, (++--'''''''
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	( 
	(s   B!C++
C58C5c                   K   | j                                          t          j        | _        | j                                         d {V  d S r   )r?   close_connectionr%   r,   r@   r9   rd   rN   s    r   rd   zAsyncHTTP2Connection.aclose  sS       	''))))0"))+++++++++++r    list[h2.events.Event]c                z  K   |j                             di           }|                    dd           }| j        | j        	 | j                            | j        |           d {V }|dk    rt          d          n"# t          $ r}|| _        d| _        |d }~ww xY w| j	        
                    |          }|S )Ntimeoutreadr    zServer disconnectedT)r\   r   rL   r9   r   READ_NUM_BYTESr   	ExceptionrI   r?   receive_data)rN   r   timeoutsr   r   rw   r   s          r   r   z(AsyncHTTP2Connection._read_incoming_data  s      %)))R88,,vt,,+&&	-2243FPPPPPPPPDs{{)*?@@@  	 	 	 $'D %)D"I	 )-(C(CD(I(Is   ;A? ?
B	BBc                  K   |j                             di           }|                    dd           }| j        4 d {V  | j                                        }| j        | j        	 | j                            ||           d {V  n"# t          $ r}|| _        d| _	        |d }~ww xY w	 d d d           d {V  d S # 1 d {V swxY w Y   d S )Nr   writeT)
r\   r   rF   r?   data_to_sendrM   r9   r   r   rI   )rN   r   r   r   r   rw   s         r   r   z)AsyncHTTP2Connection._write_outgoing_data  s     %)))R88,,w--# 	 	 	 	 	 	 	 	>6688L$0++*00wGGGGGGGGGG    ),%)-&	 H	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s6   (C*!BC
B+B&&B++C
CCc                0  K   | j                             |          }| j         j        }t          ||          }|dk    rW|                     |           d{V  | j                             |          }| j         j        }t          ||          }|dk    W|S )a  
        Returns the maximum allowable outgoing flow for a given stream.

        If the allowable flow is zero, then waits on the network until
        WindowUpdated frames have increased the flow rate.
        https://tools.ietf.org/html/rfc7540#section-6.9
        r   N)r?   local_flow_control_windowmax_outbound_frame_sizer   r   )rN   r   rS   
local_flowmax_frame_sizeflows         r   r   z,AsyncHTTP2Connection._wait_for_outgoing_flow  s       .BB9MM
"nD:~..aii&&w/////////AA)LLJ!^CNz>22D	 aii
 r    r   c                    || j         k    S r   )r8   rN   r2   s     r   r^   z'AsyncHTTP2Connection.can_handle_request  s    %%r    c                    | j         t          j        k    o9| j         o1| j         o)| j        j        j        t          j	        j
        j        k     S r   )r@   r%   r,   rI   rH   r?   state_machinestater;   r<   ConnectionStater   s    r   is_availablez!AsyncHTTP2Connection.is_available  sX    K.55 **-- ,2=078		
r    c                P    t          j                    }| j        d uo
|| j        k    S r   )r   r   rA   )rN   r   s     r   has_expiredz AsyncHTTP2Connection.has_expired  s(    nd*DsT_/DDr    c                ,    | j         t          j        k    S r   )r@   r%   r+   r   s    r   is_idlezAsyncHTTP2Connection.is_idle  s    {1666r    c                ,    | j         t          j        k    S r   )r@   r%   r,   r   s    r   	is_closedzAsyncHTTP2Connection.is_closed  s    {1888r    strc                \    t          | j                  }|d| j        j         d| j         S )Nz
, HTTP/2, , Request Count: )r   r8   r@   namerB   r   s     r   infozAsyncHTTP2Connection.info  sD    T\"" 4 44;#3 4 4"14 4	
r    c           	     ~    | j         j        }t          | j                  }d| d|d| j        j         d| j         d	S )N<z [z, r   z]>)	__class__r'   r   r8   r@   r   rB   )rN   
class_namer2   s      r   __repr__zAsyncHTTP2Connection.__repr__  sc    ^,
T\""6
 6 6f 6 6$+*: 6 6"16 6 6	
r    c                
   K   | S r   r-   r   s    r   
__aenter__zAsyncHTTP2Connection.__aenter__  s      r    exc_typetype[BaseException] | None	exc_valueBaseException | None	tracebacktypes.TracebackType | Nonec                >   K   |                                   d {V  d S r   )rd   )rN   r  r  r	  s       r   	__aexit__zAsyncHTTP2Connection.__aexit__   s.       kkmmr    r   )r2   r	   r3   r   r4   r5   )r   r
   r   r   )r   r
   r   r|   )r   r
   rS   r   r   r|   )r   r
   rS   r   r   r   r   r|   )r   r
   rS   r   r   r   )r   r
   rS   r   r   r   )r   r
   rS   r   r   r   )r   r
   rS   r   r   r|   )r   r   r   r|   )rS   r   r   r|   r   r|   )r   r
   r   r   )r   r
   rS   r   r   r   )r2   r	   r   r   )r   r   )r   r   )r   r/   )NNN)r  r  r  r  r	  r
  r   r|   )"r'   r(   r)   r   r;   r7   H2Configurationr>   rO   r{   rb   rn   ro   r   r   rp   r   r   r   r   rs   rd   r   r   r   r^   r   r   r   r   r   r  r  r  r-   r    r   r/   r/   *   si       NY&&&FFF *.	#7 #7 #7 #7 #7Jd d d dL1 1 1 1B1 1 1 1>
8 
8 
8 
85 5 5 51 1 1 1& & & &*         9=.1 .1 .1 .1 .1`+ + + +"( ( ( (, , , ,   8   6   (& & & &	
 	
 	
 	
E E E E7 7 7 79 9 9 9
 
 
 

 
 
 
   
 04*.04	      r    r/   c                  &    e Zd Zdd	ZddZddZdS )rr   r<   r/   r   r
   rS   r   r   r|   c                >    || _         || _        || _        d| _        d S )NF)_connection_request
_stream_id_closed)rN   r<   r   rS   s       r   rO   z"HTTP2ConnectionByteStream.__init__*  s%     &#r    r   c                 K   | j         | j        d}	 t          dt          | j         |          4 d {V  | j                            | j         | j                  2 3 d {V }|W V  6 	 d d d           d {V  d S # 1 d {V swxY w Y   d S # t          $ rG}t                      5  |                                  d {V  d d d            n# 1 swxY w Y   |d }~ww xY w)NrR   receive_response_body)	r  r  r   ra   r  r   rc   r   rd   )rN   rv   r   rw   s       r   	__aiter__z#HTTP2ConnectionByteStream.__aiter__2  s     !]II	4fdmVTT                #'#3#J#J MT_ $K $ $              %  KKKKK$ $                                                           
  	 	 	 )** $ $kkmm#######$ $ $ $ $ $ $ $ $ $ $ $ $ $ $I	sj   "B 'A>A)"A>+B >
BB BB 
C"C)CCC	CC	CC"c                  K   | j         sd| _         d| j        i}t          dt          | j        |          4 d {V  | j                            | j                   d {V  d d d           d {V  d S # 1 d {V swxY w Y   d S d S )NTrS   r]   rW   )r  r  r   ra   r  r  rs   )rN   rv   s     r   rd   z HTTP2ConnectionByteStream.acloseB  sY     | 	SDL!4?3F.vNN S S S S S S S S&77$/7RRRRRRRRRS S S S S S S S S S S S S S S S S S S S S S S S S S S S S S	S 	Ss   'A66
B B N)r<   r/   r   r
   rS   r   r   r|   )r   r   r  )r'   r(   r)   rO   r  rd   r-   r    r   rr   rr   )  sV               S S S S S Sr    rr   )r   r
   r   r   )&
__future__r   enumloggingr   typesr   	h2.configr;   h2.connection	h2.eventsh2.exceptionsh2.settings_backends.baser   _exceptionsr   r   r   _modelsr	   r
   r   _synchronizationr   r   r   _tracer   
interfacesr   	getLoggerra   r#   IntEnumr%   r/   rr   r-   r    r   <module>r*     s   " " " " " "                          / / / / / /         
 0 / / / / / / / / / Q Q Q Q Q Q Q Q Q Q       0 0 0 0 0 0		+	,	,       $,   | | | | |3 | | |~S S S S S S S S S Sr    