
    Aahn                        d Z ddgZddlZddlZddlZ	 ddlZej        ej        ej        ej	        dZ
n# e$ r dZY nw xY wddlmZ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mZmZmZmZmZ d	dlmZm Z m!Z!m"Z" ddl#m$Z$m%Z% de&de'fdZ( G d de          Z) G d de)          Z* G d de*          Z+ G d de          Z, G d de,          Z- G d de,          Z.dS )zFModule implementing low-level socket communication with MySQL servers.MySQLTcpSocketMySQLUnixSocket    N)TLSv1TLSv1.1TLSv1.2TLSv1.3)ABCabstractmethod)deque)AnyDequeListOptionalTuple   )InterfaceErrorNotSupportedErrorOperationalErrorProgrammingErrorReadTimeoutErrorWriteTimeoutError)COMPRESSED_PACKET_HEADER_LENGTHMAX_PAYLOAD_LENGTHMIN_COMPRESS_LENGTHPACKET_HEADER_LENGTH   )StreamWriteropen_connectionerrreturnc                 P    | j         st          |           n| j          d| j         S )z`Reformat the IOError error message.

    This function reformats the IOError error message.
     )errnostrstrerror)r   s    M/var/www/lms/venv/lib/python3.11/site-packages/mysql/connector/aio/network.py_strioerrorr'   I   s-    
 9G3s888SY*G*G*G*GG    c                       e Zd ZdZe	 	 	 ddedededee	         dee	         dee	         d	dfd
            Z
e	 ddej        dedee	         d	efd            ZdS )NetworkBrokeraP  Broker class interface.

    The network object is a broker used as a delegate by a socket object. Whenever the
    socket wants to deliver or get packets to or from the MySQL server it needs to rely
    on its network broker (netbroker).

    The netbroker sends `payloads` and receives `packets`.

    A packet is a bytes sequence, it has a header and body (referred to as payload).
    The first `PACKET_HEADER_LENGTH` or `COMPRESSED_PACKET_HEADER_LENGTH`
    (as appropriate) bytes correspond to the `header`, the remaining ones represent the
    `payload`.

    The maximum payload length allowed to be sent per packet to the server is
    `MAX_PAYLOAD_LENGTH`. When  `send` is called with a payload whose length is greater
    than `MAX_PAYLOAD_LENGTH` the netbroker breaks it down into packets, so the caller
    of `send` can provide payloads of arbitrary length.

    Finally, data received by the netbroker comes directly from the server, expect to
    get a packet for each call to `recv`. The received packet contains a header and
    payload, the latter respecting `MAX_PAYLOAD_LENGTH`.
    Nwriteraddresspayloadpacket_numbercompressed_packet_numberwrite_timeoutr    c                 
   K   dS )a  Send `payload` to the MySQL server.

        If provided a payload whose length is greater than `MAX_PAYLOAD_LENGTH`, it is
        broken down into packets.

        Args:
            sock: Object holding the socket connection.
            address: Socket's location.
            payload: Packet's body to send.
            packet_number: Sequence id (packet ID) to attach to the header when sending
                           plain packets.
            compressed_packet_number: Same as `packet_number` but used when sending
                                      compressed packets.
            write_timeout: Timeout in seconds before which sending a packet to the server
                           should finish else WriteTimeoutError is raised.


        Raises:
            :class:`OperationalError`: If something goes wrong while sending packets to
                                       the MySQL server.
        N )selfr+   r,   r-   r.   r/   r0   s          r&   writezNetworkBroker.writei   
        r(   readerread_timeoutc                 
   K   dS )aM  Get the next available packet from the MySQL server.

        Args:
            sock: Object holding the socket connection.
            address: Socket's location.
            read_timeout: Timeout in seconds before which reading a packet from the server
                          should finish.

        Returns:
            packet: A packet from the MySQL server.

        Raises:
            :class:`OperationalError`: If something goes wrong while receiving packets
                                       from the MySQL server.
            :class:`ReadTimeoutError`: If the time to receive a packet from the server takes
                                       longer than `read_timeout`.
            :class:`InterfaceError`: If something goes wrong while receiving packets
                                     from the MySQL server.
        Nr2   )r3   r6   r,   r7   s       r&   readzNetworkBroker.read   r5   r(   NNNN)__name__
__module____qualname____doc__r
   r   r$   bytesr   intr4   asyncioStreamReader	bytearrayr9   r2   r(   r&   r*   r*   Q   s         .  (,26'+   	
  } #+3-  } 
   ^> 
 '+	 $  sm	
 
   ^  r(   r*   c                   6   e Zd ZdZddZededeeef         fd            Z	dde
e         ddfdZd	ed
ededdfdZ	 	 ddej        dede
e         defdZ	 	 	 dd	ed
edede
e         de
e         de
e         ddfdZ	 ddej        d
ede
e         defdZdS )NetworkBrokerPlain,Broker class for MySQL socket communication.r    Nc                     d| _         d S N_pktnrr3   s    r&   __init__zNetworkBrokerPlain.__init__   s    r(   pktc                     t          |           t          k     rt          d          t          j        d| dd         dz             d         | d         }}||fS )-Recover the header information from a packet.3Can't recover header info from an incomplete packet<Ir          )lenr   
ValueErrorstructunpack)rO   pllseqids      r&   
get_headerzNetworkBrokerPlain.get_header   sb     s88***RSSS M$AaC7 233A6F 
 Ezr(   next_idc                 Z    || xj         dz  c_         n|| _         | xj         dz  c_         dS z:Set the given packet id, if any, else increment packet id.Nr      rK   r3   r]   s     r&   _set_next_pktnrz"NetworkBrokerPlain._set_next_pktnr   s4    ?KK1KKK!DKsr(   r+   r,   c                   K   	 |                     |           |                                 d{V  dS # t          $ r&}t          d|t	          |          f          |d}~wt
          $ r}t          d          |d}~ww xY w)z!Write packet to the comm channel.N  r#   valuesi  r#   )r4   drainIOErrorr   r'   AttributeError)r3   r+   r,   rO   r   s        r&   
_write_pktzNetworkBrokerPlain._write_pkt   s      	8LL,,..          	 	 	"G[-=-=#>    	8 	8 	8"...C7	8s    /5 
B!A  B-A>>Br   r6   sizer7   c                   K   	 t          d          }t          |          |k     rht          j        |                    |t          |          z
            |           d{V }|st          d          ||z  }t          |          |k     h|S # t          j        t          j        f$ r}t          d          |d}~ww xY w)z(Read `size` bytes from the comm channel.r(   Ni  rg     )	rD   rV   rB   wait_forr9   r   CancelledErrorTimeoutErrorr   )r3   r6   rl   r7   rO   chunkr   s          r&   _read_chunkzNetworkBrokerPlain._read_chunk   s      	8C..Cc((T//%.KKs3xx00,         5(t4444u c((T// J&(<= 	8 	8 	8"...C7	8s   BB C+B<<Cr-   r.   r/   r0   c                   K   |                      |           d}	 t          t          |          t          z            D ]~}t	          j        |                     ||dt          j        d| j	                  z   |||t          z            z             |           d{V  |                                   |t          z  }t	          j        |                     ||t          j        dt          |          |z
            dd         t          j        d| j	                  z   ||d         z             |           d{V  dS # t          j
        t          j        f$ r}	t          d          |	d}	~	ww xY w)	zSend payload to the MySQL server.

        If provided a payload whose length is greater than `MAX_PAYLOAD_LENGTH`, it is
        broken down into packets.
        r      <BNrS   rT   rn   rg   )rb   rangerV   r   rB   ro   rk   rX   packrL   rp   rq   r   )
r3   r+   r,   r-   r.   r/   r0   offset_r   s
             r&   r4   zNetworkBrokerPlain.write   s      	]+++ 	93w<<+==>> - -&OO# +dDK889!&64F+F"FGH  "	 	 	 	 	 	 	 	 	 $$&&&,,"Kc'llV&;<<QqSAk$445fgg&'  	 	 	 	 	 	 	 	 	 	 	 &(<= 	9 	9 	9#$///S8	9s   D$E E2E--E2c                 ,  K   	 |                      |t          |           d{V }|                     |          \  }| _        ||                      |||           d{V z   S # t          $ r&}t          d|t          |          f          |d}~ww xY w)z+Receive `one` packet from the MySQL server.Nrd   re   )rs   r   r\   rL   ri   r   r'   )r3   r6   r,   r7   headerpayload_lenr   s          r&   r9   zNetworkBrokerPlain.read  s      	++F4H,WWWWWWWWF (,v'>'>$K $"2"26;"U"UUUUUUUUU 	 	 	"G[-=-=#>  	s   AA# #
B-!BBr    Nr;   )r   Nr:   )r<   r=   r>   r?   rN   staticmethodr@   r   rA   r\   r   rb   r   r$   rk   rB   rC   rD   rs   r4   r9   r2   r(   r&   rF   rF      s       66    
 
%S/ 
 
 
 \
 x}     88 8 	8
 
8 8 8 8( &*	8 8$8 8 sm	8
 
8 8 8 82 (,26'+-9 -9-9 -9 	-9
  }-9 #+3--9  }-9 
-9 -9 -9 -9f '+	 $  sm	
 
     r(   rF   c                       e Zd ZdZd fdZedededee         fd            Z	edede
eeef         fd	            Zdd
ee         ddfdZdedededdf fdZ	 	 	 ddedededee         dee         dee         ddf fdZ	 ddej        dedee         ddf fdZ	 ddej        dedee         def fdZ xZS )NetworkBrokerCompressedrG   r    Nc                 |    t                                                       d| _        t                      | _        d S rI   )superrN   _compressed_pktnrr   _queue_read)r3   	__class__s    r&   rN   z NetworkBrokerCompressed.__init__-  s3    !#-2WWr(   r-   pktnrc                    d}g }t          t          |           t          z            D ]R}|                    dt	          j        d|          z   | ||t          z            z              |dz   dz  }|t          z  }S|                    t	          j        dt          |           |z
            dd         t	          j        d|          z   | |d         z              |S )	z2Prepare a payload for sending to the MySQL server.r   ru   rv   r   r`   rS   rT   N)rw   rV   r   appendrX   rx   )r-   r   ry   pktsrz   s        r&   _prepare_packetsz(NetworkBrokerCompressed._prepare_packets2  s     
 s7||'99:: 	) 	)AKK+dE**+&6,>#>>?@  
 QY#%E((FFKc'llV344QqS9k$&&'fgg	
 	
 	

 r(   rO   c                    t          |           t          k     rt          d          t          j        d| dd         dz             d         | d         t          j        d| dd         dz             d         }}}|||fS )rQ   rR   rS   r   rT   rU         )rV   r   rW   rX   rY   )rO   compressed_pllr[   uncompressed_plls       r&   r\   z"NetworkBrokerCompressed.get_headerK  s     s88555RSSS M$AaC7 233A6FM$AaC7 233A6  0 u&666r(   r]   c                 Z    || xj         dz  c_         n|| _         | xj         dz  c_         dS r_   )r   ra   s     r&   _set_next_compressed_pktnrz2NetworkBrokerCompressed._set_next_compressed_pktnrY  s@    ?""a'"""%,D"#%r(   r+   r,   c                 h  K   t          j        |          }t          j        dt	          |                    dd         t          j        d| j                  z   t          j        dt	          |                    dd         z   |z   }t                                          |||           d{V S )z1Compress packet and write it to the comm channel.rS   r   rT   rv   N)zlibcompressrX   rx   rV   r   r   rk   )r3   r+   r,   rO   compressed_pktr   s        r&   rk   z"NetworkBrokerCompressed._write_pkta  s       s++Kc.11221Q37k$ 6778k$C))!A#./  	 WW''=========r(   r.   r/   r0   c                   K   |                      |           |                     |           	 t          d                              |                     || j                            }t          |          t          t          z
  k    rd}t          t          |          t          z            D ]`}	t          j        |                     |||||t          z                      |           d{V  |                                  |t          z  }at          j        |                     ||||d                   |           d{V  dS t          |          t          k    r2t          j        |                     |||          |           d{V  dS t          j        t                                          ||t          j        dt          |                    dd         t          j        d| j                  z   t          j        dd          dd         z   |z             |           d{V  dS # t          j        t          j        f$ r}
t)          d          |
d}
~
ww xY w)	zSend `payload` as compressed packets to the MySQL server.

        If provided a payload whose length is greater than `MAX_PAYLOAD_LENGTH`, it is
        broken down into packets.
        r(   r   NrS   rT   rv   rn   rg   )rb   r   rD   joinr   rL   rV   r   r   rw   rB   ro   rk   r   r   rX   rx   r   rp   rq   r   )r3   r+   r,   r-   r.   r/   r0   payload_prepry   rz   r   r   s              r&   r4   zNetworkBrokerCompressed.writeq  s      	]+++''(@AAA6	9$S>>..%%gt{;; L 7||14HHHH  s<004FFGG 
1 
1A!*"#(&;M2M)MN 
 &         3355500FF&OOFG\&''5JKK!           w<<"555!*FF          
 "***"#"Kc,.?.?@@1E$k$0FGGH$k$221Q378 ++  &
 
 
 
 
 
 
 
 
 
 
 &(<= 	9 	9 	9#$///S8	9s&   DH7 AH7 B H7 7I(I##I(r6   r   r7   c           	      .  K   t          t          j        t                                          |||           d{V                     }d}|t          |          k     r3t          j        d|||t          z   dz
           dz             d         }t          |z   t          |          |z
  k    rt                                          |t          |           d{V }| 
                    |          \  }| _        }t                                          |||           d{V }	||dk    r|	nt          j        |	          z  }| j                            |||t          z   |z                       |t          |z   z  }|t          |          k     1dS dS )z&Handle reading of a compressed packet.Nr   rS   r   rU   )rD   r   
decompressr   rs   rV   rX   rY   r   r   r\   r   r   r   )r3   r6   r   r7   rO   ry   rZ   r|   r   r   r   s             r&   _read_compressed_pktz,NetworkBrokerCompressed._read_compressed_pkt  s      Ogg))&.,OOOOOOOO 
 

 s3xx-c&6,@#@1#DDEO C $c)CHHv,===  %ww22;\          OOF++	"*$',ww':':NL( ( " " " " " " '1,, #N88 ##C:N1NQT1T(T$UVVV*S00F? s3xxr(   c                 D  K   | j         s	 t                                          |t          |           d{V }|                     |          \  }| _        }|dk    rB| j                             t                                          |||           d{V            n|                     |||           d{V  n3# t          $ r&}t          d|t          |          f          |d}~ww xY w| j         sdS | j                                         }|d         | _        |S )z{Receive `one` or `several` packets from the MySQL server, enqueue them, and
        return the packet at the head.
        Nr   rd   re   rT   )r   r   rs   r   r\   r   r   r   ri   r   r'   popleftrL   )
r3   r6   r,   r7   r|   r   r   r   rO   r   s
            r&   r9   zNetworkBrokerCompressed.read  s       	$ww22;\          OOF++	"*$ $q(($++#gg11&.,WWWWWWWW   
 33            &S1A1A'B  
  	4&&((!f
s   B1B> >
C.!C))C.r~   r;   r:   )r<   r=   r>   r?   rN   r   r@   rA   r   r   r   r\   r   r   r   r$   rk   r4   rB   rC   r   rD   r9   __classcell__r   s   @r&   r   r   *  s\       665 5 5 5 5 5
 %  U    \0 7 7%S#"6 7 7 7 \7& &(3- &4 & & & &>> > 	>
 
> > > > > >* (,26'+G9 G9G9 G9 	G9
  }G9 #+3-G9  }G9 
G9 G9 G9 G9 G9 G9Z '+	-1 -1$-1 -1 sm	-1
 
-1 -1 -1 -1 -1 -1f '+	- -$- - sm	-
 
- - - - - - - - - -r(   r   c                      e Zd ZdZddZedefd            Zede	ddfd            Z
ddZdefd	Zd
eddfdZddZdej        ddfdZ	 	 	 d dedee         dee         dee         ddf
dZd!dee         defdZdddddg g fdee         dee         dee         dee         dee         deee                  deee                  dej        fdZdS )"MySQLSocketzMySQL socket communication interface.

    Examples:
        Subclasses: network.MySQLTCPSocket and network.MySQLUnixSocket.
    r    Nc                 r    d| _         d| _        d| _        d| _        t	                      | _        d| _        dS )zsNetwork layer where transactions are made with plain (uncompressed) packets
        is enabled by default.
        NF)_reader_writer_connection_timeout_addressrF   
_netbroker_is_connectedrM   s    r&   rN   zMySQLSocket.__init__   s<     8</326 '+);)=)=#(r(   c                     | j         S )zSocket location.)r   rM   s    r&   r,   zMySQLSocket.address+  s     }r(   kwargsc                 
   K   dS )zOpen the socket.Nr2   r3   r   s     r&   r   zMySQLSocket.open_connection0  r5   r(   c                   K   | j         r{	 | j                                          | j         j        | j         j                                         | j                                          d{V  n# t
          $ r
}Y d}~nd}~ww xY wd| _        dS )zClose the connection.NF)r   close	transportabortwait_closed	Exceptionr   )r3   rz   s     r&   close_connectionzMySQLSocket.close_connection4  s      < 
		""$$$<)5L*00222l..0000000000     #s   A"A. .
B=Bc                     | j         S )zCheck if the socket is connected.

        Return:
            bool: Returns `True` if the socket is connected to MySQL server.
        )r   rM   s    r&   is_connectedzMySQLSocket.is_connectedC  s     !!r(   timeoutc                     || _         dS )zSet the connection timeout.N)r   )r3   r   s     r&   set_connection_timeoutz"MySQLSocket.set_connection_timeoutK  s    #*   r(   c                 ,    t                      | _        dS )zIEnable network layer where transactions are made with compressed packets.N)r   r   rM   s    r&   switch_to_compressed_modez%MySQLSocket.switch_to_compressed_modeO  s    133r(   ssl_contextc                    K   | j         J | j         j                            d          }|j        dk    rt	          d          | j                             |           d{V  dS )a?  Upgrade an existing stream-based connection to TLS.

        The `start_tls()` method from `asyncio.streams.StreamWriter` is only available
        in Python 3.11. This method is used as a workaround.

        The MySQL TLS negotiation happens in the middle of the TCP connection.
        Therefore, passing a socket to open connection will cause it to negotiate
        TLS on an existing connection.

        Args:
            ssl_context: The SSL Context to be used.

        Raises:
            RuntimeError: If the transport does not expose the socket instance.
        Nsocketr   z,SSL is not supported when using Unix sockets)r   r   get_extra_infofamilyr   	start_tls)r3   r   r   s      r&   switch_to_sslzMySQLSocket.switch_to_sslS  sx      " |''''66x@@=A"#QRRRl$$[11111111111r(   r-   r.   r/   r0   c                 j   K   | j                             | j        | j        ||||           d{V  dS )z!Send packets to the MySQL server.)r.   r/   r0   N)r   r4   r   r,   )r3   r-   r.   r/   r0   s        r&   r4   zMySQLSocket.writel  se       o##LL'%=' $ 
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
r(   r7   c                 ^   K   | j                             | j        | j        |           d{V S )z#Read packets from the MySQL server.N)r   r9   r   r,   )r3   r7   s     r&   r9   zMySQLSocket.read}  s6      _))$,lSSSSSSSSSr(   Fssl_cassl_certssl_keyssl_verify_certssl_verify_identitytls_versionstls_cipher_suitesc                    d}| j         st          d          t          t          d          	 |r|                    d           |d         }t
          |         }	t          j        |	          }
|dk    rZd	|vr|
xj        t          j        z  c_        d
|vr|
xj        t          j	        z  c_        d|vr|
xj        t          j
        z  c_        nt          j                    }
||
_        |rt          j        |
_        n%|rt          j        |
_        nt          j        |
_        |
                                 |rH	 |
                    |           n1# t&          t          j        f$ r}t          d|           |d}~ww xY w|rI	 |
                    ||           n1# t&          t          j        f$ r}t          d|           |d}~ww xY w|r.|d	k    r(|
                    d                    |                     |
S # t0          $ r}t3          d          |d}~wt&          t4          t          j        t          j        f$ r"}t          t9          |                    |d}~ww xY w)zBuild a SSLContext.Ni   rg   z&Python installation has no SSL supportT)reverser   r   r   r   r   zInvalid CA Certificate: zInvalid Certificate/Key: :)r   r   sslRuntimeErrorsortTLS_VERSIONS
SSLContextoptionsOP_NO_TLSv1_2OP_NO_TLSv1_1OP_NO_TLSv1create_default_contextcheck_hostnameCERT_REQUIREDverify_modeCERT_OPTIONAL	CERT_NONEload_default_certsload_verify_locationsri   SSLErrorload_cert_chainset_ciphersr   	NameErrorr   NotImplementedErrorCertificateErrorr$   )r3   r   r   r   r   r   r   r   tls_versionssl_protocolcontextr   s               r&   build_ssl_contextzMySQLSocket.build_ssl_context  s    &*| 	- t,,,,;GHHH5	4 7!!$!///*1o+K8.66)++ 443+<< 443+<<l223?:466%8G" 4&)&7##$ 4&)&7##&)m#&&((( TT11&9999. T T T()IC)I)IJJPSST UU++Hg>>>>. U U U()JS)J)JKKQTTU
 ! A[I%=%=##CHH->$?$?@@@N 	W 	W 	W#$LMMSVV L	
 	4 	4 	4 !S**3	4sl   DH =E H F)E<<FH F H G4GG4H 
I'H*I'I""I'r~   r:   r;   )r<   r=   r>   r?   rN   propertyr$   r,   r
   r   r   r   boolr   rA   r   r   r   r   r   r@   r   r4   rD   r9   r   r   r2   r(   r&   r   r     sW        	) 	) 	) 	)     X c d    ^# # # #"d " " " "+c +d + + + +4 4 4 42s~ 2$ 2 2 2 28 (,26'+
 

  }
 #+3-	

  }
 

 
 
 
"T Tx} T	 T T T T !%"&!%*/.3,.13H4 H4H4 3-H4 #	H4
 "$H4 &d^H4 tCy)H4 $DI.H4 
H4 H4 H4 H4 H4 H4r(   r   c                   D     e Zd ZdZ	 ddededef fdZd	ed
dfdZ	 xZ
S )r   zMySQL socket class using TCP/IP.

    Args:
        host: MySQL host name.
        port: MySQL port.
        force_ipv6: Force IPv6 usage.
    	127.0.0.1  Fhostport
force_ipv6c                     t                                                       || _        || _        || _        | d| | _        d S )Nr   )r   rN   _host_port_force_ipv6r   )r3   r   r   r   r   s       r&   rN   zMySQLTcpSocket.__init__  sJ     	

!+ $--t--r(   r   r    Nc                 p   K   t          d| j        | j        d| d{V \  | _        | _        d| _        dS )zOpen TCP/IP connection.)r   r   NTr2   )r   r   r   r   r   r   r   s     r&   r   zMySQLTcpSocket.open_connection  sg      +: ,
$*,
 ,
06,
 ,
 &
 &
 &
 &
 &
 &
"dl "r(   )r   r   F)r<   r=   r>   r?   r$   rA   r   rN   r   r   r   r   s   @r&   r   r     s          MR. ..-0.EI. . . . . ."c "d " " " " " " " "r(   c                   :     e Zd ZdZd	def fdZdeddfdZ xZS )
r   zbMySQL socket class using UNIX sockets.

    Args:
        unix_socket: UNIX socket file path.
    /tmp/mysql.sockunix_socketc                 V    t                                                       || _        d S r;   )r   rN   r   )r3   r   r   s     r&   rN   zMySQLUnixSocket.__init__  s$    (r(   r   r    Nc                 n   K   t          j        dd| j        i| d{V \  | _        | _        d| _        dS )zOpen UNIX socket connection.pathNTr2   )rB   open_unix_connectionr   r   r   r   r   s     r&   r   zMySQLUnixSocket.open_connection  sl      
 . 
 

"(
 
 
 
 
 
 
 
	
LL "r(   )r   )	r<   r=   r>   r?   r$   rN   r   r   r   r   s   @r&   r   r     su         ) )C ) ) ) ) ) )"c "d " " " " " " " "r(   )/r?   __all__rB   rX   r   r   PROTOCOL_TLSv1PROTOCOL_TLSv1_1PROTOCOL_TLSv1_2PROTOCOL_TLSr   ImportErrorabcr	   r
   collectionsr   typingr   r   r   r   r   errorsr   r   r   r   r   r   networkr   r   r   r   utilsr   r   ri   r$   r'   r*   rF   r   r   r   r   r2   r(   r&   <module>r
     s  > M L .
/   
JJJ #''#	 LL    
CCC $ # # # # # # #       4 4 4 4 4 4 4 4 4 4 4 4 4 4                           1 0 0 0 0 0 0 0HW H H H H HQ Q Q Q QC Q Q QhB B B B B B B BJl l l l l0 l l l^p4 p4 p4 p4 p4# p4 p4 p4f" " " " "[ " " "4" " " " "k " " " " "s   4 >>