
    XfBU                        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mZ d Z	 G d de          Z
 e e	             d           G d de
                      Z e e	             d           G d	 d
e
                      Z e e	             d           G d de                      Z e e	             d           G d de
                      ZdS )    N)skipIfTestCasec                  H    	 t          d           dS # t          $ r Y dS w xY w)NtwistedTF)
__import__ImportError     M/var/www/html/env/lib/python3.11/site-packages/automat/_test/test_discover.pyisTwistedInstalledr   	   s@    9 t    uus    
!!c                   P     e Zd ZdZ fdZ fdZd Zd Zd Zd Z	d Z
d	 Z xZS )
_WritesPythonModuleszG
    A helper that enables generating Python module test fixtures.
    c                    t          t          |                                            ddlm}m} ddlm} || _        || _        || _        t          t          j
                                                  | _        t          j        d d          | _        t          j                    | _        |                     | j                   d S )Nr   )	getModule
PythonPath)FilePath)superr   setUptwisted.python.modulesr   r   twisted.python.filepathr   setsysmoduleskeysoriginalSysModulespathsavedSysPathtempfilemkdtemppathDirmakeImportable)selfr   r   r   	__class__s       r   r   z_WritesPythonModules.setUp   s    "D))//111@@@@@@@@444444"$ "%ck&6&6&8&8"9"9HQQQK'))DL)))))r
   c                 $   t          t          |                                            | j        t          j        d d <   t          j                                        | j        z
  }|D ]}t          j        |= t          j
        | j                   d S N)r   r   tearDownr   r   r   r   r   r   shutilrmtreer    )r"   modulesToDeletemoduler#   s      r   r&   z_WritesPythonModules.tearDown'   s    "D))22444'+**,,t/FF% 	$ 	$FF##dl#####r
   c                 D    t           j                            |           d S r%   )r   r   append)r"   r   s     r   r!   z#_WritesPythonModules.makeImportable1   s    r
   c                 4   |                      |          }|                    |          }t          |j        d          5 }|                    t          j        |                     d d d            n# 1 swxY w Y   |                     |j        g          S )Nw)r   childopenr   writetextwrapdedentr   )r"   sourcer   
moduleName	directoryr*   fs          r   writeSourceIntoz$_WritesPythonModules.writeSourceInto4   s    MM$''	,, &+s## 	-qGGHOF++,,,	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	- 	/000s    (A44A8;A8c                     t           j                            |          \  }}|                     |||          |         S r%   )osr   splitextr8   )r"   r4   r   r5   pythonModuleName_s         r   
makeModulez_WritesPythonModules.makeModule?   s;     g..z::!##FD*==>NOOr
   c                 >    d |                                 D             S )Nc                     i | ]
}|j         |S r	   )name).0attrs     r   
<dictcomp>z9_WritesPythonModules.attributesAsDict.<locals>.<dictcomp>D   s    OOOD	4OOOr
   )iterAttributes)r"   hasIterAttributess     r   attributesAsDictz%_WritesPythonModules.attributesAsDictC   s#    OO,=,L,L,N,NOOOOr
   c                 T    |                                  |                     |          S r%   )loadrG   )r"   r*   s     r   loadModuleAsDictz%_WritesPythonModules.loadModuleAsDictF   s#    $$V,,,r
   c                 V    |                      |                     |||                    S r%   )rJ   r>   )r"   r4   r   rA   s       r   makeModuleAsDictz%_WritesPythonModules.makeModuleAsDictJ   s&    $$T__VT4%H%HIIIr
   )__name__
__module____qualname____doc__r   r&   r!   r8   r>   rG   rJ   rL   __classcell__r#   s   @r   r   r      s         * * * * * $ $ $ $ $  	1 	1 	1P P PP P P- - -J J J J J J Jr
   r   zTwisted is not installed.c                   4     e Zd ZdZ fdZd Zd Zd Z xZS )OriginalLocationTestsa  
    Tests that L{isOriginalLocation} detects when a
    L{PythonAttribute}'s FQPN refers to an object inside the module
    where it was defined.

    For example: A L{twisted.python.modules.PythonAttribute} with a
    name of 'foo.bar' that refers to a 'bar' object defined in module
    'baz' does *not* refer to bar's original location, while a
    L{PythonAttribute} with a name of 'baz.bar' does.

    c                 p    t          t          |                                            ddlm} || _        d S )N   )isOriginalLocation)r   rT   r   	_discoverrW   )r"   rW   r#   s     r   r   zOriginalLocationTests.setUp[   s@    #T**00222222222"4r
   c                     d}|                      || j        d          }|                     |                     |d                              dS )z
        L{isOriginalLocation} returns False when the attribute refers to an
        object whose source module cannot be determined.
        z~        class Fake(object):
            pass
        hasEmptyModule = Fake()
        hasEmptyModule.__module__ = None
        zempty_module_attr.pyz empty_module_attr.hasEmptyModuleN)rL   r    assertFalserW   )r"   r4   
moduleDicts      r   test_failsWithNoModulez,OriginalLocationTests.test_failsWithNoModule`   sk    
 **6+/<+AC C
 	009:< < 	= 	= 	= 	= 	=r
   c                    d}d}|                      || j        d           |                     || j        d          }|                     |                     |d                              |                     |                     |d                              |d         }|                     |          }|d         }|                     |                     |                     d	S )
z
        L{isOriginalLocation} returns False when the attribute refers to
        an object outside of the module where that object was defined.
        z        class ImportThisClass(object):
            pass
        importThisObject = ImportThisClass()
        importThisNestingObject = ImportThisClass()
        importThisNestingObject.nestedObject = ImportThisClass()
        z        from original import (ImportThisClass,
                              importThisObject,
                              importThisNestingObject)
        original.pyimporting.pyzimporting.ImportThisClasszimporting.importThisObjectz!importing.importThisNestingObjectz.importing.importThisNestingObject.nestedObjectN)r>   r    rL   rZ   rW   rG   )r"   originalSourceimportingSourceimportingDictnestingObjectnestingObjectDictnestedObjects          r   test_failsWithDifferentModulez3OriginalLocationTests.test_failsWithDifferentModules   s   
 	mDDD--o.2l.<> > 	##9:< <	= 	= 	= 	##:;= =	> 	> 	> &&IJ 11-@@(<> 	00>>?????r
   c                    t          j        d          }|                     || j        d          }|                     |                     |d                              |                     |                     |d                              |d         }|                     |          }|d         }|                     |                     |                     dS )z
        L{isOriginalLocation} returns True when the attribute refers to an
        object inside the module where that object was defined.
        z
        class ThisClassWasDefinedHere(object):
            pass
        anObject = ThisClassWasDefinedHere()
        aNestingObject = ThisClassWasDefinedHere()
        aNestingObject.nestedObject = ThisClassWasDefinedHere()
        zm.pyzm.ThisClassWasDefinedHerezm.aNestingObjectzm.aNestingObject.nestedObjectN)r2   r3   rL   r    
assertTruerW   rG   )r"   mSourcemDictrc   rd   re   s         r   test_succeedsWithSameModulez1OriginalLocationTests.test_succeedsWithSameModule   s    
 / #   %%gt|VDD//-.0 0 	1 	1 	1//6H0IJJKKK01 11-@@()HI//==>>>>>r
   )	rM   rN   rO   rP   r   r\   rf   rk   rQ   rR   s   @r   rT   rT   N   ss        
 
5 5 5 5 5
= = =&#@ #@ #@J? ? ? ? ? ? ?r
   rT   c                   \     e Zd ZdZdZ fdZd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Z xZS )FindMachinesViaWrapperTestsz
    L{findMachinesViaWrapper} recursively yields FQPN,
    L{MethodicalMachine} pairs in and under a given
    L{twisted.python.modules.PythonModule} or
    L{twisted.python.modules.PythonAttribute}.
    a  
    from automat import MethodicalMachine


    class PythonClass(object):
        _classMachine = MethodicalMachine()

        class NestedClass(object):
            _nestedClassMachine = MethodicalMachine()

        ignoredAttribute = "I am ignored."

        def ignoredMethod(self):
            "I am also ignored."

    rootLevelMachine = MethodicalMachine()
    ignoredPythonObject = PythonClass()
    anotherIgnoredPythonObject = "I am ignored."
    c                 p    t          t          |                                            ddlm} || _        d S )NrV   )findMachinesViaWrapper)r   rm   r   rX   ro   )r"   ro   r#   s     r   r   z!FindMachinesViaWrapperTests.setUp   s@    )40066888666666&<###r
   c                     d}|                      || j        d          }|d         }|                     d|                                ft	          |                     |                               dS )z
        When given a L{twisted.python.modules.PythonAttribute} that refers
        directly to a L{MethodicalMachine}, L{findMachinesViaWrapper}
        yields that machine and its FQPN.
        a        from automat import MethodicalMachine

        rootMachine = MethodicalMachine()
        root.pyroot.rootMachineN)rL   r    assertInrI   listro   )r"   r4   r[   rootMachines       r   test_yieldsMachinez.FindMachinesViaWrapperTests.test_yieldsMachine   s     **64<KK
 !34);+;+;+=+=>466{CCDD	F 	F 	F 	F 	Fr
   c                     d}|                      || j        d          }|d         }|                     d|                                j        ft          |                     |                               dS )z
        When given a L{twisted.python.modules.PythonAttribute} that refers
        to a class that contains a L{MethodicalMachine} as a class
        variable, L{findMachinesViaWrapper} yields that machine and
        its FQPN.
                from automat import MethodicalMachine

        class PythonClass(object):
            _classMachine = MethodicalMachine()
        	clsmod.pyclsmod.PythonClass clsmod.PythonClass._classMachineN)rL   r    rt   rI   _classMachineru   ro   r"   r4   r[   PythonClasss       r   test_yieldsMachineInClassz5FindMachinesViaWrapperTests.test_yieldsMachineInClass   s     **64<MM
 !569"''))79466{CCDD	F 	F 	F 	F 	Fr
   c                     d}|                      || j        d          }|d         }|                     d|                                j        j        ft          |                     |                               dS )z
        When given a L{twisted.python.modules.PythonAttribute} that refers
        to a nested class that contains a L{MethodicalMachine} as a
        class variable, L{findMachinesViaWrapper} yields that machine
        and its FQPN.
                from automat import MethodicalMachine

        class PythonClass(object):
            class NestedClass(object):
                _classMachine = MethodicalMachine()
        nestedcls.pynestedcls.PythonClass/nestedcls.PythonClass.NestedClass._classMachineN)rL   r    rt   rI   NestedClassr}   ru   ro   r~   s       r   test_yieldsMachineInNestedClassz;FindMachinesViaWrapperTests.test_yieldsMachineInNestedClass   s     **6+/<+9; ;
 !!89H"''))5CE466{CCDD	F 	F 	F 	F 	Fr
   c                    d}|                      || j        d          }|                     |          d                                         }|                     d|ft          |                     |                               dS )z
        When given a L{twisted.python.modules.PythonModule} that refers to
        a module that contains a L{MethodicalMachine},
        L{findMachinesViaWrapper} yields that machine and its FQPN.
        rq   rr   rs   N)r>   r    rJ   rI   rt   ru   ro   )r"   r4   r*   rv   s       r   test_yieldsMachineInModulez6FindMachinesViaWrapperTests.test_yieldsMachineInModule  s    
 yAA++F334FGLLNN);7466v>>??	A 	A 	A 	A 	Ar
   c                    d}|                      || j        d          }|                     |          d                                         }|                     d|j        ft          |                     |                               dS )z
        When given a L{twisted.python.modules.PythonModule} that refers to
        the original module of a class containing a
        L{MethodicalMachine}, L{findMachinesViaWrapper} yields that
        machine and its FQPN.
        ry   rz   r{   r|   N)r>   r    rJ   rI   rt   r}   ru   ro   r"   r4   r*   r   s       r   !test_yieldsMachineInClassInModulez=FindMachinesViaWrapperTests.test_yieldsMachineInClassInModule  s     {CC++ (**.$&& 	9"02466v>>??	A 	A 	A 	A 	Ar
   c                     d}|                      || j        d          }|                     |          d                                         }|                     d|j        j        ft          |                     |                               dS )z
        When given a L{twisted.python.modules.PythonModule} that refers to
        the original module of a nested class containing a
        L{MethodicalMachine}, L{findMachinesViaWrapper} yields that
        machine and its FQPN.
        r   r   r   r   N)	r>   r    rJ   rI   rt   r   r}   ru   ro   r   s       r   'test_yieldsMachineInNestedClassInModulezCFindMachinesViaWrapperTests.test_yieldsMachineInNestedClassInModule0  s     ~FF++ +--1TVV 	 	H".<>466v>>??	A 	A 	A 	A 	Ar
   c                     d}d}|                      || j        d           |                      || j        d          }|                     t          |                     |                               dS )aM  
        When given a L{twisted.python.modules.PythonAttribute} that refers
        to a class imported from another module, any
        L{MethodicalMachine}s on that class are ignored.

        This behavior ensures that a machine is only discovered on a
        class when visiting the module where that class was defined.
        z
        from automat import MethodicalMachine

        class PythonClass(object):
            _classMachine = MethodicalMachine()
        z2
        from original import PythonClass
        r^   r_   Nr>   r    rZ   ru   ro   )r"   r`   ra   importingModules       r   test_ignoresImportedClassz5FindMachinesViaWrapperTests.test_ignoresImportedClassF  sy     	mDDD///*.,*8: : 	d99/JJKKLLLLLr
   c                    |                      | j        g          }|                     | j                                      d          }|                                 |                    d                                           d}|                     ||j        d           |d         }t          | 	                    |          t          j        d                    }|                     |d                   }|d                                         }|d	                                         }t          d|fd
|j        fgt          j        d                    }	|                     |	|           dS )z`
        L{findMachinesViaWrapper} descends into packages to discover
        machines.
        test_package__init__.pyz
        from automat import MethodicalMachine


        class PythonClass(object):
            _classMachine = MethodicalMachine()


        rootMachine = MethodicalMachine()
        	module.pyr   keyr*   ztest_package.module.rootMachineztest_package.module.PythonClassz-test_package.module.PythonClass._classMachineN)r   r    r   r/   makedirstouchr>   r   sortedro   operator
itemgetterrJ   rI   r}   assertEqual)
r"   
pythonPathpackager4   r   machinesr[   rv   r   expectedMachiness
             r   test_descendsIntoPackagesz5FindMachinesViaWrapperTests.test_descendsIntoPackagesa  st   
 __dl^44
----33NCCm$$**,,,	 	k:::!.1$55lCC&1!446 6 6 **<+ABB
 !BCHHJJ !BCHHJJ!/=')* 08/B1/E/E	G G G 	)844444r
   c                     d}|                      || j        d          }|                     t          |                     |                               dS )z
        L{findMachinesViaWrapper} ignores infinite loops.

        Note this test can't fail - it can only run forever!
        zh
        class InfiniteLoop(object):
            pass

        InfiniteLoop.loop = InfiniteLoop
        zloop.pyNr   )r"   r4   r*   s      r   test_infiniteLoopz-FindMachinesViaWrapperTests.test_infiniteLoop  sR     yAAd99&AABBCCCCCr
   )rM   rN   rO   rP   TEST_MODULE_SOURCEr   rw   r   r   r   r   r   r   r   r   rQ   rR   s   @r   rm   rm      s         (= = = = =
F F F"F F F&F F F.A A A A A A(A A A,M M M6$5 $5 $5LD D D D D D Dr
   rm   c                   `    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd ZdS )WrapFQPNTestsz
    Tests that ensure L{wrapFQPN} loads the
    L{twisted.python.modules.PythonModule} or
    L{twisted.python.modules.PythonAttribute} for a given FQPN.
    c                     ddl m}m} ddlm}m}m}m} || _        || _        || _        || _        || _        || _        d S )Nr   )PythonModulePythonAttributerV   )wrapFQPNInvalidFQPNNoModuleNoObject)r   r   r   rX   r   r   r   r   )r"   r   r   r   r   r   r   s          r   r   zWrapFQPNTests.setUp  so    HHHHHHHHIIIIIIIIIIII(. &  r
   c                     |                      || j                   |                     |j        |j                   |                     |                                |           dS )zt
        Assert that a L{twisted.python.modules.PythonModule} refers to a
        particular Python module.
        N)assertIsInstancer   r   rA   rM   assertIsrI   )r"   moduleWrapperr*   s      r   assertModuleWrapperRefersToz)WrapFQPNTests.assertModuleWrapperRefersTo  s^    
 	mT->???+V_===m((**F33333r
   c                     |                      || j                   |                     |j        |           |                     |                                |           dS )zw
        Assert that a L{twisted.python.modules.PythonAttribute} refers to a
        particular Python object.
        N)r   r   r   rA   r   rI   )r"   attributeWrapperfqpnobjs       r   assertAttributeWrapperRefersToz,WrapFQPNTests.assertAttributeWrapperRefersTo  s_    
 	.0DEEE).555&++--s33333r
   c                     |                      | j                  5  |                     d           ddd           dS # 1 swxY w Y   dS )zO
        L{wrapFQPN} raises L{InvalidFQPN} when given an empty string.
         NassertRaisesr   r   r"   s    r   test_failsWithEmptyFQPNz%WrapFQPNTests.test_failsWithEmptyFQPN  s     t/00 	 	MM"	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	   >AAc                     dD ]I}|                      | j                  5  |                     |           ddd           n# 1 swxY w Y   JdS )zk"
        L{wrapFQPN} raises L{InvalidFQPN} when given a badly-dotted
        FQPN.  (e.g., x..y).
        )z.failszfails.zthis..failsNr   r"   bads     r   test_failsWithBadDottingz&WrapFQPNTests.test_failsWithBadDotting  s    
 7 	# 	#C""4#344 # #c"""# # # # # # # # # # # # # # #	# 	#   AA	A	c                     ddl }|                     d          }|                     || j                   |                     |                                |           dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the single module a dotless FQPN describes.
        r   Nr:   )r:   r   r   r   r   rI   )r"   r:   r   s      r   test_singleModulezWrapFQPNTests.test_singleModule  s]    
 				d++mT->???m((**B/////r
   c                     |                      | j                  5  |                     d           ddd           dS # 1 swxY w Y   dS )z~
        L{wrapFQPN} raises L{NoModule} when given a dotless FQPN that does
        not refer to a module or package.
        zthis is not an acceptable name!N)r   r   r   r   s    r   *test_failsWithMissingSingleModuleOrPackagez8WrapFQPNTests.test_failsWithMissingSingleModuleOrPackage  s    
 t}-- 	= 	=MM;<<<	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=r   c                 `    ddl }|                     |                     d          |           dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the single package a dotless FQPN describes.
        r   Nxml)r   r   r   r"   r   s     r   test_singlePackagez WrapFQPNTests.test_singlePackage  s5    
 	


((u)=)=sCCCCCr
   c                 j    ddl }|                     |                     d          |j                   dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the deepest package described by dotted FQPN.
        r   Nz	xml.etree)	xml.etreer   r   etreer   s     r   test_multiplePackagesz#WrapFQPNTests.test_multiplePackages  s:    
 	(({)C)CSYOOOOOr
   c                 t    ddl }|                     |                     d          |j        j                   dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonModule}
        referring to the deepest module described by dotted FQPN.
        r   Nzxml.etree.ElementTree)xml.etree.ElementTreer   r   r   ElementTreer   s     r    test_multiplePackagesFinalModulez.WrapFQPNTests.test_multiplePackagesFinalModule  sN    
 	%$$$((MM122CI4I	K 	K 	K 	K 	Kr
   c                 l    ddl }|                     |                     d          d|j                   dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute}
        referring to the deepest object an FQPN names, traversing one module.
        r   Nzos.path)r:   r   r   r   )r"   r:   s     r   test_singleModuleObjectz%WrapFQPNTests.test_singleModuleObject  sD    
 				++MM)$$i	: 	: 	: 	: 	:r
   c                     ddl }ddl}d|j        j        j        fd|j        j        ffD ]/\  }}|                     |                     |          ||           0dS )z
        L{wrapFQPN} returns a L{twisted.python.modules.PythonAttribute}
        referring to the deepest object described by an FQPN,
        descending through several packages.
        r   Nz xml.etree.ElementTree.fromstringz!automat.MethodicalMachine.__doc__)	r   automatr   r   
fromstringMethodicalMachinerP   r   r   )r"   r   r   r   r   s        r   test_multiplePackagesObjectz)WrapFQPNTests.test_multiplePackagesObject  s     	%$$$=90;=>"4<>? 	0 	0ID# //d##T30 0 0 0		0 	0r
   c                     dD ]I}|                      | j                  5  |                     |           ddd           n# 1 swxY w Y   JdS )z
        L{wrapFQPN} raises L{NoObject} when given an FQPN that contains a
        missing attribute, module, or package.
        )zxml.etree.nope!z*xml.etree.nope!.but.the.rest.is.believableN)r   r   r   r   s     r   4test_failsWithMultiplePackagesMissingModuleOrPackagezBWrapFQPNTests.test_failsWithMultiplePackagesMissingModuleOrPackage  s    
B 	# 	#C""4=11 # #c"""# # # # # # # # # # # # # # #	# 	#r   N)rM   rN   rO   rP   r   r   r   r   r   r   r   r   r   r   r   r   r   r	   r
   r   r   r     s         	! 	! 	!4 4 44 4 4  # # #
0 
0 
0= = =D D DP P PK K K: : :0 0 0 # # # # #r
   r   c                   ,     e Zd ZdZdZ fdZd Z xZS )FindMachinesIntegrationTestszs
    Integration tests to check that L{findMachines} yields all
    machines discoverable at or below an FQPN.
    z
    from automat import MethodicalMachine

    class PythonClass(object):
        _machine = MethodicalMachine()
        ignored = "i am ignored"

    rootLevel = MethodicalMachine()

    ignored = "i am ignored"
    c                    t          t          |                                            ddlm} || _        |                     | j                                      d          }|                                 | 	                    | j        g          | _
        |                     | j        |j        d           |                    d          }|                                 |                    d                                           |                     | j        |j        d           |                     | j
        d                   | _        |                     | j
        d         d         d                   | _        d S )NrV   )findMachinesr   r   
subpackager   r*   )r   r   r   rX   r   r   r    r/   r   r   r   r8   SOURCEr   r   r>   rJ   packageDictr[   )r"   r   
packageDirsubPackageDirr#   s       r   r   z"FindMachinesIntegrationTests.setUp0  sS   *D1177999,,,,,,(]]4<0066~FF
//4<.99T[*/=III"((66   M**00222]%7EEE00ON+- -//ON+L9(CE Er
   c                    t          |                     d          t          j        d                    }| j        d                                         }| j        d                                         }| j        d         }|                                }| j        d         }|                                }t          d|fd|j        fd|fd	|j        fgt          j        d                    }|                     ||           d
S )z
        Given a top-level package FQPN, L{findMachines} discovers all
        L{MethodicalMachine} instances in and below it.
        r   r   r   ztest_package.rootLevelztest_package.PythonClassz(test_package.subpackage.module.rootLevelz*test_package.subpackage.module.PythonClassz!test_package.PythonClass._machinez3test_package.subpackage.module.PythonClass._machineN)	r   r   r   r   r   rI   r[   _machiner   )	r"   r   tpRootLeveltpPythonClassmRLAttr
mRootLevelmPCAttrmPythonClassr   s	            r   test_discoverAllz-FindMachinesIntegrationTests.test_discoverAllF  s   
 $++N;;&1!446 6 6 &'?@EEGG()CDIIKK/"LM\\^^
/"NO||~~!&41=3IJ8*EC#%&
 #A&&( ( ( 	)844444r
   )rM   rN   rO   rP   r   r   r   rQ   rR   s   @r   r   r     s]         

FE E E E E,5 5 5 5 5 5 5r
   r   )r   r:   r'   r   r2   r   unittestr   r   r   r   rT   rm   r   r   r	   r
   r   <module>r      s    				  



   % % % % % % % %  9J 9J 9J 9J 9J8 9J 9J 9Jx    "=>>^? ^? ^? ^? ^?0 ^? ^? ?>^?B    "=>>cD cD cD cD cD"6 cD cD ?>cDL    "=>>B# B# B# B# B#H B# B# ?>B#J    "=>>@5 @5 @5 @5 @5#7 @5 @5 ?>@5 @5 @5r
   