ϪfJddlmZddlZddlZddlZddlZddlZddlmZddl m Z ddl m Z m Z ddlmZddlmZddlmZdd lmZdd lmZmZdd lmZdd lmZdd lmZddlm Z ddl!m"Z"ddl#m$Z$m%Z%m&Z&m'Z'm(Z(ddl)m*Z*ddl+m,Z,e-dZ.d1dZ/d2dZ0d3dZ1d4dZ2e"e2e1Z3GddejhZ5GddejhZ6GddejhZ7Gdd ejhZ8Gd!d"ejhZ9Gd#d$ejhZ:Gd%d&ejvZ<Gd'd(ejvZ=Gd)d*ejvZ>Gd+d,ejvZ?Gd-d.ejvZ@Gd/d0ejvZAy)5) annotationsN)StringIO)List) assert_thatcontains_string)given) sampled_from)Logger)util)FilePath IFilePath) UsageError)trial)unittest)DistTrialRunner)compose)DestructiveTestSuite TestLoader TestSuite TrialRunner_Runner) testNames) fileContentsrc6tjt|S)z1 For finding files in twisted/trial/test )r sibpath__file__)filenames @/usr/lib/python3/dist-packages/twisted/trial/test/test_script.pyrr&s <<( ++c6tjdy)z. Emit something to L{twisted.logger}. somethingN)r infor r logSomethingr%-s HMM+r cPtj}|j||S)z? Parse an argument list using trial's argument parser. )rOptions parseOptions)argvconfigs rparseArgumentsr+4s"]]_F  Mr ctj|}t|_t t j tg}|j||S)zM Run L{logSomething} as a test method using the given configuration. ) r _makeRunnerrstreamrpyunitFunctionTestCaser%run)r*runnersuites r runFromConfigr4=sF  v &FJFM v..|<= >E JJu Mr ceZdZdZeegdd dZeeddgd dZeeddgd dZy) LogfileTestsz) Tests for the --logfile option. )zdir-azdir-bz dir-c/dir-dctd|g}t|j|d}t|t t dy)z If no value is given for the option then logs are written to a log file constructed from a default value. --temp-directorylogfiler"NrunFromArgumentsr preauthChildrrr)selfworkingDirectoryr*logPaths r test_defaultzLogfileTests.test_defaultPsD"#57G"HI%&67DDVIEVWG\/+*FGHr z somelog.txtzsomedir/somelog.txtctd|g}t|dj|}t|t t dy)z If the value given for the option is a relative path then it is interpreted relative to trial's own temporary working directory and logs are written there. --logfiletemp-directoryr"Nr:)r=r9r*r?s rtest_relativePathzLogfileTests.test_relativePathbsB";"89%f-=&>?LLWUG\/+*FGHr ctdj|}td|jg|}t |t t dy)z If the value given for the option is an absolute path then it is interpreted absolutely and logs are written there. .rBr"N)r r<r;pathrrr)r=r9r?iPaths rtest_absolutePathzLogfileTests.test_absolutePathtsB"3-,,W5+w||45"E< (DEFr N)r>strreturnNone)r9rJrKrL) __name__ __module__ __qualname____doc__rr r@rDrIr$r rr6r6Ks   II %  II %   G Gr r6c@eZdZdZd dZd dZd dZd dZd dZd dZ y) ForceGarbageCollectionTestsz* Tests for the --force-gc option. ctj|_g|_|j t d|j tj|j}t||g|_ y)Ncollect) rr'r*logpatchgcrTr/r0 simpleTestrtest)r=rYs rsetUpz!ForceGarbageCollectionTests.setUpsNmmo   2y$,,/&&t7tTl+ r c:|jjdy)zD A simple test method that records that it was run. rYNrUappendr=s rrXz&ForceGarbageCollectionTests.simpleTests r c:|jjdy)zI A replacement for gc.collect that logs calls to itself. rTNr\r^s rrTz#ForceGarbageCollectionTests.collects  "r cbtj|j}t|_|S)zN Return a L{TrialRunner} object that is safe to use in tests. )rr-r*rr.r=r2s r makeRunnerz&ForceGarbageCollectionTests.makeRunners&""4;;/   r cd|jd<|jj|j}|j|j|j |j gdy)z Passing the --force-gc option to the trial script forces the garbage collector to run before and after each test. Tzforce-gc)rTrYrTrTrYrTNr* postOptionsrbr1rY assertEqualrUras r test_forceGcz(ForceGarbageCollectionTests.test_forceGcsV #' J !" 499  HHR r c|jj|j}|j|j|j |j ddgy)z> By default, no garbage collection is forced. rYNrdras rtest_unforceGcz*ForceGarbageCollectionTests.test_unforceGcsI !" 499 FF#34r NrKrL)rKr) rMrNrOrPrZrXrTrbrgrir$r rrRrRs%, #   5r rRc(eZdZdZddZddZddZy)SuiteUsedTestsz? Check the category of tests suite used by the loader. c6tj|_y)z6 Create a trial configuration object. Nrr'r*r^s rrZzSuiteUsedTests.setUpsmmo r ctj|j}|j|jt y)zK By default, the loader should use L{DestructiveTestSuite} N)r _getLoaderr*rf suiteFactoryrr=loaders rtest_defaultSuitez SuiteUsedTests.test_defaultSuites/!!$++. ,,.BCr cd|jd<tj|j}|j|jt y)zw The C{until-failure} configuration uses the L{TestSuite} to keep instances alive across runs. Tz until-failureN)r*rrprfrqrrrs rtest_untilFailureSuitez%SuiteUsedTests.test_untilFailureSuites< (, O$!!$++. ,,i8r Nrj)rMrNrOrPrZrtrvr$r rrlrls& D9r rlceZdZddZddZddZddZddZddZddZ ddZ dd Z dd Z dd Z dd Zdd ZddZddZddZddZddZddZddZddZddZddZddZddZddZy)TestModuleTestsc6tj|_yNrnr^s rrZzTestModuleTests.setUpmmo r cd|_yrz)r*r^s rtearDownzTestModuleTests.tearDowns  r cX|jt||jgy)zq Check that the testNames helper method accurately collects the names of tests in suite. N)rfridr^s rtest_testNameszTestModuleTests.test_testNamess 44779+6r ct}t|}ttt|j|}|j |j |j ||yrz)rrrmap loadByNamesortrf)r=test1namesrsnames1names2s rassertSuitesEqualz!TestModuleTests.assertSuitesEqualsQ5!9S):):E%BCD   (r cT|jdt|jdy)Nrtests)rflenr*r^s rtest_baseStatezTestModuleTests.test_baseStates  C G 456r c|jjtd|jt j |jdgy)z Check that --testmodule loads a suite which contains the tests referred to in test-case-name inside its parameter. moduletest.pytwisted.trial.test.test_logNr*opt_testmodulerrr _getSuiter^s rtest_testmoduleOnModulez'TestModuleTests.test_testmoduleOnModules? ""7?#;<  OODKK (+H*I r c|jjtd|jjtd|jt j |jdgy)z When the same module is specified with two --testmodule flags, it should only appear once in the suite. rrNrr^s rtest_testmoduleTwicez$TestModuleTests.test_testmoduleTwicesV ""7?#;< ""7?#;<  OODKK (+H*I r c|jjtd|jjtd|jt j |jdgy)z If --testmodule is specified twice, once for module A and once for a module which refers to module A, then make sure module A is only added once. rz test_log.pyrNrr^s r test_testmoduleOnSourceAndTargetz0TestModuleTests.test_testmoduleOnSourceAndTarget sV ""7?#;< ""7=#9:  OODKK (+H*I r c|jjtd|jt j |jdgy)z When given a module that refers to *itself* in the test-case-name variable, check that --testmodule only adds the tests once. z moduleself.pyztwisted.trial.test.moduleselfNrr^s rtest_testmoduleOnSelfModulez+TestModuleTests.test_testmoduleOnSelfModules? ""7?#;<  OODKK (+J*K r c|jjtd|jt j |jddgy)zm Check that --testmodule loads tests referred to in test-case-name buffer variables. scripttest.pyrtwisted.trial.test.test_runnerNrr^s rtest_testmoduleOnScriptz'TestModuleTests.test_testmoduleOnScript"sB ""7?#;<  OODKK ( *,L M r cZt}tj|c}t_d} |jj ||j dt |jd|j d|d|j|t_y#|t_wxYw)zz Check that --testmodule displays a meaningful error message when passed a non-existent filename. ztest_thisbetternoteverexist.pyrrFile  doesn't exist Nrsysstderrr*rrfrgetvalue)r=buffyrrs r test_testmoduleOnNonexistentFilez0TestModuleTests.test_testmoduleOnNonexistentFile-s   ZZ 3 KK & &x 0   QDKK$8 9 :   uXL0@A5>>CS TCJCJ A'B B*c|jjtd|jdt |jdy)z Check that --testmodule adds no tests to the suite for modules which lack test-case-name buffer variables. novars.pyrrN)r*rrrfrr^s rtest_testmoduleOnEmptyVarsz*TestModuleTests.test_testmoduleOnEmptyVars<s9 ""7;#78 C G 456r cZt}tj|c}t_d} |jj ||j dt |jd|j d|d|j|t_y#|t_wxYw)z Check that --testmodule does *not* support module names as arguments and that it displays a meaningful error message. ztwisted.trial.test.test_scriptrrrrNr)r=rr moduleNames rtest_testmoduleOnModuleNamez+TestModuleTests.test_testmoduleOnModuleNameDs   ZZ 5  KK & &z 2   QDKK$8 9 :   uZN2BCU^^EU VCJCJrcZd}tj|}|jddi|y)Nz5-*- test-case-name: twisted.trial.test.test_tests -*-test-case-nametwisted.trial.test.test_testsr_parseLocalVariablesrfr= declaration localVarss rtest_parseLocalVariablez'TestModuleTests.test_parseLocalVariableSs.M ..{;  *,KLiXr cZd}tj|}|jddi|y)Nz6-*- test-case-name: twisted.trial.test.test_tests; -*-rrrrs rtest_trailingSemicolonz&TestModuleTests.test_trailingSemicolonXs.N ..{;  *,KLiXr c\d}tj|}|jddd|y)Nz?-*- test-case-name: twisted.trial.test.test_tests; foo: bar -*-rbar)rfoorrs rtest_parseLocalVariablesz(TestModuleTests.test_parseLocalVariables]s4 P ..{;  >u My r cZd}tj|}|jddi|y)Nz:## -*- test-case-name: twisted.trial.test.test_tests -*- #rrrrs rtest_surroundingGuffz$TestModuleTests.test_surroundingGufffs.U ..{;  *,KLiXr cN|jttjdyNr assertRaises ValueErrorrrr^s rtest_invalidLinez TestModuleTests.test_invalidLineks *e&@&@%Hr c|jttjd|jttjd|jttjdy)Nz -*- foo -*-z-*- foo: bar; qux -*-z-*- foo: bar: baz; qux: qax -*-rr^s rtest_invalidDeclarationz'TestModuleTests.test_invalidDeclarationnsT *e&@&@-P  224K   224U r chtjtd}|jddi|y)NrrrrloadLocalVariablesrrfr=rs rtest_variablesFromFilez&TestModuleTests.test_variablesFromFilews.,,W_-EF  *,IJIVr cdtjtd}|ji|y)Nrrrs rtest_noVariablesInFilez&TestModuleTests.test_noVariablesInFile{s',,W[-AB  Y'r chtjtd}|jddi|y)Nrrz:twisted.trial.test.test_log,twisted.trial.test.test_runnerrrs rtest_variablesFromScriptz(TestModuleTests.test_variablesFromScripts5,,W_-EF   S    r cftjtd}|j|dgy)Nrr)rgetTestModulesrrfr=moduless rtest_getTestModulesz#TestModuleTests.test_getTestModuless+&&w'?@ #@"ABr cvtjtd}|jt |dy)Nrr)rrrrfrrs rtest_getTestModules_noVarsz*TestModuleTests.test_getTestModules_noVarss+&&w{';< Wq)r cztjtd}|jt |ddhy)Nrrr)rrrrfsetrs rtest_getTestModules_multiplez,TestModuleTests.test_getTestModules_multiples5&&w'?@  L *,L M r cdD]*}|jtj||d,dtdtdfD]*}|j tj||d,y)N)ztest_script.pyz!twisted/trial/test/test_script.pyz should be a test filez twisted/trial/test/moduletest.pyrz test_foo.batz should *not* be a test file) assertTruer isTestFiler assertFalse)r=rs rtest_looksLikeTestModulez(TestModuleTests.test_looksLikeTestModulesO H OO  *,45   / O $ N #  H     *,:;   r Nrj)rrrz list[str]rKrL)rMrNrOrZr}rrrrrrrrrrrrrrrrrrrrrrrrr$r rrxrxs&7)7          7  Y Y  Y I W(  C* r rxcHeZdZdZd dZd dZd dZd dZd dZd dZ d dZ y ) WithoutModuleTestsz* Test the C{without-module} flag. crtj|_ttj |_y)zl Create a L{trial.Options} object to be used in the tests, and save C{sys.modules}. N)rr'r*dictrr savedModulesr^s rrZzWithoutModuleTests.setUps" mmo  -r cdD]Q}||jvr!|j|tj|<2tjj|dSy)z) Restore C{sys.modules}. )imaplibsmtplibN)rrrpop)r=modules rr}zWithoutModuleTests.tearDownsL- .F***&*&7&7&? F# -  .r cddl}|S)zE Try to import the C{smtplib} module, and return it. rN)r)r=rs r _checkSMTPzWithoutModuleTests._checkSMTP  r cddl}|S)zE Try to import the C{imaplib} module, and return it. rN)r)r=rs r _checkIMAPzWithoutModuleTests._checkIMAPrr c|jjddg|jt|jt j d=|j|j tjy)zT Check that after disabling a module, it can't be imported anymore. --without-modulerN) r*r(r ImportErrorrrrassertIsInstancetypes ModuleTyper^s rtest_disableOneModulez(WithoutModuleTests.test_disableOneModulesY   "4i!@A +t7 KK " doo/1A1ABr c|jjddg|jt|j|jt|j t jd=t jd=|j|j tj|j|j tjy)zE Check that several modules can be disabled at once. rzsmtplib,imaplibrrN) r*r(rrrrrrrrrr^s rtest_disableMultipleModulesz.WithoutModuleTests.test_disableMultipleModuless   "46G!HI +t7 +t7 KK " KK " doo/1A1AB doo/1A1ABr c|j|jtj|j t dt j|jjddg|jt|jy)zP Disabling an already imported module should produce a warning. z4Module 'smtplib' already imported, disabling anyway.rrN) rrrr assertWarnsRuntimeWarningrrr*r(rrr^s r!test_disableAlreadyImportedModulez4WithoutModuleTests.test_disableAlreadyImportedModulesg doo/1A1AB   B NN KK $ $  +   +t7r Nrj)rKobject) rMrNrOrPrZr}rrrrrr$r rrrs,.. C C 8r rcHeZdZdZeedddZd dZd dZd dZ d dZ y) CoverageTestsz+ Tests for the I{coverage} option. gettraceNz;Cannot test trace hook installation without inspection API.ch|jtjtjy)zf Arrange for the current trace hook to be restored when the test is complete. N) addCleanuprsettracerr^s rrZzCoverageTests.setUps  clln5r ctj}|jdg|jJ|j t j |jjy)z} L{trial.Options} handles C{"--coverage"} by installing a trace hook to record coverage information. z --coverageN)rr'r(tracerrfrr globaltracer=optionss rtest_tracerInstalledz"CoverageTests.test_tracerInstalledsS --/l^,~~)))  LLN NN & & r ctj}|j|jt dj |ddgy)z L{trial.Options.coverdir} returns a L{FilePath} based on the default for the I{temp-directory} option if that option is not specified. rFrCcoverageN)rr'rfcoverdirr descendantrs rtest_coverdirDefaultz"CoverageTests.test_coverdirDefaultsF --/      SM $ $g.>&?%L M r c|j}tj}|jd|g|j |j t |jdy)z If a value is specified for the I{temp-directory} option, L{trial.Options.coverdir} returns a child of that path. r8r N)mktemprr'r(rfr r child)r=rGrs rtest_coverdirOverriddenz%CoverageTests.test_coverdirOverridden!sV {{}--/0$78 ))+Xd^-A-A*-MNr rj) rMrNrOrPgetattrrskiprZrr rr$r rrrs2sJ%-L6    Or rc@eZdZdZd dZd dZd dZd dZd dZd dZ y) OptionsTestsz% Tests for L{trial.Options}. c6tj|_y)zE Build an L{Options} object to be used in the tests. Nrr'rr^s rrZzOptionsTests.setUp1s}} r c|jtjtjt j r|jtj |jjgd|jj}|jd||jd|jddg|y)z C{_getWorkerArguments} discards options like C{random} as they only matter in the manager, and forwards options like C{recursionlimit} or C{disablegc}. )--recursionlimit2000--random4 --disablegcrrrN) rrsetrecursionlimitgetrecursionlimitrW isenabledenablerr(_getWorkerArgumentsassertInremoverf)r=argss rtest_getWorkerArgumentsz$OptionsTests.test_getWorkerArguments7s --s/D/D/FG <<> OOBII & !! H ||//1 mT* M" ,f5t !!  LL % % ;  H#e*Ur Nrj) rMrNrOrPrZr&r-r/r1r6r$r rrr,s(' =$ T V Vr rc8eZdZdZddZddZddZddZddZy) MakeRunnerTestsz. Tests for the L{_makeRunner} helper. c6tj|_yrzrr^s rrZzMakeRunnerTests.setUps}} r c>|jjgdtj|j}t |t sJ|j |t |jd|j|jdg|jy)z L{_makeRunner} returns a L{DistTrialRunner} instance when the C{--jobs} option is passed. The L{DistTrialRunner} knows how many workers to run and the C{workerArguments} to pass to them. )r(r --force-gcr;N) rr(rr- isinstancerrrf _maxWorkers_workerArgumentsras r test_jobszMakeRunnerTests.test_jobssy !!"?@""4<<0&/222 fo6 F../ ,)@)@Ar c |jjgdtj|j}t |t sJ|j |t |jt j|jy)z L{_makeRunner} returns a L{TrialRunner} instance in C{DRY_RUN} mode when the C{--dry-run} option is passed, even if C{--jobs} is set. )r(rz --dry-runN) rr(rr-r=rrrfDRY_RUNmoderas rtest_dryRunWithJobsz#MakeRunnerTests.test_dryRunWithJobsse !!">?""4<<0&+... fk2 ,,fkk:r c4tjjdfd }|jtjd|tj}|j gd|j tjtj|y)Nc\|dk(rtjj||S)N doNotFind)rreflectModuleNotFound)fqnnamedAnys rnamedAnyExceptdoNotFindzFMakeRunnerTests.test_DebuggerNotFound..namedAnyExceptdoNotFinds*k!mm22377C= r rK)r)z --debuggerrG)rJrJrKr) rrHrKrVr'r(r_DebuggerNotFoundr-)r=rLrrKs @rtest_DebuggerNotFoundz%MakeRunnerTests.test_DebuggerNotFoundsf==)) ! 5==*.EF--/CD %1153D3DgNr c|jjdgtj|j}t |t sJ|j |jy)z Passing C{--exitfirst} wraps the reporter with a L{reporter._ExitWrapper} that stops on any non-success. z --exitfirstN)rr(rr-r=rr _exitFirstras rtest_exitfirstzMakeRunnerTests.test_exitfirstsN !!=/2""4<<0&+... ))*r Nrj) rMrNrOrPrZr@rDrNrQr$r rr8r8~s"' B ; O+r r8c eZdZdZddZddZy)RunTestsz( Tests for the L{run} function. cH|jtjddy)Nr(cyrzr$r^s rz RunTests.setUp..sr )rVrr'r^s rrZzRunTests.setUps 5==.2CDr cdd}|jtd| tj|jdy#t$r%}|j dt |Yd}~yd}~wwxYw)zY When a debugger is not found, an error message is printed to the user. c,tjdr)rrM)r%kwargss rr-z3RunTests.test_debuggerNotFound.._makeRunners))%0 0r r-z0Should have exited due to non-existent debugger!rN)r%rrYrrKrL)rVrr1fail SystemExitr#rJ)r=r-es rtest_debuggerNotFoundzRunTests.test_debuggerNotFounds^  1 5-5 J IIK IIH I ) MM%Q ( ( )sA A1 A,,A1Nrj)rMrNrOrPrZr]r$r rrSrSsE Jr rSc eZdZdZddZddZy)TestArgumentOrderTestszQ Tests for the order-preserving behavior on provided command-line tests. cTtj|_t|_yrz)rr'r*rrsr^s rrZzTestArgumentOrderTests.setUpsmmo  l r c"gd}|jj|tj|j}t |}t t |jj|}t |}|j||y)zN Multiple tests passed on the command line are not reordered. )rz"twisted.trial.test.test_assertionsz twisted.trial.test.test_deferredN) r*r(rrrrrrsrrf)r=rr3r expectedSuite expectedNamess rtest_preserveArgumentOrderz1TestArgumentOrderTests.test_preserveArgumentOrdersn    ' ,% !#dkk&<&? u .r c|jjgdtj|j}|j |jd}|j t |gdy)z --order=toptobottom causes trial to run test methods within a given test case from top to bottom as they are defined in the body of the class. )r3 toptobottomrir)rjrlrmrkNrnrps rtest_toptobottomzOrderTests.test_toptobottom4sc   O !!$++.""4;;w#78  e   r c|jjgdtj|j}|j |jd}|j t |gdy)z --order=toptobottom causes trial to run test classes within a given module from top to bottom as they are defined in the module's source. r3rrsr)rjrlrmrkrurtNrnrps rtest_toptobottomModulez!OrderTests.test_toptobottomModuleKsc   G !!$++.""4;;w#78  e   r c |jjgdtj|j}|j |jd}t |}|j |t|dy)z --order=toptobottom causes trial to run test modules within a given package alphabetically, with tests within each module run top to bottom. )r3rrxrc*|jdddS)NrFr<)split)names rrVz4OrderTests.test_toptobottomPackage..qs4::c?2A+>r )keyN)r*r(rrprorrfr{r|s rtest_toptobottomPackagez"OrderTests.test_toptobottomPackagebsl   !QR!!$++.""4;;w#78%    5> ? r c|j}t|jd}|j|jdj d|jdj t j djd|jj}tjjd||jtjj|ddlm}|jtj j"d|jtj j"|j$|jdj|j&j)gd t+j,|j&}|j/|}|j1t3|gd y ) z{ --order=toptobottom detects the source line of methods from modules whose source file is missing. twisted_toptobottom_tempz __init__.pyr ztest_missing.pya  from twisted.trial.unittest import TestCase class TestMissing(TestCase): def test_second(self) -> None: pass def test_third(self) -> None: pass def test_fourth(self) -> None: pass def test_first(self) -> None: pass utf8r) test_missingr)z=twisted_toptobottom_temp.test_missing.TestMissing.test_secondz)>? '(//1   G !!$++.!!,/  e   r c^|jt|jjddgy)zL An unknown order passed to --order raises a L{UsageError}. r3z I don't existN)rrr*r(r^s rtest_unknownOrderzOrderTests.test_unknownOrders(   009o2N r Nrj) rMrNrOrPrZrqrvr}rrrrrr$r rrfrfs5& , . / . . $. ` r rfceZdZdZddZy)HelpOrderTestsz+ Tests for the --help-orders flag. c|jtdtx}|jtt j jdg}|j|jd|j}d}t jjD]a\}\}}tjtj|dtj||}|j!||||fzcy)zS --help-orders prints each of the available orders and then exits. stdoutz --help-ordersrz4%r with its description not properly described in %rz.*ryN)rVrrrr[rr'r(rfcoder _runOrdersitemsresearchescaper) r=rexcoutputrz orderName orderDesc_matchs r&test_help_ordersPrintsSynopsisAndQuitsz5HelpOrderTests.test_help_ordersPrintsSynopsisAndQuitss 3HJ"6&7  446G  1%"D).)9)9)?)?)A B %I~ 1II99Y'(299Y+?*@AE OOEsi-@'@O A  Br Nrj)rMrNrOrPrr$r rrrs Br r)rrJrKrJrj)r)z List[str]rK trial.Options)r*rrKr)B __future__rrWrrrriortypingrhamcrestrr hypothesisrhypothesis.strategiesr twisted.loggerr twisted.pythonr twisted.python.filepathr r twisted.python.usagertwisted.scriptsr twisted.trialrtwisted.trial._dist.disttrialrtwisted.trial._dist.functionalrtwisted.trial.runnerrrrrrtwisted.trial.test.test_loaderrmatchersr __import__r/rr%r+r4r;SynchronousTestCaser6rRrlrxrrTestCaserr8rSr_rfrr$r rrsq#  1.!7+!"925" J ,=.9=G8//=G@45(">">45n9X1198Ih22IXL855L8^0OH000OfOV8$$OVd7+h''7+tJx  J:/X../:y ""y xBX&&Br