o
    b[                     @   s   d Z ddlZddlZddlmZmZ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 zddlmamZ ddlma ddlmZmZ W n eyh   dd Ze  Y nw ddlm Z  G dd dej!Z"G dd dej!Z#G dd dej$Z%G dd dej$Z&e ej'G dd dej$Z(dd Z)dd Z*G dd  d Z+tdurG d!d" d"tj,Z-G d#d$ d$eeZ.G d%d& d&eZ/G d'd( d(e/Z0G d)d* d*eZ1G d+d, d,ee+Z2G d-d. d.Z3G d/d0 d0eZ4G d1d2 d2eZ5dS )3z 
Tests for twisted SSL support.
    N)defer
interfacesprotocolreactor)ConnectionDone)basic)FilePath)platform)waitUntilAllDisconnected)ProperlyCloseFilesMixin)TestCase)SSLcrypto)ssl)ClientTLSContextcertPathc                   C   s   d  a ad S N)r   r    r   r   7/usr/lib/python3/dist-packages/twisted/test/test_ssl.py_noSSL   s   r   )implementerc                   @   s@   e Zd ZdZg dZddgZdd Zdd Zd	d
 Zdd Z	dS )UnintelligentProtocola  
    @ivar deferred: a deferred that will fire at connection lost.
    @type deferred: L{defer.Deferred}

    @cvar pretext: text sent before TLS is set up.
    @type pretext: C{bytes}

    @cvar posttext: text sent after TLS is set up.
    @type posttext: C{bytes}
    )s
   first lines   last thing before tls starts   STARTTLSs   first thing after tls starteds   last thing everc                 C      t  | _d S r   r   Deferreddeferredselfr   r   r   __init__7      zUnintelligentProtocol.__init__c                 C   s   | j D ]}| | qd S r   )pretextsendLine)r   lr   r   r   connectionMade:   s   
z$UnintelligentProtocol.connectionMadec                 C   sD   |dkr | j t | jj | jD ]}| | q| j   d S d S )N   READY)	transportstartTLSr   factoryclientposttextr"   loseConnection)r   liner#   r   r   r   lineReceived>   s   
z"UnintelligentProtocol.lineReceivedc                 C      | j d  d S r   r   callbackr   reasonr   r   r   connectionLostE      z$UnintelligentProtocol.connectionLostN)
__name__
__module____qualname____doc__r!   r*   r   r$   r-   r3   r   r   r   r   r   '   s    r   c                   @   s:   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdS )LineCollectoraJ  
    @ivar deferred: a deferred that will fire at connection lost.
    @type deferred: L{defer.Deferred}

    @ivar doTLS: whether the protocol is initiate TLS or not.
    @type doTLS: C{bool}

    @ivar fillBuffer: if set to True, it will send lots of data once
        C{STARTTLS} is received.
    @type fillBuffer: C{bool}
    Fc                 C   s   || _ || _t | _d S r   )doTLS
fillBufferr   r   r   )r   r:   r;   r   r   r   r   V   s   zLineCollector.__init__c                 C   s   d| j _g | j _d S )N    )r(   rawdatalinesr   r   r   r   r$   [   s   zLineCollector.connectionMadec                 C   sv   | j j| |dkr9| jrtdD ]}| d q| d | jr3tttd}| j	
|| j j d S |   d S d S )Nr   i  s  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXr%   )privateKeyFileNamecertificateFileName)r(   r>   appendr;   ranger"   r:   ServerTLSContextr   r&   r'   server
setRawMode)r   r,   xctxr   r   r   r-   _   s   
zLineCollector.lineReceivedc                 C   s   | j  j|7  _| j  d S r   )r(   r=   r&   r+   r   datar   r   r   rawDataReceivedo   s   zLineCollector.rawDataReceivedc                 C   r.   r   r/   r1   r   r   r   r3   s   r4   zLineCollector.connectionLostNF)	r5   r6   r7   r8   r   r$   r-   rJ   r3   r   r   r   r   r9   I   s    
r9   c                   @   s   e Zd ZdZdd ZdS )SingleLineServerProtocolzK
    A protocol that sends a single line of data at C{connectionMade}.
    c                 C   s   | j d | j   d S )N   +OK <some crap>
)r&   writegetPeerCertificater   r   r   r   r$   |   s   z'SingleLineServerProtocol.connectionMadeN)r5   r6   r7   r8   r$   r   r   r   r   rL   w   s    rL   c                   @   (   e Zd ZdZdd Zdd Zdd ZdS )	RecordingClientProtocolzv
    @ivar deferred: a deferred that will fire with first received content.
    @type deferred: L{defer.Deferred}
    c                 C   r   r   r   r   r   r   r   r      r    z RecordingClientProtocol.__init__c                 C      | j   d S r   )r&   rO   r   r   r   r   r$      r    z&RecordingClientProtocol.connectionMadec                 C   s   | j | d S r   r/   rH   r   r   r   dataReceived   r4   z$RecordingClientProtocol.dataReceivedN)r5   r6   r7   r8   r   r$   rS   r   r   r   r   rQ      s
    rQ   c                   @       e Zd ZdZdd Zdd ZdS ) ImmediatelyDisconnectingProtocolz
    A protocol that disconnect immediately on connection. It fires the
    C{connectionDisconnected} deferred of its factory on connetion lost.
    c                 C   rR   r   r&   r+   r   r   r   r   handshakeCompleted   r    z3ImmediatelyDisconnectingProtocol.handshakeCompletedc                 C   s   | j jd  d S r   )r(   connectionDisconnectedr0   r1   r   r   r   r3         z/ImmediatelyDisconnectingProtocol.connectionLostN)r5   r6   r7   r8   rW   r3   r   r   r   r   rU      s    rU   c                 C   s   t  }|t jd t  }| }| |_||_|| |	|d t 
 }|d |d |d ||  ||  ||  |	|d |||fS )z
    Create a certificate for given C{organization} and C{organizationalUnit}.

    @return: a tuple of (key, request, certificate) objects.
    i   md5   r   <   )r   PKeygenerate_keyTYPE_RSAX509Reqget_subjectOOU
set_pubkeysignX509set_serial_numbergmtime_adj_notBeforegmtime_adj_notAfter
set_issuerset_subject
get_pubkey)organizationorganizationalUnitpkeyreqsubjectcertr   r   r   generateCertificateObjects   s"   




rs   c           
      C   sn   t ||\}}}d|tjfd|tjfd|tjffD ]\}}}tj| |fd}	t	|	
|tj| qdS )z
    Create certificate files key, req and cert prefixed by C{basename} for
    given C{organization} and C{organizationalUnit}.
    keyrp   rr   zutf-8N)rs   r   dump_privatekeydump_certificate_requestdump_certificateosextsepjoinencoder   
setContentFILETYPE_PEM)
basenamerm   rn   ro   rp   rr   extobjdumpFuncfNamer   r   r   generateCertificateFiles   s   


r   c                   @   rT   )ContextGeneratingMixinah  
    Offer methods to create L{ssl.DefaultOpenSSLContextFactory} for both client
    and server.

    @ivar clientBase: prefix of client certificate files.
    @type clientBase: C{str}

    @ivar serverBase: prefix of server certificate files.
    @type serverBase: C{str}

    @ivar clientCtxFactory: a generated context factory to be used in
        L{IReactorSSL.connectSSL}.
    @type clientCtxFactory: L{ssl.DefaultOpenSSLContextFactory}

    @ivar serverCtxFactory: a generated context factory to be used in
        L{IReactorSSL.listenSSL}.
    @type serverCtxFactory: L{ssl.DefaultOpenSSLContextFactory}
    c                 O   sN   |   }t||| tjtj|dftj|dfg|R i |}||fS )Nrt   rr   )mktempr   r   DefaultOpenSSLContextFactoryrx   ry   rz   )r   orgorgUnitargskwArgsbaseserverCtxFactoryr   r   r   makeContextFactory   s   z)ContextGeneratingMixin.makeContextFactoryc                 C   s4   | j |i |\| _| _| j |i |\| _| _d S r   )r   
clientBaseclientCtxFactory
serverBaser   )r   
clientArgsclientKwArgs
serverArgsserverKwArgsr   r   r   setupServerAndClient   s   z+ContextGeneratingMixin.setupServerAndClientN)r5   r6   r7   r8   r   r   r   r   r   r   r      s    r   c                   @   s   e Zd ZdZdZdd ZdS )rC   zf
        A context factory with a default method set to
        L{OpenSSL.SSL.SSLv23_METHOD}.
        Fc                 O   s(   t j|d< tjj| g|R i | d S )N	sslmethod)r   SSLv23_METHODr   r   r   )r   r   kwr   r   r   r      s   
zServerTLSContext.__init__N)r5   r6   r7   r8   isClientr   r   r   r   r   rC      s    rC   c                   @   D   e Zd ZdZeeddu rdZdd Zdd Z	dd	 Z
d
d ZdS )StolenTCPTestszc
    For SSL transports, test many of the same things which are tested for
    TCP transports.
    N2Reactor does not support SSL, cannot run SSL testsc                 C   s.   t jtt }| }tj||||dS )zY
        Create an SSL server with a certificate using L{IReactorSSL.listenSSL}.
        	interface)	r   PrivateCertificateloadPEMr   r   
getContentoptionsr   	listenSSL)r   address
portNumberr(   rr   contextFactoryr   r   r   createServer  s   zStolenTCPTests.createServerc                 C   s   t  }||||S )zG
        Create an SSL client using L{IReactorSSL.connectSSL}.
        )r   CertificateOptions
connectSSL)r   r   r   clientCreatorr   r   r   r   connectClient  s   zStolenTCPTests.connectClientc                 C   s   t jS )z
        Return L{OpenSSL.SSL.Error} as the expected error type which will be
        raised by a write to the L{OpenSSL.SSL.Connection} object after it has
        been closed.
        )r   Errorr   r   r   r   getHandleExceptionType  s   z%StolenTCPTests.getHandleExceptionTypec                 C   s4   t t t dt t dt dt dS )a4  
        Return a L{hamcrest.core.matcher.Matcher} for the argument
        L{OpenSSL.SSL.Error} will be constructed with for this case.
        This is basically just a random OpenSSL implementation detail.
        It would be better if this test worked in a way which did not
        require this.
        zSSL routines	SSL_writessl_write_internalzprotocol is shutdown)hamcrestcontainsequal_toany_ofr   r   r   r   getHandleErrorCodeMatcher#  s   
z(StolenTCPTests.getHandleErrorCodeMatcher)r5   r6   r7   r8   r   IReactorSSLr   skipr   r   r   r   r   r   r   r   r     s    r   c                   @   sZ   e Zd ZdZeeddu rdZdZdZ	dZ
dd ZdddZd	d
 Zdd Zdd ZdS )TLSTestsz
    Tests for startTLS support.

    @ivar fillBuffer: forwarded to L{LineCollector.fillBuffer}
    @type fillBuffer: C{bool}
    Nr   Fc                 C   s8   | j jd ur| j j  | jjd ur| jj  d S d S r   )clientProtor&   r+   serverProtor   r   r   r   tearDownI  s
   zTLSTests.tearDownc                    s    | _ t  }| _ fdd|_|rd|_nd|_| _t  }| _fdd|_|r1d|_nd|_t	j
d|dd}| |j t	d| j| t jjgS )	a  
        Helper method to run TLS tests.

        @param clientProto: protocol instance attached to the client
            connection.
        @param serverProto: protocol instance attached to the server
            connection.
        @param clientIsServer: flag indicated if client should initiate
            startTLS instead of server.

        @return: a L{defer.Deferred} that will fire when both connections are
            lost.
        c                          S r   r   r   r   r   r   <lambda>_      z#TLSTests._runTest.<locals>.<lambda>FTc                      r   r   r   r   r   r   r   r   g  r   r   	127.0.0.1r   )r   r   ClientFactoryclientFactoryrD   r)   r   ServerFactoryserverFactoryr   	listenTCP
addCleanupstopListening
connectTCPgetHostportr   gatherResultsr   )r   r   r   clientIsServercfsfr   r   r   r   r   _runTestO  s    zTLSTests._runTestc                    ,    fdd}  t td j}||S )z~
        Test for server and client startTLS: client should received data both
        before and after the startTLS.
        c                          jjtjtj  d S r   )assertEqualr   r>   r   r!   r*   )ignorer   r   r   checkz     
z TLSTests.test_TLS.<locals>.checkTr   r   r9   r;   addCallbackr   r   dr   r   r   test_TLSt  s   
zTLSTests.test_TLSc                    r   )z
        Test for server startTLS not followed by a startTLS in client: the data
        received after server startTLS should be received as raw.
        c                    s&      jjtj   jjd d S )NzNo encrypted bytes received)r   r   r>   r   r!   
assertTruer=   ignoredr   r   r   r     s   z"TLSTests.test_unTLS.<locals>.checkFr   r   r   r   r   
test_unTLS  s
   
zTLSTests.test_unTLSc                    s.    fdd}  td jt d}||S )z:
        Test startTLS first initiated by client.
        c                    r   r   )r   r   r>   r   r!   r*   r   r   r   r   r     r   z)TLSTests.test_backwardsTLS.<locals>.checkT)r   r9   r;   r   r   r   r   r   r   test_backwardsTLS  s
   
zTLSTests.test_backwardsTLSrK   )r5   r6   r7   r8   r   r   r   r   r;   r   r   r   r   r   r   r   r   r   r   r   r   9  s    
%r   c                   @   s(   e Zd ZdZeeddu rdZdZdS )SpammyTLSTestszA
    Test TLS features with bytes sitting in the out buffer.
    Nr   T)	r5   r6   r7   r8   r   r   r   r   r;   r   r   r   r   r     s
    r   c                   @   s8   e Zd Zeeddu rdZdZdZdd Z	dd Z
dS )BufferingTestsNr   c                 C   sB   | j jd ur| j j  | jjd ur| jj  tt| j | jgS r   )r   r&   r+   r   r
   r   r   r   r   r   r     s
   zBufferingTests.tearDownc                    s   t   | _t   | _t }t  }| _fdd|_ fdd|_t	t
t
}t }tjd||dd}| |j td| j||}| |j  j| jdS )Nc                      r   r   r   r   r   r   r   r     r   z6BufferingTests.test_openSSLBuffering.<locals>.<lambda>c                      r   r   r   r   r   r   r   r     r   r   r   r   rM   )rL   r   rQ   r   r   r   r   r)   r   r   r   ClientContextFactoryr   r   r   r   r   r   r   
disconnectr   r   r   )r   rD   r)   sCTXcCTXr   clientConnectorr   r   r   test_openSSLBuffering  s"   z$BufferingTests.test_openSSLBuffering)r5   r6   r7   r   r   r   r   r   r   r   r   r   r   r   r   r     s    r   c                   @   r   )ConnectionLostTestsz'
    SSL connection closing tests.
    Nr   c                    s   d}  ||d fi ||d fi  t }tj|_td| j  _}t }t	|_t
 |_td| j| j |j fddS )Ntwisted.test.test_ssl, client, serverr   r   c                    s
    j  S r   )
serverPortr   )ignoredResultr   r   r   r     s   
 z=ConnectionLostTests.testImmediateDisconnect.<locals>.<lambda>)r   r   r   Protocolr   r   r   r   r   rU   r   r   rX   r   r   r   r   r   )r   r   serverProtocolFactoryr   clientProtocolFactoryr   r   r   testImmediateDisconnect  s*   


z+ConnectionLostTests.testImmediateDisconnectc                    s   t tjG dd dtj}d}| ||d fi ||d fi  | t }fdd|_td|| j	}| 
|j |  t } fd	d|_td
| j|| j dd }t j|j|gS )z
        Both sides of SSL connection close connection; the connections should
        close cleanly, and only after the underlying TCP connection has
        disconnected.
        c                   @   rP   )	zMConnectionLostTests.test_bothSidesLoseConnection.<locals>.CloseAfterHandshakeFc                 S   r   r   )r   r   doner   r   r   r   r     r    zVConnectionLostTests.test_bothSidesLoseConnection.<locals>.CloseAfterHandshake.__init__c                 S   rR   r   rV   r   r   r   r   rW   
  r    z`ConnectionLostTests.test_bothSidesLoseConnection.<locals>.CloseAfterHandshake.handshakeCompletedc                 S   s   | j | | ` d S r   )r   errbackr1   r   r   r   r3     s   z\ConnectionLostTests.test_bothSidesLoseConnection.<locals>.CloseAfterHandshake.connectionLostN)r5   r6   r7   gotDatar   rW   r3   r   r   r   r   CloseAfterHandshake  s
    r   r   r   r   c                      r   r   r   r   serverProtocolr   r   r     r   zBConnectionLostTests.test_bothSidesLoseConnection.<locals>.<lambda>r   c                      r   r   r   r   clientProtocolr   r   r     r   r   c                 S   s   |  t d S r   )trapr   )failurer   r   r   checkResult&  r    zEConnectionLostTests.test_bothSidesLoseConnection.<locals>.checkResult)r   r   IHandshakeListenerr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   
addErrback)r   r   r   r   r   r   r   r   r   r   r   test_bothSidesLoseConnection  s4   

z0ConnectionLostTests.test_bothSidesLoseConnectionc           	         s   d}|  ||d fi ||d fi  dd }| j tj| t }t	 |j
_t }fdd|_td|| j | _}t }t	  |j
 _t } fd	d|_td
| j|| j tj||gdd}|| jS )Nr   r   r   c                  W   s   dS )NFr   )ar   r   r   verify6     z4ConnectionLostTests.testFailedVerify.<locals>.verifyc                      r   r   r   r   r   r   r   r   ?  r   z6ConnectionLostTests.testFailedVerify.<locals>.<lambda>r   c                      r   r   r   r   r   r   r   r   H  r   r   T)consumeErrors)r   r   
getContext
set_verifyr   VERIFY_PEERr   r   r   r   r0   r3   r   r   r   r   r   r   r   r   r   DeferredListr   _cbLostConns)	r   r   r  serverConnLostr   r   clientConnLostr   dlr   r   r   testFailedVerify0  s6   
z$ConnectionLostTests.testFailedVerifyc                 C   sh   |\\}}\}}|  | |  | tjg}t r%ddlm} || |j|  |j|  | j	
 S )Nr   )ConnectionLost)assertFalser   r   r	   	isWindowstwisted.internet.errorr  rA   r   r   r   )r   resultssSuccesssResultcSuccesscResultacceptableErrorsr  r   r   r   r
  S  s   






z ConnectionLostTests._cbLostConns)r5   r6   r7   r8   r   r   r   r   r   r  r  r
  r   r   r   r   r     s    4#r   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )FakeContextzK
    L{OpenSSL.SSL.Context} double which can more easily be inspected.
    c                 C   s   || _ d| _d S )Nr   )_method_options)r   methodr   r   r   r   s  s   
zFakeContext.__init__c                 C   s   |  j |O  _ d S r   )r  )r   r   r   r   r   set_optionsw  rY   zFakeContext.set_optionsc                 C      d S r   r   r   fileNamer   r   r   use_certificate_filez  r  z FakeContext.use_certificate_filec                 C   r  r   r   r  r   r   r   use_privatekey_file}  r  zFakeContext.use_privatekey_fileN)r5   r6   r7   r8   r   r  r!  r"  r   r   r   r   r  n  s    r  c                   @   r   )!DefaultOpenSSLContextFactoryTestsz8
    Tests for L{ssl.DefaultOpenSSLContextFactory}.
    Nr   c                 C   s"   t jtttd| _| j | _d S )N)_contextFactory)r   r   r   r  r   r  contextr   r   r   r   setUp  s   z'DefaultOpenSSLContextFactoryTests.setUpc                 C   V   |  | jjtj |  | jjtj@ tj | | jjtj@  | | jjtj	@  dS )z
        L{ssl.DefaultOpenSSLContextFactory.getContext} returns an SSL context
        which can use SSLv3 or TLSv1 but not SSLv2.
        N
r   r%  r  r   r   r  OP_NO_SSLv2r  OP_NO_SSLv3OP_NO_TLSv1r   r   r   r   test_method  s   z-DefaultOpenSSLContextFactoryTests.test_methodc                 C   s   |  tjtjt|   dS )z
        Instantiating L{ssl.DefaultOpenSSLContextFactory} with a certificate
        filename which does not identify an existing file results in the
        initializer raising L{OpenSSL.SSL.Error}.
        N)assertRaisesr   r   r   r   r   r   r   r   r   r   test_missingCertificateFile     z=DefaultOpenSSLContextFactoryTests.test_missingCertificateFilec                 C   s   |  tjtj|  t dS )z
        Instantiating L{ssl.DefaultOpenSSLContextFactory} with a private key
        filename which does not identify an existing file results in the
        initializer raising L{OpenSSL.SSL.Error}.
        N)r-  r   r   r   r   r   r   r   r   r   r   test_missingPrivateKeyFile  r/  z<DefaultOpenSSLContextFactoryTests.test_missingPrivateKeyFile)r5   r6   r7   r8   r   r   r   r   r&  r,  r.  r0  r   r   r   r   r#    s    
r#  c                   @   s4   e Zd ZdZeeddu rdZdd Zdd Z	dS )ClientContextFactoryTestsz0
    Tests for L{ssl.ClientContextFactory}.
    Nr   c                 C   s"   t  | _t| j_| j | _d S r   )r   r   r   r  r$  r  r%  r   r   r   r   r&    s   
zClientContextFactoryTests.setUpc                 C   r'  )z~
        L{ssl.ClientContextFactory.getContext} returns a context which can use
        SSLv3 or TLSv1 but not SSLv2.
        Nr(  r   r   r   r   r,    s   z%ClientContextFactoryTests.test_method)
r5   r6   r7   r8   r   r   r   r   r&  r,  r   r   r   r   r1    s    r1  )6r8   rx   r   twisted.internetr   r   r   r   r  r   twisted.protocolsr   twisted.python.filepathr   twisted.python.runtimer	   twisted.test.proto_helpersr
   twisted.test.test_tcpr   twisted.trial.unittestr   OpenSSLr   r   r   twisted.test.ssl_helpersr   r   ImportErrorr   zope.interfacer   LineReceiverr   r9   r   rL   rQ   r   rU   rs   r   r   r   rC   r   r   r   r   r   r  r#  r1  r   r   r   r   <module>   sP   

".
)6j* 4