testng-6.9.12/0000755000175000017500000000000012735760204012425 5ustar eugeneeugenetestng-6.9.12/update-beust.com0000755000175000017500000000131012732165123015521 0ustar eugeneeugenev=6.5.2 ev=5.13.0.3 DEST=testng TARGET=target set -x if [ -z "${U}" ] then echo Variable "$U" is not set exit -1 fi RSYNC="rsync --verbose --progress --stats" ${RSYNC} ${TARGET}/testng-${v}.zip ${U}@beust.com:${DEST} ${RSYNC} -r src/main/resources/testng-1.0.dtd testng-1.0.dtd.html ${U}@beust.com:${DEST}/doc #${RSYNC} testng-${v}.jar testng-${v}-bundle.jar testng-${v}.zip testng-eclipse-${ev}.zip ${U}@beust.com:${DEST} #scp -r javadocs doc/*.html doc/*.css src/main/resources/testng-1.0.dtd testng-1.0.dtd.html ${U}@beust.com:${DEST} #scp dtd/* ${U}@beust.com:w/dtd #(cd ~/java/beust.com; scp -r . ${U}@beust.com:w/eclipse) # scp testng-eclipse-${ev}.zip doc/download.html ${U}@beust.com:${DEST} testng-6.9.12/README-publish0000644000175000017500000000124012732165123014742 0ustar eugeneeugeneTo publish: - ./gradlew bintrayUpload will upload the release to JCenter. It will fail if the version is a SNAPSHOT - ./gradlew uploadArchives will upload - the snapshot to https://oss.sonatype.org/content/repositories/snapshots - the release to https://oss.sonatype.org/service/local/staging/deploy/maven2 For a release, you then need to go to https://oss.sonatype.org/index.html#stagingRepositories to manually close and release the distribution. Note that `./gradlew uploadArchives` is run by Travis after each new push to deploy the latest HEAD to the snapshot directory. As such, the version number of `build.gradle` in the git repo should always be -SNAPSHOT. testng-6.9.12/CHANGES.txt0000644000175000017500000017657512732165123014257 0ustar eugeneeugeneCurrent Fixed: GITHUB-1017 Reporter.log is ignored in skipped test listener (Scott Kirkpatrick) New: Minimal code changes to allow TestNG to work for OpenJDK tests, which should be run with only the java.base module present. Fixed: GITHUB-1047 IClassListener didn't work (Julien Herr) Fixed: GITHUB-1049 IClassListener was called many time (Julien Herr) Fixed: GITHUB-1045 TestNG swallows exceptions silently if @ClassRule is used (Gili Tzabari & Julien Herr) Fixed: GITHUB-506 TestNG cannot find JUnit method names from Spock (@blackduck-joe & Julien Herr) Fixed: GITHUB-1009 Iterator DataProvider: indices not working (Mark Fulton & Julien Herr) Fixed: GITHUB-1030 Parameterized test class crashes when data provider returns empty array (Christoffer Sawicki & Julien Herr) New: TestNG displays a warning when tests are using an empty data provider 6.9.11: 2016/03/26 Fixed: GITHUB-923 Refactored data provider's parameter values passing to a varargs or non-varargs method with @NoInjection handling (Nitin Verma) New: GITHUB-933: Deprecate XmlTest#getTestParameters (Julien Herr) Fixed: GITHUB-911: TestListener#onTestStart should be invoked if a suite configuration method fails (Harmin Parra Rueda & Julien Herr) Fixed: GITHUB-793: Test suite with tests using dependency and priority has wrong behavior (Martin Hereu & Julien Herr) Fixed: GITHUB-922: ITestResult doesn't contain name if a class has @Test (@dr29bart & Julien Herr) Fixed: GITHUB-419: parallel mode was ignored with command line (@khospodarysko & Julien Herr) New: GITHUB-932: Deprecate true/false parallel values. none is the new default value. (Julien Herr) Fixed: GITHUB-960: testng-failed.xml gets generated even when there are no failures. (Krishnan Mahadevan) Fixed: GITHUB-895: Changing status of test by setStatus of ITestResult (Raj Srivastava & Julien Herr) Fixed: GITHUB-969: testng-failed.xml does not carry over the parameters of methods from origin suite xml(Ning Zhang)  6.9.10: 2015/12/15 Fixed: GITHUB-841: testName from @Test is now used and available from ITestResult#getName() and ITestResult#getTestName() (Julien Herr) New: GITHUB-776: Add BeforeClass/AfterClass like on ITestListener (@vguna & Julien Herr) Fixed: GITHUB-872: Enable end-users of TestNG to alter XmlSuite and XmlTest (Krishnan Mahadevan) New: GITHUB-900: Support @Listeners in annotation transformer (Julien Herr) New: GITHUB-898: Activate XML validation when possible (Julien Herr) Fixed: GITHUB-889: XmlSuite in nested directories results in FIleNotFoundException (Virender Singh) Fixed: GITHUB-811: Timeout is not working with parallel=tests (@michael-yxf & Julien Herr) Fixed: GITHUB-839: Missing encoding meta data for report file (@banbq & Julien Herr) Fixed: GITHUB-876: NullPointerException creating tests with parameters by a factory (@vixgeo & Julien Herr) New: GITHUB-886: Add some checks on factory methods (Julien Herr) New: GITHUB-874 / GITHUB-875 / GITHUB-882 / GITHUB-850 : Some code cleanup (Testo Nakada) Fixed: GITHUB-866 / GITHUB-869 : Some attributes were not cloned when XmlSuite#clone was used (Virender Singh) Fixed: GITHUB-842: Add TestResult#getTestName() support for @Test(testName) (Julien Herr) Fixed: GITHUB-908: Fix Double.NaN assertion (Julien Herr) 6.9.9: 2015/10/27 Fixed: GITHUB-829: Allowing suites to have duplicate names. You can now configure the same suite-file to run multiple times. (Eduardo Born) Fixed: GITHUB-834: nested suites not supported by 'testnames' (Tibor Digana & Julien Herr) 6.9.8: 2015/10/12 Replace 6.9.7 that was build with Java8 by error. 6.9.7: No official release Fixed: GITHUB-798: Set suitethreadpoolsize for Maven Surefire (Jan Dundáček) Fixed: GITHUB-171: ISuiteListener methods called multiple times if multiple test elements (Daniel Qian & Julien Herr) Fixed: GITHUB-169: IInvokedMethodListener methods executed several times before/after each test method (Mario Duarte & Julien Herr) Fixed: GITHUB-154: MethodInterceptor will be called twice (Tim wu & Julien Herr) 6.9.6: 2015/07/15 New: GITHUB-717: Add assertThrows and expectThrows (Ryan Schmitt) Fixed: GITHUB-755: Fixed reporting of retried tests (Ryan Schmitt) Fixed: GITHUB-773: Test should not be skipped when the exception is expected (@CandyLiuM & Julien Herr) 6.9.5: 2015/07/12 Fixed: The ServiceLoaderTest on Windows (Mathieu Sebire) Fixed: GITHUB-691: Fix classloading issue when using TestNG 6.9.4 and JMockit. (Mathieu Sebire) Fixed: GITHUB-686: IAnnotationTransformer.transform is called for methods with testClass populated. (Łukasz Rekucki & Julien Herr) Fixed: GITHUB-420: Before/AfterSuite methods may not run, when use inheritance, and enabled=false (Jakub Tokaj & Julien Herr) Fixed: GITHUB-697: Make addFailedInvocationNumber thread-safe (Ryan Schmitt) Fixed: GITHUB-698: Fix exit code reporting when IRetryAnalyzer is used (Ryan Schmitt) Fixed: GITHUB-465: assertEquals(Collection, Collection) prints "null" when collections are different sizes (Michael Diamond) New: GITHUB-710: AppVeyor is used for continuous integration on Windows (Julien Herr) Fixed: GITHUB-599: IHookable ignored when a timeout is set (@ryanlevell & Julien Herr) New: GITHUB-723: Allow users to add their own suite parser (Julien Herr) Fixed: Allow '-testnames' option to work with '-xmlpathinjar' (@earthling) Fixed: GITHUB-739: TestNG skips all test classes from suite when a @BeforeClass fails (Priyanshu Shekhar & Julien Herr) Fixed: GITHUB-471: If @beforeMethod or @afterMethod fails then all children of the same base class will be skipped (Anton Panferov & Julien Herr) Fixed: GITHUB-595: testng hang at switching test cases when running test cases with high thread count (vit0rg) Eclipse: Fixed: The 57% freeze bug (Patrick Hensley and @denyska) 6.9.4: 2015/05/09 Added: GITHUB-631: Avoid the static limitation of external DataProvider. (Julien Herr) Added: GITHUB-631: Allow to use Guice injection in DataProvider. (Julien Herr) Added: Drop support of Java6 and previous. Added: GITHUB-617: Allow injection of org.testng.ITestContext into the guice parent module. (Julien Herr) Fixed: GITHUB-606: RetryAnalyzer loops endlessly. (Krishnan Mahadevan) Fixed: GITHUB-618: Start TestNG from jar cause recursive run of tests from packages in Suite XML without ".*" on the end (Stas Gromov) Fixed: GITHUB-639: Typo on preserveOrder (tabei-k & Julien Herr) Fixed: GITHUB-632: Typo in doc (Pétur Ingi Egilsson & Julien Herr) Fixed: GITHUB-629: InvokedMethod doesn't recognize configuration method (Jan Mewes & Julien Herr) Fixed: GITHUB-615: XmlSuite, XmlTest: Time-out tag not preserved (jphollingworth & Julien Herr) New: GITHUB-638: Travis CI is used for continuous integration (Julien Herr) New: GITHUB-647: SonarQube is used to follow technical debt (Julien Herr) Added: GITHUB-616: org.testng.internal.Version will be always up-to-date (Julien Herr) Fixed: GITHUB-634: Review of the collections package (Julien Herr) Fixed: GITHUB-624: Fixed failure/error inversion in JUnitReportReporter (Jerome Jacob) Fixed: GITHUB-545: TestNG running JUnit tests but not reporting all results for parameterized tests (Jonathan Leitschuh & jdillet) Fixed: GITHUB-610: CustomizedSuites must be saved using utf-8 encoding (Juha Heljoranta) Fixed: GITHUB-602: NoClassDefFoundError in TestNGClassFinder. (aanno) Fixed: GITHUB-529: Close InputStream and OuputStream after use (Andrew Gaul) Fixed: GITHUB-532: Create the parent directory if it's missing (Ion Savin) Fixed: GITHUB-541: Some OSGi manifest fixes (Evgeny Zhuravlev) Fixed: GITHUB-657: Fix OSGI Import-Package to make jUnit4 dependency optional (Xavier Fournet) Fixed: GITHUB-523: externally synchronize our use of the static SimpleDateFormat (mcosby) Fixed: GITHUB-477: Typo in DTD attribute comment (Kamil Szymański) Fixed: GITHUB-353: Typo in documentation (Jan Święcki) Fixed: GITHUB-656: Upgrade to JCommander 1.48 (Ryan Schmitt) Fixed: GITHUB-582: TestNG tests don't pass reliably on JDK8 (Ryan Schmitt) New: GITHUB-645: TestNG project on Google Code redirect to GitHub Fixed: GITHUB-310: Upgrade Guice (kronar & Julien Herr) Fixed: GITHUB-87: @BeforeSuite/@BeforeTest methods happens to be disabled by mistake (romlom & Julien Herr) Fixed: GITHUB-425: Wrong invocation order with lastTimeOnly (Rafael Winterhalter & Julien Herr) Fixed: GITHUB-417: Expected Exceptions Message fails to match multi-line messages (Michael Diamond) New: GITHUB-663: Add Guice Stage configuration for a suite (Clément Guillaume) 6.8.21: 2015/02/02 6.8.15: 2015/01/14 Fixed: OutOfMemoryException while generating reports. Fixed: GITHUB-566: Build does not fail when successPercentage for @Test is not met Fixed: XmlTest#setGroupInstances was not being shown in toXml(). Fixed: GITHUB-376: Some results can be lost (Konstantin Savin). Fixed: Handle relative paths of Suite XML files properly (Nalin Makar) 6.8.5: 2013/05/13 Fixed: the OutOfMemoryException in reports Fixed: Surefire + listeners "Can't load class" problem =========================================================================== 6.8.1 2013/03/30 Added: Descriptions in the HTML reports Added: Various improvements to EmailableReporter (Abraham Lin) Added: Allow injection of java.lang.reflect.Constructor and org.testng.ITestNGMethod into DataProvide (Vladislav Rassokhin) Fixed: Assertions in the Assertions class were not failing properly. Fixed: GITHUB-337: ConfigurationMethod#m_instance set to Boolean.FALSE due to incorrect constructor call in clone() + auto-boxing (davidely) Fixed: Fix NPE for dependency methods/groups (Krishnan Mahadevan) Fixed: preserve-order bug (found by VladSarrokhin). Fixed: GITHUB-300: OutOfMemoryException from reporters when there are a lot of tests Fixed: GITHUB-137: Main parameters with a default value should be overridden if a main parameter is specified Fixed: GITHUB-107: Allow enum values without converting them to uppercase. Fixed: @Guice with no modules specified is now supported Fixed: Reporter.log() invoked from listeners were being discarded Eclipse: Added: Predefined listeners (Tim Wu) Fixed: Compare dialog =========================================================================== 6.7 2012/07/15 Added: Big performance improvement when generating the reports (Frank Pavageau) Added: allows you to specify group dependencies in testng.xml Added: Blow up early if trying to include/exclude an unknown method Added: can now be specified under (Storm Qi) Added: GITHUB-243: Add Reporter Output per Test in XMLReporter (dunse) Fixed: Better HTML escaping of the stack traces Fixed: The failed assertions now use [] as delimiters instead of <> (better for the HTML reports) Fixed: GITHUB-237: Wrong time format in XML reporter Fixed: Threads were started sequentially instead of being interleaved Fixed: dataProvider(parallel = true) was not killing its threads properly Fixed: XmlSuite#toXml wasn't outputting the tag correctly Fixed: testng-failed.xml was not carrying over the parameters from the original testng.xml Fixed: BeforeClass failing in parent failed to skip methods in sub classes Fixed: Better error message if is missing Fixed: GITHUB-221: Honor excludeGroups on testng tests when run in mixed mode (criccio) Fixed: dependsOnGroups = {regexp} wasn't working properly (Alistair Ward) Fixed: GITHUB-205: white-space was spelled whitespace in testng.css (carlin-scott) Eclipse: Fixed: Environment is not transferred when rerunning failed tests. Fixed: Rerunning failed tests will preserve the environment of the original launch =========================================================================== 6.5.1 04/10/2012 Added: (and in as well) Added: data-provider attribute to testng-results.xml Added: Reporter display the results in the same order as test methods (Libor Zoubek) Added: Support for running JUnit 4 tests (Lukas Jungmann) Added: Ability to auto-detect JUnit tests ('-mixed' mode) (Lukas Jungmann) Added: Support for ResourceCollections in an Ant tasks (requires Ant >= 1.7.0) (Lukas Jungmann) Fixed: GITHUB-198: JUnitReportsReporter use commas in certain locales, which JUnitReports doesn't like Fixed: GITHUB-173: Dependent methods executed out-of-order if method names match across classes (jjedMoriAnktah) Fixed: ThreadLocal leak (aslakknutsen) Fixed: In the HTML reports, only show the first 100 characters of the parameters Fixed: SkippedException are considered as real exception with @Test(expectedExceptions) Eclipse: Fixed: Java constants are properly resolved if they are used as group names (susanin) Fixed: @Test(groups = Foo.CONSTANT) (susanin) Fixed: Failed tests with allow-return-values="true" were not rerun Added: (and in as well) =========================================================================== 6.4: 02/15/2012 Added: @DataProvider(indices) to return specific indices of a data provider Added: New HTML reports Added: configfailurepolicy=continue with DataProviders (toddq) Added: ITestResult#getTestContext (bpedman) Fixed: invocationCount > 1 + timeOut wasn't timing out properly Fixed: When running TestNG programmatically, child xml suites are not run (when added using setSuiteFIles()) (Gaurav Gupta) Fixed: GITHUB-145: Excessive test method execution (githubCast) Fixed: GITHUB-149: reversed arguments in failAssertEqualsNoOrder(). Fixed: EmailableReporter: methods are now *really* sorted chronologically. Eclipse: Added: You can now add the testng.jar sources as a library (Nick Tan) Added: Upgraded the plug-in to 3.4+ (Nick Tan) Added: dependsOnGroups now fully supported Fixed: @Parameters now works with both ("foo") and ({"foo"}) (davekerber) =========================================================================== 6.3.1 10/22/2011 Added: New system property: dataproviderthreadcount (Bill Ross) Fixed: Configuration methods were reported incorrectly in listeners. Fixed: Was creating too many listeners (Jacek Pulut) Fixed: IAnnotationTransformer2 beforeTest/afterTest booleans were not being set Fixed: GITHUB-92: @BeforeTest method in a super class will be called multiple time when alwayRun = true (Bubuntux) Fixed: GITHUB-111: @AfterClass on base classes run once too many (lrivera) Fixed: GITHUB-107: Displaying 0 tests run if a listener modifies the parameters of the suite =========================================================================== 6.3 10/17/2011 Added: "description" attribute on , made available on ITestNGMethod#getDescription Added: RemoteTestNG waits infinitely for a connection (Aleksey Kabanov) Fixed: A method that's both a test and a factory would not invoke its data provider Fixed: @AfterClass was not called if one of the methods was not enabled (Aleksey Kabanov) Fixed: Groovy access bug Fixed: The XML parser doesn't recognize parallel="instances" Fixed: NPE when using inner classes Fixed: GITHUB-90: @AfterClass not being run when the class contains included and not included methods Fixed: @AfterClass not being run in some subclassing situations Eclipse: Fixed: Verbose levels specified in suites not respected Fixed: Variable substitution in VM arguments is not working properly (svenhoff) =========================================================================== 6.2 08/18/2011 Added: xmlpathinjar to the TestNG ant task Added: TestNG can now invoke package protected constructors Added: Injectors created by the @Guice annotation are now shared at the level Added: IConfigurationListener is now a public listener, along with a new one: IConfigurationListener2 Added: When a method fails, only dependents of the same instance will be skipped Added: parallel=instances for factory instance parallel runs Added: @Factory(enabled) Fixed: JUnitReports reports now report the cumulated time @{Before,After}Method+@Test for each test method Fixed: JUnitReports reports have the name of the instead of that of the first class Fixed: Using preserve-order with a factory that creates instances of a different class causes NPE Fixed: GITHUB-74: Bad ordering of test methods when using a @Factory constructor with dataProvider Fixed: Changing the test result from success to failure in a listener would still count the test as a success Fixed: ServiceLoader wasn't resolving correctly if no service loader classloader was specified Fixed: Better ordering with mixed priorities and dependencies Fixed: Improved detection of graph cycles in parallel runs Fixed: @BeforeTest was invoked multiple times if a factory is used Fixed: GITHUB-57: Allow usage of package protected constructor of test classes Fixed: Injecting both Object[] and Method in @BeforeMethod didn't always work Fixed: testng-results.xml now lists the results chronologically Fixed: @Listeners specified on a base class will only be run once per listener class (dbriones) Fixed: -groups and -excludegroups were no longer overriding testng.xml Eclipse: Added: Each data provider method now has a separate node entry in the TestNG view Fixed: Nodes in error would sometimes remain green Fixed: The TestNG context menu no longer appears where it shouldn't =========================================================================== 6.1.1 7/5/2011 Fixed: https://github.com/cbeust/testng/issues/56 testng-results.xml was reporting the instance name instead of the method name Fixed: NPE when using preserve-order and factories. Fixed: Depending on a skipped method would not cause a method to be skipped =========================================================================== 6.1 6/30/2011 Possible backward incompatible changes: - Don't mutate the value returned by XmlTest#getIncludedGroups and XmlTest#getExcludedGroups. Instead, use addIncludedGroup/addExcludedGroup. - Failing methods that have dependees will only cause skips in the same instance. Different test instances will not be affected Added: Support for ServiceLoader for ITestNGListener Added: @Factory(dataProvider / dataProviderClass) on constructors Added: assertNotEquals() to Assert Added: assertArrayEquals() to AssertJUnit Added: Nested classes are now automatically added for consideration for inclusion Added: will cause this attribute to be propagated to all tags Added: can now be specified under a Added: Tycho compatibility (Aleksander Pohl) Added: New and flag: group-by-instances Added: -xmlpathinjar to specify the path of testng.xml inside a test jar file Added: ISuite#getAllMethods, to retrieve all the methods at the start of a suite. Added: Output ITestResult attributes in xml report (nguillaumin) Fixed: Thread safety problem in MethodInvocationHelper (Baron Roberts) Fixed: Group dependencies were not being skipped properly. Fixed: Dependency failures only impact the same instance Fixed: Static classes could cause a StackOverFlowError Fixed: IConfigurationListener was not extending ITestNGListener Fixed: IConfigurationListener#onConfigurationFailure was never called Fixed: TESTNG-476: tags are now run in the order found in testng.xml Fixed: Now showing failed/skipped error messages on the console for verbose >= 2 Fixed: ITestResult#getEndMillis() return 0 Fixed: TESTNG-410: Clearer error message Fixed: TESTNG-475: @DataProvider doesn't support varargs Fixed: Performance problems in EmailableReporter Fixed: TESTNG-472: Better output for assertNull() Fixed: ConcurrentModificationException when using parallel data providers. Fixed: TESTNG-282: Problem when including+excluding packages (addicted) Fixed: TESTNG-471: assertEquals(Map, Map) fails if a map is a subset of the other Fixed: JUnitReporter generates an tag for successful expectedExceptions tests Fixed: ISSUE-47: Don't allow two s with same name within same suite (Nalin Makar) Fixed: If a listener implements both ISuiteListener and IInvokedMethodListener, only one of them gets invoked Eclipse: Added: New quick fix "Add static import org.testng.AssertJUnit.assertXXX" Added: New workspace wide setting: excluded stack traces, to provide shorter stack traces in the view Added: New "Clear results" icon in the tool bar Added: When the search filter is modified, don't update the tree live if it is too big Added: Two new @Test refactorings (pull to class level, push to method level) Added: JUnit conversion: @Ignore Added: JUnit conversion: assertArrayEquals() Added: JUnit conversion: @RunWith(Parameterized.class) Added: Support for Hamcrest failed assertions in the compare dialog Added: JUnit conversion: suite() methods can now either be removed, commented out or left untouched Fixed: JUnit conversion: super.setUp()/tearDown() were being removed when extending a class other than TestCase Fixed: "Run as" menu not appearing for methods that take a generic parameter. Fixed: The tree was incorrect if the same class is used in different tags Fixed: When creating a new Run/Debug configuration, "Launch.label" was displayed Fixed: TESTNG-459: TestNG menu should not always be present in context menu (Mykola Nikishov) Fixed: Performance problems in the plug-in Fixed: Workspace-wide XML template files are not being honored. Fixed: @BeforeClass/@AfterClass from JUnit4 are not being properly converted Fixed: Conversions generate @Test() instead of @Test =========================================================================== 6.0 2011/03/16 Added: @Guice(moduleFactory) and IModuleFactory Added: @Guice(module) Added: timeOut for configuration methods Added: -randomizesuites (Nalin Makar) Added: IConfigurable Fixed: @Test(priority) was not being honored in parallel mode Fixed: @Test(timeOut) was causing threadPoolSize to be ignored Fixed: TESTNG-468: Listeners defined in suite XML file are ignored (Michael Benz) Fixed: TESTNG-465: Guice modules are bound individually to an injector meaning that multiple modules can't be effectively used (Danny Thomas) Fixed: Method selectors from suites were not properly initialized (toddq) Fixed: Throw an error when two data providers have the same name Fixed: Better handling of classes that don't have any TestNG annotations Fixed: XmlTest#toXml wasn't displaying the thread-count attribute Fixed: TESTNG-438: Regression in 5.14.1: JUnit Test Execution no longer working Fixed: TESTNG-436: Deep Map comparison for assertEquals() (Nikolay Metchev) Fixed: Skipped tests were not always counted. Fixed: test listeners that throw were not reporting correctly (ansgarkonermann) Fixed: wasn't working. Fixed: In parallel "methods" mode, method interceptors that remove methods would cause a lock up Fixed: EmailableReporter now sorts methods chronologically Fixed: TESTNG-411: Throw exception on mismatch of parameter values (via DP and/or Inject) and test parameters Fixed: IDEA-59073: exceptions that don't match don't have stack trace printed in console (Anna Kozlova) Fixed: IDEA's plug-in was not honoring ITest (fixed in TestResultMessage) Fixed: Methods depending on a group they belong were skipped instead of throwing a cycle exception Fixed: TESTNG-401: ClassCastException when using a listener from Maven Fixed: TESTNG-186: Rename IWorkerApadter to IWorkerAdapter (Tomas Pollak) Fixed: TESTNG-415: Assert.assertEquals() for sets and maps fails with 'null' as arguments Fixed: typo -testRunFactory Fixed: NPE while printing results for an empty suite (Nalin Makar) Fixed: Invoke IInvokedMethodListener.afterInvocation after fixing results for tests expecting exceptions (Nalin Makar) Fixed: TESTNG-441: NPE in SuiteHTMLReporter#generateMethodsChronologically caused by a race condition (Slawomir Ginter) Eclipse: Added: Convert to YAML Added: New global preference: JVM args Added: Eclipse can now monitor a test-output/ directory and update the view when a new result is created Added: Right clicking on a class/package/project now offers a menu "TestNG/Convert to TestNG" Added: Excluded methods are now listed in the Summary tab Added: "Description" column in the excluded methods table Added: Dialog box when the plug-in can't contact RemoteTestNG Added: Double clicking on an excluded method in the Summary tab will take you to its definition Added: If you select a package before invoking the "New TestNG class" wizard, the source and package text boxes will be auto-filled Added: When an item is selected in a tab, the same item will be selected when switching tabs Added: A new "Summary" tab that allows the user to see a summary of the tests, sort them by time, name, etc... Added: It's now possible "Run/Debug As" with a right click from pretty much any element that makes sense in the tree. Added: JUnit conversion: correctly replaces assertNull and assertNotNull Added: JUnit conversion: removes super.setUp() and super.tearDown() Added: JUnit conversion: removes @Override Added: JUnit conversion: replaces @Test(timeout) with @Test(timeOut) (5.14.2.4) Added: JUnit conversion: replaces @Test(expected) with @Test(expectedExceptions) (5.14.2.4) Added: JUnit conversion: replaces fail() with AssertJUnit.fail() (5.14.2.2) Added: JUnit conversion: replaces Assert with AssertJUnit (5.14.2.1) Added: The progress bar is now orange if the suite contained skipped tests and no failures Added: Skipped test and suite icons are now orange (previously: blue) Added: New method shortcuts: "Alt+Shift+X N", "Alt+Shift+D N" (Sven Johansson) Added: "Create TestNG class" context menu Added: When generating a new class, handle overridden methods by generating mangled test method names Fixed: Green nodes could override red parent nodes back to green Fixed: Was trying to load the classes found in the XML template file Fixed: Stack traces of skipped tests were not showing in the Exception view Fixed: XML files should be run in place and not copied. Fixed: NPE when you select a passed test and click on the Compare Result icon (Mohamed Mansour) Fixed: When the run is over, the plug-in will no longer force the focus back to the Console view Fixed: The counter in the progress bar sometimes went over the total number of test methods (5.14.2.9) Fixed: org.eclipse.ui.internal.ErrorViewPart cannot be cast to org.testng.eclipse.ui.TestRunnerViewPart (5.14.2.9) Fixed: Workspace preferences now offer the "XML template" option as well as the project specific preferences (Asiel Brumfield) Fixed: TESTNG-418: Only last suite-file in testng.xml run by Eclipse plugin Documentation: Added: Section on Selenium (Felipe Knorr Kuhn) Added: Link to an article on TestNG, Mockito and Emma in the Misc section =========================================================================== 5.14.7 2011/01/27 Release for IDEA =========================================================================== 5.14.1 2010/10/2 Fixed: TESTNG-401: ClassCastException when using a listener from Maven =========================================================================== 5.14 2010/08/28 Added: test suites can now be run in parallel with -suitethreadpoolsize Fixed: @Listeners now aggregate through base classes Fixed: ISuite was no longer serializable Fixed: Injection was sometimes not working properly when used with @Parameters Fixed: TESTNG-400: afterMethod was called after onTestFailure() Fixed: "excludedgroups" was not working on the ant task because of a typo Fixed: ant task error if is used with no classes (welex91) Fixed: TESTNG-404: threaded tests fail due to use of non-threadsafe collections (Marcus Better) Fixed: preserve-order was not preserving class order with dependent methods Fixed: RetryAnalyzer wasn't working properly with factories Fixed: The ant task was no longer supporting ',' for testclass Eclipse: Fixed: The plug-in wasn't running Groovy tests correctly (Andrew Eisenberg) Fixed: TESTNG-402 [Eclipse Plug-In] NPE occurred when I run twice a custom "Run configuration" on a group =========================================================================== 5.13.1 2010/08/05 Added: -methods Added: -configfailurepolicy (Todd Quessenberry) Added: -methodselectors (Todd Quessenberry) Added: @NoInjection Added: Added: -testnames (command line) and testnames (ant) Added: New ant task tag: propertyset (Todd Wells) Added: ITestNGListenerFactory Added: Passing command line properties via the ant task and doc update (Todd Wells) Added: Hierarchical XmlSuites (Nalin Makar) Added: Reporter#clear() Fixed: NullPointerException when a suite produces no results (Cefn Hoile) Fixed: Identical configuration methods were not always invoked in the correct order in superclasses (Nalin Makar) Fixed: @DataProvider(parallel = true) was passing incorrect parameters with injection Fixed: Replaced @Test(sequential) with @Test(singleThreaded) Fixed: If inherited configuration methods had defined deps, they could be invoked in incorrect order (Nalin Makar) Fixed: Initialize all Suite/Test runners at beginning to catch configuration issues right at start (Nalin Makar) Fixed: Issue7: Issue86 Incorrect dates reported for configuration methods Fixed: Issue24: OOM errors in SuiteHTMLReporter (Nalin Makar) Fixed: Time outs specified in XML were not honored for Fixed: and time outs were hardcoded, they now honor their time-out attribute Fixed: TestNG was hanging if no test methods were found Fixed: onTestSuccess() was called after @AfterMethod instead of after the test method (test: test.listener.ListenerTest) Fixed: XML test results contained skipfailedinvocationCounts instead of skipfailedinvocationcounts Fixed: Issue4 assertEquals for primitive arrays, Issue34 assertNull javadoc updated Fixed: Issue78 NPE with non-public class. Now throws TestNG exception Fixed: NPE with @Optional null parameters (Yves Dessertine) Fixed: TESTNG-387 TestNG not rerunning test method with the right data set from Data Provider (Francois Reynaud) Fixed: Show correct number of pass/failed numbers for tests using @DataProvider Fixed: Return correct method status and exception (if any) in InvokedMethodListener.afterInvocation() Fixed: Trivial fixes: TESTNG-241 (log message at Info), Issue2 (throw SAXException and not NPE for invalid testng xml) Fixed: Configuration methods couldn't depend on an abstract method (Nalin Makar) Fixed: TestNG#setTestClasses was not resetting m_suites Fixed: Exceptions thrown by IInvokedMethodListeners were not caught (Nalin Makar) Fixed: @Listeners now works on base classes as well Fixed: Test priorities were not working properly in non-parallel mode Fixed: @Listeners wasn't working properly with ITestListener Eclipse Fixed: TESTNG-395 New wizard was creating classes called "NewTest" Fixed: TESTNG-397 Class level @Test was preventing groups from showing up in the launch configuration Doc Updated Maven documentation (Brett Porter) =========================================================================== 5.12.1 2010/03/29 Maven update =========================================================================== 5.12 Removed: Javadoc annotation support Added: @Listeners Added: IAttributes#getAttributeNames and IAttributes#removeAttribute Added: testng-results.xml now includes test duration in the tag (Cosmin Marginean) Added: Injection now works for data providers Added: TestNG#setObjectFactory(IObjectFactory) Added: Priorities: @Test(priority = -1) Added: New attribute invocation-numbers in Added: testng-failed.xml only contains the data provider invocations that failed Added: IInvokedMethodListener2 to have access to ITestContext in listeners (Karthik Krishnan) Fixed: @Before methods run from factories were not properly interleaved Fixed: The TextReporter reports skipped tests as PASSED (Ankur Agrawal) Eclipse: Added: New file wizard: can now create a class with annotations, including @DataProvider Added: You can now select multiple XML suites to be run in the launch dialog Fixed: @Test(groups = ) was taking name of the constant instead of its value. Fixed: http://jira.codehaus.org/browse/GRECLIPSE-476 NPE with Groovy Tests (Andrew Eisenberg) Fixed: The custom XML file is now created in the temp directory instead of inside the project Fixed: In the launch dialog, now display an error if trying to pick groups when no project is selected Fixed: Was not setting the parallel attribute correctly on the temporary XML file =========================================================================== 5.11 2009/12/08 Added: Dependent methods can now run in their own thread Added: dataProviderThreadCount can be set from the command line and from ant (Adrian Grealish) Added: ITestAnnotation#setDataProvider Added: Assert#assertEquals() methods for Sets and Maps Fixed: The text reporter was no longer reporting stack traces for verbose >= 2 Fixed: dataProviderClass was not respecting inheritance (like most attributes still) Fixed: @BeforeSuite/@AfterSuite would run multiple times when used in a @Factory Fixed: packages=".*" wasn't working properly (sandopolus) Fixed: TestResult#getName now returns the description instead of the method Fixed: @DataProvider and dependent methods were not skipping correctly (Francois Reynaud) Fixed: TESTNG-347 suite with parallel="tests" and test with parallel="classes" doesn't work correctly (Rob Allen) Fixed: TESTNG-67: @Configuration/@Factory methods in base class being ignored Fixed: Inner test classes were not excluded properly (Carsten Gubernator) Fixed: threadPoolSize without invocationCount was causing reporters not to be invoked Fixed: A @Factory throwing an exception did not cause any error Fixed: was not working properly in the ant task (Ed Randall) Fixed: @BeforeClass methods were not running in parallel (Aidan Short) Fixed: Test class with @ObjectFactory doesn't get instantiated via the factory Fixed: Allow IObjectFactory to load from non-standard classloader (for PowerMock support) Eclipse 5.11.0.19: Added: New "parallel" preference setting (Windows / Preferences / TestNG) Fixed: IIinvokedMethodListeners were not invoked =========================================================================== 5.10 Added: The output in the testng-results.xml is now sorted by the starting timestamp (Daniel Rudman) Added: Better display of the test name and method description in the default and Emailable report Added: If both -testjar and an XML file are provided on the command line, the latter will be used Added: @Before and @After methods can be injected with the current XmlTest Added: Methods that time out now display the stack trace showing where the time out occurred Added: ITestResult#getAttribute and ITestResult#setAttribute Added: @After methods can now be injected with an ITestResult Added: @BeforeMethod and @AfterMethod methods can now be injected an ITestResult Added: ISuite#getAttribute and ISuite#setAttribute to share data within a suite Added: @Test(expectedExceptionsMessageRegExp = ".*foo.*") Added: @DataProvider(parallel=true) Fixed: @Test(dataProvider) was not working at the class level Fixed: Display a better error message if the wrong exception is thrown with an expectedExceptions Fixed: Classes created by factories were not run in the order they were created Fixed: Dependent methods are now run closer to methods within their class Fixed: xmlFileSet in ant was not working correctly (Sean Shou) Fixed: Various oversights in the DTD (Will McQueen) Fixed: XMLUtils was not escaping XML attribute values Fixed: TESTNG-317: Sequence order mis-calculation: testing using suite in sequence for classes and same method names creates non-sequential order Fixed: Test names (classes that implement org.testng.ITest) now appear more prominently in the HTML reports Fixed: expectedExceptions=RuntimeException.class was not failing when no exception was throw Fixed: TESTNG-291: Exceptions thrown by Iterable DataProviders are not caught, no failed test reported (Roberto Tyley) Fixed: TESTNG-301: Need to include parameters in testNG report for test created by @Factory Fixed: testng-failed.xml now includes skipped tests Fixed: TestNG couldn't find Groovy files (Haw-Bin) Eclipse Fixed: TESTNG-313: Provide extension point to contribute test and report listeners (Erik Putrycz) Fixed: Quick fixes no longer introduce deprecated annotations (Greg Turnquist) =========================================================================== 5.9 2009/04/09 Added: New ant task boolean flag: delegateCommandSystemProperties (Justin) Added: skipfailedinvocations under in testng-1.0.dtd (Gael Marziou / Stevo Slavic) Added: -testrunfactory on the command line and in the ant task (Vitalyi Pamajonkov) Added: TESTNG-298: parallel="classes", which allows entire classes to be run in the same thread Added: @BeforeMethod can now declare Object[] as a parameter, which will be filled by the parameters of the test method Added: IAnnotationTransformer2 Added: @Test(invocationTimeOut), which lets you set a time out for the total time taken by invocationCount Added: IInvokedMethodListener Added: -testjar supports jar file with no testng.xml file Fixed: IInvokedMethodListener wasn't properly recognized from the command line (Leonardo Rafaeli) Fixed: TESTNG-309 Illegal default value for attribute in DTD file Fixed: TESTNG-192: JUnit XML output includes wrong tests (Aleksandar Borojevic) Fixed: Set a generated suite to default to non-parallel (Mark Derricutt) Fixed: -testJar command line parsing bug Fixed: testng-failed.xml didn't include the listeners Fixed: annotation transformers were not run when specified in testng.xml Fixed: TESTNG-192: JUnit XML output includes wrong tests (Borojevic) Fixed: @Parameters was not working correctly on @BeforeMethods with @DataProvider used on @Test methods Fixed: testng-failed.xml was sometimes incorrectly generated (Borojevic) Fixed: TestNG-228: Assert.assertEqualsNoOrder Fixed: TestNG-229: Assert.assertEquals does not behave properly when arguments are sets Fixed: TESTNG-36: assertEquals(Collection actual, Collection expected, String message) may have bug Fixed: TESTNG-296: Malformed jar URLs breaking -testJar Fixed: TESTNG-297: TestNG seemingly never stops running while building failed test suite (Gregg Yost) Fixed: TESTNG-285: @Test(sequential=true) works incorrectly for classes with inheritance Fixed: TESTNG-254: XMLSuite toXML() ignores listeners Fixed: TESTNG-276: Thread safety problem in Reporter class Fixed: TESTNG-277: Make Reporter.getCurrentTestResult() public Fixed: Potential NPE in XmlTest#getVerbose (Ryan Morgan) Fixed: EmailableReporter only displayed the first group for each test method Fixed: time-outs were not working in and Fixed: @BeforeTest failing in a base class would not cause subsequent test methods to be skipped Fixed: TESTNG-195: @AfterMethod has no way of knowing if the current test failed Fixed: TESTNG-249: Overridden test methods were shadowing each other if specified with Fixed: DataProviders from @Factory-created tests were all invoked from the same instance Fixed: enabled was not working on configuration methods Fixed: IIinvokedMethodListener was not correctly added in TestNG Fixed: NPE in XmlSuite#toXml Fixed: TESTNG-231: NullPointerException thrown converting a suite to XML (Mark) Doc: Added: 5.20: IInvokedMethodListener Added: -testjar =========================================================================== 5.8 Fixed: TestNG-220: Ignore class definition/loader issues when scanning classpath for implicit classes Fixed: TestNG-224: Fix for relative suite filenames in XML file Added: TestNG-213: @Optional on a method parameter to allow optional @Parameters Fixed: TestNG-214: SkipException and TimeBombSkipException should accept nested exceptions Fixed: TestNG-211: new Parser(inputStream) doesn't work Added: Methods that form a cycle are now shown when the cycle is detected Added: Support for in testng.xml Added: IMethodInterceptor Added: @TestInstance on a data provider method parameter Fixed: @AfterMethod(lastTimeOnly) didn't work properly with data providers Added: antlib.xml to allow autodiscovery of Ant task definition Fixed: name attribute on is required Doc: Added: Method Interceptor Added: @Optional Added: Doc for IMethodInterceptor (5.16) and TestNG listeners (5.18) Added: 5.19: Dependency injection =========================================================================== 5.7 Added: @BeforeMethod(firstTimeOnly) and @AfterMethod(lastTimeOnly) Added: @BeforeMethods can now take a Method and ITestContext parameters (like @DataProvider) Fixed: logging about abstract classes moved to level 5 Added: if @Parameter is missing from testng.xml then it is read from the System properties Fixed: Don't run a @DataProvider method as a test when a class-level @Test is present Added: Attribute @Test#skipFailedInvocations Fixed: TESTNG-169 Error message: is depending on nonexistent method null ("null" is uninformative) Fixed: -listener takes comma-separated classes Added: RetryAnalyzer (experimental) (Jeremie) =========================================================================== 5.6 2007/06/14 Added: SkipException/TimeBombedSkipException for manual skipping Added: can now be disabled at xml level using Added: Suite files that only contain other suites do not get reported Fixed: @BeforeClass methods would incorrectly report cyclic graphs Added: get/setAttribute to ITestContext Added: plugging in factory objects to handle the actual instantiation of tests Added: dataProvider to @Factory Added: ISuite now gives access to the current XmlSuite Fixed: TESTNG-139 dependsOnMethods gets confused when dependency is "protected" Fixed: TESTNG-141 junit attribute set to false in testng-failed.xml when it should be true Fixed: TESTNG-142 Exceptions in DataProvider are not reported as failed test Added: Improved behavior for @Before/@AfterClass when using @Factory (http://forums.opensymphony.com/thread.jspa?threadID=6594&messageID=122294#122294) Added: Support for concurrent execution for invocationCount=1 threadPoolSize>1 and @DataProvider (http://forums.opensymphony.com/thread.jspa?threadID=64738&tstart=0) Added: New TestNG specific XML report, generated by default in 'xml' subdirectory of test-output Added: support in strprotocol for passing the ITest.getTestName() information Fixed: TESTNG-152 If DataProvider is not found, the exception message should tell exactly what happened Eclipse plug-in Fixed: Bug that made group launch configurations unusable Fixed: The plugin doesn't create the correct launch configuration for @Factory Fixed: Method based launchers cannot be editted Fixed: Plugin hangs while executing test with dataprovider that sends \n, \r messages Added: display ITest.getTestName() IDEA plug-in Fixed: IDEA 7.0 compatibility Fixed: occasional 'illegal arguments exception' Fixed: TESTNG-151 Final passing test result is not properly hidden Added: Auto-completion for dependsOnMethods Added: Highlighting of invalid groups/methods in dependsOn* =========================================================================== 5.5 2007/01/25 Fixed: @BeforeGroup methods were run twice when in a base class Fixed: @BeforeGroup methods were run twice with a @Test at class level Fixed: parallel="tests" didn't work as advertised Added: Support for thread-count at test level Added: Method selectors receive a Context and can stop the chain with setStopped() Fixed: XmlMethodSelector was always run first regardless of its priority Added: @BeforeGroups/@AfterGroups can live in classes without @Test methods Added: DataProvider can now take an ITestContext parameter Fixed: Wasn't parsing correctly Fixed: Annotation Transformers now work on class-level annotations Fixed: Some class-level @Test attributes were not always honored Added: Clean separation between @Test invocation events and @Configuration invocation events (see also TESTNG-111) Added: Test instances created by @Factory now run in multiple threads in parallel mode Fixed: @Before/@AfterGroups invocation order Fixed: TESTNG-27: Parameters are not used on level anymore Fixed: TESTNG-107 don't create an output directory if "outputDirectory" is null Fixed: TESTNG-127 UseDefaultListeners in Ant Task does not work Fixed: TESTNG-119 Running TestNG runner with invalid '-sourcedir' on JDK14 JavaDoc annotated test classes won't fail. Fixed: TESTNG-113 Dependent methods within the same static inner class are not found Fixed: TESTNG-125 TestNG failed for test classes under *.java*.* pakages Eclipse plug-in Fixed: issue with launch configuration Fixed: TESTNG-124: setting location of testng reports output =========================================================================== 5.4 Fixed: Ant task issue with paths containing spaces Added: for @BeforeGroups and @AfterGroups specifying the groups() attribute will auto-include the method into those groups by default (previously you had to also provide the value() attribute). Added: the load @Tests (invocationCount + threadPoolSize) are triggered simultaneous Fixed: reports are correctly displaying the thread info Added: @DataProvider name defaults to method name Added: support for remote protocol to pass parameter information Fixed: TextReporter logs information about the parameters of the test methods Fixed: concurrency issue in JUnitXMLReporter Fixed: output of JUnitXMLReporter must be CDATA Fixed: XML unsupported annotations/parallel attribute values are reported Eclipse plug-in Fixed: groups with multi-attribute javadoc annotations Fixed: consistent behavior for dependsOnMethods Fixed: consistent behavior for tests with dependsOnGroups (a warning is emitted) Fixed: consistent merge of configuration arguments when an existing launch configuration exists =========================================================================== 5.3 2006/10/30 Fixed: use a single instance of bsh.Interpreter Added: @Before/@AfterMethod can declare a java.lang.reflect.Method parameter to be informed about the @Test method Fixed: super classes must not be listed in testng-failures.xml Fixed: parallel attribute must not appear if empty or null in testng-failures.xml Fixed: parsing for javadoc annotations is done on request only Added: improved multiple suite summary page report Added: -target option deprecated in favor of -annotations javadoc|jdk Fixed: filesets in the ant task didn't work if the paths have spaces in them Fixed: Before/After Suite were behaving wrong in parallel execution Added: A generic/extensible RemoteTestNG was added to the core Fixed: Before/AfterGroup-s were behaving wrong when using invocationCount, dataProvider and threadPoolSize Fixed: improved support for running different annotation type tests in the same suite Fixed: testng-failed.xml was generated even if there were no failures/skipps Fixed: -usedefaultlisteners was wrongly passed to JVM instead of TestNG options Added: Attribute dataProviderClass for @Test and @testng.test Fixed: Forgot to account for cases where both invocationCount and DataProviders are present Fixed: AfterGroups were invoked out of order with invocationCount and DataProviders Fixed: Reporter.getOutput() returned an empty array if a timeOut was specified Added: testng.xml now supports Added: ant task can receive several listeners Fixed: TESTNG-109 Skipped tests with expected exceptions are reported as failures Added: ant task can now select the parallel mode for running tests Fixed: ant task correctly deals with empty groups and excludedgroups parameters Added: ant task can override default suite and test names Added: comand line support for setting parallel mode, suite and test names Eclipse plug-in Added: Support for configuring per project usedefaultlisteners Added: Contextual drop-down menu on failures tab of the TestNG view to enable running/debugging method failure only Added: Suppport for configuring per project TestNG jar usage (project provided one or plugin provided one) =========================================================================== 5.2 Added: "-usedefaultlisteners true/false" to command line and ant Added: EmailableReporter (from Paul Mendelson) Added: parallel can now be "methods" or "tests". Boolean version deprecated Added: TestNGAntTask now uses the @ syntax to invoke TestNG Added: Command line understands @ syntax Added: JUnitConverter uses the new syntax Added: -groups to JUnitConverter Fixed: Throw proper exception when a DataProvider declares parameters Added: completely revamped JUnit support (should run all kind of JUnit tests) Fixed: TESTNG-40 (Bug in testng-failed.xml generation) Fixed: TESTNG-106 (Failed "@BeforeSuite" method just skipps the last test in xml-file) Fixed: Success on 0 tests (http://forums.opensymphony.com/thread.jspa?threadID=41213) Eclipse plug-in Added: TESTNG-105 Automaticaly define TESTNG_HOME classpath variable =========================================================================== 5.1 2006/08/18 Added: @Test(sequential = true) Fixed: TESTNG-102 (Incorrect ordering of @BeforeMethod calls when a dependency is specified) Fixed: TESTNG-101 (HTML output contains nested

tags and a missing tag) Added: support for specifying test-only classpath (http://forums.opensymphony.com/thread.jspa?messageID=78048&tstart=0) Fixed: TESTNG-93 (method selectors filtering @BeforeMethod) Fixed: TESTNG-81 (Assert.assertFalse() displays wrong expected, actual value) Fixed: TESTNG-59 (multiple method selectors usage results in no tests run) Fixed: TESTNG-56 (invocation of @Before/AfterClass methods in parallel/sequential scenarios) Fixed: TESTNG-40 (failures suite does not contain @Before/After Suite/Test methods) Fixed: TESTNG-37 (allow passing null parameter value from testng.xml) Fixed: TESTNG-7 (display classname when hovering method) Eclipse plug-in Added: run contextual test classes with parameters from suite definition files Added: TESTNG-100 (Show HTML reports after running tests) Added: TESTNG-97 (Double click top stack to raise comparison) Added: TESTNG-84 (plug-in UI for suite option should support absolute path) Added: TESTNG-20 (copy stack trace) Fixed: TESTNG-72 (display groups with non-array values) Fixed: TESTNG-64 (Eclipse plug-in applies added groups to all launch configurations) Fixed: TESTNG-28 (Cannot select groups from dependent eclipse projects) Fixed: TESTNG-25 (do not display fully qualified method name when running contextual test class) Improved behavior: TESTNG-98 (temporary files have guaranteed fixed names) TESTNG-95 (Assertion failed comparison trims trailing ">") TESTNG-70 (TestNG prevents eclipse from opening an older CVS version of a java class) display of test hierarchy information (TESTNG-29) =========================================================================== 5.0.1 Eclipse plug-in Added: Output directory for the tests Added: Can now specify listener classes =========================================================================== 5.0.1 Fixed: reports generated by SuiteHTMLReporter do not work with JDK1.4 =========================================================================== 5.0 2009/04/01 Added: Ant task: support for JVM, workingDir, timeout Added: Stack traces can be interactively shown in the HTML reports Added: Link to testng.xml in the reports Added: New structure for reports, suites go in their individual directory Added: @Test(suiteName) and @Test(testName) Added: The stack traces in reports do not include TestNG frames (system property testng.exception) (see: http://groups.google.com/group/testng-dev/browse_thread/thread/9f4d46ade10b0fda) Fixed: Exit with error when no methods are run (see: http://groups.google.com/group/testng-dev/browse_thread/thread/3c26e8a5658f22ac) Added: List of methods in alphabetical order Fixed: Class-scoped annotations were not recognized when inherited Added: Deprecated @Configuration and introduced @BeforeSuite/Test/Class/TestMethod Added: Deprecated @ExpectedExceptions and moved it into @Test Added: expectedExceptions to @Test, deprecated @ExpectedExceptions Added: New annotations: @BeforeSuite, @BeforeTest, etc... Fixed: Was returning an exit code of 0 if a cyclic graph was detected Added: Interface org.testng.ITest so that tests can declare a name Fixed: The Text reporter was reporting the square of the actual number of methods Fixed: Bug reported by Eran about dependencies with an afterClass method Added: IHookCallBack now receives the ITestResult in its run() method Added: Name of suite for command line can be set with -Dtestng.suite.name=xxx Fixed: TestNGAntTask was hardcoding m_haltOnFSP to true Fixed: Passing a null parameter caused an NPE in the reports Added: "listener" to the ant task (and documentation) Added: if patch-testng-sourcedir.properties is found in the classpath with a property "sourcedir" containing a ; separated list of directories, this list will override -sourcedir. =========================================================================== 4.7 Added: Maven 2 plug-in Fixed: Message formattings in TestNG assertion utility class Fixed: @Factory methods were counted as @Test as well http://jira.opensymphony.com/browse/TESTNG-51 Fixed: All DataProvider parameters were shown in the HTML report Fixed: Bug in testng-failed.xml generation Fixed: bug when using a jar file to load the test classes Added: alwaysRun for before @Configuration methods http://jira.opensymphony.com/browse/TESTNG-35 Fixed: groupless @Configurations were not invoked if a method depends on a group http://jira.opensymphony.com/browse/TESTNG-45 Added: beforeGroups/afterGroups to @Configuration Eclipse plugin: Added: last contextual launch is available in Eclipse launcher lists Fixed: 3.2M5 integration (removed dependency on non-existing class) Fixed: testng-failures.xml generation =========================================================================== 4.6 2006/27/02 Added: Documentation contains the new reports Added: TestNG.setUseDefaultListeners(boolean) Added: Descriptions now appear in TextReporter (verbose>=2) and the HTML reports Added: description attribute to @Test and @Configuration Added: combined Reporter output in the reports Added: methods not run in the reports Added: org.testng.IReporter Added: threadPoolSize to @Test Added: Reports now show relative timings (start at 0) Added: Reports now show different colors depending on the methods' classes Added: Reports now show all parameters used to invoke the test method Added: org.testng.Reporter Added: DataProviders can accept a Method as first parameter Fixed: Extraneous implicit inclusion of a method Eclipse plugin: Added: Run/Debug as TestNG test from the editor contextual menu Fixed: TESTNG-24: 'Run as testng test' does not appear of the Test annotation does not have a group Fixed: TESTNG-18: Eclipse plugin ignores Factory annotation Fixed: TESTNG-21: Show differences when double clicking assertion exceptions Added: UI allows setting orientation (even more space) http://forums.opensymphony.com/thread.jspa?threadID=17225&messageID=33805#33805 =========================================================================== 4.5 2007/07/02 Core: Fixed: Methods were not implicitly included, only groups Fixed: Bug with failed parent @Configuration don't skip child @Configuration/@Test invocations Fixed: Bug with overridding @Configuration methods (both parent and child were run) Fixed: Bug when overriding beforeClass methods in base class (cyclic graph) Added: Support for JAAS (see org.testng.IHookable) Fixed: Problem with nested classes inside Fixed: ArrayIndexOutOfBoundsException for jMock Added: dependsOnMethods can contain methods from another class Fixed: JUnitConverter required -restore, not any more (option is now a no-op) Fixed: JUnit mode wasn't invoking setName() on test classes Added: Regular expressions for classes in Added: Distributed TestNG Fixed: Command line parameters and testng.xml are now cumulative Fixed: Reports now work for multiple suites Fixed: Was ignoring abstract classes even if they have non-abstract instances Fixed: If setUp() failed, methods were not skipped Fixed: Was not clearly indicating when beforeSuite fails Added: @Configuration.inheritGroups Fixed: inconsistency between testng.xml and objects regarding method selectors Eclipse plug-in: New look for the progress view. =========================================================================== 4.4 Core: Fixed: testng-failures.xml was not excluding methods from base classes Fixed: Bug in suites of suites for JUnit mode =========================================================================== 4.3 Core: Fixed: testng-failures.xml was not excluding methods from base classes Fixed: Bug in suites of suites for JUnit mode Added: Excluded groups on command line and ant task Fixed: When including a group, implicitly include groups depended upon Fixed: When depending on several groups, wasn't skipped if one of them failed Fixed: Failures weren't reported accurately in the JUnitReports report Fixed: Wasn't throwing an exception if depending on a non-existing group =========================================================================== 4.2 Core: Fixed: wasn't excluding methods in base classes Added: alwaysRun for tests (soft dependencies) Fixed: Class-level enabled=false were not honored Fixed: Bug with multiple dataproviders on same class Fixed: Bug with dataprovider defined in the parent class Fixed: Bug with dataprovider defined in a subclass Fixed: Bug with dataprovider defined in an abstract class Fixed: testng-failures generation was excluding the methods even if a failed test depended on it =========================================================================== 4.1 Core: Added: @DataProviders can return Iterable Fixed: Superclass test methods were not called in the presence of a class @Test Added: Reporter class to log messages in the HTML reports =========================================================================== 4.0 2005/11/10 Core: Fixed: suite methods now invoked only once in a hierarchy Added: @DataProvider and @testng.data-provider Fixed: Interleave order now respected for before/afterClass methods Added: Can now invoke java -jar testng-2.6.jar <...> Added: Support for BeanShell Added: Method Selectors (IMethodSelector) Fixed: In the absence of dependencies, @Configuration methods respect inheritance Fixed: Bug in multithreaded dependencies on methods Fixed: dependsOnGroups wasn't working on regular expressions Fixed: Bug in when directories contain spaces in their names Fixed: Introduced a JDK5 dependency in the JDK1.4 build (getEnclosingClass()) Fixed: Output directory in ant task was not honored if it didn't exist Fixed: Problem with timeout according to http://forums.opensymphony.com/thread.jspa?threadID=6707 Eclipse plug-in: Fixed: Wasn't handling linked directories correctly Fixed: Bug in QuickFix implementation Added: Quick Fix for JUnit conversion (Annotations and JavaDoc) Fixed: Methods Run as TestNG test Added: Package level Run as TestNG test Fixed: Resources from the linked directories are using a wrong path when passed to command line TestNG IDEA plug-in: Added: Support for JDK 1.4 (both projects and IDEA itself) Fixed: Classes that contained only configuration were ignored =========================================================================== 2.5 2005/08/08 Added: ITestListener.onTestStart(ITestResult) Added: Support for Added: Resource files for easier ant taskdefs Fixed: @Configuration methods were not invoked with individual test methods Fixed: Bug with ExpectedExceptions Fixed: Didn't support nested factory classes Fixed: NPE if -target is omitted with JDK 1.4 Fixed: @Configuration failures in a class would cause other classes to fail Added: alwaysRun Fixed: beforeTestClass/afterTestClass were broken for a pathological case Added: @Configuration(alwaysRun) Added: JUnitConverter task Fixed: < and > characters in reports were not escaped Eclipse plug-in: Fixed: Class dialog wasn't showing @Factory classes IDEA plug-in: First release! Documentation: Added: Brand new look!!! Added: Section on testng.xml Fixed: Numbering of sections =========================================================================== 2.4 2005/07/05 Changed: New package: testng.org Fixed: Bug with @ExpectedException occuring the parallel mode Fixed: Bug with parameters and beforeTest Added: IInstanceInfo support Fixed: methods were not excluded when included by groups Fixed: testng-failures.xml is now including also the beforeSuite/afterSuite methods Fixed: generating the testng-failures.xml is now working as expected Fixed: Factories call all the tests even if some of them fail along the way Fixed: Better JUnit support (wasn't creating individual instances) Fixed: dependsOnGroups didn't work across different classes Added: command line (and Ant) -groups option Added: @Parameters (and made parameters attribute deprecated) Added: Parameters for constructors Fixed: Better interleaving of before/afterTestMethods Fixed: Ant task Fixed: TestNGException thrown when TestNG conditions are not fulfilled Documentation: - New assert classes - New ways to launch - JUnitConverter documentation - new beforeSuite/afterSuite =========================================================================== 2.3 2005/04/12 Fixed: Spaces are now legal in JavaDoc comments Added: documentation for @Factory Fixed: factories were called multiple times Added: beforeSuite and afterSuite Fixed: inheritance and scope now working properly for annotations Fixed: dependsOnMethods wasn't working for 1.4 Added: Better stack traces Added: Better syntax for included/excluded methods Fixed: Better verbose support Fixed: Various fixes for the Eclipse plug-in Added: Can specify a class name on the command line Fixed: Default package bug in JUnitConverter Added: Regression tests for JUnitConverter Added: -quiet option to JUnitConverter =========================================================================== 2.2 Fixed: Wasn't handling several testng.xml files correctly Fixed: Renamed -src to -sourcedir Fixed: Complains if no sourcedir is specified in 1.4 Added: In 1.4, don't require annotations="javadoc" Fixed: If setUp fails, complain and mark test methods as skips Fixed: Dependent methods weren't working for 1.4 =========================================================================== 2.1 2005/02/12 Added: Parser can accept an InputStream for testng.xml Fixed: expected-exceptions now fails if test passes Fixed: reports now use the suite name in HTML Added: invocationCount and successPercentage Added: dependsOnMethods Added: timeOut works in non-parallel mode =========================================================================== 2.0 2004/12/06 Added: port on JDK 1.4 =========================================================================== 1.3 Added: new view: classes (still experimental) Added: timeout on methods Added: thread-count Added: TestNG is now multithread, see "parallel" in =========================================================================== 1.2 Added: JUnitConverter Fixed: Bug with afterClasses (test: AfterClassCalledAtTheEnd) =========================================================================== 1.1 Added: new links for methods and groups in the HTML report Added: Added: to =========================================================================== 1.0 2004/04/28 http://beust.com/weblog/2004/04/28/ Fixed: Updated to the new DTD Fixed: Suite table of contents displays failures first Fixed: Bug in afterTestClass Added: Validating testng.xml Added: Scoped parameters Added: testng.xml Removed: Property quiet Changed: Verbose is now an integer Added: Dependent methods =========================================================================== 0.9 Added: Groups of groups Added: Groups for Configuration methods Added: Parameters =========================================================================== 0.2 Fixed: Merged TestMethod and TestClass into Test Added: HTML report Added: Regexps for groups Fixed: Inheritance of methods Fixed: ExpectedException is now called ExpectedExceptions testng-6.9.12/TESTNG-5.11beta0000644000175000017500000000000012732165123014554 0ustar eugeneeugenetestng-6.9.12/TODO.txt0000644000175000017500000001634512732165123013740 0ustar eugeneeugene TODO for TestNG * Pass the XmlTest in @Before/@After methods * Allow a testng.xml file to be passed when -testjar is used * Add onStart to IConfigurationListener (create a new interface, actually) * Add timeout to @Before/@After * Pass parameters from ant * Make it possible to specify groups on command line and classes in testng.xml (and any combinations thereof: command line, ant, testng.xml) * DataProvider index in testng.xml * Create a servlet for remote driving * Add time-outs at the testng.xml. Also: test and suite time-outs? http://tinyurl.com/kbwxq * Add working dir to the ant task * Add a servlet so TestNG can be invoked from a web browser * Make it possible to add listeners from the Eclipse plug-in Doc: * Document the fact that @Test methods with return values are ignored. =========================================================================== Older TODO's: * Show enabled=false methods in the reports, as well as methods in groups that were not run * Multi-threading for invocationCount and maybe for too * Annotation to specify that a method should be called concurrently by n threads (on second thought, we should do that for an entire group) * more thread ideas: http://www.theserverside.com/news/thread.tss?thread_id=38922 * package support for command line and ant * Parameters for classes (to be passed as parameters to constructors) * testng-dist.zip should contain a top-level directory * For dependent methods, if the user is trying to run an incomplete graph (A depends on B but B is being excluded from the run), what to do? Ignore the exclusion on B and run it anyway, or abort with an exception explaining what's happening?) * Make timeOut() work with milliseconds (but keep seconds for backward compatibility) * Improve the plug-in API so people can add listeners without having to modify TestRunner * Use factories for the programmatic API. * Add dynamic generation of tests * Make Javadoc comments over methods appear in the final report Documentation: * IHookable * List DONE * Retry patch * If a method with invocationCount fails, don't run the others * Allow multiple listeners in ant task * Add working dir to the ant task * Introduce "test" and "suite" parameters to @Test at the class level to avoid having to use testng.xml * Remove TestNG stack traces from the report * When 0 tests were run, exit with an error http://tinyurl.com/ftng6 * Show all the extra output for all methods in a single dedicated page * report API * Show parameters used to invoke a specific test * show skipped groups/methods in HTML report * beforeTestGroups * doesn't add to classpath * threadPoolSize * Parameter logging * JavaDoc for org.testng.TestNG * org.testng.Reporter in the HTML report (screenshot ready) * Document @Parameters only works for @Test (should mention @Factory and @Configuration) * Document: doesn't add to classpath * Document org.testng.Reporter in the HTML report (screenshot ready) * Document parameter logging * JavaDoc for org.testng.TestNG * Document threadPoolSize * Make sure it can run several times in the same JVM * Implement invocationCount and successPercentage * Support multiple testng.xml (TestNG allows it but not the reporters yet) * The HTML reporter collapses all the suites into one report, we should create one HTML report per suite * testng-failed.xml should contain the parameters of testng.xml (if any) * Create a testng-failed.xml that includes dependent methods * Generic reported with compare(ITestResult, ITestResult) for easier reporter for "slowest method first" or generate testng-failed.xml * Iterator factories * configuration methods don't respect inheritance - build.xml should issue a clear error message if trying to build with JDK1.4 - Implement so we can define ant tasks for TestNG and JUnitConverter automatically - Write documentation to declare ant task in section 3.2.8 - Documentation for alwaysRun - Allow to specify packages or prefix in the tag: /> - New assert classes - New ways to launch - JUnitConverter documentation - new beforeSuite/afterSuite * in testng-failures.xml include the beforeSuite/afterSuite methods (very tricky) * Provide log.properties configuration (not using log any more) * Make @ExpectedExceptions fail if no exception is thrown * Make timeOut() work in non-parallel mode (the default mode needs to become parallel=true thread-count=1 * The exception thrown when a test passes with a @ExpectedExceptions is not available via the TestNG API: ITestResult.getThrowable(). * Add assert API for arrays and collections (undecided yet: partial asserting) * dependsOnMethods Allow to specify at the level Make TestNG run on class files and not just on testng.xml Make TestNG run on a jar file that has a testng.xml file in its root or just on all the classes inside that jar file. Implement parameter passing of tests: define a property in the properties file and pass it to the test method: @Test(params = { "${fn}", "${ln}" } public void testNames(String firstName, String lastName) { } Run groups of groups List all tests that will be run, or show methods per group HTML generation Make test and class methods discoverable JUnit adapter Multiple ExpectedException Inheritance Test listeners Group regexps for launching ==== A new comment has been posted on your blog Otaku, Cedric's weblog, on entry #149 (The poor shape of Unit Testing). http://beust.com/weblog/archives/000149.html IP Address: 68.72.49.189 Name: Curt Cox Email Address: curtcox@gmail.com URL: Comments: For whatever its worth, here are my problems with JUnit. I've largely developed work-arounds. 1. Interface-based testing is awkward. 2. Only fast-fail tests are supported. 3. The design is brittle, poorly documented, and thus hard to extend. How should interface-based testing be handled in TestNG? A nice feature would be bundled tests for interfaces in the java* namespace that are automatically applied. In other words: - all classes will fail a (supressible) test if they violate the contract for equals() and hashCode() - classes that implement Comparable will fail a test if they fail to implement Comparable - and likewise for java.io.Serializable, java.util.Map, java.util.List, etc... When I say all tests are fast-fail in JUnit, what I mean is that the first failed assertion in a method causes the test to exit. While this is usually desirable, a more conversational style of tests can sometimes be much easier to read and write. Such a conversational test doesn't generate a simple failure, but rather a score. The score could be either x of y passed or x percent passed. The important part is that the first failure doesn't terminate the test. As I said, I've largely developed work-arounds for doing these in JUnit, but developing tools for conversational tests that play nice with the various JUnit runners was a real challenge. The exact contract that Eclipse expects of JUnit tests turns out to be different than what either of the bundled runners or the Ant task expect. Anyone who considers either the JUnit code or interfaces well-documented has a much different concept of well-documented than I do. testng-6.9.12/.classpath-mac0000644000175000017500000000110612732165123015140 0ustar eugeneeugene testng-6.9.12/README.md0000644000175000017500000000271712732165123013707 0ustar eugeneeugene[![Build Status](http://img.shields.io/travis/cbeust/testng.svg)](https://travis-ci.org/cbeust/testng) [![Java9 EA Build Status](https://img.shields.io/jenkins/s/https/adopt-openjdk.ci.cloudbees.com/TestNG.svg?label="Java9 EA")](https://adopt-openjdk.ci.cloudbees.com/job/TestNG) [![Java9 Jigsaw EA Build Status](https://img.shields.io/jenkins/s/https/adopt-openjdk.ci.cloudbees.com/TestNG-Jigsaw.svg?label="Java9 Jigsaw")](https://adopt-openjdk.ci.cloudbees.com/job/TestNG-Jigsaw) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/cbeust/testng?svg=true)](https://ci.appveyor.com/project/cbeust/testng) [![Dependency Status](https://www.versioneye.com/user/projects/553a031c4e5d2e9408000059/badge.svg)](https://www.versioneye.com/user/projects/553a031c4e5d2e9408000059) [![Reference Status](https://www.versioneye.com/java/org.testng:testng/reference_badge.svg)](https://www.versioneye.com/java/org.testng:testng/references) [![Maven Central](https://img.shields.io/maven-central/v/org.testng/testng.svg)](https://maven-badges.herokuapp.com/maven-central/org.testng/testng) [![License](https://img.shields.io/github/license/cbeust/testng.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Sonarqube tech debt](https://img.shields.io/sonar/http/nemo.sonarqube.org/org.testng:testng/tech_debt.svg?label=Sonarqube%20tech%20debt)](http://nemo.sonarqube.org/dashboard/index?id=org.testng:testng) Documentation available at [TestNG's main web site](http://testng.org). testng-6.9.12/.travis.yml0000644000175000017500000000026112732165123014531 0ustar eugeneeugenelanguage: java jdk: - oraclejdk8 - oraclejdk7 - openjdk7 script: - ./gradlew check --stacktrace --info after_success: - ./travis.sh deploy - ./travis.sh sonarqube testng-6.9.12/pom.xml0000644000175000017500000002764112732165123013750 0ustar eugeneeugene 4.0.0 org.testng testng jar TestNG 6.9.12-SNAPSHOT TestNG is a testing framework. http://testng.org Apache License, Version 2.0 http://apache.org/licenses/LICENSE-2.0 repo scm:git:git@github.com:cbeust/testng.git scm:git:git@github.com:cbeust/testng.git git@github.com:cbeust/testng.git Cedric Beust org.sonatype.oss oss-parent 3 bintray https://api.bintray.com/maven/cbeust/maven/testng org.apache.ant ant 1.7.0 true junit junit 4.10 true org.beanshell bsh 2.0b4 com.google.inject guice 4.0 no_aop provided com.beust jcommander 1.48 org.yaml snakeyaml 1.15 true org.assertj assertj-core 2.0.0 test ${project.build.directory}/generated-sources/version src/main/resources **/VersionTemplateJava true ${version.build.directory} src/main/resources com.coderplus.maven.plugins copy-rename-maven-plugin 1.0.1 rename-file process-resources rename ${version.build.directory}/org/testng/internal/VersionTemplateJava ${version.build.directory}/org/testng/internal/Version.java maven-release-plugin false release true org.apache.maven.plugins maven-javadoc-plugin 2.10.3 false *internal attach-javadocs jar org.apache.maven.plugins maven-source-plugin 2.1.1 attach-sources jar org.apache.maven.plugins maven-compiler-plugin 3.1 1.7 1.7 org.apache.maven.plugins maven-resources-plugin 2.4.3 UTF-8 process-sources org.codehaus.mojo build-helper-maven-plugin 1.9.1 generate-sources add-source ${version.build.directory} org.apache.felix maven-bundle-plugin 2.1.0 bundle-manifest process-classes manifest <_versionpolicy>$(@) bsh.*;version="[2.0.0,3.0.0)";resolution:=optional, com.beust.jcommander.*;version="[1.7.0,3.0.0)";resolution:=optional, com.google.inject.*;version="[1.2,1.3)";resolution:=optional, junit.framework;version="[3.8.1, 5.0.0)";resolution:=optional, org.junit.*;resolution:=optional, org.apache.tools.ant.*;version="[1.7.0, 2.0.0)";resolution:=optional, org.yaml.*;version="[1.6,2.0)";resolution:=optional, !com.beust.testng, !org.testng.*, !com.sun.*, * org.apache.maven.plugins maven-jar-plugin 2.3.1 ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.maven.plugins maven-surefire-plugin 2.19 src/test/resources/testng.xml listener test.invokedmethodlistener.MyListener ${project.build.testOutputDirectory} org.apache.maven.plugins maven-gpg-plugin 1.4 sign-artifacts verify sign bintray maven-source-plugin attach-sources jar org.apache.maven.plugins maven-javadoc-plugin 2.10.3 false *internal attach-javadocs jar snapshot nexus-snapshot-repository https://oss.sonatype.org/content/repositories/snapshots/ org.apache.ant ant 1.7.0 true junit junit 4.11 true org.beanshell bsh 2.0b4 com.google.inject guice 2.0 provided com.beust jcommander 1.48 testng-6.9.12/pictures/0000755000175000017500000000000012732165123014257 5ustar eugeneeugenetestng-6.9.12/pictures/summary2.png0000644000175000017500000004661712732165123016562 0ustar eugeneeugenePNG  IHDR:ZNiCCPICC ProfilexYgXͲM%Er$HHZҒsJR ""`D `}>ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx] XSG  hVl-ZP[KESkq~V~PljlUPBe0& ܛPFy=s̙w̜ AI#A  JAAKTDQ1W/ \_">@xi`頦*WW J5$*t\VPWWQR(A@9syyՃbc% SҿΙ+L/*V U R0A@9s*0L;fuοΙ+-1UK.{P/A=pHB@U 622RS^BAv^zՔC(Q-UJxTJ9Z*7B_[BI"k\[L"EߊNO)(˺Ӷq͐% .&cZ"KOoW8@MsA|B,=^RD[JSI.,c5g~}2D>aD=mw'soYs9؈ F(81ST( ypfwpfG(|f呂 P\{,pTD'5\ȧ׮Iۧ1O+Ⱥ0 Ld :G|}\Js~M vZf'u7db/`caJ j4r ΍I!ʆg5c$]*U] g\Ȕ"9IN V-K9RH?=Hz'Rw0AyWhW^VFФ{bxa׮H:k@MsEOethӑ ~`2Yj|8Bwm{"1"裬N}8r#JBK?ߵ{9Z4kɒ <!Գ(dN˲wqoحiSܼqpQ+x4fqLB$\pĪtPq\%fDn`_@. ؒvvN 1&[2 ?Nz1x94 /y='WHKJTw68bl\핺G@)?<Bص'"Ue.2:ёyr {M9mor$Mp=)F+rɘ"YvEm !˝/]` yN"tЦ;ڃбgR9B>teM ʜsjĢجg0z,agB #/xh %CvXEaaLEhEяݬviȁ 24 aFr;ڷo?%$Jy=|}7+迏R 7y^m5X=!G#ie2DI`32 jh!t@t#L+Q+ so0sM`oό$]l9ޛq $}li]9S/QX0H@xߐ{gl >q ~ uc]oLeHhIt=oâR2TL$x<<|O@cWKb)b6f 8RY+N`܄XrԜ][Bf`q4,廞LQB2JdPj1k&8AxU >hkX.G<.̶9!蜹Yxq(gXE8dlzQuH}L^F sjdLb~^YQ-6$'91y1:g<#}K.LjWVQC$^ t\9,=vp5mab@ބjt2RB@̕m3Bl=ypK2 s Ų V$Լ Q#D Bnц \$t bD@smD-V{m @̵pHA@ [A!41!IBnц \$t bD@smD-V{m @̵pHA@ [A!4.>ހOȰo_2{m//ծ.Ds{nD/7[p9ڵ Eo̵BQer7w.qʈTiӝ#7IF27vukF_8mJ׆n9zM8Qi l^Zws{OgPt`]-lǮoHwYkk)j'W>^O,Ec@rb>>v.h‡Յ4+ҨɄ4v|emUj_膃 d=J^ L5,Y]^z!Xnē(gכǽԴg\vemw?<]GˆIhddXxOk}w Xo8˶,dfo&1eI%f)ˆa%sie ' GjR8&(M"~@}c;_81;S6> CkcWdJرlyNx!]+^z/w.`uVve?l s tG11WrbТqf\3(2Ԓ9CekN9$'$Hv6%5l]ל I>w$Ǫ['Tz|P~-תbuQnK#U㸬 K9^ 䄀DOY2! }% ]46\RjǤ%O*..o@sGF2lzoIzoxBzؼsZu{zmIJWKiN)q]Ytr._̭;]11 l!/= h-IkI((U^#zEp'|tLv)*z/ 88|&Z8ED@9VPTB&LXU&I߄!dkpc _qe=єL+w2 gߞzD1gС[=@i ˶ؑ\'-P!3<`5f"tPd(jy#L2**XA;ɀOk' .xҥ}˪Ѐ%U3_7(kiR{>+.*7#m,J!Kr3nswYTZ1遌Kn Ӈ WVkdwt4*+S}7+@twW|> 7ލ;ۡ{bR _~;۠ZF)y'cS̭i֦3ChM߃*X4nkǩN2Z(]i5׽pƮC%9V냦.\? +ڵ{ET`l/%+\=4iڀLj' A K ;I'х Њ [Q<M dvm9,$@+#@̵& -$A@6!aKoW3\m%)Dyra\x֋~!p7 ) P7,;,1'v$$@9B%Yf #B ԉ ։!tH:]uUz1׺ "4  r!Gg(B@dZ?B$ 3w:D#@֮ \u!GcD8:1WiA  -_僾QI2sٺ2%KolM\^#~A:W䵋+Ixm~M֣T#_6m _''S~.8cN#lhsDlĈ֭?ë q>>蜏*vYY|מU~Ԧo3\ yi'>cU!AcB^%mVݿgɮ5uOJu!Ss*6܇J6תk{]\]hZD*++Xz*;{p KLR.|hɮ,00"=xqN6Oy˻vhޚFgpe͊Lv7:tl\y!YK25t'jUſf`By΅Y.|(]$<< Bo遯2T߾' A|fd^/Bw3Ckn /nR6JmX .Μ鼔 yEvK/򻿳7@&MMb**.>1e,Fs; c |p|* \U*+HSY5?qJ[ODێr.8`_|l$͝xz㴝Sn2VO97>y.!w&|7k%ɾWx~g5ln8!VdsNԭѾvJQ_ M*aRE`t *_@&hiG,䆘g'`ޘ=c`C?:Y^z I=/x#z=T?q@fo℟ZR` {:Sz,Jj`<Ў7:jU0FgW\ÿSB d~8Ш#>Ca+)oY3n\_.70,,۷3PhJKQrm̰LNʼnG=z`T.gQϐCHv]&Ɇ: 1o~yp% (,9``We E%RPHhWZ*Js͹W>i(u Q~;$C@I AF}ιM9ɳck Ι/2QD_FhƬ,\٬?8kmn8oaqܣEoWJEhZ)Du4aPhKc R IuQkp0l:`A.+G(gKmZ^yC($fcaeŌH3n5:ӱ)irĖ]:&cscg88p(8{M2}nzz>Ix&jֻUiRp 8lZJ#vi8܄ i+51Sl؋ Zԫ .>}q60t .pD,}C zqQw,zA*PIDATǐG6v$8+֌vr'x]M KqAsSE?g :YuJ8l#,>M4d*7tk3"O[ ./A0p9vq:1U(UA.(0hЖ͕Ge`qGL^f]=wDVf|v:[ŵ=X{X-H%K5%,8VgCV"`! ޙ̨ҕ+0141cB0Ҡm!9ˀg<*=@4qa>/nB<}#Ȧ2 7PSLʋ_ pl&a4!{;zz$RcM (CN<'Zfuٝx420r7xl- h{$fFC^OԩK0ےm1kgw8uPF7XX2l;T̈́;y8LÖ1̗aiaVU`9jǽ7y;v8k,k|N^U.+`Ԥڮn$ \W~XM@ijh`lY8z7p&`4]DcC0Wc* mxN ù0[Kt?`ZoI@q}{LSx3D+As* ]s;Ǐ>{bs-Q‡:oof_}`ڡ8o<{_8aMbVt7ꩈ7Ƽm&#C05EX7=$U&N0FQKJJ6 Άxj$:UDF&Xr9dPZ"˫KuC-TmJB%ڡG63\"dqL4R&+ 4I#v 3s1jvj IJ'1러h/-xlnݥw<fI31 ,E#V[> 4AK㚩hH#2HT:^_QKylzvoG᲌B61E!\50lZtCCPZ9t`ݶS3̲sցjlIɃ=-ڮNn+n_l>l2#2멖0)-#?CJ lFR#m]RG8Xx)D`+! ~^Y~cٕ<tG ,sڨYUbu"-<ΤDt(U>(qQ)\Yko]ŏn-_bovZL OXTBh^ZTOeYY~v(XUvnb̝Ҷ.=]M*2+f۴# c- p').6^J˺yعInNzlcOAQY[ml:w%) Y./= Ǵ{T{tKNJ==6pO3E19|zC0Yu,F@󚔻<#&Q.*AGQR:!;9>> rQW&c>Q"0KpdBL0) 23,:YIh6-مyy%tGDž4fWxpV6<#R9G pzLuL)r0?lYz"FWH&8=ΗyEC8ar &e)VFФ{bxa׮tZ`?ͼ+B0OuYE v[:,=b 8*#!wƓ³s0μ.vώba;0' -Ϸekֶ cbPsv],Hcg9/~BArfI;/2$f%!FB6Y Co JYK KO 󡴤P bA(Bbe"x(@#XX(I7) O Aw&\B<%*TZ*:da>RaElJ _cq"h ձ1E$k.'/1X\}ѭ"C r < \i`w>,ZbZ!,{b!OD)b!cr(@ AOT*A Ut&09_fcC37PQb::4B\=b#p@>Ʌj<8Y%Z-(K%A ϝ"~s#``nMolR5w& }`779Ikvf6`.Lã\T(PqET09 )AZP&.㧻넽\8ViJדi3iLyJLɠb4KL VAenU{1" 8zϨ5Xv%bx[Ϧp\-@f%A ^vs$Y`$2;Speŏ%ZDJRZ^AIB[#@1ZTA\e;07-mK-yeM+R9ж$J9HhȻ-1)TNdS;\7wLͬ]<We]=gCO*هUu7-ّT@#?pk+<@geiõ8~8%+qx1=< r 9=e}?9 $kH;>?,)Dң81ԗəI@Vxe[ud$uݪU 3~9g(aJ"IGdcܪ:plO|gk:,4 8=OFt_w |ʬ-Gn| ?HvRD( 'tUZscGn2`}%3>,(`8+GJ.>ԇ1ܜ-}ox*~߁E<96/='gmAӢmP)*J8aɍ=t=?@ro=ϷgמIkSGzY½~ogPto('RIF__V/vlۣNǢ#BebPEr̵3g/g ̚ EmOADda9w-e>j,pDg6jiztB\طuϢ>~}"cw"s *?((q1x,߮Pt0вK,-h<N4eݱ{IZ჌:+Ѳv{z~w4IV^םÎem~nd&Alȧqpq" Bny?cl#?@7y֔#ыt I} P=@GΓGrAwݳvtUwEQCMshu|wTQX@Wѕ<9vDJ$ԅ@уǸ6X | qFyGzƂG~]zw/;:;`uYsD9xYk5 UܡkN4bi3l t6Aʳw45e!]ҽgXKG'48W{g`A|+t*A:5_v*(x WFêiEw$>}qXm`ږ|.1ɿ=ml*.7@o >r ^@~Cà~ED\ EA'ۗ*YuޯZ7ny7yFu֚P֮;f+Q7{k]֓uã:=ovP*w 5jܻh8oG?z^Z9: s ;oga@u:ctg~af}5 1OCG0|8Z.}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP((h+HV UP $ $2dkɚs2 q|Nz:g֚}Ξ[H8 p6,YY?ޙx“1j0q73hp-:X *k^5wyjF)k~4֏FޔuM4|Σ^LvsS ]jёg\dYZL8ekգG+RSS3oTVV~w7W^vy$yZ @$ *Lm̗̚yQiOؔܯ*Bn~3xhѢZl O p4qay`U\D.cM .Jb ϯ "qW$$$ 9vakFsz]v[/956+Ƈk=[#Gw ;o !|3[ y{:28! ɫp"Ocǎԩ: ۵sT.ApdH+&۹~E.>_Zz(|=oڇ$vrBӫ/K7A$8eNkj߫*$ +DzfكGu T$Djf2:nV׵ěOt$&-=Z$ǘG]iiMOPj;^re'gƯo-F$%>| N? v[{M^pѵ\߃Db58#ǣcN@'ID\3MdYF.j"&=&)HZұ j(ܿ߹6"-TٍL0z`>YX1?j/Y_3e/𣅟 WKlj3P* ػ`X $xv-UNH8pዌq/ @f 6MOZI D:%ZHH8^Z f5tOs ZW{KIDta>( 27)×턴VHNj$$J|uP] .n3SjpιYVXۦӹ§!ͅbM1^X{R_cP`kQ"%3[`7VK1ksh~;LLJDDkqb*%]Fr{j43Jo H:@B9_xgU|$~m&JiiVB35)JNQINP & (d[lLKyxW㻋+G}b Nj q3>zHI$v{:9ӁQtp)}qC~SXK p2/$\BwOVdbi܎$MX2&n&٬ϰ6H; ^(tµn)4]s ""DY`B >mтPBZD@0(<{77$9d^MS5'8NBl ~v:GN"BGZ--@$(Y\5NPߕGщt>mΌDoL\mx*d_%,wM=JtØ hY~aU(XRDTX!݂| = tQ0- {x]Y4lY4|KBd:'ytXXO\&0%d$sc6qk C.8 `g;yFv6_m$Dhde[FfL ))H-NtPX߭ 8ͦxNHxVEfE,:~ek"#)hM(-}3@OCKU!}rʷM/f|TS-Jd=n3j٥8e IJD@ķ8ibSB?(iO?q)m;ҡC IlsCÒyWzϻ}>~w?.RZ$#EdrrB2N!,?w;3Ͽ˫&zƙgF|ArI5aH3;8٦'d_oz @س/iv<;!عh-v :N2%q?&=yf݋?G ݵ OWI}Lzpb*P\$IK%1ɥ(|0\uL%d$Ƙ[,!HVyӜ-]l뿎=( r)\&D3!'QNmC)wn,ݣbkZ?Pe%%%HvC|$㜈XeY\{-X3ٶ =No2;ۏݥ%ܯM/-55E%f'|Ԋ*oI" 7sMiG|$B:їrsqV;ƴK(FE3~Gecs_{ߪka7#YWi끦y@*ks૓i @-<+cJLVkf 5礢x.t@zK>C)еS&>3ґt(v$Kmɓ'Bzg=sbb\jYf.sEp&,4#[F%$0̇$ቼI‘s-0<-魴hG?~{V3[m if 䗈#IH~$.|;uSUH;۶[FDd GITu*ڷKt5)1Ekmy 1n&Ld钖[$& GZE&c tXH>R8j^`Xo=Јn[I_]|pR#EF,#kgYsѰ swf$"ń:גtm¬4>zωtZ(C/tmωMg;~ X^2ZɆgF,l=`=`=`=4p?1$s5I%tDiQ&# AalW9]<}.c--X1kr0n&dCk=f`4Dn, ჋fyܯ)/0a9Xy@V<{XjfIMi1$ҿxV$拎:x-joK, qi[x1Ւ Qt禞6z܆晰هŭb[F7ctX.1Zi\q3a EAAjBÄ&rLDV 5b=`=`=`=<H5knU 8/q]%D"(тX' .h9iMY\tqd়\KE~7 XNh?!<[[XXX4ouխ ] 0ЛT뎢m@ ֵ$ } tB4v-zzzz 6pl5㬉KfYb5ΰn46;2s-6\tDM K،hS_pZp94dJTeȴMRd].8^b=`=`=`=|xY3.Ky ]i@=ft F:Òp73e %?̑wrz춈&VQwbc9_frzaԝ/'qUEq(3ўXպ&-(5f N艁N] w.٠?Gm~zYzz3feuǭzhQ=%lK˰6Vd5ͭYsPn2 h!<;5X=ܻ2a_v;;P*ޅG8~X<Ӟ}7d,uwwccl/a7Ct\$u ~N}2Ƽ; jo?4!H{ Sށӷư߿K|r칔l5bCf wgv_ L_O߅~xFG8=c]]KAps-I!fZ?x} OӚjCC@/X}x[1۝;Z^yd7yb ?rZo9xp$@0},$-->- ۵'j&iv0 oa/Snd5WۡQ:;m}ړx`MV=.H[ڦ9܇uǧnmHkz/ iռ3{h{. |xH#?b=`=`0\DkWӓ FkxI- .5ָFY!:oXN \7q>֭{|oouz:Կ5dl NzsapW`0#]N5Rmo\w~z5޼?X)x\A#Y#JM] 8Tв YD-EBgV3֛pqtx+IfҊ@%2l+lD(v89~34^C1|mH cs`p P?୷|*1LGaǡ4|ͼ]`b=`=po5]jS_E;qzPDNpMo}!}mCT=X@ko9!an}# ?~?hF^?BRKA7LZb,`ƭwuv[gUsa}1-`ྖý,=G)"X#vʹ 7<0tJ9l="<7/~OƜ6p4A.^7 ӑw̽`1+aܵ ,m|ψeZX|< Vl 76oLΕ4 knHNd<` 3MqHz@QQωs VUXOҜ0D&`f VH *]^4z2KU%VoUٛPb~ gC< 0$8|ӽ?w?8MgheOȨt>CәgŰY#Hq J&.tugk=EFkNmp+s(iBI[ ap~իdm`9m ú/. w=-߰5K8#= 4N:,&n5γxm)d\n< [XXXuӣJ<.2rPg,FskҬ_l&~Gӓ_LFґ JpmƸ"/2zzzz&1ٌlMWǚװBqiVj$5y:&kXd4ͭ-/cMF^Fxubҽ]#%g1WܲȘr&_p/}k2Fګ/:G3?}[XXX4:25]4x%#m& @pڍ8=+N w57yufФfX_bMx8=%& fw@x hsѢE96!1tc q@(}Ayy9x!(4>XVdmd;Ѓicik4O_2HIIqc؄K<K"bN<{/q5㱎&Mߔ㙌̎Lix׮]1`6YJs8%3&uA˖-6yyҭ>KĒ8Z1n[hRDZ{]]vequmzzzL@ǎi$"naɇy&U@=0r馜ٗŭ3J:F ͭwm@w2QDNpM:fkD19W~SisG( 3ϔ7qzzzz c-7,`03qm6\`7q'ZWkPYBYUTJ͵-K8=p䤨! ]O74vƛ q ᢣkSGWA&-g8ImNm1-`Ē"[\7f♌p?MhсSض$Vf"OgYY@ t?V9)HIQCF; >|7Wݕ)6NxBc\`}k5W\tizTXU*_會v[(4;jD[͘lg&]Bo5 Hweaψ6ψڷMïzz̿i|/~27"h^VYO;~G]! T4jLp;%JLӉ\-vr3rwk_IEf-Mf}*,OU=cgĦէ :_r12-@z6P4Vќt<2nRtUaT,S9Tn`' ٴBB1X p6T5ڧIh&l^I'~YJf*z]݁`hL3}8 X2k'Q _^|ETWW#++  99٩NLLĩS>9q(_7Q1Y"4DԫumЫҰy̋QFJrhUaDojm]4%8\vAR,{rgB.{"۟ _ ,aUjN\4֗g`Amr⑿/-/~lDF;`ȋŌQ5ʱjy[%lC0qpy+Ksin6.q 7:R|" {ϊ/_*U|v-t񭛖MvO^Z|OdLf,ƞy΃eC<$t9Pm"r|n8l9Ϩ=fcs958\]tЩmktJBOrt1>Wxp[q"6Ӱv=&#ekuXF}bذa1rH 2=z@.]еkWt9w9._t0,2bԦKߔID:tފtg#TD9ttCG:q21+Cyolp;%\# ^M+'4Ph\O ZO|cJ?}>+g86dOYTOycZmt b²Z[|;eys] ufh'9,?B:*KCiḀYm|MTyWB~ѣt*CUUUN1oΝO?4TXX*)) UTT8<?~qyO,+q1O9>sxݏ߽xq;=}8p^y G8p^LQxfbZލQ۝Dd/-.G]p_k ]4/vSh2ߣ/o/L9F VˈARr{WeGVGC~82IK>-\v3.GNw=sDFNx.Kܩ#zsǮη6$u%ºŋ 7s8=`1$9]\2d1Vs|+nPd5xp6qdOT ?h3f2߇tOz]Hc0yb۟mP<1O]Jqlۃ|u=e&\ܓn Kg.鏽§_GPMS,tYсf a5YmeϝQ=) \Qc}kQiaSf|͹Ds>Y/oP읏wW,{Uaay!ZJ (*9~liEn^:ҧ6#5iT Ƿޜ r'j-Tso7F- 1IJ4dթBb}n4Tyxu%~!gF_=o$-x%4=O0o|#!+]0ߜ.`Jo9Kp8ӱ6 `q0/|"$giqU#Z!'\cBWT)NLAZKZw!d^}5rSܦOy+gㇾ`ONYˆ6$sֵځՍq-mym_tp}xwy~cQeV菇d#U΁oZCR8@u[KO-$3d_O')^fLL:\{RL"0e/*R\|y.H`t?ys-ϻ2aot-O!/oҧPY?J>'اDrσ@3E3xs,19dan4EZFsEE;㹸i7qA6oŃx_9=>)> γʮ PX>z0ys:o6*#xy C(Yu0bx_m9c/Jg#Ѯ0*3u|zaC.2=_Da7TO.vF[p K>Rl^A'wK%șqB}=_,/A_W݃C1tP}-Nz=<ˣP\UyFu~{ &݇|La;=۷#uh}Q<7u2_{;rVLCxjFd˷pf `AwO%݄AǰvD+=3:z)F `D)G" |A1T ܎ DfF FEl/e_b3u%^mJ\+zurCَ0Gh ]ۋV]賕wAhxNÁ"_r*:& ͫXdڈЛ"   ]DG"i1?n:]<JKQv>.tp}b\ y)j_r-W`ѫ_UhK+bւI=c۲Y9;˙,[}ROL/ ~-gc+Mzx;&d(78ܶ 7 7c<'52ڬ(oI ôY-} ٙ0{O@=}܇ia o/憽u|ogGӧ+ :L{(ބY`XWZTA&faooq} 8?a@ G7{}YP%dl7 NuOdd._\{~y~2zƷ[|BB2:Nxٹ+ӑ1O* “.> ?׾9X1s3Rp*糲u scNie}GF$Χ6Ƭdj; 7¶9F=]Zpjb.1[Ӿu^㟶n0Qyns*U-Z #ۙ IDAT;# 6W_s=Gc}y@ϓDtkx3mв&/*ܭ ]`$4MXR1C(9ᵖ0u2ϩ,[“cr9~zpO{?œW%ugJ3 ̈<;'AWV#5rqL ?;rti]*=a7xENHn DBU9Ai9nc1f1㟈L k?//=*D[xkIJZr ɭ'O܅^Ν;رcXvWc9-1KSM~Bmt/sce8''3Min#tw~D5'#)l.~<2BkV g4LW@ D#Wo O EN E⭎nK֏E^{M9]fg qkngk/xijU?¶ʮHjSHKF5-)jeGn|fK{v15Iff4]l så$#8Fhyzͪyמ@IE)G*2Ꭻ U;v|4dd[P%:B1 f9M7qݨ$#Ƶ"#d\nѼYV}{DnIJLY<_,<πr #}2[ь+֔Loih{u1{R:暰ĥCx`glʹ;&ъwaapldGR l&OD6:N6!Z+l=`= p2ODK-7bD'jC!TBTJB[L0o_N9P\Y݄d[ьԯ_x&#H%6NxBc\`U9]=#ϻ9>WbǫQ]s/m4Q=xH|'.{7~gTBHشn?LXI|Kc5*aY~Gko~ o#{Ģfec'=%>#S-QZ;\yNti;z_bK4Ռf|Nhb/Fkai,vD_4FzqߥTIDkYC_hϣ:h {ߌ]3Ѩoֆ&RQmj#kWh;&j"H[,HoȢ_v,,9a\xˀ}a͵ocKU8hd, NsZ.г*z/b@]mԳ;=ҐJφh%7RSЂbT(^EhID E⯛阬a4hʏufeW'&K8"^rC%zP%$3oّ/cp}ds'ismy1 /c̼1ls^-6 "koyn@qٶ,pM.5YiPMMxD(-#C.1a8Z'k5╌L2Ek7G KDkZt䰣32]btws;ir;Ij Liܶ.ߍǦbEcv7m *?@zcƠ;iۀgBWz15;Aq酌3@\wJ=*d\2e)h/zxlmL/l(D+ŵw א^5ɗ oWP}GWWŠpwx{ ߚ]DoF/f"%XZPFb,h~2^i5n _O:79sPD&1,˱bt5?4t{<Om&{Xug/Lk5|Ngp[ (^?G7/żv~Hpv6†oNo-Gtl(].hD>׀6ô]iw_zAGĉnuc;)>an9]8}#2n7N Wځ6CY Lclko-Km@ʒ_ 2盠 9ziz|g/Rqɵ@"b n%rIHInAx2(n̨%%"]n|WZsWn Mj65.FфSm7׫ny\c:ӱ; YszVt<5'DR2h QF+zG}Lmicdan46JZXsEEw\QU&k,}lgn@qζ hHgoILB9:E OLuZg,^mDMFІ ]ikӴ`^}wbd\k:\FIl@9HK)|&C! QU y8@"~ĵ^ Xwbɋ g22;4 O7Qvs=Lo ~wd\k:cݹ(U2V8gtu͌NMBe` gJ MwOByk ~] .aҍ7y"ӬZw 1M5{i\05@X?#Ln Vo/E3ϫ /[}p%PMS So8AQV:~-,A{1vXl*idC=yLyLs9A ]`"G ;~< wV$ Oi~jv޼L6?t׆m9z^Ftsm=2o#^5Vj$%PlYR~Z}~XҏC7z)y^Vh.t"x'#1ZaXڤzzl@a|}[`$OE:m*<De ՅyҷK6-\:m8)0҈%;%X9 7=/[#:.~6%&]B}RsNnk1sEEE:5ss=w7AbӯsZ8zСcogӵC&tˠKj:,ZfDRpX{Z#ze3ڃѓH%l(‘#'l`[;1w94+}c b.=ڍ܅ "eҞ;#9ߘ*Tl So&Ek4 FrNH,\ƛ'Ә;gȘNVL!1c&c}HOg7}r Cz9-pHœk@R<ᣝUJ)KF_xNY$"X@.@ ?vSЎ6\vO%~iQz;?_ph(bt*uZӜxc&"_Gq4q 3M_lm=`=`=x }QVFJxzҶ똭arnsݔddgm"oZO`_4a6M*l@:,&n5vUҦ q ᢣkSG,l=`=`=`=H1 OF+MMDP1\a(8T%wmמ@IE)G*2ᎫnNb=`=`=yE=hw4ϙt$\'<1.ȋq\7hhR u;ztq)gXXX&1ٌ7->D^̈3-/4 3.^'^UrwFVZ{$HB&OD6xx%rխmzzzL_74Od vkˋk2҆:1^- ̷~t-]~WJx5kNMc5޲3 \N߅rxdS3"kt07)2f=ecMFҨY{Eg}OT~J\okG8޷W]C $!%@%(*- jo[[ת"*> X RG A; o3'=9 97s6.s:|lٴmԻ/Rc7y7Z{g"`s+ՉD .ش |*GD" ?ᬩs?kG&6qGμIs^Ӯ1|sm"ԓ<Yg\.9,.!SOL"lɖh|>u9S߇ ;gHN{ttuߍ?oi: d8m 8:ŁZֲ ߅ǿF0]9R'}-;;ܔ ?UX'~;q^*.E~﷿VPkg_"vI9ފ0T;!c(SHG':`׺bܹCuH(w=6  ҍq-5V=Z`ɜoxU t]:Z*œCІt-%h!v6][ή'}MgHc\2Я] <|!7_n<%֮(kЮk \P/?݃+O1?zN(qn{rįiTO4g7~}E?MC}0qO3qeXknL#׷ C,r= ^ہ|) \9w5<:Ԡ_Z$-%i>OoJk5(XiBdeWMN; p,5pέ.,\sCB\^zc1\riۀ\mhawŸx.ߐ+{M&.s8"c>{rVSLlvT6B>>[1j J>?t]{n뎟+' [ߞ;[~8n, opvD/ =S꯴j^.c_{p۱N XLEįڅ[#c鏠j!|^R%xGAx-1x`gb!޽Lc/x^[;ǯ/9䲳pOjp>M=IJ>yqz#Z˹0w+\vv gδnSہ/~jwź2ڶ+]d/ұa{fZ8 ss}2o?#|bvD*h%#XP2#f,;J5{;c [O^%8WLGaȉdxW*Dtnnkg;p៷k+[%[iDr{n'(S-F~a-vOD|hK'ǰΣҪȷu[tXR?EuL+h|9;g̼xsGY'WhRݺ4W}TdvZE5dtV518';/JBZԞwfB!XCr~]I+|EqC -hTtԷKq2/{pSouN-Oi> 􊻾p'OD,f$>}(_'ͽd]%85bZ\ NCZ=K4S,vUįrp"?|0BDuX[{u[֚X_lYӚuaMᵰRq a5(X{uw3W]Rwf5+ ʨԒx'~IR#ogq$Ɵ'wlp5m@/ܫv(}JU1 7?1"L,-mrI-O}^QWdaYt\ڡoA'#S8ll(+_cXz&nݺ퀷&w:՛$dkIzNlXtr<*jBJVSˏ# *Yad?&gbbn5nh'c&YhnMC N48J4V %eG!tIDRDUc(pϛ`#"] |۷OOKGυеPHRmV8B=˿"NG#p}:nplˁD=Y/čZbVxgxVNVCja0tpЧR?S|ӆ JXW,2~:\SK2Nn׵(c2ZMSV~cMk[1U]zvA ) ֔g% ڑ8qpk99ڶCUCRQF'/kک?g[ :0Ux~jQsSv~g0U݇}~QW'hzmSl[D`X͋u&.\i팼cA4xu  D+7Il [|Pմ"ٴsr/LI0$_u1oኽ|y,*+ yHgZ sIE{qD7;%d"Q%]g#뽝 97{uik?Og|;$^ϳ1Ak}Bwc{6Ėe6,+܌ԘN]]qN5ji; q@W!ÍT}`Hǟ܌nwiɱGw3Go:kn'cJ/ZëO!o S*.ݨH,j]=!H_'GSqx/htF*]/~Yx%ֿc;:*ï8 7SOWv9芹K/Wȧ X4 xM1FR+E%oGwgޓ!cA`{kقc_ɾڭ#:ܩSxqIQp>moE1A1*3~8[ӆVç-ӹ}i|*$OS^:P9(.ƒcV+'BGIJm9+1)GV99/3,X = %"55Q9i~9Eo<^1GW@Wwp1`cxp ܻ)T'.s&8{[.y`)7,8akW|SQ!`8-5Nxt.t 㶂vdzj6 z[' rƀ[ ό8ǡs]~dOU?6L+1t;=ڎMţ7 @smU~9- kQpf \2Ԧs Fя?FcVё 9hm)Cm*;7Ĥl__:X|/M؈[JPS RWLYOކgߋ-e܇P"?zzehz~4yhB 5f9DMkօUdV^ +uXPhL|Deܿ%]gLνY;daWѪ V-BDtNQ0}h56,*Q=i@qgp"8or$OrH76svLLU0V> ??(x ?>42;!ɼM[)Ihսߨ.ɰ}rft:ctmxB \9N_#Q^58IhLuߣ_KAe#-p$0NIG \{%<&z1ʬ}o\A'@\;Ir"N߻ĂF^L'iUD>x!Le_s|EX^ZA~NA=&1M-wP c4ЃB):ft ttʀs٩N~Qd>W^;/"0(C ?0'g+Ȩ~T(pBNdCrd}NUtpF%x(GT1T.igcm%oA'WWAHN\.~`fEe:! uye(Xt6<2'կ7߶YHpm}znoFiЎn|UNWGb̔U(X?ڱLݎ&ݓut,_Ѹ1rxZU[zu9uuӸwb#|znu=nu}7NO7Cz O5 h{˰.QC)8M4ޤ"ʿ;Nм ۷N>/Mk?^$uoz ɟkikk׮ŢE`cXO &1u]R6ηWLP' 1:^NԠcU_w<5l!i?}xߊR5z|`\<:nl  o]N{1=Ξ3@ M-~ؠ֍nLIr@c-x:y2)\6ː96y ǚ_Z4!S+eLבO_A\afntG|KMWY Y9&3cʐQHVszsj@쭶nhdk3/ι! Ό8יulZ9.HYPS+^$+"֣wPeUHM@d=m˄R.+8Fiiⓒ}:y9}!͕6;橊Y(O?MGG?x頼qtPO7k l tr~\ 9evyͫ\gRe1^`984:@VG%H,xug Y| ymMj12U#C*>VW]19Lpb5:oBǛᚰo)<%CÄlHɺVJ)={~uD!vzU5G-xms`xlvYyB#䲆£sGYjjoc~ZV /sF+)[<]5 [\fQ4J`, p2xۨTtMVBpќk1T 5N2(iW 'uB/4RՀՀՀ@5m5miY 7HNB[/teBDڙAh  mE&6YB8…it^x/~ݖM~]lE.Kl5`5pi :ms5S3&Y/eIf%=RWdA\/~lՀՀՀ_2e5>]؊32;ԂJ$AKY8wJS IDATa\/lU'cp={#?jFUcsq>|oFYlӧӂwSww5N,醓r\eE4iBoƒ#! I9aц7`aJD!=lSH7ue`n8JMXs g d hG㫲G((]) cRM$I[mHPä8|?x@"̻M ?jj,82HE +#݁5N +x Ez6lp=ߊvGo/Tċ \^.} PE'J ;AOj?K.)<<-|<*@g0]>/utM֚X_T5*GkaN7*z׋Vp~S1 3މ`Ks-!%`ᰵc^x}(1FS7$ցS0Q2՞>XۛgLJyh2lEqI' -BqCe_SjOmcF˘f4)oNgJPu2 M#sK{fp>Y1Kz?9LI\#\Z'^gW*\F9Np9*z 'zA8^+,z/G RrW7$ 7 Np=8H uAۺg~:H|NpC:;SpV[#ﱗ=׉/, 7-AQ ='뵓z׏/J/^׌Tw_p> \/+sp=^zǿ-(^˔`k3(ἒ>dcGp!3L'bF!-s ƛ<22zb]bZ٪JVEV E[ytcmt-p&-;u@(Ny h{˰.GEM1vF")uϼfY ;#}u+H%ȻPV6ŕE t?zP9$ \:(eTaoĞPw؀a0iAϨ~ötjijj^xuvF"JұIYro.)bƷfk6Z=ɩ\oOj[0 =T䆎OHAPxO?w)8nQ/^0;nL! wQ7:&ŝ{m7DZgd g#-Τ7LԔz~9 /}lp=}Rt뽩蕙|:mJ} uazy:$ 뉷IVڴxj? 7L鼭#zIÆyܶwPxdt_bKEq$,-׀xm5CtnFb6svb܄989xYy˂7v;}_KzΪqOqڼjW\chVyƸotm;HkOyw\ɗ+nQP q-hPPqj3m pd5X/kQ2۲SJb6aiG62 ,Q^ zoqrBeiNI s%JyKjjBpw8=#$s|t:qY`)lǝَO: 9ȓnVpliM̢dH&N$)^hiث hMְh[[^8w9KNLp4zaY X eN\ FԎIgK=i#uFҨ{ g~OTYà װ,Հims.lFjANpˠ,tt}D ,Հm4]qMuF^ *8Y e 'u6^D:)Oz'PVM@(l{,<p m^mk:p6 k4DTÍu@v}|lj& kP~7DFԕQ!`8-5Nxt.tl-zM/^xq~8ĕ|ܬ;pזw1FR3P|ycTiƂ'@lkM{Ygo҄,7ueqSxiٖoևUlp,h{ OGH؎_:R(y硯4>e`.x0W!~k,GvR ZjhcM+u,YǸ&tFU'48lpr'#ZRC 9hm)Cm*;N"ލ󷠶 ό8NIKRk٘]+T˶j5-úl:]5LEPSxM4yͲvn\/rvaTLTںw1եKV$掹#j R x[mC'Pmg$Bk4, %7fYmpHuu뼃1Mv;ޒ '!qcXO12 GPD!B N'j4 Vl 7ԯ7DZgd g#-Τ7LԔz ayh1bQ>_~藝dR}gMxfӄX]`Jj՞}8X'd5p\4eo5^l έA4™e-\`7˚O`rӺ@w[m2}Su{pI0zO ? y }ZDsh@ٶuNͲ#b6svb\`.yz7s(gWދ=@9yvz<*Q6)!~ry\Eڠ_$^9m'*@}qOFڣj$ ǛOq=ߊz8ioo֙Zjz,^Ϩe\B?MQkHͫD-6Ҿ,@pPy>B9A Ne^hlsk jd>n8.>^[iPBx~ӰWo5`5`5`54 ukEia8pZ3«*!M~/:PW0,4f/&Y/e/~>ZL:s  0 [UjjԀ {iER'8eR:p>b׋XejjԀ^vZnn:#N,醓s\/bYSliͲhWMuFiuc!StnualpQ5V>G.Ϫ]̖jjրM4DF FͱhVҤɍw:[?o9XY꩒FV㝫o|K\bQV h"BrꦮDhm`gaaOzΈˑ?< / +}|:`3_܎j8$QN ]KFm9XBlo3l_QX4WF`20ƛ‡v4"Odp-fx>|R,~n%N0x?o+8c-/cN]ޘ}O&XWd%3ѕ|*O1&> R]ބvs`c6\ss\hVMՀxm5}k:rkIpfYXͲXhq.JʎbgC蒖I[s(,ǶQVQ{0%Ōg@1/X< {!}WH3Ī(UKSJC4 i22+V!{~(~p\Z#O LDuIU. Gz&:Mw)H[Ǫ2g-)9 > Lŵ` n흂@]R@pً&BɄAP$jʮՉ˥s30,KQJ@>u9gܦX X D&uNͲnƬ v+ M]6ܔz~9 /}vLAPp/^Hϭ1L\۟$^^Y)Gcґ#6>pk9o}s V5pM*n9?J=?snG3gI X2!(G&Lܩ$6if +|]Jd2&f;}0yz\(|( ʟч%MG;(i@ǰ4 [zM'86ݟ&ZʫO`KVVj@o(z&ypҦ/sw+B3 ݂Ah5Ij7ƓB [JP߮h@쯛Nd vk 'Rgzubu[6u]Ñl50QW2^(tk894J9ά2{h$/!ܧPJP̂VVVVQЀ {i<"$HY8wF6^fN/ heVk3MPI1.n8kTn5Jmjj@(l{,bU'4AySvnXk []8\/lUYBSn6Yp^N!Z6:@C9 ^t[ #mpUfjkkctx:G`lkM{Ygvo҄,GNLqf&YVT.osbCL ?d\} ,Y"h4,Ήc8I7,aJf1)+#SP‡v4"Oz~"_S8|?x@(|FD ae'/u#j[ X q,󩩩 İ .J |5Yhc5xQ=Ճ뭇/^2 QF[:<.8QC؋{VW eBv([&05 +q2{)80̴«mr/~7 \WF"J"IYro.t'P'QX j>j\ͻ%_".ٳEYlhN Ӊ 8.a\Zh\x5C{m#^cVFfgf;A0Mz4QKOp=Ѫmٷv!LѺg69 n;v@7"!L8Z@t5[saG$pӎ\~j ߍqFZPևY:XͲXhq~zRK`/wU3e ֏vV7%w'Sp=~[td>NڦgRܾL Ϸ0W-Y D]xsȑ6'!Q\\8m6FP5N/h" ^`3g'8MX1auLO$?H&'t\?RZ?ȟlpnP{Mֆmjj@kw;"gUԪU+n*IVCU6ߡU}Fzwnmԩ=[O?z:(OÂc~v:3\6aƹ3$6$nK$I3?'Ӱolp;;&R0?/Jmh~ IKKC˖-;[p*WF:tZjDƪMְ0N`p!y"uFZ0ݡW'&ދ_a_Yjjj[dzr?_%%%S;^)ӧ묈R#S(+uj{ά2{FꌤQ3 BC+2 Z X X |4 [uYYYhӦWJCeNk|(E5͑Ҿ$AKY8wz [ X X |5_ɗscǎtq^vZnbi~zW\SWF^ *8Y e 'umpF2Z X 4q[v)))DCwL͜Bds,H; p,5pέ." ,ՀqҀv6%;$v>'NHW3f՝v: z7"ͱhVXܨk,Հ@3k 9t| H 7XlkM{Ygo҄,G» L7*zaY X ` #b16l؀?A**"{̰QQmP5&c)|:iB.Y땯 H$9ca?DCĂZR1ӟ'5{ʉn&o#2˦E{ed -=k:]kǧM]&t݈;eX6_YBWwFZK.uVF۲e VXaÆ9$zy{[mCu'Pmg$Bk4, %7fY9^ *pxv͛O|q:&G*"2>C %VVw@/OW^y_|wGͬ/fk?z5 IDATqY!벆ލ_7wpռQ%LV*E Z Ыc߾}F{a꫸[Y04fki5[Yڋ8o323Z-Bo5B#sqG vߊRٮ3&ގY0悫hTuB":un]ķ9]#n2X X tcԨQN؈={8guBD-5n0iY6 " v+ M]ܬHަuW NDŽ!/`GXY"FbEƬePntfYf7[[a3 t{v4 Sil84ʶcJ>BGIG2()kNp\XFM9$Ɔ-^cشsr/BC2$Q>0y-ՀՀq@8մɦ}fqp2 _ :#"5 B4 { )nGd|Fz:8%Ë7/FhuMְ0N`p!y"uFZ0ݡW'&ދ_a_E z iN pq_q*\AСCpCsa&B_6WܥИݛtfߓ6Rg$^xJ5_Yjjjۧ!#u/̯8,"mk˰PtaͯtZP Nrs7ՀՀՀ@h@_/;-x7 4[+ȫS7A'9 ,BVVVVͣHlr$AiM`n8JMXsgE2`5`5pzh@lɂ ^ tz8-5Nxt.t(k,Հ=׬3o҄,G» L7.zaZ X Hh>$^sJp>X.hM5:bv߂ܫFX0SPu2M#s\/bYqDenn.-[{뾔OhM52moe7m ̎cM4ޤ3 l녥&Kd5`5p4 rK׭ZE뜿-NK補W6Zpnm.+#Z a@,7Bvn녭*Kh5`5p5? %KYYY4hP95C{mn0GB_Ƭ2w 2a.fi8׻v[{?ǧlo7[ WR?HC\]eq&?̾/?$޴16 ?^Ee10k^_ʋ{7B/(̈s|}XA0mKjKVTjjۭѣ~_sv@zz5ab&m,toqgՉ\hz,<:F\/.\OVo 9ޏ{5Npgtj!\+"D.^| 3*^uqrĴT>r'_7a6-sp?CzN /IB:'#Plxd:OB}w(F*zq9rxZU[zUJojjjv2T/'$x ) G0DnZ%hNp\XFMODp8EFd( }ބg2+0;)*=.eT g`ŝwLMe85 *9#vF±M6#fM"uF,X8ҽhziXE y+^*|uQGgcqɁixWxpg@^%_-Kg"kP&w򥙫J0]a3SRTdSYY >|GunY1O#_7]:m5,4ح-/\HHLwՉmiu;]˪2$'Cԧ Nt=CO=UIHNSלҲ*'%CUE4NKl5`5z+߿eeeN<#v@.e˖NX ;"mD eN\ swBcvmҙRf~O:k(˽s/B)B+:p޼yΒ/Z||SOTO ? Y1nGuXjjjO6¼Ű*nmnymN% ,x90#J.9;Ç׹g)͐s>u ߙ3.ק -gdv&$AKY0ڵ3!dO wƚojc<>/jq8RN& J[{o+ctñM\J1%έIqR(΃svl2o}3@ZZZmIpbzqF\8sK|,g<'$M5LZ7 \SWn NruYtI]Ȝ'Ynݜ':f_`CI{$NG6Hnk&KOzz'#.&ΗӬBm OLD,54y o,1[}ĖWn"+ǚ}ڔQ .eGE[mжM<Q Ē&ahSE+~ZZc ;:.8{ʪaTK兩#UGb){D3עmrs?}]y[-TH>oq}֭_II ۋC.]8ގ5j@Ga m>L,)ʬ?Aeb]:a1ꨚ53xd8Fp I$??~A7$$ mKrF-ÅL5ZtN7wB-Q|KzϳqKwOtޫbdqt,j*Q59xmm;b8RgĎ&#/=F$߰a?9lqfx m>Ϙc'9I[Mtt#;*ڧ&jogC7ZS!GD~UU,/C\Q8U(6|uC}V8ɖ΁| ?ugϞ ;37<;PIbĉΡ|֜'﵅$M+bi-8܋ߍ6mg$Bk4,%7fY<*?J Юν3G=|Y WJ "##gƖ-[<+&31^;ͬ,pY\>)[m5ܐh }θ,uY\/|Me_#c7H#j*)Uתu+HR+ 5䤨?ri;}CxiI|9;8n[us8_Uqv4h;GIȊ)wg$N##iH = 8#ny8}{~;XJ`ũT1Ca9B+c(s,0 H4^l 3s+K{qFpfY XͲXh`='F buODKwL;ڽ>GEK /Z%1=->ڝsx_ Y~?;Eh[WMMHWSYqH>t;|X3p5g>qHxKO>m:· / ?p[]z饸k$r˶ rFbYE: ^\74,6#㌼: v+ M] 33O /_~%AvzIfn!ѽޡMBބvKbBr:1$R=YEU^)Ul8*rF|WӇB| ;y{8^@^8^|O߾} ZxNm۶ 83s[VUBr/$jMg$ج3<87\؃%䩈'q%j"?)BPh) twTWviI@ ? 7K[&ҹԻ2jIvf9?)m ~#n>BGIG2()kNp\XF<sI|{Lbf8u>}2$I|6Y X ? .ڹ];tYY}藅vTfc/t8}̉yKcG_JgϞʈx2rkÍ$R'7fcܘFd Hn83`3b!X 4NÚ/,8,ǨJ*[8Gl2xKvF|6OTNWSNjj4|;$SbC8q* ^}qF̟Fۍ]eck`IӍiXh'[[^<:#-ЫůҰɯ8&@E1xem-RDz6!gWEZ X X p@ۄqz[mC5'Pmg$Bk4, %7fY\;9õ"N! G{4bopC1$k6ٙYdP&e,3MVVVV׀b㌴*է(Лe'H9D=ۘՀՀI6 :7˂86\тjͲ<M ys Z?;g$bߜKCƈl@͑Xt+0t\xFp8Sgv$Vak@췶&,4a7 a4J`,nHJH%:5GM1Z]?I=\颁\gʥ$D}0ܽx舰ΨɗHnpYz4:|1>nZ.Z(P}o6]R%tZ8zrTcjӾggiB'SqJ4N51s1wǭdpn8r p3X]LMxy5d[ ﵀\5.zϽVb3fPW.t7r'sۡKvเNq?S#~Y&staJj~8U'$ufX2~fPG˗8ca6,گ`?Fo~>y'+.Ѭ}Df#'p G6x ҭK>y NJ+q_7O4ˀ5X<ĺs'Ĺ_χ@?;3=pø:nOsls&TP?͞^_Q:Xq!4ޭ-/Gꌼ{ GHߋA|5[s;xW ,ͻpL^J{=O#ƩW᳕sQv(J_lG$vøg{V࿇u6QX3|kSdUَ+V1ۛJ# EX ,{a8l g}᳋x!g;ny;]y<}C] k?)Dckw≜QXgo-BX*˰/W_w@J4 IDk ː"HX4CPaQT( :12(0.㠂(,LNBIwS}u\>|{9^Uw^Rf_\:oHi̙@F9s/|8;4=r祟+^59$0.$`-_>"<_ NBLU29r˼ϗET'~\}3NYo*W8O1c̝}M|;Sڗp5$ pCcq֝.2}NysGw' .;Q:di;/W"/@v}\> ]ͤy|Z?dytFxN[ḽdɒYW1Sdc9GR SseusD 2C1vY/j;gܜp?' ._:8;*lt?/}jd1g㬟vc IDAT*?Qjŋ@^>ķeo^XE#O]wܺ u! b)#o njͷe7^z#+`b(C S"ߘ}L?DdhFVێnFLsrݓτ)Pa0^[) dGKv ӭ3\#SCqzE13[]x+ϱʔ9V﷏2y.7ʓ˟DzC1ǛUJʏBcSs s;C qߛ?Gm4^#b/32tN,](^dy(Id3Nl 9ٛp2\)O/Lsny-t3GJe@K.`cs&|#]xV1%[P.j|CqIwȶrW:dII)[Sb恋y]Ƅ}-Ƈc|m|9d$Yq )Z$gN=N^=<9w sB]}d^l9 3${Af?ֆ>V-T:WN{g¨PWoL GI>B{uYa׮SdXgY1\Ȗ/ÎG}Mz\v\uYywˡېJS$DŽMk,;"|2@6MSwv0ma)cdu2s[d :0sV&39}&5tfy[+Go&(Y8WY)*3G"c{i8W0W.w)LVk"G~m\vrܓN Wp F=s`86WW;#Rw6;c@T&^/?bަMk_l(|msF_SrmϺ~_V #/k»0 yd(8qLmtrOrN9_&G0W+]q"Keѳݲ;+;J&tFQOnOXWKoex_?C&o!vO.)Ĝ"G6^gs!;{GM.}%z?ʹB=ʈm߮ت K=n{xI`,6S5#(=ҥ2tAr?*ϑ$[z:޶p1tSҹs8y0nsՅsL01q $f 8]2; ItyYx饲s|Գ톥υB ͷZl|p#!|p.lZMz[hDs^E!K$Ü买p>K?6zyruK9Z,vy#Fj2bcj3ҋ6ðy:?vPº+S/+p1\ٶ={|iF*.:SƗ&O^#/,aΝ/g^tdvmiK'˧÷^{>9wrInP@N=8wʸdngQ>vW]jHYd8z2/ˎ}Ȧn1ϗʌ  ]m'}229d2 6؎r'Sed ٗ@<=Zs,?L>rGsIVq{=aĸEe8"9ϕiaS?{es9^ vn0c\r3ŌgI8dق#bSrƌJ@Ϝ- xK Igzg_}L}9ne~#+ozxdaϑkBɿ]ygyL 'S|xO׆;C#~l#ps 2;\d9~UqWXkuM&"U\OFqV:N#tFݗ-[nP-Jm;}ǬOVI/0,[j*]=|h Mtf-?\ /mhӮW,.4׳JVu kU2oͺ 3F+|-l&*۴U>g99p_I ]gGBxՅ~nSpIGN\:O{>w\_'Ztqc蝿Sfz5\fH$ "\)mZ[Gw_>;|հ"778M[8gMzd=rק+*txU{YBz>_=O 7R/0-z.Dr75:k4>b" qVګ!lTO0b,(o[vE5/g`ca \}K '\ + \J'vuW=jHhP{C~ }:N4Xk3鍨}2c$ V>F?62F36&S~X͈֛:78ڔ6rҤII;gx0Qz6oʹ 8@j\lXt\nxyMnz>qꌷΣ.gpg@\ܘ8[xòfZDo1zZѲHwpgqXuM^ fčb[bs9 8΀3PZ~Y)o2A֛lg m΀3 83Pښl3vø"k0F6ڌ6Q32是14WgpJd76隬uh,6W c~h3Jm"Swgg ҧk13c*6i3͈ZZ$#= 8΀3BOi뜦W/ G@q1L]wgtMi?ڌR6JBFKgpaHVn0lΏmq1c΀3 80Zk2 Ħ6DA#1}`5-1םgpec]Ϯc]f3 ҧz3 8@9 &Cg>ƴ$m>1\:΀3 πеm47j7Oȵ6s 8΀3P.zktފfMMi 36ŭ8΀3 82zkzqQ3nXHoJxk#Ƈ3 8@ u:vbv;nY[oFo:㭭3Kgp`3573&ްlgި6s,]wgho]sSz(qzq]踘iFvs֛xk<ꌡpgyX u͍c7,iFE7u-xםgpg[ܔ2lF8*Y91,6c΀3 8ȫEw/q!m9xv 8΀3:Ejɶ>c1+ckd(o5+CoӺJspgDXcSjZgbs0G6&RX<\m~*qgp|/}j33Ʈb㬟v*?7ڌ8ER8@^݃΀3 81k.Tָiz݀(}(yôugpa@T&ہΏX(hl(!katgɍmX æf9 8΀3P&KHlj*j3N1F\cђqspg\Pkm=: e6#ݼ,}on;΀3 j21thNlcLKr Q|< C̥3 8@ z ]۶h_i;)Msv:N4\ks>΀3 82F筘˩nFܴޔֹ0hSZڌs 8΀3P.fkj̯7ӌ欍6b|8΀3 @j\lc7:.f7fݜfƩ3::chtgh_;q]sc:om fQjqj~k3G"1:ugp`577>{27΃-o}FN 3 8@qjk]d5rlF\E[o>b31]:΀3 @jkE h3DЛcƴ\ug(ؔڧk\)Q("OG7@spg KŽ8망6#Njej"o3 8@k =U5s^fd77J1JmA0wpg``7Uvc(j3J-(1Jl&c}.gpFjr#n[mFi6ð):?Y|9΀3 kR+4ڌEosd\wg(Z[u>Bv.h77K[΀3 80z 5Ӓf<Hs 8΀3P>B׶m>WNnFvܨݼ>#ڜϥ3 8@ ꭮y+rVMMi06ŭ͸pg 뭮ZO&:H||4#l'׶3%9qĖ=p8p5kb6kX6snzzomG1]:΀3 4믝1q̷6e3(8cFe3 8@ ~뚛@F͈AŖ>k#'rpg8yH.Re6#.ă7G1.gpZgHm5g"qwE`llmfbe1_cZWi:΀3 olJ5YXlfDj O9 8΀3@^O\cfUlNgF'2H G~˷{ppg5tͅ9M^V3%6 c 8΀300 c;1km%6|ms1>΀3 8@#5_w6#4baq,b>ǜgpaVdbMQ[mFՉ7F\ck9Z2Nc;΀3 jǺZ]]Z_!fdכOcmgpr@Mf=m}iId3|ctg(]ok6+m'e7#inn^iƑkmpg\RVSy9U_͈֛:fmJ[q.gpeVl[fݜޔFgpH[뚭uFwL3ތ8u[[Qg m΀3 83kg knLgMaL3J-7QomhY$Fǻ 8΀38ߺg/Qf3yPȉasg(@^m-RFn~͈ hG 6u3Kgp(R[mMa]5[#mFyXzsטU΀3 8%2RtM:c4+1?o6ZhSq;΀3 3W5W똙1vgSfIL-‘_vgh]suNӫՌF#F8;΀3 4t~ZmFEc%F !_d ϥ3 80HMnm{݈4baΏĸ%?ܿyvnL!nl n:.7] l TWΞpG|z|bA,22[oAט,q1GKi%}ahB^qr;'N9F營nGN[0|ro+<,[L^{ gN "l?^ɘ1c4[EZU+7yѲNwxrt&qrO /W?>}rXv׿Ef9]wU6trxβrJy[nnA<@9cd1K~r\t"2d [J}oJ]-2٪W%ʂEw>.'.g15Kưa2"Z+FRnZyvnIQV L2E~?Clrz>3tZN6iD6}Z^Ե /k:bs(""7 (Q IDAT"hHÇCw.9;ɸq[V|K5[@~#55ҲAprmkX>J,^*m%vV c=ereaSwͷ㖪s/$+_]-#7d1ӽek֬뮻NgzU횬p :$TV>%'MϦԬߊQӌB#_fuBö{_/Ї%_+C+m'_Z+ÇZٗ~SK5!?O+oKū=#|9^k2=B@,QrOs|X  ʚʠ-7P{ K::Z-$h\l55iFvsxk<ꌡݰrp~sNE+ /Rǟ~>[xwMC|š|瞓#<2{ό{ehxw?8|ޱIV=]f}k%[H{efdaGdMJ] 𶻫+{8nn͛7/x 7v\2z]enU妃eLx agOF|I>1eŢ/|L2N^ 7օ[b7~^.r/N pU|G[V_-]S2j-{I_N= u͍ӸffZLo1<@Zh_!M3^! Nw{,}R.^Xw.\η۠"7 _*}2ЌM0vs<|/;rb+VwmPxb%3J{d7O'3/=dLyq#VeKnO.r?'_|5<fO7Tg_bxD(y!Ǜm k3 ;(qy>k cX.Zj,k?Vi]NUw'cDJW^q rD!sbJ?9d̓V9@\XCɉ߿S~VrEȌ14/˿$׭rry{ɿ}X>яW&8Z^z~t/~ǷSG>iwg"m ڤ-;;hU ;8nq542|Æсo9.;Ȱ&#nk$ʱu6e78Vƍ Q4G\z.F3'eٷ˄q:R%5M=dHbш6ZZJ^m-R,Fn~䥖_Ƀb}`SgfM9 AhL:sxG g?L^ 0W;B{n3:ύC/fvЈ#ī#68^.\u h+c?!R~tWd伛zd~q4\ ȤmdtЃ%b<(44=|ưJ\t=Y[9o>$ kgΔs9ooÕQ%7eBFƃ/`4yN4܎ C Qx ̍/[m @W{Nmշ^xlaX|l.__)e9Se'gF\-37`+G\!u+4Y7 ܢYc}&k1Ja96#1`j\ZWHߚ['egm8fpEZ:\*y~KnRtЀ;n%3NیXl[רD'd{|`5;oKKEN\>򧋿ޞ+#t=lVۦÄ3)W|`(y2j!]OrQmЌz[>58(>l*ϜƏ풕kֆ/b!-ttxS5%ʈU]&2˷֛2rz^2ry F\2j~Wχw|MW5W`1gmqR+SLOnJM~w>(SlчOC^,n6z`E _k]bE< ǢRCf~I g:=,G|fL>i//;.??›j֝A=oɵ:U+Y>C]# ] N[:wݕ\T6"H~6oYq] WGdʯD6X[t-="C9@3 C|q؄>XC=Mg(@ٳWSЌ~)9\u7 k_ |}UڞJK/ɧ%: 3 qV0HWnVt)`go{%l@ q93|wOu?;CBӅAmr/O|pz |f`ժUrwgf;lX DY~Eyq V0:mWWGHlYZw /fykX/|xp"TSxUs>\uUP04 O>ꐰSgſbLQ‡|m3>װ׷z˧^w?HWr|t֡5xW{_'c鍨kJhv{Ln+hFge˾T]}hhDV{X>ў"N> 8ÕnρK7;pk]?*7/U=Zb*/R_ԍntVfr2όV+nwڙq ȫamT|'[=:}~aqos*.+h!ѡe ^o|ovkoie׺_xey_ɤ-_N͸7^L,šn:bSsTX3FiuޒN~#ne)^&2_^CʪUk;p8(׆?|7"Hzꩧdm}W1ܶB"I•ҥK;o=3u/g>lvK,{OmwAokbsmlQ۽˖>"ѯ^s۳>v3V(px[Fnӡ1ݪá L7 `h.tׄWg֔o]'Ov|xoݸ^ˎo)t|l@ {?PTQhGB~ޖ;s e\yK`xi ~$nHt_Q/w/zDnQ_Gx6Jx=!Cldo |< m~p|F4P~)zhB# |AM NtFc:͈ R7!`x H-7#26JCiom=G:mB&OA^zDwiVo"^x⅋ϒpUby3\AoXXQ\|gܽA#UouZ*?/+qzSZŒMiqk35%J򍚄 |QYן7Szkl6AY6b|8΀3 @j 4#QPemM>@ꌷΣ.gpg@\ܘ8[xòfZDo1zZѲHwpgqXuM^ fčb[bs9 8΀3PGyyH3 8@/kW^y|c#'tյV7X}_p<m:n.hMiaç6> 8΀3ÀnD&BuR7,#6vJ2?oIEB9 ,6qp,^όpZ  6%:hŸH>R~tuH΀3 8) ؈gFAjt 9Qό$Ey:%|hz#Ƈ3 8@Ј9餓FژL*j)uf*0y%e+#(mAbz1_젙X{ϒ>΀3 8 Ul8zWo|am5h3I5O ~nVBO=0pg0 ,^B2)Qu,}V2ڍ4FXc΀3 l Vu]Wxl#;XS)Càv$ KIx#IE&#N$%t΀3 8 "7WK]^Y~';JC;W#ӁQRVb*mٲe gp?Dz8fÂ:|ٔhW=~X[1Q3 &&g#iS:F\??}l N[x n\♂sCf>d3n sQ<* $<`3:}1krz| :m[̡ĚQ٤Eua80\`0D,1c8g.mHն |Rlaϯ0is^?8F1A81lPC壟T01?uak ڏX<>Wp~`hL[ʁu(Q21u,}elhCb Z/<mFX^un6a8:l8A0 3VKa;:XbV<1?1~ȝ唱Ο: {7GL?XzI R?2nX?3̍oqc蓚hLggG&)3z`C |A}Z"p^ut 6|,ҹUfY1#Fl*D W2A?F'đXHt[ Q'08R1gI*vR6ҌD8}EƒE8DPCc |x܌Dsj[c'CF^Ly y7?b`.\  skt TObZ1i:q>󆶟?qU[CdYqn=k ]?K?t6VyiW N?pbKf~nR?c} 7\4&Y[58tFfhbc㭌0G;oe,6<ڱx+c1ю0[a6v,61Xl yc1Vbcͣa2lXl cfh3u:mhS1h}Z ycpHROs`G3 s!b47qK C>h#9z1~1ysx}U7n8M~Joxu-zZUzJfS/$(t*!16 fA5C?uX┘1!9o̧k K_yk1y?Ql`xFu~{ʈs1FO2LUbU#6#&`RX.@14NGlhh38cChuN\ k@%F~,6<֟cl^L+ qs?0w}`Pj56A=&˱sֱ”յsh?0؅Gf u,\8}lAYt>F98A:F;~4򊩍ݘ_?8v}uJbA.6㙋ssgq1L'hb,ɍ8eQq^CA~L@?t 0v 8d5klJhqu`9 }u"WFvlC/ <7%cou͆Dg‡A88@F 0>9ՕȃG91q\`1>`kT6y6uJ⹲h3¤,m 0HL7"CGl6-f>·bd,60Ϗ3*ųc׏1bͣa2lXl cfhX18c #6=׉I`z (ڌDXo ?m~Xc͆kCaSj|=ވ0x EԼ_xJΟױs^|1a|06b1bQxOIk =60GCf8ɠ} pRG0ts=À:q|́Oݎ<cb|_a -mؼ4 bԭD>b8n}2/&9b|_a DCOn“*mwb?|Y;?zqx[p̧OK#668u,tOVj~Rjưqڮ:6uk;X.b1Z1yz^<]h=/GtuLs}:G:&O9Z>uhѺurOh]:Gy9ڧsct9Z1yz,~;I1:6c9ѯeJ.8F M:Z QF(f % Fdavh|42ge7p ss}lRx~Õ/HD[yaAܑ< ;lF(sև]/RjfYYT!Kb1cFapuyE 2#Frnؑ1kypI=NgEHcCh)7!& A:_?B |T3'g(B~^Q.ȇ/ZHF%)Y:!5;1f%}D?86d .\ ,oO DŽ.] HZ- BA7]27fBv C8W-wA EܾĬgT/g*g7"yx[q`%;bgKX#VkNJx"Y cEJe81>5@(y ;'O!sԴ<'"s|$!n#t9M8Ae7KO}齁k:"aT!wzd hfª,z6BP ցM` *punpm` aAH #j6b!ֈ#"!H$$!!eH1RlCv#ȯI,r D"Hb(UF5QCt2zh4:MEst9݂VZ,zv/A `1G L-ĊR;5w}8L<g9B|5 k:ލ_ 4L$R R> ywz CD"A4":@L'#& &6;=AF2#I,RtttK@%k~D2\JO>MF~FQ1q ̕Y+WAL0EbDqDS)K([(()(oeeeueddn="{Q[#UjJNk&][fH%hkhմsGrt9 @9"2Zkre =gȗ*߯ `RXPpR "]J1\1Kq~KϕHJJJJ{)1ݛΦ/寧*ӕ*+(تĪQ)S9@F&c-( VM84ڄU=TEUo~RceWS{OU^~^DENjjDjأѦ1)ܪyN_塕QV6]MQ ӓlahtv .=P稗QYo@_[?T~=G4 W>7R5 4*01z`L3v710aB4q40aaڙ^5Cxf;:'&9MOtۜjio^cmXjQgj'Njigi򾕒UR7֦l264?E66mlwvv+; 9;$9lwiSGg{<dwy>h w)=,ݮ]nL$]n]:, z}E?j(+zmQLs|q>q%q]_IPO%'c%NiZto01gƥ33g%?5X!).igV85=y~lq]%g))%)S]S7yxwϨɌ5[G6sbcc !92m-9:!Qq(φof{CSvK+'mfIHH P] Y6!qpEh ITwPٌGkn7<_W/HHHH]jJG:ųDFV̨ %r˹ZW88G:}!i:kyn S*i_MT[IIIFj\u ,Al@\ |Y [ KN:"#KK @&PY^v :\z 6zgpa7 5^0d!   hwlpԐW9ז)ig8!TI?mh"iZ 铎ulpyecfg<ͣը:}5zMmzh͵&ځCxK2b]3U S[c!-)OHHHsR0w "6lv~ 0{MW9M.Mq]o0H$@$@$@$phTZo!9ZĚi~3_H 2~bĆ?3l`Di]X fFʹں#o晑yxbi}D4QX d_y$  sqtܘcد&V-+yB$@$@$@$Ю48Zvܬ޲i=X L kq gR>FAM3lVM:&̩g@޽Q].#"^n>pA49 mA||$a32Y%23Ȝ}::%O/'͝9]x  hW㵮r^PX"FMobz;KV3EB8]rY;sx;!luHxRz )[*+FSQ!(@Xt^VE;~|M•Xrmz6v.߄əmuܬ~ܧh?M۫jSmE]ӓ$@$@$钾yuL+/ņU_Ee)R[Q:w!Imƽ?^JJeW3)67n?ј aJBG? ?wJƣϒU9F(iY}b˫13w->sD4rR-|8>0:;e JhtWЗb2sMR.' OFmc5WkOuT}n[9 , hUw$ʉ܏zKD3m6vp ~:ֿJwԝ3k+8fmu" gj;99ZߎN~n?<@{"DEmj{Z)zHH kח]\sV}y!4j 5zFۜ_҆|dvڴaӉ;K -V&6bX%~)o7Ǟ9lsy//ttL}DZjѯ" Vfǿ8pzYD /^eJ p] }'k   hu*;Rk[Ͱw~֢hjSDs^ղb?dKy~vtxe_9nj9n?['?YY|XТm .f [ jHH'EN &u3邐r: vog);0O2BC*pzf,}nS|96 M/Cix27ϭ5ƾ QQ!rV,p#*);Kϝ}g'E? \2 7_=]C$M4!kF_Ĩ| +?\N 3cԛ0涙j ęc{W֗KlxQ 9^Fu D;_&   "4 b,_76g!MlUcV'!Yjgͬ}{jSm}6 =8 MhSHlh@ETS yM/'  # V~qGY*NmŢw1=:F:_紣O:}ѕj_A_S Cј!x7_I>bl﹂#c݈(Œzm`N0whXtg\Y"=׿PoGa|/lN^ R4c;Jd[ [p BϔSD x$   @#Ђ3@M.ƥJum3S2<󝘱vǼ @b٬cDDQR0*i{}Mk.|Dt⟙Fjk3V妣^)Mb$@$@$B4~Dpnv-+jKv{mF}eKv.AϞdF}=up?,&Mg۷gdtOC. rۥC׮21CT{:דu 4i<:cشA`)qѸrE=)$@$@$@$R,~(FDj(9P~E9h^}ҳ~o^Gn6@˟u7ސ؁~DD{㌡lb?kvZtgzb~,vSw#  !`}(q[x,;wABy*RH.)鸼|XK)_{a-6/IP=vӶo'KŨu9vscX<*SKݺ"2,;_S ǿO<3H?"W mXHHH\"0B HOdZ,_ޥWZKp?FW-Q8iav<;O%h[ҙfvؠ MToU6E7H ;¿w cGþ?e+:uQ^aSmw^yA$@$@J@#\rѠoH.1ጞ2y&BoP43{`zge(]P f}=9F$;m{2cpH豭,,;9AR<'x8ϣ_}/O"44 O MWH\eKqk"߹^u.HǼl4:n]ݾHHHZ@4I8%"XŽNXUykUǧUzqİy7؟Iځ5TҢoP#aۑ4Fc}زK#KHEShdclc)mZZ} S$@$@$UO5Gj@юf=oLaاKbݖt|Ywx Q{9[x3]Sru=FKP֙fuHx<7`pExW-m߯]1ld5v.?*o'Xֵ%ޘKe[/VP)GgOs,$@$@$@$Ђ|XѺuCOnF>A,1)ʣ*y= s)Wm-**i)|kj>M9^?q1wC6O:K |{f[Ԗd!  0 cป |r!^xde /'}%n nݩfϱW/YC}%nL~&^[ھC1Sݷm3].FNQ],gN?]]7\]c,EAq)1o3LuMv'$@$@$@$BT^9G/饊`׹D;*T-gk㦝kMf!>i<ב|5LųpI6+Ok;M@nvHD0ƗrLL1k=GP[~}7;H$@$@m@5K5Ӽj=%/9}QLGɗ]˩z" Z" w߀a˶{SklY-{so>xwlby(~[0k=.OcXG1){<=h    hAԧGNXYH:"Ԧ ղ΅#ʛ&j]<3Gܹ3Ǐ76ет]kkṃ)TЎNY7foO9qxr%!V&N9E/H66 '^b5mvM$@$@T#$u/"D^K$@$@$@$@$>[@+8)YQ`7Dj %빥$@$prX$* 6P8W."M BT()tHHHHH9z hu+ {sQ-),$@$@NUT%]r9t`4EHHHHHH!P&Λ!haUU} $ZWv j4mgY jqhvB$@$@$@$@$@$p5s| YRRgϢ'<8 -8CBB(DGG{wsh`\ԕy { hyU06yvC8DI0ωo=&hdJTTT!EEE(++CǎHCtgi5#HHHHHH"P@񬰬fg=q6F#[?$[O?%h(Ge5JuN{8H }EB;pZC= 5~2p-ow5mSS6U<;muF̛HgEA>ƒ! gkJYo)BF|B$@$@$@$@$@$pn@|+*$«g=^ G~045Ү#Z8oiY$@$@$@$@$@$@hXJEEEkf<;pe@5{@ hnWD rU72Ʒ@      8@}>:'m3<̆8YHHI@9m!H_&ۆ$@$@$@$@$@$@m4\Ϋf |(y D Ǿ}pIˮ)Rbbbt[.뛅v}KAf/^ D最~N`,$@$p.o9r_|0~x 4ȷY H*y[TH6[Ppx(P}-Z{EZvLSZ9N&;[سgO@zjv7",,,`?Lx؂7HHHHH GeQn7$GСTDkEâ"^nj 5֮5Y@jV_o ba].ŔI#d'(= e? 3 Ŝ#Q# /ϖ.]'NުZ7;}ZE: A$Ps'Ng EPE"V҅Wv{I 4g|gUU 1"ѴfbFU22U ʹά?&n;oJP mGDIhHw^0&A]f43~/phr;U~%xANs6ǁ8lq˝)-7MZn>y@)SU8~2 hܜw•/|y77 \\O1@ 5M3<}o+6Yuᯩ?{i&VowS7`dbB\˯!OC 34L38B#2*EGGQgsUY"##֌mD*aFюDpz΁8T^0ųS0+ne>#0]Z*oi^Z ˩j[|#~mbUZ-6mh零٭[7TTT ;;ۯ]]8{P[Y|8b@T]jdqF¯hqdv=k ==Ewa"tv O1* 9..[qq؜#63B13!qg0i`'Z(9!ΜLx=H -9mI )if5zވ'[$eo9hNV908WOd>yi5s,ً=<5̋R2kr-2εA٫={Zvn߹sέL7ݺ~Ì]}Wly #-OymZW<,nطo_ gwy'bd!w=i&M2Xrk@m+/r.Lp-u flF|i|Ą^p}XL*>:߱p/0%႞ieo->_^j|Ɨ.!j!`Yplٻ y2r<v a> SB$@$@$@$ Jf5,NQȳpN*=]@պ_bH)F]Fi!4:ԙjFUڝA;hQG"Z֖н~Rةadف\30IǥreFD al3nW;`Xh,IdC/0tJ qt3PgQ!ʜ`񤛝ý*Ϭ%5?Ƙ31`ƻD܌O΅y_W.Kpshdw:8y_O6D3SD6ug-oWsbTp=7]g~zl=Z-d=c}7y/g>-yI$@$@$@$JuE`dҢju̢"qԱ5Ae`du̹k[sH4tTs_Rd(/ g% JRu+ksX?yTaP,ӿ6գ-t?mc?AUsAyz?l\o<"")T[0˸b"d >a3o{ zƊ٦x6Kt$ =B*i-xMd}'%; g,Rگn,c̽m4uK\E-_@?tSXRߚZ#G5qu.fK̇Qxpd>5%BN360X }&PQM#ncwmw3mSM@Ζ10c^r癟AxN-PX<ۿE9o5l!]s5ҹ &L`\hȊ6"7`Fd ̲a 7;ul˶(CZn̬U♶1N|"Q?8*;)is=ϴ }'>ճ']6>-.~eشE69,)KxU"iو77ά?F^'o)iV=Z=& W k׾\tOd>4~W39 M 55y;ud< &8g}ij/|c'Oak^NbRV.6/[uί` O: 6G=7l[[jFI倛{G;-9^U5/g'}OZbv!   C|#4HA!,">2mSwYs `#-}h$9W"5Qaʺ-#M/:S'GÞq*GNBygdw%TOŤ%c1O`$m؜N<,N~|_Rj~Ke{)W^'RcݯrrjK=C?0@*iC]rSanFEszgzhgNѾR17]2s ={ĬU^)3fw_ E#[XYK:/_'NMj~^2Կ`C`o]* wΆC!1$zH[>BjwSծ pk`&LU8w y"v$@$@$@$@$kUI*ۦOWHwTAHKSZavZ]pZNsoLVkCgltTΧy.u+0YXX*;:7JKw 28udggyW"8_ Q@l"I]p5"11H)mEc=pdOg67'<1GrK^k9Bb$zmQRK󎸚㼚鋲"caޖKusFs[22'p?Bرcmآ>:朧r3]9blMkOuDWS R"M!sM5JQ3Q0,"] M7uК~#5^nƙ{ Fc^77 `=ЇJ;$D9x>WÔc㭆RYզc[6a s#-j̮Mᘟ(̲Ym 4HuHOO_|Nw4#LL;1D6m;_4B&KC 8p;y>vbp8s#^w_!xt0cQ`^yxw[[|l\+d4KPiS:U~9QfMsCb^ @;%5"TaR! Ѫi2rHB55cœy]>[c #cm{s{;?ACߊ.tTqZ[|ZRz^D.qwKhpDK*՘-e$H_F|Lq. OqrM, {C$vr%t6wx?0:V|?[qC|hFL}l%tem@= ^i*;vx T<3Knn!iݻkgjKm4(FyV$=rع.Fv@oֿ>T߿=L^v\}u5ݒ߿Z 5g/_xA$@$@$@*2wT!%S$NtfٳgNeꢋ뽦R߱ܢERul!X֦O֨N V!*R1*FDUU;PY-;U&V%uNBΆxKTi#Hk'O72^xsq>}kX5w["ꦖÌ#"V|xu9V\ksϽ8 ǖaS,5=/֮1|x{l5c.>:)N3;'q^[ Ȣ5qN{;Xxf6R_{gVjwcXq-r*kmۻ[ކm^69/qx^|i1۔qi~vfέ_g["R'z7]8 +    Z DFF"2"aa/ȇaY[ҴF<Ԇګ BkT*\ eEw:b[eGsͳeF IQomcPqo\3u.~% $؋QTZDuL~1}41T7kc4`y p+=F^ZqVmԓ nD, ~\V|s\X3G/W>܋#ObS1gYeoa9.w^^lPV{k>6|*jSw\_-sSos36&,쪇fCmOkc^^lJkxcK>srix\vͧ/IHHH6h `fuzOڮ>SR;kV;w.}[ϵ)Ŝ9)>s0\>Nl!w7[b@G3C8,I Y4lGlY"ϺtblB-fGtwqq*pM@涗t}OۧU{uSn }OK,qeeˀS>{qm|0.#:mt"cHKxvmEm|.%>]D8ɣFN"v5)-;m4|!kwaƱZ9ajLt㎾o>2^@ĥxt)>wZmm,j̛$ nF,]4ΚuAڵav@ĀG{6Ŕ{/z$zqtut-8VT_Gճr߷߸oxxyR%Z_[yP)(^祑g*vu}}|k^6vr rJ%ΎbU@LBn{`":&vnDbĒ9s8^+8ɗHby3$\R;&-btg޶xuK&fexGh Sfc'@ygWM>7-aS\v>|njxof?ae5hOj=`h\Ws,/<~̽͒/=r<_ʎR; $!/ӧOiL״o/Gs/7-Sb/G6v ֈ,v|ߓpŠ;,*GxgBhca՟\یx^E"()(2Nquǐ#[mu̱XX"\[sɳQӢHKKk4q>ozm,o퍮cP*3@^̅ UA|WӦM3٧c(iix"=a/_9xk͸7ؒqnq6bVomk@YW-5(K`̣7F=k@8S?-Z(66Lz,>~;,Vqk yHHH!(T,u QI4M4HE!T(:}:u@Xש5QjhTeknC4ƜE3jt1}eFȳn{:3?(X].0;ßfԋ*]UU{a' 3WpCȩ 1Iޮnk4Mč> ب3&09K^36-z ; .zwO?l]O~gXK¢<֒~ o0pdzc,XgDy5O<)ij?}kgN@x%jH$@$@$@$`lDpT\ NZ^kʣ]sD>ֱ1T暻\9"ZkuYlu8?+h]khKj+#Ў9 'A1<ֈ@3{]'kծT?.s}FY lĪs#g?l%YΠ{^ Ƹ $E7L56"м٨✓ɓ$]ALt<"S:Xv_ `[D,(Sj 'HJdn|b" H#8s[d;@Xv$Fv)e]#b   8 "H4Ttxj)III礀֘P9;}a֩S'#j5Ϣ" N٘qGVSB$84J4Y^Q)U&yaϳs (iÄndH^z|) 4@qyD:}NZVI6Q/ LSSn-lHLM7nIHHHPܑh4D4#mb[{):Wsp3uSf*hS A@V B$@$@$@$@$@$p5MAR9UDF8 hMNA 3o' ANM/[5NUP6(sU H8  ?"/il]      @4~ ^J8)"کji#]5xZp&$@TN,F60Qga=     8g [@3gsgZDUUI' lĉP> 6~>yΒHHHHHhfQv0x$        @pwHHHHHHHHH(5 /ْ 4cs        EZz9[        @`lN$@$@$@$@$@$@$@$оP@k_7gK$@$@$@$@$@$@$@$@IHHHHHHHV233QXXؾs$@$@$@$@$@$@$@$@4[kz~:tÇǰaۑg3% :fUc_gqo/&6YZ!       @J6mΝ;1vXݻYgmy3G܆L2g0ʞ~ﶏ d_>.?)s$N{o];)I$@$@$@$@$@ VMN1??ߍ78SK<bs>>)vwޡM&       &h4_<Ç.3:$!%k#=5Wi \qa'kӍȴfƅƜ+2ے @&0mڴ6#     sw.)@Mϱk.3iii8E\mo'+्bo4:d/bw1iɂ l됊 5pؑW&!AT:{q:zg[T\2ԺޚC$ 4$jP<9lHJOE2HTr:XwtVNPDu^=SI^ 4@L564[~Y랃)♵G8<rDe}ij~׶[;y|^(Y"vdyx}Q6eNCfaƧ1<m, \3ۧNc߁)QsΛSsv23=:hxj WLH;TK lB$@$@$@$@$@$b5jсl2#*<`Cߺ­kXBzrl0;V\jZ\x66#C&aĄ?ymԎ~3=;?fң!E<EYkkE<cxc<%       /6)TPY#מB7߀lElq<7}xoTWWˣߜs^5bG'7\sǂ8G\5:wq]Re-4d'gj1|ɾv<뼞z+-9 ݌>fe={"|;Ȧ53h IHHHHHHHj%Ц:`ܸq.zm܌ť$+S½^ފ~(dKJ.vT=zUcO9DÙG؃j<        xp CUli/]]3qMX+ٝ;`ڋN7@hk\ XMnɖ6όuv}F/EQ[@Fp4=g'q)>7~u6@}USSj+@ށOK< @s$5he]aÆ58̟2]e혝1 5YoǴ~f6Jϖ]ltf!|v摮Dg3V{޼q\2gc[x/x&w2ffeV Ag~fс-~üij5jDV1 yK1,iǽz,|ZV~o[;K$d.$F^b"c<9DZm.CxC!Ha{jK 8C~{gJ+ٹ7ғkZګvcĈ8qt*nd9P[";vEzj|֊~󏗱m^#r㼠X \UUi:(*%SRůWtАFH^*&ykIYN2 GM 1ojʔNbyL3Yv9,=Yzu9Z:FxtuK(GT 4ֽV_3 6W4;o[K4>:jΗ i^wS 1BPCi:jƁywg{Q~m?'t?ˬ啠I6uriCיȐo;UuI+&`L P/; &h~&o3j@%Z`MLz#S(œ3bƨV1GYfDv- kO Vr}4OہfUMY#84چTJ} ,)usZHw7`Dynũډ.i5X1 8e־kiuۂSQ!Vg;!|bihXoNlÛ<*`eޛOg-B[.6) jkBu-'֘HSYiX||8qmĉ=iq./O@E@+#KM.I֌cIsmc&(u9WڡN-L_nteX _d'4,+DOk )`WemqÏ%xNY4U譳:##3" ˆW` xlY@q 0 5صuL,OebeM} %*8t]$&`LN"kIgh.a ?3rJp$f0Ӿ uƳqVa-DdsYMӁ@ż;ޏ6L[KJi%9M֥Ŧd JJWk<5;7%${|!g"䄤GC9u%3lJ!ZP?d&u 3=YD-giۋgF£AV3~tëe@ Ύ gƳ`2I!6}H= " gx&Uf!+҃VoHԌgUJfgiÉ͚s`9qx j:˧uП% D?ywصqiѱpde<)"PmXP3GD(h:ƌOGI L>a Ƅ}u)&`L!;Dr7`-+0 dZùs8[I5"((w?"ci*26di9J\!dl]?eKcYa7>쪰6ԯѽߣӋU+uiYQ8dkmw1B1ؿ ;%Aɕ+MTcٖ8+e'q+& 7,ΖkܤX<Ƴ<&;qϕʙ 3\6f|ZAҊ8[M#y+.\Sg,!Fdl?Rsʌv F: ooѷ V%#*+t(?- K!{u6Ν$/q ؐMLymSH}idu]t>;C!Zr+s=6wHR_Б|t!38 ;M2WVLm`YOV2{d48% G`L 0;3`L XrBY+tj+(=0{&DHWey-DozV^q^ݓQ˥RZV:%njko4CpXc5峦vxSV0tL SuYi')O0(n(уjeDcq R)\پW1;3<쭗VS9 4=UXMRT#Er2b}(KE렝ǞtLT˲gK4T l@H_IBEv&l 7~82HƯ=޽ a͎`ʔ>,mO+yҧUgÆ-|ܺ߮#gQ8 6^Mކ3^7dq> 0&h9ߕ7E'OAAA 让UK: WlS7`L)UPWgܱO񟌔?Jk=K/9#>i<&?;eXZ|\PnHd?|V6_SRsPKSOZ>"(کUDu{_n}$,Aq~ _HՃlGPX1^mNbd/EpFnރbTϖɋG,9JƠga6ڢ;l 5aCb{["|q袮OfUzlA!5$~2fH 7J%hh,8ɟ϶OVQL%CIjt*mje#Qme84sv߃6&bgi#a :6Ls;j^7Ըp-&`Ly 8ӧ镸t@Ĵ{ZX&ՇW6B9b_ӈt]=ϓPڅ5cL ܾ\=S>~lՉG@hKcx /GPto'(E9ȍJ!|FJ6WKg{^\՚UaFǒq.MdxdT/zŞ}{Cr?CL̀yB8璐`AKnk-ΗEbmi#سJӳӏ@E>{2N&n޾Z9!Ӣ :4 8&UI1/DcHiP0Tiq]֓S`L 0ە@0Ĵ΍7J/w&BTa NnI z7V{=< VƋ۠o?ic~WRkTxdEHFzƒ_bnӵQ&o-&cmR#7#]a6-16a2p4cSPR ͵6U4qO6]q6FRjޑZ+t.v/VRFϻԗBMwnLK'GTFT*:+ WۥL+#O{yOS^N_L p 0& +ՇE9ݔcny.v U䎒bJDeb"1̉ x$ @ȳɳx(D`#o"7&n.իWK N2Ez|ϐy4Spiaes 0&0YCV TTĦ^R[λo/fR@'N69K#GcTrP4Poy2f m%9dZKF{ga7Y-oa`L 0&n -r g-8%c$!fS2tז ?h;p8`L 0g ̴R<`L 0&&"Czˆ#СCێde镜WaI};{|ʹ}|$!6I͈YE`L 0&d\=`9Vm|}m:%M#c?T_ cL 0&`L 0& T]3..Æ sn3/!]iڢӥ-UR<\ga! >H)ڊiANYL 0&`L 0&`9~pᖨopf3wKTFXz)SH*w`L 0&`Cm?ʆFjL 0&`L 0&)V 0&`L 0&`L h<`L 0&`L 0&@=؀VbL 0&`L 0&`l@1`L 0&`L 0&!zp`L 0&`L 0&`&`L 0&`L 0&P6`L 0&`L 0&x 0&`L 0&`L 0z8`L 0&`L 0&؀c 0&`L 0&`L CrrrPUUU:`L 0&`L 0&ZTɓ(--EPPҴ/Xw(\uOi۩GZmI.10)%EYZ6QK/[`pᦞU[ZpZS)c)fYL 0&`L 07~W)W}Q@.x5M7o>"44zjJ8<2 l66% ݽ~4Y_ j~PBӳŸ^N4`L 0&`L v/jU\&@F4َvn!~vƳV[km[nߢdGK.d@)Pr5 yrZ<[K g95ܺjSsbykCf}Vwc*i0n'+`L _}]Eأ.`L 4+#V#=fM˵+v OOOjES80&"p5\p/^.<48˩Spu:A:x4>;6 cOcB({{0U[j蜭41׍Bp۝J-~BK#ma8 0&BBo >`L 8@ oW0]r]`L;0Ί׏?s&",+bZxyQ1>>>u>F);  wSU="/Sˆ}yaS(/)ByZ; ztwn NX^+.bkmѱ٭0c5jLmpxxg;t6<\K\$y2-6B#7 ̞:KJ3]kRLnu!4J]{:LI@ےLѳGaS""2hb9J*Ztl5;h1U[}Fqd)~&˾L.miQ&`sC`L 0LeAL46&UCmŏTΦټ+9yĴ΍7J/o(l~f3}ݾO,%!Yxlo"0 ]uYYx_ gw_k.0{b`'8"mhі'z|!50-SL4U1:T3 $wdL.d3 'ã7~ႹY%ԓ>S@ @켻A|ShJY@ 3o%hD_Ϸ;1{?5VZc =<o]<ݏ=6aQY 0C*~gL 0&`L K@y&֥R L&ЄĘcO -ʀvWj/\.?dzbAiNޙ/ Bic5{ Dz 3]` ?Ϩ/Z jkږ>7eǑZ}įҎa1:Hu|G3Rs(X(b8SmΈLNjc[3BaLeAjz{`А~/EQQNny p 0&`L 0&`" SLS?e1&01gOjXu :cȐ!Ͳ+=EAO#%e$ Nҷ/ŕf MDa9jnj&].A1QKsGQq"v$aE2(Eq1:A|uoẸ8Ok1LzE%=XT_tїx{PU d߈5C,7![EcjKSv.ށ6Q>=VB8 0&`L 0&@2h1" hzvS. 9iNy訞و;ɀV],X#]y# ' #8XZ}MlTfVMԪ`OӞ7gտcj*x2>_lݘ5yy9!^Ӿƙ!v3&$f\%09501]SLS6[jpC]SY|9,̩."}_P/ }tO9U_KJVɆz+;L\r8t,B6߹Q-jI'L&Q3 <>DԮ蠈lSEimGiJ/ gZ֟>o1E'g<|X{'7=! ǦλQ ԢqUMW:zދ{{}-݅yqxcF]]SDߑ$y ;ʻ up7c{A*0&pGL(׹%[7V/{8 w6C=L-<Ӕ$?.nޫr95 ЪٽRh17ZY=2ɡOe2Cw+ .*,>-:.GVE#=6÷*n?Ci9?/*6F)`#,5RI<ڴi6.(!6` k4ykAct>>|)D}bӔslnmgU!kOĸI0&t$D@tFҦU._B5i[q@5ǥ@ʐ! ʴbͩ|x&="[kV3xUjKF\Bk}xʷE\uWPElnuqMJXKҷ%r+ ZV*A3W`~gV,͘ į$Q̀־}{GOG46-lN@-.U`c"Mjyȭ E}Ңʯ]¤-ΫXܺ-71ce2$}M~Y _io8fı}$m%tI3qozV$}[.V8 wg;xzһxu遐藐Lu.~tՅ P׾r QXx WtVJ%OBZI\ȫ"y6Ń PƓ+U`J]U%N6˭t7-PyTq)מhYnMLf'Ovp3zk>1KebA<\]w/HP- `έ5SjY-IߖKe!L'pv:zuR2.xK2l}`;30hX(Ft,n쪰gE2 QKAo z8B3v:JNC`LK 0zgd=# я }Dlʩ]H @Ǥя=C7cN7hJnM)kAZg+Bfn/>Ќaf}xry-.U3f4\؎HŞ^/TSά =# R0UPbQƁҽn\ tW-O,(ͬyw#N+2ClftU52E;bw1uw!<))e UeV_B^ke&)PHq̒4)VYO U M{i@)ފtd. O`L1z "MQJeN] FyjŬ4ERbEMyU~;T?Kt2tVy*@i Ff~~urԮ$SWmVTy^_K-1Pte,N)]𐦮)HkΗH+8asi^W'g7T( Ptu Բα0:9)(*‰ m*O}ϿGc섬 Jg39m S}ߍ8xYJuܹ(ոs4'+pKO؏y/$9)PUyFy;]YQǞ;73/ЧpꟅ烘ytF>!\nt̢4rBoP({=&O :+vN0^ƂzbsƆR.gfIj&M1^o w&n>V8_bʽhHMߩOٹ f O -sL N3y )uWMJ=8~- حdwsUNUpLgG-RN"0FOǦb)3%UzcwѶ[ʬEyI)~E۶_~i=]!!cu2BhݧAm5.^%y4švDQ0w-Q1:4͕` ;4w @-44]i)cnN/^qM0ҐtϸBXz$mʔ){Jf)ݜRIY=\}rg?f zI8Hʅ-țh^q#㹀(ZA_5Y4[Nf#v+Peb\Ʒ´G㨙`,۾:}k ԖI&ӟ􅔸%VEeX2 >O^']È1 @0ړ sC$tErx%R|ID9 /"@oQT 5صuLzU5@̼L9cڋ$'X\"$2-u ʼ71$QnHwcPp6MXF(yLºbphbȮ)Ůp!Hoχꫯ{g#)K 1c1bo_b66M/ԕcw1{zWa玅) c $Yw6a`;*L2׽<^S^Gv$hyר+zS, lfƳ`u2.F,g+8RA&Hx&Ή&2 φ!x&tAɝ@֯NTWb'ڪbjr&0Qñ<8/+ziM kQ,<<\yrgưm^Lmev=ʱP3)kLHܓ{G 럩yj]rWWO@H|J+3GN$3Ö'й1]A;4_4M;\e!C>vx6+(o֦9τ.+IaXWh\z"~U!GuQ;`7@1]txM>h?,T G IbxFV2H6/顎d<5[wؗz}!쌃'5{۔\;>uP6?a3+y~?@u7LY[nŎ+3^x,ّτ>;ܦ|(&;̀f`MJU<&]m3tbF ;:W+Fbx v5ז"@#F-L6\~|-;q89VzdYvU^y{k-נUHQirݳ'1\ņ=8[qgˈ8ZțM XXY,vHR3WکZ {W"a|?Y/{C6Εʙ ӑ- P MTē9p/K>T%,cn@aYdn4T&=՛@G?ΔgNB?8iRd-0%pTZֺRq(p*F1NT_)br!<1(oҥTK;M;ͧS`~ŕSџ<l[D/bd.Dx=RX,ZQ$'_Kzij>Eڧrԑ) ?ː\k\5^WD4禸x]8lD_S?¯?LާP7h_<>KSS4yg3[3NU ZLjwO"kWܮ2ϓu!;2q6g=8Fd[\ 0$H2ᑈԞ$؝s0-];OHN98#ZNDsoqNN\2( ؿSdSxWuQߏA~4Xx'sT*Nnhb٬]<ǔ8}U:CW_ώJ~ ~Rt*sĊЬp`L 4DR <}5Jnsi3[zbt鐔&R?+)y=\\ όzlJ6e"7o<4_ֳ/VN6OޝtOFiXL\y aUo,-fI' k MkWI egt&zXH:(*'A]izԪ-J.MqNmBjpteFDr0 8I9CЍCD1P>?*ś}% c;vnN9tc$#*7E~CD/u:{$;0OJ/˶WzPg~L#v w?7 N;Ո(8ch,d}uQuw&nFR2K"U`\{QՒ n#168FbO%mcԟRL 0&Aຍx2N=d=kDMKӺvqqMV+]/Oɔ! TbzFx*E븮 vitToh3dGm7[ILqNGFзHTap IWl֯GX\oʽN@X?sĮ&"^n"^VzSSĢaDmm-j^ w7!ܖ@Yz/Bfrj7<>%khɽtcEX>aTdA9Τ6*$9(gř3ɀ,lڱTA T}63&>~~y)t!@4P&+wR:uz3bB䘼?Z>z#1/U OkFDx†.݆ j仡; 0&  21C4K }u$2fzPȂ<`=SҚABI);qr ^hx|MNeCʇE!onm$[ِ3Cz}Ǵ`IS0!n}u>^!d̓9>bL 0"Ҕ:ʼnNP|vD8ܣjLK*s?mW!(Cտ(y8 P?sH`]񀌙85T/#.+bh1y6^rB1qr4y5$EۍȰwR:ab@؅wmߌvOF:b6NɛQ_l;i-|Y}3&pGh._qvUab]ZW<9z!)imvCkO ڧ࿰_R}B h1Kr?C#]XZl ,™clLi͝on© ыХyKN=0Q*t08`pÃ#CF CZ4zmb{PDn 6I]3pʠСҦtr[xɚ5FWq?]٪n@#ΉIx)P? @*qEC2 #;@Hkc. H ӡý(['cNkMўy:,_z@U/I-=rQx'Б~eetKlX^2ƔQ Fim)qfYC#M#WWpts#ճ2kFoBo ^1?lhbRnyf3rDsh5[H1!=tQ8JΨ׮3>=߲$&hQۈowmHk'#qL7BTNh 2Vz͘Ug2LsBwӯ`Xk ? SmϬ6+y=z ـv'E`Lf0xc}6%剞n^jJXk&F".o.50zi12}r {KK *9u8:T-212I1E![Yͭ ~i^2È'y7ْNm DŪu{q=д]&QwL o`7dҽHiphG`oCKJ mEwtĹP6bC!1)W-Sx&FIF~%ΈKi7RBC 휈1R@c$H5GDohxX.sE$Q&Dx ~=MvTf АU#l8 Whz1>)hF2k|~ (5^o~#g;,JkJv"walLƐJ{q,ܯuW=?G^k[ DM|_ДUS xoΓcށP <_>D՗+vGmV 0&"zjSL+UJO:2Jl;2QLc)4#]Ytb<`nY9Sue"d@Q Pd`v=º*^YJ2dאSQ!dC;MQ5؜g?j&P)>H GQf-uӉ64C.K#My4"ųk 2q:ei=X+H!>(ըIxq#IVx&Gə8:Ǧs Dc Ӹ-S#W_!4,vc&*BdMHQ$0oy!W|y4هj_73'~jCKL Z,Tҗlc)t桤U">/|%4e޵@YةkHia0UuoE̦ܐG7Q/n_NQ1 O4 `Y!vaJdh۲8~%kW:lQǒ({Sd"fŠ=psUr5-˗+=Ps7ɿvN8!}OhwtĈ+UE6o&`CUz,Cƾ0^Kbg+Ӫ<Юg.}oU+{k`:;@sfL 08}%LA2o$Icr^,,v1bΏݞ:. {V*bj"---ߙDdx?TPE$hIz ]["{#6ؤnn+Y7M-}+< ='KL8jvdlsLȘɲgZXz3J, ]Ð]$_13cwzLF%U\1%O 2?OZDr=dӤ͑&&А5g聄+0!D\ `0%>*^JoksÞ@([WhK$is8z?SS}r/իo0t=mԟ8}.!MO[_8!mZQsuW+g @g<U_HQq36|3&Ͽ^en;qc1&hJW-A@Ӽh*^\Љdhj4Itk7Ws㝽F&*=spa}MNm .Yk`tNVh%$R[s 5kY)$7w֘'}k3OA}7Z+9}6͇D/} }DFʣ?t`|א=6^_I&A;yXo-JiʬA$:7!]({Ѧ(0'ɮ7 b4:xlҥv8 4[O^޽{32Ξ=гgOwM;vSbM햺7d'@gr恑`(f޻w׷z)T]0$2ro`0ސE Ѷ\ r֭CN]Q= H@}?ML7˭Lghߡ=U Ĭ)o};Sz.`4P#*=d @h!"w'f@BgO>,M {U:[-FU{[|)hp$@$@@]?=S3B$lW9P)ײwjæ"&y8UgJaSW`c11ꁝyu{{ي^1kX,`cѐ@LХv'G N ** NR:Iwh4R<\thg0k@2 MNT:;;${HHf pgڋ/[@˟ft9Ěn-}X'\3l]J=4;7Ff)|_vёz*Žw6{C [PNŋHi ccbQm\̙3kv\hڙq`#`Zt3@<{ dL ~7۷/Fc - G+W kKSwTX̰|!y$3CV2dM'}|V$@$@$@XN /pW-^"VfB$@$иdL۶m!ߥqQ?ׯCc!hOyGh.7l+W6FpVPh:,֙hRHOZnw3-%+?}KsltD0|2 #]e~ G Υ'$@$@$@$@$@$@$pk 7jȿe:]eeR3) ԗܰ2;e2-o{x@_.&lSE3Vgb:fFz7>:#ѪǗMd7|~ՑY}ET9N; ex[9k]<d+ޞ<1| I}&[.u͆ӤUؼp e ń哟Ƥu""mX|0a27֑ \w{͈w"<' ! `-RhLq#XMnA+9#b}߭+Usa&lڗڇ ٿߍDZf DZsGk?u-:#^Jjȋ$@$@$@NG v @ h2So4NKJ#yҝPs]LvbgSS UWk"eOG h3F93Fd,IGg(Qr28HHHHHHHH vD@h[I=x4K $4Ϋn<{(:vޝ~ºp (Jn]| bJƉa3wmo0(\vj=?i]OEdPQ> ֒ Bʑ难[ h2ǽ7cQhG-ۦb2 4;b0x!iڌs-4}&ӗģ֯QPbZSEХ8*R4]rfh}mPCK &nV^K(Dv!: ^CePf9c#bҤI0]ǻlt2Qa.L|7i&VM8ɶ$@$@$@$@$@$@$@$p 4y L|Ј3މ^Rl'谼H/Q^R2=9W/DN k_bTWN        M&wה?p@ij0]2ԙiК(#0pn$[MqiSpUoKlOwb~nܚHHHHHHHH 4.Jyu#f6~Yhbb ]EȈLQ4^K*,X*= 1q0p7bH!zje&cƌQO(6/a!     h4uth5]A 4€j%v%       4O< Og#@$@$@$@$@$@$@$@$@Bh *2iHHHHHHHH HP@ č5bz.L-        *L AgHHHHHHHH`#HHHHTm@IDATHHHH P@ AgHHHHHHHH`#HHHHHHHH P@ AgHHHHHHHH`#HHHHHHHH P@ AgHHHHHHHH@ hyyytR1?$@$@$@$@$@$@$@$@$P#&N8UVa).**PQaKES1M'jwj"m |b ~h mm <%       `%Ф`޽{f| Rqt5"#9EκS %RPJecݺ,eT̈́aA2kEq9P+ V }#1dy9Xu됳W4D 7v&       43p>s%Sէ[@TEl/PHpͣ^om+VNz"Ѡa둝kT:9fWؕHHHHHHH6 # xdکS"%%tF 5ݰH%ޫMHCb=f&8X m /zH.LܷoFa5fhCLPa.*]jimâڠSDWӚpyi!µr%'qQ6wvBt* ņܥXyT*,bbbgL5 `t1^qn\fw96S +؋;2q_7>, 11ƻì%       =54jjʙhRHkݺu>EҤ< }>>j')w✦o+9S0vVf~T7F$b}_D &OvUΒ qpޮ|#笳2?†#W]S+Vr ~>sJz9c}vر#Zh#     N Rx`2PRR^zGZHMKKOǹ<(zJq6z?#^,v b\my"U_]!Vz2 gvZ/vgqu4$ͱY&~[Ye_CmR$$Ӑ\C%ί{2, 3)$7S+_ՈMk oEP|u9z4QKٳ;,rڶmN:!44͚5 וe._:w @a57_?]UmN#ofjx8mQya&Ts|y._=,y<(#z`Rͥtt{uBij/qI\urMM;d=VjU8y` /Qn,>(8c7Sm].=te)D.Hw2m3,< hժ)3)1^Ko6-iSnpTIkT-yYS*x RYY!k?=r v LNHHH2/N )83gpr_h,PC (g)3FzN1ģkW5ޡ΃$*be/իZ>%APgںd]ͥYfDƒtdO-a;?i˽e6ZKu6&,}t.%JvP.dʋ&V9ʰH]{7( $r-4hDEE:p2p17o۷GYY?xi[% y%uv Dyi%>BA .R=;kUiXہ䞘,kGukhe@xȍU 9Uj:9 Q SUƙ %ڽ NhPcoCXQ&EˊpPhTHK&bL?UѢX~L~nkڽvЉ+LyyK~Z"Z@\ڟi LhT5B7XJ⏭F4Zu)SD͏(Ûh'uam~>♸lڸ0RgHK oob^X ڑ[ХZ%;?)ș hQr M@ @v3r9sSz!ʝ}B>zx-SN a.qSjS.xB$vHLTRy?[p" (yX Wôjo}LcLaHp׸˱Xֵ7U=M"6,x%u26ͧL_Cƛ0NkGvT+M e+cXLFFǢ0`lnh-ك7gOvWQ!">3sA9o1'bނφqs:d]wq +'hik#JKiӆ PW w=|]+˱嘻BVkSC_1#7?GK2Y4cbs F)+)z+1rHL"D9Rb5Rê6DZ$Maaz',|H6 L#4i&E8c 4Dk۶@ż1QD:'x^KY0nx&vdc(wkYO;3c*ӵD5bnxlXb.=l@Ý?<6Kme#lgO7ۂ'Fxdwϳ`y+5su{`>VcOgЧUq.˷{c]<3& V E5uvEe   4&rydddt3H$oxfr/WJTdj-FtX3 27230:.֞nh_~4d^xgD"c{Bm7w}Y8俱)SB9͔hnk [7eM;.:?&K/1)=4.?I>͚)} CՎN_ }44HORght=j\)U t$3ip0\97؆D mþXI"|~}-ŒYgxQ!g7DR~E_as9RerְS|cD`1ߜŦ A`<ɑksrwՈY9y/R1Mo?E 6C? UJ3ijsn/Ul" ëuIW>h=UN1Vea-un|=|J;c;xV:Z@>]d؎HHHn9M*5y<o0̰0=j գOםku_ŗ`Y({b0m6?)R~5bTbKh@|U K(>YJz'͖g}iD",>ݫ$% }* jm?jTc./H8zd*Ԋ aZKát!r@,?Oռ7 |Lkizѫݓ@_-&_M*TEC:H25)o_Xu]ur g6c[Oj1P8IE-?ؐ[hr QF7rlމϧjd]ॼ._r5mA;ثRUawD:M;o>ux>ë#S8; $i#jhVe=~*R@#Vk$HHHH6#SSկ~1"#Dj}P%kOtb?WRD)(8mO>jc/=pH6 IU-dʦuwGnSTOTwL}u82m}LX= ZSɡ1(EZ4Xeסt꼺^h,DXEv# ܬpݴَSQ=Ue(ۙ4{ ^Al:;}d 鵯g1<1k#҇È03/: 54\kUՉT\x>VQ6|mcѺo~ + ko[ׁ[]xHHHnCU6væܮDm9b_kzksHz.񭜶ma  F"Pij81Ed[";%o^LN汑H~)w P,ZԌ8Ri?fa Ŧ=ؼL;f:=ǸmD:Mbl 7=yԴjo)>eO=YjN.~Z鮑YJy"6=2ǿ{SE_h6NCozeڄcB@ @` 4&ufHLSC 㰱Xz.cR#lށ#~Eo.¢]p7~s {9,q1J!fa웚: }4QmŨ^o"Xr.zIl&nY=xؐ@|fqO*gBmQW_}BQX*ƩF~]٩SQ-a=Ƀx6űJ>by׆7^/)gtNfZ/ ԗ@TT, *vMib)R,#9IJ{F; ^F`iK=]<ܹrvN*'b?aYr:|I&دU(v8 V~j}xhUtH2='t%f7ZXS/ǣ\w9\aNvkhbZS?,AﶮJH5V:P;J P0qGo!=Y\htC?| iY6;L*V\ֵG0Q/HHHnħor$@$pXz21c(<72p}!<<\}.#3(ώ'S|Ӵ3zM)4JX.]Q־ m:;jk ":*1] Xt+$9 QّK0{Zp嚺Wш ֻT=@ɔ;2M3y:v3X/lzhbZHa5u#8TgXFZ *f9|^ۊȧR mH)MIH ڴiSNA iR К5E~#4ͦغr n?,iHx&!ÆSh7!2bvQ8Zj"S P1'u2/6!/Yc:; (' zko?#\%!OQg2ml6Cgf UuiB ƙ >#7D$@$@$@7Ac -B ::ZΝ;D]|dZ˖-ahiP"(" FIbcٽ-E`'u3 ܼt u{[]l$ѺFu        [ $Dֹo>|7۷5بlm3(9YUUb(c"\Ƭ0qUԄFzIigr& ƥ gJJP~"uDiNbe< ' LU^NTƫ(2nHDqX񊞿^8D+ćZIzd CN$6IHIIBN lvxD$@$@$@$@$@$@$@$J@aL&|JTZee^w6섑s#I;vB9à%ꕅ_$\JlQk&8lFFb]2-iv돪]lHHHHHHHH &ɴίZҤb)lJz֗tv46LS/7Z8YR8ml,c*B0] qcKKD:śY?} B h4gׅb'ȑX;5 Ð߾EYĺej ML2Mzo_೏QHzӱ#8y 4ʘ4y5CZ ,boBCCW^ΜH4b3_իWaZa=} m4'v``f&943FIKofyoV2\tW*+L͐u$@$@$@$@$@$@$@$@7^e7Θ2݆9DvofӞ GG( ~$ɐޞ'詜NxH$@$@$@$@$@$@$@$p*-::h 8Pt7mci],?*=ڶ0sLC MHB^N16{‖4s,zD]l6/"dmQhwcQ8cXHHHHHHHHnFA!tM)S6}O״TI3lEL\(ah8юԎFE9EPh"W(R;3s$3k"z9ưcV?*k+ޞ61NmwMZh#        D@F=xGRdG!];k%6M}3ҴqL52b%4QGi/b4쮇grgvT<        Zn+/yoHmoK|-:c&l(;/ !K?Քk,X˄ 3GֲnYfb,TeܺSd&Mx7 J4)222֙'LRvh, G L-Y3G% u>&=aaE w)όrjI\DK~XtF1,ԝq3        @ hrwMe;[z4,?W 4~ *΃GB$X>N )MCU_&vgQiZ4G{V fE .f9X%r)ZnF5.'rK/6 h|UXNCZccpe7׹sgŖO؈HHHHH&!HHV$ #Ͼ[DF|| d#g AY݃eWagaځYMHHHH|"@'LlD$@$N JYtt"I;ԽiФ])ɗLl߾>^m%[wĂ1|ST$ܛYPMg'G#蛘vWo"۳}6bXB@KcEМ=z`9y_&jY Ŋ0D>GUZaVQ7k-<    ۚwἭo?'O$@' S8,""B&_R@奷™!#٤Mi۟bUT ЁrրmZg;5xV>QIvvj'‚/i8lսݫ@=cVl}vg؄HHHH P~ I! HLϦq-iSׯ$c.)=ʹɻxwI4aAú؇H?ċ \pF8lf|sD٦~Z=&[ @ ~' 7D$@$pb4bT-iSڮ_imq'wM|7C]l xl$tz !]r?>  쀨ÿa./aKD+ѾC:R-UcR.TG~#TJ-.KgCѲE;$ˎڂғe"ZBl\}7> R63~O䰊*:VQW-nC!m3VKi(/V e5`p`Rię3+0-JEw4L ;e3(+BwՕo?gB>hN5 >g9%U"F_~ yyyHKK\/HH&jzRD]b$vzǯ͓띭Ǹ5 z"eM2s0˱X@7c*L~.2ͥ$c0#r iE6lb8yz]Ϙv<E+a+q)ElN'sbh҉ga6=_^_!8z`/9wOFZw? 4 ⿃'NU~e5-xUTBl&Mi= x# ˛AƲwҵqByy;+olC<3"==ycdO|$%"5٨]/‚q`♼nڑW1s/c˱-xbL6+x< &ûg)L6)(6!".eD5JF]u? ϔF[4s>cDsJ1<>L|wsQ"` ]a#  [@]Yu.E64#bߚ,̘}d~Cn_~V"om܉}d!띵زf}&Ķ`}bX2^:8WŦ.xkv}}09y,<_ TWnkۙ΃CvLצJ0E-TL<4܈\5UDI{"^ >YިϘ/׫Ђ`.܄;adU xs޼pWyޥs]i9D;뷈q P[.5k?k`ϧC1 /naM;K}H2uc_ Ψ,9&~蝨'6LNU.d磼ڳsMeIHpUcPw}$ gk;:w!6$mS7=#Dĝ:ϘX^xuhoSqo/]Y 31yfjs;e{ʾ)G!,1Aw   h:;3QhNƒ>;lF4ҭGЈ5v8Sk $@$@ڴ(Z){zۙcNF)s:<4P1@mSF0:38EARخ9ַSp”.Vx>wu)+٠)#Ci @pMDu۷| s\7rF̆UB(J]l8SRsQ0DiNb("2[P;]cYĎ]Ș׾@8/00؝0q9P+,b-a$FUDEX:1Aq8,ןF2k?8 C7˥JtHWyD$@$@$@%T LU4)nEK^>޴bZ+uҰp$)|&=6G'O۶/;+K ݌=gU³I"/6^8x,\U7$7Zj}B<  [@ZIi=OΤS_"Ҵ`kw*tdLۨ^R@ldk%p[!w snVC0"}XN*UըpTiA}34R1c O5cMUu @ktl׻dBիx:c/1a/+1 IiHo|pMHHHH V@sj/V$7,Q~(ƲO]}*dIø! )t*9r'OF= 1k=#&iXDz(J -m^ʅ;0GrӉU2E!?K7oʧ>{1{H߄1§%F.]u]c  [ /(̥%8\K~g>gҺt;o.xo9 kj6!Cx uIo_bEuu5,,9~]10 KnֳǰwCke/Ԣ!$kfn)YتԞ,ʯgL RR>Eavy ҅5xwtV}*RX6@y%no¬|HHHH p~N8*29-ǐٙ24ySdtUfW˧LC18)?Zfb3et*ZOM=aH1EzNi'ͤ识C@IDATo5Bhhؠ@+a@7({$:;~R󠽉voy@$p+ Qxo\*H))H+&̝\-]Sh+x4Qlk$<"Y__xA  }Fg At53~aDZ6. /p4@ii#<[ų)/v?3M{wFhjĢ́H9굹xw\fͼfb-z0m{qV(`,q?{ؼ=%r{o]oəT6uPnoɴTcC`5~7$ ( IhWcE}./=_kYC$@$@$@MB (#^=}A<8 )bm2Yiy+fobDIVUfl{{*5DltݒcLS0"c6ں- 6k難m=bʹ)ѹ[7t_;XA۵*[v<% "łʫvMi۟Z{{XT=}w>pm]x"cL6.%cAgbZzOz&?Xhm]~,so/WOg^B:ƒ?Bs+//ǣskz_m|Ó]ac߇PUmEET! dڴ{o+?to~{)Bn]:[ϊz5\N^T9Q3Xr {)CnJq94Jye_kyL$@$@$@MGȀy??ڊF~]8km]ZI,r,&Z?<>G^p5w"=IS'IY8}p:Եzp4Ɗ%bM_6l'L5 Nc, g ۫J>EX$ _߅~W7Y) [6h`L0!sCH}^`—`U!#2E1sSf{2\5Ѿ~$@.իW+3f~{S)+T4>5v\Fg2QF?~?zJ5W] ˥+J|h0DՒPYiEDM0}jת, 4񫯳JW4o~[)Ն1+`j!\FHhsD|۴s)#BdǛm{?Ϙ$_Kk"[ĦgϬ| A@ﳴ/7xJ$@$@$@EV2]7k5FLvR<egxVCu4lTV=m bmwMZ94q,AmSE$^ޢI>Nxw^]=2 +HH&"ЦM:u RHb\ h͚ U͏"?ǑɨB2ĸEG g[*~as}t!JrV'da=x*I &ÜaМ0         h]8w㙪M2mb1CtR!96Dx d HnU ʗ"     wTn܉D4Lnsos)aXHHHHHHHHnMy$@$@$@$@$@$@$@$@$B  + hCO}U],AκuV5Bɶl[},X=VZ*ð|, G•pValtٙHHHHHHHk| qȌO-t\V8n0PaG횋UsߋUrZ/14 `%Dg_Wd l|tQ<4k>U݊)5^.4f63~0p՛Xv1 wD,~k;SK^"       `%p h5b6Ҷ5Y^W,e8rRr B\fwei1p ri|b3 kWPs]D+_?u넑/mSex-,B=úa8nnJ髛t;JmFuE(Wx<1tB5+쏬,Pp,x:pNlBK=}cc; F"{O:WWȜ[h`L 0&`L 0&$ph`;÷+jDbWcnx8E]T]n#ىh>'&-w =~<"c&9ʪvm_ڊ)~D4?wޛ7|{ x5HY&]M~$|;##mZ&.co^\P-s-w:ӎj*۽ )v eZ r|ܻ 6V|uJXjQlhǝE(.=bWihh|w,*s[Q%bR4'r*> .ס`ثM?|@Y_ b/QWm a`L 0&`LN43~+$]0n/l*ގRI&~_}(g W.DaCd{`,PĠk |Em>Jo2OXv &y4Yts R\d6m/R/UREhVq5(oiU[kĀ}Ch=5><hS_ʢNRy_cGB/QWm aK`L 0&hÖ́N=0j~67)תKOMNFry)(gsƀܷK!5g\{k(KmW"K~)z$0c\iGkXfDiie< ܤ4(9MDFFEѬ 7w>Tsxk1ݎI[L -^(ڛE 2F6-a=Z6;aL 0&`L!p"=@[iOqV~eNndupXWʆ naݕ`fA)y0ЮE~Xi7O̊j:1h|X9>y+0& |pJ hQ0c~W;;@" hׯTCYȣUJuroMf4xAp5dݫ"W2=JeL 0&p%/H G 5?r7%`S?$4SAש nY|rV~D9 D z)%gORCF}'\{Hqy4挽YaL5 [,_QRE/jdc"S,iQm"m\HB9xc4Un4z|14,z%):ڻ`b: <  vWmւgڴ.`L GVQK!220m(5U>~:-)MXZN7?pu5-:"R-7Bޭocݺu(,_͡r~;iĶwFļjRsxks 0A纎y&3.]0]=R 7>R:+! ۞ڲYų)<XUodHMPBًEɯ9Af;[**_I_#F. 0&#}B&&f-i⩐7mJx` `9"ʪQ__ZUMNi}r\Ä4K~J]ƽxvP46+gmߴ}-Cϑ8rZLFl}q<0~ONٶl#(5nTnZpH)%tsjT:}BA*5VFL]ޮr&ҹ^Dg2}״u"~Y,E!O#{j S6ʚLzX 5MAdn欒Mń;ٱDxxS?iK.YQXenK)ٌ"h@IloIЮk>dLPC7E3%re< !i[(&o݄AU??75)mxo0$c2Z-N׈;e Mڢ1k#U27)t^=t*j1RNYzHs56a ohӤ\ aꓱ'c4a C: VFQG*̴w1~Pb}T~| zo! R[xtbaUZٹ近o,*a M^/l?^?yՁؙxwx[J!ѕXЏE W}=ٴ]%caR^?c2ã$O'T݅W.6&bSS#n صu,t7aP8m;s<2sg#מgc<{7˵JĜ&f|M {c6`xM/jPpLYlEKICak֦k3l?>fL 0&"pM{߄m7%-}IrS_ ~>!΁ZVFZAQԗ]JT'@?S_Eًi-se SgSjX=79XVOڼwj͝lOlI#'l*Q/\{4C,`W6tN k h̵0g||}M]nV<(@c t}N>[3}fH1R_Q~OgLy~xkmQ1ÞϱHAA/*%q\-؋v'oC ܗ+܏:& t3a"yiNyieJQ$(֣/Z>iɋL犧!׸JlL(j*Ln: s"Ci0j.%T-YTlrݩ1 O%*zc?qz:><b`e 30OP!;OIcVL !2Eb帱4L[(V,saQ`x}+gXij(K'@Ƽx{*{Cy4+L^H`ϴh4vzvݼ6n?&`L ״w:ܡhwL|KJw8ɻ7xt^gqY9sub֣wUuu<Ξיr9_'F!H?J_D1ވ5%u^Ծ$sF LyEUO^e;Dr9 p.\v;n'op`kCÕSiX}a qoRvMDƽ"bQlfZ)}DU1l2EXzÒ_C>yݙMԅz'/dEefV~ͬPr@soիfA+13$AʤVp&$*ץxN V%KVZOOZ3/OQs>7d4dۅt0~1IsZ.\,m" _GŽ;~`ܙ> b 8WTŽN{r&59it}~ M%<}yŒdCŖϞbM<ڈy[a`:vI8g[G}W6 UQ,M4ݸܸ6=Úp 0&p5-5fU.(:]BBAA [&v!-4}E;gz{<5sC\U" eB$P'!)6 PE5Qcv/.sb }0wk67ߞFaM+UԨW­":LlB㑬fc->!3BU}7CdiS1;ճ#Krߒי6.rXvX w#R<:sqqM|[>(pxg\wJ3/@%ґW7], A# Tfe>}"67V](c`f ̆.ijyAb*TEMsym<mL 0&@X@kW`L 0w,w$0/ 5xٻ"  17 ,ooX a%IF) r3c16.}WE$ÀdD-A8D3pQ|/*a~R&V.4Ea!Wb9di %wOoK׮3:Č#6nYKLSk׊hՁrѦ!{֙!%K"Nc򬪿)i-ޝ43=`]UxpKJ$~T)bD?ތNzW||^Qиm&>J 0мt"U2"X] &[ VEG֬HZ.L=2k5ٳ ˿,wV_,l2390\ `m\'q93ۜgؙ.cL 0&\P^tYO0&p bIICPʏi=@xyyJ>s}y>nZ*a@&؆/k/R-4$бDʕjDi5u%, wG߉J ]h+CQj(wLQR,(Sh7w8 6V.l"~Y:CͬHoQDjc!2>;1?ū.j؝N.ZYWFO&hr+q!4s_`̇EΌ*&w36RאJ^aPB`hxMƼZ;o<΅w0]'׎t*ւTK/4s5++?yzڧ+mt֨g]}q3aָ 0&pB@qr`L K@apLa Xο#nR-__XoRNM\Ef-504>jG_' sW(&RzcrPDhM>v M% t])Ӹm ,pJOYSrS0ɇ|4He^Y)ەشL(߅ThWѣTJ`u]\5b,VFDQEZ/5+Rf`~y6x7IrK/.ylqtq))yAGޙq㟳lzQ9P7Wl?jY$WqjݔgA=$p*i7C+xv[*;o;쬙"g"ammϯAg,0&`. 3&@d2k!S@_5K;n۶r ]wH՘h JʪP+}mʈ]+f#ѣQ^k*d!>y-&L$,Oi{l @лp* fMcaSY90<(hDn,>7=coJ_;,^Iw6^;P1 ݭj)<0q!Y\3s^awYDǰe>>fǜqH~uesBlc͵LY;SRpB<5M_c<zOpW;%[ S›lڈ+6zb&:sb墼 X&zhțxh_$PIޣ={6APچZT!mSPL}hwuT 6Z><#c&`LtE˙`LQ7\¥Q;JP`γD%Mi,Q'mORaǤ5Ό4'2d.KuSEVpOx 0 =S!y{Ԅh߽f"YDӍ2ǟlHF-W rH1Σ-ݴY:ߢB쉔DC u0x3kdxk՟ͣ㩯a㳥9NI# =ғkjt6'jj MZBj?<ҥ7aL< c_\Ih<8kht ìǍzXt̕⬥O!kĴQk Z-kr&>-Dg-}Z eym޳Qsvݚ<[ՎQmȵi3w&`Lqi-eL 0_1^]I@ 1&м:jos>rk*tS=J4~,aec0c /H[HYtǕ^i3Em:LdNq}$&EڊIYM"o+NEd㲑/bh^^Wl>3_ހ=INǠˉO[&! `+IRf>|UY 0e fb?af.Ϋ>N{i| NH`YS%W V5bXH׻3Zb.ʀ%ߧ54bZ{LriD)ąic~=6rJӷj9s]Okǔ7aŤh;{xz6[Yϰ, 0&pNfyE.eL 0Aߖ2qDg/}68Ik/^‡^B\k,.fM]NQhZUE%~G}}=͡i?;iּ" 5 M Y($dHshf~( ~=jHxGyljqOg΁:Z߉QMQ<'Tߛs]@Z3̿\mg]S#*mâIRf[{0ObY <B%y5ym pU&`MΦq &pB .GjՏ$ѿ&ZMx Ll 4Txdp-f'W{Qz!@'j|kc@"U3~$:EuϞ>`[;7w^sQUꏟaws&`h\?ޣre&hw}/k%zZLҩ)D3Fg–)lsbL +$[WTkW#0&`m@M=N8SNa؉JS}MOSg47R=j(G$ojF gUjv#iX1Q(h8eL 00գo:x56y! YMgsL \5~7 26 OwF VFj#㎙`L 06 Цk꫖)uqqqݻLMolGvk"^&2=iw4iS:FOir^K`-NcL 0&`L 0vJMC8 Ν;>@z|sR]XUIj{5TqkQr9`L 0&`L 0&@!p47|wyvlS=ŪJmVS '`L 0&`L 0& .̄h'g$#TWW$X&|5m*+Q]#>#(..F8K`L 0&`L 0&Z@iPΜռ^"T]ټW|ݺuW 8SNAtVOc?Ƣ[6%l]9 _dB0 xUʛ `L 0&`L 0&ڄ@ /4)jkkF#iCH|Cq沩_[%q0ٜBȝCaP>1 4ώNK8lrq";85y<%Ecr\~Ǭ嶑s'ӟWj'n1WRwsp >q g5!??f%$G`b4YN-ꑰBVaأo֎Bvʹs3&`L 0&`L J@ ȑ#?AAw ? -Xwdix,J sa ҠL0JTHᛑ`L 0&`L 0&Fڅ&5)\S_S6]#x7I{S?I I;F̓ŷ O0&`L 0&`L UV̆ ]H"1!2Z9ӆ#aČd$,a<õAF`L 0&`L 0&U@dAxlb$B޴)wv1HNh^r^3`l{iM3&`L 0&`L =6Dދ\iW d8eGMp5gbJݘ1UɈnzMҁv[Z6Xsၦg`L 0&`L 0&Z@ hbw'|RZ5l݄MEo=&oJ#7u 5'}I>)8@SfqCV-mr,ǹ*[ڒ=;>`LYu`L 0&`L 0&Z:\ZƯUG% rf~2NԽs鵔&; L |'N(?`L 0&`LuZLeV@$q+6[=``L 0&49EG8]6`mO@ɆB<Ieaz>Hfy!'ۭ<m?)d*@IDATCp^W7u]k/G Bҷ.DΰTtg.F^v1AN_ʱ46QS1wClɮf2l_%gZ]v>8`L 0AݿQ[d'NS0p@DGG埅e_x:u! $=CLYMn$6+? 7kq1&p 4tSLM@ԀK(g'ۖW5U3?67o EJ TA}  0'Ϩ΁ЉjWxaN5K B:R̨{DVkUThLs !/.(kַg7tm0o>ć]ZkEeY/6AZ/䋠`7*ǝrspkwv3Bfͥx5sG!6#K x1 p[t)xzM!`\5# mh0Wnt~3f:k\]AOֈpM{>`L 0&@;#Ц{=駟ѣ7Z޽[IYH< -v6 vޮ= 7o3ѵ;9`j7Zv[dl[r.N圶%P]^WfcA[~&Xj#~caґ~&=wKE!dZ8pqky:%Ζ>b)) "sW&a`#HKW y}8O᪟Yv♥eO0Є#ߓ&:t\b-pf5z!^JjAg̼,V[h:Sh9&`L '`Ν;>@z|S 'KLX."0re!QK^ 0O@yc5iK >R@%m.U<` 'c$_a9aN3QiuH/o,(OK*Xc!-s̤1Ror5♨Уa4♰Cj0ڤsފVu2ۅɖx&hxeyk`آ|Dƭһ㏈έ/1G5YPbU hh\ ؔeKmpoӋpRi3fʁo+؃=ڃ#ϤNZӈgPo[ `s w1W#""'&`L \so;jIx <$<;ZOGv?^8ln`N_rbL 0'zٿD8~+ e e ʉ/g@FR@%Y)P]%raɯ!o wgbR?wss1|0H]> 2 {eTf Ͻ](WHaB֨Bty!|vVS-ʂJ1`>ZD9ek[/OQs>yސ `,IPz_|##yK)S;Ww3=q}"2wSF,_9S4h\(l5?fQd O~ i/ p$=`.źmro`]!s.܇wB{c.=SEg=WeL 0&#p41usdffh@/Ezz;Oa}5{4=ZQjߡ0ƑbHi)NW'R} ++6U)IkKgdU:go4R#l9 Ih5fQ\|2ڹ0L 0 L$!]n~T1MAz;Z":w,ٱ稁,'=7cvݭ"Z|s\ǰ֞NQ&tzL^&b]TڷMY#kxaѣΘՁ2G"jƛHMk}yKHmgPF)k(u>Cl*dȉM$[?K &\ >n26Pf@ªgJﴛsF TL|7}RIP|tP|> @‰=ՋMǡccۻtdM s'ۺcZ Ř94\]ZnjcEpXV=7xExq|[Fk!n$?oHAtx xk`L 0B5Fx"3''zZcȐ!ڵk69g?~ !.>^, {둱,]ӟ)5k4MxđEtZ{$n.-pr'tT %tV["7u>kp`5a~cM8l)¸(0%W"$V48d'FݡY3Ǯ2&Ze /{С$u߆J6\3'L lq4ǖW]F>>ɓ)D/Z^pJ|BKW%nD9 ;#C>H\qT{c~`JY"Ħ0Vc# chkjQ^VoJ @Wu'#A~Dlc?BCN1]7ٶ6;x>AЍ`<2/dOG 1O1OHwr@', `Lpa}ql=)&aӒG;/^f+?>._򘺺k)g_Eb_C#2"C9;ǏĈp8öT+mjQ{tzh@t-5F;MIBUѤ͑Ial(dҾJnAe$NT9Mu-:9^sEbO{wѲM=g0I"^FZ,^r˜)c85w^x*#Y"\6V FKy8\ w#ջPei츽~. ;0†,=Jx,zd+3&`LKML^uunf ń*Lc,PKi({_g[Ѳq!"jNc X{8^nVD,̪Kw`R?e'P\l(c\uvZ&lAEWoS{W:<7#냤< ?t~vbdm}xsR ;q^A Џ}\rSMEu 7Rp $wt5ybi7`,6զن&3Q܍"B;6-58`L 0@SS`(pDJ>uk:D>L Z.)h&T|"ӰqVʿ-BաH" m,>Ѯm3KPG17-)Ԁ^O}PQXf@LJ. ~,YSNKo!LmAk? Og<Nҧ1ⱦi$ O$oD{+6.m:^\2&ZQڊoX9M5?seK"t|&"oo+{[uQog@h ɘWkwR' Fanpi̟,%iz^7K|,CjE-ˋ$"""Zdu_ןB i"Mc3,s}a$N_E5"E quZχkzrɈAcH,h#" S,`rR:IYt}}a%9Ku:uu¼I`-nDE:[Go\qjS/_anj,~KJdKwIkzT8ŭس}e8qԨ+Wb' 9l.%Nz'M l_9#geE\sKd>Z>vS-ʐ6x 8MT[+y<qBtᴀsHZ*Y|.kv,Ax`F,TD~fRebGRej8(nEV<dI\ 0&KwHLL}r3_rБ _!nLtJ0 2EayuvЙH椚Wwz8V7g,-꜅B*aL ٯjYh~~A,'OV]ĺO͒xユvݴm12a/D"-DsUv+q"gzkwbᢅXufE0WX=S*>{Ǟc,ˑv.Y鯤㻦#eÖ0ՒVm5r0EM}a,3^awYy Uw-ħdɍ1X~)hme<-23ʏcθgNi텨s|.&MYnLUǰy~/ң(*BYRTh!o)Ԝ7qTEiC`n2+Wp jj cʹx3] *gjQ]Vb6JiBiyнuM/]MEn{v`L 0&e}F3 tޙpaIdn_4}M=(f^؅b:qk5?}Sv.]G2! Ml(`Y\"*%)"=!l{_"u!ukfo) k6#1$Y)kS"䃲`iӣN;Xs_Tu-y[F%o* mnr|0Ĭy4Sӻ́DLỸ8#RfaIn7467Uc&d>7r}i0"Гl)}V<k=eC=zsL 0& 4s=Hzgkz{rf=28h:W nw.M)+>rk*tS=OK|a m<&"_j9YZij(:$$eLZM/Oq b'ig{ MŻK->v 6\`Db/BgoMbZ;3:҈2$#s hs=Wh V܄)Cla&6si04dtr-b @BS[_!Ggޚ.5@:O'<. :,7`LRMۻ1wd@و )j-HZ^ 50W{3󟛐(sOz(whgρjߙ`L 0&t>_}UB02dd }p䪠ވg}" J񒲖uCQk\'yY雁8wͷԧLFrWR td#;5ihNL \?~mi2'NpFzoY_bKi:'4i⟖Zx"Dޗ ƓX ]p}sTc-\k@uER# | VwҞ7EZ˛D@]@7S}y!PGc-%ƜEHaQs獑$4l2b=-@BKٻ`6a¦_ ($ܵ-cql/eӯs |۲T#B`I> tdX{sMM@ץ<~yo.PM)i{l2х!HZrbL 0&V.j9 Lgx9 [bT 8h{֏I ,M~4MD7XD 6=hZ T^UbqH}Z(>nr=6h3;" r"zWfL :W?8FhE4e&D3a,4THc }e Aa6an. LkLyP_i : i-'NxGl͕GkfU'U؝oFXZk3|eB8SG|LGttt{‡/EѦ=I\\fk%vZ:\=S -CLO!٦ȹa M!}$;x9疍њ .َ`2JU'XM]Mݙq+@Ef-)6B<6_K׬fJjmƜWhf̘[PL;&@;8<4&`L]h5O>ޙLh5qʋ1!҅Ÿ=|OtpnaEa,n#^nk9⣆ڐ:=簜ڄMp6=ԡDЙ| aoO wXZߙ`WB }A R%mpE6uEVm [)u cjCBFe6Ưw|z=Ϝ 0&p@ސV=OQg ZTMeU" rkݜsZe1_q4+a5u '`L 0&wkҜNݛֽ6evt[ L 0&`L 0&`ih55fZߙ`L 0&`L 0&ږuֶZEdI􊹙v`L 0&`L 0&vH9('&`L 0&`L 0IC8uQ1&`L 0&`L , `L 0&`L 0&hX@kׅG`L 0&`L 0&NN. 0&`L 0&`L}`}^`L 0&`L 0&@;!Z;< &`L 0&`L 0Iy]xTL 0&`L 0&`@ h8|;2z_+q2&`L 0&`L#Цډ'i&:tuuu-&g/עSMnLKHvEFJFLŘ:V C*6S v?ia4]SQ3&`L 0&`@ hb$|7|sE jJ߆ON$09{ÀH%˰~f/ht|?+],{a-ӻ oO">İCܟ,2XCؼy=NtYjTڵf4#&`L 0&`*6Ԏϝ;>@z|sR]ƛENj+>Xy[.-ʨNFx^a`ris/?ح5qOYȘ`L 0&`L <&S^h!)U,1,/mII$@h4kr^O@n'Bš58R-`6g?\WqL4n DzS.q'Fo:[Gaӵ2n.!ND{J躘dzKv5)DS9'Z?:>k g`L 0&`L J\u4-gʙ#<t'Nݏ㍅#Au3I#nݻ۠؆0""~=icn޽Nͼ Ę}e,c_֕Щ[I}G_D|<*arc{1U1|~C(ttBXD$1  FTó+|uN\G#q5m00 >aWd~ #_+eْSQZ:uGdL4""!22>ckDj`l ]w F$\sK(S:tqD(N @Un *`++xĿV&]MLWJg-yIezʠMM} ߤUDE4QDdZ]f~s93su^ݚaUqik_a^Kr_\]ÒRHkI7HP`Dt`L 0&`L 0@2H ^iu딥yW^1l=Po{:ς)1~6]20)N>f ":j7-+#Wm6kO/X f#Mόʾh:aVC<Bd׌l#[^P=0Hx^jnDSXo~ac5¼1pV +f͒>j(,r fIcҚ1Qߍx"L mT2 EkD3sX-ݗD S00Z0]M+PmeL 0&`L 0@4{!:žhb4aP)r@#)Z5jV]}P$N>=>r'J4lD"Jo">y;tAB8Jk616Ԋ<`L 0&`L 0@5iDD[n'ړlowԀ 'S<1Уtn2ROKLf :ur:Ed*ᛓ_ ՗nmhqTMY^~Jt=vH\ˠybhŕdUX]q7g<T5V}_eL 0&`L 8oҶ?B#fe[5k&MH bae1h0w{`złڒ ?UꑢOGqjÊo/7z4#]Ҟcq9y4T%eDJUnm )n瀞ݭ+8Ҋq++*R}j#2&p>qZp9`L~ 9Fy'lk{p5 ȫUU~u._2\t ң߇LPwGx 4m۶9h_(u$\Tӥ"v97[ޗef8(MElX=qѪ{+hqhgx ÌᛉoO6z"pɌ!OMObz<H8C5T=h'r(_+[4k Pwfjn]{&0k'b]t;(:Ij8c o?ZK;ɷm~JuݞHj{u;{{.geޒkz&sNH&?'cL 0&ppbL 0&O '[Ұ |GoG,a_(@+QQLVfg N0 Y5zu>#kXyz&ctnĖ%cC ,%3d[ !kXx_?M˞mlHjE?Njh*a>!cP%نIq&H_ՓE-dO2]CQ'x$^2;R&`:uX_7cdw"_;8/cd=憃FIf@gGh &)k F"~L/ o7.Ya722$Է9+?-ޝ"|B^ȀVtgY=wȵ^%`2ܕ 0&@6@恘`u p:."lSxv,YTCmɿJPNgs6Gcc!,,̩nw1gE䅔A`?ۉ"䊱'XaXPSܕuda=T_9:*i:S筞`̲stb/e!xYd([O/#yE?j/2 ".V6W$Kz?`qrV^Be!'VLGv)YN6h1E:yD=B蝱Js30}VV5nᢛc3#s{kY&`L 0&LK4E $ ֜kЙ=V5M)35\]K")y(JπI0JNt~(k¯X];1sdLh 2<NlbuwuEѼBSy.hב\&:`Q29yF;](|Qrg}ŤI+O^i|ibc^| t\2Ve@2yYN;XVk!yhiCq DjI\\LuIFyv\EzHנeBiD95n|ukQ^,̌0G'-_ 0&`L 0{8mSΫݽhdpu6./1;< F6Oν޶O 5i"kegWy;O=᧞cpK[cpx&`E hVH 0&#`0ܪF;SZk- BPjL i xcXRろn]WΧG Wg!X[[׉QL~ةL]ץaT lAY,@n&OAg? q!`L 0&pWpoVgc!=\}3S˗Qծ_>GSi& *uGq) $]*X4`_yaYUY^S'>bV:i(=sBj 9_n݄K%p7T;!dL 0%:x0 ?x-] &L)]XOM6UKwK} HBd ۏs6L ö́⯅jRHV_ ; |3snK+df 7ۘD\'&`L %`;v+]'vS#~/HJL#cﺿ`Fv4$6+=Rtux|Z ]ǗG|O[k86UWS)T+K$Lo#= ,2ꣶbLǼ=LJl,U34E`4- 3&\>}[<Թ>c^lM!Ÿ 3ֺr(* QRywC<q֖@,}qq83%0T\B1)υj==m\T]åKWp i0KԶXGr^lPuЩ\_n;>?kszLL9&]_&Ӛ1{KWVovY:@_b|~IgV+W+LFZq"ZtX"`L 0&MhբryvL)ǖcۜfƳ!r'%}l5z5^ha<^4F|-)H?ˑa2 Cz#u,>o=†LTIˆ *X8؀$n`КLV >WhSx aC1"ÿ#|^h[bik aJSKH^'Amħ2S(kN#¿Q~$:Az%+"9 pS cI+%l`O\~AR8Sˆ,iE>A8} zkx6bq*]ƓKR uLczgO\;_cSa>4oTCEz zescBdGmZn- Ygg#=s2V?2&`M;9r`xk({C^żѵE mc-!IAJpP)hڛ؛W@YPo(w*-%[АAH?> ~F-|XWz"X zvA/e̘OPkh+Cn\&\)6-ZuYߡG ۏ}l@φk`Li7tAzM >҈xGOF;~'GGBK[0 f,fˆ0ۏz -Ϟ8,e |yfu5QQQP5ۿv6z/ ]5wӷW!`TeڝfkcӲ8fz@IDAT!m+?NvzGvW ضd$?ͽ>[kCsSFvQ75گEq Bؓ1;hQn`L 4 bܘ17n=ôGi3")p˶,mZr %0eOkZC'/ }W AkZgsi69}j?Ņtg_ˌUs?4yK-2GrY](ylܰ9gXe]Y8!\\DE_cD3?W{ %J4yswɵ|L&ulħ!cW} GL-[-ٻC1MżكYmB(@/PYh t༊E\3u=Z{POOESzQ{܃ 0&P;z|U a>̈D[,A&?T bsY"'݆#VΜ|mpW6,F`ShAL8.F>=5KMa\3@mt1r<fT)w&/ϳ&!"x||gOqf4)? o w~6C&&HURfqr||fhD8LDM:RbnÐ;SLEҊ;P2&` N`k$YIHG]6⩕[Qv햵7qN)ƺJtTSU`FId)eOF'v2qIcC0Dת9M@6qO E=0urrTș ߿_::5""BU?g{h.n_j Ex%.g#pHI3EwF4n D s3 &@u %Al 1~1nK.dQV˔3a񾤥r@&)"]F&[E/"(MUgWt&U+J7o&=nr5MˡTRmRXby1 L7NCiMICeEQоw4%*۾(FI8eG]gF]ע'a%`L 0-OVx$r2~qIdgw/c:el|"' Z&ÙRFExl8)!I{pѧ?: @\>-gǞϑ)[phF+RCiA?m}76{6uȆ"M]r%0m~8| i#q7{#Z g"BC9,\`zxkDh7ߞn\I@_־p%Q-ַ~j'[F2s&1m}.M\BRUfc՟&"U1$iE6J^VbS[;l56V']Ef.3>TF$ "['Mp;]wLYS&`LZ+ NV5tn.s;qxDOǕ\:B' v8 rf(j_' 6iD+9U<`Ee9?ƂrF&N#t?.$à6{|SR[0I)z+SŻ+`L%М 6e+LapM3Ndv?fD-Fg[Hl(Z1{sn!:SxQ< -xfn\RG(9:hF"s]{ Dz sT *)dzbs̋)]?uO1F1 Kq*[À_ں=VA:9ō6c4hjt'y35/ qQFKQVVF:{[h2rkpH-sї0ܠO>- 0Zq2[;vB_tx(<=iG,{ѷc'>ʭgji_ďNӒu~e5/C*];u;aV2 ukXZ9z_b&cDo(Z[\=H>EQ~,|䎕Gژм:C1?qut*r1*Y .3>%meD:<ݞG?xa@߰\en1xu(]Zﹲ|&`Lϧ~™R2K^v:6eK}-zٻ_!;0Xm]џgwK(=M'Dɿ33B|K{ԦG=hע 5vB5_ՎҴ!nT/~_>]."Sm:?./uv<@V3Gsd|%Ltd@ {1f aҴptqb01-E^QDoԠԄLu~CkL_kybLl|-N>ØE^U4~|5}Ʋ cKJ ܼ&y8tQym$i䬕OOWdΦ@@8Sii-:a>'BC 2[\㙈t~O )j8ҾԑNg%V06oo/S>NE@ Fiଜ}ېCg۟)kvjƖyiد>衾j&@1j3h<| zL(|nMp&-Cמ4'kߝ*7.YזbД$XT ,V4B荪m5#{kPQ"}qFpbL 0&"c1t`Ǹ&bNl?ۖYj̙2FڻLJR1./z聾ؘSzYFXwj?<&/6s4 hRAӡn\4{aԨ ~)P䦔bޛ^Gg|)iSR1T5 2}Vy'x&UF!o)ͪi>PMh9ԞQ S0b`lcDiANC`܈V{^ݯ,$.BY s ~fL&À˔)&#lȆKH_<~) E=I1sqE:ced ᆫѧjۏ}%/GK5=ƓF?ض*Tf;,/7O5*P|8S>-L9oIc>j՗O1 IkH/:t/>ig*; pBZ>qR:]늺ECI6Bx4\փ;0&` C@vAN._Ùs4'D'?`S| L y{eh}?2`  ޾jh[tYxm(cU.# l@|p dhLC㣜O2+ VkFчz[sh"i5uKYF'_.]!Ff^ADmGO#ī^Aوi>йj?3ص~?tz&Zp1jrrR^N0O"TZ;Oyc6W(}eV>Eu~)/ނa$Zˆxmfhy 80w3U^S88ΨgXzXٵ=[da*ڝAJ306I5TK:S䗞K[C3QK6ξL!H[6fYkt$`TKCW[L]oFo2[z>=/f()^{O[b*ZfB~9aV׶ujfVlZԗI<5Jp `L 0&DLXQ#Q@N:3`:GY*+/s×^SQPDXҌV1JnU>|2_ZG+%nFWIČ*JsVhV=Hۚ#c =ll~s7(}C{qh^Uw`K V(O3?Z ҪWۗ3P1YTY%/F ϖ.mfji?犞F*=\fXx&d<{bo- so2ux&:~TWcO~]A{SGwgBx@d,3)`jjmdz>—V)$ >CQp7rCfPZ˧uuZc$dy_ŋ!.??B~-4(9ij9_"N*Wy(c`VLo^C)K,xTj5%} w2M>ھR EOa/L QQWg^[iXoݻH~~ :WoԨh*7euҪ̺[.jZuhZ]áōz6L`L 04k֌#p?< EF)gNkA:5W3xh&ڋM㙶]kOA4ou%9rD郾}:p2'F2vkU=}ՓԎL֪$?[-[f٧kDg86+ G"T#H$N"B.j矲f> @*g}[Lt=-9vYOnV HFP`Հ 15C9;WW ^\\ѶL6& a+յ%`Hl,9WQKk'SkLXs5m#)^Ju7 Y%[wAnH:*^u=]P_9+<mѺIDž96(F^#rp֡4_rk\پmpݨwੴT*#Z/[h 0&0x/_sL׼9ZtVj]Jqz錎Јh<fп!;nF c,[xɂqbjSN y?~ #셴㡇IWi29(جVnjP3З"6+I-g&:a4375uh݆Sw8!RZ k-Mb-߷g`&7pssCii)%֞Xb-:+UYc8,ǃ\k̖hR?]F`y?I=mqHTMD.;wifԕY,owDĢ[¦sx6ڟ"G򪪬)&:2 aL 8@Jٷ BY`L 0&]ZGOn;`& \EE|u躚tkPM)\꒪eG5uh@IX#2C5a.rq11>nm DX> #o7~ᨆRQBQ;ܗq^>B,P΄翗D &@=z1A簎?<$gL 0&}Me˖pwwǙ3g$lDCM^ĚhVG0m4<u6-`?n;8ՏmR56튻ZTg?-' i-:Kч{!R1麠LYകe޲{rqRuw?_/}!?ҩ'z.bBb`L Nsl\< hĘ2&`L@K@=IՓ'ɓ'|bܠ()NLĚkK1Ěkϙ }m۶>g€V/ɵ7^p&6OZKy% )s*l0d[+F޹ꇛe'ex'j:Y96i)NƶeZsa3a8"k/b g1Іq,,9t7q{FLu许Յ ,%3hY)lZټlEL 0&`L 0&pf۷e^?߿o߆lj ԕ@3?:e7-\i_ر#`unN75{19uBd[d@&TlBxv\$HƢ <,Z k^9&/.Sgp|YcD2"Vin&4m6nlR^Lѝu励'X2V`=1w%zYȆ4?3&`L 0&1b-Z@8Јp[nIx& hJ@ԇ0Jr~ j@kFDDH<wmG@#hb" 06 z!l3na|$0蹸wiL*5f_+ɔ^<SF;动_ 7x{&A:8;4+.9u-䧙;PCX2jOŒܼ^X]a;ヌpg]s_Ƃ!2چO2&`w Q 0&=M8Ӹi}&ڋ<'&PWLB#cvvئVfdMk(A# ']mZfێ*gУ5{3{r VFii,w0/./1Pc{kB d3 6Hӟ>}\zTzL 0$~{i W0&Ꙁ0$KbqNL ԝEuנ{с sv2>l?%z imflRjN2ļ`Ź1U1cˢEL ƭq`L 0&Ф&u;X&`L 4)kIV7;2Bny\atx9f az:6:.:&`L 0&`L 8<,I"?;w0 _'Q2*'|*S?Fݷ| `L 0&`L 4qZAz8^x oӿl'/O h dL 0&`L>'|4];{Oz4`<`L 0&`L 0&K@s.O`L 0&`L 0&p`=vCy:L 0&`L 0&`%4diL 0&`L 0&`6c7`L 0&`L 0&\l@s.O`L 0&`L 0&p`=vCy:L 0&`L 0&`%Р ;w, 0&`L 0&`L #]=ʶ}I#<<aaapqqjS^tpum:7dL 0&`L 0&hM`0 ؿ?pԩ:779C<wdL 0&`L 0&O 4M|"_TUUY.:ZK`ܜ 0&`L 0&`L4zLB;s {1)yPz)T]P~ +$Lpژ`L 0&`L 0&c݀&a~-;A! ]׬]ktEWj CyT"\\[@IK\<}%\>.hٮjee+Tyi iIc]Eny*в <|Ku iL 0&`L 0&` EB8mMPr~ңNaZF4mȗax!2ۭVel,]޻Sz'~pk / דj <>pE"R/8 C톘Խ8lX`L 0&`L 0&'Mʀα7nnݺ; xaµ6e-Fs#t&7 .шU.r\7k)q9+0kf<XL 5,*ں~49`L 0&`L 0&Mpa i t1<'۴099 nۨyÚ:VFr&#(A;SrO8Y~r~5щ(:ԙdߟ58`L 0&`L 0&M F<YOe;2gO,bB[|nCT=5f@h|>jhjr7Be|cbl^Q0&`L 0&`L 4ń8W7NC>}зo_8z2gu`83EPuӴQ QpvDpӡ)pYRM4`\`L 08A^rN=\`L 0h֬NO<:I<<<UyEM[ɻG(5~yFVO'OFǖ) aK1&`L> nOqL`L ܓrsW0pM)B6iknmR>W|VeWx6yeRM 9 8M~|`L 0@6ɄyL 0&=CիϥfӦMp73e.i+De޲{ZƟES xCHeE.`L 0&`L 0&F hm۶ѣa0+?z~[FɀW_dva.+,_pK*h.W*ꉕYpPYH/^#`L ؀vW&V 0&д SLe8&ıVm0k^VM6M{f]\u=wN6+AAAxvC^uj_Y ,rj[\X2hJEBP[gfMHJ] >s ŪCe%}4}uX.p~ Y`L 4Y][/hdugTܽl {anG~a1.U4ِJE QtvbWp'JI4n^~!Ζ\pF|ҹBs,,>+R{GF=m=_/< +dt?**.Lr%SsV`a=G- ()Ga1|\!׶֌eYRrQ)K}w^+i.~ K,j?گQW:זvNevu덾}-Gf=~siӔf1O3|k&bEz K+ODoEiǺ_I~ըw!l|#oTe(̃ A i&7SuwtUX `L ܕY41I%! 23/Tk("H%Pk*ZK^&.jL)7viޘ3F-s0hn, 9sd@AM˾(_9YlKEf}Bw'Vu6_9a>L(9 /Eb$$.wj^}{+K2Oq~cB 1fZ%㳓oJNJE,.޲tkODeH#6Ã5z+B,r#;9Zgj~A_}9k PjtE#ڨ|kF+ ?˜L9覰WHر{?{8S\=Lmf7h` &;_'VibaFNx//x^Motj3~ W9//)$%#|GG6}Lu"P:ZujkA%`L 4Uс$bkl*&ñUӘMp(uls*~nVכ3"yvCv>9@Ch땿_? rB9ilhPNsYپKgx٘Jڟ#ț4i7Ou5oC+ͽ:wS_<1#EXrP+ZxP:@musdlzv q9t-Tpy\*FknmmbѷYJϜ2Z(n4Fkc8Wwz+W…_p.[D+XJi\& [Fˬhߔ{끯ɡG xy{MM'_}m/2QckK^0'i3WPÃPHx)}xkw^ xNz3 0UUK\-MugLswf}G+^v٩b&t ?|z&>%Vjt\1){M .f eGtz]6}L}w-w,{h< MO䀤/oRϮH0Lccgs>0Bf؋ X0K4F=K.ۊ7G-Mp5*R9e2l#B%Y5Bl&D" (޷chלO*Ƴu_c`OgflL]_D10fҞB<ٗHAZt,C)DFKbf * 2J\xM.C^vyarb=Îoj<τl3Pf5I%j0L0"/F/:Up\?Wj;گQ-غDvxA3a/ <{Q{*YxΙklTN3]L M $5~;)-h<TK)D/q*cv)I_C(`̤W+.slMK){b *82}SDU8ٯŒȮ 瑞u7UǼy#{Ho1$o_7,8MG#9,:>>T^IS{w92_yZ8 Bng\3NTtc'ֵNjk!Xz|UyX3C66A&uDڍJ9}>(#aέLT?E䮳=$v3p턘Go>#IuwSkc)Rg}H,\_n9U_5V)!q[gOHu܇<-.}ҠbQOe$8`<%?]LV\K34uڻ(ldt|kF|?τr:ϖ*+dɧ8=mmcbꔩHZ1g 4pYN}͌gCL{Rbw6rЦEvLIaFyy&xfUx&?Ԝ|%O:/?Aio>m#)M0ς`!c6–MGoLtړp$:yx6dxIŘSp^zsl|;7i%qzDiˤ*!MZU)E"x=6.ԃ5҇< kJVY{խu hfL 0&`@HBlVv @^G[Q}@0=?Ʈ7PT4V|Gqy)f\$ؘ報l$m) }bO_+tiuSFpmIӉ9rgiN}^^.~bFIb=CjZ'bt.d/d`>'gfF%#MƵo֨O/Ff}#N]!5=`$$%%0l|ur( 4M+}Po(w%+ mc-8GУ-7 EbI_Q$QdgM(()X僛(S4u+~ b~翉!ǰaIAbsWGƗ%)?cɁI!9eI%WRlCR ǛM8ƫ֑v5W~оw .N~+́ #ruYI ۏ*y |P >QR"q-@xM*>+Fr{4F|YhpG~L:aQi8mSfd}{NXz=]^GsDOZ dݼ5{n@ܯ6d<#TVI `Z̷kdF&1_E:ZQ%طI  G› `RjፑVՠ c`DE`[P_uQt'r47p.}I+K#^{[:tǖ7R-r[]2?m~Yk2վAE;Gt7Og*Eq[f2jkV5]〷 bޝhЊT ~mv~>6ͻ(w(Ҋo5U-ĩ׹j[ybw Vϙ\|3.m۶M-Z 78:]E[>j@IDAT"@f(/wNf@ ϯԹ[?[N SxQ?M-~A MK574YS3_UoTYVMYirOD*9us|zRVJ59#Hqj:8"[~|7R) 4S!]̔_!2U ڹp. sFb?uJUzj #X/-NJ.Hݻ>t-/wu߀rӼڵΕ`Fv;'{%5m$?ܸʿ ʗski-v*:+aޮVb,gkr|<1)E=L[{ =4?6&.ӧ VB;xkY!=0 ie!ִ^[M ZI2K\59ZmaPoP2k{Zyeuј#ܚ\pKO .ޝ3. 5+EF/_wp͌J.[` ATL^%-.BK/R_7<.biչ[=ZC -9y)걔D]"^"TO3IxT4|sOٯεn2=1m-ݾTrD.aut}Yd͜g#̗ok#S=ȴH98uߖQp)/Sf^Vkͼ֬V6]߱+?l-hɈ3;|Zxjͺ^3ʑ#Gj* mv.\])j|IFy1Ӆ3gR|OV||Kϱ}O(ߴWV:+ۙl>^^W&iK3Nr@LHHj[Tw7(jxSjwh/IR{lVìӵhf


Z8^'{#q&jݺw`^-jZ#^#UEc*Ie&dZC綦*[Þ[k2;+nh0rO97ZuHo*oMW5XA3*ʬ9zjDgJ?А^#JP^fU,?ATV3<-ţvL12g*u@%mC5e!?g2Q!z@3w*'iFekgxWúTbim}czFRy (/PoʄfqRh>WKS502QfxVkyz7~Bv>5?;:^%OyaE.BѝjD]Xuo?k^:#̤FxW+\J}vjMb_abc>wacjҀwVY%'}\J vNߧ}koy"U}o:GpeE5okSu}En[{/l4 J(Jך)*0jky~Z}SZF V{]PH#;-F%\sͼl/r _^~t{hۖ-|mۮ[+-\}\D ~jǤ8H?:BC9Yk3lvxG/ց};ޢiRz)k^g @{4v'Gvޔ czMKU3MgvܻG+:'K[7VZu.:VvVfo[=a6:Ijk/H߫ު^1м智f":jnʲ/OSZ2DHmu:ܚlTZgVPWSF?E_zaqRթ"I#$uok֨{TS;Y}YF.2Y -SU~vYfv39#ժqq3f18\ǕCFuWV{ޯ ƒ:)zvGܞO#l|B5&Ts} fF+k%_!4#6>i^Y6{J/3fiɃ~gm:Fl=~E^TG_ւ7qo -8Y~Uv04m>Ire4j( ^/䑃ͲǾapI'N83vNuiEX kyiZmMn`Oy%S/m[ds7\@  io$-F.|JASM8_F+o*Z ^ 3a4ŌR:lFטRz$fI13K_q 8g+oҋ}}ˆ瞨{)NdZ[_'P:~ì7΄Amͺ)c:oDPb:uҝYneT?'QDŽFm} 3mb;K6.Q}30ҷyGGTkb7ר'ް^=utjЭomF7>MlJNuyuW炮?ztGO'`P]=g~i><3 2 Нc Gn0.uIs+6j?3O;O[gR)Zw,jamkoṯۂې'P7Gs z'uy3f ]SK]z}SvuTkn*NX0E-{ub |{:rLbn|l;];;uּhVv̬69ꡊ%44xV}c~q~ nCЎg.w4'WB3n=y?2a޻é_30⮰Ͽ䍢Gix9~R>k`,ӟMGY^> (g ] CzEU ~sSJ$u[R5/Zg  q{__AӖzOepx2zކrP<5Rͭ.-Ӵ՟`uuGτWƿkݣ_ Zn/RФi$s5:t5>GhmxD#`8NMR_B'i̺]kt?s^wy*W"s%+OY^g˦2 \)W1=<5X:8~|^y Uݺ'R)斴G)ucEȓ`n\~BΘz?1cze׉ :H2g_Ƴ:}\ߤ$$rbp*8seu9 ,`R{'wWVu'JޢǝjJ|޻rM96o?1F4}y'M5sRn>_ y_k:o`|#xsҧf^7-תHfu fr35,yjfBg& Ǝmӝ;NKgoթv*5اVk$Ega2?Vly6 ڰv~m¶/-&jwzdY8wZ8LL?+ŇT7ۡ}DpFJw(~}nVEf{^Sa,Xkm~ȟ`0VNy*jmy.udlXm6G*ۘW>_+M +mnO6ӆ6Lﱍ}iyj,a<ݿмf:®o%oM7 ֿg}oe.ZWp"ձAЗkW:r zx^kX\TȾ{,kHFIq:^MXkA]51-ݎ?uy??cR#Ϭһjʃ!.^6AiڵE)2=3sk/<;3Z\mu&4YسSG? T=%i4ܹS;w?O,L (ReUnXgѵ$RuղpgdO&}Y4LLes=oDHϢTd^ g‚~wNgΉ; /g=V[W]fk ^ 6> {=j=|~, VVzŷrt? zmj^oœ#nu׮on&wܹ7>րNM"䩨#+MJ4>O9xRVMV]8p5Ўǭl=c~߹*(x~zcK-(@`v<_]_&+ŭ[a&eی.u~N S_1zz~b8yJa^oJ7h쿽#|w| I㶗Na_ l@^;V8x9g'1GҪ߷xzd ~!aQ EsRZ^.uߛιCKXzX{Ӗ+WN)))馛{a{+W~jwIdK[Sy?z!N4?:R f;˺4zĞLj6YQ wgԿ^~(UӼmy[ҝ5|GnK z?f~Uo]@rrX`xO8}?@4yh;vJ*EqYJYWXbdVXޅ:r/iF6Eٝ=\=Dj{-w`􎓠G3 VD?ʚrؖwIgn3g>  .%: !EY?]wn~FnYw4 Y[*a?'N a4)+}Xq}E׊+}| [6l' 6~)Sx(**LIG4ͺDu{Sf yT>o~|s5YkTRI?ԸS/j4RYSl}_4FEtxM} ]SQX;+Z{kO)7Rtslw뾿E7E瘛-m曹X۞7a^ eyu\wszyW=e%OvrGge3'|Ӻ+9貵|D/L5V4%׺vFh(@@eWe&7T,\T Ԡnkq FJ%6"E ,Z1 ]iR횑*Z~jsW`ΌHCUR;{{bΜ<s^cӬ{BjúN^V=t6 웦8j5O^S<1w܎#bgͪNI<" ?TVFq>ƨh#Rɢѿ]IwSԪUK:uRӦMU"sT]Om5E ,d8W.ג%K1w?X+Wcjj$#ڗĩsvЇXVnyCY[j}A^ USMF @     UVެ6L7tSUdkt)EhE9UD.|}D,x\_6uu,1- Բ9tkm2&~哚d]sѲ^)ѬZS%E 9S_jƗyj༡?ȚmS㳦wȥ _h{Qjڰn"~V'@@@@x(ufFꈳH*[F 3wNӯW60Kip2+d.V7_4M},hC5s@1eo͙W9&^zRoM,ȐoϓQ?-?Oկ[a}-ܟ3@(1G,ᅬx  ҥ@seu͠{9*t<[Vw>@9 _f؋gt6UnL> 7?3IkYP5_7,dnޛO>[}ZUnp/|&Ei&&UWI|B[[h 3TO<>XwԽ%Bx@@ڴi}@@ 3!O/K:sL< T|H,Rc/]8 JT2.]~bntb3ԙst-\J$ծQ$Y@nn ,?`'   {qw[rzʚY٘+[bKy\ 9U5m<"   U_$CY    <@@@@ WIc@@@@JZZIR    @\ D۫ŕ*A@@@FMW@@@@7J    q#@-n    !@ UD@@@@@+زeKe|  p5/ۦM9'9zSnpm2*kv' \C;ujCU@@֯[Upl ^Fz `Y(=Z#'*[͜] Vs;^1Usz{rl4e)Ń9)' ҕ2.elZ?2 r# *UrxF@\8sLe`@;9+W|j1+Vvj3*M[F!c1n>9k额ܧ3yu.2/Z}_VYÓөS#=Vhljhk    l]ivқo (l/O_m~?eg\u(AU!e素wEUZU#_*`v)j4+    ?j_.~aԗ&6clKTtOh? rIr^bZ oeó5'oݾ97y8   D- :õУfJsFkatٗ[JhPRי˗U T_D?B-)]4wR%\f?iTU4-.'yaLtCj_vhy:w>/ٓ'uiZJߢ&ͩs性TԦ<;Wǿ,`S1uJYe2WQOc:tVɵY@@@N;tE_o:'Wkgwxaa6T))JMMUJJSթZN5}C09;N;IU4jʮ_ZO0\}xk۲joS5_G;ުX2|>nU-gΙtgv֭j9aڷR:u61ղOWzj{^rUiUT5mXGeZ}YO+'׃ s,--Mش3TRe+濠e}  9*HwxA1uLSZG40^U7MjYΙ2vЀݩY4MstTGɹXMmhj9zpoqAf5C;?WmNxDAzAusǵl͞=|mG}{UT:vb|ZÇkuQ}Z|oȵH  #aLg9ZIj7/ymפ,i>Y3[oO v$iq5ގC}]>{@3*]ە2K#:pV߯{Ko۩ޔz/{7F/':ܮwZYp6|zu&:[:t阩]'/jm㘙hdO ӥ@P= k:^X$4u졌+ti_ۙ^zək6hlߥONxUe^w4Za튪)%:}tU@@JB@KHi@[9g RXR+޽h\ꙞkD{$93Xq\m~u/Yr՟=BF,:47uګC'[SYL;Rv)8G႓ޗ}C2OU>Zu|A^7:Q3fʉ ^(A@^w{jeGcW\ ZuܬCժqG-UUNoL27[ݓ͑`Lqj:v m!f(UoX%Zh7n> a  %*-ǹ+usb8_n֟r|Ve AIz*c8f&?o>ٱC۶Q57/-)rHVߗҜ'! 73ujz7J<j'hǎm:MHb?!kfuP=Ρp;imz2z:ܣ4%D;m6$[ӇֽvUJT:qND\I__!!  Y .~|o~ss5iUE|sV+c݊0Mx ;gF,Qq;V#[9CNȓoz\ &;wk ? TM?TKz{5mVi[Bu3+%c' hL:fZ&]\'Ϛ˔S7P5sJOތ.SF+ܤI#'>~HGN7uS~*7*uR hs\;VSU5II! 31J_8W:mlf7TcxFv@@JGT~^v)7`s4U[?מ~Zo%ҚD߿S—dVܮ[Ww9>L<{\[C Օ\UgD 9i} ܖ@"p " 8#OzCzi(s3m|?ajY?et>Yf߻5ӻ+e;uKg,ܤ]/@:L;צ0Z3!ӮzPqe~2< LO%?+j8gri\/W ;Ȓ7c,ߔk;%,u4>Knp%wTK3Gh@=4^x\oU3Oh`m#_X{G]`^?׌e{ۚ c勾TJQtix@@(ER)^/.fi۠=-Ck쬐\7}4Q#mխه5*% ZjqNju5< q;?Uhcn(_n<~<8U#Xn*e/9roWf$y ͺwMUM,PiGڏ!# eܿʍm')i7SK7o% Emg7?xf4|l+1뱌mCgۧgXe߯Ӽ}h:Hofy "}۶S=;vߌB[nOl6D̜a_ߠq[X)Qr$ܬ;zNo޴ۿAui{~Mv3zslz vꌛ+r޹_7^iՌ冹³ŁGϚ l4n*3ʲg#MO[!3*n|㒹QS9[05ko[!׉W !e@@T&8ߦ2Yb t|}^[wPyyfJSj> C3kSyj_$)U3Oz=zWC9![k SպԢKGM/gՌjh٪}bpMo|9pIU4l*UnVx:*!&e[Yg$\1@"Z#fמ嫭8? UukTc։xx!]f73?jZ89U̫Tn֖[2ǖy;;ųtˁdHio+I C6}vL7eYӕId÷w)cԵϔ$ЂYQxm k#0#MJԡ@ N  WY|ZZ)*úce`? r_iN{ԮҒ+_J\5|.2ze3tW5G7LUV )ˣnOoPNRx%2sv(&ԕzehPPʝuʆj7̈؞(ξXGsK? S ̹29Աz%, {V/ H;{R+sv}sljvq1W{TeyrrONCÏHqLɬvZ{Q'D :Bs5]@Д^0 2ߣ69}ջ]4\ć+7+o/I뱏  P"q@jk5*-+ˤ)s{8krs:_ -?o}G}*ӈ?!:u3d&Ѝ,LY_EeQڪŦɓVV*f]gtﭨ=P vVhn\J [N_8sofy xOi|E*h"(Y"@ 4SIjYz}w ]I ̌*L~Y2v~\1‰b>Ggu n+ͺDلf7 R5"E]+*iLE/z>XE7n,Y_Q b\B]q(zB@^ؿDk7e*YJ X (No,%bA@3uIMc J(gӸpd7HJ)M[R]m^՚T|<-J ~_R]7ʗt&&`kf?lҌ|XL,meVjR!*~ٿ*?U" 9   "WLA  b/I$/_Vy:VimZTvZ1L@1]+VqfrA;m OW/35pn:e[So=l>?".͛x 38tVXm8$TVճ3iOlP.ƂyRO$" !@ UD(Gp&3:`uH+Fj츱g`m(G|j&TC>M+ѳ sfےfNV]nI%|k+u9P<dkVg7F7)!%#=ӗeP]me*iS's)OB*'ی|񼼠U#-fȭ !Tl٢:RJz]. 3g~ziӦ"#Yd  ྀ @q+\Kuf+hfMoVpKK/vJ˹z }^*ԥo1CQq@@ )@@@@ s6@@@@+ vń    wi     j-''GgϞJS    %Pp8p@RV2e\Q;rs}KݛժB\lf~^ʩ*SqcSʺ7]r#ח(wqg3c3rʩW'ӁLA@@@ATڜӧOԠAuQ+W -7G)3Lz乻n\2_z4wxȫm ˗/N}IvS*C{왩×.Ce@3g#i! Z͑F9rD/u^Ω"Ki3TgޢB ߱պ9i>MBr}jUy)w*\'  Z`?}?j מu]wE4m[lў={ԡC%''G٨*JsMΗVU_jCwk4u_gjiCg8 ڴicl6mF@@ρVu[[on9֭L/L+K8ev4w    q.pMj…Qi}sz'Շ|׏L^ҰCTF|9Rl)ݑ@!~;RM.I;H2O.Jk:Coվ lOR5e]ʟ    q-pM*VOoTJfu1=75٫oNQʄ( pFdVȘw1O$ )þlXF    ij5@n׼;k&''#kSMX5M}zgi꺰"^>b9/OvhHڛ2n    .phV̚M6Q߮)^Sꣾ@n;e!vŒi[syKށl)kA=bAڱ    C\T\Y:tPqF|XM>礧u洶Qa>N*1"SݴNdb%O]ڷs*UfK˷]rލKS@@@@kQGYkZ{3i3#QbR]UZ *V*s}>K:C.=غ6mRR}ΐx    p jZ]Ӻ]Ӛ,5 $ գ qr>33S22Fa9 : @㣇  #.DUۤ# DCX6 04?,;'[r$??_rrrFazIp?iІQ   EZ8ܼ\:uJvvPa]Iijjsə3gȹy-sF{t]hZ"  0*,< 2ru׍c4[l'NHFPG!s}Hu@D@@`t X.Mx6:G5䉓NWΑ=>?A9Z?1`P$@@@yf7y?xoH%{k3E@@1& X:qĎ#Dڲklg=  MKZۤ$mdG\ vMٵeH-\#%~=?4O{@@HFҶSv5 `cٵeH-\#%~=?4O{@@HHIkEi h84Q&0ܟAfe'A@@ZLTgLy-S[?_ڪ)[`um{ݲ%+2 #oӳRW.Ͽ9 ׵5 c^Ѻш^"9%0Ë'kNz4]'>8ܟAJ@@@Z&_50CETQYh'I8[Kl} q%òm՝JT.}Ik@\onY)IJhQ9Z;(r'$,͚kϮYs֪Zz~x5zlrMh) pR  @4q}ڵ5rmȥWw#G~ w}}pyZY\Y6i7rD^³Ev^3(U(>~ܭt8 p3Pctt802{hɇ"@@@` Tʆߒ&Z^~Y_WQ?{~bGQO[D ?DKn:1d#Rz4) O˜-p/`hJQ9/?H8z{^835M WM   (()JX{J{GWz,_Ll[f/67OKU$>4]J/2" tKm %IyirgH8"NuE6Kjɗ>a{dWfIDVNa9qS&(3zZ+=Ƣ©2<._**ǣX|R)+!l˹l<2̱hwW:OE{O2AliuK̢͊t9ע,KJ&ȴ]:>^W:Us6 ).uC Gʉc/mҮh_?heKŽK ehe/>>[ٲnI}BrK=$fLTZqymj8"'sH&ӓ}Ͻ~<%3o3X^޷=ķ;d@@@wQ/w*yh뵩/}=zf0Ȓu[ ;eɜ^o|s<*(iZ*[*ˇw.t [,{zmRdY/,כYڽ;tFjF8*V>We:j%2#1g޻@d ˒Km ~Gj$)PDeY_cfR3w?ݤR-Y8+ {Uˇ6}}˃VhuS1']o'gs[?N:TRlzCkZ-=w_/], S\PւgdlNkފVʳy} {}?v)_}Bg[O<z˵GM{Vo'f'?{,*Vku%[}1ЮsO@@&[-FߥY;exfk[6_q4i-2;!qP*vvu֊L" Cx@!Z_#  @%+UhlVǯ؛VHMarMzïm7ۺY9'?9U,=-oWjW~GJOkYv_ҖJ=3XR]B[el~~r<=}2-zV>(_]qlSò]زUp®i{e:u{zӰG/MIտNo_mbhw-^wOk򔻓ۤ^ׯYiПKwG@!ymy ԯ$˯gflZ{AdͪXꥢy^8[Zʽ@[ʪz-t҉4׿oYlS͵*ڵyީ5  {۷k,5W6Ǫh}nkN'Eec B3ew^X=/+*mX9!3 {˾;epEB?yrWz+U㮚S&<-Y5[8c rT|I~-&J}Uֻu]i=,$3-WZm)׷+{3&Ynڡ#r2ȇW?':Μ'5^9PwS.S9Oy+?LWG=ϸVKY5/ o c=+ch^P ^X(v~dwJmYP]?~{ٹk;Bb,)iE[B  H^.{tL5oz)ejHԝbyDG7$b/.ǖG>-T$eR6}F_mEҕK1Q|5|{ސGL[>uKOZHK4h߭xBZRVُc)-VEQ.^lۥM.H HQ4b_UO}A{L]Bɒb$XQ#.CV'TCZg\'KW.H0]>]3km<֋εk!bbJњ{dv/ K3`F<#>/@@:& n ߱T<]6]'W"-r̫jmu^~֟T`of1j[*?_-:H[|S'p/:+mkջH9VRpn[>n 2GN;d ON.|>l[R2VڸE`KKo̓R]7LLR tA>z,7nMS5@sTNyo/B:Yu18wgCrm?%@?G@@ U?^Z;#i!e.ilZ OV֮}oo裁t8!?ŘTHI%b,=(%-=[ޒf#^͊%6)inŪ<>g(-1e'_AjY=gC ̭Y[[9%2c,P2'̫}'|˔{ɷ#V*>&ݡɆX $X;nd\#Mnp{V>}׺ٸi0nKŢxHo2lʑQm}'yrrV &1 S7 6=)v@IDATTڿ[jŔPL(JXyZƹW^>;{JIR  }Qo__ۯѫb\>(vًr{=~,vl-[ǽ]cyx]3$e3dޒo?{J?[!M]_g}`L[>e{O>qFyqoZpe"oKv0Ѧܗƻo<  A{qg|%iKL][m7q@[jo~'>ƫ#-U,y` 7}X;̃kex䵲G_pXX}6E! uX2x}zޤٲT;'.o   YY7_/RH}h[ÍrMr1ds_d͚5p]-zV~FVX!Y @&#Yw㔒\[yHQZiy&tߔbCWd>wx}6._]Wmz oe:wK>9 G՛ySvluB[<#m7Ǣ°7u44c^ s1?Tъ+<%w 7i9Kf'rgu/ʁ&D >7FԻu]X*Wݽh&_񭟊/k5l/xShpIYU}S51B$z8V?^M?]iiCڭ}O;Ӣ8OKΛ   `Îzgh Xj}W˧-o_$j뢵g<~KYuWamác!=|Wh:Sr6^*K>isJ]EVKTzl~lEWn6}M^S{7!D귲B|o7ɞ8[-{PתB6^z<>z-kW|A\UU5syǒt> *䑥:vA;XJ'~XPV&.Nk=:ž>>MwﻱG%S.uR=ZUɶC:^|6% ym>bFLpsf\r/;SgB6xX_ᕲi͂*`F KzyTk,>O6  cL *t8?u& lq*;ژ#ORo+dsʜ1 ٹ)6H\/Ϻk&YTm ;%AHo߰RbCzw1ް]:'ܜY.ǡۤfA>ut_gS>v!)ؿ ,Mey Ruc z-|&fHf?lX(=Q^3fy)۞FU5egc~J$jf}E_)UٴGCl$l'e9o_gq=\u x^xsx*>?@ ;s}][KZ(G @ȑp!)(.ԿFrIQvTAQSX\ZbxQ~{X .w.y+DNAJA xt&MSJKff'l /+{_|#:DlW¨nW-+AYΌ]㑨*R+o)z!5Szv֭{d IBBSb1p_1!#  7nf!ikkuNh6-IwGN,hgC(z@ z,  ͆eEֿT-Ky k]B/qoה][v2BIoOnҫ?u*9oկhݱӪO&t1~.c3#  0&2ijjA#0Z욲kˮZ;S^4]vKrDv<@*f-lE]*Wg}2䔻F{@@E Yc#C\:'`הkldi9F*ꎲq WK~S$dJZ&dt//Љ>A|uhAP'cR9@hii' 7t5Uw*R~]NQǾ.W&~$:j.ɗ`ul~   A ??lE6-&KYY٨hmmv\pAJJJkj$?P= Hu@|@@P;4i3omy7[zzzǂDlfdfHnNʔ)Sعg\#g-9ڵ𩢎  Rl<''G&L:9hzcAd ϼT-++kD'H>Jq뻯 χK޻ޯm    x!Z(\>1 $ x3lZp`6m&ew*^t_hq(@@Z\u(k\U@@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@74h)@@@@ hA8@@@@7q[    ?>    ztw    =w9    @BӰv    7˄H 'c@@GVjHG,D54{m/Sólm' "gTp=3vn_9(o6 I[5<(?W ENWzT3>iړ'N:]9GKwN}QhFg\ 3 jǜg|q3Pm pu}s 4CrL2[5|+;*(ٺM.?=p|g?l?P3NM7)@v6QBN[WN_f+Ziy3Da [ł5fFZV Z.qnԮQٸq,   ,`1l 2TZϞ}8 H?h\.e%b Y_]ٱgnu}ΘanAuv kv[RMNBx~78-nzg|X H>Uy ˯y)gTZcP7:?˙aBq/ә2r[5<+ %MvuҮguN29adj6) d,-/y7kf+|wh"/F N7n:QBYL@@.`m͂H h:<'{F3Ob4koזUuq|QӅZSg\ZYwO֘XV: &i1,_å,g4E[Pסl̯܈ ` YpթB5~r5г0mX Y"N@f-p뵴cңn(:Uvν/j:N[[Vc9a+\J3˹"X-łGOf-i֞%F_3c@@$`%,GHcP >$e9@'kNzMt,y="ǏVHޔ"Ni3ʥ29G@XgZ[#L9O:ĉEάu26f+a[Zijv0irmIV$ʺpj2$%݅N0d;NvJr4;ZOvWp';w S|, :ጅf!p,VvnN(*ȴ)NfP{8ǫSd7?I<]Yr}Iu:|Ovj9e\} M$"ʵaB;>zbcey4a( #e   DI}+bU:<RbD_;&[4@|}AѣaA86Y*ٓrT_#Ln6m*}Jz^fKeٲ-~Bzz*aiHզ]4u Ni!Q.ehe]:s-Պ m\g\/&-BL 20fv̂3%.'9Q`7KRkm'pJ\j?Xj76e4_`Y8glޭ[[*OO-O- .*_&+ԥf|cOs9ie[B R7f- ,lҀCP(?_[ٌm,Ҭickbeh/ M")Gwc!0L-%U˃ؿ]wKyWHe+Wʾu )7Ŵ 8N_ zS{ }N Yݿ-a]8mM-ܙxcάeN+ R˺3Z8׮-B;`gu, ,rpj7HD[v:& i٣1*tmP̞qZNh hZYN3[WEc#8@@aAm fˢY21h?s [˷jcW[r8Mkt\5^VG~y[Uo- 6{ueM:{?#3cM|_V *=#]Pu4ʮgl6Uz,M;.gX83(Z|{"y1/ tWaH>.S.&Tw5Ǔ/!_tR%ܙ:2FX -4݊QN=CYt^[fKCqZBgXgXR$% ZʜÉWy9Y 8k_[[ No~ f8ZVݟ<V@@ MVћñԭ任wΝg]T-/nK~ Ɗo-g6s:JTl9%"~/]*jdnxfsd+5nZE*mv3{+-wqIĂ_C bv).h(S'K]!G[}k˯PP.An Je'ސZbkR]:~YNJ+ipV$7hh2y"$dNw= X^Q^0_}_\@@9R>}sp4jv&mMe[?$>'s4WmֻDmerw 93MZh7h劔zm~'#")0@"&hPvT+W&=ЧP`]!ۍ0(Wͺ%\lwnNM s[bd|ӍYvgZއJ-i«Z7VG[-lX%әt8WXVVbBKoVg9I؀   0f{zW*9Vh\"rHK ׎7ԌjsRpa%__??"G.w}w^?(Z\ /4%YQۢխo;S-SU5@&G--ĆY7N'Y=@6QNl\̄:Z_St|muhn, Fp:h%#S2KJy-:N"ݟe]bAv6V17;WƼxw#  X([+/6s9<>_}{5ֲL?1ܷdĦd|C,Or[]!7U Wݿ˱gEO%SuZxn!=UUnѵb7MN^4M[Bӥ 9cY%'ҍmɟiHʷ][pT3rt^v{}3ܬ XU6yshrxwOf)2qe&[^Wzo&MpZ59/'N59ZNxghW0\rLrtj4kضVe\oPgu03?. z="tb :^!  @z3Yj}3zS4}_Xc?8bdIs/rܙ >z@l"[v3 @]Km;ҰWZ@#SͭjƗP:y).FZ ZnnJ, 9l:Ӧuf -RF*Z5T8>sNrYgckM+kf-)C[ƏwnQ5S..;Sekfu6WN.^YPh,|$<ܙ}@@Ɛ@h,YEhu![C=*ٵIĝ SN;;$D#d / pW⻐T~)w뭲?l}jl~kV;|kuOh2e˦Gbl~YFnW|hlM^uPͽM4GbIsz^nLanzDn95"M'HkNCOV'N;cP>i]{@xyծX4ex' ܮ!޻ '#*3ʥ __K,9Cg_h0-G#kЗ';aF^~mjYiR믫&}*׮QP$Y:L ӥbe&.ψOgmrôI:&[:&c@@=)/>+ݣ9(k˚oL'Gg ݦf$n N/_}<:7E8WAOY,_M%N(nك.@qlX p ~\=s^u\_xqt}U?<d_xh{T6>YrOl}s?z抵BXu&ͨf]*m-^-k5$O' qb-tX׺:h$O6.Sa~v͑Vu?Я˝3'@2$4qJ&i,j 34jΞtv7{{kضV=љ@b8"E:kiQ?z;@@FH $w=}J܆[)پ<0S?Kl},rxKUle,u^y N=7}noXdm'$ *-ۿMj=8E+WY7v CW-0kӲozIq]H6l/O,o_P6]7IC-ՖS'O "#v<!,ώ}l ?{jB 6roy Z5.wEu4/Xpv9w7;i6]g`gS7?vZ=n2ovkף>-,:kN ~twtHsң2N+7D'Ȗ\ ʹg~UgŒQT]\mi6{hE/M-R^$k!  @owyGsjƆcr^'͍\4\J .; K,҄]D6:E59bץL$n% 9Rs-R+{_|#Fr 0ܒQ\(ѶNm"R4^53uok] 57406~~LePEf_8V]ښJcʱnhg[Z.v] Hi/ ~I9,6da~LZdqTMSW˂Nm}f3P:Yzˇ7 eVi'֪[oְ]z'*\-zPfXXKT[ycY >nڢLI<$OIVgy}$ ?[Nxfbƴw߿?ԖdG?ϩ-O״n6AdDB|Dy@@ }+ϞhjL6=Z0ߏp=xaw؇o>z4b1gu<;[ianJS+ZGl5W]:&Ώ_a?k:g7k{y>Oe|o۾WwXPwҍ[wdGjR<%Gї݃雽S>{?i>g>+z9쟟M^}:@@@.>|0=ACOZп`|kr=0ym9USU9]?RǽFCjN5E'H+ZT&UAm4ҏ{Ç֚λhuӶ;ivr"X# zw[N;s[ZC 󚪻ZlZ,s*pr+F 69ZoJ6?οs@@8KcccVmB4k\QFl#ppf[V q6h+fzS7se[Ukʞ©z}S6:w֎.5VZqN x^jjso.jf#를q?<)9E@@^xR^Oifv&Ά 6^n56<]xɚ6{&''L~/\FmK咭9 ҙnZi;=Ze-WJAQ^K90=rؤ9`mU{(d_ -j,K*,O,ª1wҪjǾ`k_5ܞjcy7?}X^Po)$l({H*B &jo65<΍  p&t^ŻiO=HӯAnH+zZt^z6"oV{_@Pvޒ*ŹוYUSN39D+yɃ׊#f;yͯյgj+ky{I!үy%Tz}aQJʶ|9@kj=6ߋ_ {W]@>]AFo?R{q׃+B+驭>OClPa񫕴}.ꩢ#9ʳB[@@^MmP]-pxVv8U.nrF=?UiZmq-62Y键.;_υVڇ2NgGS/Sjکo\oKag&!wچ:s5+ζu/:P:@ks9g<\VS+\qʱݽNٕgsEڰ{IfJ~=R)Uo   p<Ւ)ިKEpW{X#\Gt-0 7npI+$Za߮~곩:*v^N)G5oh * .OkzHzL^3WNSwouGOZm4Tr_Mhk|@闃w;B޹+.jӒq    O`hv9GsVTB4֧GZ2IDATEvkс+S0+\uwUzbע9M'-vD5W[UpL}t7_pF\ګFvN;^O+W?ȝ@@@@ @ ^,f2ͻNjbwM_.ֆnoV^8GQq,7?A[D@@@@/,Oע xN}a>4 *d]fƙ@@@@@ t5W>}}\VR?Z   h_,*R X}΋   `0CAC@@@@" Eڄ    F-P@@@@hG6!    @ 34@@@@ ZQM    a  A@@@(@qTh    @0CAC@@@@" Eڄ    F-P@@@@hG6!    @ 34@@@@ ZQM    a  A@@@(@qTh    @0CAC@@@@" Eڄ    F-P@@@@hG6!    @ 34@@@@ ZQM    a  A@@@(@qTh    @0CAC@@@@" Eڄ    B`ەTt:T*h@@@@@ 3l6SRVKSSSiT*H@@@@8QfTVKccc+ZWrbIENDB`testng-6.9.12/pictures/project_properties.png0000644000175000017500000054041112732165123020714 0ustar eugeneeugenePNG  IHDR&uS iCCPICC ProfileHWXS[R -)7Az;FHB ˢkAł+ (DTu7I];Μs? o2QyH/f|B"(@xFD(ce@usqWQps 'srYWg y:^ov@A, 8U58Y-%6ё@XTTGN%C b7vqē!Bl]ԿLbci.!rg9deЅ&  V,Ɛ;O X <^雷bFٹްf=pX>Z QF(f % Fdavh|42ge7p ss}lRx~Õ/HD[yaAܑ< ;lF(sև]/RjfYYT!Kb1cFapuyE 2#Frnؑ1kypI=NgEHcCh)7!& A:_?B |T3'g(B~^Q.ȇ/ZHF%)Y:!5;1f%}D?86d .\ ,oO DŽ.] HZ- BA7]27fBv C8W-wA EܾĬgT/g*g7"yx[q`%;bgKX#VkNJx"Y cEJe81>5@(y ;'O!sԴ<'"s|$!n#t9M8Ae7KO}齁k:"aT!wzd hfª,z6BP ցM` *punpm` aAH #j6b!ֈ#"!H$$!!eH1RlCv#ȯI,r D"Hb(UF5QCt2zh4:MEst9݂VZ,zv/A `1G L-ĊR;5w}8L<g9B|5 k:ލ_ 4L$R R> ywz CD"A4":@L'#& &6;=AF2#I,RtttK@%k~D2\JO>MF~FQ1q ̕Y+WAL0EbDqDS)K([(()(oeeeueddn="{Q[#UjJNk&][fH%hkhմsGrt9 @9"2Zkre =gȗ*߯ `RXPpR "]J1\1Kq~KϕHJJJJ{)1ݛΦ/寧*ӕ*+(تĪQ)S9@F&c-( VM84ڄU=TEUo~RceWS{OU^~^DENjjDjأѦ1)ܪyN_塕QV6]MQ ӓlahtv .=P稗QYo@_[?T~=G4 W>7R5 4*01z`L3v710aB4q40aaڙ^5Cxf;:'&9MOtۜjio^cmXjQgj'Njigi򾕒UR7֦l264?E66mlwvv+; 9;$9lwiSGg{<dwy>h w)=,ݮ]nL$]n]:, z}E?j(+zmQLs|q>q%q]_IPO%'c%NiZto01gƥ33g%?5X!).igV85=y~lq]%g))%)S]S7yxwϨɌ5[G6s|X”(%l6m61Oר iiii4hbce}ē{ǻCƵG}s$pU6aznȕ(/8 ܭhm{} >]NHHHH 8 em7\/BND Rd1B q᪮Ai}W^9H 6߿_ȔXOӈe2ϭy)ϳ ;wDԞG#_o4HHH Уeme#!-p:tL;A㞉)^ShB틋P[U ۥZJ ENN&yX fZ}Ң fzD?'㉗&0] L)_?T!W9HHh/?@1ʑcc|X&7S~&k_*DnY/ ~t2q(X%   6n(s]$Ho3e&"G@W muIqYWHQed f^ Py%J,S}edd]f'Kd)nw@l`ګFpža@Zt*fgϴdHHx'P_UuYfT葏b19Sp2彈 ٿy_# 1Ct&wc6=H$@$@$>nyCsψЕdj<&JO@G E~"(-A/"D*8d{⌙")G uVyTފY~7'"B-GsPj2BkďDaPOUfHHgУh9bWX&Mڇ+y&#' qྉgP#&6Z aʨ'7E4xR'𱝮lpŏ~3&bs0sޞ Y?g@$@$@$@ ~1.ڗ8y3Yni;TRTUPʐ.I2ܣlPy:fg곰Z'=HL2m'£ب5"XhNo#ﴶ`HHD 0n\|zOYWNj+JY.~cL\$s9Hl%9zG1<}jEa^qG$Oû65G$@$@$](k.WBTa.x´;ּaG sO^AJIt_= Sy@1|01TʫMv܉{m߉w?@IC4~] JhdEI%v"YwD{-`[71j";='dGan/j/;D׶dCtL,SWhP&$ 廷aO|`Gm C #n{jhv|چ3X4TWE8TapAEU2b}Fݑ*Ȭ,c4z6 A*T@AbҐd\f 'Zd.\xZ= [bFGdd E?{R+͖c ;Xwx{cw߽cMs%8\ՠ.b1d<Pk7ʌ!^'s\zY~yz`HHHPf ҒMjcLǚPxcUKyD`z䍣Z.v?d6*K"&*W}>UNt#+iڗO"iz LS>U߅Tu&  㚀vJ43})8T,SE^JDRkޏ~jy߇݇:1Rs1g+v\-7/} w\urM]ɸZ),|Y:- p_av2eg"([Dĩgn6<ӅM;p 7"7cynʝ}8wʸw㍧r ?Oܩ`T#Xe,Z]"i'\,5[}aE˂+׿v\z{?ggMV+.4bcؼ!sj];+p6<"{ڏ\\q|L-LYruV㉅O>_3.R瞥=$@$@$@@2 "ɻe] ;*y޽KƓ/THR2n*sH 5Қ$@$@5AW'˃DU \lLvc9!ή$*V<*3R2 i*i*=-vO0Sr7$y#35QvHH0&g҂+zr켹C+/%[3COߩs,Kt,w 7w&NMRnp)mf[ۏܡjlH˾7FMpn_'.P} O(E#L&phkJ)Yskdb:]Ze,we;td ֆr~Iͻ(qy^Bzٙފ#?â[ym{_}XONvke.6b4[E[`X+cʷח?_C8+.O@VMoF!ժ[63 &_896U{xݭ8bZV̸C~5T`^3o$@$@$@@=ĭ DMaIV1Sk☵yM6ۘuzv &[[Ev__RU*{l<' 8{GSuTgS5xƅq_TCO"w16P⤾.Yii{qNL%7oQ? S5u&brCVzhBt"ƞs5~.Z8#V3UW,:Ȇe좳Yl67RIr٥VOq8+mGk=*<$o:^[iڮbeb7oVӉЧ✡:jO?g9 )}ROm6,6,"EݳPsۺkoe wjr?FMܙz1]xԖ-z29"> %OU{MgtNI3)mV7 -FVsS±Q\Ra]8q`FJnD[qsE(ӗ:n}3򕤤ּjv@mX@i#7F袥u 57n'#@!wݴi齟E3cDrti&ҸL;o_VdaaL9#u1L乨ŷkWΜϘ)"}ud  @!` `h"dHɲ. ݯS뻓j]˷KWIyy6|KgOwOSrT&}bzک,THHN0%Wl\}(*.f$(iEice|ݓʯ㔋ku J5eK܀5Y⭮6p&1{)rRlnnovnPL1n{jBxiۛoby0p(ss7 feIAV1d['|Eݏ`ɁO` .}8] t*nSWOd #1\|y6< G](*hc>*XR|Zl-Ƽ HD-ZgG,he oH]T}P}{j_#%Etߛ)OL/ Cְjua#YdHH‰HxcóEzX|=gF,Fj|Fk[{}&MA`1@8$1q=sWqc-ظ~=>^۲d=|^//o8ӳ Bٳ[͡-bGsb=j]zUL7>zߥeI3R%-|:Yˮ/Uyk @?#嵄K /=MT݀n͂~VvLuGyWAӔ(KCo߮|D$SSoJ,Yֶn ÇVV~ L ,ɴ6Nzg=[6 @?&P<KHa,V,onfqAn;%@0, ɱK3Su{׍"JN¥W~9[ -Ggaiq&6=< &i+X22ׯvG)َ:.r+. ߱r ޽p{4M-RczDҬFض"viV&  k]( IhݹQi)b(5%Gg6dTSF6}:R.}w+LHjyjjj}k.*_,4XE4썥Ρ83u*>ZT.|R ^ZBgVVi}ÝO<=˾؅ʦv${Z/o$JoMWg,%,|cm)WAɓ8ckV6 M3P&icE;3oʱ#_| IV7f}y)LǠ=߬{$ n0&Q8sV'{D䴯o{x5釸xBz'x|UvIHHzTo~ ʓ 3EKeJɑRyU^U} }VRXnn\R7E/9yڪ%/Sp389r6wUxMTGYWUT_O&  @ ̸S}=QZ>^{JTsNUruvf/-;7\83:/<_@W ~'<"P|WtCxY٭0UVz< lع{WB9JQbx·=Dm`L,i#͝.chXG>ټu,ÆGuo2U)'=(Ts𰎾Ɵ~M{Oyrqdk0*uƻ'L;)i4]dog_7/KO܏_ f?^|+KY3 dG]1nؙэ6,{} !Xakgtf[x~cOtPl\۟aG`3Q!g9yALM3yNhb5{/Ēb{g /sB-S%'y)(F=ޙ=̐ [lKuā:">[x8@e3VvY؀rD}mʳ\(&AvUjjexi),))Iɔ7Y_{b|XQN8bcajuA6>hĴqU8&춝m^oU )-Jhl)Ųy` dOh'obp]t˸ 2_y*^q-Vû{Lñ2ny =m2Ӫ>y'^f}ѼꝕHHH@֌'Z3 &:ͺ+ǿ~Z7 {ݩ75_+;BdX @ +B95(Q>IaPH:A=yYx h IH$kɞ?"p-EiQ%f1%qk-mZghW5'L+ r)-!  CW3%  M%hIbR(O< OK5 #` |}Rv{`! @ظqqq   Cl*){p D@]{㍕:B(o{& ìc ;6lPvsd    lhQ((H`l ;4!D,A$@$@'&9-ΊHHHH@T %eHHH#xoHHHHHHHHzD{IHHHHHHHN(;Q$A$@$@$@$@$@$@$@$#ٱʒew&        8 DDDL^^^S        "ă.ds$@-zJkՎeʴ# c[ ( 7         e=$@$@$@$@$@$@$@$@' e'ȍ4HHHHHHHHzFBY5 BB r#9         P3~lM$@$@$@$@$@$@$@$pPvHNHHHHHHHHg([ ( 7         e=$@$@$@$@$@$@$@$@' e'ȍ4HHHHHHHHzFBY5 BB r#9         wyYYQ__\vv$@$p\툎F||<ӑy\OcIHHHHHPm6!55iiiPR 8j_444555>| 6KNHHHHH. eJ$kjj°at:5,""D$@@{{;Cy*l߾}P9G     8a t)FZn< 22" HP_ }j[&֢"Pu '$)))'f;NH3IHP wۨ62 $ʋL$c"  C܄LHHHHHH_]jZrD$@$PK1XF2 xԇA?~o8-'}P3 wH0~b     Ռvwܭ` vGvjkkCmm-!eVqnP(WZY1ILDd[~R6di:t7e3ХuĚ$@$@}D JPD9%ڝ HGrr2|;aHHHgʓjD2D7HԄjHFe6*S kwMDEhef@bқs?o妺F8QjJ7,Y"7Vk"`5Pf|I(ȗ'%%t]\6+|bqɞI_pƽߜ+GwϜ1pϥEk[m{n1ZMo#pҗp6m{3} y6aGK?,{F۟x ؑ"s$@$@$@$0@ d-ue(i"1Y88BT%i^duuup7t:Y 'D(kMaKhD'b^1]S$KI)dy1$;Y+Ӭ´dR?Voq㑨T>KEM"T-"lT*R7Ӑ#NOLfgLgq^\:Vyjtp B<ډ@fظq1FN)Lx$   I"-[ũF9!&nM$rLqQK+52 lv"A%=gOD(N~ b8JؓF (2gn ׿_7[Mޚ!~FDfMaiބUD΍Xb}FYk+bq/gb:gմ_yh̿J΍ؽc5y٫ܺ3c!   $k'+œ5lįSR_)Hm2i\zY~i.sKϲ ~2mn g8ZZd (¢j\w)i4PKgc,bϲMFJ:Nw+)..V:luFKc#Z/6[ a{]KTiJ@=P&nƺRJSD;:gy M-JHmV,5~[{;(MMh'b^47"ԧEÚ9n%qg>|V⯜hu͒Z*kLD;J[Ϭpj^$6لzKˡ0m|8u`אd_TQ֯2>%sde}[S1(>m茏w٣ GjT0T N>Z E=gPޭUS0ip5z}-`~ eWhKn=?e<6o't6|xYx`H7(a̿|ˢԩ0TU~QH:f¸<ށ:۾⽏f>4ORRbɧaٶn?|TZ{Xw-$П8Y/v/Op11å={VY62w\9& y0 x hdGtO?y ("'-%pi48q8oLsr19$fKHuL+@=c>(Q–z54JR3NJ0&]T^=gY{Ȇ7=ښڴfj7L({GG,BRhS]ȩj@jEj UJQ) Pmf,dbP `UشcHibŚ-zw?+vӏ1iVSNB~EM Ny"hd:9tGoA%8ss痟qԩa'JQTD2kr*)Tx9pDVQ1W! kwaL}9gk5"YܐbdXl^ #>ngǬE̻ptZ<XpQ . \W=}כx&]t.#o=߹L/klyFyM;_\L-l&) N 'I2E2fTzA_:[jcL%GPx,~dE -M c<%)13v*Y=ԹڄO%uKiJ6ho<"~ZrjZ0嚮v~BҵU` ΋CzV@.TGqCXq8锱NEƪdvK>i0t}6"YO-@j{znɗbwi.Ƅl@⏍P5jt x?;#dNH5sStvW=nXݢڕnڅܴ1.mz1ò6!Taͭk#S1ftxm¾'Q ClTM` 9'IU4CΓ!E2aJN);+PMpx̊G7X/fwA;"?ɨ[,&*  Nƈ0=[w8:3⤬ط{.8G`7bbb}ba# @#ڍ?d~w_:W=1y_s/¬G/<깦2w/^Nϓ/M\8޿}񣿅+'caG.r#7}mތZsɥY۬,Q&]yZ<^q!{8|H zشI-y>KcõHy>rD2"7F0y|1CmZbۇxgeC fGzPqK*gG4Dk4+.' "G/bSWXQ&Բ߯2OIHHH 4V퇫%'H%,yE"9)]=Hv*DCl<6VFq9t~o쉣$FOc:q% TRV+u۰l%زXqIXv4J*liNAnX@$@$@$@@,t5XV%K݈M#A#ʗRAy#sH<4-卤}݇> V[bb:MJS' ݾT_LvԒLMPK/O}d#Y3PI9꾸hek} q5ЊF%ѦªMD2%0*/lM(KJJ%漂7kc\Z&vT/[sЖ]!;E Rh+lzGrD` ^$qAz[@EEvb{SO8uDIϬ;6 E.) rYޏ~s}Gq 1~ow}wꚪӓeJ0Go'S3Jl e|~@S5U73A͑&1 eXHuUr:"YY둖Dҋ").#˶5ERb% VQa\8b#֕s) C u`Eە1O KCz.ظIߘAkbꘜ˝z|H$pT4lE c wXbÛ[얹 ExZX󏛐W5~6<{{l]}'۽#'I=٨"Okk&aYpDfk̓ H@dDjCkc=Uv&O©GNI[ Boş$@@<Ϙk([e|k}kfZ\3/}¥xe;շ+l=m.t(~~47z#g,vs*3   3 =/C΋<UT JT܆C;#QN XLJlRef@KV#\YWUhinAuu5$zNvTPIys9W.RyUL9(̫G0vWњ8 U&0KNE\wݵ{^$3杹YrL6$$k#W,AUck@w@gSYV S # lxOFܲ޲t+l5QeҜ:z*;\/jXS/?][bkZ+)d7 ڋUEZQknڢ.J9ℼJ(9XVjWXW;tFfɷ(/-ݴLiL B?I#yccM;$S+`} فٓ1CX3AZRݑ>y>7e7VACeQ/u+RW-kq$^xoWe=IrH%jgJx?tTX6e)YRejx)a/+33OOULgYbC6JBzF"MQQN!C\fiSRR|޴w{"=11>o ͉X7 v9v,Yl&;rO*FŪ/WcysXrBe|.y]\ʊV`nQ*vb<:2wݩGYdgkqh;<|"RkP.Ӈ cmꐑڻ-=aC0o z F߶̻P<_>y}^.6ZvCƣ(HysZZoVa\bqccg[` bfO,[`p^xgWbh9IR   "eeBXY٠*k֕$#]dy$_8&QB#/&i#ELQ!X/qx׵"iRULLITr& YjCEfu$S"Zmm֯ zD2HfkW`6/I*9es Q](qMCmħD㪛.@jz"TwGsvdx}HJONPV *cHǿ,Y7؆]77ťňC?‘qS&b}f9<$yr&Z,]F.q7֗0cĥ 0r3dY&ng|B''Zm;Q*1T2gstb&D AaUm((Cw;q:tCP1 ;3ۦ+}w<Ӿsi?dy̙w7Xb fS'$@$@$@$0p (%_*HbVd:OTS&Q\ġv P} J$sGqBPK m4R\\^\{|N%xFw:KQߤ@zK. v͓:ZygkE-״i&^\R2lGVNlԕ25MH1;ɪoq[b *Y IQv[=1_.#L툉'\ QP#&$ .`qzHȘG:3pYgaCw-mKJx"6N:s0\⮩.s12#Ķf8bS1b|*ji!HdV]=fd/>f.(BYǤ}o\ #`z7g n8R&cJ5,B|YؿE6$<$T^o&d55vJD2]O2х>HL׮)KQUb#!G{.oVz/nKq7ˠ2m/VtH\cJ5Ud~z=6&v+AH)L9;csew$zqSA3;A&X.⼯ Q|y!K/]ZW nQj.Qtङ|۶mÔ)GSO=tjDzCexQWqYL7x%o{S]Ԥ}331pp#ya n\qb.9p 4V%ilBēH |}U6!  41լ,رR,ܪ{~>mXpKh>e!8dXZ,jwK%1bڒc-#ǑQMQOؾv,4Y'[RρG{DI/fHH_P(Lm$$$ #/C tM'EO2AeKX.҆ny<6RSS|竜&C]wh25dQQzHNN2%1 @ 2s 4PHHHHH%)L%u3\Uq`l{{neeeN Ң}hթӱLة7\+0N)~A.7 0{pj1w+ZKgvcܷ?bZ. "PvX qIHHHHH"pbc<ӚYKKK^kk PO]P$S2{?NƼy=j"~ϹT~(RGYD2X@.0s|\*]UihG]KD@ lI.IcLU)$dʎq%l zRWx2C$@$@$@$@$@$@$@5~))j9_M0SY蔠%Pǵu^CM$H[kk+/bu vvUv㺻^e6       8[JQX:CC|h<-#55#~Y~Rb4%<{H1Sq@[ge,W6NU?ulڴ ߺմy9ps=mr'\W8nkJLxt fݮOHØo==N޺G?ߵe.:O̐ qN_(TbϤIpꩧ0a3}X16p7du=;Ъ413ȯ}Xr' M+[ˇN݅OX?#Gz0Uk;p`qϸn#f׎f3OPj |mTs/K<ocHHHHHHHH&/m˔鎛>5]Ój# 誱^4OB&E`U:ܷr :1}-{|\;+v56FԀ&`0+4V%̧YvTƯ J_ e1ce׀Ɠo.Ѫ<KbϲH~gb(?0lDz@ԫϥo%ĽAǒ>ii125.x؅6]0UIHHHHHHHBZfX/ RK0Z l`)=v~&nlx9Tދ;.Iԯv?WެwɦJl_fxNז.xMH!-aZG]eXklpP}Qwb[-&O0v^r.-g~MQl jk6.%       1_XXkSLHKh14yQ`ޟeG#1up:YwJv|YϿJHs%Pmp 3({.c7 sFD4ikSfnPwyq Fx~>N'Q?rl:t       8N 3,99_׵zrLOغqkMq> B/1xpU.v"|*\5t*j?,0Lt/;_Jrg lC\TJqzr|fy.hH矏G-;\^-ӑyuM wx@Vqiaĉ= S6׮+XYW+vQ yX{cPP DGrмxII<姆&2?+|i)s ]{n^\gwF$<–>LB$Q0,Κ8HV:MTCTYƩNԉd!Sա "(b žX9^q-257DmRUs 26ɶz7;pu$=s!5;SmۑD*Q-`L 0&`L 0&8:(LF4G77e`?K]b]3QtM* ZŎV`*DX.npq ZHvPgz*l*hQV3&`L 0&@Y5!KXb%ߣ 5NvJ]ͣG^UeS9#`L 0&`L 0&:zY1&@c `Li >4j|61&` ed L 0& .6_u+Yel o_x\ ut|l3~k5VRJ@VWQNHO=})q`*3.zQEj;uZQ(\i]1v`L 0& GYC`L> !XB>zNҁ{}twkie-pƋ&!^|qĬ @ܺHr/Mlja2(Lc()VX3ۧK)ymб]pb6jլ">yZ.s1&`L <0X({`; .]h"׺| ?KO1I^&#n"3~DqM ugݷܮΜ˥4 nVT,z",&aGte2-;kڎޤ2*vm[ n:r. _-z^ g˼b"آ5E=J$d nl+<:+Ōҕ\ѾC; ֨N_~Ɯ mO4Wۻȥ`um'Y-^whZh|2&Va:m}յ'bYҥlƢ[(h٢%3\D]1P@Ygi.R8wBLT-zK85X߆=ڣ]Ĵ1&`L>(W}2maL 0zKe6QSG"n&%\Dҵx<3.dP.5)oaexe1s f^*:9\}YVt[̏m»MBakfх}xd8}.#zzz"~XWԗD/jj6+Kg$ ?ɜULeBC2)X0\^?}$i' clllS1oك_$ك/PYl;^ɾ WeE|R`<5f 3gѼ8^2jDn,h%^>Fà ]#[]&^ 4[قGJ bryl? -`L 0&@x5w 0&j[+"+Lޑ0Y6D25-lo! C̪W?iniG(L{T*iҷ L'G_ǹ }։d]tkg܆!ؒA^c >r\ZgwpN#e%}/3C(y#,LM%^֗ؽLTj쿪rO5@R&b؜ Y:O&VB$3}ۨˊT.i<-ՄU3U/Bu 54"r5=E2m.dh(}D%Wr? me+}&`L 4r,51&j@L8瀜ҷ|}"+ym?p9Wssy-iՃ`e8v'څcprU<M {W r/dk)7ݍegNKDk8''&ȕP 9u51Jx25{*V\?%$ʏ\2/!'s?)6l鲎\ ȏm I iX_}aa+j_*tBdD \V*U*ˊƺtN8O-R0)j" 3|έx4NRn|H}wpm|n[jYnĞ^HAjҶɣ+Q&`L <`X({i'VZ7)uC^\%b3ۿANb/Ɍ$b45hRUietЃ*eN'b0:̀CŲgUi^42_|:_(syEΦl251/qd'@g[ΘN(=¶d.졛 pAny4G1T/ep!䚗6~G6j"܇})֯Ԍj&۪,+SQ]󥄾vbΐ˖`YHP/ 9|O1<,:{ i @6&eD/t략cq]jAᕛL 0&h0 l F@pL Ɉ|}:4W *ɺuB5BУ'GLp2YF.155^<,47AgUH+SLE%)(@ "h婔 O3\oGL$Ml[Fr C\sU5@_|be~%3 K7h;[FJ$^}->mѩu'O-5`uXOnB7]ˬ٪(#_ҝ7L\&=J-ZVP-FuC`:M:t,UeFR4r\7/Fb~h ?6x`L 0A@`{c"Jj C ZGuHTY,'5g̦EG!nPعf4 WEa;8 \2.`L^8Ͷ7߬ [Oo$`l堸xZP)M&雕 ZP*S. 46X*ŗQE9>E槉LDܢWI>C8eyUTtC'KC|bچo!'&MmՎr=v}98=+m~zgP[lHI m}uPiY; },GK 8IkJ/9Eļ11ifY1&`LA$Р2p^=.!1mOgplN=إJrQ\i}_ >;BN? z &[3_[žSTVj@E|*JW빗mێW8'V:3FEHovY}вm' R{HƿnEQbL 0&@%H2W<_P,qQ؝g1/#dD~^ uWTX(QjQ)YǏȑ#8| ͺtĔǩ(wxߵe*yJS4߈+Y?rO_ gL  8iod2>ē%,w:vr~"n*…#Λ;k=3{|Kyae7&O 'Nv3z Χ8x:=Z:[=8MZ v">W>o݂77^~˷gE>hy[_ mⳏ!N yêHc,7T7/T@)C:W$ƪ,ec*SQ\=o(Xgr;NO HL$t>!ʸ,2b#wpЋ2p ɅHeܱH~N+c;:!((;ݩ;֧A6ȧ#@*#vSyʪfkpV-WO_h+gÚ8cg@zɰ8g)Z5`ky}%[>-{Ny}?'O>U;2 jiM/Ԅ藟_6hϿY KGDwĿu _ox㙗i,䕧-^sozoÈ],nZUΞd/K˞&9CmD0X(S7`",4l?y!EgHS"^&틽12q#@o9[ acGصPR.ؿrn|[վVrE|*JW}TTqĐwR E_z~0|tꉯ6hTU<O+:wHg^VrEbzZL 0&x` 4p1yGq0E>q *Af1+u˪XށU0JjMށNwHcwͷijKYL a$& ĤH<{O>~*U0i< [Ů+Q&@9 gO9mSdsn%',D.sZ_,M؏d:ǜbvϻ1o KO_9k\u02cɄJ bl \2KUI„*iyHlv@g#O_W޾w)m|. 7ٔ+FbYڬ*JNޭK1 l3z8@ ?Dʴ+ AJL Gׯ̚4iͽ+m?n4f3l,:+ " kDHƢ[(i"8:Y*j2(y#LˊQ#dv[[]#&\p4:eYV4XKk-6 pnْNa0&`L%H~v,Us S)HDE"R~gW;J^n uZa0&5 xfCaEL0t+b;?;B'DЯ\d[i2ӄO'&`L _D( g[h ōQx8>4]2v\ H?L22w V .$]Z{՝QXLM-(s_0 ĒhNkB03z""4 b&&@C#.0w$N&Yoe%4}7{#єc ɟ[ ,2%x 0&`L@%H2ZL8_\ag#,*]&2BgKEr[sTfBI$q8|*:<e֤e;wsnbB.ﷻ-vnbߣќ 4&_ZU}c&P!gklܼ'pRx'E*l30&`LQh4ꈍjԜ~6!sX-%%BB-Z)L9F*#!gʝ>8͙CkrRz^W+gw2,Hºgl3&`cktܺ[1&`LAxAYkXZގRwXӏ5˗XL\5&yH*R SVrf`Aߩm(vozT(Dmؼy3RJ ܼ0r \]8`L 0&`L 0&3F",dge!K}OU_ +Owti ?aӰH6=݄¼SȲ^rJ7 Ju:cTS&cB분8}%Nic|+ V Fq#iz+M4|ƍCH,S6S!'ߍc8`L 0&`L 0&`h$S/1.c#P/^x&+'aT~U}jL~qRzc-[Tށ0Z; IH/03 )h.Y_:Xm )x鴲0o&`L 0&`L <G^01!.К_bm^:<+dm9hSYr~{v/f*5gPn.f.gu9"twH*Zn_+Dp Vˎ#W#cGW<"ԕ_wG&Ǚ`L 0&`L 0&h]iyb28űU|uO/ ɈBJGT ca> RpqsC-t9 0"~zI&IkҖ1&`L 0&yUxxUvV QJ4#ceyo!б*6[s\ 0&`L 0&` @z٠HL 0&`L 0&` ezx8&`L 0&`L 0"BY]v`L 0&`L 0&5qL 0&`L 0&`uE"0&`L 0&`L k,a`L 0&`L 0& euEaL 0&`L 0&X(1&`L 0&`L C]50&@&PZZ;oָ;̽cL 0&`LhҤ ~a84u@Glbqa&(1H_J}@IDATaL 0&`L _& 7oDfТE :2`4:'aL& D2eCY2Rأ>7L 0&`L.q=b0$_~Qݫ%55ʌ>uo>H=+y$ GNNX3N&>`ܾ}FӦM/'U$3&`L 0&j*kq"fT'4,;u35qo <g}z' V| :OPX|lgL LG'aG^eK_)|yZdDaa.."_Yh፦f-`LA%&j׹L 0&`L 4չfiBY7Cɢ=쌒@}4^NLځ3K9"!]bHtcK)K$a#b3 0&P5BW`L 0&@u-"^TŜ-ݸ}JccSd">CAA nCO hjˡub/Pp`L 0&`L 0&hPV}SP3]M72W3$. yt&`L 0&`L 0F|ըt&y]2#!#F#yYg2hfeά&`L 0&`L 0FAQeF,4V&C71/حQeL 0&`L 0&x 4hDafU*pi:9ظ1EiעAw[o`L 0&`L 0&j@V\k`8Dm< E7>#TG*k"G2p 0&`L 0&`LA&Ѐ)ebaϕr1+^rsr"`L 0&`L 0&HA e}F`2j+¦!9hs Mxm\6~T¡LY`dY&T>`L 0&`L 0FFA e0a(eHU; h p`;p :X'SuR-)Ǿ<EFv>pw`L 0&`L 0&hB Orc~xܝФI8zb%ܔId@+Jx'HVG`L 0&`L 0&/6i5rm@ۣgobn3f'о% pvq`L 0&`L 0&@#!7 / fA)EЪ/|<*Ef#`0^`%&M$msJۺW@?[ms{L 0&`L 0_ky٬cY,UdL 0&`L 0&@"(^6 l*`L 0&`L 0&@=%BY=6 0&`L 0&`Ln PV5&`L 0&`L 0zJz:0l`L 0&`L 0&@`nyskL 0&`L 0&` et`,&`L 0&`L 0%BY֘`L 0&`L 0&)YL 0&`L 0&`uKͭ1&`L 0&`L S,Ӂa`L 0&`L 0& eu˻fhYL 0&`L 0&V(30#/`>AD899`,3f'#bDFhE#W„ ؙUR4F}]=-x݅$&`L 0&`L1hBx<0Ga<^_&Mb֪ȮU \x )V|z*Xq#֥ w˫"ɱظq.ܮLB,D:[tC&6kdVY4V _h `L 0&`L 2F):ZZZR})?NpʖSAi}KTD5AsX3 Xd(@K|ZWww>TUUn`L 0&`L 0& 4JL?(:GCt67ssΦBTj~,r\ݩֱV~>իJ5SʆDB\H}͹VNjY5劆}NhH8`L 0&`L 08 p:Sa/\R882Cۇ쬾 7MF΋Dž.z=ѱʱ6t˜\Q(D7'[3)ɿWot~򆏗]*0&`L 0& DO -$C=s˨7c66,¸%:2s j(!KD4j/~[>Pto"]. CҔO1]U೴Sljb :BE$)#G0=I}.d _O"?"#iHwTW\M)UTpz0Yjޜ#ڈmG3/a7P2aےI8H$=)0@eb_:Mx=8@:UU±߆с$˿$Zm:O#Q1R`e ICH4<^nfq{ %Tt<5LxĤ`*dB־Ȋ*r)4rx*kZ->rd \}mNiBLۋw ;LyGdPVޙ)O Fh9`L =V-pL 0&PfW#Dƻh߾=yj[\y' R///s99Wr$]\zIE>8BKwf%ţH%TJ66x=݁'KO75!i]4Qg]$y)7p.|uTY-7ڇ7R* D@[yZhX;xXu&v5xDԺ8-Dk#N r 0&@ ТEa[`J۵Zd,*[*^t M6mT^PFꆏ}%rwޕYɽViQ:s%Ȋ/Rbe,Q8z @h+((4NdT*& ?JlNڟcұzlj\"9G~T Ea@U$3׊5Ҫ^Ą;9ʴUu#Z45,XS.]Q |~eL 0&`L 4>bM2Gф=PĹquIWiLq ĦSX2- U2F~O\4OaOŢ|$FXd5=l϶@O Qx8>HŎ DgfmzN5p۪̥HQeߪRqbQB$`Zng7Ok#Hk\]#L 0&`L 0x(kzL,֭[KPS1Cx`2kgZlwnNiX†W"i]:#Uv5YV ɳAi&Z?miv~HZ^VRS\ag#}YF6) :-6HƯީO_"M{"G \i gr`L 0&`L <P&f`90stiʃTwi&OfGX 9ɟ*bnfSMǑFBTf@W^Ec=a^e._Wš١BjS-N#u;Rj&;[SU)9,,&K3=NU:ܢ̤cx+px0 _)ȺM`L 0&x T Gڟ mL}8W9XB3wOOxzlK/c^PW/Qά/?!Uh2 +Vc&B$)I(eyj6>dxXL\5&yHZ=N8O/InځDJԑP dKL 0&`L 0K߿6RYc;WPPJ)[W WR75ɋaY%p`4`2#utWκb?Y)lc Y& hCۑ_՟u ؙnHǩYB:ͫ"9 R4NEXŠiv$[0ĺA\#= o0V* 6"_☇}TmAPm[X.=ŒyF:*gaL 0&`L <~5]Cl(C$Pk}b_>Pf]c^T RV(7G ʆQ5?#02lG^6s9A#CZ9__lۅ-IdKJdtẄ́t XnUQIR cI(L¨ ɤje~qR5+ 9V[mIUKTSk(G1Yz!qi7dAEv2+{Uu8?`q zz=bL 0&j@1z"j'O'-S&PGM"UA޳l^I-Cx4/t. 锺\0f2ȶжIH*J޷^:M˧88ضC!Bm8&v£BF&HnfG1h{v/f<3q(7I3eunЪߥ9eҸW5yFg=Qf rdԉ.9@(AN?8:q4Vw,= ̈́⟱N 1{GG^:k؄{54Q1&prS$`θ,\9 &"WKdjMyȾp#"ZSg?52e i!eA5ȿK5 nkCj?OSG784&xzyߪYuUhIt Т5Ors.&p/֯_/4iͽ+m_AA~a4iҤ^mx{\춙6ا|lV`I1nn-pL(] -[ܨVB?oChANj^Oޖs #^âͬ :Т "w#;fpsK(}rHM9I>zfާ{#4SOT@ ܾ}م޽{WdiR<ʦG xLjPoژp6LWcxٮpmqiӦڱrׯ WWLŖ5`2s . ={Dnd G$ոH&*wtW _ok`LwEcܻ;sxdc;_HR;Ef?՜gsq\7`X\ͱbu:S+-]9&;7V( fC[3%6Aݬq 쯕^*O'[)e/Ҫ]k%Ju:m[{ј S\ Nt p`JV%ͼ4c VLN[Ok(h>G/$/9bqd\m݈~QR q2Diیx/t5Pb3N+ǜ>h.v˾پ$ HL 0&ИnfGjjkbNE9mux2L4V9%ŷQD?t6},.+fnm߼Es-Es u wAs}x \. ԮT#թ.;W^WrKG}W߾KNpkm3)qC<5ؑxh3!Tۜ[Qi\W> ײӇZw.Ξϓ;t[o*j,LdY N89wst߀V4t{9ٗhGѹvޘҴXq:EvU^Q:gkn( qFfX/L7q%: i :gZxxYTHSOt^?fq^^TA֭.Lt?TPq'>%'zYOR4Oٓޤ oO9<⪼jbc$yEQ>Ph[koxI}2B\=GɁ-i= _iъ犘">*evnҹ!>#o>#أڛb:X4:u=6x@hs_5{qḙa~W`^Z#uOg 96#eŸR2WGl]d"1 W73_JvnC$FHSI0ulD0>7_ N$(2=1yF2hrW:An 0&@M޽L6k2"Vh,nF0io)é/g!ln?5~C)W0iݳvŤ'ZBXn-׏'}?7:%:1,{^q)7v'ZY2cN ?3)n/Hrr1)D?ͯ/Oێrݹ/b([3Z,i*QP/=͐<'BFq,װ0Mk5ao7`K/F\6(@Ww! UrlV+ /CYPz1{Rl"Mk7yĚ1ǥ:^ǯ L݃ȁ\|dtsxHfCX;QjuIQQV-&? ^At [!\[_|]Yiֽ#^.^WVmɛB>(>;b*A)#f}-gW˥MTԚ7EiN5Og%S_De HMm>YfH&(wx?omd"w1B*;jm&bǻ$剦cqPЃlD21&*w`ZXl>o։dD{gG2ߥfi۬0kL"Ub>r)Jgdem)]eLdgÇ_x9HA+&,\Y4 1w%drVXO7o$Li!cPKrHrG2 igIÅCٙzZ?&Vx $GBѵH3/Lvڅ~O;5r5Ls\ٞ=˾Un PV5&1HQ\zIH2FgE؝,U7ob?wϒqtl5P"ZxۿC;cɏO C/t~:uq'+2[RHā-'\ q5t̫ ig]^Sh833q$Q32IbwQ|47G(mڵyGPה=G]"GK8S7Q}N&2C\EڷP@#h)U! ZL'{1<)$L\{HwE^ n$vJM4TO1h,:WwK36/C5/;$HC[Tx@_FAteĈ%'ϣ[_ ,VmmTT;sl.m N{I S{wQϥdXg*aݺz:Cԭldg?z tCI?#=ed(M۶3;O/\) 6LcҢ0ޕy#,t}u!$*My ߥfrlv)k^mz2zݗ`krv4ףx{.=h4x."t;b;%9t^n9bZcQ/ 4񪫖bzw⭟iDOSt 7Tx"LiJjѩtTB+tLxs"0}̳^uIZmO EVS>t#.f[C1?F5 '/Z30ʆ-^.Cgdw`L@"K5Cs<>p MA/^{uZ|XQR~ćg7YF?)=SU `vnH:!BY`F`L 4G`Ĝ˫W޷*>۵@T)kmܹ6FG6ԔUTʐU/[?r *퍉"sR '7iTuZ^Sd>i}AJSXڠIX_e?byJZWN3fFkA7qӵ+<cۄSRFbӏqxRkLw}ahڴMa.g]|e*BCtĞ-&R?#k W,M&#jޡ"L4x+]HlSBQO,El8ZҼ=#L.el((.c;fLK{_|RGcg+X×Q({$yTOz&qEqs(>w_< r\\Pxyjr)rмPVt?mr̚N#L 0&3ǟ ?Lܧ횛WR;uP1œ~)5;Qܾ+75=Zڍѣ6讫pDU_܃ {sT[ژY]Љ=v cmM&V+pf4@crJT5]צ{[r[!Si'weUVjzMMoW,w/FGuN8IBrIS4@rCwڿ,tկ&0oꪭ;?OU&k!k(Ƚw~1b.lE<9#,aJײG5v{NA,XStC[(&o U{M7uSjuF|k3|,iq8yqa~ r}M@oT9e]ÌdA|T<=OEx_?%œ>lɱ=X&!\:W|"/ 2 &Zb VyOd5),Fۡ1]Kv{`9M {FmcV_b).eOI$~eڽtfqd@7['넞j*׳X @+)وs6 &ztNx`K!)T^\ S;8PK3|~?{+ײ=k"GHеƐmdSӼęs} }oiyiqXp["oNm#zT4=tPzOFJ_oVb\29D橧*d ߱8苷x qJv1(qDz7KNkfX;#Y,cc5 2g!.d8w6mnD߈AvFxS<fc|0,nja9GvR)I܇ 0 15ڸoLt'{6a0ѣ|V?.wzUy@IDAT6rR&1ƺYbQF?goʹjpw@2p$ЎxpP#c#;y+_PuH6((7=)(cbӞwd3烦2׭t}Pn>:OMKOFn꣯d썿oLuTjC-E7d&$MkA{C{?绒Љ#F2Q^JM=1!8$J5{D+i+y s=LeWG$NV0%bޅM.kY8T\טGYy,X`AN+Kf^x@o4 R8BU1{ۃת-+LQأ6wnjjo@xw6Ν= r:apE!hIס#=E(ӼslEWPi^NVzd*rvx^9\շ+:>J¹׳gܵsצ>s甐=ZogtšN<7eW½GY^Szf&Bx/-bc'>Pg9߽4~m[gGo?p^ A;x\U z6+}52[P D?Y!Ȇx`ҥȸ+huӣ_?ȨHp nP! >imƲzG8S`ٹs'{  3} ~V ᡰn7 iF>.|70ff@xa,Kگ^v\EѱkՋ:`^&`@ajNj]K_` d {'t^E 4:w I ;u/tԺz+0tRFs޳[Oyōdu*kJ/?^Bؤru|^{xMީ6c0h [HҰ{>?N* H&(^ݞ+鶟dx7xPL_eI dL i&ޅ\nbL@# 8q4*\qE@#^imF2Wz֪|D 1% ROO@zP`AXf\Vǀ|Vg2Fnϡ4|$;..1ak}669kśAa;#~D94S,ڈd%BuIºv}5#Aa=$6q&",w&?i;ĺiAh7zT8$uTr*,D t:t~j/Ѳ#Sك\ݷtqa^$ζ]:؍Z$`mFhˢG*\0 Ź)&n1 3W[qپ:ۭr*9hG'Ƃ b+y(!uʚ?f\&c&ڸ0&: t"Zʸ0WĽ!qҪ e*Xh12IS8;ST7WN0,1ӦmB!R2k(kE la%S|\Iq!)q-eh6 q4r?i+)~P .qz:!cY G`RܨoIWBͥ[;CY HAOm)c'ݥzIrbސ/νNw?AuF%qF|xm 06L 0,vWH<04k){^Ud]{Kbĺryu:τ܍wh*wo>mT3na+{&^x5SG~2υqOO ݅[iB2܏ 0: N⧟~B'J"RJ[*P&p̯Z y/)FmځSX;["e{*4YZhU'OX%sᇊpi3H.g\*\ Fї{p'?W775"0Pa?eX&vJ<:K tuMQ[ab# G/AVDE5i:y*1.բpmҞyF:7D?0?#ҕͷ'2HǪKq&쪒^Sj]L|We,38d͵ & ]2_Ko~.YvnX:ގwG*:8yhߴk[M_|OH98% !no277n܈K`CLw}q!|k8ru^^7="T`bBu-FےѓҘ^BlZ )R%>+5G?{TTb5r=IܫD 6i_2WSQB(W'E r4ϡ"~!1w Afi(("-;֤ɪŦ"oDc>{P&4"ͥx=Qyz] ߬\>O7_K; xd#^jOLKsABJңwuK77Aͺu p֑*^^6י`L &@9:ѫ%{_uB#eD&h :PҦ{"䁓 6$/|Uo~<ڵkUSZh4zeCZӴZC F>}QeU=*l@>(HGaz((.eP!78ђMʂ2TUUI=_{_&w<El<1f$SMDj,D .OhF2u &O͵5Q6-FqQfh^pD5^VFcg`ۖp KW")qǘB.t1C&ȻRiSYÕFl| 0&`L 0&p 0"H"=pfQ__K֠ #SMī-%W9JCYdd$,z\)O4\.Ň?FȥCi-2UJlY:]Qu<zԌqn)'ϟIr7D'Fd:/>%ҏI} e\$쑸.gkLc`xoIXE;9kqOI>>k1/0unu?#w.2c诣:j? 1&h:ğ `L 0oPe™E~Wٛ&Je9F@D~nת exBB>Md"V(~bXwtv="%$3aXRV7Peρح]ΞZ[f HL5%&7\RLL.*FI =sI8ٓEOWMj(Eәa%& ͕eKug䪹(N$/_Y)0G.;[IF2qrDH}xvӱ(e`6LIZ=0&`L 0&`-OG^CErқ8X.L1VQF6łU{A5 'VK%vAJWJBY̴Lih{'ΨwŕfXI~ev\wf̵,B##fɀe&#le"yX2D L#=0'g7*-iQIYkQ_ܟPQ%1`wi%[QN^3+8\i,xPjF1]SL:S?r69;2h(qlY-fgzW"FыrɉeQN,>:`2ӕĄpEb}o\k}sy&`L 0&`LhG.oD=܃y9h9}1R s>,u 3aֲ- )rػ)&ڀު{Z>=Qbw|/F%es"ņi9Y} zVt}Ma"4ye*9T=3|z$uk ]G?:kb 3;Yת&YYYҨ'JN[GUUBM|L 0&`L 0sŋ!7GRY߿F2D_Xw&Xow0Fɨ¶%mU{Qqd|`C|~j/RapB:dBxy8w-8-?kvr OK=Gl:u|@[ȣn #SYc3Յz`L 0&`L \f-Q\kQzR Og&s%yJxP`a EiYPV|8E#"fI Dc[7ģyts%1c}00WNi-|Z0SmuNoه$?9t#tLzs.spK=L 0&`L 04֣V` FTϺvtV(\Ȝ4רǼ)Qy<@TV5 J1"^ -. dB_%ך 鎙5Z]L 0&`L 0&@Kh]I,ItKf zW ֕ 0&`L 0&pOEsW2 P_یdxZ昈e2&`L 0&`W8(/ _@Lɭ$\f `L 0&`L Il(k'Kyڼ^(י`L 0&`L 06GC/%1&`L 0&`L 4C0&`L 0&`L 9l(ks`L 0&`L 0&l(k 5`L 0&`L 0&]R^`L 0&`L 0&@c1x `L 0&`L 0&@#Т\TUU9 obzKaL 0&`L 0&@ȑ#Xjvڅ)Vk1X+Qo;#??wDYHZw>$󁟟l,tnArRoD0&`L 0&`@Ēdڱc}4  g ejpOba!2dEXa_y0 մwClK̂4L 0&`L 0&I e*3gO>^͢U׽9G2cݜ8ĚfP,QA,ą ǖ+x[<++=9Fu>j0ت\cL 0&`L 0& \6CU{믿FMMwk2[BHj"KڽQ{@uQ.QQt;Kp^ Fb 0&`L 0&`vZܹs'{ <QQQvJzj.G8Ky||McB ~0ڟY-f:eC]+KKqYtw튈Pa7݁ MVcob\pC1Eb:~%ډ@W‰_ȯΟt pՂJ x4C0ϧi 5 ,*gI$ f;NHh n81Q49! l/kett]ΤoUfjF鑣8}VHkU&`L 0&`L!p=E 1y,șƸ8 m}AL9^ BRV[ŊϞ ݗ*ݞ;}$;..1ak}669kśA5-ܕbg$ӏ7G W\ϟPYɤKXZg?҅+뒄u+y A!!9Xe ' ˑD2cЏdƒ̈?$gl'hMNR=bhL$ ljdI*eQ2|]N=6;  BHPm 0}`'cGL 0&`L 0&UIU+P\\,c /3cZqvƧ&(d2AU>!I딝N&@rkSf iYK7"bxdђ&5"r-;}pUUuܗ2U]b#AhR< 0u(^H{ڵ Ft2›@EV$ڄ`cM@ XUGO+ 0d)9zcY,3%7uq 0&`L 0&Z JC"S-˄że)PEځSX;["e{eXdetl-T`*)_;,Zj,PTR>yµPmT}{3ΔhQכ)T(BReqSz<:K tu*LKp9C"[1T-Jֶ{6ۈXuT%ٶD;5u;:/>٣Jy2LRlKPQ+7(DcGR;`L 0&`L 0&4P)~)B YE[Hx&5<^5PTD4vڼJ,4#ML^Y(gZOfv)AZb 71U.TU1Jݕ1E7Hc$I-þSs},U҆G_uL:u&`L 0&`Lj%Ъ eHHH@TTׯH@ Bú[)i)b)ȥn؏[ = =}՞Vl1#O3jJLDwn>*{g'WG~7OKdȞl;;N.ZCC^@+uP p&ނ)}?eq?ɣ[:۷`L 0&`L 0& D+ER,,Ep6nyWHR1 Tfɿ'ճ(HC`|f<6+ąyX-gTGEƸ]wmtVh`^s<If"cbOtp{q*ZF[Oဲ~j8 t8E:u,h庐 Ґ~'} }`L 0&`L 0&`#pٓ &{mL$FPHBQ}(h+T=| [0@o$H&{ʧXR=) S+K=-tZĘСO`"ʶ,B @ɺ>@zF λ[L^JұhC}e.ٖΩc] p Pؽ9YRW%ۙ`L 0&`L 0e3uG^Js%/ bEd V`RbXVX-؝3=ƫ#EǤ &L+F·q]?FqV_Ysh)XuC4fUMe2E0K2+X4a#-r!j(`99QiHkݷn>z/)ZuNSNf>`#?#qд F5FL^ыpLMΜaI:u*?)xx,`L 0&`L 0&Њ85j"{A\\\<Ȝ3މcQFTٳK/DzpÚW옩}6r`qYJ"b1Fj#]rII\~FEy _-9A3mI:ԩ|ix*;FJ^[i!ix3vO.9WyQ^S#S7-?\$:cS?n`L 0&`L 0&hQ2߿ӌdҥňGn*J0bFe5I1,tRȂ8}."NYf9dJ Dc4`FbExe T'E)b%0#]$67IѮ$$_oj*huL8Qz?u?о}{k׮`L 0&`n sŋඟ6aO0=Hccl3z^#kTcШhh@TV[Gh6@0W5q+I`L 0&`L 0+@0]9Mk ;:h*h*ϣ‹Vx7HOu`U 2&`L 0&pu`Cq[t]ElOoE5ɘ TTVPh})|:{pOn-v!3gΠta`L 0&hl(kW3q^\`M! <~>3*m#r("/A.]2IoG_,kL 0&`L`CY,&N@["<<\2ju"R3k2.\xG)SmRX ]z%{>\/J,<ᏸ7֜܃e~\?$݋u-ۙ@ D< 0&hQ״l<`L 0 TpKKx]{󃯯o^b!BvJ#G`ث[ 6;v].֭qؚU'yVlVM5̴0jtb֋ +kk`L l(kh8&r]s5K*]/ "H/d7Tޅu麭C>Ԏ]S6Rjl06Íچ5 _ġݺVLWm&]X,`L 0&F eMǣ`L#WNߝ*¨& fBr~nx gvj1gM^U+1&`@kjbL 0&мQK$4'YBR] ߺnvgJH;טO/@;7aWgN4biǭ=ux`(B(0_j8OFHg)W[uM%-} '9~rmE58]/T# ?_ZcMnX$SS^a`on uyD%uH2\CᖿrFY94ZDvt}}0*b)xf#Jrɷl:ϚS om~1 c;xKjoc$ kcp^akm5ѺDN} K녹+R0.6kcdgFɌOy~_@YI&(rJ]{@(U4y Q9memHG~7)O *O$Pg=~q^xet'wP>dL 0& 4%˪8&`6M1f٤5^v5lʑF;?@cݗG\O.d$J.Cӫqn[^}f$T&~9 |~RLvF^ziwdS&wٲW.B{i յJu͇I.dێLL|Mx1kغU#Yd/.M}S5+R!m(%s7E^t+3 0N kzm]"{+~"G `L 0&Z@rssQUԝZ0 >paL 0 e)Ӡhzc㒬/pL] _ [>q<|Uf6ϸW"xn|WLQ[Cm7B87I?kfs9v,='N^y㐧h= җַmn4a"epUm_`˓XٳMZb`$f.+MIkg}3ڑsJxOW`9+e#Ļ2Ly\ScmTTs bE@Ɯqv<] cL 0&@hQCّ#Gj*ڵ Ͷ(!jbr @b n^ Yx h ,*y>$󁟟l,V[ 0& P/1uBxlƗ?3AbhT<:tŠߧykfxQ[n iӡ;ZdB)>M5F_ 몆qCts dꍚ|ۃUJL+CȞr;'XXf~>c te5y0=[ldn)վ w˲QYYIFo] Ǝu[E 1j䛱'NYNCT)Q/ŞZH}Jȋ'+C?\MIoDhWpJoq4GMZ9SM_ѹ2;c꫌<ܺ*3>ZZ#'z:S'jl4Hz#cў6n8}tJơ}I{14T+*jL 0&9 9s| "##O8l4z_5}Zz\D׍ڇ[mNC5{r.ɳY`R.d/v#O1&zϨ[&5 ~Ns Tfth^wd:/<3g \: W׀1b]7Bj.@pݻ5tfązG7RjGF?֤.w(^m?pߕPP]lX-:ݫe v20eL˜`L 0&HP+ē{qqqIڳq:P\Q=ǥ/sF/]b7:9ɧ`WܶڒuXVۏ/)CA&vZ_Hðs.%=X<\ắw[mă:|,]QMK.FI缰u\Nj'wJ/h{ n9Ǝ?b]XUkL 0&.L]cܹ=fEb5 >z}B}Pء1hJgDs5}5!Ю奥8q,|ߵ+"CAcJEpWgˁֵ;CÃb1:i~V ~I^u*i1Шy¬2:|B2|ݝY}\f$V3JfDkJhEjJP%D>8?_?m} †9w0a/$!z?pЯx%aVNjA`+ m`OءD3KʁO3_9PMs8|tӸ[8ÄDWK#^`L 0Js)17l DRI AXɃ-66aA~Hzr z櫍w+>{6@:t_۫t{AHDĒw\\\,b".Ylu꯺t%cY3CZ[-",w&yWafgיB\z P e$ZMk[%0eqY4Yr!$(cO"bk06{]G2&Z3?6+j=11 4C^t<)rMsp^MJ*Cu!l۶ vw0ƘA8'ܵw-Jyf\Ƌeؠqu]Q تW?Wj}Eܡt̡] )'C> 6mބMj94Voɦ;7/7A\Z@(tq#3_P]x{v5uAހ;F2[4ug`L 0&*CeVSeCװw+6ΎlmdBrT>!I!|&m?Zam|zʬ׀t#"Gb`B xM:&Ņ HoR})ZI#(2<56i!PT)u˔^Agi@{5B5C̕8tҌ/L3ɔ#)PނnEn+Y|5$ǾلϨs;C4色?2}]ڮ9;K̲C0wXx1yQƭkrTlr!3KM|M$/V^f_re)e-u>s 5 l }3tMj{¡k Rq GɛжHr湚71&`L5hp̯}iދyLClc]Xlnm~CiP>mΛޘ>Ќd=jG>@IDAT:B0Nʩ{Cj ;֤—ŲLQ8z98p >_ε[+F2!7|%rW(z/  {F2{4|/f3~W;ը*G=-Ⱦrx#c=}$_sW[3K~bo$p#ڜ׌d+' Ή}Jz+OA/]\glt']>"QH8eN_"Y$,|y}BD}9A&@9{=1.Xk3ISgLd|EZ9`ujAȘ3Q V̅D}NPҪx_'' nc}x埠\fPZʜ -}:y(x'7O&`L \+gʿu^F>;af v*IZU$1"|EEqy?U#'ח}ҍ3aJqv1J%_  }lZ}jz蛂\N~#,bM-4Op(U QO=mL 0Ν;ĉ(++ChhEj L YUgpu]6;)Ʊz );>kYS:v)u?cC.uԞ(x4|ͱ&y1./t٩0usT&`L 2P&|^GH@9\Bú[iWǽHIsaD2aXf j v+a'ɞR@+Sb"wQA;>yǓwOc\~ y_7B@xu ¿sIOdj"ᖕLl+rL.z+Wk`L 0{P&,EˋB+a@\>p6nyWYy"%_JytjփK2gS'|)y(Oc،H BiO\ύԫ:HCuM}=qF5\@p@}kFŃht-:tٳgO?I  <ɿIߙɔWo ŧT)WM]#gL 0& \vCYTTf٥KR9n[Pc-G܂z#Zѻ.d:qPg)S,H;ԕ[FGLhzRfÀ)?g&g`ƣma%U*~m07%@f\R6UQO@wj~gL 40l|b&ZtVҫ5+ȀucL 0&N\e ѣWCdBg߰+ʏM,;@R9j1mCdra\5VK%vAnBY4Q1P [*}Q\irToǜr{}w(:P"9R*t 9+ʋ1>9'AS- X,pL^CK,ݍ{HEόtLO7&`L 0&`L >-n(a{/ ]wble?Y >7vk^c*G`_OW%bC1cMѥ }z4Ub|A+1VC5# O/Q /"HctsfcH=}50Sؖ)FCy76Θhk`L 0&`L 0&Z5,'L7 Y]|1bߑ7b}dk 1 sA)GBs] Qc꾖8B . UKm|jn! ΖS:j>>ulFɨ¶%ӝM_Gc1)s!Kb@¼QPMJi&GwS\\cL 0&`L 0&#Ў"_|{gfGOl--t1Q0}&2gdhPB;~e EW{&L7`'B*E*З^ 3 ":qc@S deeI"&N(:yJzoUUUh߾=yky>&`L 0&[uExҕñO?6=V@8fq>yv}q9T7u@No@Tw&`L 0&`L 43 l浰x&`L 0&`L 0&hl(k4:`L 0&`L 0&Ж-]M^ `L 0&`L 0&@ x `L 0&`L 0&@["t5y-L 0&`L 0&`&FL 0&`L 0&`m0&`L 0&`L 42&`L 0&`L %^ `L e޺2, 0&pr]r^.`L 0&bu-帣jV֫/ ' e+s='>`L 0&@Qī} ʄblY4IIXlim[˕̶~:;砸m/~gmࢺE SHH66ޠ8> "悏5՚Vbs[!G-!)&qD5z5 F1`U̍0g9 of}^{>25kC= ?|h(IHHHH P&ݳZKCH6rW$å'w ۇRՕ*le*N ꊷU)V7`_5{.$0!$2B$@$@$@$@$@Wvݯui(4P0 DudSS_YQX"""͗H'V(m<ܗr$@`y`2 Sw     & yiF2)7tҟr?2?T8"6}I-^,$@>BBB`Ѭ? 3{gIHHHHH3-R{<$#YK{C'vk N㢸 A8Ą9u<)?8Χ~vgm1{w`GKc#N!!쭨TDXm[Q{7pLԜnjX1WT\s-6wgO&mgϢU짴ᡐi>V඿Q;kqҦ}ymVXť.dĸxI4(iwhڷ5RGG"?!B$@$@$@$@$@CA@r d=Ium(GX[fd V6e J>j c+ErXTcOC kW=eՎJ- %_ÒɊt}Ȝ*c#L(9PhFAH]21Udm: mJՊ/.wo{& C{ ԼL-Zr"B4hTbD.w_m@kQ39/"=@VLf+)MY(p0^X2Y1iARݛRe     u>ٱcMl6 R amG*QxЬSmPM٫gF2{00ґ:uOlٷ܌dҴȚf"w8׊NF4si]Etq,-1l18)B__V8r2G[5N%@ǜz#) eXh@A#NfiF4õdbCe63IHHHHHHPf= es^۷XYTQFe|ZL-)jgR]P|ד~կaƮm܎pI}lFlZ=<PN[h\m|KUg(kjFJt7Umݨl܌,ՉΔ]iL2ƱE(q^. *C{+>-ƤFnLvf\|36.U&1RFW}^:8 jtvWyõۃdtG$@$@$@$@$@$@$@=q ewbljZ6U3u/G!?R=ˬr/ }!巏ڱW'pMyGV]Ü%*%?S-2FꪰAwLU0i4T0̩UmxEu){Dh,(_C:U*;N#0<*ZXØ%S?=M4@C{,SEü\%W{5dLGL s7:彏)ze6 K21m!Ҙ \E7LӏMHBRR,Drfp5GST7APUչo8/K5T^zX!; pҌzȑ?MG>T3g7 4bo1՛lMj>5ca[4X>q)0fźoLX+{Suc+\}}-鿏Şo.|jnt+\ˣ &6ab+alVHHHHHHH`ͭul. 3i cUH./k Ge&k4;/<`=3d=ca F+4g'(rRA5Ҵ& )Z۽~5<М[0>!WO=9YGz罄ykoȾ!_[ U p "ıU}RW*LlEG,܁^Pn*}(^]h\7UcoMqVcڞ />3u>ei\D!M%HҍnJ3Z]=߂Gix})Ijg[_w`lTu ؗ6؄PGt߇H響U۳ch {,KCci$@$@$@$@$@$@$@W5VW1c0fL~09<cH&Wdʆ>%SXa<azʹ/~u :ɤqwiblzNUv2LVz/*rMyDK1f-݌#R2c#88On7.VH߽՞fsy^:(ΪERn=ZHHHHHHHZ!pʂ%#MG?GMA;_5cy.P-XRByenkgH3o(=~'|)d3y΢I?o.óuQב>mxQ2-?VYTD㚰zaㅪ$~W4WAϕ\AH[ESԩ+^c'UקU^cuC^!-EnhކbL%jfTַfs":#OxDe::muV, ?#E~jy DJX5Uy:y7R͕R8ܶ50~G&j:91Ƹ;^u cӓU9¸VW.-ҏ{>'\7r5ppqߋ阱\ 졬}|5E3-|j?c׷{۸m%4cum THsQ`9OPciG ,UXtGEq61˥7p&PZZ*7,YD~?{$@$@$@$@$@$@WF(0YGX2=HCL3@w.ǰ @:;;q?      + 0b! 07|NYCn(~曲L2=Z;{geG [ps05^kŶL>wӽ [HH|" .]eeC)HxJT,$@$@$@$@$@$0 9f?#GĨQ SLSɓ8u9300P;wajFRlu.H!ߣDDDXv e?ߏHU ?c-b<㏿xƹюF>w@Hd$bcdd.Zj6=HHHHHHHH9$1)ٽ{F2,lsWlJm&rыӝdסȃLٱpz- AAZ#G?7$Y_F2 d,^R˗\D-tutKtuuC D`'d]zQ5v9Ϳz?Z|/m& ͍ZHHH/C_ ٿ?~ɓ}y[])w.򃰺H<׈2W.ӡd#ӆ_s[jEiVg)݌\f!҉(++FE!Zkk+Z…6kn)^_UAAA_g4V#pJ.!gZOIJ#38%an$g+2 ov;]CڭVX;Gعgv=}ݜ^W{~.o릣VqJ6q\ ܠPqrżKtv}MCXN6BH ̚0X~Q=6f$ΜR nH#Ædj[/o`up.fhooדK1)7M7$4޵XI_J/d_j?su^׾ىew{ԑwą?fSx!Purϫ=^ *ӎ?yfqr]_ol6HHHAWP~_?a+< ڳ8,&T_l:K"nk[cN/΋7|t՟l4saօ g|"#H|a"м?{Rl%E¹F(pCn5EuY+Z;RDjNt:Mg8_yM!?- /r[=ڰ7w[qI-44T0[!2v 6N 6EG "Vȴ BLm]Czqh܅q[x+fD^ Ref?f}8)洊+9~I\zYȿъFyXE"f$^=M%^R FJ]ukX>?a/y929b"9(&_$@$@$@=_}vP&̤y]$?^ Ye'`rOێ`qD*s9qS]1 Ki ڎn"̟g(&ly#S!M_x;]e?<pM)}p P <͆F: o1fxc~>u?r_ly 9ۆpv7 ((z& G 7q=!Z mͅQ"|c?ڌg>z ?Mp3>łkBǻAyKZZ3>%ɪ+ .vuxۜ'K7nԐl^NZ'6|8~}ex10Jr&ᥝ?W >jT sF=~I!.Nq:¹K So!֐r%6mRk&etb}~j֪C#%hsC   뒀'Cz9S28opUR<)=76^8,- irb5Pd#|;kKŒf=D6]j|!UR%{0I-5?|ԤPn{ᰵU*l̾C1,"_[+D8iz_KBDVE˲LK竰(u GujA31Z+r0B75&s_v omEbgڜ:P;Ҍdi0+ܯ +* 8n bD4*G$0|5fϲGO=LjN+gg5,9Bs?pAqS<S|&uZa0MbQl\0Pea.͹&z|7\l0O. 3v!ٞM,~Oq?_*>H&_%~ڒES`$\A,jBwe%*uBCA x:²F5T[5k7Ył5,1JƮu"Om/b5?Oh*_E8&E؂]w2${(_gs bZ*ڻJt7U-ݨtriBɁtsYp1n9=!9y3r68&cQP]0-eDiLf.wFŋ~#1فjtvWb{1>J}m0=k;]fUJNQ$p;+G'&[jT/yd|.6{OuVSx;fӑۨ:VyPjwQ`<[<ʜ.t!T9l HNE/~[27vVgXgbwQlھo~pʹC~EֿR̵,UNd>,(R;5ئn3+Ϭ\]E[~Daf-iJuIO%]D7`zaʒ\so\ΉzשX^|Tnl.vծ[/cA~À('[ߐbg 95 bHHH&pӵ:W)I,,VbLnw sܿ#[C.btA 3Fe~<84}m-R$UQ[Lu˝6(.!["&Rvս\1*NaNR:?Rj,߆FY-iNM!VE+N._͆w^ܠgSbdCh APZ T^%=X25V?!q X&߮sT`8醪슟`~5?V 6[c+sOW=,xJ5<}~.%%vYEu@ RdJ$KKyʔgR*LCM'KCɪ`0L1 Jo~c5JKJbJ#=a7*yOǩC(9|<"iȉ3WQ vVyaS+F6g=T5ڥ`/{g06\3%hT/.ub âZWJ2<`^7?I-X Oz@y{a! ٛYbz]a{EIمxf]"瘟COցûKSa nGե}/9>?]wEJ GJPnCU%νSxJy"b&PLFy}W%VbFFzn?NhٍX'   =l+%Z1eY-I[TY (XЇ0O7VoLyȜcgK6$ך7>AD|L{;>ܧg[s΢u,$?$鿏/tn>iqc+(tXXDL.ي;#_Uހc*5(r ˇ8n[͐&u:}o@IDAT>QxL |dE|2wM.b2K=MX&.G8@>pNnѣ ;]}01kHohgHw)#՝^.eL>:Q ]<?Ob'=wQ pt4nEr A.eH~M6w}\O4V2d)?rbݳX;tyOqHI.BߡC?yHo R1Z !h?B |H/LȘt}-mSD]x_|{Qz3k> p| {o?|[{uB?WE%tL3Rf~?/OݣO d>R2}ޖjK0freԿj%10 )~AAAIMc}o eCXl պ/,Dt.Tՠ F+ X\(K-iԧ`vrE%hƎs1P#ƍQkg':Y+{cLfyY>-7+h덂H,xU4v"9E/j>iC{}j&8(8P7y82J x_B0Ink2pzj(A/"Ͻ/tCįoʑ9ɞ/LB٘`t4{j\';ص_½F!I\pwuŀ6(>z0y CU4dp񁻀?BtWT}S}8r⣽en5g?~PےgV=n5{\lZ돺_3}v|0!_Rdwܙ38g1ㅚ #sʹO'ݻ;F$@$@$@^jѣGcK_: .ö#<&֖:< {0~Uf/xmX9s 4,#eӧu5G]]x(q%ƤbxI qظVnErgaҥXz}VIjK1eH![w%ywzPm*@gqUƃX7;ӧ:'/LƳjfkAeQRTs %j#ݨ-؈f fmG`֢,B&O\RX@m[#$aH@/…t)X~ogx?bqKx<r׫OxdQobҍ[k}p]h݋f}6m¦ewb?œ?*e*1! 6Ur?#ķUC@9[q8>^ظGy>w]s4V9;<.4c/o5Vt c1oعm^לhO,8#.GoaSZoF$"jU/qaWB1BTi?W+J=|395wbCb4 LEy7R {zdsib%kW W*R!'"W2X6`xi%mE><=r␢=c{M_]ɪS< Jwd͕=VMX6Ka8)| Cci"Lv5O&*Saov̒6j9JgZ O 瘺4z9a\c\\lzϕI 2phhE,[> eˁè|z$0tn&F{~euhww,Sݿ)DXU(/{GK.8q*83Ɀ$Q$ihs=paK's2'=L!m *=WBa^?e~v@'7L҅Nغm5-cx`zDf%rKKv˭=bɒ8E;azA}zK7Z}m[rTOx)^zW>yըDJ箈 \ {ЯIO,կ, @K ߂ԛ0盯p<*P{U%rHnA X[نDff>B6=)an02a VdJbqѴyy!)'c0{;=Lw9f@ß0?֡CDfe˾5]+?f}Ֆ|ٓ80 RcCO(G“Brt0p;cX_@N8̰o9ɡapE꫏Lfq@ۦ벷-韀]Nsk̬xbZS~]鄚IT91ܣetԦ_r1Naw7'٪ahֺ\&GY%7IH.F`ȞiFyO1M伹OP9UXZI^o/^kK08xXy+#ټ]OYNo?BvO+ ?{/=.]}yx~oE3qQ0ˑDʏo))|DX' JU__Mx_5Dq<:Gf{ Z 8;qw^+/ ҈\}4!#]vYA   .߮w_+E)O0\#4(}.;ZONLBk7A,&'/<|OO$\wV5^wv[abŞHJG; Mj$WmA[e]g PDkZàmh7"*Xp1e7eA?:2JKK/YD~?{>?'n(G1(S 0'N\'d$ǏGgG' Ox!TsCHhx A*5]܄60|mι.X;Iك-"AI?a6 @$st `c @b~$&+I3$ckF2i1 _{{WP2y3 |+KqCQƅC0t 1>o!]/}͈/|5IL;)j؆c^UL|@I&S;},]>kj]Mxy%X"5]9 H&ɺfgu/PJ:ZȄd :6$@$@$@$0Tx/|%T~VQeK1N+D!YZ0(S68: $+ #(""#?W&ɋL lmmdL_e2^'nʞ="W֞MX(^祋<HCVIHHH?(=I\ \;J[@! MÆ@j;._lb\,FkFS*B$@$@$@$`})E!)EHHH`` mFLJ#   nZQ)        b4 1pNG$@$@$@$@$@$@$@$0< P6I܇M mu>VK˔Si(e| 5-HHHHHHH'pMKY?{Mul߯@IQ >]mqZ5pįI y蓻>V_@|`K1f!S       ub(DWʣQt"S((ۃ{na•*TcmiDΡ!hJBڌ9 $q&r-L"Fx󰡹8N_0*l<b5m]iv1;1QΆ%1,2MZEW=,v £De1H]*םjX>j]vXv= UHV*\ 柪FaDy@jvI[x.];I1~jQx`'YسKcDκ:rsxVmMi42JKu^~|'      uQ&. n?^4[ja/Ca.@ؘ8RS(>fbSϥ”qXn08kub0Ok,3Mb1ɄĸXu=>Zw#e4I71fܹ;j׼+Rʝ`) ӌ=Vz!5|CW=v7A^V sX0nPWaX/ TD ;\B?Ecau q G>6PZ%{&}VdSoˡzI(j`lzC#loX#      0~ eUGV-M6ƭ,&KV-j~ђfNYr"bA,@ b3*[",ٌ2Ր *HAͩĹ(ƘҐVl@ib e`H;R҉ a+ cibg+J;3I)7:fŹ0Q!B4u31+*[_@_㐥]&3ͺbF       n eʄ]Ixh<ݔ"Ygw':;_d\ӊWލno«kTe)v{0N7E)U{^c&檮cm  UX7W@Yk_=hE=VxXҺZ<0SugZ"h~`N1źRP$.TǛqD۱tHQ-U,܅yyڊGz޲gۥ=YЕ̫E%Wj6xY_b>6S(*.l Z :)HHHHHHH7׍L3,ފ}EObevˌ{03I%lxE4dǞMc ck(Ԍ[D=$D$ mǬٵ 9LNG.'8HbS܇}n(B͚l*uv] ם8p6nIev^yzT`)XPIᕪFդ忏"Z+>֦9SQX]/,/wvk6adb 8ka /4/ca_ [ AeEuZ"stLqMoo1{'QhI_U°cmKtJ鿏-"b=Ǔ' }"7Z1f rh9kZx*e1Cr<$WCG.bo!mn5YXN:pN4;RGNҺ:ޯTwS&+(|߯~HyeX5kE8]=.V<8"II׉k$@$@$@$@$@$@$@?lU[ 1ikp,S5g.) ~ $;.!+A9vPm1]:IMo> ϳ{#?}L0'`T4TW:uqoիFu(XĂ^{ܩ9 L1^SQ I`aB=6ͼ~:Kf&9bHHHHHHH_C ;"ZZ %$m~ {"0A@ӐK[XD.~`R&۷n&fJƲs8`EJO v]^/5z uI}ע!S~E^)6}1޲]۷J񗬲@zm/|۟O_2+$@$@$@$@$@$@$@x: .XM(!4/4AXkRyƊʞJ䭚փxnzx y:Oh8yril"3\eg}Om9wPe%0W>xϺzL0Hx9 ^%!Ô>;OK(ıiBe˾I={PM$@$@$@$@$@$@$@.dVee=lep"ԻFyDby{zk]xzaO,wduL6m9FptӂHl/76Oź-j\٬Ϻ*tyy3ITf^ sczY; GtP .{X&HHHHHHH pr1qP`c+v;ZbDh)Sz2Y!Y27qG nErgaҥXz}(2ae> /EJiՍt2STz3*[ {RWIگ;0ןu-؈f fmG`֢,U}[gCCV}|_aѢEXd5kH(`mA*"|FM_ `?)CK˗h-OkZ-Z]o4$W1I^e؛]U0-n6;t \ m`Ah? ]a kd.mK-1]v]4h-xXPBʄ 1-| 39|ys/8|Cz R\5ؖhj)o)/`Hͻ(1͕殘Nb0/:Qٺ3mPRv@ĶӨ`8Bb+@SJ3!q2!`N-<@ 5.HQ` G0eJr6;S&`L 0&F>a;O%7׷BWW?N?1cફX7aܸqy4~TU+'Xb( ts06: 5V}!G CߦSn0rb_`l&W]*Թ%s.}CA~8W1ze4t4P.CҬ/_.4JW_}b CY콱\`L +`8 efniG`@  ֹEo<=Ug3aoۥ [{jASx\1\%ass4ԻaH̫K86騵t5% ڻБ` . <>`L 0+su{Hx}e#ٰU_~cǎ /C6]v(aV4)ii)'&`L 0&`?c.[= cWg׉e#=xA щB.P"wgL 0&`L 0&0 Gٵ^;e /)ge4e.9(3&`L 0&]ѣ] ?4gm/6#G%CUWlžs<`L 0&`L 0&/Pi턻;Q+xFij2?ZC 1& ``4?q?X &`L @>{z9Q\iB4r- ~>@`ܜ 0&@G.-xfc%xdA7;?˅5/t.uGYp?n?<:`L 0&0" UL-rO:֯{|֔_SF4XQH=FMc`;ާX^}> w]v>t({9Yivg-!vC3| 5uֶF3=qj'Q&!)r:[gks+M0uU:ZqGओv@G=/ZmU{X^^B h2<)\f7rp5ADuS <]C%5x> ckW#]Q֏ 0&`@O}VT?(R]Og7-w|K&^%+H+J4?er~ُn%Y׬(sT0lgs |ޖlڇ{ æHQS/'VN~=GU%/7ր//(7Bup/T\2!]Pa2O_A:x~H%=' dk0麉8#dHU 6ן?*+Лs\7mp\چ|駨=i2:pNH i5=grO>%YOW[WhRٳ8'aNYΠ:R7$1_I,lүVzK!Xm!ކ%KL 0&]^S~H) GvDMNOf9"G}M)C@=Eځ v:7a$l>w kRmFcɒJ ZdZ?fƺ0;3GŜ6Yj %#r=LMP7D֬e4ê5kԄ}hC?XaniAy&-({@nU}x (\{^ʗ}<) ,f}pC=nݙK_ۖ`NZ8ch:j_f[ۄ)SqǂX<7S[v?VhX5g&'V52mu3(yI}fF #6#[Ma괻S# g9fe?§o!(Ē~Buk6 3f݆ 7&a;~XY2Osƿ;*\}Td&%6.dL 0&./?AZxA:Dy* ='#%#bFB p&M_#d`Yx@1\߂8Rg ,WpVxGdLmʘɛđ=FV֯i2< 5ws+-=]-G3I<9@ގϔ<6uvѝX -YUE2$lٹ9wYCKNT퍻&K0daNŜmߊwA([~FԻN 2&0DBYTV~Tqʚ*gi<_}v:|wܧ0u 괫iϠ=R(V_f)kvG3l|T@j;ny9'狵rÌbAKQk3 7\ -g`k-zU^2 0e܅ii|C_S3L 0&Hx= z!:?GS?">??e.|l-B >9INgxo['Q~F67D.Q W/W^`V TQTծOTVHY7ћp˴vp ~Hq=lRi}KÔ{~ןٿhᥲm 6& F476t>U6 Jlh[,1%C_@ bzЍJ [.t@ȥY{TK=`EWbL&>spJ^ Kw;>:| ǎCRa:O=t\}䉓tCɯW+ _Q(T֓TTʤi'>(Y7#S[י b ['Q_ˑcEgoNNaK}G8Fz;JroS؂F83&9$EsBvV5'0 1&`M8e؟Y7=;IG4"X)<^ *Y#ck'Vga"˭ VG6y#**;E*fߑrG ~_qApj O77/m4pB=Q||%i@-> f쌼p]oU_ 2V-Z- 8|4}WI7-w4[XQ2cI4#B uN\g' 1YP{" zL4 A~N8 -F@91t[Hn:f6B1[u&o1uONt#Dz:x{$7jN4qO(as/'𴬔<q*ܾc[ tD&NEΖՈZ+/aaK{tK8%,ic&rԝp/m=H8K2=Cv6>6g%J?mտ\1祉lwnᲟ։3L 0&HòIr#Ś=7RVN8|j(PO `GRWK5^V!6G^y+e:[?B E^8}<MNwڽHG`(:Oaϡ[Ktȴ*pǦj[;ʵqIc2첗)zr҇|uHpY%EKrwUBAsascuaK|L#yB7/?PHT]bx~ZG.AF'=ҏ*MC/= /Pd*,3>b5/g-\~6EfWt蕇icD&?XyF&lTEJo0tedge;&pyffVt(x~zчU1͝cXzH xg'ڠJWg?px\ؚmF2/b}d7 tGd&Ε+l[~I.cKhX~=?@Gk$0&`Lŗ}xL!-AUK42c%Na)##'_4h%,2%|lK3?m@O:̟P/)EUgRI5%UߊGc>R7aɣxG]KDo>*@ @>HHk|v*pV5pn?|i)7RMfko}%VIFBh4aC)MWcѾ-^j*O [C4i2ѡFCTb4vZ0A/NRj'K$$SRIf$G~wZL'w+H# ;!לBN\NFu/RvF&2e.Of4NyCwkr:}yFd>Dƅ-s:NgD4-\7{+-[g5x,.j}*[ rZNߙn$o"b՛SEJRl6Z~YBNm"ls2&`L`Fq?1_?<BMGSl^\j3'UZm}rar)ہO*?) s=Bgϑ#:ɝ qf:܂Oъ/j>)C]߃Kn6&TԹ }.ģSZtN TZ7 `b2W"C1N7VMˀv6bg"Ȅ5/ )V҃]I39xCAiJkɢ^Y*dndڈ:GSމNZ6[jv]]z637Fbf$#*IRyVd$wU5PUU|:?]ܚ>FlC:ͫnFW)lPnLnIJj/myQQtV]\>XJ=`L 0&.2 Q~@(j@IDATEFbr>p ٻD_(e n |%WЮ)?Yf+.cCgJK3lMǏ%ҝ38hk8?O}gVܼp{H큳rx%򧥞rGQiN=~bZEC6jh@c:TRgQkE6jұqX)-cW:ZL sԼ6 ʲ%fϵl.eL 0&I|H]-K 9TW7~S*J7͘Btdڱołxq8=Ĺ`uaH|q܂8)pCo?!=:RKkۚBHV讟-hx&O'gTYޙMmm<Rze|6F|gEWQɸ\bIb7jxMEevl8RߤںZtgੳTlm ҋ ͭhoo - R\:ڌdJ!fWRzٯG8YLDad{͖—P:/WӍwP Y}NU'73d!Q[itHFdJKxmR<9?Сo[0UƸYJ>}39[<ҊJs4CSO Sw@1KGDHi\뒍\焩Ѥi Ǣv2Ldř34k1q탞s;.aL 0&P?/ٚ07Ŕ(Vj9[kRlM/*Pfݔ[,"s)&YbpZrmv0G(h4[I k95qdܻ"IV-yq K-GP2mبifni:t4deyqB(Rىd(S[ted%-46BGv3 Q\h~' E8VWй5Q暽X3?08$Sl) 74ody,s:zx=j]ogWlfG[%?v/lՀuewi{x~+ޯ; L{1G6sZ8W 6=rd W ,yOTyFB[7`*McŒDl_rHslAUr؏ |QiUw;߳&'f(Xzũ%L[`kSԆٷ<`L 0&ڃ#Y{Y8BGI'ڑh$dQ2|>u5{{|4뗋&ok7mR"xxwsX.܂l܃O+eHn0ͅ)g-Ȣ]|ʃĄW:W.IRy[A6 (RuAT<&@qBg\Nr\HYbKz o m[>@F:&n/LVnX,;t._[eQ}s*M%vh7|m.a3h&d`[loHT}Ɇl~:72x>1^.dGh^ϊxfFzi۳~j/EdR&SMR̫Ԥ0c$-;=a|i]uBւb;p¥Էk^WCUsj g*"m--NFh)4Ado}o~JG)N//jL(\6a$%x ToBٰyQr1obHIG7"-y(H^gpN%xR]gm&=kb-oAB>z۽@_\,ĩ>˕zGGOH*\y^Y2F {r)B8ybߴ/u[S0NW:ߩHmVƺ_3%(b m_[7g}҈p LLGǷ*U!l~2Om[>L`35[t+uh͖.1O2`L 0X7={/_3"`(>E3vaT{Ԙ2:['SE/P,Ty +j*smYaKk%O0kBIt6+VZ˘sh&<(ɨaZY xR4י!!-sbmqɤ/k$j:=` S,?AӳnP ͭ1-2I6I;k=);.oh܂ 0&艀0z=5r& ψxVPvnC;2 %YUɴ@/3^H.;8͵7Y $o)چƒ{ *![ɿyW[b.2bSJN;sZmhQ<{yޗxʬE2=$="g*maM홨$H_Ԧ-`?Y;CS6b"1o1r ytaPR=ҩSs Y/L. hťM;xLVa^?<<F;1N,Q>LQ3 a'P]QR~9%# 0& X9?(| 3xE2&`&0~x;w2pA@<hHڣLW YлM7Od)5;uJ 3B,e`Ćh+|F4Vt N [1P}Rov7WcCu(:)E:\$m=Fz eV78{q.q^=xOFαWNrAFi+w!)1bD]Ҝ^UF߉Xxu!ݚjl窩Ðz5)ժ2: ;O8eA(SMZ7%C =kզ "yj|n7SYkC=dESy j >3&,h9YaX7xy 3L 0&,rиf58y$NԞwτx63"ѐtQ V`6r8AooOAh[ZX2*~V3AR};bYK}4'h@[fJ^pMq\&: ,U6.cwj&@<-lP'1fޗ"iZJNsL 3pʹ_/%*,b%]{ˋDx^a@ҥ< d2Xe ~JY'(XK -sRyXZpq7aBChbl_t#m / 4vTcspez>O~& Ot4'pz~Q?{0/{>s4/'ư[B~pw (o=esK##drD`EE]6BBOĂc8}(uB'FGވ/OʗdtmebUheCM)=C@ e;yNw?UZ" '=HꈰN|q 0&`L 0&\&e4a!rJx0%K.~'`Q*,eu>>FTev}0|s+Z|)u(ޔ @"A)>jT4dCY u,Wf.ܥ@§px{]6^+{_H1.B!cžYufb<_~>ӱα xJ1]P1T1A"4_5wkQxJ,r4i˦{ 0 101^@3p襇Lu,3>bU/kbVxhnU !?y:|(.t0&9U^qijZ@`D\Eϩ!<^nmv}9`L 0&`L %pzv^E~TUj}RfDB=hXdi5/)1|؃C5}z®A v:ޮkH.XVF9vj ƺƲCUrIDG#ZZ [Us#BsRU$ܬx;'U0s̙3~v[ Es-Rm7AW2)1:t3C骯zU?ú`R B&UJOvT">++%%IIF9O?"z ~Z 0&`L 0&2 \&2O9Nr!S;sJZ{(Buc;ڍ0+5x{ҽd=a_~#L J?ѼܚJ_ԌMy%R.Y-%iT9IPrJ$_~?CȠ^7D4CQP S|4<1ai< `L 0&`L 0C21/1S谩1@U0͵MA.7LF`i[Dg9Ř!yL2Yٳh+ k{,/Ύm\B釰 m!&C:đM_C@p8wWe[ڔQMH:6FZo_7MF](R,e\cw޻؝2DZ_1A3f˞"f"'&`L 0&p#5 %STC_ J5 [V"?O)Kde 8(v2DL$k1L;rJ[,TPS龌ڈrҚN^FPOd*'-ɘ}_GZ0!z0ז⏀ 7 1%fr}Ad =x+S)݇gssٯ!/}1A^w&۱s$ό즓[ғ<#[,-8~mOZ,yRP4a@ \uez3L 0&`L }OFp| JMz Ȩ;59Avf)l~'#C] HCZQUU>1Hۓdr/In8P}q6©W_^ԂϞ,W@, gElB᚞94._}5krI+Xkd/B*\8*ە&xq3%sM(LVEX`S_=S)I®ZG-UĿn@qq1Thuo)Mً<蕀0_v!W2&`L 0&."a$W_=Q/Cg%:$vUjTH-s6'F-|mm *J:F5(#Jy+UG6C ATy +j*˔M{dEV3vCQ vFFTw *\#<ފ*Tycm7Ibrʜ;/a,3jJ qoh€e6]<)xa-kNi0ϓzV+N#ּ&X,FD]PV?P$PP-܋Cص)>\JoU$$$  yt9JZj;2~;v/72n`L 0&E wP9&졧5>C#K3y^8V:7deʲFɪpy vF7c4%ޑI(R@50zIn^HV:حc 3*a /wLو@ļҼ6 M|i[JX0^|^B&KR8- 7R ҏ17`2VaTUz&6}t!8͛ +bi9fذA}m#ݿܯ;}z RJ7=`t:Cx`L 0&`LRPWϨ6E]Ԍ ;uܮ^bvpvy`T[sȮ pST;>M{I|͝=ȗh玅org#6,GkN6M>%Dc}9}ixxQn$!(mE<$%&"11DiN fyنO.ha+wEpOs-[J>Y޳3]3QlRUsӫO3$K y*G^z1L$F$OMWÐzjKvB:0 !u &/üܗ 0&`L 0 ! T#M& &!AWdI)#2wOox jScBx_;Ou"^pҜՂT;=zibu+]~󲢩8Β0xwj"(yHǸv*8Nš̤CP@2,RSJ"׌;Nz+pzLDX6-BmZh.MS \ Ox{r݁ٺPRlҹLtT?#by}F̼TL 0&`L ~;zO2a$G?@ 3m@={mlL [/f86#޲yų?zO"A)q3$#@`i@qzd$n@M8ޟy{2^m77 ^nX2&`L 0&`9 \0U_cKGXz~l "z[[5ʥk ^OFI3 K\yԼ&dJ-r#T'.ZXӐՅ^z "`L 0&`L 0&0$FuE,|㮻BHHH?&v>k/\?wj +p921A94?NGy* ]k//%*]N52&`L 0&`#2jkkuVoQ/lۃ (Rm*Fk]VDވՂ`6cHJ2jzd'D`:eF"ÑAy[⢰Td S-T+hVC{%LZe@B,4,Mn/A5>-xc\ E}UZ&I_ƔL'&5FM+njasz*LM?1 7nw8LW5Q)KDt^{N 0&`L 0&qFLP1?`& gCw*b(9ފR^+=LNsPM#GFߍSؠt0uۑZf$[>s7d'{!r xq %8_]]ޙ J; i[p KzCb ͯt#V)l iQitii|rސNޖOp Jlu(nY>ͧ2O)4U̯ ےIen)m4wtr=#2MPۿ9W[66 5`L 0&`L 0&pQXC!d(+8{, Q}iybܱ[hT 9+ܦ{0K,Ӽ^ӒuT=ɪ1`# 4Wpz&Z *mZ FLC\l|Լx>F9g|eJ๥m؀9ˡ9y y'g"Y&L'Y@@3wsNJ69D 1Q yv_4gV̡n0z9@wCtTu^aKhs{k+ercߟ(`L 0&`L 0QE@8nìYf_p B75SmvRq5G =/ ފ)A @XXs'Qrunu۫iuKR1h<0.zPiHOjQ[C^QjWqVAlR}K M5f$z R K\CSYH-Xbp̲JiPe@+aЪ)&b:GrhNp.Q8HvtyW PM.+.О/`L 0&`L 0F`DʼhŘ G+ Jz111]B|P19h}4%wL*3B9js&߉K4]^d\$R*La,;SfL 41vAYMyLƵkʨvN7Omy6LlƲ%_K+H*C.)7s7m܅9~D `LgX~ٔKV Xn͘`L 0&`L 0G`8-Xf)Xcǎw54Wcb$KPMO,],L8 Ӫ""=fbi82҂Β"$AK_JF<63t)Kx6QUm4Xd |!yL4$Pu8{9hu3&ѪO[̅K##g ZXF7`qQ53wAz=.h{-l~ sFįRߓL 0&;(?栀[ox-q4jUjZQꪻy)3̼Yfbj%]M0;<dž9|9%g{HHHHH$pǃKcǏGkN$/4߫`JA,?=v®j@z!u*Kfe Wnx XUS#˼#Uxwgbg᭘ %/~Cͯ[Z&?%F]qvO[H)0?B#-_MQn}LxYu{_!#~2tHA>ERw!C_L6 >J-c0`sa4=Cֶ(ɀ4p->2O!.6 s+}LY3tB1z7N(+Szħ)秛cP[[co:Ta^cʿ0NM-e\a"      j](YJccǎXd41mG*vDx O`*ҔO'*iP;5@. RN vݹU+I7)CZjMgWvTy`#Jsn䎀Pucu6cW O"dz&%$"]<4*BgG 90fV朴V]@[4bPӹQ֔sV_xɷJKQStȦLBXN7V jU(NYv֭FY:jEЊAJR= }wXwfk>aFU8B9CŽ]opn_K qzJ0g :AR~$xBS&0eXnWtld=2|S4Cy Nhw/=ٮqFqWNU֎$@$@$@$@$@$@$@u@["յI|ȕ@eX[s횢7G:aW$nΥ'iDu WK 7|QB7;ݬ`B`#)FF-QxdA{SI g;cV~^G.=9rL8[Ʈg݃W$Pm&0auID$@$@$@$@$@$p*@n{р$t:$ B1J$qL,I#{*b\aP58ȴֳܔ9deb9 AS(7Ʀ\\56߰1e\:M4+Ɔ讙%      (;xwiaGw4+}|w^-f $vNY       :L~(7SCD%"~ n`CcՓe :z:rX' un`kIHHHHHH'        2>$@$@$@$@$@$@$@$@$ P(c@$@$@$@$@$@$@$@$@2>$@$@$@$@$@$@$@$@$ P(c@$@$@$@$@$@$@$@$@Oc@$@$@$@$@$@$@$p /y&nݺ%E{j@ d{Æ q}w֧BYn'      (@QQ qxEŊX!)zYy]Yw/:YG5ngqwduuZ(309g]1 f>Xd[&h2a٥9:#  f|MM{hXA$@$P G.ݻwW\-ec['5jT-in(..FNNrssqeɯϚXaW)ab%x>UK%\IǦ;TQ(Ǯ-8% ffَHHHVf bcbktHvu5~@*F֥,y::+UT^%WͿhHđflC$@$@$P 4k֬ϞS' k]VS[JBE\gkiϙ܆y;zy<.> D䂼oWC 10D'D7!:&>nIIbenͻ%      aRL2)&p4_ HφSzV(9tc!_m|Uf0ӑyҜڢ|}*i@څL U[edF7xx;|pL5n|mjDFj2 Nh^uBbHHHHHH H[J[j]#sFg d^D_iwjC,a2Pz."@tk}-1P˙ұmPxA@}0;ݩJZnL`9(t>U5ksHD'OkSXtAd\"vN'6%Z6#~6pA2@yEHv+      n޼7YHEVL@zFgEzfj+SBYELhYr GxXzؕrm&Vcʔp=bt0O7_H"YHyۤT5!}tuk‘ʯ 8NՔG=; {~b$ڄNJcj} {/E:2 0HHHHHHH]LZNg5^ҖKY͓P{0<܊ه}1'GD5SG:ey`5"pOn؇}u# +kD#:gLkD A5WzmTToO(x -j:tW}[ \)BW+V+;L":K̒ W!T_+g&Խ::N܊!7Be<F!v8VTR DPξ}C.ɽl"sIl|-$KUwI9йfD2ib]104pON3iљF,[D-u%3As*$@$@$@$@$@$@@y 25l?c;˯g qE{3wCu- cKrq uK6_Q?_x}{~m IG| dҸ][ZQeb+1XEIXIkB,_> _q{A /HHHN0Egg7 G:. e,x8O=M~ԫ@."wqre(҇bZMV:`$,B>C`[LJuR4vͅ"E2eʭD{#N2]mϠlE _!L8d}3M N(3/M2U\-PUa? J+դ(=+YmWgQGL#km,$gyN0ï <EK8% xGD)k8hU+%+HHHj@#um*/yT,܈4s)3$,? UYy9%D "8,}gLσo;D9H>cT(zNX)[<|-ihLL,mWTam }9<4y,Y'n b2EcӗgmH08."Q;߮Q5f4&vh|Fcb8z3,0O#,:kONhe_M⇏Fb^+X)rjY'qɫwu~3cg3_/F#R8j!"1941†^z3w2,4Ssd)Ps/`RUx2`2!fi ~|D8,|=Cp[<_شFɤZ(9O셙 "(<U#ՐK(cK].D$|9}1V7Y$tBħDM8yp,IS k  :L-[Fkղ9x7@k-e"9) I╜˺zVPD쫫/Z_p 2 5!L%{ɸ`Ϡٖxɢ}ZyV&Q2ĘZļ.([fffqUyfQm6M$]U84p/顴?8 ]0֟{,ُq,9=q+L7x/0 _vLѼ Dk1VUXE   hd'U¬^2WnH&SOÇ3Zd!B>3uƇ<=:tKɤfO}qsGrzth%~a0H֮F'K?"_1k)^ #IWcpRn9XYLrJnP/v"<π'xߪ|-ډpwj.];bǥF -k-&&a<;[5KwZVVam ug?84}tA았5hǜ=*sG.]bPsfHH@OJз*㋠/^Bɯ6:o(wME_uBar_Ot h埥v5 'F|1/*"Vf[/~3I{ EОޤ0^7fM@'1yŰ{ŬdLJ-8QmOVZӂ30/* !C `5=dо?C)˞|I)(aXuo}!"O m 췻Ҥ Q [ Ѯ? Nbk"?nEօ{g Z   j$өDO8!OxgxcXTS77.c@Uq5:vY7Cr8RG\i3 /8U!RKJGzz"4L(Wwr.$(N`SA1h)lSǜS޿Ę}aX,XP7O$v<&3)U coˊAJՍJ""Zx,Q&/s{K;"hc¦`4,z#Bj_x V`rn" Ȏ1E8#Rin-z ljxjZ,քHn鉮C g_Φus r9IsjN6CcLC[7zu뿌@h2!d1ǜ5{J(sn43z`Hܺ!y9Ys ×}M **!g!Krn8lxU[M0CQK7Z2߅W 3LNMAJE<:t&";vþ};0>6ʴ4N P⑕p!-j  paMod5.>=;Q_/tA#%$㢠f͏bպD4%}u]2ێX\ً1y߷xKKe N௛AKĖ۶#xo:'E}OiuP gٚ8|wZyG6WD;-_`9?2 |]!ujK^ٺ8|<\nc&oM̸=6s_kS_f!" |QٖAF\Ν̰ax#Np^`7~a<證a"]q^4pN{xPSQ-=%U~  `#P{xyK<d^k9Gf:СCxNV%55̧U*{Z D@F§G\M;-w0h)s$@u)ߩd|څ4ܰH"$5XrTsJA(}̈.F!F.ĺHH o(錶~ƂȼZ!^W.C(P< Ґv"9 `-4:Ll.!\\7tTe "[L/IF9ڃj2JєޯAћZ-zʺAVY5 T'c5{uۢVTỽoN0^0}}S_ը31X FzSn5bKm:>vņ:K䥏cm1|D[a/(.KA[h⌀nY;+LIHH^pi~+xYlnRnr<â٩.Ⅹ]//AJn|_|Hax2[/GeǏ#N!}1Th O^3(S%3!7^F>.LFZ4@mBYvV>3E̶)#9d:_Os^n|<@c @m4tz_5[78&*z4) ᭽ѢEk4sNªUd,vĸ)ӝoXt^Ga&[mx xIx}<{8 @q$OPv*|<缾O~RPlu2gNRIHHhT~IH!!x"LjgA'wa1y"<(h:3K-!Z}[F8uR& Muk$oܿ}!^>f~=b\@>]&wW,aDě[=iyK~8>i&de}M[ԡUeY,ŜsA ;Wuآ  *gwh zJ~Iw(<GK^KWHZ0s<K/C?]{^$He4:b"kȕ(-HW)v%3ufsd8SxMz'bfT>ڇ$Cu;`uq$@$po0o"[pA~^ѽ"** j?)эdpL-]`L.p2o|ыd6md2~vQZ-l9*op͈^}<[TAulz{NZ`#h:rSǡx%UW>&|YD6ESAY_ML6IHHՋg0/ګ-"[3Cu? fns{]S|$FuEN5lT- n.w> <O. sAƇ¬ERt G S; Aݞq)_735>:&17.b&+Qɤ./B?ī:mhUv2v]I.=ΝH)uə Vp9 {O3gay1Ǫ)jrO,ߛF#85竑C?:))ļc{4M|ix {#d;E5}d-1%'^4_7>%C_ -q/zFf3oV6˺&Z%ȰXu{6O0_3`I='-N3␂38S +CC8ܠjϢ)3 .]j-gC   0ErW7E:I|_'IЮBglOԄ(K,[&OͶC >1 [3J'܉.ƢxuNˮ_2d$+W>h2^^Zo<|3 h iW СZ<:V]wNIH١ƪV -^6iJwG RRSUMon|!KҾ/]mh[~3%_bdIpj>G^m{&Kz}ٗtrߗ^AcZM׿^n!!k~ 2y T5o2wSY.QܻX7mpMRne梣MmenM>{B h=(M&   {4h >pCT7M܅$' Dj[mڴv4xx".t{JHH"`1_Z^M 6GlHi% %iS1J g f  K H (ݥnHJmdҺkG[s$@$@$PyVta @4iPӪЛ]ِYDڤͱHHj;ǃՓHHHHpuuΟ?/!: NH"l7sfBY,|%/{UYCAD|4Z'w9Tscl 7XXμ{oR_`2ąRZ_9$ @۰/&    %аaCxzx&Ξ=lxy{[SHͮ%PXX(oʆ#C~Fg6Sʜh0S䰙 6Ċ[1 ,Eb Ď׮M=Vv+~߭o}n 30}#[0+O=g]XH$@$@$@$@$@$@HQFhٲ%wIIINw}_nAӽOq} scg׷)ZjwqlvBY1ICK̚VgױK.[M|V+to! cG(+j1˳{\g^`3o>^>^S> 34 o\jKlHHHHHHN7n͛7Ȋ!dLċ' dKƴSHa $%$M|{GU"ei%>]!up,u\0h >XZ$,œO».sM߅y   @lLyvXXH$@$PI@q$IqN=P ,3C~A~!>C ߳m)0JVW PWK<-$o-Ksv선_7kePVyBȚ/p.H/űŲ ĵo3/Urb_w<   kw^צ @% UgP7aY$1]p"Lp[!'Y _L?_?'wq*߆,> &[ ?AP'}~?bɵ҄-Ml9rCį,dY{cU$@$@$@$@$@$@$@$Po +쩾^WooEI.uՉPGDnXzs,+™?LaJcѢ, VhĩV㘭ro݄r bhS[K,!       uKU[ऊObx9z)B֟Q?#Rx_{34F_ ~H|3tkT-VlImm:rV9Wɗ)K/>Ґ$,*mHHHHHHH3{Z=ʣ?fB7uE*^vɍ_]R. c6},N`KH_ !?~ʅ4E#?p{ئy Y<"B,GYyXG$@$@$@$@$@$@$@{ML)ݞؑ 707hVky {Kt OB5ݜ5YvHHHHHHHHD*UfvraoFhմYVn~beH vV|L2]C5׬!]<<`WnF*~̼H[teVs\+ f-cmdD,+/+ b MmrEnfgBFj22/Xqbw;hl n^s3v!Rf; AwܣLLڂo>vL폛??7rR%6|U]И]7h>sv!ێ%ۢ|l>nJ̵6cۜ>l x]8ShK c8/bN. `[eV'~X8!v`xH0Ñ#O$ͳ&i)1U&@=T#('KE{Ͻ]ų :J F69.?N5 ^ G4bӔI$.6i1J{I,8 8m UÃ1sYV;N*攌1_,y8^P"}/46mjޘԍz71 z_^@l=0 _^^ڢ0d:h_Q _2C$@$@$@$@$@$@$PܵB`@hh(Ər freHѴcXt[9.ؼ3|ۣ}{_8`"p~jJ N&&">gi[0*ʏp_؟xH4 m̳-b +*}􁿿zud/Vxs-0Czj_J)hfoN"h6вe[qrd'b[vTbRgq,@IDAT91xP>f ZD[O$,XjWZ:nNj^jbHHHHHHH^&2m]v?FUa"?1B("p=IاԟL+{IcD"t B(T CO+?ާRIxGƬbj{iSN6N$@$@$@$@$@$@$@uQ&yIqȺw^EL!}T~-BÕ.Wx^!N^$mH&7A%\6KSF~"ҎʤwM @V"L),C$|_16zEk$m磏*ݝ$@$@$@$@$@$@$@$pOcBY1tP%o;9wąj$zؔCP:|Ivc,vŤh2dEEDU3~;F;9r-: X\ā ~aBfu|'H͇I+75t0WֳrC>o!&5FѺI+_S\lG#??l[ LHHHHHHH9.I,%ﱱcV>Ykm>ENŴpqr'BGz֫ أz!vB<ѠBz@LSEص'1/π'BBjAjm܉pqy x`%*ⲹ~Vl[Sߝ"ZŨŖ^l0G$@$@$@$@$@$@$@u@ ei6nݺ6˲0u~Sٔ^ڝLt4 ‘hLi#E6Bjj{wA;}axdZ7[l~59g(V Wj "gRPjxKq8"צ1c4:l:$|!0Kz6VqYHHHHHHHDSYmBE;}}e4c>roK&^nzɪt}Gv@mRo=gr4/gx82?G @ضml{„ {֥,N~:~gdegի(..TC\-^޸ѤIJgc     .*5]dCJ;UTTO%2mypVw ˗/ٳ}hٲ%fo[8dGFXPPHd[`#     FZ(F4E$@Iv97saÆ^RH,o޼xy{###C"'ֶgMNx)w |j2    $@6; WvKFN+7n,D" dd3I,^%%%(**VNɳ2I!nа*PR?_ˣqسuT0U(*7Y#N3zquFqq<<s&D#zUg#yW /#Qd\u¯E`ׁeW7ϲݙglB$@$@$@$`EB^ 8J굫',IwrFLe2iQ_şp@MxM7q1-)n7Al!,4۷SP͵ԡ 2)%D&p/0ׅ.N}.#;;Gp( gL/,ť e빹`t.#-xǠ)<hc{M֚t~ώQz»-ZKʱgMZ{m!07S>]ss"ơni; TG>VhD$@$pжXV$L]$):L&t4>xF*#?FbRUVxvNZ+0o]e;43q/oŴR&+8$9Y ,~Ŧn\*nlu8/0(V/o;~`h~ePd,?ozNڵs8=Z'n3mVr#) O_q.vd=T,?[ eŧ1Dݺ1w@ٖ®=}R.ص#q\ y/B'DoKϹuk)1h1w/RE[ߵ`p螃 '1+fYs$@$@$@$Pn_";Z# [nK̪`5e۷pc'S]sk||xE$^G:fofŰ:,zX6w"^Y6YLOb-Q?GdR %RomH\xClD2uu,^`dr/4wVJ+TQ|z,ՠ/ 33Q@~61C3P*WE2;"rÂQXEUH{n'b{u\ge UK։dRM(R~פL$@$@$@$PS(Y% 4zL+1 lb '){}ZWؽٯ>T o|t߼+܁ϣAmΛu0FƪR7c{E;Egvg8uHs,;^6ƦhGgbte,޴lkAK+7-va̠[c P]ni:t =8E[k/$({y&|:d~*>cr3^Ҽ^|܄=X2oʼdso̓,co!sy7} 'q_Kt%llHHHjIS$@$@w;FlM7oj'i]?KF``CO$51I557,[#xPZ"lk 6Qꖹe-@!&'\Xd޴/)NOS4yɭ!BDjshM{R&݆YVAU] _ 85tǤ+8LQ [,s;gRb>jY o[`_1P)<IHHH gi-Z4E[g`\]vjqH4nh&Hg&`IbKڣx~UҊU#I.Ͻp"dą<6AW ,3a2& #?wf!K%}Z$< .bI.=qEomr[d![eT4Tq7W+w-7zAa*2H[D&*M=񈹭y}=$_jm^O;W+kӼ"   JB$DI eZ&#\JM0&aDqrTN.لqpBϾ7 ׾/];b 4I:98 @"P?ѲɊHvœGb쫻EE*.6{ZuE{`Z}=hY*_vZeBn' {=C"X7g]YsX:S8Wg@{ b_/å:9YHHHH2ʐ*c>`HïтE=b5UZՠQT9 Xi E%*\*J( QPL1QR $$5dB2a'>dY{]ka~Ykm'q0B>t-[61ꙺ*ȇbUķQFZrC3<@ΨogMV~cZ'nVn.%ݜD.yMdGTjS556Qvj4uꚦ_1˗pDIOV~([P̰uiVKʫ+Uaj輓J'gZY1XM.\e*8mUM~?oU  P/:\<'Qy)ن6eUGEVdmս{Ց`G> 8LSf޵Oe)PVgF2"SHik?vH-y9]{y}wtYQ  @ eg"uWuS:wSA1B볝Ղ铴 s.Tf'$?zZR/tFE(ują#}O;餻B?{jNPh-UʯS]l=|+m?wKnc>:5ӤGuU5LjU0?=WUP=k9\qˏ]@@!]?>Ss{ڜUqt,ll]m{;n;JGyBǏ-;.{OoȬ˪zR۩'-'#M*`B#!ڱVe  jmZjVfVoqiʼd۾a;Ɣʜѣgpu_B- ?ςkKqEZ3wN8LХk.^j_lr›tNEw WJ;LdrB`ZqԹ_hgM iFq 4Q5ZIyZuV%UPM-ke=z?2P@hwe[I7v^ ƧU[Z06eQ+fu,_M_$gtҙg|tM}!N?KgV?-P)>/H7o>RAaРI(%R+TƢ +{L4 IOT,f_B(**ԶM}>%p/Giң9꫏)5y]z~6VAJho9SbwתTf${Y-_?v6bJмDKu8^C‰7Vh*Mrf̜|VWEL^^sOMM/ڦbӖڴ) %f|7;U/i JUiF ?I]?SKtU\u[|}{g/զ*/quuB+**Ki )S}gַή)8z֖t  @ᑘn3μ 3a̔T.b]6jVhHrd{ٟ$ `Vxz2L5{A$y7$fɺ/o'fiOF{=7N=W#if^V zndߑS)7OӰ:T5˾/o%_/d#,hwN Ne\}f9W|=kt֠k)44qN}wDM`f\q/1N2Cf9X0FZ4ad_-Z9 *eơwt;gN-skiH[#H=JpSA 2"P5n^vG٤yu~3|,ZkиY͛SLy5$Zh8a)))*..ֱc|if?q,yk&Hv?tLP0D_Մ[ 9ou?ٚ1ڙ^O^\s>8,nN3Z3_Ij:So~&WmιWsl]U_dӻ=f5Xs^H_uWz{^))?YӸOk3kW59'R#{uk, D;8ט?}FhVnknzJPusf액k]'2)Z_ڳ2TkxvZ>k' /6]~zz5Q3Jjݾ`6.?= P?4 |f|۾n_e/2둝TQW37-NM1OmJczfl9.|s.ոŅ]ȇQZ4]ݖRJ==˰ʹf gsvJ8v_Q|tśV;;N9f1e,aX`rÆ =ݳ?>sty)117 uTE;lΝdVYJ K'*-!KUlo:YaFѤvT Vo_9Ԟk'eDunx^*)5٤SJb\Q헚V(cF(RG.nA 0-->(Se']ZJY溴#u)Ǣlyb惧H#0m~_'mP[]g_V)# '!PϷ'U+mDkg21,e䚻uZf&P#kThef&!WdiA;3h?"l+f$ِ*AS4Grd럼hJΊwn~X7v GRzz#bVd68-,H-0ͼ:6!P @d:leeZY{ Uo6%7EM4.Qix%8rT븓87<Ĕ4\R#gw1cQm$^95@V4ט=Yx~DiEj?۲u$G@|,Wʗtz}V_{ݫ̖kK/8]U}&HDlE[1Cu@ۏsDvg8_KDiO-󍴛s$3{wUN-6g={Df elvniobd6O7=.E@@S[2%H]T\K}Sheδ2kkmއZsݐY+GW}STW@̜uW4j.njFUփfJꯜ̛DԨ#1ڵ8]v+ڶmidNkV#   Uze"es[5'E2t@M{YsU'o`M:AԀҐm':!̈Qfḭ[ΑYVJ7؉l 6S뉹K}BogO`C@@@N1Vvٳ=R|Pμ %1$.ʖV9>\%He6$GFX`aÆ{   i9pv686JQM,j2N@@@@$b^>)     @)@@@@ ^P#@@@@f P     {bO    @3(ktD@@@=e'@@@@5:E"   Ğj    ʚ"@@@@bO@Y 5B@@@hèN    '@,!   4f@H@@@@ P{}B@@@@A@Y3S$    @ (>F     @)@@@@ cJ@K{KZima6׮C:|ZճM tNzzQ>Guz=ʆ  47D@llO҇'6%G׼c[D}|0Q/׭2!5   S/]@$ @T#lo&A7QZw(Y=ǞkywyNܾ^ˋwkǖMڸq6mڢE:X}{x 45Gy  вzٲ!&`$-O6H֪U+3e/pfm6.w}+_ٚz.HR-tKkn%<k.X>YB6OJKUz_^\WZDu]Qdu¤'nKx?ZKn^wkռ'4y#lwNҘשkH! M,&8@؅jEViFu]c+qLǎ r|O&XU\}S[^+)E)֤-Q;Vy]Tuұ=6G|OoEEԖiڲK \e-qZ?wtA:+m~6;_*xNܨuM,=_|HV] U@0׵Tzp\2d}nfk@@I@Y3S, p* \V/כe.:[|a%ܭspFT-zuOk+5nW)NU_v݂֝3M $zk1YUyPna p;͚lRȑ|svФpf?w&_i8a6}C:%s95u?}YZn6iH#ySfkG=;KaV.ܠן 5c:|Uu'g3Z6_=دGpis9oY˿aʚ&;Kh╾nS=>9%OsvO擕3Ioݠgyxw:U(1Kݚy;S=O`'Xj}wo kg բ?G'j|{Bꏟ4-fi 4zv %z`:Rȶթqf kJY--(ݮ_=15}t-Z.V멅2E**D i>?xԏ&ԩFr#jԺiDsが6AþsԱkf6ֿ-ũ]k| ?7i]ڌ2@9cU[9۬=Ҭ=u;O[gNٛH77(++378#f~ggu~˺E@hbeM Nq @Ke&N=Y~Y_o6$3rUINAOq8vɾPͻ6)G)>Z$-t=X u;yOM gJZPlIʙV7܌4ѓ2!ٝOVO34L4B-,y0/x҈AaԲ[v$%r鵜$nUkෆk*0kM2KGSp]C[NҒvJ ʟ}%0-3lTYR]/[6Ҿ+]=Nvf^\Qm%Qʞ  %?@,Iq4ھߪ<~Lmo.UjZz#M'JMj0>]oV׭J_d܃1.yMtaլs4KyU3.go\P^Q;0lm7o-4<ٟKQBye)+TKkeZ*B'2P[npΈZ}oR;_Ėu'͐I|SkmaGv Y<:=ZZ;(Vfm7 K_srzVuiC/hL  Ye:*Ğ6szHO>K& hң};3By-5oNPZeƧ- V\@uukk&̍EӪmmSZLxivwQΚ,_- px&/iMfXR ^gGJT4NA2sf&HV @@Kʼ[!8Pl,1)ImRR}?deպQ;+VdO)_O~f-^]okɚ<.=|JC-͓s8&RK ^Q~@`V2U3fguktr<=t^XMfUAmZ6]g:IkZT"}``~v 񹢳j'Һ'{׳f*lCȣlO\WjVy6\Pu¢hK:J]ܥIhZo|_kn2`zR#5X O4'8xnej1ff mĝCo İpũ @ ^aeU``vdUԠv'riyG?)g6\,W?ޝJկj-dr4uf-@ Y?>l\{etoWN-o?ÂJ&0v:t \))Zco2MMHU'KCV.l#"{-^8C91P@oƧ8WhDŽ>yF@IKY9TE | {޻g﹩,[^ٞ6 Rؠ2_5쯖r;}Lv?,ڞ`n7mGۻjAޫݻeUT ,,eX)?fJ|dś`_ZJpNlR. kH)N5Akh#*-.UYE/E&*KK%mIL"װht3L ֥f*)2R)%1r^3]FZ>ڱbhJviMՖJ/~#k>>9]]\W5PZ\lg\JM_! -M [Zi @#ܟYc+ Yf]5S-Dfli>Uj N5Eͨ`1_b.-;1,5ÝC@@I5)7!-KVhx:2D-0pYdRڤwiֆ\g^QI'jի|~Re=F,cFk f  @3 FY3w# e֛   @ pX!    $ʚB@@@@b]@YC@@@heML!    .@,{!   4&a@@@@X P=D@@@@D@Y0S    @ (~    M"@I)@@@@ zQ?@@@@& P$    b    @(kf A@@@ueC@@@@I5 3    ĺX!    $ʚB@@@@b]@YC@@@heML!    .@,{!   4&a@@@@X P=D@@@@D IJ@/pQ\ǎ[|i   4@V*!!*D8@}uHeG|}A@@BR/tZC6e Q@ _F[V۶m}QE  -`# Yyy;J,c1GZCD/@7!  @ fbg4d#P5A]̮E A  4]f<m}E+Fz@@iioM2FqA   @, (vQ%ڍ@YbG d5ʸ @@@ 0wh7eъ@'Ъu"    ]/g(h[-[`$@@<"p#,4eh@@@@ (k]K@@@@ Pi@@@@Z۵4 @@@@ eh@@@@ (k]K@@@@ Pi@@@@Z۵4 @@@@ eh@@@@ (k]K@@@@ Pi@@@@Z۵4 @@@@ h@@ظqɜι  a޽{| |QA@@e р Z u :Be @8O\@N]CyQ普    )@1u@@@@3Vm@ .Ӥ#f}جEuEzx@f3 }k޷]kMӴe5KtjEN_}\MuMnxXTnSUv# Si9 |Vyzً: 7i7\&5oٟ4|*taEM鞥԰z雙P|bgT93P֬tm΋z4YSnW]tzw2STbUbjz "ͶOVzj1e%t,nҕiOgWF:g0w&x̮ިwОBk_/:&ji2ާ6:;kkq26J4dfo&]GqFv@@SMIz^@Z?L4bfO0k^v a4R!z>M{G+t!7gMsrRاdn:S3[kɵeo7И*]z$z '=V 3xlU0ŴQm0lYgԡy5÷3҃7*)XKq'}@kfݭ;+tx=mOA?<+bmlo|Ko{es<f0]3\?uQp6kMM_k_yT=VVâȁxF@<#e** .|Z{U|Édl_$ovW$[:A2j8ږN qrwg!ES6mϩYͱh㼕JUoxĄ@rmo&\vhR!HfOY=M|gW}8A2|";ܜ&rc~|W Hfn1䶾f^_)NhvxptFX1~rǵ_Ov{3+oܻtj  Dʚb@& _n=D'1^YWNaFkwn9ﻴ_{O^;][ݼC@9oCuɺyGҮ߯0V(.3뱶VŚx>X1[; `ݤ= !Z.c5bE-Դ;G;'6Sxl8FM:G>^yV[㬆m~k,~RNk_Q8ؼL_ÂUJ  .A @ kS!e`\,^Y4U`F|ʴ~3WzbU ,]cMqF#B^]D%^i{D]~k3sL6@ԭ< )+~^^;UWe$WcV,_fs5w\LO԰Yʹgu>**:YtW熲Kꪟݨ57G}[Fn~xf\5}!5뇚!fM7g,L@@#ri-AhA5~1VVHըQ ×oTև˜fbaQY?4^:9oAyfˏ}FcΥ&Ig"D7 PN3/3q?5Jԍ<~\omӕ+sFg_яQ˿sjnx`nUV$g+7v?C7k @@e ӪeV!xZ`ea=1F;WbW7ZWϫqi_(RgT`5H_ Hh[$:ϹjseJH<9BrmoF*M{n^=ophN{|O}屏 0e-Ci вwth`X:f$Pg'H$sޏX. dԔugC2E j-he} k7iU+lL>V= #Bgše @@cx@uU߫ݍVIi&F D1$Egb[ΔfK}qz@S)ݶcԭ]VU;i_va1F3 z磵V?L],g]ZkD+5  bX̿t% AZ@*Xl]umZ҆7jKQIE"*͙3,r?{NpEO.qޝkjJl9-~/;ew.],Yխd~=6ePRSޚҕuM>90pyA-jzP4ġdYoOЭŐ@2w! @@7(+~Qb% 7g=w&=4I뗣?v|\`/Py yŐt}n`5,i? Xu޵+*1~s$I1g:S'@bQuN(Zcv"g_WnnrGݨK?$-9]ΛdGz?Px@ee2ߢ:TyOG@<+om GhqѾHH_tܿJÞ0VO󨱍݂٬vە{553uMV<Zh`ovB*$q8]w\UdǁMeF_H]s\såwhm4Uplݘ 85'bE5r Fh.?o!un/S;o Qt{;"hz.ߚ?mG֡l߮M46|滆"7# @@ Ћha񁠒sz/m'ΉgC*IWݷPo=wLֽqkj9jPn{ YCC  S-#g.J ]IDքF:ӕ7j7W@@:tH+~B{;{4Am[]vQ_}QOb@)d(iR]"9)5]IA~ޯq$FsR\?`;D&81@Y[Cmp@hLlJ@@@@ Pg    @e-Si    @ʢ7 @@@@(@v*MB@@@^@Yf    NI     G g   pr: 8@heJ   @@5#>E# @޽O&^@ky*    @ (k<[rF@@@2uUE@@@h<egK     P΢    '@l@@@@Cʸ@@@ 2%ڍ@YbG >2`C@@[ $}%(V A6m(0iAv@@@(@̮Mf4d㮗 Q@#GѣYC̄@@h@`eَ$A~/!P֐^@@5vyy***X?  4bd;ICp @,`!5txs D@@@E(s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@IV     Pݾ    . (s@@@@+@̻}G@@@@\ P"&Y!   xW@w#   (@ELB@@@25G@@@pQ@d    ]e;j    21 @@@@ʼw@@@@Ee.b    wy9    \$+@@@@ (nQs@@@@]̋@@@;J?~w^9LH@ hժ9..N[{c ~a6qs@;@@@@*++Sii>2`?^ 8Y+ %&%Mr())) ݳWvD|D7J4@Yh   !`c/b?_Mli|}=y9 ^1  A&]_)&; Y)jws[۟eD@@h2{;pL BT)ٲ|7<(   &PYYKVFF+8g~g6>%O7?<#  @ ػUTTRjBSPMf?[3\撧܀eGuL4iK-bl۲EzJu7\x7ק\وgsڭy<l^e8r8E*ViiMB(&$oL2L dKYfZkoߏw@@VxpFX dv?Cu 2Hv  "0\/AM3~T`犯/R kΗjum:_{~{ʧOKK+>lMOC ռl|:oq_d8w?CM8ⴞj2><6E@@d(ӆ՝{~u͢:;USWoܨO|D?>yIQlGGBHgTh֯\/'[uԾPmE'2J;k^-pϋ }єADծ^u/6hQ˘+oX8@@@ 4eZc~Vb3v춅Ԣy}9&5sR]JZZ&]_K N T0i ca8q*\V5ju^~geiW$rRUo uqKYo::hGeu˝n8%(xB`ݛxIm|w{>GFRkj@^գMfgW,?,cV;gi*iEq[ZTeW_oR2iloZxz)NhQfkiYbr/mܨkK LuO?j ,ꙋ\[9vmk7Ь#ô,ut4mz]rn|zmnUްSY6=v*PTL[fUο[z*g7U5ZbAOlma>oKtʚ%FQZ;+߰Gr>[yv}G"]꽿֭9%|roON?3ʘfTm~W=6iݶj̨6;߸kC5qúEPKP6"mgRwdBŔ;k#XMv m~n~ņZ꾶Υ^eρ ^^{Ǟۮu+xB}>r\65G%ZI̍>{vUJW륺bg}-s  \Um.Ԣmw 5/_Gw4l?Esd勖,Z];_knFd6HjJ^{5$]8PRs,U  >7)j`F$-M,&2K,";  blk/lԖre7{DE7ᗶ*ں  |JiKzP[vۨ7k6~mʮ"  0FW:~ݵY+f!/Yqw8{"_k$-*?dЊ?P>nہH*@xR}~v|^FKKﶎ#j=mM2«fއL^_Cgʪ̶|6pA@Ë kkHb>XBUjp[Rsƴ(i+Kfnjw}OjnIsD7k&ߕ*2fA1ڸeXn6Y %s>n]:hUZcM*k]ym{BTAR UƟj[˟r쁏{EmlX rA@@F@Yu]8ݧvpJۮ&ޒ@FJD>,=$Wh*SEg,LZhQ_̎ jRvz" enl!uUϏjXGydxY?}U ֣-|Ȯb4љ'YNhɢu?n{V޿nb`Tu*lFJ3nxRM-PA'w ~E^\ Ykfu*H<5  cL\~fFJМȓ_3?/ѲiꈧaJ.{IKb]&YT[^?׳;ȗ{i9ТW,ՒQٱ^bxzy_x\SBM".AmppXh&fhJxgnk)ư G v|ڵ={n_d|asAu 8!;͘SH`{kht2lֽə-)ɮي4,XV1{(@@@Q-μ*L~kTu~OYᔏ }}C}GNRNVK~N*U[e6#|3EOCфUԊެOw~VrkO?3`Pot,  ^ϢN~jXw, }]Ewhmڲet+{viǎzX OEӵ[ݝhg|th -jַ: 7/\4C{X#>pGxv cڲe bJl>'e#sC^3W=]/Hfmm5>fY6qZ;{wmKGZw )J]p7e+P5վBtk ?vOS[u1;_@  tϼ;<{W47-S5d_@Y6|  Y c?HhSwȧ9[>g&i R͍WUr֬YsՂUZr, ^~~htL{g~_ok5KOZy- ZJ\˱Wԗh/~wdm\~59u:6CVxǴfgcM/#jhlTCC+ڱۚ9g6[i̼!G$ޥȫnəl|L7[`ѥ,f~?VM? 9d4IDAT+6 _$u}.euWϠ1˿gYE[Ů@[H`|.2Z߅@0z?^]诫]fXV{/_W$+7tw5"  -;v*- .>hSnUU>{*6hQ=p.^ɰK- Sn?mLY}(nYBuֿQmLjmn6Zyt&M6*XgeoAM}O~}{TڰzQzɠ]^x˫6h݊y|u99z`dMԮVūJeEoEj6^|!r=߆ D֩bF+׶C/^\ sr 4Vυ}qF W7cuY˵S_32fm\yeڴfQ~~z^4ǫ~JL4fQ̘W&,A@@Q"k)*7U٪i+~m5U 'qikӡGŔ9}#ڹ1G6 - >lwnҒR>ͶoPPG-ṱѾ,EM .ՏmSբ}F)~{5x >L[F,jɲz5互2#yv>c܇цp`OETeVk;d7٨F;=:SnT*^UmZ]SHܠmM>wFswOdo_zw"˴ܹ&YSLiy#-ȻWx칝PU94S'G+f.uoQrkw֛E5g@]_e]*;fO?WKzM'{\> (٩7|S̻'gMZ\S>/C9DV9okGSN~2?vofW.k)5##NA[aEk\k8t5:Zr[Nr.W<.5c:XR)?cu]?e}{vLM|JO,ls]GT>׼1e[@~cL60Fm>Vo;dTVvYm~g  Ч8 ]R;:gFᢡգ*#  @r 7b>++++*m驶 dyY#v7@Y'PqrQfd[CZEXRmqdMX#^SrHMI}J~C]1Kj oէ`lG5 ^0M/G@@@}]GE}$ESrHM߱]CO$O탰.hǣT:.-w T?kŊr}@lO&G@@jHII2ɚ2j8c=4=6Rw|X*HQl?~GlrM\klAv}E6y, }@ec @`L G٘> 0Z[[uctÍ7cHow)V^^Pw}phl畭Pc[kdK  Q|cc`Y Rܽ?>_{@3[br~@Yrkj  p|?ɓ\4YEEEI?91'&dI={V=5E#pʆ R>  t N'Mu>x ˺p.^(?&'ǰLjʔ)صG_ {N}@j8F@@Du &xYdr//HebBX$\0*JKKNck).߽U:c  |>233uB(m@ V 2 yJ斱 }²H}@l(e   ܃~>`bc80RFQ]*    &@lh)@@@@`4 (Mg"    a`@@@@$@l4-    0lʆ@@@@Ft+    (6Z F@@@MF٢    &@lh)@@@@`4 (Mg"    a`@@@@$@l4-    0lʆ@@@@Ft+    (6Z F@@@MF٢    &@lh)@@@@`4 (Mg"    a`@@@@$@l4-    0lⰕN    2Fɉ    +0Mû JG@@@@ (KsD @@@@ k:єݰ @@@@[>?@@@@ An@@@@[@Yrj    e f7    -@,C@@@HA@@@@ P!   $H@Y     @r (KC@@@@$@,A@@@@ %v      P hv    ʒP;@@@@ (K4A@@@Hne}~    @%    $>?@@@@ An@@@@[@Yrj    e f7    -@,C@@@HA@@@@ P!   $H@Y     @r (KC@@@@$@,A@@@@ |\/*x.]`QSjƍS8fi>ػ/5*    H@ P ttV e^͢frA,R5i|22tõ)&(͂fL    \J "H^Y-ѡj=׮@@[bcyYeL6y2ZZi,KK)=-6I`ZR !   \pAs%>bT=kzFM0V5YuY(eYaHOӍ+;+C {L( ΠֺSj路72|)`ٝP^Na3&@@@?M@g(XbL _3y7K**#I!INXFI(s`r3-~kkY?݂d T&XfYJ}tW ХN mS_L S L4 m낕gM43Ҭ\h Eڵ   VSО !TssN>{Oyyy+ٞQS%~wKcnԫsmzw2Ledjr-lY>5td)>[9ִr٥ }$kP~&o[>pvɳŗ   pU hJ暫9ؑxwtI999JW~`XΥ޳,}52\*+8:wQs^k˥MY6l7#  0\2M6Fՙݕd{k,0Fu5Zk Ètߡdc\.ZPkߡu9:\scKOMIIU>| dUGJ>ͮf2Q5߿5̧>58!Qp2]vZ,8:&:U`=wtO_ ؀|iL4њwfS&MFD@@O;ٺ)(,#N w[)HN#ϾH l2)jZ>,Fɷl2I~:ye[[϶mma͸N#}~"e|oM2SB{]2zi}iss}M8@@RLDNfoWi]{tHO#}H ms:?؏yZo/4sY^.LOy3rsL2ftm}5[lv?ENVp}YvMZp-MJA>Qve7ʙ6Ն|@@@pY4L@2]T<'{FLhderuY:yY^Geɭ練gi^p޲R@Y\/62\b62MVf׷uS-'*;NrM9:wcNwYs -8gɴFt0!  % W\S >,,/7Kٙʶ]Vϲ|T,Knn޹`y{EO.aeEsRE<   ~zr 9_cecjƲ"SjdwD uOA2ZS1_+6rL`g~x'HV9d@ ?%fo=i\uӍX+ rǢ'Uz*)3%s2뽾kf:wHHy{mzo@O8;tF-~]{$G6@@G|KU#ydTZ5kh9_=-_Վ*yB;? }T~wUzV&9-Y5}b])}3DZnMʪ6{ }HO8( Xs Tt?Kʱ\ FtlJ822 5ןs#h>͢۰3,+ͽO\ͳ$s%Go   @ k"ִ둘]ŚWvNzOyR+fR߬cGSuMf}IO_`@-Bn-M^8]RVdt1G}%Pزe*j\xM*oEv|;|o4T |N2'[~͔Bo} v#knՙ߼f~kRy 40߂n=EOhgZ?cfyG@@]x箞}5&H]~E(~nO,pL;6VDm=[U<>rBOeG~[c)W鉲Z6DoWZfw~U{}fQ}rz {-W]$Y. WkWjz"+4|"WxU^A}ީUUG4lG܋GЯ^Y>ʺl \3,̽0(FgZt^.ZflPf99rYc.K_$R}̵. fL   hh=q*\eޡ(C/饗^?Ay➘ Yyy"=]9ջ۫Yvh5AmT_>]E۪o uQ~a6ݾ0Ṋ{Vgc"G%Ut_x}ǷNǭ'rp/Z{/$1 "@YGg.Ft/5[_b:yAӅr3eQQ>,,gG.+^f}6`   dݯe}tVaJՆѵp@"5lN ^kgP%w+Ӛś:t q` D_uK]oz9|˔_;%NTO;W}_6FyݪtGKz`fq5)@YH馠 xYfgUDZחe2B}XsNM^-s (벁Q8^Yh!@f@@@`&xU=jh!#ulі/꟬S,ݮ-? HD=5 PYuo3d XN2-(#i7Y`]U+zxnq{<-Vhq+ՍJT^ek7z]r8%hڙ*ssth:ή`w+ݍvo^ddrW@Ze]煉gܢLz;;   Es>% T`6X_`'ҭ/ҔK7 -m_?yA2WXn3:l}L=:6vmz|WUQ9oد-[hˎqF: b;S=/Pс=kY˲Ͳz+lX^PY=_37B ef{Y_@ڽ9vsT-]_d5!?GI?hy.a/^s̬Am?   0l骬/i͍ڵQͭ .Л/ՆՋ- Zxڶ 5_s}UvQ eM} 믬6_فjӇrv{p$4uE)U92hfu)2bkje_YYieڿ$suM93L+//{X@@O;zJ>p"V*W<9$EyM˼晡o}C3Sw߆}Cukmzy1GjQIK y݁5WPO\nQ1T~mؾO,g>_nx%+ܻ+6oD-ޖ,q'@jhb笩㙳~;z_.NSuL}y.뎎N`[Yn.f/C5tW^jr_R2\sN7@(v@@ƒ@gg|M31pX55(233hO4X9qѻb[_SQaTk Ռ5miyZ@KL [^AFNr2.P5弰|JO`غ&Mz9ۻFh͛|Jc_HKSh-poUٖu:Y,v,PQr?߳$;kޖ a%  C)3J{{4ʢG LH9aOn_ٍ e fap=w &3غYpȺnePƔ7Ce.YkzQYSwߡ|P0sj>ӪC]uFҴ^fZ=a&]Mvկ}}&ҭ\vix1   0ܳinnִirH.=w &s)C_-c~#y?$2w*S1GhB~` x̲sm(.߫F` ,Еb#`l^Ggi ?Q-$s Xn0xQz1!  )S\&Y5bB`$ܵAw-0g?jω%^wOR~׽L9w*'˲8XY nakminZb ׷T%5ک^f>tcB@@W {~mp W/Gpw͝>)N!C2,nF$P;gX,LS5t`斻2"-0sgZd96:9!vkng#B}Yڽ~:;**|$Km׻>#  V^^%X6w k.|%sĎ0:u~Iwp?$tާۼL_|:XP뼗16r0rYb5`M3XY :wu|՚[E+ߍ9FTqnI_,{]n2G@@+ѡ'O?~&MVQQQR0Ʈsdmmm^3ߓM'm*((ɓm̤B~H1f+lCһXVf׵XNN]:c}-c̅\Ha3HƢHd.;/`PgZ\d֟Y.x:ss2ffZt#  %:S4iש `zu=s3 W*ZSڔk\M2+-w~.Yuz?hF-Uڛ vi8+.̯ p&\|ii^-T,0YvmXݷ9鍊y>RR^ݬӧOM?%Q=_]IENDB`testng-6.9.12/pictures/refactoring1.png0000644000175000017500000030501312732165123017353 0ustar eugeneeugenePNG  IHDR?*?:NiCCPICC ProfilexYgXͲM%Er$HHZҒsJR ""`D `}>ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx @vAn<@ ZBx Z'j[V}T[mVhW*hGEzVA V@AH 73M "*q7y3;;O9Ui49&8}tzmll .br-I wv 믱c _r8--222l2~ 0(˹st#deeKi@Ye?&I(/"nu䲨6/_{O.=e/ '5t|ϭ;|?ލ_\çW1(noNܤS;giJJ۽9d WFiR!/Itq5TyE? ʤ52MSJ9s0urD_2=Jj+El~_O:1&/Rr/uʶVGJ5"o]<қ RB*X#EDNsN"<(-˂{񐫶2=mmAγSjŧrn/Lj<*MT%}6bZ#`8m)|>A9 8t _Ոq4F(K Rl-}2ߊ1M֕'}hs tnPS\./48ں%8}ZgaS%9JuAqءO쌿+^P@ RԪ6W2nMB"tDn^vS書>4UX6sG&_NWm`V?'GQאJռx/ڨ>!U4{K'ԔD#K`gY]Vz̹[$SP%y`|i  A_O#~(ȹ>x2G͉gwЪ.b{  pfl*,PXX#-rjnE^d%~ `)(ORpsQvL[{*X899; |Xvvv޽9JJJrssA4aPez)qvv4\YAnczv.,xg-դd彂9 lԡE]4 &̒GqƀJC7qIճy 55VB.y 5 Ţ+ |Fh라qG_M1mb^=d&kxzr)_0ޏaR77G k#SX%t\ylʥ&]k@QR>CSVUvo>KM=Y` f,-=,xZС5a@$=\dra 76c D`tR1Reӆ8B@U䱇mC^&YvovO" dЁoWȲԘ%y m9,S$AdQ-L)a 'q;kg-RuԔ„1#4%jy6xM:li'l 0`Y5!Þ[=veLPy^}V/YcJ2n!Ys Ñ`SP%m$mFJ,j,Z@WU\+3*ܟQV]f :u]*iͮ.Rf]L-{'L>z>`Fչ3v0bp`+8:|4ͺz`(3U_W4ؓc_eQOjs"uεLXXg+yÏ L*k}nCߦMѪb#ꑶ\xz{Ścb$O\U),vy^ؓLDiSSARA\@88+k]gY'lԅ%Rwډa@fKgn=/ Vpl5[)OqR0+SrJ@Ԯ}Cfezzoȇd ^>&TuO]z ?@* p:X@Ga]\N,  FusGm@ z/@;,a$Dz7WoOliVw: 6 6ߘ-gQGe&@ʲJZ-w|guLds/kV/˧ vbF([זH־S,?c褠WChL"΁ybNBF$LH7&TETTT{5X(7'**NtN,y߮s2ŵeڻg*JiYt&*7SmуB&KÂ*gl!TP(ѕW8qƥ:?_%J%Z"9iJ I V, gwR''=*0扉TJJ5ˬI^jjt]T6{'Gup-k "֟hRn u:V{x:wkeXse6Pڎa&mq-^Wڤ0X4!1հY=ԗnKIKICZUoؚ,T2r!*k\o`{Q#-)5V\-o̐U&Ias7}:kxLm()oXqJaٜ֍lYKZ9O\ <*ܾߜPBɶE^y?{4lLOw3lOjԅu-[;{̱?~G[96ҏuYp<]7YUz㟦7LX:iS{ʚou0uuUÙm3ֽ 00Ժ 㚘ѭ|'t$K^*C/T**гs:垘׼Tg0Ջ_ ?0qpqU\n+=\q)fCWSr #RܦuXx+̘~S1Cъ;FhOH1nDg;EWB09H[{MU<ʢӱ0+Հ+KiNf -Ň#3+-V5^ X״kuXRe) 4pTWfE/umg`%#l@H),(GLVLwhx,i4%qq"TOZ$#$^Ϝae캨'c5h;mp+ w۾S5\lja$Ӱu]0؂w`|4de,P>:噜VL6|`|k`l#5v]F`OF¸c:'}_/rXki;PndZ{ O^ncJ)"F2e[bs*oq+b +`a-3v? FP#!Ep+_i oNlkhd*.ЁE0g#fϞMRz N 0Wy}"f T5^%^2YQc?÷RFt̼(C?/<Ǻo~@f}gq(1}n[[iSr B̝7/jm̀QJ9Wݨ{ژ9\w.H4RV?!x_0(`xor(Lg)6ll'47-PM pC̫1(e_ ۅO%q4E2|MYمލhX+Y]x}c %( /MqΩ5;E4a}T_ĩ:sx#MN>99֐szq v׎[=_y@kVUsG y$? (xV?UO6j(PTF9C8?Sv3Y:b$2>f@{UzG˘ nD6nݗF y}J4U )7^|: PŅLp0nlfywn⋾:D^y a8.lNf ͞H34Ykȁ; 8p@Ϟ=%pl7/º}[J1- ^u#$ 15v_!C\xMo]"cK,J6pv f ud1?lGae@mZȃSB*u n1f <* n?պ{  n<$9&՜~.ffn z|sft@N;#~{>ӿ\¶Dp*\ KP_{ʫky3:2f <񣲨E _hsSS<w,Op*//ʃͥ UN]lx[o%W#XQa:_"p97, mCMgRrÑfUY"lL#ѕs*&$$4iUZBWMŝSt~cJsn5Dpҿ{~§=V֥wo_29CEa~eL:1X(/J\&/gI17N{/8Gq?B i X$MbkGG;[;[K!i./ - l>KP`Z< 6Uh6{xxt ;΁O.Lƣf},PfN =m#{Iq`)Ƒ?[# a/In+{.o7l(p7GK=eKq\,ǁdAd`,H9:Ex4&+dafLG 1RHH6CJ(-∞POj !2$& *e;[c/ ;#x }?P@2-xھmpLjDB c</"ۏ/;wRg ځ1>[ߝx$ExLFa,쮈 W)eLr?dGc,clgh2gЄBP%u{"[ p 3Ձ4%bW>0F|9!aP+0g/M{ᯯVi1g|Ih6MUyaG"^U[:g1 ҇^@ʀcWc.LKT"#|2[R @@|Zr[[3 --@-һ/m9]TeR+$*ck;RS0WB $Zֺߘw2VO6nanL\f>cZpWp"&g8 MAickB4dg,@Z X 6$~C~Kde.nLz|{ sd{&wGw?,{8 t|T)H#@x탛z'Dɹ*kp[.|Z̜E"gk1~{s?ٔ\8"xK(az,Qb" 4[@hDJG_&0`y -YjE0O,4%Qe.S@l3v ٛip`br6-a/bXqJS bիmP¸*(ʠ/pA.yťCiֶv6VPq6$D䒀|aHdB.&kdHlA [ԝԖS"H*EajlޫLg ]ߎ[Bb S!$̽5>ï1=</و-~DDQil M!DP i(6C}6lҨQc77g3b-36XpY4pacRr2L"Z/|6[f7]FZ:߁6#ثG6svmT.ES~VտD;/ a̝ܘPXjd%2?;Y{PHuo9JEVV-wrs ֱ8 `dwd .K2} ICG?42gl:~VŷSOK*PZ GC"M|IJg}p@ͪ⮓? l*-*il|*A$ -P-P,,$KE \ vpϿyz9!-]_'7G(R"6`fbH O oG.@Dq3NA?"1a@\cED1Q/ <|ƓY󿫷f{610[?a5sXmXonrC&N-`ϏP/V+3fiLPչx)o" tf̲t]22p[ټ:V1nf'w~Tg [7/;w~m]a@_t_%A^N5)! H] S_k2 6#U5+@ݚ9, ߫wʆes-̅TXDe,aBtDPk-mzvvvFZrKP _6bׄ'e߻i;>cK/~>l _bОO_ _IܿFbn|<['&+ލo[D\n>Er7\:+u%3e֋Uqn{w>ëaæ-ڍ_uQ$kko:IXfQ?YwwVl43Gm0XI"!{Ӊ1-qgV~rxw>ܭq`>{⁞hf <7tՓSN9E LL{ [+gs蔿&su):5Z@{p׸<kfЧEZ#I("- s͜0hiK+XnJt\t?ɵ˔EHȅ9xD| bco^ұQSOOƍl8LفÑ'!b 'đL _xcOK5פ 턶r4CsJ%] y%*!=rGPۤu{=/Bt蔟ϞV3h62o AFЉx:ƙ0{cbwǰ"(=vExG`9d| Ro>-`bܬD\0YUsj쎡ߖ|drf_z~ǿ͗QEZ=tZQ:\+[*:;3ӠJU d O9hTc]DV2i(t^L*DFRw4htJI :e9q5NҭuN)vu?:%!:q'?u9.4ᜋa"v@}Sq7LIҋ) (]aR#l*,[M]w=s\ȿ`?~R 'nͧb=T U^QՌ+/58Wcg P<>,ؑEz"X6 `iq7T lJQdDn-љN;D>5Ya?~H٦gSN+6:ZN p/A;E !"x6 G`z l5 -ZZ0ZK60-JꝛbP6`9 vwbE^ɯk$#(^-S )gS^ƎSn_ @/E 8B>ܥFB`ȜH[$Cy {, )jKL7_gۺH/n=P1~!ؕ"Ux#?&)V{jAɔwB=KkqRŶnv4 Gqhȶ,zPg]f zX.uw*_QLЕGnabܲk")WRrQYd4zBoN?1eHp9MS.{Ch\1W*\ܦ}F)y/2^'AA\ȥFyߓHAh-ėZgS~շH.:ef 1;34*HA8^ (@ Gstg$+ќ"nZ2Fpž}tH[*2QءOFo=J,f>f3c^~9Zk?ܒڋ%QJy/5 lɅ-o6w_K l1??y6_:wEfMĄA_AAYɇ-GQ~d<+NzϫGrL a-FSϣ"ќl?ysEŖIߓfOid>X(8,0u_SˆBcA΅6uU:mKp[i3yin!(|e}\LNI>qVyNĠ8Q+y:8/`| z){q&UhX&zDԲsu38OA#:%BE;>}̵"&cz;^t]n=ˎ|7-)`H 貑y)Qtz%}E0/!aw Z5L>Bc^M>xWGU/ȤY#?klbFӌYJZ^Hjo 8)ȸņZld[c{;^īG?#'vزTb+k1 f0O.`9L6%UkRҤ? e2xS~߽nXc#N0ԦÔM\ y[;&5b]#ǒ%В6;h# RKaW϶7/ `ՑSeS:h"fD)!Wc ;U}R-2Zz mZ\)E({{B͠xEL'U5}&wbfDȖf ,`IY}#! MXQo@\.쿓r4MiiiIIIQQQaaa^^^VVVff۷O9.8i`;zeӰ\._;xˡ]3`{e`9Ϟ\4``)淉hWWa: m#b>^&ˈ%+c ^BZiO`q3Hl5<*렝ݔ<=&c. )$AaşQ~^-=SM8wu܀SRXhOxFɍ8:VKƽ9:B341P'Ay M6ޟv{ (~uZW!EWرWYX8iXJʼx\Eh.őyV"w!%LJm%_W5_C,'Z;+b0e+kn`~͛L-_C &y ԭ׳N4ݺuOLMi`wC*۾ eoec)+*R/XyĞT:[a5PZ"-{e}ֳٻ9N(n_40& Aݷ$ `"`6B3[zڡ,mLul&1^Q}Ƚ-L!rv2Ѩ>i9x@ӭ(Dgrk~/9OKa^,0ڎ /x'h 7Y~j5' px3`\nu{{c|7qqkQ7=6IRx '#P|+fD|4~p,tO d3k̇ġ1Z8( Z> AȞ)9m|aIE~3Nua{6:fa?^/6 z|^t;=_Aa%,֗g$YD}gmR`<#i1n޾}±_~!iE} /F/'ƌJc`2xl$n֑H0<1KאB7Էߔ?OжCes]N>}W$YsQ˰ف5؇9'kP :Zsq5]>VHU)-ڜV‘G2Vgf#%زE͛O[v6M\Dnh+VytFzv)E;?w76:[UNaBkQG&f\9ֹmFM;2)koVQI *z1K'ϫyWG.&XN'e:'}[oC` {g Ȟ~q#o^䐖A㏦Q}x`KӁؙ'0mH/z6%>뫧L p!g6 m|W*o!k͜~{nF$9/xӏvWh!JJ[;jiᲞ"=~&+P#OV`5_cGn@_5>QMp{7onFQW#vRWFK& 4rJMHs&=:ZPT"͆;*XVúmjZ.U%:M %9V§GM/K_E>߾9%*+Ok^n#pO`/$HY ɅwLv0Ys8l?99Ej(GYgCW0DDaiZXJM}U̕^5 ɈFQ2 iUJH`8ClݺM(8%|mQZ@]n!|C w|OY5SIo:PF2mvHPeZX4r JkibrUZB\TTԁq78FH"C~ j灸dNU֍< dr:ZvbXlZnJ'* g)n$`a򺼸d|5 F}nFvJ_ZO߮x? }gC/|_ps&l**,:%S\sE{= 2n𸪟d9~%oH)"[FFea djؾڒX9:z(Bfkc'(ֺ!4'=֩)B0YԔÙf:f4듘1 "LH43æ5m泉ۦ P"c$={6!g)Y9{]1w |* <6>>rN{e(qD{Yd=|mK!cr{߿)W(TV:MF\ Ԉ5sN?#` {WTHYW0 ): - P4QgmE:8_(!wjsЗ]1 aͽ- 8SJ엠/?s "y.Ta=d$ nr첈"pM)4Ɛ^8H™ϺCҾϴIa)Q̈H`Ff IDAT| L 4'jtE( Gjʁ(dOQDĨsA0,6tȥt D#;aCތP@+bՊM6B"+<+`-~NH(>^nI(pI%6aJ:9. H_% M#ziФI!SAS w?X\ l\\y3Rvm[JY1g g_RyL,mkө2N4\\\?CH{T,x"mHOp/C1mX'& E]i;4Qxf N 0`ed KPzݚ9|f)kqnL0Nx@E,&b@<4O k금e GstJCjlܲHsH>KZ5С0Ԉr:!:D)yРij p5#(o퐣wϮXFuja>q&MP/L 5hatIPRi!VfVJAw)2sPڹ(M DpߢFss_!r ՍL\CTyͺB| 65Q%QWpGʉv:1chq;[IiflOl:<6^?:ʩCf&\%uҢM0I&֜_VY5f7~PA:؃RɺK󝬽8,Ew[NN΃-4LB~9D}۱/w>s/΍h[8D"e(#$Y`9Hf Œ"1)B"#1ss2[Zד%Sԑ׍%8cOVص "C J;bZ$N/ ewGYqǬۅOk؟|mG[/8Bp.]0J<Mk.ZK<"[Lm\P*m,p3dM0OK@OFO6{/}r23%yx?dEROw[W?@d}] ==HKfz}l7$hW!s:" M fQ%4`4ڳ~-5VќOY6Smbp=<<8 -PG ro`fK!>ajZi͐Ou{At _?1xu9lc̐@;.?h)ݴCK!(A1z)Q>SujA2UnyGNN ?Q!6 4IǤva!K?ix0I79wp(Ɓy0@\Ll@%r - lh%\Ca䚓pզ0FFM{VC)Sӊj6!SIg*.T۵p fFҤ4v Nk/¾\F3N݃maXܴb) ]r g1'펷O | DvqOCUZ:ĈE{2Yp"SK҂*+x?JukUkARN "](l[I rvrv"[}.3eFl'#aZnoY 92B^?F#&W$$SV؟gVU =p361w@yN*$e?I~o 3/=m٘"b,C\ԩE~*X)@-fR\b `(Ga=^^ 5IDiHIb {4,1 PfC>#[Md?R\Nav"f J֝h)U|2d&fdjl J;.D4AvlÑ4Qa3ﮢ|/t=❢Rwa_~w;vB+Oߺ}EK  [;M:YɏQI2A$>Pdk*@`F$% Kcq>Ɣ"M)pJTw~A&ձy`TSb@h-8ɴq@h$wr^*hn &B*y d4x㢠@ɰ/RHd2 YiQq` xsN:uגJ6EKXq7QPzN-S !m%>o[h(ƴ(x y]"K"Bg$%sE\,J%%HS2Ma$fD"&YKIM[̅ 2->!. #CX Z"+7+\Nc⹺sutg:\~5إ$6`Mh RtI]:ك@|f aYyT(.)q@2b3>!)IPDZ NHY9ѫZYa(`,ϟL,^Ȗ^&H>vH:I_݌?W~^.wBԨ$dzMYL3,~ܜ h&}H0`ВBHD#vO/Eu`T.He̐ J8b1 UQ=7hb55*eT(  aG<c}+韑ppfLnKO >8h3<|]"Pc>2ev@_zM:%V4xۏ{NȘ>M']눭y=_"§e<8q9|THtܫw#0wsu/Ik+ZpJt+.y"٫ǭQg3sa6fi)_W^\H+8CXC+ZxyKN(bWXV>H5"TB-ww* (~8.Ev>4>ل1KfGq>lm#fFH_|#SAzWciqaqH,D56DH ԉz# Ə0WP 8쀾߀# Gg3b(-%/[N[|]D}[I=ux ^. 2j 1_Q )0c ,I1 TDWAYE(\]z,e9{–51cT{gP#zVqO6E B *57RAɥ|ɚaj #6LZc/Sgif${u CnalvTB'<Y*Gbd+_1mLweO"P^|:I(몴XbggE_1$t9 =F.7FUv+Pnj Ds |u)tQ/T@0/zb7{cOHJa8ҒO,j栲L\QϠN`twQCh*Q0؂bM"Qc]lQ4~S1?hXY1 vQi(h@rW@@Pʌ7͛ߖv.$O*᪁b# LɼIEv.e E$6tr. [edS4kf*iV5rct_uXZg("1r4{<fNh4_9E[![Q"n8B9%Jm&*7]rPKNq[̀kt{qPx" eyf0(چTn|V‡AjٷaC?YXç$'=շu6/(<,KB,T2:`$/6;=~/-ϵ,o6o-=kں( x~iSM4]{,bGW8M.b9frDy/ޫIC5ShƔ?u8)R щ9T'yexV[Q_̾2ߔwo~m,&-#ۻKVu~ hcs9пkmNb 7ӯOFNp-UHUɚTrb/3S?jo&0_09yѓk(_jZ/Ќ߲k5fzK/#gm \5x&^TB{ 88`',0J^;%m'OXg2@@ykɰ&dzY[z(!ROY` $%euvNdB5^VPP^7Obߛ1#% ^V]:gק, W>x戠Vk,|,Z:ߊ_0[S?~¤j]ch/-<u3+w%̪zO1Dx:ܣ.aiwy%/iz)D H.{k Og//T/T!H~ ^5ݹ|B2pӕ쟟<ɴj֬A4`_taDˀi[d$}/d3(VN^bE#+:1- 2oLRY?bz~k/#uJ>3Te(_ScЇ\|sޯgoRaNi;\cs.ƿ[ `!PZ/*wJG`k/-16F|c?:A˨@-6`0 A0@:\zbܸ)p;U!ȲPh)$L$He?j@|mbt6ow/5/*3,!|m9lVU'խeee8AU :06jt0NY3cz:;)Pr%ޘd M\sjɗP _.]DC(aBxP^Y.br !60Jq(c)sH\OyU[e*wO6 %{@4n/*wJIQtI{ݧq[ ]RCGӵ+M#u ڄϳ/nݪDןk3χO*VݽLBi[$Uif`+O},ΚVT܆ =?]0l,V!h6wΔ1̤tO˸Lf Pث)]*&.CW[49I*lm'~ܥH$췛c|k-N_mԮG/1I|8b @օQCz[/bc(䗅RbC-&:Oӓ'P~r`wyg{:ef!^0 *)_r$^stاeo1jh_gQOS_X^Zy}c?xkcc C\|iY0Qp~a( Z"KCkJn>'G%PzHV.;G}pHUL>L4!8>):Mڀ]넽Uثd)%Nxa3j;ܣ-~eCH"aPx#v$B%Bff82s&ygGKvi%prS]&a0^;%%J ~Z_ T߈L`7k\MggHHK&UU=Ab\KzB~ ,Ve0xԪ2f /*MvJN^Lgqt.\;՟a+_8f|ޓ|\*|RG?!b%^fઘ)!O=Oī2=^dMSeknVî|D9;ܡ<^QJڭ. VR>%*`)(]aUM._s+.5W?^T7 UCҋۦ@z ?/1'(<ܜ{l"wx2WvUV}߫ˇ~~fԌx_}mwU@rmZn}{N]H:q5: ޽ yrlwAԢ/GM9" ^شu675rgJa}^Jy!K6&l0d%+%d/8lAn$[ai.H.P u=Cc'(d{5^._v/ς$u=׊&-؂!5+?sSsٲ=_ʭG$˷oޱcGp- |*Dydqߎox5 $NpRWCjhZv%\Al5XI/Lث< >Vzt:)BFt@W/uFDmWUͬT*>_Pg>]yO25^yx!}rO{6uBYwok]NR~Ukв{:!s/T){g´uQ] [->.X5,רɆxW :2TƯ@BGbo,k`GEqIHHxQ6mSpYض眯 W?Wy@ȥߎ+so ˡ7 juqKOM`׶@kO]-%Lo#?m`)޽GOsl1nq_~<>]]u4*[JR\\Mҙ#@gJ~R^(EsNNԩCHvuޑGy3&q}D}k'K;Lj6`ش>oLwww}aJI3Nd=X-gL=Lʦ˖t֍m+}:ign^;=0xgszVѿ.\)z| ޿R֭J-NKx::a4Y_"Wg^>*NPBTRpa, @]Lx&(`|{Ѿס {ԘƊJ֣|CK}5 % mTRA{ϵ0o^ ߸7H8Un*`0^;%a/-4hPOmJ-.b8ާ70a2((Oţ Tep*2"P .Pޝ>sF HRخy`i !Ϝ×^ц6^D@TjCy,_ۻVA%N(ÑQL`SY *7T dzyT>lл~4xp~g}N[XFעKԊ,pƆ[hM*T$4{zT-Qo؂]KZXXwPV[[ΎO71kN5=w&$!{3ѭGϢ5-H RA(g1JK,%0 x#RBd=S77Gx;FzVJ-#ݪ蝎Mj7W]bJ5RxA۰[AyR4cWOݴ=^Ly"f١֨)}N>4yM‰b/{~iNUBѵz xlj KKz܅5j 0-횁DV>_~ϗZvpGW'ϻ/jdׂ ;X&is[7cSQTilx{VxzZrS):w[G eA^ؤ_A!mY7,X@]xp!n{n}>س04jV?UB8Qn*RtYniV ..$CDwŊJom!O7XYD\Rz3Yȓߵo'AlQ ?n9Ң+KvF?AgBl&7UFǭ|oFY^O/ܫHN3[P3MPlh*Gm?.Gdm}l;W5 Mw7"%w=<j>;$e3ɇC}f~ϵ E*W4 <ٳr#t)Rd7sݰ_(u}9^/\<1Zv~ϭQO3`8 YS$.MEJ;0^:dvo9)^OS>03F-{[1oݼk]pRuu㩦ٹ8< HݫۉM$cCy|D< !715<|&Nq¥KN}s`}K,'Cn+r / i2lAT[W'4ىCa)Wg*U?G*"M-A-,;Cq-Ȉqrg/mJ\䖘i[ XvHrz/rQH`ϼrW7K`j5X0Z뗃:9MY8pEM04gDxv-I_K¨ԴU/2RlkXXYy.(+Mz3jBȶ= RyQɃ j`ixl@/$;-_8%2*=bBOMM @ſy~NA&9|pKXI_MyL&.~ 9L#a.ڬ$xeۈ,_ALt+^l v$ĽSahъO010vJϱQCN;̸%K6˲<5.af?S:K[4k63i#[7lBӆam#MY'+ho?[wYxrwy %:q_/{PL"@H2?96 vq pŷS_.OJτ F}ڦ Q+b]؈c6Ml-)"\E#g_[-._1R4(}^ގ;5}w0eo'O$1.9#y0p#>s5.D>-3)im^O*c~#85hd*ؓ-a ҮPsC^n ]?~ b[h]  a׮'f Z9+sS[ۦ[NA*BQ^pMBP~\GWI-mlB<7a:}5)://OZ|8c34U+>L\ﱸ' 0 9 ݒzv?y$/N=\`4ij-٥_>Vʁ7UmBnc'FxZn枋a2!lqW>?xj`llm90~t>qAf[{.M ԗ(n|svnn`^9j@DS΂ )@}&5YQ8L|7Ѽn+.v:nI:̄}^ oV fghB/ChRSgfT7}IIEC6j@SJksc@6HcR ]yNm_CT9Ò4{;9}4^\?~h~ oKUICchi~>Vh4 2+++333##ÇϜ9j_z}W;(NVId{S{`L&w5>|\;du to'B+eV'/?xeDDURY!4.67O;#iɓ 4> # F֨YjcT7 W\Gp5N}AOKVgobӨs2RN*&DlTS1I k)jK4p 2v/(0X.Ev"arͱ,H•),`d/y6ItV L3HL0D(]Ț^?{M~ ψȳ4fg#+ t903 YnE 83T 튧Oi?`"1kס!h rk }QCg~ i=4ov |Y%_#oV=]\(I<ǠM58yo|-C0+IvMTKm0Mec#K齸kF0 PmDpeXҠ"RM_t9d8_?zgZy:4bCe:a< !/1}Β0mV d@"L-nNwa6D5;<ǁFuQ .%\G.\|oV=5wE}3\wYQ!5=`}]4G/!z߂w4|60XM IC?N# R V߼`p'PnMFN= VڣCGoIx*E/:mz=ssݲc(vWO)BD1 qmsC@5wA"3 ;t{BnR,:lp v`n3.|FQz!RU 3'DT^5.CM])/W:+["ZE)o)8%]! !n{AqFU,z:{v47~U)ٱD$vt4/5cѼZBth[`Hq{cw({\bN~iMuC;L􊿕-ݹ\)Hl^^ ثFYFC L@\jaGmO>ŽW޴돡~aEv7Q6-F<]^Wƣn\&ȃ4 w"D!JRXAk#~k?֠UCP;.AGtmC d/;ZF5E2V_3މNCP):{zn O@v' d3Ccf&$jjpA.qDڴ`MmEЁeO&Yj@R#GvXNC"`urb'Ϸ᭕Og/p=1ˤܠ`rLF[mҙh+!XaTkaZ!)wTԯ5:՚QhE;M*)Bk` aԻкZܮBH BX& ;\̻B-(#woqs6j6"v+;ЂZd> >mZށ6.= ,&8/f6FM@bh3Z˻M52 P[.'H_D& =6p_(HX3 TMsx0 -2ݮ 7,0jEh٢cwf*N~,8x4Lk.)71Tj8IT1$d_Ai۷'ϡdSj3C =$g8(& . %g ӂ;-&,4(FEbEsy`Ct ]ɉ!ʵa4 \;qgSȞV2UxP('jCd.ZL)|'4x,QT4sӑ\qE4"P %kɉW7}n s*qGXLnlSR/Lފ|if[bWoyCX \M|\7L_O}{ %/C,' ˄]>^""W.hȍ:m5"1r4wr]䠑A}Sɝ_іG.п{6۬YϣD,? EzL$]`<٣xA_挜]jմC\YнsʾZ 8zQ^;>fD 9ïe!/&m_ <}`.`?+kk ڳ|#jm @CNnN S5pcW2/m3T]{WS z}2/*j Ή5ȅ-e{OA}!98<ɫ%Z7^ @^.ԭN)M75~Q~sߊ F3-~SgRf. _s޹}>o%Bڰ2icno& ׃2 jn&Օa"++;;_VWJ\-2"ZSJKGImV,OOhM]7CdB5x|eh a|Y|]|ڨk]ȻX_C&.i6í*&PmC}5k?=Zeҵz9-ǔO?)QPX{uS7ү܊ui~lx8޶ؽ]#%z{HD<XLYXYW ?uIkc,[@sg? ȿ{-M7N:{:0c<_Hۇq|&!mڥQ%2' U^9b@dLIWU9k(aO:i Mډ IoA1W V!l^;F٧ӍWE$TfRɯq$#醪Y9";j;OҹBu;=BBZ3'aj"J̅שPvK}-g6ˀ -!?\բG#ɾSقP]w%5zQݣ!/g@P锴 "<8K֪`[N%+bP {1^C*f (H|Jf|ļ^I'խ0@(3C!PÖ=*F"ܿ{200@EHp߻Ƃ8N#"0mvZfW3Mi\ {olCR4%aD gͼ} ?`{O6me {5 n^C!F+rZoJƫP–^)U'tC!(OX>: 3?"Įd!p<՜Յ!`0.`5#s&2r#,MRvlQuq*^3 kI+_ણgi3A'kPtߖA$C >ߕ^BdTX(T_á SYLO~g.3%ZV;^Y}!5@?B 3BjٷaW\xJ2%ug~gam 0sRu~ ] 7N*>" 27 [j~MiF E5٠ak52PyhC$Bu}VN9x&zP˱?lfFG/nՠ|+V|\dT.VHu$rN,9 }i;o܇K¾gfk VFNr7!*l뀹{;jĜ 3?ⷛ,T0sAOK6  y$S(LPqNV~ʼ/x(?YYY6%%%99jU ObĊSϛ[Gϧļ28= ;kAm%NQAvKDKR"Et [!{ߧ[Cv0##o#4YA ,Z!]. 67OjZ>-M3PsY%RfK7LQv\Ap\Yp}U\qpA5hb0 A.݁I6j$61sg9J0amBfvϳ ] KPq_k/[v߷ouNjm0$@wȑM#G/Rڣ{l[%Qc1#pn9G IDATzVY[Әq-,\2Ǟ~ݙox_bAEu>,w/87M"z#qu?FAhjfv7:w؃ lL2ħAdVu0a-0*$'DV6l|Ѕ/9v,!=1" AP&뽄ቊaA.S!{HWorX0~+,<WUc\E+ثL<|t߳+~0OlO<;?{Ղ \K`f_F~طu{FF|XG :+}(K{Ԃx@25gk1]3Wwq}ݸ=$Ͷ2htIyhh7OUOB09}sY0]ǧϵ0pgg+}mLgDvE&I,8g(a/ vU - ;R)b"*rY3 @B*da5e1Xuf+%*aebA?`X"YޘaGޚ!PX-_x*,d ׋A߅HP#CM`wY`,'.%-"F+!PP"#( G]4.H4)ܼ̄Ezh +Y8+!(s&('>H2V f)U;%,B$ Q@`.YQYA @"@_I*"uaQڂ-F ]lȬWa,eQMZCxKRq`MgTRM_?W&K`%C@&f=7Lत$@J0oaq(>B̞ Hp^YǟH=`!ܿ! bG~yHBT%($ A OTA.^TAh @5]]aaNQF݈J!a> X!P-D[ƉVuo"cw8?V0bb EKVC(7c P KGQ K̈T1e/Ez)0AEdD̥/wMҤ"W#P.#9pZ,(se1+!& b~tv U [!IӅ125af!:|",#,-LKHZ¸Ў N:\dBYkEk(}L+ =ư -?[!14 ;8+$Kb Vf!ĤeX$Ќ ~(x$< bQ0@ ثtpdVoG6[K)lW_YC0*.bL!P.*K;\0*>f,G ثL`eF A_tяY!2/̷r=6f Aj Y>G$as{:2D3 Y,Qf!PPXPF&gO{q99kXW+uHSE}aOsVg>^ r[U618{qH#Kn&Z:P_UkՄ)/E|h1(]@EWHԲo?î5R k~?Ңǿ kw,n"T;{' kkkq}va-E=\^~~!g/ XzqWįŇ36q˲=-^u*[/VC`J%3J5}V,6oٞ}$n{fvp,`e^/wѫu%C` W[~׃gN9%|VsqwVcSBVxv^0Z)ulȦrR2* Tր*MZ7>7⊍$\dgF(bmq{rޮ->qb-.Q;6v}8lWlEhM܁1q[gr;Xu{Ҝ#V:`HqcxGUtkB#(W.RuY/4ᓄK߁@SI.5곥ov ywF"(GDwQ'oMEK8J] Q7ȩߊ44㜌"7 ثun^=}%7G 2[+.H:NyQ42:G))'vyIF lR! d)m/d@@aj9=ozύYݧ#Tkr5R_q!2L8$N fgc)FXLO^{If1aB2B ̬\UU!`2 + s,5RisMԄ"5 ' v퇏/YTzfb$; ]58Ǐ OQ2c&gmny;zѓ T^_W>8(Hئ<#sif9n {U}rʸ,f$S0yFD"a?{C@yU9qZ]N^;y Þt?w)$s۸gpNX:-LׅXY㊸Uӟ!l{n0 gf!`^|[, ˇ<8gxLEC /W{A9r}8r+BrHS+Ac 2 c?2{V.}Y54{ZZD*Kc0^@VMqq Sdi C P9*K_`0 7@K0`ԀL6:FjaqgPN2WZ[BzA |!`q^j]QUT|G=:2Т[5~/o_?ɴi[0LS!`08Fb-ٻt[_kA-H41* ڂe6|ΫYH .8Br`42=hŮH}y pyKv h$l]MML$rB}A"/zom bW8X۽i(ju|-|]΍K5J<E d+`0FRM a}BÊEfV<:C6.^I/yG C'h4'&gD?+/){IͲynҗF bڀG֧ U2Af X%މMsAq;4lӴ&R$ =O5P}6 vrBbd#57E3}g09[è`4>ehB(t;g e|8i+Rg-VHCco Q3g'+7"?6um`{;G2~iҝA' V=4ov |T*^o]|˥Dq}xlBXb#HTIІ.q,CF `0ocC RAJ~llWoEcB]d׺.a½71_p_j3HvҀb@`.Yׁ"ԁfrH:={R5ki8A^yQH`[o~0dq̦at]E @FjS–őik}xk{!?FD#{`9Fm5oKԵ[>NCxq<@y)L[+.kJؓ4Cx4My h&bsD #YT}<"| ,'`k] EgqDԠdt#IR@^'NY%Ek9/2222R)G4g*YD)1^/N5rGanl~WPs"%x*%} Q=&ϥCPj6. :4'k':tp"sQ _, +p7D?[4%(!L2 ,j-k ϨP.VV/+"D~c]pSgc:.lCvh]bV?;bĈqqrmRV Kq\׋yKf0?iz]]Y:}3>Mޓλ0)b9J0wq?Oy+]KjqI(/p^ kEkZx%- \^BF_痴^@+tۺש. =sY(hk]Gg|>?O2k#$C!@0*szޚk)Snܨ. Bv)n(\YHQ%n%kI=soV|9ofoC㡣Ւ B UPM5 'VnEXO)n 2~=ndYH[xN%>Y '\8fI%cawC!N`ګ.T( ZZ (`&萢I1GwˏdZsα|=}Aх&l>G|0sk%[Fi$!< ;}ߗNo; g+^CGmg۫˄Yۏ}ż ?$cK e0MwzLPW)}w~Sl lDG Nt󐾛y?]-L4aMGm(3mʎB/聩=Wv-'Ɉgy38:dZȯ bYш{P ‘c0R;|ެrLG{x>Ŀܻ7+#ۚk `a #W`5B,U֭ۛpfө=7K$7-<h؅ Ȁ:ޏ ɗԔr՝68ENu06Vޒ^VS8"@\c9ش @C>P / 㢩qrd sj$ӧaVĹ޽lPA9{+ 8RjJүp0ٙ^+F{^!YTQE8=E.4F)ņ@4R@N`0*^{:ڝYpgIǷ?[&[.+`08fm)sq 'KY0ch;fJJ^LbӹMܳ;}bڋ} {zǧS65W@l)#7񁖮 ?>F̢#HBx#j+ջae0 m9|S>TK1.k[cM8ıp:egibG$Mc0 R`ѻ<ހ=Uܘۣ `\U==| =n!C!`0)a6Y;7L V2`0 ;23uδV-u^N 4$e* g0 jjuF(O0VV+0C@@YtJa^!`0C@M{)˗+++ (W)ra ! ?$DG7 #GnGҀA(|UƍqcMԴFSͲlss72JAT+xxm'^Aٸo8mKv5G(M^"{, 4ä潂$hkmۇcΜa[/iZǠ/>qPc齽T g֘.WkQ(eÚ~i֦yjx,fӎ[hNk./fU tvFZzmXķz=W 4kRQ4Ɠ|bо޿/#1NA+dFG\}hz|6Ħ6;sAVۿ J%EƐ|rͬ<[+ _ Ku=v:h5- ,?d/qt8ﻩF/{~hu={]𙳱MK$Uw ZJ IDAT5D"\ g'J2#C7Ɵ㽞:wY:|h+"gGV~KZ'I!"eNꅹ#EmZ tdI̔pFRWipcg$]8<:xPyw*W(uX:}||_T: %zΚ}|vx!4&"/KWr%@ѩ ϣH -P Z-^{tnZ02C\`Sn =Ndϟ!mx"^^6[Ç) n7>C_K:]KXw ;o @{A9r8(`;;G^^byoZ,9y,x6LĂ#jXul3hFȤUP(*1J @-^QŴW Mu=rmo^Pu~X ׆|"]%]FAa@4-ǕgƬ;xNDӿo^޿㲽x6$GbOD}`ՁJ4'@s)1(9wF'TyA N9j:],{4ZGj) y+$`Pjᬶ$gLqW#s8Bvhyׯ$MҖNZsa)Mҏwt%['͝>p3+^lo^H&uUJo #U`Ta8&@bV&/,xвeaGQ%޾Vy Vn%ڲ[%>;IA(jF<%Yy(VAD#9/gWDwi_E_ew1SjIqBBֽ3ʿ8n%3$qx^1+u.[he&$D$$ ޺aV}o]թYv,c(x4}_ۦupJa2Bg:3:# 5UtuҎ y5b-!0tiY[9O-le Ϋr4sWGk v|z;:O۷9]FLێ6ַ׏|~?_#Yt1Bǧ7t齍HE} J工 vYyTa PRJ04ƈ^Zqp'<ӬǠ@uYYL^+_vmP]Y>;ez^`Yq9d O锽( }T02|0Q]p#&m3[onfLje .شgL_\ 2!ahBo{^L{i^V/>vՕwq = {z/~芗uzk]с+4bgC<բOWw.[ʲp򃗻/'Ut(61S: @;Kgc AŻ/_+x`e.uo֭[?rO|O.7% 3rysrH$60X.GD,'V#ȷYdPj*GjG3?6\45Nve& LLLl֬ڜC0ظ}7t{NJfEH'bz-ip a;d<> v!H-Kq*5)dovű1@ytIŦX4OeRfUdم c̜|7o[ᵰ`ق+Q(l@/ef"zaM-qD->F:mΤ/ak# Gi ϡCׯO2z `+`umZ`nBt t4{&w]# ?_MqX&#o +1!ޫW tڵI&0?^YUfTBgJv }r|Z4cQ3QT|E'p-JЯ GN=7O%b)2^շps+~__%2{`0^xh!PF_ѩ7R(my?ؼ򌍆́c4t8'j5[(hZ)dy@$# 6o^K_ cUI4eœ'&®=Y^ldn48N/NQȵ -2`F;k-oϺP %Pa^ `^x2 >q.v6EP5k5X"窃hVVW+pC<#D@DcB 4|<ƙp|,_(<ј>U7nƽ  U~s5+v<?>r}m^;jܼE~zU34KB?Q_ WÕW|7݋eGCEzmmm+WT͊&`/^۷oFoxQ@&? B`!Ne 4UzV&9m9;h u=L"NMx.\ppp033O \ipM2G^lB@Tًa|o'\**%V?zY z $m([ՉP矃 TcA4GL{h0C"Pl|QՅFDߵB|?TqcV{Tu@پ0۫6`K!Uw@eUuJW Q+NapլSeۮ[u ڵkS o,ABQO^1bT@eDL: &-?QKiJ(hjaU1ycr(TU}uj5OT:{Ԋ( 'q ?MM^Q.Ƿwmg?֩^*`y|e;3 (FgT)Z@*n*% O&ǠZu(}^ſ[;xe{j`o7mÑssiy+$(RO~da&!"J}MkE9awCs17E'!ڋs} `Kh})B#pUO0KDžo9,Wy~{1hJwP]r^:5]5{T-ij8$ Nlzc'{c''_>gPG6tjb7d n2s?o Sfr%^NP'e>ck{[Z%Rګgvheȟ~Vt}RUs.cYW NqRiOtX EZJ6~KLf#: ЄK7 qD.6~k eh |{ZyAQ_g&g7<ˆXڥGD$Mѣo=7}r P7y*5@q}}bT#`&=ѩIOD?: hcQ~b{)wgpBO^d֘fm=+^|F·fc~Jᮯ HJeo}J9Krw,5 K?e$_!㦜Bz$C 4$ 龲L޷Jiy.@0v<(0olSk'_Hp7(mLMMZLݞ䍮2u?)[Y(U^0,M# ?߆ Kwo֤HqX }w=xzs=P}^SP(k2 ˡOHPW:Ւ}=o:n"^4yۍ\ynFܭ1=|3kȸ\|nRi l'\01xVt'N4WTdP}1[Mޢ:5qG{-Q eO?!qTvK7P^qReܐ ↮fj~!Iʮ8Z\h4nBDſwoBpMS{8E:{hG9w܎E}d^G8؂!֐ęEzPP5k..<6%kPmlcKêGvdIOt̲$wtљY+F -޺OIYң3Y/iO :wCoYa ឱoBNb?kKKqʯ@/mKNJʹzGߝYh?;9=3rJ,&~hܪG~X!sCʃ-AZ읃eXoZ+gO E~l=FISzzV T WLzz5ӝf'0sO\U+)2]V65t r 9Z$g';aZogG[2aFц@+!=3wYiNMyۥRe@B%E5U85>2<4b&e):܏<=uggkˢ0OcaѓHX@@  Qs YcJ$Ωk|Yi]댞<T/L#8IJªB}mM?mXa !؃EQt[!Fu0f?K I(a_ԓH% QEDK?Zfd?0ӑĄzq @*=&<]P€,Qv+lw8o?2ZS͐YCǴݍs˿8nO;x1\C6KҨƊua:MEId4hbfI# KˏMիqϿ;X|Պv<Ou\zv^fAV)?y賺tZ.f%^^C, Afm{]ؠvSnbk"ϾB!ndq(MIj3B A'~l)na(iplx<^=Ҭ.0T5UI4pQ(d9¦Z~hѹ7B&0(l 斸E YQ?z_R<G"o!0T@ׇs$&Xx3oX%*; & o)Wh!LJg+ >.:N/m J@"S)ރ}6k8]ݽ$ m؆ _lD%YYo|ay;b+ZTTb4,I~{Ҫ~g.#eJl;RՕqa-jIħyڭ"T\ zR1+Z+P,LȔQ:` C\R,b#LdުmhrD Mj^U ʙYXk8rLZ \Qca:9޴ۺֻÅ5;Lim[ iLEu.c֋X bYsIOm#G]N#6k9LJr4oҶ a/s{&?T*xGk$V_xD5TG!eŦYdKP:k8xX#kE.ZX^06Gb~<PA 3M3;G~|BH8k =12k рq/OQ󰱐75Cej.T n>H%)*CΙ3gׯO\zz  \yت O5+ΛN? J0JPHC1?^o>`#@.]4idhѩ=98d&QE@|t!`_PP bYi{6Kyps&;SԽ+a &*c5JT FcM*8CWJ\<1C!P(}zcR..8C|RdS-$ѷޕG%{~x 9mq,P:7xD.oYϖgv]мyvڵi܋*Le*KR,9ny|OM*)X>8ryHWxаXq)"Ҹk ;~ˑهp⍙!z~ ͌ɚԲq붎p藪5jos+aYqY~-%n!Fwj3 r<{Fm>qԾװ*217m]Q"c츓FSƂecPR&Ļ(x!T} "q3%'mLVX,|/A/zJ~y9}mIxtqm;dWv*믁KOOk,#ӯ_ un*.6:8TRP39 S~솺aZm7Kl  )j#^kWUg$(˔ӛR<|$)^P͍! l#auGWyX¦?"M◛?3 }z\x!BglP/:2#P8 NdKJQh0y+"ٳ9Dkq 3b+a2p䅇 hj~50΅377oܸNR#69EvJKdu w mشˆPkf$j\p8~7!;N~xz?}^%^E{gį'Y&&}XEl'ɆoIoȸ) 0}wӒqܦ0g``j_~Ȓp08*~*@/gN446ĹrFO9KrwOU7,I B>vP#@{0} X\݃U^?X|;WH_nFr ts^_XimAmN,"9mcN=m192X:wތIIlVFBEENwE er,TPD -p:W>bD{i(s,YJ{ C1p hpi >!Ogf?aoC(f{trV֞vby|a6= Z!͸Sh˧Txh^{d%G; 9 b=_r9bO]F/r]t2󻏾MI<.AE:oHIGE3hǽcE_!W[Jb &eփ%=xpWPB_oT"җk8-7UIBpM c5e[ >i/NN~o^>Izћ'on]u ^-:J'MtR4u5"SZm-) V7*)Qr'۶-t۶g8p dy&%݅"h^31^FM#[:w?nی\/=PH&"iAntP'pAѮؘ7'H/Dqbeo&_i݂kl~~8KO7m*HZ7F>{4j%;M La² CR,ڠhQ9̀|A!zov_B2΃D-kf=&%jM@tBֽsSHyF~8U|T P(;8k:3:#B8˓s?~{إ=G#\D/6`P$k-?\x"!aC~@jG-5ҍKKVX,>/<[';@D'6h':21qcdٔ 0@]OduJ5'Y3gK {a|BMP dOz" 4Xà?T۫`P,/x2b38 f#ҥa$egWw{#$wqY`Ae]*p\} \'I땙)ο\<'" ,˗Nm'Ovg=:Ѱ~<cwA,%5ہkk+Pr¯//EHTIT%3u"|d;R*Lׯ.{(/fNc,k vYzb\V){4~ |\uwh .,qHE>M3 @ICf?x4w?@3P61¶y7!a+Rdj!gm>jݴT-,lѕG)3-ǽ&; CGW Jo · 6е]SG9i`KYZN#Q-BbAnG A[RD%KM0{ծ;5gk \7h9eCFC! ]Ok߻I;  2(n3ʿca8C͇`}A+"tfp%Pxe@q4;ϣ=&AL wrfuö]:?Z™M[KMvhgVΑ]V3WŇD 2[}M:'h\x>ywĭ&-'Ì!-pʱpaH?Q \Ŏ)-K^s7_YfG@B `nf_|ޛNk`9؈ a$FNKYb$۴G%{Ӥk?TrN|M=e;` s0 5w\k{c/nIo2la!7-O+Gёg(hJdODfFk" aINʣQI">X",Ƶ3LCDMn3E,~{swO0YꭝխM]>rށ1]t)H>r y Pah"ǧЍ}Ϩ4o'HLV5ddJr k xB SRz@*xT`Ï>>3y*x{ 1 sDh>1S )jծI-|y!74ԃI|Y>Sc{diF<׿|*,%/WW{t=p ad KV^,N3p`4eI%" jgP*!' ÔJHR 7;K͉HR(qW- dd #2ۋC/`t9=7#]AoڽvbҥCܓ'W꾌 :\%8`Δ;I)2Q *CUGN*I`#ģZٳh TNZ0E\-PbH\*Pb8ȤU<&."20j`iw|6 W+zR$u">sO@R QE tPuAbyA >hTTu%L)\`RAa|<5C\㙻|gnyܒkv;w /aYcJ`0Tv3~V˩_3x4g(UN#ǩе Qa~*% 4.L#G`G(j 7 59MqE_Jmb*0ķf{\q?aӨ_ԧQȠO˨o?~A!jGk+̺PXD|^bkռ`UאNH!/W7hgڵ )X}M@UU VTʄJ% ķk6G)8wnݺ&$t"XV6(CQ`\YT\M,}܋RI<က=[e!PRqVV@ǸZ_u>(U6z3)82d͚5Sw8{,j[^󊺳Z},8n ϊOYΪSEޓ<~%ItT(J<G>ݫ?HƽZe3;E.|i< "W_&[JxuQ0pyRznT9YsnyR^(,oz,,˟; H$E%#g+#!j&kHWw^ G.[2n[ôf/a9 <&a}><> -9~_J v%*6<;+$K!P/ɨ6GQTV1YYY&"O|D2E]\Mvwj) X\jŜIKpi#49fX*>S#rSb'DPޑVw - E͝7BpԼA~ f"G?"rGEs_2w3z%H4jh7mr842M])d d:G{q(TaEEXQզ(ĥDR5F~W\;_0yeĦ^5j N::nIgJQoz$XH'k77'V8j֮'Cutt֝ĭmNm `ckv(ivLd^^"eTS(;kW]ukHk4C&ϓ.]f&bZ&ޮ̫I'I瓒R3A}kD 5]ibe銹m~F\[fʈ}1j{@rr8GpJ5Zj%v.kM/3= ?s(.ܲ~_++`>@y `Qbuʆ. HOR#݅H)O6Tx98-~b]L u,D$KjfŒ܂+/ yߟLL8xʟ=_;ҦǙY<|zDiyܿŤgS@fAAt{}m4W:pg:a&8y DQttD3L*ƍ='8a|H~ˢDRATXZ WZoHU8}0*WQsL@=mɢuZ s$ifȱ) u at%z %a-$Ԓ{pô],̜Ǔ~"DbڪS/'G6XC)rkrZc_~l$WE`jʾrH@r HoXx5,<6ހ 4-=a~D&hN #<Z4Jc\qgn)CV> %DA_YQ 8]b+*(,t_ɳ2JejNSW p) RlXb_ߘӶZ,[50Ts=)s 7%~x|cis0z իw1GК2%\z'm[gv!MI_~N\P nTZ::#~a롛ۜnFu_A{Α"m"AGWoB8W.1UwꇈJS m{v(PАm+fVv]q1.Do#@Eȣ'9w1ת娘(X27t>#r) Mpo0;O:~Vyxd.2בVZR/Ĉ5IƄ.I۷p.Cy~_3vJ6'W 2 d4 8-qkQ9N)hL.}g>fɥfB%KDS"W^9tv Owk{mP_z@4`&ƺEفA+{_ooU!1]5! Ϻ?K;G$Ć.ן-Eu'C^_Pwx^xw7F\1T9D-b#qVitbQc4Bgb\`iRۋvEv8D:Em/Qqe]&^9&N{T&Ϲ 7gI(ͩjF%xdd *2ѳ4\&Vj2KdX-XRǽ&E$bQ.!/?bX!KGh fyzF4 [A?Z"W*Pn9I|^n؏Kƶ-ճ͇ =$ۂI}E![lٗl]y hO{u4E #1@l(la+Ki0Lc"uPHpQiEq6۲ek.]0Ј\8r"8-8r՜vr*%\Z Hܢ JΦ UII/HJauf-I b& u*]دYnyz-c`eE&hSolU8ޣ9SK垒zujUSL,ۂiMNN> t^mE$Fp*NtTvQ8VbzS/0'LΞ@@iGSm i YF .kQ6ʕY W1WDIjx,Ɍ+ԔE~2گ]ܻͧ(R G$4y%TԀ;oIZ5}kfξ5s~M/pdSU {.*"+J/XN;`@={VrWr [٫<9c{am?R ,6h[$wĹ qigA[J Xmi)FBo!t%X]dޮ5(Yv0w82)ɓ=y)UiҦgcs+"7@`պus." VE`[yQl'6%+zrcЉo qׅK$7q}rŘ&zy)'O:z849y0sro?wZ<k"8jeT/ mjy؜0JdĞ(t{?F~L!ްao~9-aCΝݽ R?l\_)ݪw`<*-pL. ?կ86cr؝!x|;w'jUJIlS$ك?U"/@]2:+g<.{ g^ЃşfJp{]jCӮ1V.x:FO[۠tVˮNˀî2 ٮިƴIBh/S?V3c/ZԐ#j׮-PTXQA(ƊSi.ovX9rz>PFv(K9x+ wtگr/YI&7ݺu{J,'_34de#vR8E> r.DB2korDͮ鶦߅z"K}832$20R*7 |#Gȋ~lB?0Kl,a灪Qf(,K$\ r- H ` rً 9s NF`W$T iPJ,Hr 3 D]EofW|,:G̼Sݪs@ҡ|2MM%٢A܁EX”^@e5jTp$G!ڧxFx_]Hwm=+2ɮrd?NgX`Ur_7U˗ݏ{.ufBe|S ODא|6]EYxL.w/Ą )x!_90=80eޔ3֭ojlm +;֨]Jb1ʅhJPO^ߎ坿vm̳Yl¹kPìͻM0,*,WfLM_2hFbQ <"~bpZJmEc+ "1xM4Q]J91e< sa}x<^_qm/t;OD6b"+ԵkyQٵDZ㲶@z(I׀ddTBr$X JQi$OdxK飙$#lDgT)˹ Um>'Ӻ5m+&QAhӴχڶ-VV-#jc xA;͍lc!ps @UE!{l/#֕pphljaE脃ՆL<d'h2JG@Wq7ڬܝ{&-2U*cCMJŃ $bt`L:"[  heC9z6;9"YfB%qK䑄?('CGy]ϘcQĝi#Z7Z9/kǁ)®F3 *]DyAƄU5REaFGy@Wx _Uc̡M,9K&jO~ӡqEL?~M{nۖ؝! YINՠBWz+dG跏M R)}.OV]ڟsB?Ѐ{QyX&8 I$x! “r@gϞ-}YNmz*+{g]XEUA&5|f\T,-󍙊&)_>YTDCpم]̽}塠wĽ3gΜ99sfΝFx?GAā]Ӛ0q@{1rdooӗn"B`w(`5i  802i9>>>CaQ0#-#0(KHY\r8bt3 icR0V˞l{h9E;^#?9Д|dfSO\޸Yƨ[y^々c~X@JKK8fA@=|,z@8m@𮵮c?gARb- p.`nMf@w'?SOC{ - DR)xݻ,Ex>Ȱի@jz ꁉu QrEޚXҗ/K *Փ jŖ_~ZӽT| %II_>~gQRbO"WM>Q\TCo&>l!kO8p9 Gfq8{#>ajЄiK^\Ҡr;#k(AEqѡ7~ _)m׾=TJX߾}GPuܲf+B9`yAz5 Ik+a<C|@1u{x9)Ln HZ[>_^0,LီZ53qPb:- Qô&~Gi /M }tK`:mZ#haM=ϯ-MI~B9="=JN5IחF>|ޢN.7KY` I <~6evM2-Qq->ƤeV Gc}}g/MH )U`\ӓ5X ^ĥ%%%o.,,Ͽvq1~hέc9)Ҝ?+& cc t,scch|iH( IehҔk F8$`f**r}'/-eQSL]/Q1ܤJHMNw 8(ȕ2)-R"{BUrJިVE31%ϨW EyFPБ켔uEy c (寂LTLb7JӢ E3BCg̘A:?V`$ԾIlUk5KG}gKX\T@Mnjc"h[ѥt|˲G}oD$#\uaN {P1:&!o" eOV ဳ+g\[j*|{Z8_0 0{5ɲXHd{fDNφY?v,Y R X-{1+w$!Šnd]p|㒔{y QH=dH'6B V Mv1 RO-d^S|=뻭&4΋=ZQIǥG :zn)0:*/rd@85۠ "_=3[&ݍu(t8 A34:(+=Ȁ%dˉ%P@@,`"[ڽ5Zm/^^.so26rI`p-Q@Īʊ5: ԩI, i:ڀA=tkʺ.Lxo8PpLra*UDZ#DIz՚q SBU;8J[tR̽En}&B$r;%d/hc,. <=ץlLwñMjgz1Ǹ=Ub-x% MV&V4[=;S E oy^ݨmbZw3&mZP"Xx]އe{Ҵ8"Ap>\0!.#&HPiF 0ѫC -ejZ$sj6Nh;)V]H+qyKкLkK!u{<~mTv]ڦ&C!}gZ0 B7ѽ&5 #ㅪ8@@d:0m6qM"dѐ(b{Izq5=Hٛ+Ҍ+.w18'0zPJX%p9 I2jBh6m%7߼yDKU0[r nCYN‘BwL6X]<~nM(L?D?0w77OVčZrΎbW]7S??Dzlr!~7pM(s=0vQM^F$UΊ=xznUiMDsn| 2b~J`r~Ó~dOT䣕I9W]e-vƹB1q`97nSJՂX!D̿Ļ>UlLuтٟ6ѶO=?xG̀2w4Y¬34[ >%NLP8InʤĿKf vfЦ"'7I!2suzYw1KQ`d$)g:ȏM<ݱ粒oǒB>g9IIK}xwxxxe^i^'};F4p6ں+g/*9wȥKʾ$-io)}ڷ*'"C}E`QF\ᷩp -Mg U* ΆTW:v,TX_P&qQ5/v0}{D@N^1.ū^aBVo~4F?a„=u8_L8|xg̼tʖ?!U) YuƄĞH&V|bO{5M^) ߯p<@oPSiHrZ[/% ܡIr7 ;mV$ãGCFޕi"Ic;Wt5rh񤻔T ˍ0>PsכE.:v6dj' 3L;g"30iP 26=۔+Wm0~]Xp8P_X:3mS]6?90/ [v O _ Ӟa89k(Ÿ33<~zPTo߲eKR9 ^/=2x._t<_rO҈8 pQ!pA_< .8ӎsFRuh$U xpLJNX~5LǮ+H1mWؾyxK=xǼ\Dc\"ryW#JJXo%f}}}mߨ%|v+gNƊQ^H0iXtnbxH ny2>6cТ`>|&R uLVԔo"/ΘG* o8g֢S<4;=0dN~;h8Xv<`$3/'gţ$tA7'o֦y[ .Ɍ Ś(:lΆ4ܥTRW1 x ]N*,$6S5m,5-?''B ب}$?_P C|A{û ȗx]th sss̾gReքC:c) [IRjbs-^#/hoq"y<")^L})H2Mx]kGhsG=+_X)onȥK٫Yls)lyY-={1ga;N8w,v 'wGh'xO"wGl:{1Y ؟ף27Gn ! ?o[/%⽨^?&^ͽ|ԎT R zLr3cdxujy~󗯞%dd<ۯ>PAX)iJEܸ=?>5Š68W ݙ\d.ܼhtǜj4k„ӦMmFxe6O&zb⣄H=i׊#=E-.'11]T#/˿3]k2l i4ΛM!?˽3)5=4:'',RB#%" 5zh>eE+AYI'A:i4y%~LcԞa1 &Sa:7_Hr%PLzjxG,T}\oe=}!OhOa,` P0De A Q0d/. a(yxibF UeWDЦ }6@0lbg6%ieSnߡ*dޘEv썊mx ]:#<+v_:td8 q4#xh+M`ucTyVz Y.v]hdž/n\;õY]`w_s)( | <{:G730͹5"ѐ4\UbM,3@aE@tqJ8QU n>(N[n`'53fqWk &ne֘Įܕ'\^LN ~TIS^Z^#{ p)Qð:)s,kIg_үJNGyٌ8b\VHxqY:vs7+' ),J .O8`^JNN~PN)Oz-N[`?Ӡ9Szɽ,ougyw_*|e[W ޹ o|41N_j |Rf%,"lgn>@ XӕtXܪT=yxrt+ 9[St0f,HK~Ob"P4dθ~bspWD8Y'sSA-W*vdIU_Pԅ+?@6,W eWQZUj:毢Lo(+חïL_W3g(sz?)'R"e˝`ϒwCy&ٖ,F"C(>7Ҩ? \AdX$_$'u m^E4f{QۏaHgؓ JR/n }~=ex ȎPO?ytGFզ^AgWO&[~Mie|XOuG?A__\'M=XOZ)Mqpҗ=}+-0 '|+7Shdw_. xI ; _< I熆U9rJ-!*َi_J۟%RoaE AVHҜDc0hR?M,~?u/p,Kn{G'c8( |߇Ť@^4z;m>^\v$HRETW/\el*PTxOsXM\~I%G5@xrz=8!'XKw4:R%d?x^#hc>C 9` Y$%rL] w:b/6uﲽ{uO_ffrK˺Od3cނK RJHسcϫ|{>r餤J푬@h{ЌK(N03o>/^Y a=zT#k=j%1X!9h=*zJ3T2hPX3V Dn;ؘ64yjAQkI ?iwU=4%MFbf_OGP\o~},4hN\B~` ME=':ork`6W堦t}?F][8Y7ݩWPe̬΢<4-M~|Vx85mw:UKqI}U3̔ eOg:Ã$fH{:8$}'jn)Vy;wU_Ki$}vb |krB 1:~$g 7b[6 eR#X` ?P&L?mTAt? 5ՎwG M91 שTQznʾVA%0lvlPMn#sC˲M >tu]!prZrvme[t+* $@nA0] !ԣmĠ<4" M"ZGR9.N#GN"hh xjLNExpƣ{Y@w@hi -L^Dˢ~aզӊC?4<.׺Qv#5F'  \iC5ﺕD>AX3!p>8'fwMInS7m` \DTV$s{3sͰqT MYuV;YR6!C} +D'!C榀H8BDdH4|<趇Ǟ8)\HbUL3&XPj}VPto"wo_'em?kd^\7,qZ$48 +K9r 7NB!EJ̸d E^h8~`/ CЕ3÷GI.{ HXУ9.uZ>磂oZݐ:#0i/`ouq? \ӗ<۹ 9shۗzoˈ zp/$vkMͨ~Ƕ$*ע}HrzqPP*h|2'nqq^GB[(@ eboP(B1+<[l8Ca,j K EUceΏzJ4ZSO"Sr+qgMaV(fAVҘb\5>|*(DtݿΛ8~>,Ntq\,Q=!@ ώg堾13e}P_2aMwEI(IYNJU~Ҷz>C.'11]J҂ٵc#2M^bx Pk_ (f9[L#i2vmy~Rz4YKiM7U{/ߑw4;G;yr=>V,zYVMy l)A IDATN9 H{k= 끶<8aWEP ث,m8CA3?Hjwh ڢ#6C|P\H#%a 6WuWn۸%ع%(N)V!X$Lgx9C{yC]&\MT+"?dFm9.pfnU*;Hg=R^{o*VM-K~\!CBѿsRӘQ!= ?slZBbjHuPyCZ-%q5zU>w˙ %-f裩, NBα-@V -V/@3&K'qʴZ ɵ X_ t`iمLOamfx1qPb@xª@!ͤ=̟}LwJ엲 /JpP 8^a,)͸X֬jXD3;9C1+ܸa&e&R;Ŵ|ȵmԞ3uH{E\J5A]1kȧI%fcI_B,82G~@rzLL^,BNKeXP̐rpwG4usʰtۀ/8FY?CYLx,ZNŃ2'n$DLz N~|cUo!U.}Wn")YmJEB$^}@@3͌.ޭ$B; yY ;6gncj_="8X8xvx'fvnV޹bYڀO2BB"FIwjOe`vRs%cO! W!Օ33sUa #VtrU>a5uE/ \fT{|gq<q%iZV\ dg^[ 234)cnnȰYU RCLAP:! :rd~ذ)wy͙1.46.5̋M) ˎe*܃&XߘP鰑SN$+~ ʷpҳnSvܺ.E^Г29 HW'΅+RsR'IW%*8?T I.|  u-ꑲ)W҅RnN:.4e3ƌK Z.<5T4Ͱ<#s^!wxxٱ7Y z,B"ȩ@ē ?!{z|6gސ;?.-K#4tOq#X呻wBOoC1#WqK\@)"8q˝ gҖ(vaUȠ99f:;2bZ8ÍHHv|6KCx#Қ̮36 >C]ۓ 4k'ۺ>) =ɇ+w{bt{K'B;7o>~1Nʺ[AۃW~߿|?>zq 6_PC "tm5IWoٹwvr:R-6?_c'$6;?SXT/CK$>{ Lm͈e7$] T3{boƨ㗯_=`w~MH-q1Dhu4g5s Nʛ6N.?Yt"HvcG^l ,f5 q_kY e7m[&6 BHQaJPP k/m:,FP@R#C[mDP "Ն%gwYi.HiŬm\.$׃IM%Z @O[0D"aV%3\,|c`u"Tߊ rssu'_%Ű(s6l`Mt6`Օ@Oof4H$*2#j ^x h] *AWffՂjFq/UCX-z|#W vӫzc> )8*Mz`,6+U뉀W D&pkUe`>yۙUAMfd0(#%6"~"y2927 =-I>'IQvb rG)j^&XR(h0УG\M"t D'hLMڂ!tlRe0yCFa>di ʀ$Gsc KLdm&Bus&Aԍ˪e䉐8p9@U.5Q1 %LV-jiӥ;JZ(ډXA:d>RktFt (^ӕaS8KLnS,1:0fFgit]QVzfi%&,^ā_4"r`E^7Ffq֘%HJ/ܞHףE'D{uH??iP}[@LZ𲋣KjmKWݧ Ӧd>0%T5ԱE'+I&vfqyaQ&'v,U, Z̛!q:y,޻j(*,Iܪ7"|l؛jj :Mրnx5EIxj ,T(wğI6:ͦ-\S}BI {_ʇ͍ZFuY7ȭZ-^:|Z5. bQDrgl6oY(p@@=s/#2R%!Zg6 j22\ґ٫غ:q)H/S% XiKu( [D|?~x2+ѳ )"xD[)0T؀?D@B#y>ݡI\Y.Kh0b/Z-2oiMk1qpc:S UJ\ O7C~8l3rp&S Ȁ VC#?,&{5k=` xHm ܼKq1c4&st<00\н#$ R!T˗h#U(pğM[7ksUZ@W4n86s!L+mlڽZx8@- =xGo4WSM%`|1?<\d"-ޥ=I'ٮHy" rZA#5!LrjlCرK_ų7O( sǒK^<9Ig4bVfSQdngI.%7tLXETT dΏRkYTܽO[3[jDoěeq1U KV н|R{ )ԁG:VTl^˝N4јGޮjU:~k}tfT^|L[K)GQ|r!ˇ~zg?LYwWWQBvboɵ&[aLlC_wXN9PB҉n!}fe #.T\6+4tYp&jfs pNx̱}Fg|;u*K+Xaf,gkۂ{֧>O+W;rA _TBg-y 72;N=$=r;%n/ ] Ϭ'CSe[wHou:TTfmJm,{kK[^a ed80BAKWk;y{{-Z8DG *%=ǮпH@ΚWIn[z{0̕JDM{%1P'Tr,|YG 떫FUӛi\L^nLV(GDeC_gx`[ex[2)BNx/_̮3$ *e"QPUh gϻ=XX] E! ?5xKKLKeGu^A-1,n/jPwuCeb^$Mk2bQIܾ\62G, a;Ψev:w=jXՋ9l]]oI均t}I/FfaNIIy\.7Nמ/?H kSx;T^WNŭk@lJ2J8a7nCe %R\sN]'v Wp z鯞*u4f-`x1X/FOTYUژ)soGJ˗ +-3;'O97m,y&<[Q/0e,:rgF8\> =ʼk~ld7w x-~F 1P%t7ېok;mЉ;i7ͯr*BlR{j%(YL*$OR<VlA%ޫX'˩ )Mթ51֤ w O6gTtQiAzY0' Of@tS G0`+BƨÕ;6{f/E k{,tdf;H_.}va3ڗ$9Xb' XU@}q6.?Ҙ˝0oZU'WxiaXPcIʭ%lZ] 7*mC \Qu4K"Cd/ջKD-fNQ U;έMH2h̻CåX9ۿ^lȭȪ͞B+wg㒑#7tr*nM@M)0\)Jl(6\(C>JKQ?ʛwd4;тz 77|Z_Iɍ^y>pbJ. fr|D YD@jۼ|*j`,-.*"H/Є{1KPJl_5o;dV/86xU@-8Tm)Q%E闌z#pR(?i!ͼN: j,ѻ4BeX5T&H/sz O^]@݋t2s%M{Q7ZHTVZ)dؾt{n>9 SW!d97 tJrv"Eta!ܮui+pճ#y :GGu/nVUncþZ!h((p.8/:ʨJ02wLMev/+ʚeX%9tnlD;Y%dW CeNnο-cg-ӯ0k2eɵʿ!liܕf{YAcҤ.#d)]bHجv(GF+ ]hݤsHvp- "R0y[DhhH^ B|bNJHy=-Q@ A]}v<UuSSKMW4C8cmYNxfcH6>miL*jˁ{W$vP/y :CVNz-w/VfftްT Z-e; Ɂ5 N^ZvmY.*9+2+ѓAo١Je+ (na2 rIH%#wJ 1/-ZE(Gt\KFwrlV;puywB=گٛEBrwWi`y'ײG,tjMx5@B1jež|⮊s5x>5b#ik/ČS]-O_AW>neAykB΁EijIw1;X dgjFq/!+Gjq!]H4o?J֫lISL0 ͑b ]b@XoĺaG*q8gjΰp&L0b4Eݨȩ@]-*P6A ȘW?aTv0Ci5$~:Y72Y׳?Sp!nղ i Z\)DIEٜT*e`HZY~4YjZAz񰸾ٹTu,p:=t~F.>UQ"۩{o )l#<iV|C#]z+1.⚷ccɠnϸ/Un rR7 wLB9"G[3ӤR,Vn|r=5ү03VP/10N.IT) ⶧J70v}rEъ8 R4I0xG b:2+(孉eS{9aClz]I)=g=ZIuD߭с}hz>z`Fi53v}-;]nؗZѽ}LW: !uL ˺POO+K}zq%',I}3L OT=o < Jc6y3}&&c_wF#67$RqxReq;(!b8i+ */cT4ya!2ڗ)^Fj%1C˚8L@V|dH^ՆLIW1Y⢯׫e.O|tEaXQ P Oj'Ƀɧ<'>OJ' 7ɱe0>TM+'PzlsT1N fRQQcsϡ^0Z쯭c%O+hUfwQe+B9E~d l`W` *́H/W 61;49?[S4 Y3me+ &- m2=d2^P9"/z<{|ڒ,嗀fbɂE (ou Ȗ  @,՘k-SMj$@WUDX^#qD+E+^5c1>>&=~Tم)E5I_DEirC|Y}3v/xܦt iN&g5]p%>!p@%! A~,K5<aPQo 0j4V^?c /ȩN[iufhgs~ҢEgyhTA^ pk\O ʟfPJHx4,CAWj'X)@JX9g=-P@<X M/gp`>s~Պ]=}yFcQO3twlR!xH9|+BhOl0u YXK~WZGs]^1E(nLH6yii3 yƮ#omtCIe1[nKнxn|q㖆.nd z bFE`k4ciYD+'H9mYUI %J)뀆"ҫL#߄No|$RL;t.+9 u9>Flqb$<@5{7i<kiX ~q r*z!ܹsCղ’=FQkrSowXm ?ؠ!NY})°8ZE #{  >|oժ}-G&ggɓR_E?w<7mQ> S^xZΊ9?@66sf)'GnUzVfdgDf\o??ܻ,CGGWVfE.j/y?#hȏ+l&V֝sdKգA'Af# | \ X̞=G__/::|Q0m";8 Pѣ@ BB"@5@.@ %iW=FvH $``)))< !ddha^z7O͛U( GmwU55:yݧZ]o. <T{1|ҏ`ϨjS-9? <0X]HZH)6R{JF.(l-@IHEc` /ݺu;:: )_$VQ.ptP;he !Q9JR+7hcO$cWw)gOH2D1IIz l`d@0 lb\4ZJ$1]@Ü$ڵ/KrPm-K],؀~bL w+LO]:G[&-g`ؽwK mJqs$z{T9B`N؜9sͣ"ᎄ5poù 0z CGczכKg~$|z:<%yP 0IL @À$0!$j 2 9RpA T1w^_\n#ˍ ?dYxL;63jU] b_t{KC L2(2\ul1\uU #e hr ߸| Nx "$5 wpqA Ed>l̆TQBbh<$=pW;pRu+02 |(ˡ]ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx= \pSAB+xU[Vj@k+j=TkVA-Tj=*^ ` TP9EP#@f7Y$ Zo͛f̾}sIR̔ F 4"Ԅ+ ԉ@ކ---]aEEݼysҤI$ٳgVSS FX* F 0~HGկ8$5%_&*c 0ee4TI% hn2#κH5%Qcv{k=c{d4`g+)[ c SF*5bVJF i@DSw‡Ib4o@lY5Kՙr>g 0C6Y]ckLԀD(DO'ZO$ei@PoA,=#S>)/ZNG&gZ2_ɭJϭ?zqK4v͏I%SVo|K}l] @Ga 7&kkkS[X|~& %yX`աj% _wewnr~ajmo_F&  Y«|Tۇ+ᴱA*{g(_գj= "K ' oVgJ-M)k[kߝr|u Z6E--^9V:`RKؽۿ^~̮'R%P~xguTTï-}*&:_K&b=UZf cszjZTK8>Aw^~`Rӟp VJ#)L hK@d9$fQM4za" z=MCTZvEi°oGk"4Wu6W4/{%4go٧JA q.ITsaZnݸ6^l=`"WCFiJ.JXQ~FaP[w$Б VIG"۽hC W;sއuz* 3A0biµuG H%  ɲiX[ <-b]sc[%9xG>7Z-mBVDP^e_uh= !5Ay A2W7TԠ:q〸}Cɼ_v֜{DC$jѴD䕈- BZ:%m *~ZrpM!^pO"Y]^T;=hM'T*PIP$epA9<6e7sH^{p~V9{7W{}@ul?P°ZD-RI6DX݄~sN*hDQ;-=nθAj~K]-Rbû Ⱦo%a[$t{|$ t>a/L'dNgEl]Fj!t4"0&iLKm&D$RbR& < ]~oW-fY\s, :%P`{WB}zf&aI#b5<BF2uJ^aю}8ٿaUBu^1]*m`cgJJ]GJv}tl_uWMY԰?Ym,ifLT޽w/)T>{OH% EُXDH"ݻ/)4FpL9wITi3fx/<3_Kr7lfH oz]W޻ṱly77ARB۽vUnI' q}MtV%o8XՁy&F`st8ō37[emj|Uf1>A5_T}dU~LJ@YWX>>ÇOyp)YY*$Z9dISg;9O[rwW2-y݋Τ)hI`η ŎЌ(/BѳJ6P*x"i}DT2kR'^X ϠM[*$ QHdGQR 4 3xxrcX 'Bv(fF0U*nX5<˅rpR˰7tm('jrٵZ&7 }n;M,NRAr&R('H8K,Nnf6~;>3?\ ?÷rs[ɴDEqrWS`vω;8--a4ߡxHP_K?\~zkyֽ+VQJNkzԻ0 cs;$xZeVQfx ḿ7MYm;X= Uf(=)OP>̓"5I! Hݝ}q@nI.T,"-N•$jK>Є?O.P_x]C~Z='w(` ||a-&TtѺuaw!~ۉL Zܷ:Ps ge͙E`Oo/-?D~d4BQ:2GJDR hsԀqR`c*w8d#kIGdeJVDX iC)a1]MD9Y: Qa=~T΋&X"Ԕ\C,A^)a)1htJ59=.^%+cp`?n;wniZҶ\kֶx@ [KD+H N>sltUSe<l#4P$0FevУ:! u\j-c= M׸=K&$9(@vWl8Ϸd^Indžߦ]޳k%lȃ4ۘH'~KcHKrZjen@OOqG';wN 14U)pO.K?dO%QH e4hEhvD4Tg߉3|U7<yFv)&RZ-0M&H JM[' wa*; kd麟P<`R0\&?:"#$%gV6uy˜g [;)7;!\ !"Ff)fK0P1IWQmI{Nÿ݈ gs ũXӄE36nsV|n-;q*"㇥,mk`FEcu5͸Vo]sn@aZդ-AmCߌ,Gny~wNڊ` m"7FevC(q$ð|09]I>QnC}ko ^K%c*k%6À>uŕ8k;fZ"Ⴎ̄b7?*.i=-b1&}TZ5]K DX*˦P~A/ao?T7)$1QЀ'~<-Ѝ҈V \J%OJDB&* 0xAh72Rc&amajY0 &u X@I2s/gZr_R `Y=||nF޻*,}0YIؤݐ$_;T4<=k`?sW$I|vU`IJi[G/:@Fّ%!CȍX Hg.ÐYmo }Xȉ`{ѻGeq#? :}!|CT֟EC|w9;ޓ;x BTiͮ%&ٯxޱ /s腐{Bs~ zpx"baHs}nn*3N?!}+S AF&I^w0z*,)P4$ @=tnl}$Ȧ++~aWYo?s JHw480FFrs\D~66WmՁ5$=槏'OFl8̎^`h@o7r#i Jrʿha*2kQ9B;v4vxGDR* U2$2uȢ R22CWn4 -//733;/fEAZP-#=ahדciJ0l:%[^cA@rXl e$RU% p g#(A^(/`nGHњW ׊ 21 e0vM$%Ǯq |~Ny rivN_ ڰɤ_$GK /EIaaԆ>00VՏUV N%&&RpG9jjD*&!舮Epeu5 h9$@ٓJR08OK 4`PQ*\( 477=h] -ŶU@ t]n[XXPv 9:R&z?/i#dٙ =J"Wdv q-{fFx4'{gЖm f̙6uFt~8#r {/̶}Zj5/mn6eyEvb ]wsk22jA^:~ <%g>W8MTdA0JR 0xURȱtD˶'?BqaFBY~ټyW98' B]bIRI {[*?9n-x Vֆf-9GpQ8=Pc~jjNQxOC$YTA_T$E9q5ψ$8΋8wp5uYj^FO n61b(_'PC;5۪l+D߱t*~>t3&MyVAo0ܺVc3sTS.Q,Lil;Rh]Ҕb4С~{PUƣ|IK76_?/q!K- ']ҡ^Zi(<@WkIB&xP\" o[>Xp o؁kW3aUbJ{Z a `Ay"pURĜM\2x@2|:EN qʀj*Y4JNwCSeo2v\$E kWK{j eªU 7UY7MؙS$8 IDATr]L&Oc)Kɬx!W"@0TĄh d aaK^`1PśsZ[r xpЬN#\q8JսX$t (=ӯQBt&$&lva FCM*oPW7goL%OOقvxGe%3kfDxeX+ %Bf<P4cɌ\!ihj RΚތkҲ $*ʢP$A|>ӡ֦-@{z7#qUMM}3jה?Ͽ\]vlT:+g9?sJDZ2F WzAő <3` ׁYLHʳ·FWZtF8 6h?},*7=CrsssJ%|eLF!(eIuK4qRoeU 8+B GLF1l)G ,׷G9&S ОcTg5\s*dPN=²e/2 dؘ't`"r:JK%1upK6){ؔJjALKY/{MdfF$M:>~%6UW#cc*~Rh,j2tXX$?$$ku o²??ZIR& Fr kKm3#Me$%S['KNQtUS+<+d>CඓKh!v."BÂe_>i'5.--?!4mA!qk l5p#,-~3QSFERq 9V˔B Xjb6ۄoy+^x@<!W hoܻS>Mxsl=9]1̚ec;Cf^ YdwY]Rmil Z.#-" _@B~R+#h[ N&ʚ`Q @H%+D) dRx<==UxjF&*S1p:^1 >_M$ fW= $HL!4 =9)]#܎P*d}bwTjΐ'R2/Bd+}py~/B.Ó.jȑT{{{8CQSS[''*^{;3g,9ܙBEe8NAVBe6^A%&<P~[vO׶G4 rbLzQ/\}6\NLJO~pSe}M~YKs-콆 K]C_ZMf5+-Nz槁;$n[?~MU6E*#1ݷ-TZۻ|s  _8-q|Y2`4@j/I* YJ@ܠ!`zut#%K8iⲝ1;&{i^l=aI`kwف<ՓHrʦ_@T{kyPMyXoHٞ1m0Ks޹HOi^$Yaэվ}&!h"+q1j5\EDO\yvv!l9qAzEH ϐS9xeaNSW{\v^4Ĝ(Q#"CuGFC .:Q¢D-U֋@_F̒DQA.A)$[J^^#F1ƩDGyshwzZ}ݢ6`lȄj@I*Sa϶QpamojlX\_Z(,N ^k _Ā$aH[Z[ mnE,-,4miL][êK*|P*>toܿw&|ġ#AQ=Iꪣ<`G  (U3ѓ ;3C~#es0˳$LKS f(sa4$ @!H]I-Z̯F ?/[,r9%/tK0" cB܁#h;Gn΋zE"fXz",.>;qsv>Gj6܋V.5E,6:gKS7}i9פ^gv$wi:PkBcSWwAV!+>4jʋ^w8r?M%pF 9m2^^y<D܀4!%|fm @A;3DhL63Ccf_O w`3m@_ 0H@ y~# vه"!W ,Ą?K$uϠO؃1wuͰ[v,`Y^u?GYwlߦm7n}º45v]S53 TY,oӶR]Ey;,ԇt|՜_=ןeWprplS[PPVD0h)[ÿuR;tXJدMzd*_VxSSSS3/ٹIms;/{pS?{#)g֭Ypubo'R$y/z#}c!K`=ĹRWIk@Rz*hz* ZU8V;61U)Kv%- WhUn.-@WEH g =l^q;tp7ٿgAH`S8`g_3#z>n!0zҹM; ڸu%yU#/|޼ OSj(Z0 ƅuvqkJ/~\ښ&SX4GыBMwzo߶G,!.Bbo0 2EpN r}pz9z9vpwK`?IliU#jO@cCo )Ư\Pɧ3sPh#.wĝwYbiQB\[u Z&]FQW т+뇼?6+ k5`xpPSpEvqu%Ip8fh߉CXښ&SjN-mf $nxJv^ɰ%g[l=37\IOGG9eܦAqVʳ/r8xqc:t(!6kx`:]6fv4~JrB'ςJrX@*r.zrʺ|GK+ʲM4,<=^D8ïBa qߤߒJQ&aE_x%!|[_xA™_M?oj'N/Q{8DEppυˇÏc˕rkܢ{q!4dy%_+cāJ8D pg%h֬ĶĐ,h2b=-'% ҆$猥x 708v_l[P瀽q;mW}Ls+lm+njW#bk5?xC`7n~դb%Sql)hs` `}B[Ęcj;<BѰeUs>&tp.7Xشldh'Yf2'rapg6$ufb7?cIJPc!cnY8]kA9n`- ?`89.̎ A{q-&fn) 埘ϵ#+Lp?ގ6& @ &8l^Z1< X ^oַE3'Z%9:H "j ݇NlP!`Ni \ӐLJ0)'ٰ3^`Zv;Us#J#wPePVF"b)}}5<̼XbW Z,SMjD}+>zKWhZGwH90/&:@@Iu p[-eUF+(]7&W:$dAs@2H+NA(eA|O¶W %kszځˡn 3 ͫwM 2GL 9R@c_cSLGf!ɵhXq XhCZI./r`pԝ&n?ڹ\ȔNjmUJuw[.CeϿ&:>N'G/>iC|W8Nj}өt!,s̓4XMdI4˰ߟxKȘ% h/?1`4$pl*\t. [u'jjDƔxENTi݇4u8 yU!>kTsn*Xj,Z@0FvfaBSſ7,6֐6遴lyG4}o9r0;xGm[F]5d/kI 1I^dG<[>XGoը B:~/d6 նp,H=q4n)cA " 8ً{+rg_p= R'/K9`Uɢ(Bhٝy)>{ߩa|+hwK'~s‚Græ!Q= <sy̏A{R6f,ņ*bټz/4\8*OԔXUuIJ>Xp6*?b1ʻ_?=` ȠAY(r k7q:{zLeªU 7UY7MؙS8l8V.YkY! {M99#lhGq&ha4yQ)U7"ͩ;͐g֌#Pӌ>ѵ7v%{X=ɐ5 q䞏Ƌd^!ٍjj@YryFH4˃IcfDVO(3 ٽۀmI&<;@_#\ n]$%uQ8LA IDAT筫f c TSFVr~f7pÑę\S.ʐХ*&C-x3X0l]&zhf$Aͨ_SzҥY}eV_R; #LJyJ6<8垕ge,.e9'LYvoQ&k l5O m -R;0!?ۻ(FwX&&1W#wl<ߚP]3MgcEmTbB҃PI ,Y> `I<=Z(/؏U0.f p.ԟtRRZhx1'8t1>/*w]‹^y Xƽ!? , rہ^^ȡ8@^d2sX̹}Ia4Ѐq8I  5L]Igd( 0L^y,ԠT'WFJ|fɆ iV%: !9p&8q6"uG\:erhE6A>Q̹}(s:%Lă3;y2fx;5%/Qfxt`2(s&zo4rvM6]`{A [Rc> ~*6T꨼qzL+MCyp'j r8Oskm|N_Z26Z1Jx[ (->šGjp(BX|el aöm7}Cz^CڡT;rlr> L̹}9;>zqU׻aLP>#P#g2Kn(,|JOvg57%Z.ͬք]x.y{?  +Qnitʼ_m*}~G+~b"!aJ tY̹}]8&c8B9xLVN3S4ތ#>6̵*+1~IaFgΉ(JCC] CPRt~^p'ѕJP(a4[BAGCѣֹc""){ 425t xXfۻٷ;)Q%K3ݺ [:@VAXWƲf']5Z 5؀GqI sovz`p_9aW=-nVڨ¨)eeWFtO&oAtk oK[ŭ-͂ʇxޫbxї=|2sG `W}+C:wsV]R(]i)w~ee>rf/seYJ%dXN׳-AGDI Lx=4#!90t ?CAJksm彊"WGU"EIA`RFwZ. j>p.X<>';yi0w=ppq9GW<|0:}ֶl۶4"{B^ܾh|n}}ka0Nq$Ι@7J^>\(K¹}>"gvn_/kbzԹ}co.\- L㷭kɻ#)b9?4^3 e.+H9\gs}GŰbh;ޥ[O|PNŜL_!C5JKK LXC+ Uǹ `rur$g*J//jEHabw5}MvA&Q`(xM,k!jWQkx5dEU/ |'70Wg2 ?xnB>Ula|n°4Pv&:S>Ĺ}y~',¹}t <G$'Z]>$F̱VRW|a#lR2 Sl|ꥁUܿ]N9hР%Ox]:xEYozGcęQ,=n=6]XRDbxK? ih̹ BČ mkWjʊOyEyQMwhn-E~}[)OFHqi l7T`y?y(d%0.Â3ig *L&MCQhgDDw}{/ @Qݣn`FMjq璦 XkX%fq quȭ{*ɴڕ:7tJzps؍~~|3첺vI/okr*q"70_BaE̹}])c KY'1~7,+XLAֆHTtX0yոIMwW4&$e,l WZ DtZW"XY2]0\(}> Qo'i/nuN PKPH[kAWgnh%"8gS|cA [okVІo(O) H0s2Vma}RXBgB/:s(s_LuZ`:x O"WNt AAӊ< ㎓n-$ƠT!9Αiƺ 3w!v_-Z-h;YA#>>4e*NY~(pZs$1|Dpf8jNi'Y :d\,cC[9/SO6 5jJ!t=]D[x?n]vreҰ0LލݽJ]`S9r sjM5Kў"{X)s~ yW_"ֺOXW{&tkOA,NG?7Xd=?,::W)$q4W~ލᑭN}*ChlYntC[zҋ8X$:w[?V6?P.|J EV&?0릁$5u_>a#0u+_N̐lEocj W%%1  0`4\5PY oumF u^j pO@t_6#Ok#J Ƒnղ v+tbRs2W;ܭ=dĹK=uH>_ziKŽKł nWD\R}'c0J2=̙qGvz$ 4Uz{ZY)=mu? Mȹ^ܜ[gZ8PBU[Z[+J񪗫\mnPbhT,GĨ ͛q3;{3g.7!wz{?Ł^\1B_Q?Vy'(2?O~u%c#M'[gI~c'-nS 47mpWKHӂ]Yޮ)soJlX6- ETj9=os?gʤO ? j7m~? Q'Uq|+iM_,z'Cyqwm &!*rZmLi*jYɼR޾W8q"S>Vz4΋F@"8,cVzK]2k7hDPg]Q]QlM_@OZN=Z埱e넼Y]'k-,Uul\GzDn2l" *Yv6FBQ!+Ak`9p[z2hK!>9Yؓz,sD ?3BQxDOt9r6t&S`b痻[u]`ʨڐ=?EԴlQMy0c-2W^Oa-n%s^nynJh_:y,D7m8dT]異0zY~^u44mW*{n߹8?ԚMZ{v:}bҥ _:%FmzB<׎0J8<5kācΏC+X;%ռl`-{Ť@H4WFؠȝKjAAyQ@B~mv@s $ {N6h!c{␿~]]mWS[wm6|ðdR 26b7%r_[!]Pg(O $ 뷠n <9d &)~YpHt!>]'67ngm TM5RKOc=SwXXOqbeRui#@x^j>#~g5z529pbB6U,xR"*&\}oz*<۔)mn8.@rłYvd؍a㍷$F!s<)j[}EAMqg[ݩ[dt8X60w&s{c4Z~R/V ɗxN|\(ow6% ͞SC`jW'U:E4Z`u:7u{}pWYw5|>Rk^ժKmV춮+-=Z?Zrm#@x^j޾eIE(gK)>0ˤT7Xv 1|AbK|Ss=^PHr`5l(vIG{zGkC }A.jZЧ'jC NNQz,58zZIŀY;wʨ%Q CsWjY~ϑ"u/H7duE[otud)4țR-Rt*UR3ey#LȑEƧi4QJrIdU^>AJ!ֶ籪XȷL>>&‹խme V0á `7/ `%~^ogۇf/܂jKT ȤY4j׺ xqQorjD7T?tY~2ý9 3 \AIk"G^ \nxd}w)X1T#\wV4+TDPC>UVįJFB7U%|QF\斨U*ӠS- 2(ShH :{wc4Q1DʑۧJ9'R~) IDATx&b8r޾w3K/>+8! Dvo am/a>nΏîҜsifK38M uyS;*q^j_T f+x9ԕ:0;E%22;y*yJ>-T}"!HP}K!ۗ7 A (B&WdoxFzۙ褤0D#m}¼}*>l@ꐷ/5}y ey,?B7fe Oм}klNG[[x¼}^#{RhSTOoX={^doˀSouJw,NTm3 >OdDO;_ߴ0 KZ4k[Il"uC#j7BF>D=un7 Uק1Uyxswر#Ϸ6^ɂJib$9Xnְ'.A`ﱙyV1xP.WA^n]C|G*m|ٲ[gwxg|Qiu(k9_ f߷SU3Җ?|O jQ1^;PtܜG =)zAE+oQ,z3P=A&Ⱥy=86VnN@&ʍΥ3+2HpZ"tU깤0ah+@&^_ڪ>4׾%뒆b|ӗNLW(1&œ%U ( PGS+JZn鼤 ֖[Lvl)vLYO{0),iR%]ʙ4/w=E0p7BQ;lAU~@畜M(8C7"',q"GMX֡XEߺ0QiTGm%nF//i"?l֖0 3s'_KGaT!: =7gw$ EϨetgTҮ:lWH ^^^Ba8g}Q3qP3L쟴/uU2{}(J5-4wL)'+lq$B;T뛜8J !-ڦjSeP1m m@+h|BcRo:fh{s9f#+,+4AN3U?QDuH$4HdK /. eZk+zBbb/Eb^Hbavv1sWmհ2*YOf ㏒w_:8ڙ8=O{⊓BY梴UaGӚ <`XNTä Bg:ݖNJ R,׈qYL{^I5, :(ޯo4')UL?_t<(wܥ 4ZbjҤ :YVdYYOyH`jl$Z 'LT-hHdf\V+K*O;YS8&''81&}>2M¦ex)%I=8]tOӷ ُ,@'=R~paPAw JKȻ%XF-*H;Ce0byXy9ڵN҉_j{c e޻sԻ 9Ckv+2`5to>' eY=Ml1QU~n[~4U.;oџfRu*}iD#! Z'.CĽlp!(tb<|}ƪZde\L, #3ZN23S(yZeR)*N0e+W]׮mPbr-=k@'.Qn9ʙP `QCi¼\Z:Q~+$z#@_Sp5B_/2lvC@HVEe2'1o,Na-DD( ;/ri1 ! m!ԞV%X!(t׽"+w#jLJfmUα + Oą)FVOuBKv ?[ee)V:$jҲCOS{x)ڍ}ɲ,p %H$Hnl@rG$,UkQ)ʙ iIJzf0i% Qt%Ja[Ni=cNO] Y,c% @x2Ă%]]1ߛ튌0L Y{g%: 1pNdGC;y+;O*6z3ttH&<1w@OoFJJSV\UbTMD#ry5?v! 'B@;qJSP̵zX]B- QU65AL6BA qֽTjHj֎C[.d$&(CȂ7Y]p$Gc7"͜b~.z;+:{C zy'[LAWrRظOj;C?˘;Qc9Ek{rg[Vǡc@ X߲0p -!vO_ M?'l~zMxq 4 3kT7|X-͒?\\Č:~}85|&9 ՙI-\bwъ3ǠrA`[ :?*/]FAlK iY!TX-Ĵqq>-,2͏O6oZ7<^38H[-Tv[Wtt$FsW!0{QF >|ip?:. FT:OA @x|L+>3gQ\)|{KOS2G<6c^I˨֨.BeT$J#n9}@δ/sJ8iRL ^ ?.׳5g/Nf{쾬pT{q::3p.1U'<ݼsXtLDPhjD-LT!y-IKцzzy!I|Y';g5C/8k4=ݽ:RLcа0в b)HJ*S0lm+ژ±擓ץCHP%֓"s{z`a}eprgg :/̙>dlGOG16ztnӖ 6`9Lۢ&4Pqj^uLMMMw}NYWޘqq'^a3Gmrfn=X21Xbj-$;87!.#t^:8H/$5vi(2i_/^(6qAu@@&X^Yz3ĩ[FNv=M e wL`PY)jPFx2SAg9 ɀjA|WF .F >FYFFH/w;3$Uf0e޶c*1 Y~:e ~ S]&[nPedC F%q!+@Syo}~0Mp/07ԩюfRlTH)7 %GmV1yRY@SЄ̵0vj0Bf_̜#x$2[0{H"@'=0mIkmiv1]u>޾B)}:xPS,i\^ pbqA +AgG`NWVo_Zb\gT&[foo} *uR*) ~BAY0 V{ė#j>:ZAiΠQ'޳YՐ SOxUcQ@| :tȐ!` %`L]ZD^KL8a1ma1Y/h7D MP'A쒿ɗII 9 kum]#] AĽͿd}A qAkȪ#N?5V?d檳¬WBzF \}$_Hu%ö t^sK쒧A!^yZn XU~ ̩D=N([sA ϛqPg%Yř%z :e9[" D˜osTH29lPRW?]H z z0۠<ޔǤҡ;(87VqwO!nHd=$9/X-' єI|iʘaQVXݜLGn)]9LoVABrϊrioYQ& bNԮ}ߊ 39Oeė57?F4wV~w@E5  "f%]DHGIrd wΤ}R.9I\g,ZxBc^db,=5 +~uōfVʲ%mpa-ϴ7/'O j4u;L[ g~Ɛi?5qE5IxV24Pb<*A C@RnJya $ƜFTxt}k?+@-2CP/hJ8b+eom*YxT6=d m_RxzL@2#*";{c%-ǣ'adފ`%D>$* 4^[Rl~Vo;q6aєU펖;vO~F%o״@{ H?$OxU`+Jz]4Ȓ:}ԀnF!t^6fwջf&|P]`hL6BA 7cZZbqtx% E}bx~vl$քY\Ŗ@ LoFv" og,mیe(m@O+V$"^Sxn:+1,@n\(*N8z IAW(utVv"A 2#`Xc^6{,zYrk;G?JpϘf (?Z]k]dah7"JdTI`=08vT& dFeH|EAP Ln"7Ge?5 IDAT!zWz95uՈA& xLL B&޹+u2av{$_1x8{W=UaP8 %i+S"?.Ν0Ⅷ_[:J  N"B; 71\ӓ}m#j .#N=v`}D$M``eЎHB](ҿ_[&VQdCx]i+Qo] ٚEqs'Y3XQ=v_VF8*`8 wW[ãZ_ u\?8Z,|[zS`|bACo; nTU,% N5>[L$|!˰ {^ڬWx 4A$^m}`_&TÎwTnVv"'Fp-tBİ>QXj䵶ZBX2$(3-'CB|aXKJKK͛D]"WRj2>DI$?o_}uE߄rDu#3.a0ILӓAOïD&njcugCq >`*b@ *AQTY":+`4Kmte!?uSIn^FC/svvq}E+=G"A BHkP3X&2^`iʻ?۱= ni >9&SݚQ z,E)֔j * Q~8nMD|W`u@hW2.y_:͊!wC/Q^tWC!̤d!RLx "%zV Kv Sn*lo0s.cW~<]i:uLSceygܒܯ>ώWWԲUԱ#⻷kMzRFزR%#;t,cM:BI /655)=%t+m( 361{ISmטzZwU4p0SUPK)t5`$o6du<}N!,oR􋊬l4ƀSr%1?dM-\)5V/ _gW .>I:|x}44^_񡇙xQ|_B)zڷ\ˢT5rD{e+Ҿ&΁`?]; :ǧu{knuZ;ţԬ*=c<;kǎ9N#.omf-r܌t|U1Em-Yշ.O/۶Yqws 䩞d{?s No(G{b @x|깫 Dw ̋}CLx2sōF* BgP. YBhRrf$pnˠ0'|ŮX}N\t$u:+z۾)f{Q jHLxBѽI')H7k"=9D.W=⤜044 7WFnn3~J3`4OR1 p&bK'0+fFs:Yi{iw~5ﱴi])p:qj|Mf(P|]+n6b)0M/&4ᷤP GLkM~1l-\uNw̷ԩԓ\#%3miL_ҿ{)i&[90^+D)٥knz@z{+ZoӔݸ~ .ݶgm΁ݬ߹PƛٶuګِH7dfT>0),)i9,uׯѯ+g` {~)܇-;f<]Bm;G8΢5W}՗95\":w`ݪ늵 D@?ˋq7~?j,5\pc X`-IxAy8̣>i'<t6<0 Fn<j+X>cde<)xĤ07NL:) 6a^ե!4 ErJ.ox\Lxf ̂08s64UY$]C nIYc>cG[X&d^q0CV%8D6wFݐQt]D2B/bX_] vҰl @57P#x Ty hQ{BO>z_%͵Jd Q ȴJ[2kLXr=Dž\b1 1 :d{=lv/I`92V[i4dc^/B ʉ/yC6TQ\+ G{.J]\LoPdbaNEØkSoĚB5ɼ;P;pHt7J%TU W(B] c>$ObB l #bi@kކع 1Vd#=4e2s& 7Ugg Nm L&&in,i iku;3 6&|u*f`s@a|$}.2=yԊ(Nr"B jz.'LvcEDV{ެ+>C8?yGx ON!h1Sbg2#=lmB- =Cg<ʤTZ~0fI9Wi5E_da%T4B=F5g/er>A/IR Ɇ @xҹh*EW~p1=us)W1%BUf0e޶߳qQU xPP]5lɃq[}tqZX.lAhrF+ISpWzҮ2tf5@z N(d9YU:7L/0rjsV@=t<'_z^\qf{ ~o"7"5k#B׬#GNvʃ-e@)ҹ]^>xfs].Žt0H Fe-I8tFpRхRTY +zͻB-ܮ2/z@7,oPcuC/CnT+%;H[jkTĔ7555$Pu@;wk477766644W߹)oWWo߾u֍7K ?.|]7oQgH9AuCfƁK ÕUmm-\k7o޼z*mk+6;v/m4xZ'?AuS_ʫd/PM|á`Geq"d(u~O DbXO4η n 6㏝:[{,Vm.~p)(8b.hOXe8_D. q' *P|`j& R'lA :(ώOg1R@9FD.P=\b|N f![ rc_7Gy rԣ#s 3(Lpkuip7=T7C%ۜ}ncp6idDe#\pa )\peK]K+UgUUO:CsGw0;FujmaW=-4P[؅tϜ~Jx^_9ׇ @_Vp5B_/ph=>E0'7!M[P]1/60|B!efDi }L:aIfD91 diyE?P>¤~1YI3ׯ,Z1:t6!0m;ٔq.8DhpR R_[:׫-]D$F, v!fPAO$ k[7W;6/=ѶPf }; k,$FVKzj恵ABًyNIdܖlyۓw oR=uʬdԊHC@5-A @ K`uu"- 2-@_dUHI! AmU]L͸0+=fVo 9O$*>ZQu]'lg~7_^{A|tM"wF%8=}#ssS#iDąFF1u EIwCW#q8W=}1IhH-@Cj,&8$_5DE7zoК{lK;ssЬ}aMhTw01r @¸[S+7++ z NP۹*Hqca^F]WM֩RGGI&s`O'w7eDq(BE'HS׎咣a6$!UY8U3\,QM8v,Ȝ5Us3F 䁺1zD]{ԾkFA^#^ʇ@&ݐVW%OT!@Ԃ7n 1L~Л%_)#tJ-;.YpQ8WJfN H uo _|;"cKHF(`zm81y%m z(:5ֽ;y+;ocn;l.b޻}BhH`wTV-vnQV䃙'J`ʜ J;wtl:Vgʉ9kNV;Jٕ7#_$ SR* $R\,qhY 7 үoϷs7a8L.8[EBUۼ .?5$V{p8%h{k{7Q!l'xQ=ӝEo); |38|#4v1  sФpJQ0n ͦQ~3B>/3h @Vȯ ~\supй4yvCTKnMDSDTX%sQAVD'RPT0D <6-\!4ZrȴbP3фZ\wa#v֪N(@㵹mm%g"E7ЕUWZlsbXy ejoJjIs'xQ1ۑOrtkC'Kgu}mv#%a;vFK:z dY4Ғi3yJ?Q&.^ud`ݫ8alұ\i[InMoXrӢ W%R7k1r)<LXfWܼ00N 8G~.-MFXİ&IXZ/j`f IDAT.1$y 6mJDc2Kk۲@>tI**.@㇪Y%e"F8(y1*鈢p6j=ArH>hia_)Eg`+t3.Ei;]#KNv XBQ- ~B~FEh&d2t6͛6_AߡeET5@pt wyhwEAvU '<쒂̨y6Qu&\ʋ 싂OPD(uav[2z@-,aabE,PXL>hÛlX;++C% ǘOFD6< URf:S7Lst2Q&u Qh [z2p p{@Ot% Q&Z`NK?wY4w|'?|BYp>hiLV||{ז3@{4/laHޓ-bH[hjE@ 4sYCjuƠvm>h$w^]hoGGGk0'~r"o#"m`C4yɈnT1P ܗe~Wu[>䡔è7uJB7|z…ROB IxgQz@ ZA4e8|(n hD?5tt D1ڒ\D(]kވq"vPW' @xLܦ-l2[zْ |5韺v\wNj)`M{wuҹ{vcZy X(2SZ }TPxUqyr ]tB랢Cm¢$gͱl^wi[ Az~`HW^Dئ;9Vej 7m9^9i~e;uL HWлiÔGH@%U="tyo{uĠ(; WrwQPS$עCL31Ψ2KԝHYQFuS[D@9PTpvvG5ig1JA k0FphQH9A D_8A1B'Ą,uBW,lPN=bQe_lv;7^,-Ҩ.3r +dL~77?0}eO]qyP b+F߳qV\͛&'1=IJTqro XpMm[۷& _sTxXN ͍Z36:q7]O}5BY]vֿ/O=M`^f\;MfkB ,dq=dz]!2*PLABRa7SÏ}\4^!j? !|@: M!tgIY$"r;gPFP1{7P' R೦5IEL3BG.Q>HT!W*o*hLmOAqs"G4D}( QHE,X:=-_U.|&ښ:Ee 3ef٤8*1lmj=f:Jk&q0VT nC.=V&'jcId̏ʠJ%8kLOĞꂑ(Ok| wK3d2yvbhjW*ny-վk'EM 5>[L$%tu Qx_|w_$UBxQp}:_4ja8 {(85 b jQ gINK:603>6l\Fg dT0/zog}QZ (8D^cu<1MI}P~æZ)bhAwQQ jmxT߶ysXB->TAms" ؃C1y_!jQkzvE?[?2hYkVٱO\\sHmi5?HIBUtţUHlicEViwCA |0-|TwV6;2P3yɒja{ɾ_nl{_/wV^ k7mJ^,s~aA/UoIgA #%0|t_34`!|%J !/l>+eA @ /guuu"x_N WNKDdsssSSY 'm bȩA!iv - &J ?KVy~_L o[*y&f蕣A]1iKEp˼vgЛ-L+򑉆^GJJ )(^ z5f͚5kgufϙi4vwjKҧȻ)Nǫ鿶 B6`F`n u엜޽EL>6bF`@%z5hDxF0OIZ!<}K߰fن#X=Vn;hԱ_6~qԢNNSWngF6Cb쥻p㧽}kUwe:W-s y[0-OM͚J5h?ptxOb̀VMGcF`zEFj2+gF`[{c*+,8{P־r`F`F<\w?pF(ޕ~>' k\nQ!Pg~ ZUušf-+fF0e$Μ|"R_xY$;//$v˜ _3?稃~cuhq#F#PɵSNKT'/`l_ ?L޵krƪ8x9i =soS˟K۽vzX`6m)ӣo8N>sq_Z+\ٳw>}z-2TgP:[ڵ~\gʪŢ֢XU0ؽcW> o]^X4igϙf7w!p-T_Xw˅FXjܕS^p}͑oO3a_ש/Kdэ l5\>gGĬ6ޗm8}p}pzVy=%jSx!zE! ~mq\1%9f p Y||\%b*8r#4<^XH|3O PnO/]o8{dVy|Y;%v.wh?!zuC1!̯nۆD z 9f p Vfo[W_Gb@ ]i& G. 7wQ+B;1v Q9v joN-LM5 6/5l0t B`>\ݔs=O3](*TRuXӧ~ Aݴvd[CWl>^% ϟ?'"veb [示 D|BQm}݄t~Kʏ!Ow;w>@f>_hSA9|U*KN"VǙ#L;6'gƐj&iٳC/WW&Kg~tTY@v bB,3·qbQԒ M>oxɛ\wCAj ^h&O+r#0 ֌ׯɆ˦T6S{=1I-CСUL(,5 W*kqYqE2F*B>h=s8䟳hÿ5bjFV%aG-4u0`n__W-#V;輽'{cw3+𕂴=|}L7 w8 `+o>c d~^~a~0b6#4"g̫1J"|RŘan!)#0#/ ~`_Nh0Ewdm6M߶aWU]yu]QaNVjʦkg0ꐵeNfdո)#u,YS@"p-TVXXxE!lgZF=a~˦fc~=i\$ғj0ZH4{3hRQ݄{Iq")fʔvN陹6Cnk/~>BҒZʂ#pUa]0qNb~l} Mz/[La ǧ)L9Y*\[ywLz?n@wq~^qeGԶD›5aͼC%kUա֟`@Yȸ )k:ů=Y2G[O[ZXq2 X5Gh9g0Uӳc_H60qTg-;"q șYܸkr(SQOMoㆧ#i4}SQIYηSՃ;O]6mP`ȱ*FE,!]Ԕc%?CF̜#LW6>w*q`n,Kn1\#0@EkG.uevq<1XQRcuU\RppYK^ [oo7'XIlUTp1e9^p -+7^,=wwHT0e.Y9[OH~hEabFoʂUT.3GKw ^Bԝ yUUf6m]oUex6fUy+_|~ILh4oeiywoiF`e#/9:qBtL}3c6Vn@+C|[ 0]SjX2 1'uj'2?>]ٙ/>Y- } }Bld{ų/O*@0>_Ox*oz\r{ `!Z6o3eZ$ġ/lcH,sz,|qIsi_dnYܼϼ}O'Er_md5:907re#,|-{k&@-+4 =fC9,G÷5ܣ;i@Q"m7/WT_x4_p|m%>챿m**F y%W>gǻfGIoڜ9 /*DD;,51g&n<_r#P:Fq{Jy'xA#^J; rr8ӆ!:FϞwޯODo% 0`VanJBYyBF /-L7_x۶=ۨx#׏͈[2g˲yQyJ.=#PG4vwjKҧǩʾ͛s61!Bƕ)6L#I8ǎ4iZ- +0)//0"ʎDzsAGRWw#0=|λ]}gd!I8կ ?ɯ0V$+'"VrȎm.+3 %TXhG Br heGy<7-繗sF X5|N0׍@Jӟt:5jI ׭ 0# q 2~0ob%XcB9կF?iW\:wwm-pnlvǩrQG<4)AfKmTZ J2/j/dY/#8"ꈆ$[u2+]Ш+d1/x}I}!zF`Fz`zcyF`SaNzcLwR0e<,6OYgUn5hÌ-ɩ)ɻr 23ȭR/%JOr;FeLU2*U½~dڬ>cֈ {JQb9d#g1?c)8٘u?{ȝ9waAN-#}2>r&Lϱ/tkcIy53=ʌg~buK0`Y_}\yoʿd082FDHX=buU*F= _& L9ڍ9w; NY9"9f9-;l8_ۢWLEtbn]dO@NͮU*Gꔿ1վG]~޵?MsʛsZ84,/iX2Gr++Dplo ݅\q0s_/jРP}—3"Zu +,SbξE#BxYaI=?YR^ĥ}2EȟE}M C4ֈ3 fŬ  x:{#Z'z) h~7 rEqn4WoR_]Æ1@= Px$q^}ݯzK`;ӻƂ5  BLM5 6/5yS7?.c/(%xԗ4ʌusO/4Sօ̊2ѪaEcl>~ ލ>bȬ_:!ߔuuGZuߥhzxCGL}`HHIZ"ń"цrVE* KB/#PGdn],JO1푄SrxY+/bf -)?<ڣx}52'ħtFք"z@??};=O=={Pâm>Wf0iH}K\9V{(HDCvU"3V8LJZp1rZ3o:(GR ,A`q~XK3DܻsPy@M+HB<4Y0'F9*(1,;\l_GBEζ~zE,;ID'/TW]PMLɘC|> dܾ-155w6 9nʊ@>x-n #Xq5Mf97|&} A,L|***<8thbW0K~?v7Ȁx&ZU3U>qŋT`{27C[6IFuHf pm۶׏Ѩ[J/XRTRY-VYr9: ɳyL+ Jش*ƕY!d,-bq*/((U>Ng+bEu<{l{^^է2 0n<(_{6oFɗ? A0 ;'OܲeÍF=Q2ݤwܻ<[ٲhCC|ΰkׁ[ R[[t~8փ:[.J[/Vt 0ۦEW%>ZY([ r)W?ÙMr F]hkvaaN\S lݙbF^{8jgAֱ@C 33Nȑ#===Y_V^:cvYϥkh(Nw̟\\J>MX6m|/aŭ1=٬MqF0Yr`m98U4y$lWME-i_9.:wjޱq+z#m-) u)z!H"z)enC?yQF5nK?eʠ&㖯k6uKMƬĹcb"VHAypQOmov~IM8R({$Elc!?bdޠy}IuϦޱC# .^=KkI3;KipbG`#̚uP֏,uny߭{3◈ ]>ןIYtO"fOcijh3ya;[.$|p4/Ozc/^zka XҿUHUg*+(h`ϩm_/]HA^/jn2km>6Am\^0sn̤ߡm>-nе9U 3%I*_Ïշ:c{ӥ;>RPܝYWo1bg_ZuZ o~rtL p+˿^.5pՕnK\S̍ϴn}{=NҮ|m0k݉Hgu߷_ rAe LLLiuuxOJץu·4S2n8??~髯1bz QcK+J+[JO!^{QdohGu:a%O ϐCZ3gԨҊYy"틹s󔏗:Q1Ѧc̶ z'O邛8e*\ ®=CfCE@-gps.(NxנMX | ܋nV:qR APTUu]rwRޮ(- k.D~?]0*g!6jvCN5mv_S1ED r&%mN 浩\E»M9 >))]-JWˆ[Xcm_ ڦKkSp`c6mOSuV_eNCܯo֘P?lfƒw{W(Oh|*Gđ!wYz6!LO;3@x䄊2_Ks{O@tdN^ 1ǵnlV^RʢKށbq,$ǟ|YYcIXX}@?IHK eTZ>ӌm֑`M 8"x}̠`}os|1eF}𯙻uM|}˗)D /)q3t}\.:߮|# qAk)[fQPb⬐ٮ :fnMn,2]-I?kPaqsT^[p^ϝNt{xDkS)M05k#襒kPaK?6>#p]͢YYnJIN읐o[%;m̀f1~bV:GzyPl"4ֹOGk  i@b^͍|٨F.Ϗץ=_y|ݺ7Mg>˦QFؒ/IX gLۼ98Q:V"/j J)+n7Z{VSK;~?j%gn |$''S:%%N ֗}-zlT;fB .aM9&(۶ءCrJ) W꒨}=c8^"[ /I@_Δ˂$q Z%Z<)$&i2PRƿ\?prv[SL$.uh`2Ȣ~IeRQcRB/rsZгd%b ؉ H!ݾ}{w :u*88nXA6p @ Nsww %&Cחܴ}jㄘ[!,TD`,96hicFЎ2ƭ"3Tj\!!!4CF;HXR%+C6Ie%_&pΝ;G?<яD# #q=;kse.))!iӦ ӔI2-%) AaѺPXV` b2L$1$h$@S0Y! p&kƅMeAи@h4FJM) B*4xR݊%b$H$p=zMˡ2PExqMUK\~e)Ph M8_R@ǵ8|C$*B)#9DΦ,h >hd84H6F.6jfn"t}t%˘ns"MLr;@.rRIBQaCcG@@b), %hQr9d}b"T;Qfo%du-F OIt*%A`,! #R)iSYA@$iڀ Ar$i,P zC2@@q⨚%hՒ~4đȁ~ 3݊k:WJVIU&$&irG  Ad (#!IƑa*W]gQOIȺ#cTL%Me{+)b6 ш) dR#IeO18@Ē)G 'R/c욀RY$oB=)t%HC_"(ǺNh RMA BS,Lh|4pȰ_Erh$cQGqELV$&JPAe4 @֔IJᆈD#Ch@ bR1)$hI_BOJe2/!wD"P/1;PXԛ17'ߜUZ|Jgg94r1a)"mH\1d@͒4C! /lX%iڀkI\\Ĥ`RӈIEdLEZεhU!KZ%x MKzĥx%ژMbAӢk-wȭM @x"P P%8%$Lڶ_Ef m k&i"$$]d=eQq$A@riQ1q8 aDj'>K"l(EMR%H!c- tP_h 餖N.@QЈ!Z𡁃$M̅2K,Ho7DMY)H& j |d4 Ib\$@$є4 @6Z&$b\đ1Y4p@bbĤac$qFk6A^RjAAP-s;VR-]c?8!RQcqIENDB`testng-6.9.12/pictures/success.png0000755000175000017500000014300612732165123016444 0ustar eugeneeugenePNG  IHDR nb0הNiCCPICC ProfilexYgXͲM%Er$HHZҒsJR ""`D `}>ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx \G?<@ . "X֊E\PVl-mCk.jO]ѵ(hEV ހRE-AE*HpΐO2̙3g3̙3G#..f[8A @  D-A @ MA @ B(!A @f @DؐA # ۸VիJ @ ^J\]]Jץ aDM AD C_ M/euBA(!it k?7iw6RJQ_sb՟M)2'yOo79I Jl =t" _K:Vo4ēF,~t0tMu"Q\D+hg@b!M֌ vj}c ͜ΩItz~tNSƒ`5j$i`hFK;Ӱrv;w0O\be?}wQU3etfGäu;gFfS^dhjBαLqthYogoBe?޼`*Jd%Lm`i|c)'RSTKsT /,妁_SL6Ʉ:6Цԕ^x%P%\Bܹ'l/b{! 'D-OnOb/P䴳kԕ_Do!&Ta4ap2F^D*#-3AWDZbQ=}?詸S0.} !a#+::*]#Kk*,H.Uh8ƒt\7P먩9Nr]bTSd m}=hVVӢq/v2/Wg=k!-Vk+TC Ԕ[lu.g6yZڛ+2O{_1L#!iV4[sZ:D0M;CCkv271H& kp=RԤ5t4!=MZ)N'qO.^rU{bxܼ$MNs2 7 s;@PjrD*"FjL:Bs:j*.{+qIô,^ 츀a6>?J﯇uw&Hϧ(>mBe|7f<~i1So}F?K8wjtOoa$*%sq{\ :@o//^GK!ȽzϷ[NeAHƼo$rbY1t̷,NҥiJf|xaܷpV)N=u\^vqC+[ȍxvIR~zJ&+B\-RbXZ3¼;ԵLMFcŽ+9I]FىwMSIhv|ޜn²jmb' d`" B 7h% BHG 0Gpٹo5"0Vbe=rq ~k7g45MLVN@5` NIּͦBwv4FLXiqGН8t34ژ덀;X֖.鯓݇1a̭=FNcCqL!xa:|2!TA][vhRgUɽ0i2yaA _!!@Z0)3UT!5vmK+͛6; ǹO/~Lp]4!}G8PB#h5Ěc6uoYiy־ͩ ^׶0pGI0ɸVPqrsTZaїG;-fzEIp(]`GL={1B65kS9d|ѠeIފϴp[E3!vZ j-SΖ 6,a=-%'9zTҵA;`7sM{8?TSzuK;p4Mr)viuxu^ ni*&|Q2G-4r ٩&!+HzzOH[h:a*~Ǩ֩9!/aߕ\ p6* p4锌9s\1+ă't^:-LXvx M=ȷCXBV/%&#ɢ8^j&mw倮] .F e3XV5}ٿ`ZFF,&-s~9C">9ߩLfN *,+|[^.EEh;#xu%<=K-=_<׫a KWi^g /qȋ07ϧsUgGی:jB:0oرcm̷^.y"?3ՃoI(y^*MSs %[%-Vc]qw^~ːw}k{T01:X&3Hٴ|K6F\o5®HՃn_MMMY,y%dSҝa^LD|YPq4`bWDIChx܌`$!x+ .dKZ#Ƭ{{s8@ }$W,h#gݺF?`#wY6&͈V!(H^5hݙcb=*v݆q^e(Mnr<2mlW}7]ZBѬ8 c]4E@9_4qӰUVeDY՗,3i}}#*Vׇ{9c=FY]cua~auc;N}TJHٮV{R UdA 7BnY+d/Ru>;'d~ZG16ٷKnmm Ѧfd;u7Й*cX!qB@ q>c&Ilah`bo֬PUJ1mxO  %é0lTdEP+ZHC}tW bLJEۨHQŕT4c,<q}7dBˆ3Q[Rb+W}eb p0aE##}CT&1gUQ_7֪XZ̧.h Zmkbv'L9U Wen0-k8C[#QtBU![xЍ6{8li|k4GjZHՃ@,UIEEů M@[ȦOba樛C~ck-(xÍ`I+Ҷ(h·#G#Z2_]~E KJ6.EOO̦|c$w?Ɔr }[>ԍ4S2 49388v0))!!#EareBQcك5yҧF#!$|˯Jq ?_+%oU /bvdl0TD6<#7aXq.nE#tG#c"BfL&`YZ u tH4%)P5aY89%̀#T~Tp'c1uPfX9>3VyX('i;GY55u2%>•Eny(+Q dq̐a:\P=(B^aQ0NrF$s."w"GX d$W|~hE*UI)P !;zlWy̠G Ca uC%撜v <@^}mkb84 /-҈I2Z;m_ok Rk9B "n^^uhSѦLG9DxP DxH,Ј @#L"dL09208_{ZνWRpQ=~aT0Us?BMFTz٣]E:zRH$aw<ف(w_PK@GR%>:H"F@Q+]>xWL[zie0OSad32w ]F+E r< o)Q*@a(K׭"J[I$A @k)E"Wi 錾OSO鯄`lOwPh'R! @AZ$!4~D*]~U$}B 6:1؞;oWaCr' Aams;ejB["V鞥IW$~X'.GDhlhEЖE=37€ !0Еa6`lOV^!E ` zЖEKƒ 0ЕSKZ`['&'_٧}Xe9hhQ}ʛ0# t%5kUAG dT5HD  DI QNDA` @Ā "A @x%1HD  DI QNDA` @Ā "A @x%1HD  DI QNDA` @Ā "A @x%1HD  DI QNDA` @Ā "A @xȌRnILijj/}&./cbmR%`AI 2%NޤD4/^tss366Db?QW;}G <7^& k׮<7LIFAA@6eϯ ٬3zŒwttrDN ]W+6ɝ @  n&ϟ~qC | ewi߇ +A 0Hx?Jk -ZJZ2H ^NIXpt;;;,m@_M=qBXOtUM>w먏b"".|Xfkط72b=][)7A`!tMI37f2瀿r B54\$)?7.En?f&J;/M $TncXxV@P[55NF $(L *Lǒ&ŧ%2xEeboȖ4,0*0lZG,/O#+tDӧH^Q28A"^I;p>|X^>:B`@R"(8fW۾:.QOuՙVYY $ʌ?"&鳾8R&l nԁ=-pN;p4cX3Pė/5֜=XX~_fUV}*߻-L.)+ٸ!>:ӽ~ʢ_Pŵщ3*KnӎXG:T8 Nz rHٮV{qZb]/ʣS#2&HN3 >9[-% sh$'|o J^~3yボ 8UVe[&>S9.(y?qE@(!H= tLtKn@} O)XpL}frrϾt#PHP1~X ٟGF8̭&~ =#^0gm"MQG@JpyyE'΄8}B'wY~vFOK[ ((*;; јewr&5HٱĶ|6z,T*4NыN|z],X8~pL Os9zpյ(.,|}W?yH*EUgdz ߹.ȸSP{ <Ǯ?[ʖ7d9li7Ys}`oPŧmrAgZ3)ŀς84Lj NJ "!¬D3:b%D!I~(HBޠA PuhvtҊf|q[p=S;Nx"'''%e5oKKfaٿMNq񢽨@竽*#]C4aJ_6ܑPwR'᭔6^MD!!*1v\8B[0AD՞ƬPz=80޸Zi@;R,WmJ*LLS]+! yYEΈγ|(N)jPHH~ FJ^a:T޶O=T+ % JU/DhnX !7$ؓ:Ч)AAgrt2luz.VWql/Och8Zҿt2']18ax4+ǮLw5H1e} $tdS}"Qss8 ^%;x]g Z}p,|/2#O++tgPbg&yP?W>=#23膿]k.pHԠuF6j~lpŌg-s38Pg҅^t a))/,UyV;Z0|nMspH އ(|*ɋoAN-.ok;'⻙0G# m>)E,%{.߂l]"Ed& rbϞ=[BXU#4 > E,8URǢ("*pPϲGR ,;s<&4%mɈE$#E #i\T3\ACUiT$A Ikwꕧ-n|CS lpr.干L,˓(t*{7x)8y Y'TC-!1DT\]1J#SS9 YPU^c(R5z tu@IC5!#=PJ39Lo!3ϗt>͎_$"}ʘ0#,ꕄ]sTyji*U%!/wEt%$̑" A@X_4'O"cOF$A 0P${T凝OW8 Wqk풮Kʸ?7Rkto1lNi<;c] X.M*:[v,3 0+ KxS2%孱$s%L+0D.XW:oCޛt9WU#]СNxaզ,5 nm.. rÇr=H}v^i݆NDqE.7$n72i̕Dmpcc#wZyY6A`#@zWmtG )S\pAhԩvS: 3]wmnY'%zĻ,qEg5ۺJ)x 8/h)7jp=]#.OpG=2cH҈$u\c%n`ۿU|un윹޹ےcBu ]i eJ:NXͶwFJ6IE޳zQUü.ƶ&w~%pcUiѳx i.͞*a˒3G-rE DZ0F\ۂp. yt3Bs5Fm,4ܹgu|*PY%U]:-5P,^}X)&Bd`.υDEwkL+Kv҄} NC[[[uuuSSpy#GVh]6Ǚ㬑Ӗ.ʮȞ2 (i MDmc z-MDCevRretbu?L0"4i| w $h'p[L{c(-&R)O]=m]a' y,_c̯؁ӣ尅VgwwZBBеSҹ1ɔb.'ympV!87![i/ fdP֩JI㵒\(AFK['x^ T*lh@\:=ZL%aOQQB>P{dLuZ̋N#z*>dJ~V"wc]HQIW/ƺ"#G,*oH[Sx{ 4ݿNŠn{d/Ln_pXTq6ާ)e[}uFZ$m6/^nxZvxCua;w<==a͢` G'Dg}6Uz̘B@:{q d]z'A544qR>&L#GڳSs=ݱj̠vwnC꾨5vlEgݲ5w_ ]]zON~VElg6 qK W{$"ەK+vsVI aMw_ Vg!k>!`WxZn-*_ӦU 舼pi2=mI߮@'y^&Qa_)d?1\JpRNgQ{Ƶ4Ԗ]t%5q`c~R+w*0h@^oR :yB?w٠m\35f…cCt`p\"vssp=FC_4}UQ0H+!o{ qtHC6g\[)ny:,{AG `F\*!vA"ОG8a 6&x4$i>m]ӓ5/1)ͼY~|$ دVD;1s$$թ̠>E'S `dkj=K{Wbr~5wPz#5*g(9Ƕ B ذ,Lˁwu@/XYO[OcR~uy9K6/Ƽ}8*PgxiLt#166 1J_z+!K& uyxĐV"x#./UݸQdin UUHl0?rO3@F9ts(efk1n#^{Sdd ;]e{3_lj?3Ǎ *-`n69cSҴ0/zbkh IDATUZa5YLcRX`|>5GxE+( 8}z/$ɫ#jq㖗l: R]dI^QI[s ¤BE$Tnc(' ;a`Q T=%, $/$0724҇ |zCKь1b̙jCkS 4>IFe.|y֦bSfP{ w>~ fEn8 p1w0=e?nc/PIϙ}1%&1؇\QS,cGȝ oP Wڃk@M1K((s%[ڷ{rQTRzIn!rT>wO5*Wj^Tpxw87ꉣt7+:%[˓oZ;%<ŻT8"%QiYƿk {axMPNN@{/e!XGd]!ae./uG'?R@7TՍ{JuҊybс!nfp5KGWWp.K 6ݗ2|= (cǰ8A3Âwt8s5g`k2ۄt/,+:Bغ9viюe3a\*@ TiQfܶ-|J4my%GqʺNϏfq`?90֨ZwӢݔxKZ;{ڱls6^l(_,<~xv$nn_q6Ϥ7;~֗z&^ ΧPE Q >GrFBJ=·diUPT'-3g>IlUp֙&Ǎ5X#ӥ И;;ۯfXzlWN'fk9_ pxδ}ww'{)Odb]?+fS!3yJܘCɤe#l8fxK'񠇐9{†s84|1֊2[/8 ;/)uΈ5;n^[d@s =Ѳޓ1XX>vhZg |dliFG,P!pV\vvb+]H+k]Rtcцpκ6m--]m.KW15QS&P']]E*mfϲpr|io$^w@5\SP_ش>[p;N.o85!sl|ֺNy<yNJ, 6-ZQgV׼ 5dY#gaFc%Pzuk=3У;?F9#ҪnE&π&y6OI*υIGu32>d+,E%Y NwwC_ef~fxR of&'n7Bp(X/;c2LY ݾ+~܂deg i:ej6r ҹV 34=.Y"׆ӆ<SSLڰot`[԰Y$gX$P/gWm*ceK &8!,̚5ôE`P]>r1IbdmFO RQCi'Sy N]5hPv6;N'R\OSNO}&\/+j%馡!fyHr&>,,ȃe|sd/Dz\M\(w͓ahqĠd\.!daN>zObhv45"MN-  5-:7*fI4sD\NtȎ x&!}2phv\<<~a\.ݸہ,UD(hgAn3v: hf:UWYaŝ)`XV٣<>d5XxքYy/xV D7s s޿VʾTKO̓^ A^:54-"@ fnfϸ'!9{,0EAyk=v H&r3V]iBE9^FH İ|yUN龹()X~2= mcf 6rIpʊ/7)缷Qx1=1UTzrG+;G^NdAs\ͣ7ǵ΃~?7I3~||a'w#>כW"Ԋw-np$ 0HHMMI>k>T l F[ko?`+4 >76XpI}VYT"p5YŹ8 GߦP_/7›G*8Un 9"{C-EU9WVZ: $DKxFL- Ѐ5:a\!&x =@]MJ5 !?膰(\x' 8bM  z}KOMCܞ: 1RԐO@GWK8^u Zz*/;174H~,ߟ^\RE6""z"!؋ I ӈuGgA#/L ^d x?U6dxW \q) =~K{G"x۠+ 1 fP{%/N:jsXA vJCtS F 2T)ª ͣÕYezQ`H);%n$q^So{myxa"/S_Fѡ'\lĆsҋL[5+0Lf'psp-80 ɝ L{Dr"%~6j.ܓt|96R5<`__5i0NPN0v֦)0ڰT_]/`hUbB@&<3$_QySFW>IG%^,܀' $eFzpR=I+*`:ⵄݓ_Dqz'YqR2p EXrsge.tQ+NH:]>Una+.'X$'B_ ?F0pС {b䉻4FKy2Ri+`4ۧCK᳦! !Ow>=w.yɥX?̍C^:UB%m0'$Ww×c͔DnY_#MnVuDj 3 d"6qrBNM F@#)su$7k[CWkqXC3H ` hKK+`ppUPA` 0{lRHt~I׶}J8YgF=OmyT GDzs靼g &B?<2B+꫏;'.hYo#Hb/ٓlw2Ÿ>n@ ]);}F阠O[ET,{lpmOScN.mî/W{SdA k>i~ 6Uk6wzYw-w4^J>8 Ma@ϾeAa )Daw\FV=]0'h [j$9 lVϨKpk j\arp`mHÂMZZ:CL ^Xx/UIa}@$@-vg3 (D)9Bt[&Sx(7tw~ Z_Ć@ .Zn2@5?Cph8ijU|<|.]X.=kw(`us,Tӂ@u`+>1dǕ74HE\P6-ϮH0(](ҢQ(\'*_RQG?x(=<<:`c4/u>|˅ 1c, X-eX@d/GyI)}O+wHk睜%EU#E"sE~Ĥ ow5@>qBu-LC s0hAb7P%_'dM ɖBJ)d0hk`-^𔱼g IWU1 !zP -)uĆv,-e=9Np~ ugUi޽c \]#p{X r޵ ݟEw/[_?// * Rzyh45t3Gۓ?($zTPB_ {dgfil:3הPQbғ(}WC#TE 5L+>x_$ިq|,g͑Q& 4)@Ubנ2Duiq%ʬ)HB6\a dƏx -q#0P)HpΤIpQ|:;$~46ٔՠo[:N_$l E,`<:o|ࢸν0.(BrV2JS4)% D &ozM[ \ 4Z1Mb\r-6WXku7WFe.qWw93;fL`9=s9793>_ȁ$ )>bYv> Xϱ_T322z=س{kͦBmf3]T`4j7 NB=*шCR0EFˉ'$q+[ӚYۍ5T Yr 4e?߱*+W6o1jaj tKRFQT` L5 裏>vgSS/>V ĭ6+$5ofԹKƺ"z u,0IOWTl~, "~anQ9aU+`&eO2/j= 䋄#Mst0Gf\1ͯoH׌E (GN̑ՁH";t[t>HIzSX``0-?ݜ"REK߼Jx4BM%04WA A"r &^rRrs % _"kW.]$:}unMBpw/Jd űhޥ̑`c;/@"c! UW7:s1ۭVP^l:Qz4Id #a)bXe6q3Y@S;A45 * 9<]h9_2B0@&$L&R2{Q;UJXi|#GYatw6#F_”ڱ`]z1W!9" Rev!\¤w ȣҁҹw "Jݓ#5}&@ :Q\Sm!טWSGdY1   )rAb+qjJ0D >#7is9 IDATNڿ[5 $q@$x~Od"U(3SgW> ũlm0`bjc'`k"dؠV[%iiה?9)D{dxŀ @ [vdCjlⰽzCGwjsWLJ;i&ZKSϷ ,mUi Džku+֩'=He\QQSOٝo)*+ I:%<d"Rml{,QNfjKܩG%ZL##&SÓDF5*iThpZ.t5\ Mt2P6."]exgh#e0ۚ*TXoHV̜1SvY3fnًZR$б~6))&_Ջ׉ԛ37ϪZrMOT[@nQ8BlH/q:Hkb6ua /?"DA]h,)#)ث1~JC6?@LZ`>Ke޿-mHDt!u:20ᮐpGPANBwW[=K67mmu`k$D:1iGƬ4Lup3IkJۙа/5 ӱ]<)= }In)~ ,чo R5JR ߑkMxa s K.jЮMuڂ`eC[әgK2U Bu=iQÅ֣.RΧdzO+ bmN<:B0Dہ*0fth'0Q.VtQ !r9}Sz̄=#vY*wc h"1&gOyJ<; Y\6J'*`!\ifU1^D:^eȶ8j`x8+w ~^H"\2. r- Cޒb *K:=_ސ4 |w,TQ;'̽D.2k?&w^f"JB4' tv\1g(iYୃ$|*0\b?l!E$w)=^",Y&0vK _.!{wsV =Q 2K ]`[z(CnyD*Uo o0[w=Ox=[!gaGP+Bn&t(恍k;P EK˭g_eY;m,У|xY+g*3RHF!ph7׍ CT()pmʣPcկA2hDɨ2{ҏ/ @&@MM/??XwΜ.B*}qfHfTƒ.xhg":TCHN JSv+ ciFrZzچuPOJ V@ UPw^v*:v0DE'6ujm`U*oTP(uCV:4dhw@9U-F,KihщumDLy6b2@ J|Zb,%2b鼟^z5MP3 ApYWi>UbQC*'ܞTAQ6 4PTpϚZ:?ǏkSN}gϟtxlvڵkW^|d\`3:5pBN:"LoGS; Bu%ϙLvQlɊ%\__̉  !*' Oj:* `QT: ųB -AP@P pI:4Kl-* Lb CSnfS 8 CvcWm}(ބ&Sou]Gk g7q/b~ )^=u'@A1H. )7\oê#l~;a; G3L0h-KFFI+[s*ij cX׸R# 56cJ4TV Ś+tH2[vF7kzF)7 u"A'yjw[f1UnoȑjL򮊦KgWuIHk}DWƬgĊpL%Iڌ{F .Jsbu F fmc2Ӝ~ 'z>|U@hf.-(* LMbʭ.ksMU3F]!KIp=.E]v SZ@$@x G )Ͽ[QrxVޫGȆ5^IOWն1V kcJc 1w&;9Rkʹ,ZSDȧv1 T}3/g; .:Y1v1vcҀCNq%08%>/u}/3E>;fDžiDyikrSꠚ\Z['F7(I(%dT`+\ `"EՖSΨm[K`pRY$@se䟦]Gl޶1]3q6~G trN%\vGr{ l≻Y8\\pO̿8' 7$KsKIz8T|@j5f!p<-u@..JU >{09aj%xM>clFX,`q*Ȓ724dIDX]HQ=Oҹ2mhiFzZ@τYs\@+'NtuŔD撁mR^}4jm7t>Ep @P A,gK"y2zӻYߔ"X@!n~DO(Z-޴ 8C\w[Rz*= Z(UYݘ;rCB#cٖKC2tgPAS6bK;n* Q *+t?n=ث/tСe +9 ݿ/K.ж-nj'ڢmd9q-}4G}: 5{}|= s跀j;H։{(Ti( K,u-ty6`!̼/~CEY]? te*~_Ƙ cT (@H8s}>Q$֣@脰cME mjjGp*8o8u}'UXխel֌^3 s QΏ~_uH%E[3 +V,lf(fH[MmYuy'w65\M!=M2(}t=@xrzMäc\ o%NTτ.Ϋ^>=榀YN ![>d%+J;w9h vh|Yu5 'pfݏ(t#zq0@ @ŧg?Pp"GFLMeQGb!fە+7 oc4%|ˀV樁xG+֩']u4r /YTez`3Sei-[ߑ UJ|m eARjD T֭곍X :ߥSBA`>yXì~8v"iq38B,jn{ac&]fB7=7;J[4f_2wS ^688';97H7rqHHb͜1SvY3fnًT2tgVā.f!%ܬSRL.w-Xbz@ ~zqxQNH]N9kM^VQ"URE6@_z.c3IsWLH⠮inׂ Xz0PK9~ Wv1 ~;s~ rUde@ +j8nDVVlOKq#?f>nc |P>7!%(yn^6`ÈG/y,o|`kY76{{SCqN\z@ NB! |\AVEP* C 3E*\rr9ggS)D 0S=_DΛM\H^8J48t\ߝ/88a fK~ӏ]JÑv(Xh'D*WG1?qtԄ $2.Rm]ױbV~jnJl(,JT'oRPHHpNYĐY%bפULDhH^9nX$q˫ڕҌj`#D  I.АeߢKFN_nf ,1A6AF 6ndTЂ˫- 5K&{@SYͿćѬm9]TR6C{;@TRKY@[o[$.BYAĽwyɜɅGXQ~N{s&wq%}Ly4,NQGi,ĩ $j--:t""5AP )!*;tX6 byyYb |F y>ckD|^y*q6섢*i# q$YfIhY#,gD F|;4J(_4yx M*NMn_k 84YĉSú6=ۿэ: c@ءCz-N!;1'be=7湶 WFO89i[#60I6E c IDAT~|=Hy%KѓWoEޘ ò?L<7 :tC_F_a[dj 7eq+7ڣh  qSCO⣉<-MThôXHTS :!&T@Q@~B)0 AAиn 4FPTS (:;* )D C~|!f^/P̽^vCo/C,ػ -EFCW{*0bHYW ?7!\nábHgܰ#B|"%&' ?l_{$XgecdvdPeEֹc4ҜCPA"0C+QxZ~&o}-j~TeAiL)<,};~'%̮{u_MHA1d3do-?pAk%H# O|;+fTTA1H$t  axoOj8zS>Q&U(@tf^!eTYx"x"@; O&Qy`#)?O}]-uP%ֳ6"qٶJC~mQs]f ?NX"Iz<#҇ MRZ Q/0N!]!]a@T{<XwΜ.B*}qfбBR o2 4o !$pN%)J;m4#9-,t Z[ICCZ(:j&*:v0!:!԰^(w)IE'T-ިQnR #HiqbʁsZF-X,,E'j 12Ed4Qt*{FF[Oi>^c1RmtpC3ALQyL*U-=}ѯR{0Zo@ M6z5#}CEd Ig?~\՞:u>;Kf׮]z˗M&{phHޮzP٘||ǷCzГjN, P@LtlTx_ĐRO􃈿z!XcU5cQD1I)Tw$Zܷ Fn|sKqG$-:JWNC(颂'3z +_ݼ,eihd]q"rxxxp@P  Ag2wϊ*5Q.J;0H3kr[fK-oG{(H(jCo)L'Ͷi(FFQ)ůQU &ؚ'ĿIP}]R֑=+O}=axCV zϱRFQT`| DC m0Ǥ!GzZ?20IKr1Prڋ-"'C0;"J{rK[ [`=;}]cD _2@|FXXEmzoǡ"ZW,WԊ]Ð-@m'A KuEPA"Cj32KjuKuI_܂G$}$[FI R"5,WWdIBݟ[,k߹ӓ/L-WU\H6Fz4,+C _VxG<S6KVS5ISP_YՀ;*0~:D5СQ97^|4҃G $b6J;ƀ"Ӱ.kGXn\Mds;5Y#tH# @PBF޸w^HV,&3¼ƀ"Sj_\G(\mPFPTEg3Ԁ"th_JcjSNTAC_ u 8MDnp}tÂQT MB* R ( PC-@PNnB* @p r;2tȽ _A1H t.!3'Brk?],ȣ>v9 ;ƑG $( >C:UIc';Lsߐiu 1ķ9AP1(BtYg=P uroGiU)uSSk=lƕypd A'7E@$n)Ȇ }']}z-ġl :z6`8TB6=s˧5kXPyv^ʕXP-1䟧С*_x6Y]n R+OYҫS-L:7),Ց+]VVV\V@&@?n!th@{t:uAO͡8DiH&PNE3>ND\%ߠ0 *0qB8tq+,$f&I]UB"Hb !(ng9q;l lIrS'T @7M]`iZ VQg>dT&+k| @  O@np}PTdӛ(UG*ṡ*5)0 H;3& ZT@V4dN=,=߲EVGPT, qwN##=aslnznhm쿩㾂*n(ۆ&pvappx|C Lׯ_|[[ou͚5\k3G6u5ofT[u*wӎW=Jaԟ2'%<v-gGF|ZF&K]rӢ^GSi~9RUC%˼ v&?GV|LUnOB.)/u$$M(rV!{V4b03* A)1H̘1cn+,>BDBWνLڋqRt%/iL=m[bz`lLH:[AnȨUXIxdEZk3B_K׶p` #lau{.յֲKH֘eOm> n8̅ *M ~G;,X#$Mp{~ZN1#{[ΫՄ3Q`8ZvŚUr8jXu吮ؿv Bj8Lѐ0ղsc^ƎMeFq A{}<+c9z ^#+$gi1@z TjgBBt^D3iYDϡZܳCTF3*{xӷl=˖k7s.b=/z4 %ڢf!LdER$ƼŕUQ[ my:^s}n*"ԣZ5:4-4ǰ)*ˠ׀5 * LH2HIw}J!̙3-[&B=a| [/EW)`(iq38+jn{a)6%2b꼬ZV ?ǃPr#eS؇XO_8.P[gn6g=wi"f6JwXG執GFLGrœl='ͥe{`hQuŚ-dmpC.wob2|X(4VC:v 0G=mMT-}&/* ˦Sڋϵ6:ƲZeh0$?wy)II%s7,BAPM\̙dɒ>8{l]s_8wi*`(=ۢi)V u,B/\GHzbcitFt n00' Bv`|=ĒӤ%09FgE;ll~}C*

j8l#kظ".N@U[KĝKmlڳ?<+h-E-.ۏhOR몪 ծGXGWL`%s UmXn0bdqxl(ΉK\ 1 )|r/Zx18y2s,9 BםΝ=+n^p60,<㙙yڧ٢j@ҙC샫{[.qoD6cM.W4m-d3ѽ+] "q`fbW.hXM76lQ@tJ$ уyJ̖/ЇzVv%(K&f̷Q M9p%|3* $$ L:l2W){C_'3vU+[zY@/vU}E$,a>ܯ?/O{rK.%)B#afڵۍ]*wu$%Tí;pkiDP!"Ɂ$C {WᑑݕF/ٸh7V|n-b*F}KnJf . /޸\Өc ̹vUp%U;l7ݑ[ 9m eŷ~(xZ; og KW]'Vn" eIJlHF9fu_KU!HjNZ5a䫫Z2-RFQ_9+%5f҈K҉+k["e{$mpй7R˜SE4rD̤GtU@dU$%$$l93?q~>>{ogBU68[!l'ՇQVS5rmƆҰ,&  ¤-/C:Uݑ wZϨUҰߜK7Z5 sD< ¾O(IofʳpMÀ LP/Ĭa'5ꕿXEdG_642~AAx8 ʴؤr "4*;K1ۤ!$83XFLɰ̽=3jqt?tQ-࠮9-?IMrniǸK!w&ה*RubCe"O*N?̚5+44`W* -Bǰ c`f0 }0<0Bpn0q:vd.=;t[وys)kܳkv" 7vf|fϱTᙇw;I>q>-C>{$pvvy^ I +!Ȅ*ीm]MG?yÃ4 ']7b]w w TA1HSk׈*|ݞLF![k$s7&OHi;A d{~P(89!]:c;{X1ʐJ2ϼ.$51rC 舰А;m# ($(s6>h  Śķ̸Q`c!^'׊i?'gI.C9 6nܤ#%*IQ43Jb7]o ƃ6e ڂ k4&s0}v`ER :=kţ*t śĭ l+e~O[*SC514#c3!]չֱWsś:XqV}}Fjvy&UWWА/ I- V]Cz]2S0QS1KTߡk*cCdꥏ;((\ |zl"Uzփ{E-4%+~ ਼kQ~&hvK+צBTkp}C(#6ju X4;>M6!a8ckY”kD%Bh^6@n@ [vdCjl9W^/ ۫QF]-:>vmdDg l6o-LYRqs)!ƶ?ДIԥ1763mY@Ose9=ƾ .GgMMٮJ˲ִY,Ɓ4_Ei@^|gdL;(=4b;Jov٤׹\74\aN~9 =FmúB[p.]RgVB 1dZY jd//i-bQ;!T[@$@ G )Ͽ[QrxVޫAvCo`+x]fQ #ՑGCN,).{@MgY'p@F(=53.͙9 k E[{c3/ 9r%1 >EV88?m@;Ffƒk>2gu}w Y<;^Il2B7-7cGh9-~0!( ͖]fOnT~T.0q Ԅ7pvvP4E EkSYD}tߍy٤sh}͍T_ +UP+ 9>GXҎ?E @KxIB.&?DQg)eJ۫u0c4$Gi$F5eM<'p(?YuDmkȣ+ojhM.$ YѾNVe4rAĐ_MJjsfސ7=^#s4%f.RoZ Ā T  oHK67mmu`kp@NgFx$x6>ion03-OҎ{)=WηYwءݾx $IKcD(= XZmRHg3O{Pq@&U̗Oj_MaސUT-KT,zQ0;%ϙL?* LkyZ!E뗶 W.a%*p3! @(0uZ' thĢPT A(BƓEPR (:4Y @p  .u>*g@P  G3L"TA&СU=v?'A@PI t(xCÝ%Kx    С hd*pxDX* Z`J[1@fΘ)e3E :T6ҿQЎġR):n9 СHBE!BC$C+[6XB,t(: ! !+ A:Tn0.3'tpXx!WС?_C:D:TСT!Pa%@ (X/trB>, e"j6?O:H9rm:(* @0):d^.:FPT` tС`q*PV  t('i ҳW:DeD(PK:dU1C B&BA}]fEx>Hi' tv\e6@},&XkF4,op@FS  v9!TH tS=Q(LYB? 7FPT?y APAB8qDg%0* *B :伹6gc*!t(Ccǎ!tHP# tC!<(* K_Fиэ:4>xHy@d߲lE)2CfCgρ[1ua&qY`9ʾխϕjP/LGP+oA ;s%_0|p4o1W,Ϋ޼>Q&UhZvW>m,ˠzn(N !!dTjDA{`}cś !-g'CG=[.Vcצr9ڼj-ʬekp[UWegbGIjI]QTS@$:DlW){n7U땄LbSf m:z^/KxFnccr2+V[hnT6a$vY{Ziw$C]#}6 0lQn1as0dh]=}b1T,uf]6i%˦Sڋ]Auaݪ>ۈe}H_S~ݾd3V4EFZ T/+r*r;xbI]oj7W|;!TuE`Gبp:tell~}C*c,bE)RN_D|jSA"JH3+Nz0k )\iRھciH z$d'NL lk.SNB4"nBWB+6%m{;h&A.!Ԓ*EVL)c_  !h!5W.YQ%?&ʚE v'cMVb|4)|;&DJ;,CfwLw-5DŽ6ƮEk-IoLg}[Wӑ pT(*4G|&DP(MCC;̘w)lPi%rΎY@%HtlO w5 b#ڂwtvs$! WQy`ڹ;  ן'=e.9w•d~V)]o1hr]o9PT`A"ȡCFahKjuKtneJZH*p(n%)µ 4Mxa aE ڵ 2Yң El&Z6\D},v<âןU 0dw>X%GH_ٖ֙˔ީ-ȎE ;&uԆ*0:D t(wli\&LXV"hfI.tK[[<i +PT`| x=ƍ/TFTB>T  С}aPT`( `QT L7QA Lai* LW c:`QT e ZEIENDB`testng-6.9.12/pictures/outline.png0000755000175000017500000021314312732165123016453 0ustar eugeneeugenePNG  IHDRMYiCCPICC ProfilexXy8To,c'=AdߗlYc`%I)*VR)$f"ٲZDJ3[zy|sous,|@?H&j`mlԯ=8kp,o0, )- 7|sORF[QC3`@0G)e[Rp9 xQ Ƒ0$Yk8ƌ]vqzRtGb%y{+M$j}^w $+0 <ïe8f?rhÉ;zV?ܢYA=r;=mo/± - ~!YF.zk P ChBnOSQibisB7cY2e8Zxo^1_~`dTAN"C3򛊴J@Ն#jE4ifi~S[DAaѐɴٺ9!kf6^v'9 dqtvlE?L &'= ':<-uYsߍP{R}\WēSiW_Ξzpܭ쌆oe'u?=7ATWs#B"bز U55j=zjLAM^\imjni+j~ûٙ%۾ץsuPpHh+̯$5c{.v\m|y{l'ON>}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP(&I-Zv~ĭ`|ݑWFF,mF4l&nlI+(Pς֔֟ԭ[7##Cm """&Y[["}n2|_."S(OrIY xk#aK,K-B!n`3_R&JĄ$17DFp=4}PD< 2H${s^W݄4I@....&&/TnY@opW|~p\ ' ﻟ4QSHS*pf@!YkvXh533 beHt&_-=Tdr 3_dQ% ѫ?4JUWf(a2gρFP,@7p\e&df!}#s}=B H$ mT=^y max;N< /}\I<sĬNy%M%u͂B𺺺:::ˠ+XAkF{h&\s+*۟[<ZYEṯNƪϖiXL"?gTG RzJcu-Y -hh7g-?MO"p8''D3׋8b ڙq?R͉Lez@IȤ(pzxvá.uRM̗ũ֝ۗ?L ($l XxPm>߇^?LE.e/6Pnkj>x_Tl Uo.S%ؽDf~4NCsε,n*O1yȠ^5@_WO,xtU#!&_nW[ymfX I0#g~v^d',?y6=V=~2%[۶Ӭ !>Ӧwݶ nyWφ=h#8Ǫ?Ŗ"(*O?$/y/?⨨:u\FWOT<(AlZ;eD])))&&&4D xȣ3 lBCLjg%zڜ̫x6!/PW s IZx|e߀i3a,xoߴs}w61D9[\|Nuo&\G䟻KWsg{R_3yu'`##֗_Eln ,# (}Nb`10 $h4t}a@5D$fDH[|j_MyچzZXWC(M+FЄի8իQ@T]fýPb3"3}> [pV0M(d ]~_:=(X/C-}FnjdQBdCvZr.NǤ p*X%-<ߗܴB\$']Qj9v[7E- ![o'3/O3Xs2!t sxFrqCE} ?"LZsHDP/\Sh1r'C70v/~M*k[` LdB:WA;5⩖SDJN!W[ ʑl m}xHUK)2{48, {`׿^ժ@,aTbRU=]j ydQJ* J Ze펔ybyAV FWaRF-kh!Ą2z_I(c:pP_"XrPDE,ɄehupT$ c[ -$ Q0 ڗ-z:gHKPM7M yxߞV>RzZܤ>טL`՟ /k7+o`-4z[n.➽onr+|C[C{ɵ F4N8es!I) Q$2gBT1 S&s>H }u 0wͼ}+VM79;1l!0ju X43'|@kP-Y%AD JNz`LV >ӵ\+)GoߟΥ@5Rh4,> CԎEccthPoeY砠+@^ + [_XA%s+lp* % xh3.^j镫be"VCB Y'09e v-` X K^4ڿhpl\ؾwq r *}C7"e*RuQ]X_nV(2$P9Ee@r(;+ryE6:/@eBtͣw(˗,88O 灀 pzD$+\mm?-{ҒRL ͌tٵVBe0`43~V+K_yRM9gIf]z,QQX*d7,UTߓKZrfhrDW5=|4H6evT4yvGK}`zݝoeP{NuL ~hSv烯M#^:yҀsӄCl(G||8$:>Y,M$G|K0W%|IMIsNm$#y~b)fBڿRRmk{] ƛ+7^ 'Mַl`WŹ͎4f̚t۫ވ#kHQ3ɑ$T1WB/|18 QOFRA'\5}w Jӄ={c\ z@ӼWPA݃އwǽw2^_\Ц^jn㘑kjWȩ]جή44* k׮j`d"A0<>YkepLdd4b.::u>7ؼ @z r!Q'DZgHd'89_v"Z$ZBjՃS!0_3bmqU7s"937sa!QVpҢqz > U994D>\9hAs)*ө +Z AD 6IxYõ vэɉiм&S}[렄#}"UH\}d]D1s:M\Sܥ+_VjZZZʧD @CO+X~忑>F}NNJLM5 ;]Nd矞}45xx*+n˥` }9%Y+32gCS9ɡJgE^E=èт(Rwv }2h$rBBq\LA>x"r&テ%>ϣ(w8l;z.sxKIx.,!=S-G ~y >P'Z˰)ә_54Sҳf攙`1VƔj#rytdw?}}zx/s1(L+%JcN_4ٯO^'} >B#nG cwN$J;k4LZ&m)B9;;;8Of'i֬=]33#*_R~S! >SV>Zuג+і-FNCDhmC- b0eUT$58c\+Jk&~[4xUASܶ恨WÒ VH~7hҕy\GWWuV\\E^(jzfDus\D(m)#nG 7ƻ YͷU HNIPí{l  [%Ph]큀[x~|Qa(O _KyCj̐YuK ##\hYtߟEk!nv9S_Ehu\nBxx+RO3<εi g[.mRͤ-m,V\K;hDC$Z :=A! 3/KR}JUkљk|s*hTkEVAݦ(7V:G}'2~ܸ"S.C[u}wxRȲLt MM!3ؚؿ6BI邯B[/xlGFRdA,sX}ghltͪ,ejt7*,tzid![}RLRR0swks'Ʀ~w8;$*b\8$}r%C:ɹ}d^wR j&:#bTJRh!(M}da sC,P@]-A~qQ Q+8 !*E5hp0NW2t9`3f&% gV 5B\-H:0lحK[gy ̪:ҲZ@ZS*]g y=rso7;[㱋b:%6!Q/?Yz ]j eXٱ[[ݖJ& 0'$@6Oca6kVuHG@}-i߲s #",VRmLjJJ ,o?Q\ްkn$ED\<_<øFm6{ p*y_x3^6WݷtWo!߷)fmh Zf.Lƕr}%He™ujoR*Ͼ$l($.L DCׯ̾{Rw,LJ= z@P5S`yP{3atrZ=3t#)! IDAT5<\NW'S/c^_¾tԚ;یXӮUA^nN :}Mچ<6(ܻO|ON)+5:j#eh5bn qZr nW`w#}ab5C+NJH3l[vk0)0lWdCszCo"5l2Ḧ RXݻwa)Xf ~/͎q9M hыRz4g}K܃M##шwfk::8znlͭj` `$8u+)"3ljպ xY+9۶mkp,6֣8^#SȋD2ק<9#0%BC}ȩ%';[BIn[J)taԌFէ58kG'1 W𡜬,Qbjϯ"j'- s{5Ѷrە0ERhVioB3ہ'ζDŽq ؂͎uD]f{H_Nw%rO<{\wp˘S^^w2Sc_©Nկ۴C#]q|Nsb K{][}˯Ȉ+JeH *J8篿[@i j@-EEE`i|@:[fYB<ŇNJ1ضL)AaY;1a`|(drkхdR/ zlފ@93Y:]7ݪYܽ~ǽ oiYۖ=Lܲkyss`Qg{8')tӣW_"K2jD-Xxe^.;ƁpLe_u 'k @|ͿpwJ8 2B>ICuRQ4& \jfJMЙ,%ǓC*ʱl8"fƽF~@Plp( yj N,1m|/N:/j;TvxDϏz};+Q[OSJ, KeE/q4i@PS*RʝF2,pIU8ܳbw [5L< Ōq@{aX?X3 {Yػw4ļLQb|85tLFN;8Q~Qܰ4,X\F6vǭA\~JI ~ۻG;Y~ [N bG;¯'^ :04"_SW+`}RN]Y_dPJy>gEf`6~=Bf+[J)w_ >cMtLseI)fԐZ {J26SnUu\PX@uP[&ʯ. 1/SyI:, #gq:m~5CqC,*Rpj6vh acʶk";z-gy^8MWnOO^6CTL|nOOi4ڿD`f ):=زڛx_J!RT-;/_8=t_8oms*(Q_,e SDn:W]ʼ |ޢ~FpX 4,,AM[ #Hh&nzW\ǎ2)klc1 cc[с+o?צ[-Qmۏ Fz6 y4}xv_,G+Cmݚ`OWfC-9A:M&896rԜBMJM `14JLG§BʆHMc)+Ol^,Թ_KpРñ9@b4@?qO %mAAuC$U );_TJJI*`ӠmPƠa3 l0<=-EWe y:٧rugQk"pI$D/!"yHh*P@cg)=Ydyu@}d8 =~ Rujk o-{DYPyl><9Qv:)'K+__% u]“xUT3Oxb Dj4K)ݏ(;>ڪ`,t?}5rb.7t) d3BQL=VAk;/=Z%?Z4|oaCLm+3U\ TT}B-hU@Vjdc'l5 `j8%Nrb&MӊZw)>lY%h)}Z,(X+Qc̈́fGłkUA 2K 3Ra)XYXvY gRSM,!nS0\Tc(FU͢ qI9   mR)DJT0 ٸ27kjX8iT(_Vo~,,,VWĻ։EEE ?XBl:@EDub``V"""P`ElQЈ"gPuoCUCE%˩# x_QZS&wj NS G2zH$V+†v1ʲ,~˖W[uxi'_[XЩ0OǞ!?\Y28dWf3iUi2aT{nCξƦl߿doEpz}_*8=).Q[V߿rM>P^S9@2>5Ov8p-oKA/L%F?]DqsOq!ui ֱ7/nYE@ᬻd<z_> ,˖0 r֐Ak.$M~c1?7w@ |dnW0_?}9ί~ጚϯҩ#__r!/4⹒B"GE)˰x(uZ4lD> ȳ'e 08J39O+kc+cLz"wFckiG@2ڵon 7o u.׸v{]XvYXwQE>299zO +U#QZ |B>#Ti 0=i2608~=ުUz_ZPV@|E+na^kkkP+6Qh$ fyC [Nf* /eX$UЌΑ R/dZ;w^r Oh?f>*F ̉\|w=U]^YHAuG Pؗ/ϻs(M,~;lfys)ɫJT͚5A5o@$i252@tJ"D3=*9"MϖPqPj>~dF/7_IG+)tfPա< ȱj^ǜ |>ԅ")[ټ4jO4Kq1S./olL= HRB^O2ɣ/cֿ̨gcr}ٕ-m`DNyizk2n֡hNXQv4F )+0Rf@P E> 'Eh0*T;y3(TdJSK`d@pM0":718)3|"I{/ŐCcb8 K9wݙT@kmkӬ?ߌ7jds 嘛TpM- x',ieֱ!rP/f@KKN_BThVLJ~ @?&j#R?;`G5A>Oڡ!/Q1995-a3$Zp^U+-i$'km/S|iԶ!?e+ Ju4ǃs~Z)SäQtDFalx%2lߢA@dIZOU.÷f+I}7nZwFYՊL !e!_"I"[8U k jMBW5)Pʣ+DdJ3) 7 ]+ʳYV<λ$Bl~s0jև`/ \bJ)7/ W4"qX)R4ets%nS=ɳ%rEk& fǟV"dfMi'ڍa+cV3M=҈0Č!6-hA^^1cd&Kʥ\eTɞ F#v G(QD$|T~AXׁeR=ZPVbAKBT8'ֹT{9_orOڵ.^WxʙvT5h$G/Fx-OSW;Cwj1#OA Y|3ơeiYF]O{0@޼M~/Gc$Jzn>f%o9xdY}}S˃9T{IIw%#3rt="E$.7Kve'6{L<% 3 E _*OqJl@yd W@/$zp+kd$i]d L ػvhQnqdÝ$nƊ g&}E >4I-t8o!;&KJqr@֮|Km /eEwMiߚ4peE|!@.e+;7`l*@A@>O=X0'r, \ ) 16y;Rӥ43~3"t] h}ΜUÚIӞn-qŻFjMhW V"QZ`຦MWܶmY㐽=F ꄄsI:AJ/9 ^qvÙ{Cd a=~VHϊWc]8>΄v_R$s7yֹxHp~U_+G56B9~][t76u'WeHȂ6|ɚ47?hxzuڑYœAEq!3ԓsJ=TS/E (]*~ XAŃfGY IDATPGzeff_|>?%%%111..cݻ̶~&)e|g4>Y_M7y2o? Wy^{ÔV$,8f?ǟܴPj6tX0`IJIu\d05N¨JR3V7"WԬ5z"ԔP Qf:(;c/~BN8y GpzndN/+ZԆʑQWw5d,%cIhLd6 %+Wl5CGi #.,R+\(hkM_Jj|Pin 2crHQ 4s$=ݴ.ZuڹV@:RgbnZ3UKg!0*`=,J~-e 8auC)FzL]6o L rUj_-Σ jylcd4 F=$:D ]?WDsc=,%Icu 2Yy7B:Y7 5u}M0ó{fOxiNck' WG>LPM5}ʟ$q(wmE7 k5٧wr26ӶͳCdV판K]ӤET$mX7/w) Ut2mr|*RLSuRg֍: ʴР\5"Pu\F^ˉgbZ6;v0oUǺ~jO?μ߈J2l~ý%cۏq%XO:F)^zWDūixLC|%rPRr0zp-?QM{UV:/vTլn+yI$\'4xV2wJW|D d}{<{KG4xɔ9[&p{އz B_bH;l߿? \4+U Q |2@cKZ\D-o桎sYT/s[# vO'q>{&H.xvlDr$pa}ljI bf=Rk lE Pڿt,;}|~~d߻FPKծ۠I1EbFw "6~?̙vdJy~^\gSK/ w9uOC͞u]{:m{/Ħr,f:SeǴ[gN+_zoV<Ϙš)0N-}yͅ$ZR+ #{i m/v_=ȁ]I]{JB"Ȣ8i:1FE7W[ݛzt R%v&s5MkeZge},fQ&v\k埅ؐvj̇dNlBb2_/0 ή8Ԋ$Ècǯ\Yj~gWpl*Q?Z9uр [5Ց6=pgVcT8t ]s#ʔ9]VXs5jZ[ (WN}"ɘuCJ2$~ܢ/ #dY*( #GfggTgbe"nk<(}6m3}q18.wK{M\9a7ṄOzΗk.| fU|Cz3g^~toOxs)*@kJ-yU"zӦ?~y p5tCsO_ 0 ;(:u"-vnFK^";>rk6e}DLRs$=>ii3~V|ҼC{L[Z<4 /cցֿ+&chߟ\ EQAƒ\:Aݳ{kQhZXL{N 3EwL|S"!z r$AR:zL7okeb[D[&7yyH[C4z~fT\ikPMb:аT[| ڼ |_r׹Ϟ_$!XlM*Ly0s_Y6CA$Q O ۘ5.ֆWu_[ֲevOū\~&ֱTj8lAG"WH>}ZИeGAJl\*2`X `0RfHR"]jw j-;jb2D8 U5r)FF*U<8y~`,o#2 A+eNj/wsOE#AGeGE`d,_R3 ~*a04JFY(_Fsstf4JA44%?1bu(ѲA@de?@8:v%)΄CY,K@ɞb<`q'M5%U*" JzշLTEEE#jJTJX_)o;[iJ@ihQZ8V)=O{&֕c4(:EvqXY*%/mY35ˊ/GgRJBmw/Fi:sa';qR뉙suZ]v7hK뉦p[}|Myv&PD9AJs,kr8_*42ZEE(Q/_|C^\᜚O—UՊ~E em/\8Mku}?}򔟟߅sN\Ԗ|Ͼga˞\4pm?=.v>}}A%@iQ|ڮ=>FˣU".1q={fddFT"Jtgfl @9\u׵%dό-YlR' JÅi=qf]XO_t\[ӿ4I i͸ip5lܢɬ+R H%8븞mݢ>mӃzSf\ ah6nܴevP , %7Τt:`Z౶MWܶmY㐽=oeY;G{z3EfLJqu[ sZؾ^B࿾.0ĺzڍf>,7wt5'D^Aqw >3BQ/{Ğ}ͺp" y.u/ ;ZOE?Єk缏"t?={Np0>Ώu,Ȱؠ ~;wDd+ʵa,pFq{%|':TrǵK0/8Y;?al~W4 Ȱ19ޥBp'5WCO5:'ũ5|Hk.ݴ [O|DAPҽ]#*ԙ?'οBjM{ } TJJu3~bv6ڟ]IPV8IHH[C[_ +@v.ǂ\lgI'.Ĩ3SfӞ7jzL>f~(ϰ'G-a߿ ¡)8;9]oVCƠ~LAv޽ca(KtߟNvБINR2orlMHnu >Qmm<}YoA\ <;ch|$<=f:v'R:b0Lr'wyMÙp4RFYU[9BDK_ߗ/_ɭUzi;|}vi4k _7VEu/z0#[7c>n#`wk)]-[>E+BX"%r9Gaե,kœ^to96_* _$PE,G[06xb"q7#&/>=l\GfTK1^%[6FrZnQF] 4ųKK5WUFW S"]I6}-,y6ZN0& ҐUc;N+/s 豋3J`$G5(GV8eCtN_݇ P=C!O}gLt[4eKV 4*bY#kK?0Fn9V6aYݝ޿m%׉ŨqzMM%w]bH*מjl-C["r՘YbǯZ0!MFW׎ōFd£=/CKA]n!֠ %_;ýKGb֪ն[jAt3m MwAx[!}0'S땇Lkf6A}釭栐EspܿSKhU$ 56LٲYz3Qzjɤ=]a[(˔9~+|wWnH0ϝ.nB;b <`=DJ6}=!)i+ L{FiYC"0vS%O*))n$#;WO $lJ5k p-Mj! 20^L}fк[xzL.i(Əoۚ/0-a;X>޴-6ܢZ=_˦M[v>cy`<߬휀X(n tв$U;\زyä%`7_ŹK/ G >Õݓiu'"fn>F@`d2xUY@RYJ£G 5o;r4 O}"1λ4A*9>yRJDH*f<;z,dv^Da|Td+n$/)]dDZ\Y, n s?k)=GWWqI3nЉcd%V;rO:}ۄ~&[y!Ryuc CB@Ƒ3}OMY #uf9-Z ;lأ#_^fn|^w[snL$/^ͥG[.Şc|mC Tliq]V 4WxȊXB{uI!& ZD㬎}_|iW;+;L { +zN\b?>ޑΫglγ L d5;ʫ,^ӫ{Js_}V`} wL/hmMrnwί{\ 9,GЙcGՉm3ү[sǹN][RPW |N(=l!-K{uԒCm^/Ğ:[@?f[yu~d-[be^žSZ"r `h?mJ;6D||tp5 ty/[O{l(_70Z q_GG5WG&&#$2CSYbې@ZW)@H/?X@H@_y 5EH KBH T~GWw~K`XLj8|QPKԚ%M8r]ǩz4-=&vu&J3I7)H %C_d,Ww&b^ rrRVon~|9<ɛs]WPM}g8m+ bG%iٵ'/>=m*^?=V_|R,Kgq50Gf;R96+@Յ &r|ʕp~!1᱉L@׭@}`;,W0c٘ИcZ}Nbjy w'AQۃKEADCXߍ8zKJn+AdaIjF|@ Y94Ƣl6fs2ZDy _LL:~=F-ql핞2r2.\\{zXl \Sr_?)w21UgP*sx9WÜg2kez->[&~-I@oS]3Rs5[H"pmvkm\~]}Qcl913vп _GЭ ];{s{^5a " $I~~~^^^NNNVV֛7o^zz޽H@ h {#W _+lz# #9w|z%wv-7Ua!w2印:9\o{.-}-K=2ҳWU2¡ gMV9;U"%QZa$nf Wmd܍|[ Etq_!`;P&$*'BRO 'Y+t 6];Ydml-qH{]7ԤJOj%+ dM7|x1#TZu=6_ Q(@7f9KWAX%Z/p8A p 8pAĐ-F&{_PP e0?Xy"#/*r+j_mͭ:uZpAb ZX@:}q^LM&AxD)r\[1J Ol*=dX|j%/IZ)R9}'o 0RY)gxImzuCͱnbuݤ&̾]`|x,~pJu޵Y 5IJ_# @"PE*Z )MTн_WK^i&hck.՝yDܩށF'"dAe!Ik Ԓ%8n?YeyGL񱳖HB䵚6RS*'5EG B-w1aW>#^ KBPR~5Hᅨ뇚J/;y*+8@E?O,>sm]GxR|47Wk߫{~cOZ}h)9n祙xo&kcNHz DI`X/!,gյԤ^dY8* !<Ҟ'P̤nGv|u"4F(AZ~B2il%8AIb@FGֿ]F!`[Hɣ7 Cɾ՝bU/>c_9~d\[J7wmӯNf7S =r*b^Mn2IjF^'kŭӮwӌx-F'/bC'eNfmzu7uOwE8㒃Aˣd+<[DOڽZr՞BF#k]Z77+0@ &`h_^B1m٦Xp'w`` B~%6ӓWwNQ7^;T9kR׬휀Q>?"gOn~㵟 lZAl;Oζާoy7\opԈ*`xc1aeFZ߶ `N]ePZ{klg=Z\? Sj :nt=pYm"$`X>@H(T׸X$@ѕ2l@H &_7AH T]hnbː@ s@UZ۷2$nOஈƭ[zO?[OA gtRbQH̱[@E^KLމ9wṄw135fVAాyͅak*T7a[2lEONQ\od@Ւ@Xgw^9עENZB G𠐐M8?\D񋫾}.B)]95`O8{ NppAjΥE%/)'ٳ-o'WG]˙@X'mMۙͲ~c^0[f1~ s5%]ww'+1%yKCUFh9ڶ3#̠ ==OKۡfEC~!s\+̤Ђ7EO?Ө;/e>orezCR =!t`u17t 3;^&KrpbbQ_ ys!02 ! cdI-mgNH(oĄ'c8a@Ֆ@<+@Y>5U$=OܭkyY7G_<.?ڿIaQD{QϼCy)~ ;eະnQF] 4ųKK/֔_{E_v}[ ;٧:ZqxmF_ Kswa7. }Ґ3N ;#nh/ 7{@5&P< 0ύ>ѿ"ZՈ_q{} qaH<{g&(s͂;v?H`E|49yM=5;9 _ߊ j'*q;u28ΗHrg$Ib"EԷ2|,3O˸=B6?|E$P Tȏ@&i^J|DZyߜ^sܠ>{!d Z2237lX_OϋTK)'rdX,>k O23Qr* qzP{&L\Y&+Ƨ3/O-ݕ$&OΟH"vV&H@O*_*$9eQRLƚ, rINfqY n77&[WzEFvm&.l&DՐ@X)`)rffd↓ܟ}'A^3쿯;p ȹշٱݘH^l7r߽fKt] fʩb_В@Մ@X0RuOwR IyhhTFIXm2M$3] IDAT夓q 3S:,Yw6yiް>BݼqM Nq40qμo;_\T $1K' 5Xr I0^WJt$DDl7xMtA*S ϒr5.&൶qQf&H+dbKW{h7Ū3<^~dCD&|*#ODW7c4ESUEg4lb].6Lѫ6̈́{ҟg7  <-3ڬ9H rWkx^;ztV8VOjФH $@Y?$~ ~'I%#+d Htp$@u Pֿ#:6"$@|e,P1$@!ֿ5 $PH! !$էH Bh Y` $P}Ty/M8k z>{4 O\CZLCIHtHWxu9Gzl<|Y}_m[8m+JND0N<*A~[`*F+n7,oԫWw砐A))}cJ9 J?ozetv)a{2rﲓ؂E2r"Q~5޽6kϐSuMnMC(*~p%n.\\PMε+ s\-zg]=kߩL< Ȑbfyc WwFZ{ۦv3-\Y'xh'=єП _Y)V4* ,q d&_|p`{oI{_g9&6] 8* DTήf=LzQ%nҶNv}{`;W~\сZrk6+r2gif`'M߂y۴2/dmCmxdi+ * XXԩo:GSNN:boeV栢H TaǬI;q-רLҍOtSypig)o5hV+K1 v *~,khѣ#L68yޭO{A'0moZw2*@ź7f[{5,'v>xݳ̛LȢ@ eheO,p% [߸gw೯uLg7^__0q2,t4)}*=/ګU YV8Ǚ6MzEz|rϬs4n\nPI[j#kv/g | OQBKN eDٯĤ"锡}TӌN"J%%D˺Dj)=ħvmK"d俒,]VvP'5׀ӓOȞ@z/i +&.uyf񽎯j*i;y5PH42 S$URN_a+G\<2  >?zzH ΩÇ,;yc%[T*ϊnߚr*q:-7mAtL4ػd{0Ϭ`%8Aj5%C{ V )V\\\Xl ?>L/_kT2_b ԞPUvF0 *F?gFYd 77UEmZ.amU*yh ,?`U^pGSZ uS˨_eT‘ z"$Z# T $h EH 9FA@H@/+0rhP=$^T2 dfziZQ2[EbTWgj30*ɍ,5ڵkrYɢ j8V^82d*A-G W6=SQLƞ Э5Nb/Iuumބm 1;" &Po}?F_Sg񽄇ͼ7+_1$/frkԐmz.F5-<6)[Nj@95`nyw##;68m}]:;=ӶvݺusqVZDe#J@?/9 rh]{0-j0BRxmڦx:v Ꮅ]w8*?x`n9HsmiγBB"&ii&Zr H999ׯ_>}Z.]EEG~䤿I;02 w(ǃDx$B1,Ɵ~ &2|gCOAc/BadB.YIdA`=d97Oz(DAͿ6){OhnU\`lzuvw.<>?dg܊ C# Dcbm0L(d&lPп/!wFjTsJJtkJ/;>׭wӆ jJJ,'r8￲.^ܝGo8}& ҐۛAxH5Va {ohz!]<~![;{Kwg:<jҞ- z}Y_z|R04w:p( G96 !ph=aZ>Z:mQy=&r;v.A1U$qkOѾ-ɀkM@pN։U!c!`Xvʳw$#dW9Vxq15Sr؂JP߂_Vljz5 Y\(B23 e'`5i*y:E/ƞ;w ʁ֫/:1 |v35J~R,SIJCb+C+E\՜%!\.ɩѬUL\+-zI9kL8>Q[m6 VF`Z2i,wR6'4h V! `kUMz;8ox|VT H {Bݔ9G% wj(x0k6XESc`”meh^˰u0E#fMVB*+aN\#?HK w͏լAӯXd `P/Ju\/^q8-Bƙe!=Hgsŧ'lcaΒ # /[wޠ"(q2!%%!vĄ c߶_0B%aN  tMec]OU3?*ĂK7_=zKPBzɂK,OR*p[ .[%I~~~^^<zͫWRSSݻ އ{ԙ!\R!j#(<)6Wn_@8rRSUt* &eB<"0K'_ׂ=9h;V?y|`` /;?p pa >p"]K_#J"})7(Pd] aN-aVG 6 gx<+gfy ,E?YtYc-gVQ&6C2HeWö9F|*@D&*#OU W9t Vu6fHpj7*|( Hiĺz ;@TP.͛s111a0D` jN yrN3*<*unT`ܭwUWE8f ҵFuR"%XCgՠFR ;$"$OC"FH "߸AH ZpZ@Eqj0 ጵ $){n&n+eod<;›VjڂgGci͵J4_Lļ K[{ǧK;{7>-}߆߳xUCبL췩MjH /0ۑ>᳄֩yc[h}ϟn]B&זIBҧ!k5Sд0c%P]C?/Ŧ|%Kѳci;t kP;~lSmN%邑G˶J,eM7G_h*8Uqw:ەi2gGƚG~BNq'Fp;`6c=!5:ǁloo<n!`+CO$d ]r~q\Y`*յ(S*+гcJƛ{C`OWzzm.X4gcaԷh)_פ(r"Vw뽨g!|֑SKyD#[`ܾaq5Ao3rw@ԩU}NܬCi‚:EPtu$\xD+?;8wi ϫfh0gG-c@Aق ۰7)`~j{]0ZL`αe+ŏޔy T[GUH;\,͍pgGc'P P!pIuM}nk<%T.'qOޝզK[GښJ5dXa\$*W;쨽gGƪ?؄X=tv1󖨔.9_N'1Bgխ#Y4#$<,JJ;H_|asN1# $KYг cx7^]lp̈́SNvy 0:F>I;׎?=.N[?è!AίPX') $b*+%zv*ώ*proЀ +3&FQa{uT,KI#8z|>5O:~!=HZT3гgǏgj ѳacmO<;QwHyUQ[GM8[hw >0=J=`6@"`q5 AH  /f"$(UcYH  /f"$(UcYH  /f"$(UcYH  /f"$(n޳g@k7-+fV!I/ Pa!axZ (Sa ~ 4S{BU_ر5jİ%Jl?sjT% zm E|}sSUV0 bQ?}.P VUa؞jOG~ (-?Uz\`Q1ŹUF, @X(@H 7B@z!_/XP$@o!$B^bH #';CH @׋%*͸5p4Y6vso\ T.=0Љ>Z؏r <]bi߳N_ξ%}8#$@)BZDۑ>᳄֩yc[t*z}aǵ%:0 Gn\\UViQ Ta'5a \]n<8z9=u:_X\Dž^e )ZJ([ՕT649s矆CFF֟n~4/ε7֬ewǥAQl;X`#8"Q)G%bm3r3vbqPSԖTG,؝}ӕgiFrʁ)~ A9+DL4~pǍ?Snnk"=0 SzGtrژJݚ|ˎwuݴadEQޏ}6M} ϑJEBޝx]y` l8u!zum ϒ##~ 'd呂>.ۇX!%O #dCc:'ZU$-~{C=%ӺtRtG}@9%n;;.͠7=waS+2GH\힨'-qx)SƽPZ>(Q`:/6е% [ДH] z)Ի{|(0:ϭA@ K]Չ_?\f]^ 2`nϔ*cEBF~ԪO>'?/r5 Y\[|Gs`G )FeuL?lj'd[Lmrق`!H%bDyL*μ!g=lL] SUAH TpL8݆I=k5aQ]Y咜Z5":T#02cg-ЮHj5^]xwf}w ]cP'|2zӠA*%(Wڬ]V02}m{ٽ61[~3M*NScY8Km hIԱ}S;PYcfxxql =ӽ3 +aDڷo>֕HgT #CУ96sH3os8!߶_0#*qtWARba^a(NLP`~SRn[HWuWwea^)xmR|%K|Wd7`MV x| IDATzjt U_8mG-՞0r{"c̺S31ӏ͋J1qJEx0D_Sk\AR@,L=;q>K,rt:qwQb,WvW(C н{7ګRt*Ws\%x,R)G 6 GI)%S)ŤLQi+l43SD8333U(Ҳ$O{sTKϴ"}W5T%J)9SU~K޸22 n޼9W-p8ff!8 KŨ{$`?аf9'ƌôPE,K5~^J1N) αԦb^va-CH T0CWpsz$  $P mFH } $P mFH Tb럗~eCO DH 0/&te+ҪHB92<~ŷO}Q0FxZ+a}jOCpgEW4d-'B(bL%D<;D.UO-L 6[<;,̮#1vOBZ H1+dƈ; x[7*E=;V|C[Z|hM&vAԳ[`phbL1;*=)LWJ3n,i|do2r fCƏ!ad XHݣH"x "loo<.|߷_ti:1L,Ɲ䭇V8Pq{=?k$ mqb gNJ叵 E^7Bd34o襘}Ck;і4/bڼLSYgbN,E46e;-^05?ڿIaQ11.^ r|8tb 읝gh^ܿ.>RP˝ї/;vOw-mWf޼yIĝ/1~خ׳cb"CխUb#w7@-*iӁ' }Zoܳ;uLg7^ n5JQzގaܸq͂$ %ܹ2IHHy,#WMBQ.%xV#fx8{(qN0*~q9fT[sBz]_k=zb3"uY6XD9f@\@͋( gGT@*ڟOQQ*~pJ('zצY>_ Iit"](ӯ3HSO,1~w&V؂C8;VXR6^`Uq!ͅbѣFφ]ځB.xPϫfA/k]L-j/uF1 @@⭿<-aEy]m?a3g`B]Qǣ)?9ڣO|jIV=]#6s._$`,S쾍jWӜJx_TaAr wV{|YO 7WLܼND X}P]"~SZ3.u3+,`G y=TgQoun;|vVW(i_B+ kTpWaAq̺Ƅ}Pw1S͋cHD-~Fh-vn.K:BLkW]%C@ώ&C_Q:+<+ 9e=5`TyWjTajB\q%;&GǸiEdﭔvW#VCBbNE&$DE䯟RON&0ꗓ gw}qFI,f\gu$I/0im'h(G3%N{2NZڝ'~hn# +2fjWQ+w0'۱{f`cr3!fc~NSk)ۡ>1v lZAl4ՈTOy@%([_ ,Ix>L'/_kT2V@8i_&} AE5b T%e9sV% zm E|}sSUV0 bQ?}.P VUa؞jOG~ (-?Uz\`10S6 GH@.0VhgP/$> '], $`kϠ^H }@OX6@HX 7֞A@$_tl$@_gǂN&,ai][DUl=1%rй58@@XGFfbMTԊ Zv>U-h3yMu9qQH8.zk?N?]K [*l5iRoA)saM%` (LFAL 򉩩/;^M|b/6pL*OTM}H? 줢Y?ozetv?gaǴ˫,-m;$kֈYT.kRՕ?D a?^,$P |h.ʹHj0ر'AL}Sg7ܑ/ OIAk&O\q)e6V҇ǖ-Ά G `֩-R)pJA /y.w! Qpbɍ^TpN+E[xfBww7vJAF~ Ȧؔ5LvUa qH!w RW<i:1A$gf;OgNY?c/ʡK&2_~y͔1̜ko­YKS&IGb2N `,j:L:d_r ^)Ʉۆ >PBw BbTȅ3֟ʪTG.Pqˆte};|&Ļ3ERna֪e{+S4ƒQ9.t ftQ'Rڋ#rZ},Fӷ?-"t'mݑt2Z_lodJ/%q񭕅ZB/ȣ lȁrx@X)ɧ! >kEHflXV>c_o.v-XMU2X-B&ͼpCcCД*[J0:(~r!B淪Mm@UU%(a{ɓmvL5j8nd fX^0]*(!) C>?aSaމr2 B'4-ܨocF2 _&5Yw4|]=GO:YSZR+>eV.ń{[d€@ RoQ~߳#l9)ӘAЂr1ƕ.35_5aQ]Y咜ZiUN.%V=l}0!hu|YK$ԠVݏ[PTR Xp~ʖ<;lָINm}d?ؐ 1PVN޼Xp饽xl|/WBBBZg(t^yږ[jA O=m;EЬ6g*$V.Xg \ȑx R~㬎$iW?M>7-0yf5o!mj>}T͖k3dIߐ.#=\MNٝ|'ODm¤g=Pl.k123(aZZJB}1Y~dy&=} :l#U:gSC 4_3USOFX8!v|ՈJrRqhtrԾiyS $<{+!gwHy$zeY,ۼɀ ]L9q?FJ:x)(F4QAk&{Cc F&5ذ@cߊ Dߊ{v۩G [t[|JԣzT+&cw""%y}cd "jI+A PAGYէ~٠WhnYY\uXͤ!%tA>ן0ߤ3כTZpsƼOAq֭{Ä%_}f[X)B>˗_.}oacmܱ'>n=C>w"<up -,{<\Fvh;r7}wti<1 j}^7{,S?wvt)bZQ{nZk񸟗;̳GGo0*VK:գR@`2[q}ZOj-uBE Jf>ݝ* >rX_U;V;DtCdX\ >!x<:5W\ vKثxCwwmӦWIH8%iSЄۺu؞;&=3K>;x-PlkżK*''Zf1"E"3F("*6Օ)B4Q4pL# b4j/PkȉtB4Jy%_0?>a}5.1@Ŝyb5-30SlY1-m3@|8)Ae0m_T^9^(zgN^M..Z$|5/U>_^C?othr-k\VU?sr%2ͧ~z@>f#sڔŋS |TV X[s7#[ǒ GȘo5( $, KJ yu&j_\닚O{ʤrboQU&DZL1蘩4$"e XG,omC<AvҖ.ZoIiD4)iMbv)+K %[ah_> &ij%)RF2[1ퟘhD0 0g9ȧiw:~w;Pb1b% |HC+$g.]lٞ$wq4zpe^]iN`V(^kŋL,g/Mƴ*vڕDՇ6VTnd?V3Tk\]%.Ϛ̽nRd(J +ׇ ƈNG){@?=U?8 @ @۶vY"M.s4˞nŁ&0N3hD]}e3c|sc.nW6b3s]͢gN>!Ya딕9H}֟hUdd2ȘO0u#7.qH-0b-ewȩ&`FsJ?uL;B] g~Ga~L l)Zwn|i.M)RO<ѴPƧcc3<՞U 6S'?Ҳ+I1iKPh9iGb-[)|zmO1l'6f)7Nn |:(gs?|5/ZcMV9W23A8$c-`%zwGJc*~^)[EyQW2?W$JҺiBxt3N6ܛNh*_̍fb`@bm0g驝'بq~}´h 3d_.۶-{/B`@>&~!~WPH3O;~MSI=ٻ.чLƈZer퉺0jRkNEXAZ $ mi hh IDATva|F|;UJ*X%Vb_כ"g|1ofV#٢U JRˣ[/+bNVpWo'%*VTlX?&EWBG|p&~CTiJrhg[W! *2\Б# _1Bʃ՗'|q_\#?8s 7B 4`sV(j*eU~C4iJ͙wFMK( \ӆȞZ;P{wHRD% 琏ٵSI(BѨ*{ TRf۳C>۷Ÿ FR:]NY 8l3Z_PXOW-R:T _܈W˖ Ԃx78,.4M5c E+k;5=}b:=ӄؔ,?aSA((LyMu\r{+<cWC CS/v~ 8(HL 3E\OPA^{1VRY#b\FlӴܑI~L_Gյ b0Z,E$ij*U[DIcl[R>;baX巩i6ͥLqZ{^RɊJoJzY_s_T9ӌjz,ZN[H ~L0Ո8H$a%wU$,IʫDGLzYXѤSdAE-'ڷ*uyVPzI.?L3՟ 󓼘,X'v1oS-y);hM /.u_Meڕl'&.,{Տ"$E&΄645ՈkI2Ŕ^94iJ1G }C-!/1c_sˀ,-d/B0>8 q~":eZj ^!> #q`B!#2cb-s#+R^džΏ]vl_R\,4NZ) '.wHk~zI3_,f|eyeDzSZ@Zs"jy gYs0lҢ5}(=wqA#` zˁGTƒ%_SfydL[sMdd dRFxLtS >c*$aDicr\ܻd\ꊟjY^Jr02զ\zJ]{ObԋxJ K*z~M:LP\ߡSO['1;@R2mYh@EIU6?Bk֬Ypo4,05;) ¬EֹfY;rvK+V|F%Mv#/K %`io+ܼٳg!˶jwt_UViFy#&V ІLdY9x#Gqõ̩,,XxK5[${b7K/8",ũum:p]J~:L)l&QF>S(.\{?g9 F!f D p410w~I~1m&3ݔ[_nFA UsK&zY."`_onyG] Z#x &<4Lb<Ĝns)%5q^¤ɱ溱l1殚Fyl37/Νy'}5rΞ==^tv՝ Mqmے݂=}v*A]?rz*A7sPO`UcWm?0~! yju~*xfIȑ9Sx QF{Jŋ'M(e}Ul1w4[Ba~0!J<sٴ%M5ňm^Ih֩/*ѣTO`Y!EG9g# W|lsda|$d͛;z1*$zmg8}o-8C࡞vg|_}c?.a}IgnKRB1!,_VJ1}`6/9+VsnekZ[˯PBy*SΖUc,sCB'y\󛖵J=qIe$2%%5j Nbst]de ,ڰ>_Iϧk{;U?x !E_yNƪ_Hwh=1~| \?wĜen I?.7aiv\$p]$*LƌZP9yI8Q| $)<&uYMrt;>b'U ($*#{)[W,s2kBͦrp1Xc;tQȑh/=\hZԽ#?L^`?jFU?3f"D%#K@,w~ގ˷P߂ [9wS`Eۖ[۷'IQ/*sN< ]oM%AF$9z\עI[f9#[\:cΐp!˷C[Fr)%`pwt/Ghx%cE*TVFZXʃ z鷸+[Kԗ* K ONK b ۶#;np;JnAo߿}5?z W}i[z)<&7?*h٤7cԏN?>-F?\irn\ ;Y^pгseLwnr3_]|we߈C*Wz۞5L(CU0BW<6k?-"9T`39ϑ&33%O>J_}sߥ`;nY7x;gW*Q]WAMqb/1+Ct[8B\y{;l ;;tnپ}{ooo>K@w10p͜A~'rSpWOt`pB _9M'"X7ݽG7k\-`-D(b6TӁ/(eLIJW1XA ,'۴̋Ȩx.rH)C0Tj6Wٻv *)&v$n aawF:ۣǴWC,P5le9IIJA\yDP=ӿM&&ܛm9+vuSL8mWC_5A(ǧuϞ] M,= UͨvSgSB.E~BXhKh<<z] oxxw7={Bډڸ;$dpc骂;݆tiM]o>z5KF#RBէwYm/j4Ӥ,]۬z:d{HȮ5 ?q68>qpEk*T,rzxbqwnP\tqOnH/f}wϏ.~_z#|7AhrwDR^_\WBu)neNN:Y>5r k׶fשٕ3Ύi5ޙk+Doz?zE^c|צ뀞☬#\ҋ {;'cjVBj61>朋꒰녧WOvU.w?yx\ݿ}a}+UYQV]ݗ] P9ꗯ+3RRUvso$xK%`ş?w"#]6}62?G8, >y}|$F}u['~6L(Xi:sPvW7T/I5@v[v O: 謡 ӷ5N7BsiiYl38vdk.}NWCD.c^\t>,}?fǚI+lqiﻵvv4g5ʕƖWۚuVyZcNJ{$pr EA,cMR'7w"%imŸ Mm > bR EgِB'O > V5K .tjyŸ9< Q: deGWyKfa5uۖNhj  %_|haˎD3z.9[V^Ђ7ȡuxցM)2>TMx/j-iɩ>r%C"'@Mw0}We 04dNdET#n(~􇿇6UR,\ Gäd2W?eA_{:٦xCFjzoloc=mYbF5hQۨWON]`6lCJįT sGUF6];Zyv5KkίW13-9c!]s͂ij lx_#m N ^M_'S:d߰(X>g$J/.]-[%QG)xPPetʾ$ˎ#FpBqb1sa?຃Y'9qp\2kQ0Ѡ.O-?{Nĝ'P,dkbR[DE^Ɍ8Rѱ7 :(Zˠ+wػfxFj 9W)ð}=sl{Gpv_8v'"2Y= n>C WtNC+u!nNcR끽gFD\ 烘%_utl{xW_蘷"q&΅o)[&|R)씰g<7]G͍vкAx36 Ml˥MՂŽC/ϯ^РAU3C|O5&cYլiI)sr/m<j0v3wWWi-q7FU]Mҧ_?J!!J &ǂ@*lQd2d1>WB۷u&}?=vw-7cubxFS o툠tJ!- ~<^OdIM|M/ ҅2?J.2?v.:g,sfʐwT|x}?eX0zͮ>I\ IDAT|FELf_cg@knE=ѥgm*G}VeP7:ڙ*ӗ^ϣWwSlQuݻeѧ≅H6_lcj|Pm cB1S %sg,SWo0Y];JyD:6;T?\NmjEbpBHUGc϶%[H\.>gGd̴Ӓ~<%NyT-!_; ZJ0*0N6^;/%~nSߝmv?C&c~tym1:$*}>Niƿ._vwvWx@=tr89G(Wxo rKUih*5﷾y?քNPts֕䐸/^𪄞LN}ix5TՑXo#m!u-|1ha*wic_@2\HZm`L G"]A'0OE.CUr˶sCh!09*`HU 6c.wX%TfNR n4/z7gZҰhc_?"u׮k^QԂFuH UN{wˎ̜k뷮Kd+EFTFQo0_ zPl0n_UYZġŕ85^/M.&-tj  6\QLP ;ء4:2VBKTk*uMOYe؛m?DӒCiɢTag[!`ڑ0aҜOPVAXs$LFf8JZ g`ٱ~ ̨,̊ p,0p;iyߩjfkˬI%V_Urkȝ;gP4!L*;'9ixn<÷`|Ңn/ -ێ`7Ĺ$Jzcn+DUc깱zڊ-j}$z%эO޼[Hrr(  2٦ÞCY3/IZk̼;CչۗMU}Fߕ YtIv*qF&P:R<ؑT҇9#jM7Z^WkmȉGꟊԹqsۀ+UӒD"U;) һNhܧk`X0ja *8l|[iuh>8PF$eG_XeI2 Kނ$y(h6#˲ţh~'8LjӃtEaՄ]U`B-8luC,QPdy8WiJr͂5s0M5_D <ر˫t )(緓Z>ϟ??u6|[4)hJ:ibrrhXQ܇wue/Et>w<1CDr-cgccC>lA÷+Y$xρ&,6 _.$@4)XpU! pEH eNhStA  !s̕%e%b, `|r%n4hi#v/&H,9ܚJ>ڗ|) d8Yp8ہc#O\ghג/ͳ]:4ۖnuhU FkM# XD>n 1)Lk ^:+P V݀>##Ocm{/ܼ 7{pJo'ͣ.tPWv;u&h,"ᇒxnmQ݇8E-.pp(HفOUk$@C`:(OV%lIG <{}r,{.xJfUh]w͉kٟ K8)|go/}uyf?;կ`8v_Ws9f47:j=PXx̼*ۍG1v+w>stwybK4Xrb2ؿ?; Ŝ>2qWLa`@dGOx7/q}48'mN>p$Iʂx=a0H ڟ!@Da=#?jQ@ YClԬ nɰ?cwgo s U2 zlT?w3XƃmMUY>KG򸣁K#k/r|12MB-+8ĵpS0←sc}SKn3R,S"V!yرCͥ649H53h#P2;$@mJ*[M-NqEѢyE3,537h ʘ+?\lxrOo]KNʑptӁ_WH~#?J5UZ}RsNMCx*VAlьd5J* |8Rh7G,eĆm6p۶|U:day]?{ݶV/2Ō50p;Cc:VUy }4uxu|~$Qjr_lUu^>{|LP_J0myлmc'5.et Pn58H:*G`*ҭhq176rt13,L<i1VA9 "iTcx x瀉xY-Kn@A)sq:XZs|W#"MoQL*~^Oհxj*\c$q[eԚ{1[5n͊ѽPPEG> 4%fT),V]B/[ l#UN|U-KLdTzmdM! glh.%-;#1qCLE>!P4(1&FES  @$gD^ baQ#t!ucR*d:Ņ-_DEhđc5u'ޝF!J{Ia*G1j[,;ꪆj-pi(z}r0M 4#d '9QM >WIx,/b% {E)kRM'"\y*<2 !Lz#3|Z7hDS\ ަLŧ^X@"J1fC6h,9(bhifDRGJe)5n@Rԗ"6g_6hm=&WK*G:}(h4sJQO TT[][d6r0D_ZYēL|(8R 2k$[9 l N 2V!^L``H7A0>2N8=L H)S@ 2"!%!z~ rpJ2Zc8x׌dKPuyIвI+zו|GXؿ\}+i1U?gp4L>Erоf"@6 ͞Y,,;VDȹ{_|@wᾥHg9&><>>*鹾iB'ڿLbVU"-6J7"'1fwVMRO/_ @@Jm-7'Vݿ񉪅{7(:<&7S7& I K5U}ŮAMv&]"/ti{NYQ3_S$t+ RK i^ ܲyTP0hf*`03|58:Tq`W2(zfP 0AΆ(vFΩ+R@zzmY#|)2N@.ז2`QP]=p؄4oFş գ}Cj2 yx*wz!ƦnQ}gUw ‚-ܽ܈a%z{lڿگd"NBߩǬ 't8cUn fzxclcb,}Jo]X隨m3664f 2RcQ[uR]}Goxmh{?dRfޒpy~gp7,1l5M<Ūolh,;Y,(l)Zv\tȞ㡳)aqW}m>;fn3d:}!3x˻K!uEf尥=?}|w7}]3LGa5>;~_-PfT_,֡kx.(Uv􃉙m|Y.?2:KkίWɉ zm݁ӧMM8$>h >SMMm}: W̨&:j[\BJ7zCX{m2v=7:|xpcg3eZN.2*04O\GF+sƆ}mee`#|@o!]b̥OYrc=^]o2H&xw7={W|q(1Y&tmGKV=tY2.` [w^zٓ'O"###""n߾}+WڵK* B^M5___OUXvLi]m8#uԄ)"?KEݪh6HB)K y!l`$Ga7WcuQה:ŬCo ;GzIF*3}nKck 2rW| + Rdvj7ӯX˰!qdLJz%4rm/,܊4ILhĿȹNJԂ."eRmU7#W}mQ]'ȄΏ!Aa!Ada^D_o…ڃ=byeG[&xy!Zv,Uaߜ:^E3rV\,[O.աtvJѺ u u + n|= W":$<:^_ߡO9pԷ N1Tts]Gj ;A]7W-N}Lb*(5-g|_ttĥ ӤC(8\ ?~(K8j?4G T7:)GCmk, jzA5íD::`s nA٩R(YR:EΐeB}v 铃nvlro6,,;9iјc1'3j+yY":&R7LRm$3>?䃺^~jOgRU+s) G'~1v7_? CƇ:銥xJkXlu,Ȱ,YXٲ[vReGq>ٲck[xV)Du-PsҲC.BHQ$QUG/o')0U)YGmC= 6Tq5z:):rS$ lESȐh[#.RK^ʤ-磤d{wx5Q=y۷y :}$aC^չWoØS߿$ ;ɠGj#CfB?Ũ7'X +K@@&$`iOYv&ϋ`Q`qm蕈;gl^z'Ox;7ed(nP ·G7W QZuT<.0(%OEވ;]yo(IS]NVwQx=dml=q;ksmUri7{l4y5,ZUޞ}V} *'VXDr+S~؝H(f7!Մ+m?y'A,į2-G_vX7s]4}qc˅YRgGǼ1K~ja% K s0]g^Zw-Ҷbo ۵ߺ4+ȌbgnCD&n3FԌ:&F]!l:QmFGCi3H'rybULJ Fec 'l `J 697/_&J%~h`bӠLH~]Һ7IP{)[#B77!KȉLtp1k$TyzN:^҉bLKg3 .s΂@[}'|4bo^ٖ֭òrR_墊U& >~XwVi>Y2/rR ̣r W^L6ITe8 :PIDAT,6*DlCf1< QG Y=:?H@䌂*C,KH9{Jr| nK3m:C'&b)P tDuRg24:1K%HfYA/_ #0i7DEP2T2JuisuwGK, H"r CAN|;;;t{!X'OAUTRfB@0R'UXާ̹ &OG.]ri4ނZ>nOKx͛7 .]:Ÿ6trH; >i|,X[d~d _?rGP1\sjg(Wb,P5DeqEFA\[@NzX"4CM'baT%'' RyF$e@@N'Kaэއf'G] f,9EY't VYZ^(\@CK'K q1ڻ-kVQCP~2  pSIP*QPF?:ݟb/u8' s`T*u.Ҡ$&֔%O0 oǃK@J YSW`$|FS(>*F~JDvԠtDh +mr^C1bn¤e.' K M ?/ijR>DhIDGPٰH,PM(h84(M 58OK9*01cU8Ү ˇdELAJOU VUGYK yHK})UU8[k(e't@Ӡ0g%BFŪc,P(z;t j')YLS@VK Y7ʖvkrTI|oլ PǖQ\8hԵ:w~sQHAe*u mթW3.PY sAK!u|ʔe d }{0` `"SWQ\'vh i*VrN>dǪpL#K]e X͗QZIENDB`testng-6.9.12/pictures/testNG-run.png0000644000175000017500000003765012732165123017006 0ustar eugeneeugenePNG  IHDR;DLWiCCPICC ProfilexYgT˲ّ9nr$MNE69猀$HN " A7}ff%bHH0+m#`3RKtѲ0}@⇺WAd<am[0}$:"ƨ0 Cb_%cc "1LG{zp`h<|"XF,00Xx&I$z? X7<$ ׯn)}D]c!|@AGa! r33{[ YDhbA^!6|t`Lkc^QE*>0p/i;Ա"p hp$ d|P*@5Mn^0o`|a!D@\?$ @J:@V yCAP$tJҡ-zBih  =!D(!17"8(BT!^b 1XDl"ɈF#:Hs# LD! U&dr9\Bn0(:%ǩ!(JDeJPuvT?jGhQ G{gtz =`1E!㇉d`.a1=Q fŲ`EjXs,=-6bacg[$$\$2$$$A$H H%yN2GKJMOBjNAKEz,.  Y2YYwd<'ɋ[OoSRPP8SDR\xMp8G\wEIG)AIL,l|NLEJOEBGU@JjZZHH]J}zzFƜ&&#yZ,ij3tH:^::w+tf1z?t r 1 w,ƛ;LLZLLLMLϙ~01k2{21731YXY.tLXEX-YYY.ѳd{Î`abgf¾aQqcSӏ3.:/W=/x>_ǯrsrGrWrs93Kƫśǻgw ?)! A;ŝ8wB8! P*a%aK#"yRgQQ_Kbh1e * q q-(i F S˒|%%H6>%%MFD]T,NV_6ISvMNTS\<9> a M |eJJJJIʷUT"Tn^S?"xȕ#3jn}MۣBG#R:ӵ˱Or`uut::8n:9;:;u?&x,#V;ǩ]\͉UM7[۪{Gǂg眗W׼wOϒo_sZ@@[AAA1!!gCBUBCWÌj¡cIP(Ҩh'"sqqWQ}'O$NJLxN'͞48YLԩS)v)]9N<=sLYʳag'Ω8:{~8U68u?#qTzA^{L̢̃ ^ʳ1A5.6?*+($+,*2),+.+)+.m.c/K-qr ˾_UTW TTc?_2xUj} kMzڠک:zkײ ΍#uw67U636Ȗ/7\o4ת_emtmiP{ljOTC-[}]]mݵoaum,z{{~PG*n=Vz10DISm u(t\y / /FǏpzju7Qovߞ|~6I=Y}S Swu|v}fSӟq eo//|q2t+ײeV4Wگή|XgYݐ۴|=-m=^O]Ba_{$"V p0Y@ 9@ #/ȋ(=4}5&!E.͓P,~RS+Ҹ^bgJ`a%a#q}TtGOg>_7YBenq`eU꧵oYAon;۫ٻ?up١| i*E[b1\_Rc2Ir6 J % ZƘ֛.aY%}mco+`".$.Y@D[hؚ% ĺdԦt̶U9+- CB%Myle)GdVKQW֨ f^-׋ӷ3P4d1%|03542s57PbZo,ׁ&Jc.g'cb=Nz{կz@+|3E#gp+!<19)S})/OϟyKjqhIڅЬLBO~IPZ1MLMY̥򁊵J*3WnaUpYVwqK䍊[uu#xpϯ|վ<ͣCOzvxvmh/qWR=u}ԇ鑏۟f>"趔uto-]~/3*!|ȓ(T  $ "}DVN@3ԣRUӡ7gg$21QFdZp t  "<"-#bpL$I$%$ۥ^HIɜ+o&^!HaWV~7y̅;wss7JsKJW/V].vMMad=5ߚOD6qkԝyݯxOGG+_<.=u]SF3Ǿ|]h9 Q(vp=ĺjM 2@ig~ )\"@0JB (s X ^H ¡,X  nAJ#]{o(a5Db11kXS 6Rq:87#'0EPRSIQR[R ٢=CGMWBOʠ0_D2a`DZ7rq|<ՍwFq78{;| BB+"Abb.%3XsFrr -YJA&*ªh#]jښ,Zڝ:-zW/ sMM3YL2^8z6юho (rم8U(-[*(dz=?uRJtz8\bRҏS?N'ŜNeMPʜ*__]]N╙k;)ozEt܊>u^_F@!֧^F_g0:bs.xqqrMhC>+jk.5 |( AH$BeP7BLITC!+(j *MvBcJT$T8S.%!K~ENAYKuz6N yE9B&s '+;Ev3rǜi\&x* bW^a  .RB$B·E E$$%jIs(+(.*M*

rSzFfVvNez,g0ilL̄,-<]l:wwtu:\t񗮋nwVO ~apv)7#&v1^ĉ$n7RmԞ9oz=6#:}A||LAR^qb)B9meIUkM-7[eut.t]mw޻޺Ea??:Bx~qw,|؛w2?M ?|2i2|YXU[;.=?/? &U @hO< ]:]u+@D b) Wm.#?QިhFat0R^!rQ(J}*6ԯih[721>`zǼf?%&X$t];MqJ !I-)'HlFauE6%}H:j4)utr'L9|,Ve6_l99SvisU!xxyTn.˅$SEGVG^;80)ÔgzYtj y}[o궶vou}p=~A ÖǺC&<y<%؝ W onL21C)xvpfz!K˥ԯƬmnqnkj?:dyv;;3{<{i{+?v'?P?8 m`]l?ح:8 /?+1SV~tN^/̏8&n pHYs   IDATx] \M߷nuKOIJBySyUR&154kbo!W3bd2jBEQCnӽϹv+ESk=u@$A")))A P#0A#@]@A @@\9 ϝ;' H 7fo~.)) ,qqq~sMjYdfGrG/-3Yjj;)]ܱG'6ol_F^|JyyիWjll2yMdv$3;-/rxWv9s& oC-B8'0ܪ22YrhX5==P Mn3Yvo ̎dKnX1d\pD"l^Sc|#YYWCd)lDȫGF9Vw!)2oO#[x俅&*raweINCxU&R͔f1,1J f!x c h]_:y"!̉ QfoÓ3Ir҄kɸπ.OnZ"$Plg: Z;v)W ԆtgSӋOЂ dLlҨ5 AI\Qr + uZ0f.N! v`h T> P{ОzO䤴xִqDml]A'nVX.;ty1_xLyXFQW9TNө䂟lxor2V`ѮI<ՇKt6N`b;i{ }yOPɌz9uUz響w:&nQ:  tQܜx;fъ@s7?T]"aziz|~Yh}zS fJ9,.@TWPPt׮]přnkjiӆnt#z71Gx# "N@C eN<;Dl*im`,*˶xCo{LoiwGY)_1v) y&}#{Τ)gj0vLArj: .E"u 7z{Or}N*D4!ZF3.tFO"MuZ`TUSӵ+2&8cg7G +Rp'A&"G Yc+JͬG1 }S‚}nV iA ]m[:rd :hb7_ )9kۓ>mKDɉ#9QC'8Pn| #ţ@p`m՜ WsR%!C1 rdť] s%=%C\ISxtv}54P5w.hv#v e}31AfK WtXwZzD$9cy,>T'jrj=zF 0Ca!OQs]p Y#F+ݨSnCElP*O(A_ٱ>g'IK`ht.^3|~.My}{3&sLb:vAPp7Rtopxɓq;=iкķDS!:oS:v<5Ԡ;mP'K]~K {Bf@usV'r7/^)+vQ)g'?Sn׵R2ƒx0ɡ?lT4 \f!8o=0B,s;x)y'C |T&+utLOfށҟ, G`:+:M:[]@xamp 2\39qOQౣ>x#kF.ưCO%2Lf~xhf'm$!~[PEC CSw;їoI@(vB߮3a w@4¤jMO|G_exZӄ;`?e9I+ #N1==7yRڨ6jhd ?\!uخI7//B'8 G2:!~#~HVx>KSqN םqZ{'S(eS:#ҤQp6?l!ϪgS*軭c&7vQheCV7c3(_tC]Fs󅃎A=J`5uNl8!m H*"nU֥Gm)4i-{\_G<]CRP{Rf"y(z3ьgS`uy&:vTI\O.&L` tl' qBYo Սbتs| בpNϋ(ӂ }W}dm(8paT9׆cm̥yC`y'%yAY\*yk3syVG+xcbꬡV>ݽV5Ħ =e=b1g+i͛c[1zB aA]z'pH#A^ ˦u#ZG6!́T`}F~u"1x-W4PՄB?p}jrB}rx7O<Ύ\jcc9lByF4=xf_|/j?f G62J.Bj/Gy>#%'8syUVCȔ@aThM#,_;<w+MBc2=-k"%8榕kWr6--`Oto45shG~8#;ٵ7j>Gv=Ϧ!v"N)^`c'31R~ӻEfu][PX^-pZ{^ =/ΰ_)Uvo8S Qʇls&-%B=+bvTYbd|rrl\gn۵% o[w!0xk-k/L[5?,5'7pukW5M5Z:%|w\)ɀ-3$)⺓ӏmp𲧁G8R7&4a(FO%]u+`4f t%p5ypl dLz% d¢H(~h/FҳtE<[NLf-Z~4G?ZOSmVtz٠!>εgj c6-)-hޗQLS&@T3xB`nS3{Ǡ~hlqzF8n[u(U2Wڕ1#[47|F)4 Ӻ0$(0_35µ `|D:bm`)W'8HRe)N6%6 5M#?pcI<}z&}r{ SI &$_e<?m.0dYZ6?[|!3ӭߣNѴfb$=DDDT/_*;}ˡCG2Kz65k-_[=DI:ïGxY\į$Q|V_˧X%Lv?7TU|N杵?qem4h O(L߅Y ?S \Y$V(W4+'YΖ_M_ :yILFX͎ yrLiN/ 6D+\;Tq5g3@"Xق)мu AE`z<γDRukfF   ~Qhu>M -ZȤODHC][GK;nvn=mWxKa T#rYG[G d;$Io`cePT 'm0wKJQCٽN*Uڪ>sOp单H&wK[beNwHf-Ԫ5vK+o5ˍ]غ|Ʌc1U::בИu;8LLcȐg1L"vx0IAF.!.ۄ]- .)Jp y IH/KJu:P$no fbo@.>u{d0럶B[ ,8!vJz#Ri'oB͏c-v;:`$A#мnb ~N$A @ t<Hl) @  NR&voA@!eA @xo) @  NR&voA@!eA @xo) @  NR&voA@d\xBHA#!`mmmoo_WWב"(E@Wl !@ y~:l 22> @ :u([&H/^ןMzS݃mk.u-$W52`54Q JX/'XHcݓAI#\Q' o*g2_ D%+&ޗj^9l4Sse=n8=H ow.A-(X~~򉻎#6E'|}2ոYӫɍP&Ck|ֶ7b-.;iNK\6c {ŬfqAZ͹z͟oPӱ߉{k?Tn*y09ZaϠ1z֗͝_8eQ3͹3lf M'Cg.(>l}}iE "q%=T3qmmCO Ea ޮMX?p'μ<(ʭ!uh'Is7}Uq(EeܬngMbL%##?A^t"k6}=K4]^zTw*ғ hZ(af8U5CfRih%!.¥?5/* bԴPao:kMO3f9"|@ф罾&`qx+zF# ΔNkn;~TMMTu:.vD?pf|`V9VICu6r7PV-i<:ǿȝM_莤W~4.y("XZPmo,mgwqD3VSIvp ]+J'سPЀ iikE<~'~rf$EQiOw ->; 0'76ҵq$1 VߩJ}"a%_``uS# $tTsfVM%?~ );j-L:5t99bIk(H5'$׋d5г22e`]z-,/ZM[:Ky,Iw!x':r能tu1TƳ2Wu`5 P7 Z`Spu@45EI=c2SR!KtU҂e3>Ð&E~>Sz#k[yT>]tXOp@(pRS:E+HTs)C L/N E=HJYQ*csoY1>l#9 q@B#/KW93o^ԏ.!L sM]{Iakȴ_z[h]̼9q7d;ѰЄcvP<,mr0_غ!Ja N]ΈAzQUxyI~>SiTF$4߿z٦C<(,},&Ն_ eW{93gxHBS:P9t4i*<~gkdF{~SLnR8ص%+dGeE25;/Z8YFdݍ//PpN7[uQ> ) F3b 1Ȋ}Bsόp,q@ 2rnJ@SDFomoM)Tqo@OBgV^{Cu1TWGZf0rlhFqҠW^ݬ$T4]M<ʄAwY5^FíPVݺSs,t5%AxA*_D ;an4R}yʂ f TWWUPN!2:z=Fx ӱ Jm?d^;x/Q ,D>bzEhC'sfS"^| 5G/0GxfݰnUx-gmڴTT~3tnY"JjRAe4z:Y# א ےWa2EI%%%[zqQmvy7t;a`f`d sؔڧ #9ꮟM ) !򄄔)>xF\ĂHRxpTVEh툀-J-:36C9a'nc?UQ74<5Txc'Oʛ Q?_tT1xAca.*j O4ag#[iV դ}[|8/e0̭ܣ ä>r +AzѥB+s.S^^JaS߮1vP'&sӑLqu+}{IZ9'!\N{T&q9x*4YZ2"8sfD QU9u]g.ߵ w 63nuD %,B=cf5dyz1`BjBVn5mZLd5a~='O7VJ|1ʹoPאcvvo l@)@!mA[dӬ"dem2 *3 G*>o.(sx%ՐӘxPgapM?tp1;f;PS#^͋Ԙ-837q+p`4zAAK7+ C\ѳH$Td.i(s2MiQayeplVJ)JԴ+CV렭NVf`UᱦZzCFյ׍<ܻ+fcH]<-%Ɏ,YDo&7ɀflM~g gҩ-_ f'/{" СPW0Vb A @P@A6]zB v AG@L[  @ :u}I,!Uo B'vg_KA@۩B A @]ٗA @Pv!tA @8oq% @ T!@*d @ :u}I,!Uo B'vg_KA@۩B A @]ٗA @Pv!tA @8oq% @ T!5:{jjj˓O$foHPV8))wܹs x xXD <4ȿBMHA -;}/8Ng] *r-q4!o'LooL y;3#mHӬ T*b?ۋ*zLYxX_ELS/U|:R^/b+yxhQeRI  &8",8bsYZL+ ~[GOvqsKoh\ 3cX ^3g#foW9a.G_bqwbL4VyO̥%u/ĿOg5.ذ?ø%v|`[YC"i$)/K 7>CZY_Ė<_O k@;PW9R۝ Tfqҹq;0@a;qՠCEy0l89&T6of_nyu15NB hjq:sEOK/<| !*5)xk#S0Tv>zWwem@Ae,d諒*v@i9c7+ t'B5LI S,NdVTE/^TRpK+Yz[s+Rn:͚w#E67)n77io?C⹆&TZ#`FA^V3M q^Hr@Xڹ4R#o۹mSB~sFOߒ8K%}dC0py,^PqQ2ڂȵ Fݼ\e\LW:biWtXw_xfr@|HfY93!GL*@+b.JEG޻)lx֢YE0q]peȁa+%9A`.=ڬR68n'5=)3=HN'tnܰ9ٹ kjdʤf*tM#F E| KtMk` tiK(_I۱*wk/Ph_6&kU{!~ef ‹wJc^QTo@x}{Q{W_}JMm4Mպ؈xvRcWM4-rAi!޾NH鹶Ň]#E(5Ei_vM1{vO} 2l~;5{.I>[3l},6Y{B1#5 -*7wN]~kI5qH4H e 18WNḶCAXD=N7[@jۚsDv_%j E䃎n-~.U2౼SVgnqy[/KUgjo< mQniv[7Bk'OtVF;dwLZ^Q E-rx4 3ZPr +%@R뭱5BDReSTUJW v2a(l^obЪœǺ63nuD %ݭʪgœm-i2I @xx]uhbOz@ xd@Zo<уWOyg*'`S31xD6ŏ)e25TZױpPf4cV7?kz̾ ;&K[_7PMBxNm[a t(J'0),n}p٩P#Iݝ!yf.-Iq?h9N|Li'~bFœ0#՛=nywDWf>4.baMN`S0 q]u+i8 Zk8B v9~ IDAT`Sҏs2_Ks p^9 çd pd&v:/{ Fvgv zanhiLͯ=+8nhIkpZ䭑^3l2\] ^>P(nylWs,o:x*z\yd}Lq}Po󧗖bvDDDM{H+ ۿYdPOO `uڧ!'lHGzE'_S/Ѓ:Ip>]Yc^tLq#]]X{xpPlVQ\SUt9rrshxX,]ʱR\\V 27F(Uh6ָWSP#2F4ű-3sO ژкk(ܰь-ZQVU^ؤ$DU|_ć>*A/Փ}c{:-ijw1;p,(GSԳ@oIJo6\Օl$G ^ޓFoX$ekA(*^dd6VfaE v6otEiZUy㳀o']*~x)lڛ A] @n{%@v+AtJ "PZZN/7N T}'gXA  :4"eAO v( @ 8-3=g2) bC:""vMT(|:Ny HMYo{rw w𚀀5ቬ7|:ۨ ^ US"UaY ~cwK){Y\ ) zx"Vy;PxhR.w {ĭW]9i8Agw\ |L-Ζń\T3}F|B%c 帆3ceAN-zХs8뙏\̻]e*ڽP_xks'{!wtʹW%q4WĻj蛛wp 3m?saP^Cyg -:-UkW^5@rk@ƌsEǎ+%v_5qS+G; RiF~%>ҽwD'CU}@ںU~s23)˼[JߜL~߶bh]~gILY4ˑhY5#D2 > Zɳk븠hSA%EW~=E\32wWf'E ,o@Z[v9&i7 ‡[-ݭe&|u\RiC}nnaz^v>-75l@T{W&`PyIMM^bKUguIœ`u9O4ps*C`6(="&xeNEg/MjcIii沘G*oS!d&ϲ֎2}qLn:cA%ŔEй,c]ȡP 9?ko[V0|\΂?>U?^QT}*tl4?X__V/>rzHQ ajʃSoApbE=>-u2SC)}ls_5w$Ail15WSGp/sTcTS8~@Gұ3tA4)L]7}A'.BX,!!d{ +{H/A ֨a``r Й zmjԁO\a`bM Hu; 8K pnY~4ϔ] ~ʲu)Μn._xeꡂgN=<]?>7c ]Y7:>g5ZyI=2= #D=b}V cwgb`q#sg&}NAX.TtZ S*SQȟ^8?Bt:;Gh6oc>:x@JT*L\/y#{6%A#W;wMLLlm[ѱJF" +yAG7&j~oq]Qz<:҃ r:Q#O62uvqҒ%lq˙ Jj%_L%A]t Lb5`$5ETæ ,t cs:IŰvflbƍsGBgNçύ9)&r$ +==u2f ڻݮM^EmY9M,"]ID.<%bq m2gJLcӣkls><Θ?i0o<^0ךAC_]|pi@}7sq@P1ɣݺJ$!3Q|&)Ulgۀ?^ vynmj[]' / s9tɄ=B7~N'9}x$&'%*H273J}âwnsP෿cj[5=LiSw;_;(92BzpMWi8|7J ?~*wNDcwJܾ-C164ŵJnntV1*oݪ:Y,7sP*>|Ka⎹yIJw" jg勒(NE|B;oA͙'x&FI뾷~.Len!yxV%IQ?`v14ϙÓ 8MZ,3uINC=dbdK ہ={2ۮ3xY9G3w aZY= U1Yvj5,7.BXfĄxxe;CsIFWz )ӷX}t,}ݝg كh67xѐfihtpSfNo 1n4\<0¤8iηsUv} #ir6"OD,{7)fLf_$jg)D*/8=87&ѻ/`3;T~sKU^Q|{Uwܘ}9!̜-?y!>#mY} 9,i&%is!^1=? '}S1_'(UO)/g_IU#asMPpcE9Z2z`b}(Bzn`$9ZaVC0C}!+NB,j5eC2y>F2)-h %xAgI IRZK/ WoK>yֹ0P(9LL=m{gl`Ҷ^|=g3kry:gxͭe> g$AsgꙘ0>4\'eCD} WK \&9A5C =^P7OE g{>ȹu]U74pu|9% o u1ڞa $YK v| @ @3{n[ T& !"Zx;PZg`ȿEZZA2A @hL&%4GKC+l!,A @Pv?ڤդ&GkP  > u+MZOJ[Iq))a^;Oڪ)'/EZW9I&Tӈ_BTDVuS4T|t[~\ΚDijJL6#eieTÞ|O[*OnI2C~A %혯*5W)C^Ä"QuEI;֟۹п|}a/Wl@Hd砽)9А*^ B)~h`_snG™OYK|m3*7w]~@泱־ِٙr\ݚ9;0s3 }?3#V:rG>G[`_;>uOZK>|*UD说| $oGGߏGA @xh7ɽĉeٳ_t9{aoƉܣsO0pCqZ ^KWAV.=zt;34>עC5z\"<y墈r g;&~A "ݲA)xU&?C,!.sΖ6>lQшetCRTCeEɼ+;&{w:"TEP*D^ai Vr֗!,Bh1deG lIC:UoI 3")@9;E[ >e*w#4i5Y!$ @Pa%e Rb;f@_+_Ni̅-hf Qd`(Bp{sTՇ`~:.l;&;_ىVCmR;y&Op76PҰHISlILh@dQ*SfGn>&%#_R ""YlS!Kqr\"H ~{G3 #ܹ~{Ow$i܉s'gZ  A_?mS00arv|/ope_xoc.C*5mi&b~hpD9덶ZV-h{hE7!_0lB.3L(T(y9OPT \7t|M7?7'$fBrb;_[93ml/檚y!ffU}oQ鑚rT/L{֙܇^SH?y󈉬zw~?gO z^S]"3w.\ *.'½>K[+e׺]J̞ S?,Ndu@RPT*+Ӄ(* ׋Az%md*z!&.U3nޤY[EgPjk wyH'bI.4%/pEs*7ͮE^U(kD1~:|`_)tVy*@f^y"ÖRf=w)*p(p dB뮀:1vB(+\;W]Dn‰8| I)]?wC΢Sn:اeYSDl/Z%0\J5ߺ㤜)9 'ĽReJH[#;yb~D:KFUbVZS䱄 >k:</* ["M3\d@4?`ӡrYPP qgyRiC6XCanc&qplط2V$C>G&|*ӂ+{y#Tn]7$q TAݤtkk ɔ6M UڮɜbQT@'9At -* (@Ez; DT@&* K k܎z˄4U]+.|'r`'0TQ@nט^i If YH*51æ_ƕ :0U%heRjZff̴TAʤ$y{,!4d:u{cɊiPTvc ^N.) Zo8.ooy遅+*a|;3YzKQݜЊLWF0p F7${,p,[Dz3)8,Z5{ut3S * \fd.Ȑ}U_~mwvWig΢M5EIIԻpVzdr5س hXYȦ@{3wQQ@;oP 8hi!"Q[T3@4qmoܬm'ƢG~Q0 #[!lrUpD \ / Z76&Nk9g*aQ]'kUܾ͔4ߍ7 *[( IDAT Lî(OK|1|PPiAz}!7iPz`sÖ, q\|[o [y>3՚^nwfx&nh]PeM6IwV yplnsBl -l-s2c7á73Y]o`1ޚVUl//~/pB!kTa*&@.Zn,?Pk~kȳ32 uۜ l[MBrIɱwsK7[߮Km|UM­WؙRmXvp^ZrGL{ AGgr@o ᣐUuv/|Yz)IKeŽfGjՑzFlK> 2,5MOm&5wfؠ[WMip)w4Ü3I۵Y$̂$}'~j2:^ˢ_ X aٚC{K %ZGdzA(hЁ]x9Y&CT@&@y;Ņ9{GQQp8*&^ʁ|` ѧ9E=u&>?=Ѵe'r]>\+}RDw-3Ȁ/C:ZY)|Mj3Taf쳷·nq;PYelڜ1GwmN[/k(2@Ɖ)_Ŗ UYz_-XbhE]$ t XI.>isRA D;n7* #5 WЯ5*ƣ\ÃΏk쮇xtb.u u5aOWueuZcY&;aT6EoJ4&Ux|!iNiܭj9NV5w?|ȳ)y6tb=u/Y70suc^ڧ Jt| ?ݼ $NJLndކwv:Ht)늉i|hP_ t 1*0 (uڜsO#UgC#\/龜T9ztUv,Z (p !%T Qk48,ͅ.yj?3;Nwϱe'y8Ԝ5p\)|f:b֟6{ ( Ǭ&&.3%m{G/mHIJ K[`NU(<{*H>Z *tL8Klzˆ%mMTs:hLJz`zd+H6fsbF!hfUmd! +Q+SlYoRzfh^Jhi+ֲ_:?,2ˊT@&D$WLQa?R%Ap;5 Q^0إMO-\!5싫(q4j5p2ZBXQk]0Vg'tVr=Yad`WA'I-5@Ϥt__GD&37e*zJԵ˜ Ucj/QJk|dNE/a@P)"\'~ ?RHdo(;R25~bQbN$kL|]Uח~7gM566_6of0Ș)@nxķH|ZW>_cV ( j4%zAyPGL xPoj(E`u µQ[6pAS\ <= F,6.S1Zm{L ztz!.n32s9cYjGH!w)+ ,W mP\m&+57PfQB =R !W54`Yl6VF ":{/XjcWjЕ@V}COekzPirwxy(,B.+t;0& ]<b$qExUh]mp5?%BCV#Ɉ Ӡ?PQ3 <=6c`Xᎀ^)U Y. @fWVKݪ 6:t=Q a8_'' T`@o7)=@@i*-MPӻxqUF%6z尻dz]IwYSZs7*csv RC8CLmǶ, 9ҺsUR /:φ{ )ZB`pRR݁ƚ3& Aw 5)ە UD+K#|e Tb (I4בi0S%Z,u!%҅!"G7m9^<=(6 Nl߱[+%:(E%>d ذnv)oh+KJ[.%/‡h] |%uOh2/ |h.z{JD* LnRV;Eki#\UsIsuColm%7Uᖐ; IxqI{1|c09{peV^aF"?\=)޺П)6L/%rn?k: ?QXlKΙM}+~{Z A1TT@aicIսuiLV~#Ld!!J,@nzb/bW5֭):USfJʼYCH VEb2k6, ̒pzTva鞻jsZ4yMZ5om7K/{tO>gBڂ*0@k>:ƛ ohѭ3“hwXhQbd@Q35Y;<^ߐss+q.U)g< `ŔetXj˼/mSc#Av,Lڡ=c5Y||biu A ԂCCmedO`𵁘!)U_~ZX=VtY?afuurz@o7)7@sVgoK=g?"ۛ~w]ٙwrkfvZw)UQSOȇ ꎟe/mNl< ŐH֖B݃p~ΑTo_h6G1Z,d]Se[}_Nrrƃ7VQ::lge,\W0ʎ)HO'۵LJN1Pm,5 P^wR 뚜C}'P`R`wΐb{vnp⠁6 Dv3c~YZ(?JFg6iԪ<^e٘53NkH3V.;7c]@e}uqp@Ph$#4WB>U[[&C|2H}Pxu?^XXp RwiFdn/__5k/D*t^3@*f؃K32޿.<.TF[SWʢ'iq^.:Yi?XX{bW%ę)7+Y. .^Aj+nǩOYz ,TR@acQ.nr0 j(DYj承 0P8RsN-aN.XdYW3K&DPT:U@aTS,T@P[%$%*I* cQ@4ױ.APTPL *0.:NN@xGSPEz;^;ʤ ص9)is]X^mA8.I 6wL,yFCnEׅ}sԘ@n,zn/,7 a' ]oIo5gwy=KT+] XW8y܎7~eۋ\DKË*p*t`50ݔc-/BxPƛ+Pp-Qkrik] )PlX8vRrT"RQBj≩@ON/dmF'$g0kЩ>Y/TM !Y/2Im!EY:z}#paB_C.X;RbE5 MϽYӺ2]DsOh a4&8twF5_:7kL@vLDHtV9@tT=Hs@4DD֐zEoت?R_2UQopmcT90Fk ZgYff0Pi698PT@ ("4*?Fkf(TX[5h^9PLО54(z 'dY'7frJMJ4W >{|h&E;PYelJ//&b4nkm=7#'nku߷WmtB>LH| m}\i%.Z/wXaVZ(@֖t5Mк_zqi[af^x!7>"tgo[$Е7m7y2M6מ3A)\0#r,T bPirtjxz͖:RA*aOWueu׀jQ:w/M*oV}Ӡz_Ͷ6̡MD|xox_nϧ -:틄\kV4wC@-Ca"-еx?D.OsY4i;KJ/=@ZRb'4ya9otB7kZ~<#o5fe֏?jD~s ݆WA D ZrK^{ωWpP9Ĭ~f(xMϸ᳼ap OF5eL0a /S+K3[E1@t/ACX1$ˎ˄cL"Tct_0M%UL7<ot5#&[/`>Ы,\B J8,:Agf<#3Ut.{5&.6PM`4 ?_Eؼ_ m؃}q1\`LR s5G)"7qPܦ^Vy;:(=ֈ%`iԺfnlf1tJ.5@:ehi;x*vbe # 5i B(yBk-G'rl"3.*Jer412owMd⪼gh/[,^@H'.^zQ48tj4uY"7r_O)ę(];1+Q$^qoQ^LIx 7 rwKsW2>FJH|cPTvW)eyr)ױ%TDd%x]DH EO*p t%`* vHsT@P(Ho CXzӠ*  (M&\EPTvHsW'_ѩkՐ|ذ@W}΁+.3TS@iw~bIJ*[p`L-o3ޤlqYM2 ٕ[>0 * (!un/p>MP%؆idnΒo^MV'H9Rl|\|[|뵆冑A#قPT`*)Ho7#sFT7/k+*4OC ln\ꢢFx>פXjIDAT,b#N! Y5bR꺥 gY>MB V.,8%{;ٛ=g΢M5EII?Rm[gΝڢ{vRXYȦ@{3wQQy\B BgiHη[@-/l%xliFZrIIEk"u:봢`;m?(-B $=geNϘ]Ua0zfF6j~U?'}fU'* \Ve @gp /=(lpab x((4M*% #fc+Lf 1>Y2 \8%F<vx! yle>֔9ܞ;ݼhlcZ]om^\Lwfк({=^qɣQZUyl(Pk6df-Ҙ-&'v|ݻie٪Lo(vmal'&R/r|BKyP\$KmT:WwRi*P^wp~٘]/GIJc{ s2ҥ=$ا` {H]/YFosr9rLBDlտhurµ4M.fu1*h`ƨfʹ"M8w'h*0J;Bs͸g$8Ȍ2iuOh2/ |Vxmd?voiS Yɝ<w"=tI@5 Ԥuˋ֒aB!(K@/.-T@FV@ac;zy8**9dy0fkOc9#iF([*c%b~aR=_bkjo*vW5쫈^ALϽo+sU~S(.Bz4$V+#T@PּE+i#QX #W9Xgs/kN[+ ųU=\MZalD\xn,:]n[ZvӖIJNVz5 ըwyFAJ8H'U̖[>$ Y]3EbcI@xw5ڙn[.Ok!öki]\QuϸhaY,T@I gRzKavHs^5榓O 0$0ie7'GxlKEJccȰm_O}6'-Չ"7* vmQ.ƫ=Ƃ 0;+CaNL SۍSIr[¾i {Jc S5T@ak2X4* vR/ UPT@Ƣ"4 ic]L * (7Hs@PT`\ (!u\i:GNCM2u`켒 SDEz;N`;1Y=fF7v50!at$Vk\DaA }]x{W+h:~S@iyCG%+;6hnhy ĪRcM}iԗ ȕ,5QT`(Ho4פhrSQM;`0.ZTuη9xÕlMW$ bA@]Z.k ,Yz=nبY fx&;ݻYLVAE [5i¡3{ u =)\0kg\Yk)&'a۽8 !}qdoF_I@>}nF]؋O!sQylK U|G&99b}C$'^A"Hk(i/ >T (: ͕Pi 0TfvыUs&{L38J m5Jgń`Tgԙj. RHk b\@R x SI*ǜl]o-+skNQ2: _"Zv`pe(4N3Z!hENoޚ-/Wr M*,$=sr2+˂j2#i}n8;Jo~6t7~!idϫg5] SCe^st+t:.֘ltmgU:ҼN'yȼ]a*NzK\}0Ʀ =opüH2N_}XaQ&+O-mkLP ̮M08*ȍׁ8o7)0\0.J#d0.iUwp899=_}SkJtfձ^^COZ\c\}u!=ڱPkĉ*=]9<͕'_ Ț/IC"zy<1mh}O?Rcyrĵ=AL5%6b,* p (llrwך #pr.^!C!R+ڠ<pl7)}r[®c%Lvő0RDY#Ẍ  [9l8* cV@c[4XE@PT`DEHs["* @|4ר>T@PPChz+w駻Ƃ~+9p`FT" (!Zܝ]IIe[@u umfЖ7va͒9,aɐ]='=c6tu72Y'ZwnIw@ M 23= ?ruQvg@ ;od<l.Fr(u%}fUc *0vF+)Î^> x=>!kڠypt!sv:3+grܾ*/Oegx}jbC.+)%Vc`'-7Vfd~ej]pJc]o[-XEp[Gm5Y5=^0!iiډ]'6CiŅ&b{ d~t(U9B)5FX؞9YlY YdVzvFRiqDX8sߵ7m{=bKbY* hgoϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx] \?ս CL)faSNJ52H6&{PhW1nSME%=ros|o)y~?s>ssݿG u_A @ 0͢N7v<3, ~_`ȹAU̷u*eH:Xゔ7%3w˪˾!aҪhG`\66=Cwvx}< RE߁ƽ#sMDTO*x`2*=^;6RbáP\)ת2Q8It*VsЂYA]">3-,`kE7#bЬYA?: ˅ ~t_}`(M7G;-TpbPX3aߠC(/g- ӹt9斯 n&\حNO:{G|^UpF,3Q-?@X8sRwCM`gg\$baWx$ Ф3<4eպ1?/Z5-N v8A%@@mҧJ<#p__L1)V d^BNFj3E"{O;K.Oٜ~@QmO݅;]Pq75k7Ɋ1[B~>B>ޜ9owe ݆|kkF4xB16$J-u=;'q0\R~6Y9uQB .*4iˡkvRβW`ȹ c$`>ՑygC \lc:8J.[,B&ؐag>}>ڷ+&fFil`/A O?һ___3jԳPxzIoIII9p (+b'L+]=- I!t![d Znn.g-?y!w_+vEX:nn{K"U#T_$up«Qq(`7@ ]{"\T/di ЉҰ#aPN\rAڿ9i9%2?fpq!*Jћi1QZ&h Ԧr/C(0p,V?#rºhK"AEP35ASA:ϻ_RCkxD|砓{]K Zs?Xj$k[㼰adx}ro1KI.RHW;ߔ Q@y^flVVM|D+-+v-߳`Moo)~u\j-F.ݻNݲOuy{u.{+5-=n1^56st%a\>W3v av0G@9q\>ZdhʕE`}J q`4*#Im3v-;@=ʘE=$$A \>EJ*>=GK/ПKK-_6h8?f?iDj)5V@3-76PmG 6JkåCaaT X4 uun EZmAah(a#B@FJ(0҄n޶S׊2BKU{|_< @xP3Z6QvZ]v*!ALx9P3-z9j-v2" @h6fpmXmékI#泘$E>'H#G-98h$BA =@ CE @{B$Amlmp(H 4pl 7S>VhI^ ̈́lY{h&|X@#縮w #8 8iwl=W;GL.@!ݱkvvpօj\(ԯ}IiɥVMDBY܃v׸h_!FDXAq8FB٩\1Qi*sll?d|PDP\(m7|LJ[Ldt>]BY2Fmtے:Z=<,$ hK/e5UPVu&&E&#4 :.վFWBY6^DhF=%k+ʮ ey_/ݑp/;v~ mFB٩.6=}8so?f#4~慲[ktn?ӜD 5љ @ 4;d!&ֈ11׈A !&ֈ11׈A !&ֈ11׈A};dȐfDМumNDv"Pp捃H'4y :t [!H?AH+yT6Zlb;N5\'g~~P_љj>vk)DE Af_emuyүƋܿ㡍SX4Y&=Q6E)U#Rwܹf:Jt{n־Y&0 "L>C n,%O~9o"O^=Q)t2xz%<5Vq,OEu5B<{՝q1!QkF=tbY|}޸=Ns`q6_Ojt`ߡ<^=y=կ-=_bG,(`0Qj wv2J_^M!áVS8j*7iփ,khhƕ"S1~e>"us>Էh ̇.8RXCCpWքtpssiynLE?_B !N "Foa9^XDp[N*mcS1\n-274_;<,p|`xts'^aVFMyɁA/xY۸ T4u 3 V%yJy1_aV$\cB ];l4>*&_$yy߷ Wr ϟ` :MjZߏq!JIڷcC7v]Fd>3HcLr=B,?IѝU:Jl`raBëLղ Mҫ}T*} *)y8ly_ͩ\\繺 51qB.UQ 059{Ϣy?gă9tSUkg(rO&y4 f}# {f3U'dQ?|".6ѪN%g+k s>\䶈%5v]17K=w*X5ZyPk^_Yt>phыM[sЍlW&Ygʯ|3PvEǿ-?}#:uȢcJOeq Ӆc]rgT8,[ٯ93qF HTF *>Ucײqq Uq_X5wxƔᕋU(>9dJn彺{_.z bNt[ 68-8:6eI!' UDz?ٺO]x})QT$ms :Wmc9 -5 (x(C~^y#zYfS#m7&O&|}qÿqч 톦7{͛= ^Vt(H!AjqyNjo.BqV-zؿ)~|NNj 8FP6zvGV {W>vH^IƊQH$* J"$L_#{ UA(J+~͘՟x H Lz"3. $B.mL̎.}I{wݩ,@X$!Z.H6ymfį; DWq'w|us:9J5Џ8W>{"EOBz zD*>Bm)wjRLNEtCiGta!Ƞc__iN mDZ}y1o~bD+zzC:6dٽʾ~у FuOWU:S)SPkzTTJ ~u@LjIn}2O(1|ĴSWo!]U)3\:yGTp VWu.gO@'WBgw55PWWWdHxԔhܩ{_|cvj3EJ&HDԭ>1GG)xÈq{/vr81@zt^0ҩ:J֮Bxke*c m.&fpe.[PUE(̓S3pѣௗϻ3^Gw3i GcXtxpB({=?&=c7z]  y N,CG k!,L ᄏʪ#N ,,6BR}}בmga"m͌8(6WBě>Fcf}(׃͏lmYw"3?Plłzةk%.q{wc1$ȼR,mgҊ&t;Bdibz;r Scfm4@,*\חq@5(Nt}L#T~[ :"C@+8wG` G^Y'SnM~%}簽Ƚ6t274M:JӦrg'v/&㭵ysMw]|ӹl_:@qW;~&ll_7/ZKN؛;'FNU`6 )1Wj\GO8{oC^(\ݐw,MOd^KJ2Q˸Vi3#ьO>qٞ7uC4󌄝ۑeta2 ƭ{ӼWGatm/o ~w@G0fca4jW8M_L륻3q5_KgZ*Agwy뤧gƁ톪C!9tRMMlj]Z9k9cԒ_ Ѭe~ @>^2t_f1rif_Y_mqܸxu41`rk$ߡITUQe s>I0M߈kwR~v_X dnrڵכ(M O󨻚ۆpO|8 /%,N'Z2h2#ERtRA&~ħ8FjZVƯhV/1nfuU封m5tT ~rXP/Z 9&J*\pJng(ZkT  4q 8Ԇv"A|h VB,#B2 #ŰA=B];8)SGz RԱގ/9wqu4ՊݩMKPAWv'dk8foofl/kWl OzXtv@ \QuKW+8 'M,k\o+V&h`UvjҍLW4# /Ȩ+?5% XiVG68{ `IԌ1r3 Nml QU `4֌׈o4N6yr`4U `\{ p7SU6GOj _!=JhAi<lӼ]όRW@8?NO-ϋ88$9.x-GfL_8Vre%2ztHgcla7#FuSO(YtU_Xi׎zA$9qEvHضâB&˾_1ꮐ2W=?>(. i;32򲓼ޥ. ˊ ?v9,Ő*o|HYX? m&$%arhO mu'eLL]9_YIǨSDrlK[>9KQNݱA1ЭJ8S;W>~ q;0SIbt8qNF]^GƖ̆Um<<'ƙiv~w4sפv}l-vLYtAǑ:@Ed qI^h|#Hs;u(:5tfv' )ؖJ̃Tă.T^R4<̏zq"< Z" GǃB*19GH :BJ$-0AޱRYʪӴb8{ V d1z$@hǃwF$h|#2@ҺU2$iBRzO5[pEgࡕ̉x AFW~3'~׺tU@*-K8׈kTs)2EjdWq:@ךvTaCA )>9 gCZ)]dzyn`jaՈ"W<xt8G(Ka 1!8mֺ031@̎ł|Eg9SL zp~s2L(0Dʼnl$C uL 0B#nV4j~+ QۤÈj˯̀mPlnny\Aܘٓ>+)\9.??ޛlNYXӤ}?QQ+4ۉtM;_3ixPdw*Nt1XȯS:zKhB#=Z{~H"łűI<"!|<]!s#Ra%ٸ#vJRU]i^ɥB<:OϋaËpc&=xoȕ}4%%~6RX/KC a3iA_;FUf5_|:/BSSTWCG@-łr݄X5trAȬe(~V,jq_TL;ShB 51ĭ2ӉA(CPlv#@r%ΜFrA0LJw p@[E@9zhRrbs-,Ȃ["zVUyWTT!QK^~˄_҇|n pу8ӏooض͹ g&!nat嗟l_޺ E]yB{s7\[) ,0P&^9#?wL3Q~#ր%ǾcbyM(@~ >HQQ̰@_7F9#er>"$U`q-@ťL+.m| y&'ah8 +xp|'Xp;ߺ {O#$vlDݹ<ㆿ oC'\" Nq)$jK##´n FFK[y:Tr\&g|;N@ζ*$gֿ6y͖ng qfkVYĿQ4<4b+ЕuT)# /5yYdPhBs*4ύQ`jF# $.@G SߙsPԽ2n6LzQ*n~mobOÀõiXxU 3uIIy-Y?\0Bh^CNwGTy*hqH !fQ F w|z(lC16J5hB!J K"Zh X88m*O{uyf9#k`5ur.ل޿<{c σgZbX}cYW\XuƊSSoL=W쐣 +cU䋟QYg,[sfدj= u@f*/XܦoNfɽ;(V m°ӻL~L/v֔]]zio| ʇ7}w+?q-!6[vq8w=[[@< aa LMQ]^D)PXXXۢTc 8[#[7TsLݿ(jLnֺo"&R%CjxV!dDj3Gxt3y9alr& @h4lrBRL 9<@O t#\23BHSGuBA҂N‹`EFuJ<@{Fm`<ʕ9WvJ:qyyI@H 1 SI0-\O/Q ~0`8b0?C[pXKϮ+1+.c:dj #ӨQݹ:D(%{ Juݓ(mB:π6=lwԕ`'p9(Hs;:ԅ3:y5-9fuHhɰd{yDw[$ט %Qe|D"²\E6A4sz1{g"tGvz;;JRƇK,HEUSza/O؁M 9/ J8%A]>++Xr8P }(?ʈ}*!Tjue q.J8d@a]S1P5DݿMIkڎQ.sGO]bvR),dA*BP>ZHEH$Pp12_wHaUwv$B|)CbTRxy:"i,rÝ6Ň:cO鹡ۦA@ysyf'5mP!{ڮLJ-U,8_*ưӦBR2a32vx97pzER&\`s+8 4k'e$kP " w&:Aчo2իLGF edF>)Àz\# C.Ze6m9t )@؆6 3ůŬK^TxF>pՐWfݍDrCnPciV5QWV7-`%[>h,jq_TL;S(,.WGMHdj1zE5q/,)1/A>saԐb(oH$klW'/A Ъx^~ײȠUA'UJ(U ϭ.4&9H=zznt\M^ A"=ķ$Sb1p1BczJj!Eq,-YZ^&`H>d@}CF@OBP8ܴοuD/~]oVpPE1A͹ޏ)dmcӼok[KgtмLg35 m*ړ IDAT&XՍ͋[>BhőEnfp[ ?7$}xEߡrL\~c]yU۬mW#z6Cok<yTpJ?3ri )Xf!Ybp`. e>C2}owm3ncB#`z 3:xދO>4}K"9Kkqh (uT0f<1&R whl1+~(C7*[ P}܂m W]~I(qAc6cd`qR-u_.,vG"*ik.?C'W_Տ7hǎs7:W#=v̄zTedm8DdC!b~OTwׄnQf?#wٿR Q|Rt8ZhKϬ7ooOgʑ/0.LoG=):и,~sǸ+؍<]y#BGbs7\[) ,0PB?f*xx(ڧձn=,|޾YAzt w %6NcE`D}hUdZ[yx&gB :g<SII7Mq/WGګ#΀oNdEKe.Ik?R$|rpiv7_0aZ\mv檩\lBj"*n~mo0MG mHڈUeHciRp*8o^pu*HdǽKV_(?03vyɣy/5`nw ><}l%7NcrZ0Bކo`zW.`vT9tQAMӔQ~enjHrŨ yŝ>ӯҨXNؗ`0iV@ N|d hvl9)oӇToš\M8t4T.K$-F\0 (pnLFϥU&D Ȱ5m^kC*ϹX(0TU^Ag~ qU+Mm^p3wQ&~P0r,Lצa3Ē4bidP\=09"Xjb b)w7*rvRQ=8Ŏi@MeҖ¯,׍j 1PYW2àx#@{BA桩L F AOCcJ L M<5D"?A#!9 Tl8JΥGL8 A"ߛ%f}[EI-DK6;Auyuu*0Q޴sP\ VM2Gei~zJ>9y99gx=C"TIrpOׁTzO1;¸`c3+333c`=6P/`nv6{oe0۬@3"H&e'ȣ#fVXq: phGq`$ۡFSt8'z#X.|uz/#cK|L -c vNq5yrpPV)ilJ]9x+6DX&aQ(JxG*]{P$3ExP]`P$㌨oDtaYv"%Ga(ƽ<xF+.CꌎDR^J$g>𐩮+ wV&B}S%)C%K)!2 <.FȢ3Tc$zxW3<3~Q +<3:IHj`O/ t lZA$Q~'XUis(z.~1ӧ -/uu={{)Hǣ֭;bAZwy!V(vUtu+}+7Gp 7޺ۆZ\Ggsd)>ebY>,_Wa9pz8jec ~??]nF\vA~ܮ@#/%~}{z6_V}%yuH&fE*U3Yc}مWE9G0QP}'+NKD{/{J^J zI\PGd!ɳfYI$Ӧ}m]dPoDeg M]!rC%ATU{3q(bBFX$Q xG'2?4QB0Bvcm\,i06+řo`n/8-qוCM83q4OAOsC~_dZ<ܯ5'm9EGLU Ü8qYؙ:MZgrg9pnG:F|<|PEQrlDd7|"Bn=0ι GOMA摭ӹ'PX@Ϛi$#B3 Цu\VFoq9\@o5`-6U[ 8NQS)Nx> P{y1~m_]N{W<6h ;8gқD:uaӅMs8`7ӯD:0l]fO7Ur 5GJˤ,OJ`A*82JS/&;{{3Dx &lmy\|UCeKɄ0:RhyT("v"H,0 ㉤@`Q:5lQgʉx*rqlԟRiYb*g7"@*Vru`"22^'klWV AybX_8[$a2'f }j(%OIV %ljQPyS=zVT*!#suump(qLMl[25T$/@Cr 1T˷5~&V P,:?z"PKxpX(8IW;jRd Qh)x7$:Ĵ[2 h8e$R!̳+K IpoyPOHiUҭqF :P*T?!Hҭ)AݸtXت;B%1m4)Ar!>(x"B]KϩFVyՏ!ԭ9Wr0TQ\?#`}BnwNyvqgmk:&V.~]oVJވM>Ʀyֶ鎌P~pʜ Ѵ Խ/&67o.8̹%|sV `g"eYV.r؎ÖΠ]60.a`Jwo+R4y{WH۽XM'\g[wӳ 32}o~SszǦ'qW9jJЇ pv9cj)@H3rqBsm (eA&I%'&:2ߟo cfn߻dra ޕͳ3 KN ԭ{~+a"Q's: y̝@|$ 9}KMF䙸"9ؚˮ[=m{tod݄,Tz]j-W {a+-y+s7)fY89_8-U Pyw?N~3'$v~s+eʦ~6Y-N;>O݂d%|==z>>cخuH${茫1 r(|}'fKcx]9śo;yOAp`<Ŷ\}*8NJ͓w&c?9h|ck] -y楩btZ=mX`[{Xw{`ȫ;"ԏ/:q!uwEÈN #!+ #eC_~iX=oW=:Y~;rm#yߺU_Ö́~p{ʢ vJ'Ats.py0=;k.Wt=vn!FO{ڄ" V؍Ap 16}G?'7~?tsݍ9C&9rU&y:Q6SO@> ZNׂ:!.-lMTqU'5ب"j0$Ɠ\Swp#v,-4-ϙ: :&x*M)7.t<=L{@m^e]a+Zեk7B KKqŚvX Zl;-L;vGt-8]VTضZ+BjD@D%J0Wvs˟ }{ι=y oHXNW;0yh%S+{SK pf@dyo<o~OmHl#/V|N(oj`̀ڱ)ɚfHƾof?eHWIZ3{#PmL zIX9~=cǔ v5HW,]TkT+m.Xb5k5~jƢf}Cھ0SXm@@(s6WX9腞`` j^UEZݑ/>-+g5]Azɨs߅,'wEmp~B\Td'@6(<9'd՛4Dk~?M֍#+n^AA^nnȉC曽YRntj|b XHDa]A>X:ON:])psW[Am+r$M."< cH޷TTk@PĴ\Z4zh]RNd{FC6~wgѤة4Vg֊R . Z1+_g[Uٽ$Uj9mWw<#08hm]~BhZZZ[N_!VO`oLSvL >4(š7>[+Zo9̃ٚH?R}q9G:T i8F6LD^\ǴԮHYD ;'|\XG!{d!SSM Q pttB%śEbiT̂@XeP8:@ #qc\4Gz|'c{0F]=2S Fy[VG<[$׼j"q`HDDXXXG*Yޛq$ PH? 1z‡/X0PHZ{c`ё m`uu54"4ÈP|U{, R!h-n7 ]ʀ|IE]LZ L 8h쪀̨h3@ȍ@ (Ϯ2 jL\j j@T=0kMp*cȓ1̡#y=!;A%6[׈9sQԠ)[L00!MՃodx(P˲<5V–n?$;$+p/9gu{E^RR<Ə$`IǮV`9 2z*BMdUv*Q+OrQCBqbG|w#T,n}"# \GMq`C/щg#tDl;KuCFM 1xkIFd; Ԁ/vd(ez.*Y2p%meޞ\:Ō-vfj=.), N~)weyrMJV9aTE+_J~,/Mx\x63_c=|}hgE! Pޏ>z4=T88!LCe3xx{*+)e`2B"]A^VS%:=j[BY"ToCANA5W/9:١7T^~HRDlj5h t0L\ TjohA^mzaBkJwH?׬Aӭ/l0Q쵇0Sdfn<ÃI{1%oIDAT2`]w`d)Re<),-SWC"OI!y.fD@طԼ<`h)0Ce(5zY4YF ̜s)^ lX:k<*aɮ3vLyE^Q 42WM@O]j)[z5gYdUνtZ4jXvRm&2EmXᗾxN/aAI)h9m EI0!w)0[<{S$aDbXidʜ:o':8k­ q2Ih20pӓ" ^ ph;JCGH$ vAPP"eWm\V\WNB`sNb5 ܍08opb1&d̡|}etj)> wuLB%G2XTc1Z)D" 䬠ȵd+/=n0f<D7.Ym<<<wDB}wZ"w58ry+~0ryJ!ٯtE?0j_@GyͩjnS4~-3$um[鿎+m RFm?F..+8_w^'<. E_]bwj-N@ ;; dGxMh{B?BKQWJ=C%RZ8#c|9_%<s"pF/~vatC356`?~Wx.Js%˪8lkg8'q!jm+J<+s>nJvl J +\C86wAng3#<9U=/WZHM5+sձO-Æ ~DOz.^jiPt#ԝ{p\p783!}{(;3&B{g\ڷW|W/ؗ܁wW:|3>5~P}1) Sv%q`% -<﫝n=?:r4GDoDfC)\~X;0m%_30ğWss1 C$J+I{,ڹiE,ZOi?z"567䅏2 7M6m^Bl#k6Y @ g!ǁ>p[KapVnh7D~FI8OJ0qNXB.ڹslOLos:xZ]h?~A0 ߟ,@BO<ʖ{ Y%Ov 4la](퉾=P}H~JrYK/pX&noRKo1voxD~-~rC!0fy7x}6}ۜ$@`<ėrҚ/?O.b1L[(9:{@s%vm M77V]diItSo״ ٩6eҚf>\pkkc #,@f>X'^btI`NWTEZX.<.wv?{,-Tظ;DŽ i(O=ukR_h$sVB%g:_J --^&w7#-V"p͉)#)HfնFz:<5`3(㝣x3@S閚ukbFoJCסō_yg6Ake$>*1]if;tO\f ROgFqh伨9V\ .\+}i5z~>@>- VT[MzoܻiK-VќQjлw?G?1W {vs 5j"mZ^y^h%܉4 B;'{qNXKd@ֳHbT*:$ ykv+xmWֈO6v1>igD}ͧg( q c㉘\Owm!8tl<(=W|=R3Є ̲5MKZ^&/c9+gU䅾Pƅ mEpFB52cUg{"5*ro*=}7٤FU3h{~~eo`u]g(v\3qQh_I@Y>+Nl4?w(3VdṰO̟};͡wt|li8vě]F 7> qeyDv&zIPcLL}eOXnF&4ke#6?8t (&t~0!""ouE]؋>~ʅrr%NNuEkpw,)VÑ^pmaE )VÔmZ|L|xt2n5J?x6ȓ*ѮaYY7%FBC4S̰VV2ȶT^]J(JS.D'*>G`#{4y3g6o&P7L4I㢵]{ MRyxxxncpϹz;J0X9\XGGGG`"p;̓Hyv1@iwzP~o6 \"Z3U :^?\ J]^aD88Q&8!A [$SHH(T7 ?PMnP&d9psKĺk#uCSލwJWPMPih}yz:Ż!(t.uTmɦH{hl*Nx{d-*Ԕh _$8V(6/FtCN\o0-8qf$MbvϬAuQЊY:BB]{z T$03 ZzJ㈀ڊ^*zdʶqz(}-iXg}wHcHzO#SUrY:K@\ qDItD7v~|W,iezP&"@Q 3DZ ag<,BNtIcIAOGy*1E&$7T+(f #ʓcsˡӀFEKw y6*~m=} !T;)5WC^OJ=L0Bi>hw=\0wZyQO, QfqDC,1T u*4ʢԿ2qry[Mى[%ڡ~9CUYP-Y-_>M Xro&MW_n0:ڬ%mj&{cQ' % y_IbJ gxbMzC%]g464$6teT{G' %ЃU[zLp­%+LƾuNۈ_ ۡ7z0Ph:Q> ~Y(N6䩷E`Pa?`ћ aP (I{ִ͚iӹ;{>U!U5*dAR pSJ8B* c癨OrQCBqbG|3lwbH( yԒp$"qW\ZJEuA#3邑NI*K #L_{T,FݧM H I,W'ʨ:\TD,5ݫw}yl'ˬ,8bhQ/~֋O-4I%)vu`_QDA/%,OI*o„DuLmŦ^X8t7ei+++gh陛g~CnSgc=,V|1ah*+w=\Z 5E\%^Lx/KX"Lh_Dk 6=gѤ9B柉:.hט#wRP$FJJ'Eb,}R~ vaI"q/W uquaDl H.7~5=z [ߑ"iuJx!63y' P #0i 9E/|p]:ɲ3AMYF5g "#P'ľƮafW9,%{ RfQeihfma .?BMgΜjhlWY]f & i )U- KZu+?>2jШ}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP(^1T\~7mډouOkE@PE@P~TPkfc̼g~ k,Wdj1c("(@(b:}^^z>X_6uIbmݖIzvn:7-x}e}gn%\}mu/6I`1Pm;f({0K-qjW է)~<珞?^z}SQnvoB͜m[/lR!Wmzfn z_kE@PE@P$HۂGf?.X f[d(dEԱE?_6k0 2~@޴c۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{mmnv۶۶ݶmom{msmnm嶽zk"K-BٳϯzM*r0BXPxz/øNj`lctocqbnԿ;LOs{_H0Y=  ާ$w6Ϳخ:Jm`vlŴkBC ]sʶn˴DoزVE@PELE8:/>:\ΖiMbŠFmUDzƚ:6}L/mٖk+{kx8{)~OqG@?{#yEMj^icƳT a{C߭vl}(ϲY8.1;peW RN?OE}6 |^I &άMjcjJ]EZ,:%K'zW}mSVgMԇ+7`)~npG=}TϏ/ߏ9Wۋ-dۗ^ďkN줟kљv'؋îmv0Yj/륏'cMYgc{L;/Yj/S':K[Իδ֭1n~3du|LL;/Ylj/S':K[Իδ֭1n~3du|LL;/Ylj/S':K[Իδ֭1n~3du|LL;/Ylj/S':K[Իδ֭1n~3du|LL;/Ylj/S':K[G\Թٱζf)sWfv->>lq۵de1,}\,~S6DvctTE?=1}ojOM?|\6eљ5kY6r1mLlKKXapɮԋ,q[tfm-5OM鵅cO$&1:_n:k7[7'm7[7۵NMgIM'vf릳f{vu~vuӉ]ٺl?iٺޮltltbonn:Onn:k7[7'm7[7۵NMgIM'vf릳f{vu~vuӉ]ٺl?iٺޮltltbonn:Onn:k7[7'm7[7۵mm7qY=':is-p.n̶f1l/~M6cئ.٭h)$YQK`٤#)tE⊿W-fͲ3}ujW7U?y9QZ=;άbdљ5\@G.EzcƵp,?r=,>ikMȮ$e<>whQE@PE@8n/Y{n eC_rLN ѳ)f[ံӮ=֛mMY۲yb\hxGګN<}QE@PE@8DFFx|>o֟4^:䆪9K!t--[mlەJMVv9W%X1Ev,bS/C~RP+ZE@PE@PN&XZZzݗzg?BT2YRf.gʬ6Hb+5.5%6Yj!DzMz6lxyqq1kQE@PE@8E`~֠A(t0c6ʼOHؑ*PزiCvy@H۬Ef;s_d[ںp1@NYE+]V2tO~q5dd &&2c1yܼ.^/2t+^]N-ۈu@+|^3Z'%!UK7`ξfk-š~pl2^DwѸqc4iM aCeȡU9Vj!^19Ͼ7iеG;ѿ`_}1l8O&K"`"Pewqh<} ǚvQIừ"(&wcuR3IR:g?7ipɮ8I2Re-f-6\ uә`92z+t~MlZun˲hs'~Cvډ!-1 [m֥35k.޽M6DDEF<(ޣx$$$8iiiG[&JΥvI8m\9Gq4ڧ A3,DZԮ e4 zE@#>'Cp?c`f BZ~-|SGDFa׎}(0PIP3 oBnyLXo\n39e߯*R-YGd#6ɫ̓>vT(qߐF$d;o! ǣǐ~="Kc }~ ]&͈_^=RPȻhp)M"!lÅ}(W䟋w  lxĐjg(9ZHHAT$ò}nfWH+@X-o/0|P;D^|W,w! H,^-O5VE4E/H.'D*$Udc[y&&dWsx"\}YN7ѿ 1wϸ5cӰg4}("P;1o\|p?[YgBj:E\sٕ>iK-DV\ }!Wvr##&iqH!bKEQQtpXDӪlGKːA?9Oc/KOjs]r?|vGK&HNNDLtCvQ(6أhڮ6 \_E e#D9鱗MxwRODZ,~bݐWM c.o}.0x )z 翘GuFD=hd}=^Ie9x1O/OcÏ#c3J9> SgOǦG>^[>5==t9 Pw>3= h4+ُG6dpE .@`t ny Gg`P@E9~y;ٖ7PB}(>~{_O6REd!~}DɍHHW_k!÷ ۔6hD]&+0۔>X P1cF">'n1hVKPDc斠 cjQP!WWFbJKݡJgc>ؓٱx8~8|X}r,"='a?H. n_Fְ}"lߵ E2wGB$t>W႟w@(EjZH\~q+,нIC?2{O3.CZ oIጨ/"8T?Yܲ,:F\J1eXl:\k:L;D6kCr[Kϖ~*]2Dȝ1ôZIA KznнB|V"5 U].˶,m~U[?}QHEX"Q_+"")CC+tE@|ZtV #bWrA>&f Ij?l^@ctAү:{>=s)ωj˥ON=3ر|\g;v9FQϰ|/R[}y^wځ\QEIx_Waƿc7"J" o-+^ֱ\N(z֕:}"ޫpv]{?۫HTf;ypљ2ε~Ov-E_(}FAu/oe`Rӥ@:=pOq~J*5޽{˷cˇ\ʱJ?«8r۾߭څKzw@ld b"c[1P11+/_ۜ{}iQ ЧYGϚV/Ý܍=~(˧irLAPm!cĶ鉡x{$D=y-nܽP-]aTJ[x#GK 7.Z{Z:>53("P3 begl+ėϬ踖b>d]ˉpk[y2XRkm_g|9Hp>B-_ Km!\ .IHWc;98,.?o#vR.Q Dmؖ},-:{NspnV(<(Zq(w]ع ~q0,E F~T٢Pv 23 /_:[f^0kۮJ݊ږ͇Lki5>Fd;+,}5iz+ÝcQ/DѓΘ#Lj龽LfَWwSh<͌-?.LvثH;oÿ)h޲!RSkE&;î<\ak2OT(&1h޾-|{9AW=λE 4.A^Q#;ضu'JY,BYg5vs?zhՒx{SJb Ҭ6=[-[ X1vj# su' }&ҔB؎}@"(@`᷑;?.?Pab$:߬ ǬM=z[ׁ¤ԭެMI)̵ֱLRE>`IfIӟY0lH!]}rd>ݫ6Ydb?O7ѕ<r W/##"ѕgJ$|ofD6"e% HO: ?yD|Sbk((^E n)%tYR]{ Cۙ"藝=A$mrVV;=Q|p$.("Py(z:2yr+2$,D\s"̲؈l,;%m LP݊ZϴYb5!n/5O~Hq݌s31=DwcF 潵ēLfyeWora,[x7؊:xߦ7ymJo^)>ՙR RE@8`$Ip>FBH*X{lnRw¶\M8K8d7`L f$aыOŎk؈ 29ݱcG`-Q g5 <\ԶO3ؘڧ("(qD@x_PuR^eajYc%\kjǵ)Dox皋FVPV?\K^E@PE@P U$3IpA{'mMȤv8M;s-]ۙsڔeR`;_ڕ7|ckQE@PE@85`>+U;SS 3'W"̃m-bEϵlEPE@PEDyݸ%\'vRm. i1n $2mK-5QE@PE@P/p,Kg"}PlX6U2^eg_F&K"("('I[j dz2K۬m_U];6y\D'mI^okIQ)>T-èEkb#h#Cm-"(s82dn'p@w\ԉ^lÚԄ I%1I[؀6u,7m8gp18Q+'1E ?zz1t*=sO"(y8sQ4!ҶcZlwM.'V8 !/ Kr'zxNdsJCEغ2 /iQ^]&MbѮqՏsVzux"(?-:!ebcrFı_إ&dKR\K1eqFm[nA*"D7kvE+{Py5~r=GF'$ōQP¢eJxD(݄ a6Գ[OtmP9+  dHBf2:!ڴeٵDw:R]ožЬa"ڵLCzxtk U*a"GG:{v k&4nIq砿( N5SE@8}&5όer[! (lc?Odvڍ첓 &u0<.f -ߢk7"Dwz5Rb1h"h%ֵBnii) P>6gÿearFl%**"Md5\D'56^mĞ}"1D_֍a 'IYK"&)~ƌy?.oY 2-/v-!^2bbb 600*AG_8!]Lx;ih( g6:`dPJElq1Hջ4!gNSP3 >LHV>n6ajBv%yA$9O칖 r؊Ng,;WuO ^ڶ \oR*#""DW|СCسg8|$''~hܸCxy zp7ںh[ߩ-A"(gBLg:-ClK>mH$g$6q-):[.^,@A[.sEW }0/>> }1t)6/yv *v#//?7b޽ί,>\sM>G\բ("A`id=~-mr77|Sll*RsM-RN3`~b'dۜ8VN,;o3]_Aigj\iEWlOV}`7n:^r9D"ƚ_=p .f:Y긡ŶmPPPjʫMsE>'s3c߾}Α33Љ+?6vcUM%qˏ3kI^Sd{.v:ӗ\ 6l[Rǒ^lvsd4~` вb4ٺmĤ.㿪z8nF{ҧVgmRb;Po5te[g."Ni]İBwv-$~]v|6o9r䈳_"|nQ8 @Fc:<lgcAE|s0lѢ==\8hq0:REa{]*BB ~9GT5#w3S;>dϮeN,65ee;&DMz#hwGK0- q!NXIV^gpӥ?|0 Ӷ߈ǯS%0Q }%܈dֽ5Ar&xc\R,R ǽ)3qi(:2X<]+Ύq_u'7}s$4~^VODŽ6+I_ͷG1+ƀ]83+ޣ˄˖-[pYg92ܖ"v|򹈣sWgbHI ?u7B{:7JJKլ}X8aF脥SX?nL"L3$x G_dlq3p@Y[Xp4ys,~w+&Y3q|nC\s $ c⥢;z %U|Ƕ2C݋&)8yNNRNBtyب';a#y=FDw #u=x{!8$&j43݄݂ _ށͪƨ)6)[nuD!f%os`Rl'fn*z\9*#-;`;n=sK_v3FoRV9ŷib07:ǥV"BTu-To~jr֥fBשY_Z6/fՎ:c:cSY`gZf"ʍ7~6 YMep]wU^'Ň]ʑ 6w0i@X?c< !㰈{I[W`s?6ѓtvUhB-۬F֬l[igѭVIPS _LE};V8ӓ ◌3Yh6mڠ-8(GNOd-شb*L; W7[ [1r]1!^& =F|x -~qy^x{}LcGAaKʐ@&gQZzYؿeLـy٩"[^i8bҎ!D4qzcp%}I,L2 V\2&g{Ѡu wP)A!Ԥa}@UcH!---@vʊ.EnЀږB |N+?G\=eÂay BX3V,¿"]a9͡qeyݯ `Ţcg8%KQx[4nG#etAi6M۶Arm?q\FP"(5A~0@4tHK/Evv!^vĠq"Qelنe'WӁkZ]STZZd/ o$n&&~R[qzU] T1VSќDCǶO;[Mg+=_j4N?|Vge&رK\4V`#H|&yǎߓȡhjjy <۟ (꧚W V>~>cxvf4i$j-@nrKb"gx|.9g7_ ڊnB2jKrg{6j!}?,T?gX|.i۟hf(">^E?kC%E@@b?"^-Qic$s[ctο^tEx\s;XfLǑ9WTw\۟ oz uԒrhk߄q-Xb:z(\ Y3i ʘ[*y%E#^,]K" ;cgej>nōCp+ Xt3n&|'1&'N]ū b1݈nsl#%FQ}^1Z{q ^yyLR3o[ iOL=ohf||XUbXciM~po_)TsE>'sՓ[1ڪ; d8+9ɛacv%^}bc7e;&ԚBq })%S;>Kۋ/q+Ll!HnVG"(/W\ܸ|!萚نw+|N:9wq7u2Ĭ4rcVg\3] sZYjӶrMVgP3i7uaUbТAdHgED:"㵚.wB4:޿% ix[BЗwwGpx?ҕ@lRn[?ŋx)]20`Vո/Ư+M{m!\}?>x7Ehkt |h.{Ϛ( *2poڇۓUcTX+>>x?A 1o_w9F'!9197sd3y09ۿ'b.+[iD_E:I{@#ԚH1~|LZO-4Z,{z F<1s.?[Z(IE˜܊]>v!.V9-r}֒1#˜ҡZLǦ8*zo܃'B2.9v8L`^_]lwL̿x&ɸoq1PQHӦ"J"7TЙ~r. ;n#xWm/w'#^/n( q39qe -9IHK۬ek[5Dћ2q>X/}vݑC>E cNχm4}(;Mѩu:5HDR\T%!@Y(D\9@)E!Ů.I &Y;MSp.F_v8 󑐒Ѷq- _|{/Aǧ"?4E񴗌dRJO|󁦂d`_>rW$litFB|2RDT"(' *vO<x%aKŹ\>X-}e>Dږ^dR,;aFIHaEtR[m\DCV|HǶs0-%!mkHqnŷZS*?˗{L/D㣰s {o> K#X/ SbjDt=c5훥UKC~+ETNnF'#=#EE@8,+>KaD'++w7S\drK:sO2!@ WCمu+< JU(@.~x_QY5օVch5UE@P~,f_uv JFgn&ፍH:= 3+Ѣ1|/EӴX UkBE@Pp:l'^tn^:˯.ȮMM] ፋt6I-㋝J\nv`5T<}tq.FcE@PE D@8MfUm}]];srgNFL](i3H5VHqLWv]Se'Mx߸ZAΊ"(fcrP#7ٵ'g&oUI\MWHo*I"("( A _cL(Ǔ>jwW8q suUkRj("("pBonOyڴ15~YƶCmڒ9)Kl{^dE@PE@PN}Nn1TL*5]ٵvnUS"("()@ζI[lvәՖ׮]oC^}LGM&Wǧ4B^ lh\v ++?ưۈLG.? 1H ,z70O>kzkx̑GSѫ ZNEv}*9)"("I?if٭I2ANVM]&sqq1.\g}۶m eѣY@UIع" y/~Kɤ-}~߼kA 37Lii~ ^qǎ gPi|m("("p # +E_a5Y>JLK;ٺ2ipwSN@EL0J~؊>#w#>Gs0옃D}GP*'W"t_|󲰍E@PE@P~ xqCɝ d/cx5Y fNԖ_m;TmV;##w}G 3½>zrwzЍrM2YĶZ_fRP>IA'Fgbbb>ZPE@P7':\+ډDUԢ}6|bcc1p@<h۶m6-jڟ8 k&R^7o?BA޽;:i‹b\2Oٗf1w݉^a5؏*("("p" PtRwbo–% MDtR]uپF0n8ݻiN՘Xo2' "" M]HY'zñПF=;ZO|5q9{6k!&K_E@PE@ `r|1{lo_r_94X:jlZe^c+ƠMٚ;^XnzrÒgGr7=ztDg30vnS-X߃ YɁOئ ;s!fU*ֹ;<m }=5K/0%عDi鬒Mӥ9_ah};DmX8vf.^ t}Sa7c)nߩEY>E6g6fM0x,=@g3kh}4p+Ͽ|YE9i3 mlb60vynZ<5@ "p& aBћicmk|B2۸mIԔ%=yS/֊"P rNƠqiXKGb̀&|9+pӤxld}-fLwqmdzJ 1sX 29uVye7_0rlӥYlo^ [yd}Y|Yy6#;kZ7_\Ps?7|: >,pƬ=76;/z| ,8٘mZo1rMNCQ#MFlL6SĪYW^As1X μ ~uExl<\*| 0(C&x,Yw`PoA뺝5vWg`*Z?; K'^q !tv {::͹|Zaoa@;:o۠qxhUr6/107#ecI8UkȶZELC@_y{ىލ3_Ŷ+v"vN;Jru9EgPޫxe#Ivn܉d^GV@t4MOEWG _-YmX|)SA|bոmd,z{5Ƭq|;-.mLO<y8gyxt`wJ6/aէ#h8f"=nhX˘x ?-\<-YrzCšV3҃1{Qd@rt6')' gһGz͙W継#ѣ HOF֪N~_Cg=' 5gxf*:X_EL@ \em&~nf\Sk'bLmWko=?7n /o#FmMZZ)8t< : Vh.ټ2K{}&ȳ0>h3yz9b.`}w<:9)IFzbcOa_+w _ߏ+ƫv:ė3 ɍ9j3X6epx̡nVɀ u,v:4,^r"]cUnEhZ.e$KW}rG%v=Y-xbȃKt`$k> ~kƀ|x,Yi4,,}c$s[LֻE0\Z3`k&Q;}mHK5PN<`-!.)m-;?fcӾd僘:?Dn2qsB|'L3̟t78NgAYZ/RRqC[ѿ LOv1 ||8VCW (h&ĂyXZ~?#le 2%mc?h\J>Ѹr^^̱4n_Am+$@,AGoq^ps3Áo)op>-`HsD!V^}f<5rð49+(|l9ܒVIUMS_N!g(jQP|}Җ6b[ɮ$斴$gmk׮Ŕ)SgLXp1'1hD k@üI:OWv 6җy1|LҏZp`©@FGFԍnFh?1wٳ.h#9oЍla5}EoDʔcS \o{U㰫x55_Û)FF^+X1bX:yCcbct 㞿 ڛ|eXsZPspڇhhWCsU 1;_1NϖآVǯT *7pپ*pLofڰ̮r^*LInwl33^@siu+ z%V{ ;P;\/Mqē h[P~_6`} K'Mc։^df:m|Don6#Ϯk5~]Kh۶m˷q:ƚOqpټ;qy k_̻?375ƙhƟoyWIjU88OP+h 2>ۄ sz˩;SJch$Ŵ WKwv=5+k4!Vwh3lsW#W/Be}S7cDZg&rƼfU ׎=}.q*sW۪)FPN3W1j">jذ,m7IE u@ϲSpVp&RI siӦa糇nDCo`h||9u@LV4=ZH0)IDt9O&6e=L"ptaDɷ9&\۲U&ϽzzBBNr4YqµcONun2u9wmՔU(f&ĔMg^5U~T1JLK`oWx+}Qy]hzjyr_"̦*tMREF ò6E@PNSL d/cx5!^̉ڲuVw[gj E@PE@P~Jznn:X5ٵ0'}dԅ("("prN畅Brplƪ?dמW%rE86^WE@PE@8k74y٘AAvltA'"("('/$QެMSo^;kۖAMYۓ7"׺>BCU P͚ZjE@PE@P8c/Ulkz7N ꖘoʜ}j(--O?c4K\p>Zs%]߄ßGJ>4s1ҩ E@PE@8"ѣGQVV'zx->"##k{pymg>3ٛrMɮ633eۦ_̙34hׯ0iJJ]<ѱM("P}Q8_0n2Ѿ ~aebɓ'jJLn8{YYYAqqqbd٦MuָkРA[a#rI;ؘI޴"הV TpKv]x^Ak׮ŷ~`qIIڹl:.!y++1}XJ@捺 ;߀p#o㥉CШQF֦"O~>ƫ(BF?F^&j5̟?+Ve] :t@rrrشi>s<ٳ' ( f>i?۸'캮i$,9nsxaO(!.\UVah۶mIw;'۰=4' 4XꝏY 1[^^уWg Uxfrh(7oN:!!җ={j<{n1c}wbҤIh߾}],_|~Lnݺ!33}K1rȠw5o.&n_X&2$-ms':i-n:V21m4q4"`={MkKG"ď1q Λ|[1[dP_EAWMɋJvPhu`%сNVtwڅ'"-- |uā!˱c(Zj|N믯%>)smlkUjBvkLSWIT9##.ٽO?Z?PﭸИ~*2^dtzZY&V,Ne^83/3דּ 'xnvvD;eDߵ'xZ4(;ZFq}WpEUVn5S_a5!^Ixɜa'[[Cׯ_?WT;W<z {5Jr-[\CͿ.m]AZZ8*(}ȧ8~:O=fM[+ ``5qWE@PdtM26Y ,A4uAK;vo_BzMR ʩ+k͜k >D|IIIL LN%s^!?9Q[6v¡m{v1ܸ8]OG˚ctϯ>;Cvd 6R,OX"p߄¤E?m ] $H; ňCd`Ts`c=pWIH$ 7 :L}ѡS&gG޽{EȨHgniY)iu2"#t$\Jxѫ ]6_{];=/t#i% EEE[@b ukb;IKxf6M[OaÆ1by1w_/.G#ݧ*ۺ8F+Fa1rf=P s; kPugڡLnxܜngՂ)x~8;DLm=7 ] h{ =a%!':ixRXt䫤yIjhzknE_2bmxVwkwj^%uOۧ/LvN׷YfbK̡  (8#5-2s,*E0[/8?[v}S짱U1__6oﴷ,=~O+Ξwb}{Ų{s4 (_ƊI.8cɘlXW9N`NlatfP.ȮWnԜ\uN??;]5kG;ƌZ*ۍ )HK9CE LZ߃6E۱䉞1-Pޛ=BwL4Y c cca⅘7t6y!9v*(|0Xa#@a0OŇ/fueǭ@Zh6aBv0@/h.}_3y?&9{k9_b`F`?M0x,ݡe [(990{(i|ړִ]j#4Z̄l(K)"~6+U+?]A|G|6]]qA9By^!c;J0oaD@zBV+/aǟbtG/5&0>o? _R ѶSsNc{}w}K~XХ.el⷟_W9 ndj<_;c{ajoH\#Gs4&qWyB&r!\df$3㏢# +;`4rñ*fNńPB|sSGq&ohO._Hxx1H߂҄1l#U@ Ԕ- 3%o-<. <俽Q6 ZJ/i );ൂqě).y"_`셩\]0!~:N`i~ K?|Sc3Zk9>c^;>|+X71y#0W M^?,Ұ/G3ţ#fX@p9W ŹYxl| RI49'KCߙln_ox ©qrs.3KA@*nXY8C+ moᵥk%,0_QQ]`7ȿ|{nsp|i(|j= Ob`RƑGqFW"wyhQ6muDrçף];W!*ľ@;/f}Fm@+!2۬9 f w9176GLo<zзh]tm+7GfĂwNv l7VN׮6ަ2!7y O-o+TVtkU˰km WqxI43-vlǦ~*mqe|.H$_Vo==/i?f` -)E3 􆟯'K* njl7G|-bǖ87NGbظ٣bF6<žŷ9sJۃO#۳6O % V_" E5U˶`ZwA?9y̒;:f}\!@'&r~37e3w|?~هQL&MBF_<ЄaP)RC"{ ,(5@RM;ͼSd)ym9Қ]ZPID+ 8t醟04umЏBkmlUxҕ(a$(˥*zS*y<ÈEhoja.r zL><m+wc9_ GM5_{А{5bi-:ϨF4>HGDiYm:i |2M#|i%/S,חَ|$r8n33bUǿU6;Y"3ϗۨ)5EttczBv0C(_5•+W4bD /o/nѫ!?@zaqtZL4tػo~}ۢ'N܊Pmǘ.TGߍdv~ÿ"m) _cn<$nE;qx|#nDM]E85Ii9so';~tˌA]5~fOktd} fNztd.'᪱\ٺ6 |D{!onhH2؉PJC HC\a6b=cKhsyK[-ys)M&f31)܂+]$6qOMX;5W[qU` ۇtAШNB/B\DvAqwmt'랔;|cY0KF9f/IGfk;_XG'po BބKRi,;Q9 W:ՎP/*Vt>љx'Ҧ}zZoo4{4im)DGg޴fJ|+A>hnYռSYF<|#qHs$͊,:os8EˎOvaEW:OңhGJn{ݕB"cҤIny2#fHY@,D h]hRT;`UPPJ'6X(cp,΋N-1hA(+ M]Md[?Yurg?l=|;sC N},';vL?Hl PRJ(9Y-qPGrxzhu5nJd]mDÛMiЏJ߬F(?>E$*jj**y 妥{50?rsv<{it cg5h@%"%*-#()9>NDa¨'1/̆`ۅ4q ~W;67Z0wUIKu)!ZMNL.˛agU=4DwͰ]D$ljM֯Bt53||[(IvlS!^gS{cg>5e"|;=u91b"$''k9c2n&wy^O_QvH_n7,זd2r:-gee!>>^(``9it仩t^$9|)jIvd " ey&%}tGUjz *ج`X;y%$c4O"m,˹tԐϾiĂT<Ψq`N%Ov$p8!3Hgym:?|0*?h2y|LC C{ |N'1q7Gqys?}6زe  ֭[pB c)6W<'td7\zUu:DŽSRȞ\"/Qepq䖟#** m۶nuR@Ө?E.w圾M_gLs{B(bx*v{^ҰFDN˵Iȯ 0C;ʒ_ճ,A=HLi}ݽ36+'_%UYD/;Cj:ұCPP#{k;Hvptf$P&/N jfxSاF]ʣITPT?2ꫯuT^oQ]~zRپPe1.˵+&c2YG/c-ڐ8!&Ί&ng~Ow.I_t$Jt¨q=mV,Ȯ|F/?A=zw3qQ5٨\gl ]HtݚNDJOk=h2Wt_ǀR|BS=ΉHn,]0>X=ױf4eTV@גG;}S`>DZ%B@!PV<7|v#?lWEQw;53d'vV8mMB~ ˃ٗ?wΚV3"s0~A4VmEz}qpdi;#b\& YX[_8rg6'xοl@9KBNXHgfy!MJ}h,$ۜ=G#B֏^F>Fx,/fAVP( B@!`C |݌ɜЬvCu â.Lι,e\(|Ʈ(\Xļ9UψxHW:[)MXp2*WfЙ'Q!t7h :NGM99[–x.tABSA.٭B@!P(nZGG3u:9g,윉1'!ZdWU jtK/EE k'IYiK#TV9glMxYK >:@]DgqJXjipY5sR%M.\2* B@!`Ǔ2wBǨ,s,)#]6I~Lujh?c}N?k]5Y+ B@!0D@d(Մq?n )U縙3B.7uT5 Qx L+B@!P( 7H],2f2V?^W[Iv\ؕeSB.D+ B@!PNgtdfj,kw@ɓmvUW( B@!q U61I^dW?9y1\&ըP( BVpט?Y. 3ӑ]9Ŏ75Y#=tRmj#p&n^>R®)Kensx}t#c7M\>LMԼjP( B@!SBy'td\zUu}Jku 'y=vB^/"BCCuFptf$[+:ݮC0 SEXO®p|vR#cϺD?٪L]9a~0:u ۶mCYY6Cm۶.TB@!P(j@u|MD] aԟu䢏y]]+m:;/džrGpFLL ڴi^Xn(]{ S8˩%FFh6DF.#toiV"c04<8lSI8n:=<ˑ:7b5Fb>){ÝF,FtP:U^DV¯^]UQ(~$_ Wm7閬3.zEH&תܰaCӦM3$ji!l|aw<Gj)u|f2"wG]X;-R~."LMSPp|`k׮|5jH>ɒ05{.}$>oڭ& ׿S&AyM:)]s:#ց*( h]\:\TwgdEY掍[ԩO஻6ox4E}7@֠p9m(&B<5,F%}+UW#e8G{LI#0O?ۣ0m1pyic1|:gEڂ.ɯq$yǒhgraVebl/<5e Lޒ/_Hxx1H߂҄1O-)9|ٱi~Z˾9c p)uǪPXx6"~.B! H?6g(2'ȉϐ;QeB@!p;"`5+\p^D.\gWF}d4yĀq1y0tm-ȭjPܶp0u:f9"}`އcP\{4F!hڴ=Dkzv*^K=)m9z_ s1W}ctD` >7Ik6)|8g ?Hx;P7g-񡑃{al=+VYj<}_p&uFFS9s(I>zߠ qBalHz44ڎv lJ5E}Aٺ1ip B@!=L.șOv.ȮF25ĔB]zyy|$eHJ R֡KH^CtOV9~+,m ڞZȇBWn#WkaEDWZ}0"BHKKN^*Q9f$pLc~ޕOj5gyG*X3stxqDthS kEY^/'M%P(?$2q ȅs}C[ IDATuĎ?>.ȮF2v@TA!p;Y]/ S1z!RSSydd'$ii="{^3,Ƈ> rs]Ek}Wp_*B70bЭ S;yf7ۤnB?Pba%/tGՔTAxx8\"#y JIo[Q-sh=P7Z 4k_ZF!RC:^p9pĸWXK>ǹ)sHcGCl ( ,ԱZcٲUUV(?*9yBW Q3LGٕ0XɓrY&ReBMx}[/>~9]{v`D^+S#CKx|0:ӦCkHgG܂C/FXEGp'aBdmU1_!ܶ@)h?|~c0B$׋hI=yxjdLDpHw|k(G0.ξɎV7enqjzDf};r8zȸ>chYn?m3]ph]cmsy=I(H BD@p:1egk$3Ucq (s&,\_gB9׍^?k|:sv]Yû>D~G:m <7:_&Mw}W1T'C=FNN}1Lkx+whq +]+PFY/YǾ&UHm+<ۤ'fOrͤ gtQvz(>rS۸0\'2l.c^OzVf*ZG7=|ZQh[{,c @"U+V[nغuv+===ѧOm}+=6&/DTDđ[IYhӱtl a"`fq"d_4<mTɹlH m+qQb{MFzn9Ŏ`̭)]t IIIK%ڵw aj :|SxOМLX)C+؛8Gxg4ڽwgѥuCm:Xf'13}31ϛ0ܹ3ڷo}7;Cpb3[ݾ!?Ek>˽醏ۃ<P(~b7#'B.cf[cٞuɎe1 ]!H&תx]e,?_3Xwm~tËi(~r3smG{!O 1AH;r} EelySw0o_O̷kL|Vh$V?Ds"_Z=6 q\NWT z-%. ms)@UDI49'RЊLC%`i9집nX4#<\f}]Woe>Vixj΋ =y]g#էSGJښ'< ̴yxi)fwt5tAv+{h!~`F?O0MGpI[rz>Ħqhz|ː>o6p瑉l96x~m;S%v2;D#G83ACֶ'ӮW~O899^sg4rA+9PԼN~( B@!POH(z' ermɮ!y"kbLm9DLL ڴieG.#YL$D%md`J7m5)@n`+o*&-t/1Ln!

KE4g1d #ݓmV\49.cGij iR{zwLѶ2Yk#=G&*) B@!#`dOԅQ1>n~v׊yWuAȄ=ףڰaC<ݻv܍-U˩hF5)y 1),}C۲-:Qֽd ;^•RXigyڨоDX:" /,C4Y/u Q/+^z k5A"='Yx#AMWu,f-ʹ -%#4=~Y!P( :C݌ɜЬv1Lڐ]3cDey/rNu>ޓG[*/˥t mulOvKkP(  e2codqvP?9&F`WF}~4GF A5T_B@!P(~`Ǔ2wBǨ,s\,2rڕLn3O@q{BJQ!sDԩSضm\Nߗd:m۶u B@!PKMr[M٭q3g\ojP(MXnFGyX.=t6n܈Zvr_m;mt]m}8R vٽ8(6mNF>52%nkz1 ;>:W/fOtJu>tX5* ;錼<+˅̨ՏOF$;.2)!eOL~ BƻHN?SC#߃Ͻ(k׮|5jH>Nɒt _"^1_á|{'WzV/ȩcp^;Y~,FNtfs#1yfzFcG~Zw0emCf5ا4YUR]'ծP(L3^&cFF23[55; OɈ6YV]}:=tRFq[ ? ;QW1*$fب#tt.idNF9'xJ@X##U`K#0h0KEh]&cJvrz5|X1HKNEn ʍP(no3Rz wtr7ONv^nsr.pGǬ&t~z\bWa*@JgbY5:e[\TP)];Oum^  9d;,L=rDx#A%@UDTR:L͞xGpHWL\wc廳}F|k [({xUy p*yxgf61£:3f.qbRaN>la!j2.r [F ͥ_H&nȁ D;ھLZLJ=l)w M\W ؚSY_~C,}c(˕0LȒ"$( [sHh8݉Q78>}w' 5bA ?㪮P(C_cgd>#\.yVm }kl7YNCTl ]'׍Clb6f MDjB{Tx =t2I0Yہ"#Nohٺ#ĭ.̜7-Z,z:#pYFsĺi ao}($fI8,sD/j@t< J'UGLd/\%Ȯ KB0dQos< \~% qBt[ x/&=}*=1"aLXs+>;-s0i¢%:30o?M퇭zk"DEY;g|H5]gmn9Ń># A"n~Zpx@yW)3SH'0`{թl-}/ioOXA! ~If~H 8x)l<2Ðd?9bS0rlV8xa>fJP(E?aS \eY/tWպpJT. rQƍؽ{7/_ӧOWҞ72RaL]][qi ҵ\d>**Jkx<yb]L0Gk_9$DƮV QAk03F?ljJZ!s &b-Οy6-2&Ī3P\ f<"~(23+BwuDKxhWVkcAw^z d8uN+TJpj1L3%ZӦ@?ox 6Z:Lr' ld (@Qd3ow}/^-))|V4 }sC+}5 TyJSs5FEבK+, B>:>ZOܹ)Z4[ܠٺ1iK8\'fA;pX @fzBnnm#zGuz/GrV^G`ŲIhENutU: gߙZÃl$)ZmCgo)fƛv6eG0wHW4k(R 4r0V KE\xS}YJND.GmF9W/.-R!v9κ^J>Ҷũ5CPb-ـ=O̶VxxU#a6lFgi|شnXU32\]?*o]%R( .<3ڒ]#<\f}]Woei>a:8K7v~#ˈ:YQjOY99nб)=EGh5a'O"҆ -=pFAfp;f۫cdXҧۗOzxs-H:TF"CIzTnAl؅b}0p )k1rs 49uUg2e~mEYO?9vS,BWx]KVaz饗:uBtt4g[t@nYqcz =a(_F²!ZNҬ HZ5+! -x\Wqb-)=]ћ$CyhW?к]JR!?q WᙻR _sёT2z#gD˘5R1OӰbW VnwnTp UQx1i$|wR'|=KtLj#hId۬^U׬2>.jkg?yLKY1>.l5uӊָhџ2mUcN_V,4Y2`^n޾;Z";"w'\!P=1g9"ǻ%"vǹ,g+d,:reF/;\R}Ė墬Y&Q? u$WDWkA@:7 IDAT@ML5;ժV(LڞOӘo| 00P;gP( :B@p;3s.tdR& /n!fN1/lmofTe!VuC֖kQN?OVh[]R&>Hnc B@!BIr9Ycu|˲arյU]E|X4Dza}Pd'v( N&f[¡>e'Ž Ť&:ڍ(B@!P( xB&rWNen9MDDz5*) B@!Pܞ=d'd"rImF23(8 F!;fs!]$ыU]!P( OyBW Q3LGٕ0XɓrY&ۺ2tRC/ADD O* =FйjsMduMvŠiQ'(ڄLԅ.F2ݭ^z[ Ë}DTFǖQTS}-+MBAUVڞoS\ EϟQ&k֬Yp!ڵkWkϝԑ tሌD;qstDlF.su2RmbߞI}k0TM^5M-'y1x/ۙBGr٬v^kYr*EB@!S@@}E5D6'xnAA^D"Yk5{6Jt'gh4vZ<ø][/#'ʌYnsj{Qy<znuz}UW(~0ڽG `#@Gj Xi$k!c7dʦB@b`ڵ+ 9[A]~o^˹hܸ5(qnW=68p@ôl#'d<lV?e8+_ H?smݝweK/` KƔOaZ(1LBι>:HfEG^dWvh`#; rcuQ7oҥ8y9Koӫs{m|~O<of\lżyؗ1ZTrUiv}1/=x7.:E;-8j} ؀BұD)HZ aFM7j2r=EI0BLN^S֦آ@> "6=~aH!~Q g7J n"A5ђa$-QWB൹|6?dW\#Eb`?ө~Ft /8[})FwG_cܯ6%m;5[:4vGxطK]:R,~)|9|f?A63s80,g텵s#Ar+.R??? cڍ$8 ]Y.dFdr3M^dWh`Y&OFelNʗ.]BRR֯_+W8 F:@$±72JXvpvQs'%Q-Ft\"/m,\&r|}x F>~oN|1) ^m )328[P0S{|_/; ^! 4'^H[q3Q@! Wb8q1`ŊąAI2ÚE4v{ Bq0}sx"Bi{pDa1:>o?M퇭ohL¹(oB L8(5ֈJ.-jѦ @΁}{4 _P׋ 7w{? lGD[GQ#;30b\_$ӗh ϡzދn0jJ||.Gdl";] S %˘1)c3n$Tegk$3Ucy]]Mhe׷]B||<<]!XّξJ,{v@4 lqog;zzq5°Ĵix7eh19wFt1@!ӟ`sb$(? Kb5ů"">SqVDUh>9g.ڭ-k'd;^lz?-Si#nKڒ̿E !' kSoY#!|w! 踶c5^ℍ"p{WhӪTM!Wz[q\MOx/~̀2n@̦O(/~MoRc:+[QߣAX`6e-Ɵ_~c7=*ad7Y|s۟sa)}-Ax~A><j37^r8k7tf2׫Nmc6ܭ8r_ffNr>xzX|9N>n$82 D^MdNqR{GnB }|d%֌+2wN@tXr<.>xΟ=fbq8k%{*dh:cW --w8-1]\d\J̗~ŅѦHx76! \Cǐc[#+ۣ`7zO؈xmΗ4J4 Ϗ Cax~c<ϑ_׻Ѥ}Y=5rA?Xah+{ tH!oNׯ_3YS$:FQ y8NUo/"wQw.RVU)9(^Q! Xb ix׼奄 EU7D)/' R+o%W4MP+hJ9A{=ga͞yfΌg^k;?̌{5w'~Gz$0cĚ^Ƒ _s$^8K>0.^L>gOAqѭ=}֬Ycm47^nfE`ab?T p> ڼk#Wzg.;Lr a䌰;ҥ~8]ߡ8~c1tTu$aܖcWܝ0{s:'YC&iZY]ţ9v={,B.g\]7lvovkI-w^/Ʈ}.náі_S_qkukӆ˫g . @ gJ嫁U>}oO&7 uyS q><V3ݑnw7w|uX{ϟ|~Wh\f:S:v88{ܡCtm?*FKk\y#< AcvH`vX`W1bZ+?"GsX[ۗ#X=$}˗uɧ17uK0b :4|[ ?l:v-g[^hn\aK)9):8jg޵;sшvEKp.%"G`3f -ZT5M-w5jݖ÷~{Muش8H{ڔm'|ykm\ ]W%w[>Lfjms8]ܯ"SO%C/Y"O:,3f`]w- 3|0y`-HHf?|~cn"BsݏYC~k%'xXc_K8Ժtk^%KͰ:tsvN9眓x?I4o9߱x=wh 従30xݚ-.)X}O~۰ aWkpM5[NFCӱ zGqH$'}jŵIH4|^{'x?7vɛQu^ںjB y3<< ,-*fn|ߧc"4_jBqUi?2ʻ 17uaumɹ0hWMb_Y窱rF(vU}(}b޽nxWח7]K^qrVST:m]n%]@Цi,CkfU0"51kg/̨XH$_ksi[0(fvi%L/O0rR?>-~'Uٕozrܗc4OؾƏIMW9fz@mMd X\j%ٳg&oAaۓbf L 3+6ǵz kqm9f7&̊E̷bBh ^$Pk>֚$! O 5nmCUƼ./0֗ubuh[1Vռ-9&   M!1Q4ͺ5*^cj<ԤCs,[^tu[Tn)[_LJ'  O*x6iMheWnHDcJ])󥾲תp;c!7m۵[||Y8uk7v/'t?_mv>THHHH`"`=1m5.ͅb1sZJٵBb"@v~i;Lx15as8˗᤿N7A'|ADa<_{8AnLƠg}qr|18߾`Œxq|/   yBB}6XLgW;Vq4nc:#l;`]ѵ؍򡹛~\L*KemvY6 N IDAT&6Uxߺu'ᗿ߃&lfŝX>YnvBv쎞ݻY'c];__+f-wv?X.%/-)"   'Cb5>_ %}P,LŇ/?|C{ܙ-.|z:~q|f!4Ľfv8a%]nO^ΥHHH 1z jܶ~lT(86vn;s۱A&۠_~خwfeƼ%`F O>=sm?Iӎ8f8=^t.9Xe9+OC"   bjcuybkJ^Ԗkv}!/W {ߌㇻsO6pUC'/h:jD > w2ƵomIuj t|hG\$0[bk5 @ ίDzzC JL[1 KK_UK_N}wZ_5V=P&Ƅ [фMZmU +t>֚tK%Io&PO<cƌEj\G$@$@![n8~w؇iN~/%.V~4}+m#SYK6/1zio5﷡d}Yᗚ sƴ-ʏt@C @(|ߧc=YhԄ:'s+wX+y4q~zȵHHHH*G@i,CkfUήnul9Xk l>    49Xjtsgz@mMd    v#.&@Zcj\8s[ٍ "b}&m>X 7T? c}YWA[-X$"/~}}CAf,}~ p|{3݌[E&2M$@$@$ $~PUBTV\KMZ>4'/܌K/s͋ uWcS`BU5Ξ 6 *igAGt=O׮"oz#O< EЄ~ f,XYe:\HHH dz5mӚ|ܯ hL[+eԗt-^/q 7w-i.fmK/ƜwN{LĂ4=sq3Sf'Z*s cc[Xv'  6d/yV\(:ٵBb"@v~JwfϞ'Ě59ٯƹw㸁;Mm:&7)',6>r:ٹ >"zv7N :==1ڻ }/-1ph n9?,}͓snCޕ7/x ;1 "M ne0pTy)N۳i.> ;/   $.yZk ͏XMٵ61{ۘ]>sJ̛7/xtH8>v.n$:'3;bSn2͜kG_Y 1>xlj\7K5Y/s܍{Wb1U{8U>4#;w=8>w?_88fz3(ֻ/4w^{N%k8oUrp48 asI)a&F7?ikۮNYd-zb[̖={[֘ܮ5ۭZ0cm~q'G_u}sd73^p^rG/.qʭg`6-&W+l]lO'=#  h7zjYj2wvY6qܺpƩ: ?Zwuыϻf;%kt5>ҕгsrWqt=#X0C;wqtQrjgko|6 O?= 'r?b{ÝEEzѺa?nnU@G=uk #7; <4V'w7ts6*- @u5~1gV]/VcS01Q" R5FgmvݴF3ZZ 8 Qf>͡spu7b]؈OzqaCcbkUsGgggSqW\nһ=.`}`Mdnf1mlDsSOJ{`/pD)vp[pLc6n0``nÂڴUL{xp;ϕN5#F*;ӟ[r]` 9h8muS0{#܈82 +aHHH#"o!|_qQ 즶۸+s{ot[w\0&,':'ogNխČq}]c'Awhxv}'űf`H浺p+`+1h]2*8{nyVǮGu>I'%lQ_^6ti-@vݹck}_9c$}[gܣ]:ߖ':&<;_p:7L=};{مu7ȖHHH] +&"Vg,u~Am(!1k?ԊQYX}#X})ĥ._%|0vi k4/TX:Q:+WwDC,l.܄FUK uhrwdZOX>h:fWɼ6wEŚ`շRW|Rw/wzfE+K2MJj/=.G3f -E$@$@xN\#w%"0k,qieq֜\fX:tsvNEuuu7n\rG2ۂ|g7xϭ eӺ'4qϩ]qI[3"$$%ZܻezvJ]u>3Ñ2;cHHH@i9ԇ⒋^؂! R֋YUî_%Wrб76oq F$@$@$@ ;[ ͗P\dn+mvi?2& nqˇkՄ"    jP-OZ.Кbl5.kjNc:ZiC1gHHHH7ͩ/c~Ůr̮/,+^X5XC$@$@$@$P{ŔI^k\|gn11aVD/dg[[x涛-ז{X]|fHHHH ļJ|YO:н rn"x)׼.7bA` n0/Ao?3.$FfW&u.}]s]s}/. BOcrXMX52|hN=}]j˗%kɘ5L|.]fWvsf}oGt~SZSç 9uqN!   v# ИiNkBm,sf7$J1mR_p_|-n~K1}P@Cxo131q,˚Mܖo Η Txɘr5vI]{ZkƤ?Av+(.œQ}--x >q&vx|3tnkǎ]ߞ3:zbHHHHӅ}ڸBc1;?Vī9vS+F6f}ݏɹcƣɴˀ3}Y/J;u =/єxZU[uqp㰍|N#pz+SndUbh7}ZOv_Sܲt܌fSΝ_dSбxK?w `g.Ӯx7wRf~³7b v]b1˓*!6Y~l37s5VzlHHHH#"P̯YWV$g|j]pVg-1 #/>w;={޿fϭ3'6=V/ƬbÀwk1MJ6;ݣg>Cw0  lk`{W=<N{]ghc7zw_c   4&/l܊jl}jf7&JCX!*fq8-vMC֕ 8v 951IW߀nŰkAώ.0jdcbֹ1Źmt{Jdwk.]_ƀƶ8ua{ǶNʹl6$@$@$@$Pu1*q?|$+J~+&Yb&&~Lk/9Xwڵ9{57}LnC܈hq.7gij4tkHL-mjth[Vs÷lruvAk'OƘ1chѢO$@$$[s'~ָ ״Vrχm/?bbB?.~rqlZVbvټK]ޟ_;z-W]Pssu ²'<%ٻ흒o GJ ==H}Z vM+y >4(}yZcOVoݼE̠0fnhHHHHڕ@1>|FkKn+mvUXHsX4\$@$@$@$@E@\53*mvuSc{@iLZ+m(f 49e5үUec|˲FY5ʚI$@$@$@$@3[lF:X]AfE"@|Jݗ:\z饘;wnʒ͸L|XFrꎺU4Ξrࠫd.yI|3M:LW |ļ]1g=a/C*h1V߷\~_Xޯ//^/q 7w-}L8kZ Ąpa۹/kj^?N*8y{y Ƥ<,=TIjטXj9ٳ1qD\vwnj1\n zzii~1B5/! |"dz՘iNkBm,sf7$J1mR_{W^y孳́q)0sq]wcjwgwe~I?\a.é#gHHHHZX'yV\(:ٵBb"@v~jv.\ks7/YAt{bg,}?w t2e&G$@$@$@(B}ڸBc1;?V+avmF6fתZ}3N=T۷uWoï=7]=qn{ܳ [4q=y=ݼNgHHH>o^6UrM01ue7h#1CE֭kq8j4y?j9hHMj_ĄwFνum2{MMXRި]/   X(׬+V+dZm/Ί,5ycȑlRL9v 8cu=7k{'G\:ˍS>ANY$CN5ȖHHH>nxqDӜ6_Rf7&J[R J:-ѣ>`N6l0jZ2l>[b'}6P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گٍPm(z&IHHHڕ@̿ }mkklG5̮ھogK$@$@$@$PSx3[S:\ P}8HHHHj@V_c9C6kv}!nfپc;}    'Et6Okm]^\", W @(|ߧchmmͮ Vq~Kt=˖HHHH_SR2?fXͮnul9Xk l}    "4O۾F1,bxocY` @PoS&ycs5u* 4 IDAT-ƄY6Y, IHHHj@PSlݫ-, X~ߊrqbyc    $ű~NSI FUkL[se,5iHHHHڏz<@cڦ; ͷJݐ(:ƴRK=/    $`=(1m5.ͅb1sZJ]+ q(&4n cHHHH` .$yZk ͏XMٵ61{ۘ]}    '.zPm([xͮ/Nr0b<$@$@$@$@K@=]Lzje,5 6x+ deHHHHxqҮjݘ(Նb`HHHH] [Pjܶ~lT(86}$@$@$@$@O@_1:To~ffVK?'   }i>P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گٍPm(z&IHHHڕ@̿ }mkklG5̮ھogK$@$@$@$PSx3[S:\ P}8HHHHj@V_c9C6kv}!nfپc;}    'Et6Okm]^\", W @(|ߧchmmͮ Vq~Kt=˖HHHH_SR2?fXͮnul9Xk l}    "4O۾F1,bxocY` @PoS&ycs5u-ƄY6Y, IHHHj@PSlݫ-, X~ߊrqbyc    $ű~NSI FUkL[se,5iHHHHڏz<@cڦ; ͷJݐ(:ƴRK=/    $`=(1m5.ͅb1sZJ]+ q(&4n cHHHH` .$yZk ͏XMٵ61{ۘ]}    '.zPm([xͮ/Nr0b<$@$@$@$@K@=]Lzje,5 6x+ deHHHHxqҮjݘ(Նb`HHHH] [Pjܶ~lT(86}$@$@$@$@O@_1:To~ffVK?'   }i>P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گٍPm(z&IHHHڕ@̿ }mkklG5̮ھogK$@$@$@$PSx3[S:\ P}8HHHHj@V_c9C6kv}!nfپc;}    'Et6Okm]^\", W @(|ߧchmmͮ Vq~Kt=˖HHHH_SR2?fXͮnul9Xk l}    "4O۾F1,bxocY` @PoS&ycs5u-ƄY6Y, IHHHj@PSlݫ-, X~ߊrqbyc    $ű~NSI FUkL[se,5iHHHHڏz<@cڦ; ͷJݐ(:ƴRK=/    $`=(1m5.ͅb1sZJ]+ q(&4n cHHHH` .$yZk ͏XMٵ61{ۘ]}    '.zPm([xͮ/Nr0b<$@$@$@$@K@=]Lzje,5 6x+ deHHHHxqҮjݘ(Նb`HHHH] [Pjܶ~lT(86}$@$@$@$@O@_1:To~ffVK?'   }i>P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گٍPm(z&IHHHڕ@̿ }mkklG5̮ھogK$@$@$@$PSx3[S:\ P}8HHHHj@V_c9C6kv}!nfپc;}    'Et6Okm]^\", W @(|ߧchmmͮ Vq~Kt=˖HHHH_SR2?fXͮnul9Xk l}    "4O۾F1,bxocY` @PoS&ycs5u-ƄY6Y, IHHHj@PSlݫ-, X~ߊrqbyc    $ű~NSI FUkL[se,5iHHHHڏz<@cڦ; ͷJݐ(:ƴRK=/    $`=(1m5.ͅb1sZJ]+ q(&4n cHHHH` .$yZk ͏XMٵ61{ۘ]}    '.zPm([xͮ/Nr0b<$@$@$@$@K@=]Lzje,5 6x+ deHHHHxqҮjݘ(Նb`HHHH] [Pjܶ~lT(86}$@$@$@$@O@_1:To~ffVK?'   }i>P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گٍPm(z&IHHHڕ@̿ }mkklG5̮ھogK$@$@$@$PSx3[S:\ P}8HHHHj@V_c9C6kv}!nfپc;}    'Et6Okm]^\", W @(|ߧchmmͮ Vq~Kt=˖HHHH_SR2?fXͮnul9Xk l}    "4O۾F1,bxocY` @PoS&ycs5u-ƄY6Y, IHHHj@PSlݫ-, X~ߊrqbyc    $ű~NSI FUkL[se,5iHHHHڏz<@cڦ; ͷJݐ(:ƴRK=/    $`=(1m5.ͅb1sZJ]+ q(&4n cHHHH` .$yZk ͏XMٵ61{ۘ]}    '.zPm([xͮ/Nr0b<$@$@$@$@K@=]Lzje,5 6x+ deHHHHxqҮjݘ(Նb`HHHH] [Pjܶ~lT(86}$@$@$@$@O@_1:To~ffVK?'   }i>P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گٍPm(z&IHHHڕ@̿ }mkklG5̮ھogK$@$@$@$PSx3[S:\ P}8HHHHj@V_c9C6kv}!nfپc;}    'Et6Okm]^\", W @(|ߧchmmͮ Vq~Kt=˖HHHH_SR2?fXͮnul9Xk l}    "4O۾F1,bxocY` @PoS&ycs5u-ƄY6Y, IHHHj@PSlݫ-, X~ߊrqbyc    $ű~NSI FUkL[se,5iHHHHڏz<@cڦ; ͷJݐ(:ƴRK=/    $`DE IDAT=(1m5.ͅb1sZJ]+ q(&4n cHHHH` .$yZk ͏XMٵ61{ۘ]}    '.zPm([xͮ/Nr0b<$@$@$@$@K@=]Lzje,5 6x+ deHHHHxqҮjݘ(Նb`HHHH] [Pjܶ~lT(86}$@$@$@$@O@_1:To~ffVK?'   }i>P~Oiƞ>5yA1a*oyzy +b~}:Vѡ~֖V쪰hiLӹlIHHHj5o!ui,CkfU*ZӘVP'   -iMsDXk_ "Ɗ6e ֐ v1el?6W:_ǙrnL0oŲHHHHļ |YO:н rn"x)׼.9&   M!1Q44kTUƴո?WRaHHHHdz 4mӚ|ܯ hL[+e"   MByV\(:ٵBb"@v~0vHHHH Bb}6XΏ$J]AhcѸٵ'   }bJ ՆbJW$g9+6sL$@$@$@$оTXWVR۫ ^mΊa@\IHHHO ͯ?*z[گK͖Pm(V" DXv->CY&Dz=9d ?n!6ڀsko!"#Zs0fx>[  sd}ݘ?>.\> ZGO`6V[mmx wJ+ៅ҉VQWLHNCؚrͮټ틠Py @&Wƴi裏b=ѣ;K.!|rxC a;VL,MV_c9B6ƵĤL\R'Zҗ9N}ݯ#.uc^$%0yd3-؞#J^{-V\o~?_W,}_uukr b[/Y(`^-rS1q?́>H+}i/q1qko]i'J^K~y pL$@$ "w㢋.Bn,+3 ;ڵ<̳%\;rHB_ 6t͗P\dn+mvU|8?Etb! Ǘpc]v[l ݽή]Ӽ&i_)X]L{?u{iM4͠?'!g1*`QlqcfScEMM+z<x5,r,ј~>?~`a| _s"|sy*5k4O^vۗHbW9wv}aYX:Ʋ  O0 w#a gv4-pC%׋3.;Χ~+3qgwRbᅧw6kV&jA;07ČL܄`-ļvm=ֈ)kz }Y~Z;kjժGtX~_ X |r w˻{ꅺ_Q>pwwWXIX_׍Ɨ>xdվ:} Œ:sស$>EX<^7w zu]lx[vxqqx6NL9ͭ=j UNm߮i ;qx~ex|.)t:~=g O}?=yHӦLǻrO!afr,Kαr +W,-g;-ڣvc?meuԔ9V 6brgk'AM-j9c[~=+|=d1[[N; Wq go~iXނx5rF Oj[FVyC}Y%ŏeb{^m9f`\Vkޏk |L 3tM&]1PrP3Y:6̜+.cRx:pxkX_f?/7X&dp(l<4vӦXD'_=vtBuX-X=}1!KaYv1ɞX8#w{w>NpMa%bӺz|xy̹b4xٝZ̛3vƴn{䴲?8; $,x CDM/wsOeT^R6YXh.?7xeޘIXO/2xowbUObC7aFGrro}<~Exv9>_B"J=CR_צ~e<Ɛ⺬5*^cj|ݬu=I˯dHHcO@ބ&I;{j䛹۹R^!Uu?_\ c'?xNiFۿv1g NA&lѳЯ'>Ef3uw}ػM ?{݃]U5N#r?Fgc:q?l 3=q1N{9'02`_]h9lW[| =zbϮ݄7o>ITvh1U[%5o[!}L{6ظs5uz=[=Zsѽ]6{չyh,|^"7h =p=rp/7_B:];t\+g%Xɝݤnmiz.rL7v:vLP;,z|l/յ\bR3J`&)])W,W{1IbS9c7xO},M^FCupن quG`nWuuk+Qa5^o'\)O8?]e ѸށQ  O<1bpNo5lbĜs[6hf=?x;쾿{ ^[9 A?{[ot3|I8ngW`u/_ ~enas-Cw gb߬rP|k{É E΋-㕷'(9yw}h\%k5bW~%~GHL_#3Z2_m׫m38|t4Μ9;Kqc;ge_"9m\{v8`4x |{1q~a֘l|mӅ^Cik,4?c5I_ֻ19~l)Ycŷbc5\#1%ƏaPoR/ۿ#q ϞYo9?woR׹x#r9fd$^c>͵Q{#GE2ɸ&`ga؎Xr>i5ܖX%|y4N8C~䯇[;4.ɱwd7@ sl~|/]p]psnף=:G-r\#wG˖-K^;yMS_Q,Z&: ǣGCtMغdɽνw|g<5ɽfN?!8b-\HF=]LzP,VӸVKLZ/_qieܕ ;2E[K˃Ug|m;wn5m޲ +WcwTWkvwVz1ɹZy6w575bn庘 ^UE-{]Vd/Utg;;-M.lOn'7)u³E1T믿~ދvLp2[q@)7.}]Z,esSw}ߚ;OV|}]N{"uDyNF[y[ciGj K_[ۗXDž[O.1ռ4*J9m$@$@Sr'3Lbpg>x_k $jѕH]}C6RYWٯ=S,+gFsfd]'[  # ^x'MeeX<ʫv3~ȒcGmil"cK) (*fi֬YsxR㬊EJlpl.];lx֖ψk1:zSM]~q]936 [?v3_+\ H) 04p'zvwt0Fۏ(t.tV}&ž19zpr8k:nv\xbQ H) <Hᖧ:6k~[nuNssvOch. s9R@ H) O\OU2of7.ųc!R@ H) S]ieȓ?jqǶf0;^R@ H) NRoȅ"_|OX1O}p_l/IŃ|X H) R`t*a%DGf7.7\<1Z18u\0) R@ H{<bu9zu- 1Z_C H) R`t*{<}1Zqxs9?ivð⾾09R@ H) r}'/aĩ~4~{ qK) R@ ~ӕV{7w90y]}+R@ H) ظ +zNi_~xp~>@_V l !ޔxrc}Ŏ03c͘UOR@ H)  o5K,kTk扩Ҽ]H$k1ߩkH) R@ lZ tE^qԱgJ>@/#.$~N0c_'_ H) R`+Pbc\WG?:6-¸h-nn) R@ H@~-}\}۵w˅\#X++R@ H)0`-\'9;r\4ccL.lyR@ H) K9Xof7.ųc!R@ H) S]ieȓ?jqǶf0;^R@ H) NRoȅ"_|OX1O}p_l/IŃ|X H) R`t*a%DGf7.7\<1Z18u\0) R@ H{<bu9zu- 1Z_C H) R`t*{<}1Zqxs9?ivð⾾09R@ H) r}'/aĩ~4~{ qK) R@ ~ӕV{7w90y]}+R@ H) ظ +zNi_ƃa :jK) R@ 5~~~kޒEaq9nm%5U7ux"߶ve{szm @ H) ,֭[gk׮5kTۖuq رcm_}wtkÁ pzz q d/8,8~fn}4ܑ_xw{sjrxٵγCuM2<خ'/tw͜) @stRK%K/pĉ;ڮjo{l̙U;)hr.}ɾ;_>f?X> Ĕicm޼mcxZ`gI~13Ҽ,рv2n0E>ߐC xɜ}_uݵp}߷W1I? .yjٳfT?.]]^?I}ٿ&R@ Hѭի/k֎֭կCX IDATk<=z6ugsWyҮv-{xA}{}fϞIߤmMj,r]eY6lto.݇}#ﴉٳϽhWfÝ\?[Oۅ߹Y?jxH{{ڊ+쬳β=sZ~S… KI[om{ w}1~~evهIHj1e4cO#x,g}ba#fڽicoѰƦjƆ8_Ѧf jTmhVzVl|as[lncw{~m]s{Ι6aتׯ]j+W-5yD{;j;n?jx?K8CR@ H)0:@#uE]weglƌ_GGǪ֭kmmڞY}N>7Tx}Nlg1@ׁvV5k\ZHϢ~v.؜eC_6&14~ ~nQi\QG>>/ U~hGzM4~~]v쥕첫m9->>f?4k)R@ l ŋWH`KY5e쳫ͦL1n~;] aم]vM;jrmܹ=?Ëaɒm`{qZ^wew#/ vuCS 9㗼ݾ/O; ޯkv?aSJ6쮳U}6v69im6iЛG9؍1#4,Ųc#:[~ȎLwnKOeóhxqbxlȡ _m8=i )  xc=Ʀۅxfw`@K7&MVUqv3뿼޶v6E;m6%J߬fmߵc/76]nqbqL0z?qԩSwʻ8@s]ٶ{m+^Nvov'T'bRk>r}oy?VLpRzlȮX֞GchcRb{ؒV딞7n͜]wo*f|,{Ґ'_L/g=m/nia~% Cw^hjuқwu1+~}_WcvL~#!fM8>5xl6GM{|c ) ش@O;S> |"z9QĆ5s~F;fjߘsּ[23ϰK_2f^;ت>{~i;W~/]qt؉Ʊd~TįgbIs{m+V ڗW4]ՌKkmz~@CXh7Amݶfᇏ'_d{&Nk߬XgRז>7lʇcL{r@ٶ ._߳'vο؎e+VMaxC `b3a{Il~}Eȗ^(|]o-M4~g>qv/iH 4n>%?kJg+⧝fDh/G H) F /ǯ)<#$\ЮӇI9vn/S섿rG+l%e V]wv{/}k퉟]jtd|ٯ}gsOi>Gΰ:ľzҞYԼEӘY%u.,~xf-n>#!>%c|zyڴI6%=0)5Ǐi~Q3v~v*'xw/M#tlk[}s;Us6ǣ{u=}H^Sli^rs0%D޺.h<8户V6"p,!|EW\W(~QʦTwxqhH) f3hШEn&~x<;VsVl~ {hq/pX[3ͳmva>Gؾ&W]?_V5[m ,/KoN2ձKǖר~恖)*R_P)SڤqclJ#9nzd|j$Ev뽳M^4uM8{ҝgu~S0K7{'~Ԧ12kz`z4k@O}y͑NuFn"bu9~99k~4X@nuϕsj.9mDLL9<^ZF1ګmj7>]o>eR`*.>}z.~b7;D:v_/]vܜg_) ~; 4Qd]jƤkOߦ1nMO7_J>$*4ۨذQBc ~>&lUs9)EË'(}m/;sمW؋k>`s GnLVlźm#?e v{b' oV^6n{q`L<}u㢰hv-⾾^cv>s<˱ˎۦ;e"e/>sȕR@ l E7UWxYlv̍x_N;l;_?xMD୿gf}{znbEG{7E =vbe?`W^!g˅j/4=q@#lhv߆!!;vۮHIktHMnWmK-q8' ߶s>vmn._vmV clUܷ_IɎ+H?T"ns5^vR?{ܺbGljK;GNc~Q=ƚCnsWV\<ޘ7SR`VwK˖-OQx+-q:1׿r-65a0Pxϳxō6o&͟Ύ{˫{ꄴum 6_9c3s@>Z~KmGMj'۽qsXvM8h#07X!moc~Pؾ<=)}vÞZ>ns_3'ڇWfe1f?|7^V ) \X|~՟=lwO'L)q=w['69GSMLnntտj ݱNt5! W+xW/<#vW^{ex`ϟ7-ZȾ^q6ytg8fcm ?[}Isk6:jw;\[yOoN{i {遫7zFg jOcR A r[8j.eӌEctp'>tZua}ii?{o`m?kk5-(R@ l N{a>]Gdss>f ]h|zĢ:Vs!hNh;x|ZN4ƽ<;_赶z3&x#a[_Ǧ,}c W ؊e/Ǯ{L#u/A]\n`>hs]f/Ea^ rMQY[4}-0|~wN&OX}5 .n7ŵs)xT {衇5\c_|vin>ygѥY]|s=g]tQ٭GuT-4u@<+Vmۙ'ۤWlcM/2%.}ԥǨmMcҟY^9[r%IC+m]&Ľ4kr 0i 68&~|XdɒR]_?^xIRk}쬓>q$|+V炾}OEyM" ?p կ>`öW#x+ĝ܇zn馛_ukQ~ _OVqol=>vk>)NYCwزݻa$c8'PHA (>64WM-cX6'-XX 6&94&x_ݴ?oIBx;Clkk?~~ÝvOoβ8iH) K<`-^xg> 74+X1bܹ;T/T;..\6hVQ }6|Z3mߛݴ/{{_v=񅹀Ow>uٺE H) &+ o\ƏrH]:lha냦Fy`eZ hxn&Owv^XlryopqEbZMwv\s`q~qn>z;v:j;;p>glogzWR@ H)+& <ˋht0!4]/lмOkt@?ܰvZs\=895~7\|b.X<1uCjH)  q[ Bܥ.kӥ`~[nOuNssvq1h9bɅa>/_ H) R`t)P׿1+>brmƅux{9đR@ H) } + yr|R-q3Q0|NjQ H) R`)P PK K>ik6 }xЙx]>K) R@ l~na~Zlv[&NoTxb}-rryϕ/R@ H)@{eŽG#ϑ|G}H31K88>!R@ H)_C7bCsX!zưXGx 9\R@ H) H ѽ˫F@dpgm|~s/q*|.;;F|#_C H) R`*?]nxǸS^6~R.[y1#s} !R@ H)Xh]q;]z(t˭= k]a jq‘A$60G!R@ H)@{UWٙgixtl6`{87/e61Ljv'Ɯ;) 8Oi.)+R@ H)5Qݢ_ _ z<6q'/-6-E\|cKWR@ H) zV`…wxr r~/?\Y?,Mw}LA-E^C H) R`)G,XF`S{7a8bx}_}泶fpc>ȡWC H) R`=+F7;̇ocO8!IwA>"OF<CLK<#&71>1ڽ,YkH) R@ BfϞѴi[`qC/cXư~CM3qeRj\#sDcK<$ch~G>qR >q766T\X}`>}=} xM/}u~O?>-W `*b6ȓZ ocϘycGn bG5p?hqCL 5\SXCI!-y?C'uuG]?}|L70<>-hc0_81XK(}eCuHlТdL89M7r<`p^yܒ\|C,Zk/Ӗx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ gmWYG[pіx%u%^ g-xaO M*# <ߜs3OiC\Ryl𫑻\;ĀEC-}cÂєbxhكqEX ✏q|9qغ +JpVڢfBsDz1Rc?K??^=C:?]zztm*?N?c+5lHaO M1C wri#ww9'<\_/M 9173 &17lR@YG sxj`q1~x>G9ȵokccqXngCf9--q[yg9u9-jO 6n jbQu98u97Ө.';Gr:tS=.7ڿ`8eP{1-eg;i#A'\3b(}naBѨdžU`}.1:?b|{z~]:N]N 4I?.vIDATΑ?:t}ˍX7{*ưgz`lh=j\G!(0 @ȁ9assZXl5s=ȩ˩@Fu9'@9RG珮u)3 9`06b 5y^], _ycφ1RZԷ;@9hQZܬMpZ[LP8EWUߪ@IZ=tNvwPC\ҩ9JVJ:j~%JkUS oWҩC?aފ80a,v#ѫ9'cX қi&;qziv#bgL[̑' ̅ 5hh1K9__pK??=G׏IGOy06GM-ɏ1k<>-A>cڊ4%0f{|̝F|~"x"j1?jOp_yƯ \ܝU6Xz-э\'x-+g^?xm@L>-xуCqam4rr<}rssm) 3ZM(0lq [j,\q-a&;G# K,66#p 룏9c>=ƪځ'_7km6}Nsr7C9| >"|\c6"}R@ H) " F4_1<,WGacʘ<0qRys^c Z|L!@EB^<8ֲe-<ױi溘R@ H) 6WGaТ/BSA{,#Ǎy&jqc-8a1719ӲqvE1,Sb *-\3|9c qOC H) }bkD8^<`ry Maq1` =f)9sgs E9rTq'<xsy0:x~SLΟNϕOΟy)g9r}^?uז1,1>\8r6뱮RL,vG#ϹИbx ¼6ԓ<}Xõ''MSDS\tɝb:ttzx:6쟈1xW#1-pc>98W'w=1Ⱥ) Bl>=Fq8b_ 9`~.\, y·# 5XU?@Nx:D~U?@NxZ紉Xߐ9m"j9m"c7@Nxz8xa1?/F9 "O,krXc/#;I6x ~'y`Fsq~p1sG BNA sGo(VH)~C? G6u?y]6β֞ ӘG6p{ZlYZf'co#r,6Aߔbnro5?ѯqp<}7~:Gg?:k  5뇽?~9lgY-ac|!z`Q^C %y_  ,sEf-06 -k,eL,(8ǘPք#1mXp"1m Gc&DcBY<ƴMb<ƴ&yiĂyi eM86'ʚp1m N1-5cL$cL[(k‘ǘI,8ǘPք#1mXp"1m Gc&DcBY<ƴMb<ƴ&yiĂyi eM86'ʚp1m N1-5cL$cL[(k‘ǘI,8ǘPք#1mXp"1m,G)fż| \}L1J.DE 16%Ⲗ<ྙy"ym(~mK;Jk_[䒾RԺE.k(~mK;Jk_[䒾RԺE.k(~mK;Jk_[䒾RԺE.k(~mK;Jk_[䒾RԺE.k(~mK;JkBgo#~x.8|ߟcخGfK)8ƻⲞs 0_xb}^W[+pU?t.~>zq"?ƪW _l^#o&|`fxis%+]; IFTbaD17Yûcn6cD1UϹszC/:tsNGqWM_]Q1%/ZG7Ĭ'-8qkQ#ϼ[0-DcZbQl:\ 8aYa1<4XWpK??+3L׏]?]+9]?\?8O`L\F1X{9bb\u9 1E\9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs9hs/Q\G{scAyo$]yXo}.Ŵ>-khcڐjK9SgsuSpFu~;_bN?1Y) R@ l f:Di#8sZ̅:".a0Ǐs~bE%mJU8$`qsXi7>@Nο֪~Jiȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6aqȏ6ayo#s\G-}8_ 'ᱬ?.փy$cG>Ʊy3b3 z܈1^/5UF~#Q@H/?:F:X<<AۈbFcoY7-6A.b>>1}ژ\.VqOR@ H) 6erMcx".$9}Z#x"M%1%yY) R@ l ȈǘyuIZ;F0W ֎x;/+R@ HMQ\/>#o;1pYA]zUR|}sӇqrxr:A-7y݋a-4%NǽԨ~H7E/E7E/E7E/EZ? :'N;T:ql쨰@9ˮv3wi¥R@ H)*m ?aЮuh:IډzUR|}\?8K竫'c;;I'ɜ/_ H) RnkNN~qromȦ}ukCR@ H) t:iPsuS 7t#H R@ H) *Fڜa46qM=") R@ l lRb#ۥP}_Fү[ZүUn#׭b|תGVVHCm7[I) R@ H) R@ H) R@ H) R@ H) R@ H)Y+1uŷIENDB`testng-6.9.12/pictures/new-2.png0000644000175000017500000024221012732165123015716 0ustar eugeneeugenePNG  IHDR]D,[xYiCCPICC ProfilexXy8To,c'=AdߗlYc`%I)*VR)$f"ٲZDJ3[zy|sous,|@?H&j`mlԯ=8kp,o0, )- 7|sORF[QC3`@0G)e[Rp9 xQ Ƒ0$Yk8ƌ]vqzRtGb%y{+M$j}^w $+0 <ïe8f?rhÉ;zV?ܢYA=r;=mo/± - ~!YF.zk P ChBnOSQibisB7cY2e8Zxo^1_~`dTAN"C3򛊴J@Ն#jE4ifi~S[DAaѐɴٺ9!kf6^v'9 dqtvlE?L &'= ':<-uYsߍP{R}\WēSiW_Ξzpܭ쌆oe'u?=7ATWs#B"bز U55j=zjLAM^\imjni+j~ûٙ%۾ץsuPpHh+̯$5c{.v\m|y{l'ON>}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP(qT},~QDc}'z_T8XzGʼn8*N?QqE?/qT},~QDc}'z_T8XzGʼn8*N?1t~?1s\ۓӦ nG#eHles:_uIa6хi@ZluU&g#Uo{'oIpa=~:_-g(en=ֲ+}6oX?&XDYiYNuNxɡ}ґ%>0{i~~?&zYz_'z}{X|91}"[\?kcщ^٢qkEEI ?{d[So?c?uJ kZbO֋MeKMGEߠd2feXb:S'M2&#։_Tp° ӅGX{OG&0taa:?Naa:00'00}oΏqoN>7L87L'~d q2 Ӊ߇8|t~|taQ:?cM]~/Z0g Ӌ.Q#^HF2z,2 ѻHԋ-:OYܰXl^g~qMrb$6Uo񆟽RD~'#Ha~_t&z!k2f/iCسE}[#7MW?"Kua2uB${?jYP> k/J]T֋oX8Eh/J]T֋oX8Eh/J]T֋oX8Eh/J]T֋oX8Eh/J]T֋oX8Eh/J]T֋oX8Eh/J]T֋oX8Eh/J]T ~k2ı]d=xߦ,cl/8 S袈֋G鴞XcD!0,Md^k}.f3~/{$l{'oHr[s0ߴNd_zhR/6de8'62d̞MGu?uNJt 10)&}V*rW{wtİgl G]&M3Ѿ_i\ҕ ?/]c{ۆ~M0kz&rXO諝];ܵ'Aezha9tLr6K{NN]2oT|K.d 'if!`G7wlڵok MCc_J#IL-ʚ{i0YteWԥ:vm}^Vػw/' C0 ChGEp{g}?9L6K{!Z'2! S}(2Z6;]L $JzI*$J|]dѽ1ZnCsrrplV0 C0 `#&!// /p#],[%IHrEYGM"JC|}Z}O.E^)]I/S.8cs˚!`!`a'tg{]$M$YG8>wbɗt`= %KnrXQ=s T8l-/_~{SQhծz*eе+v[y+++b ر l"۷G>}PTTnounT;,صM;?4\:x8tJdk0!`!p >y曼 $.؝: #zlE0G%)e{_3M/]_zsHXܽ\,]|mݽN;=2e:lܸ  >qECHsrr͚5Xr%ZimڢuBWuܭΝ;wb׮8ѳgOnm&%^Rg;gmXtÆcٽ^6Cλ8eQ0 C8⋿7wdZ/r:KSKZ8tiRx,:MDNfE_ʩvsR/ѳMp<\z)^{ Oze#!"WT#ςsҥ vc;v B6oيr|CCfe@r7/MG mp'\K^]{*wgba$^ꌚ!`QBc#ANp^;O%]$^^UNl=w-|U_ u#]ۏc'qMXܺ u;X~jt=2-o)nذݺuIW֭"D-yС Z="-..F;w+3gױ'iC\NmPj6 ֻ"Q;Tt#* C0 C>ExQ&{QkD :PrLIWd"g$*JF/87ZE#S_mǹu@G9#gg%ZY[:Rr'1a?HH;b&g{W.c1pч1m\O"}yO ɛ@=ؙ Ҧ=Z_ *07D4!`!`GGg";[Baz ,~c- bdQǵ av.+żO?u;1m[WWo;Fu.&Y^~ ;\$\nWK[,Pƍl'8˝bEɭƦ #wyжe; pٝY'IsC0 CmHQOoFr^lNL|SkBNBJtDG].\,ǔzxj]P\ E tsbV-vrݵ?]so"Vם5dKH&Yx6rlWn zRmy-ҕ/5ssAch~t;/O3~!` @2V`.c&ZZ'zFڤ׶zrI9ً́Nlz.v%#207/s=O-tY^q6̩B=(ȩDYJ+%#bO%r: 1lZjba^> 9<CmǝG!ɢ%Z!`@- "ЍdKQDıO:acN(woS2f/+)^dittwmٌcA GrڻNvЊFڅ=+yph١cJ23\$S钋c6-K/A}Zv膪{Q]yhv滃y+Vv]qsWA,'f!`;]$X$?{ [ EW6?'!Uw? v=B쮬JizC0 C@-pj~ ϠrO(K`^7ϨeBXĂu"d=.ɘ=unwĚ7}wV Ė.Gj [[Kz嗂1A|֭[Ht4>eL=qٹ㍿>ǔ3N@~p\Yϱm7d9Y5C0 CE܁D;ZQfps 9PևW"]RLxq.Fd(")K|EDZ|ݲs>.SNDwP>Nw;3ی+3o@v'5 C0 $]|%Isla=u'"],8^^:ы.7}xsJ?|زYW)i[v |=pIym۶^\IvMId1Rg0{+>^vj qlpo0):ۚ!`!`л]4!$KE&bMhK6v-ʼnšmWkA,c V "]>|8iEA=c mw^9 6ql$S$U<,j ɭEz"\AQ[gEusd:}yuJ~ C0 r$-]N lp`q,:|߸VLt) SMt#s,6ݷH$яH֭[W{lwۍo/JMN6n:i6C0 C(A@,W/MN8ş4X.Ot ,eQ$vαH>'IL بHU C0 `\Ex e9P&qPX6-tI$uAq/=}|`25C0 C0A|&W9t/ZGY~#;aE2%]oZ0?GdJ( SmQZZ C0 CC ;=5 c'wв?8O"g:^"cݓ0pYLIWDR9:Iٳ.>~!`э~>]hDC<-l6!QZ&X1-!]RL*c驧DzXߏKRo0 C0BE#"JPhA=wŏ1lSӇMOr&K&b/MX|}?zm|zC0 C8 C^]x M"C3!]8&cJ6!Skr> C0 C @p,-- \ =9FLXGĉ8Sqˆt3^pE?^7 C0 /nݮ^WF B$v&6.cmsnM#hȖtIuǴ.r'!`c1v/~q,yi"yq*jjɘ#~k_X.&Jմ' яz6ѲN0 C0lx6t=$aYS)29˘lB⣺C$w0#]☬WSXKO_iԱ(y^>VM۪ PT\üvQپ\GtV!`)np|-I,k{o?Kq̦{#z6q ~jnZ06I%$K*eFKs 7uY+1:WJ ODN~;t9:thi9Ŀ۵xu36z!0 C8H#I2ĄKf@>_!q!=$('}snH1e1.NlmsØ-ѲNk1?=u_:~Lڣj̙x.|e5OtTٌk1Axpx [%P$& kgq<""qd,>gHOd~!|iSf.Ҋq=z8Oˉm;rBL9 #6`$f/Tknhv&^ؖϾ2'BIP\Zc.Mm 75 ) =ށӋj] q#kwLv53`g.:B50EP;rQ!`MF" U]F~sZ2 DC]:-] ڿIOum 9tm kju5UNrmF|J zb=+qY)/b`RE1ٞ^ڮx;Jz]75۹=,NUu:^Zqh+YHCJ b-=su#o>qt Z-(ŀO+?cCp)y`LLxt.F܊Wتw!`@ 売OB"+g\C˾#2{=v bI3r2]Q6)RЮ q?#yofi]p‡CP\bٝQܮ1{0NIYC0 C ++w~DlL>.P˒C(6|zz R,BEz^&>~d+qo`߭]\ptl]&LCpTc98I1o [>ڝĈ;KV\t,w luk){tD*?U<|xe -]YosR:댜 !`@$|iLE|]à `/2ˢ,/YHM~"4dX2Ӌ=qovI3_EYx`rGt) y]:=--B,_'FzZbK^M<3aDo9|$a3zHwɿb靃1ոt"̞( }"bFe<0%oj=)p:r־#d)֙j!`!oI2.]3Q%+GtQIX%s_cb9f[2Nz=%x}X A:W[S?OzYc]!;ΤV'Lv}&]{1AkU b?ʝRn?+SKkFm^XN|w!WcIex|iSGwW3:Ns$\{Yѣ*Ø%٭!`!@µ// /]fM-|Be^sx h8"X N*6=Ⱥ<= Eȴ2urFZñ"aS Z 3Ca~2| ՕUrw  +MiL#LE(.jݛMj,t5R;ɭcQЋUnCU~8p- SǧXg~!`I OD,2.ir+$ d,~|a~WZgpB(z䢎6^ԅԱ οVG9hOjד`j6 '-SxBt=sĉG"RЩ{7FXM#ϑ/=C7ۥXg)ld!`"@%D(!>E6gd'~0!>72شlHWRO_-KiYzC0 C8  !J㓚.oS>wR֢9EڮeɤuaQ:&]Qbdtf4 C0 C&M?Lo)&qKjTݍ8Ѫ;?BQF]?|?MMtzr_~:dC0 C8JÚ;Q#bq.&I0]/K!`!p>< ^! [Rv+hit6Z/sOM2a&MIJQئ%9{1*!Ò9hc5dm~&ls3,[y33{+ 9G;tn܉$Д;[|vOh&dX|-Xҥ'2c)P)>(i䡨E(rK:.JƜ)ݰ*P]~ț[Àu!;k0e\ݴa =,ڄ㑅kݤ=0 СC]?17r\97}QRrL:sn%nNg70j-% kX<[vFtgOĸNv~t H 8 .~GMvQV͹ cKm\@,/¸fbS"Cy.nͫΝ3`m8Lļkw16G{mj {ī Ɋ--:\rҺiFM]Wr0i_y> u E1ed%We{vtY>ӗģR%!`+O}nKkO YJĢֳ>L'ueC&Og2)Џ^l~׷7r (fʍMs1bAX&̛ ߚ;g]5PЧC S16?̸坊EVFl~:u.>*-68"ױ7?ÀRu<]8u>οi*ܛz;0cQFVSuX8Ưj o_ ]; OUUX7`wS̸J;XcjR>v=3U9*{ݘ\x]`cЯ` 1t;4[1qX宨ޚ>=Ǭu.v#unY8<[WnDs7oͅ1צD9 W@V$y]]?{C@lE'_q?0ŏ5N7wû D~{mhG$rk0yW&4)4m K#lHLtaZf 㵎GZ:so]Xݩ;t)mb)xmT5qcrT sg 1Xme/}~A+( QzYnc|+ټ8(9Oҕl")V%V,}Is[!\ue +錻iPW3F< ?wL~<8 7Mr/E\;[)\p2>l߸x%Ւ6m~UaSW [ -9]1|Gør M.F%AZ,qFiUGƤDz rt+{}?y% 1oMY^̑8MBd{s` )D֟kSQ)^LW1N 佹8>̡=n}ڹ]W׎PKKY:]?ۦ!T@]FOB+ɃsK{]70,HgqYna!iVMsFv- к(G}Sbu1Q2 O+Vp,džq=G_^0?; kG} wq!=/} Y˞1TWKwc͖Zn{wΪ30ޭE8Y݄ʷܖʌ{0g)?cش~S@|R\Yd{G 8Kz}Wx3?n>{O>:p7;v z ?څ~X.Lf[|9 O<6 #fy;[`glq)eQ*^ZuTM"D۶7G ~+l}˲۫"aw l,n~2Yxd.dyEp(Wnr;|b۰|V~ xl֣./F7.iγoD G dOG@nj:&Y=i&] ].Ɨo~|mHaq{ѫ1xp Q}ȍۻe 7݌]fSnۏb-棰<oxc6=aY1%8oD{p[/"̸R9LWKb%qc^QWO"iX`nWdwoXgxNS;%ՎЍ4 =1}Km#W>x ?Mc᪳&>?yɹaۣw`RۛZ)aD*k%#m(E^JŴF89#[R{3`vAκYu7(+(z{ ]gzoa\{_’3ާQ (-`aGI7xbw.+1^~X2D/rXO&s`α~a;-VJw`Н]bڂUpt*c@a:m5UWƝbd-"RPYnJRU;T jȯ_w:WW07+trVx֟XFSus]Օ!{-iQ u!`|H&~hF+~N8;W-詨)bA襯 k~M=0PjN^C].:~:RLNǼ,6hF9hBd^E'=Ie!WZDv!ZSE|)t[) C0 C x[Piفߨ㹭8r;ޒ:BH&W"d+M,DD,ZOԵzA#jF2&E▆?oCi C0 C  GFnq"PjdaA/j!Fhonҥ'EEi_}[o!`IhK|-̔WHa/оUL&ZN{GdC0 CH2$-bXAȔ(8S<"͏!`!`d@pK05D<o-W4H+2%]%'sc99T!`!.@"Kb3^2OTƽ5вGG%.>SҕNR9tZ-̟zk!`!(t.0>9c??NXҥ'YᏥ8seK7 C0 +S;|V&)J:fOhtd!>ږ?k,hEd? C0 C 3H>L5 Fg? .6y! )Џ^l~ml!`$O)I7󗧹oKd>?RΆtIAe0^(1}3Zo!`u?OٔlaC"|#UggCM$Jղj%^7 C0 ۊM|kNdmײ,_teMMD,(*>"h!`pL8 >5gԲ%]Ni(!`G ³pI/xa\C93c#M\H(+/z C0 P n)uOkx$~^E  Zg!`!pt">9H-h}4-bME"S-v]e!`%Բ7?S->:޷!Om\+*.6yB6?66 C0 "ЄMp{m2](>W"SҕQ%^XwS!`{s3kΡe񏊏K\Z}+"1sL[? C0 C=a+՜CDǩO韗*C @dY?TXb`#zC0 C0EpAs^l~W|N⵮:ы!/*ғQc'tbZ:5C0 C0"C]Kߟ?/z!c瘲ޙjmFricl9?^]X6lӛ0 C0 LDϞKٸ˔i,NeHl!%y7 C0 sh4؅olHWX)ZXӲċ!`!`a1ڮeZ({ojU.&JfAQIaFC0 C0R 1ҧ_tt_~:dC0 C0 t%:udKtARӅ6=~zC0 C00!:ɪlIWXAa:)NۨdK|2!`!QC8O8-Jw], LOF0 C0 "5)Ol~9nnҥ'EEi_}[o!`@*^!/оU\+jR8Q>z!u&!`!@*n?4H6gں"]~@I`s4 C0 C TZ?޷gJ'[^q60 C0 C 2pmZ>Z*gJ2J2Kn*C0 C0F@xFTZ(ĥgJI/3.^˴So0 C0 tsh9}jޔ%]zeX}x0 C0 LDX^O IDATyG$^ɍ%]z-s,j=e+!`!`4!QC9?)OZefC&Og2)Џ^l~׷0 C0 t9Md>?RΆtIAe0^(1}3Zo!`G7Q|AKFxϪφt%He:-KYo!`@hNZuaQ:̍Qbdy%a!`8pǾ}0-eW-s?:&\\Jߦ&] =Fڗ7@FQQQ n/^!`%H*++q}RGuV̛7WFyy9[k -[DnгgO >:tH!ZgC"S'[łtOɱ6=~v!pg2iF2A| C9Ȅp/TSSoǣO>h۶mƹ;wbŊx ѣ?D'}2%>Y՟- #Ja:)NۨdK|2Bz~VaS!pƍ3Dmƌ`)Sp'.2ZG$gqJJJ0d<0>}:n馌a!'a/qjߖr-J8 Pʧ}|LV t6 w2٩?'OFqq1bXPѰϮGzb~ܖoQFecrאP)Ol~O_xܤK z td IMn:a4Z0(>Zvmp{Mvw㹰 Iϑ \s[Os 'gR QM#yM,8Y$Q>k]͛yTu܁/~;|smtX9^{%% ϼ M1 C8DTWWc8p v Uv۵//)кukϣ}hH﫫Y x4K[5R7ܦ"]~@i"RW/n芓O; %: LuK7/Y_;mY]lq^nBA[?Q咇3rAQwxvލM6SOENORj_T<'xũxh^s׮]رcG x\!NMRq xVf:>q Ax6ɸ٘Mxgu9׮Ģ?Eς&I$IzǸQ^9Z+VPXԭfZ*gJ2J2K4\-غmE~hfƒgC׮]I`mxvD;-We/L폿'owqCUܐӵ-Z34$,pjg0GSnbKpv,v96ںgԮo/^z (,w~Kw%\[YSKpzq~c]()K\E990s̕xL_ZUo\t, tgOĸaG/r2z  9C:C0 wsİp3-K~~{1l=l2a p9]gcM0We*''d[ڵ !NM؄gDԜCLIW:IEck0n.w zq#K<}KåǜVb0p=7v*kjܺ-T}k2>h_θftze=I1N>wމw7}Kc^[mm]9wG[#mq):+⽹0axmG6wC?g6lwr>vOϬɭ^ŔΟ~@n7ѭUmtիJ1N.]){d'`ջ0x|G9{K\_aw+jpj+F*DAQX0'c7pu"T~na;$1zW/_q-VW;])*j<֚!`͉" ws4W-RD&7/1AX5}h]^n'} t8}q zv -ktH︳׏W|O}_-uA^g97`ݘ9҅r o q+6^@< !NZf ?NUfJ`'U$v=Ȳ,iDϱ.2n|_ ?x~%.~Wwuq|0][O!j0'jKuo[~pўjp}yg-:+vw;XExw*rU{5#{SeLoKKpƜ{E~' cw[]Xo0߹CDNObȣV.:# E(Cn<tۄ˰)C_FÆ߁/9ݍЩ󉎳uFNJ&n8q|^l%wBvWL C8Oȣ%|.^i<4|ûYW`]Q\ro힑(sr,gr 1Xӡ|d:w9_ϗ?]{~ qǢ[uA1 bɭC+_(`cġ'4Ox]hk]=+ic)P)^aM?hoA^x sq,[{ޏE o߮NHޛ<yɰKq.G+Ƌb$N6\v*PWo⊨;åW`+p鷾/ws~)۷Oji2a~[){qڌ5BY ራ0qOl`z:2/V»_$Y1MI79쎟:jҎ7eKh3 C` @rEgϞ6wH2ގ῎mFX gBPugdW/ N?\*;_U}'{y"//@߱\4Lnhڌ~5']9W᥏g=ת-kY."D`n(,'%dC&Og2)Џ^l~׷5޼ +뾮KǸ]s]GvsphIp;b;G.Fqz:b7'_Z˱'Re@QiwN z t{foad;Wnjy'֛ks0fv{]3]zǪ`ޒǣp  +\ p.]G [s7m (W5z JݯWU`"\r=۽I޺#pe;9y=]0p pةXt;5k=J"ye; >÷|GG>#d#]x\oa^ q8X#@A\|mWlԵ^ qM;"[Axֹ@+ZF"8# &ar\02]Usy70V;~u+}^ 1mĵs>F%bSL0 C  [Ylz<Dn1g;%_xxgq?tkPHR{_򸭰D;p:g4|痨tg_ >y9]?o]x;sgY&=o-[}SDz7]/]}u5R=1 ѩS6i?txtd=mrї'yQ&^d";19f[|~5e# kRmQ2mQ5x?ne-X* .IҒxᄋD=K~Ī.p0 kpўc]ú R.`K-N? p#\[kpš!pPVǎqyԞylٲ%ȝ9h~P:q}\'om۶ s zA\AlԴKϺd2Bu12"/򺻃Қz*6=m{pxH CAZ|׾5,^{opHO<_T0`O?K,'xݾt%FTْ.g~QX5j1|bxe&\u/$C0!`d@&e2q#vcʕxǃ'7A3)}Ż6w޽{O?K?D'}2%>/>[FtRQ d>f;p{pV!2t[!G ʴh TpLJ@Ls)V&IϫmriXCN^9)kߖr-J8 Pʧ}|LWzg C84t, l~~=Ԕg;flδuME"S-vvh!`@?2/~o7ΔtE%OHmql`!`@d+4G4:^۴^}>TΔte"h!`@ :&YKsE].Ɨ_0B&U5PQ}Q^R CAa~ +`޿h=nْ.g~QX5j1|p QwÆ@v*k!`c/l.йmayOF'gKˆRN68Ylpm܇e?ՠA~ l:C8@hݮ :pߏ}WfGwnn.xh99~7CK~1Ƿg6IwP/ q2־#[+bOв~ܿWe!ppۢ5>ﶻE6-NW.ڹݮtI֭[1o<^ػwo:GO˖-ѭ[7ÇG֌ 2'6Hdh۶m:GΝ;b O~Aao2K5ɨo.Y$Q>zu&bxh^pu*9{'w8U!`r+VTa/LD͚1c0e|ɇHBBygC cӧ㦛nwaCsT*H_dЮ} >t>=q [?ty~6 ?Kɓ'X,?-IٵyBOLp}᷿-F;^?IxK:>q.&I0]/KGG04 @4>xkڵ5ݡ3'c .?<ڷGzl=8sp '44^z 6 e~>U$KC!R`FŦY]b KPݬX#Ka΢ώRFC8TWWc8p v Uv۵//)кukϣ:n#r3Ă <VZ(ĥgJI/3.^˴S}.-]\CoKe3W~&'8h}},]E[0޽6m©-3];*vIb1^Tr>8{p{}uڵ ;v|| qf<'42_yzwo,,RHċ\;漃-Cg=~YdL[,$Y#Vf9zDb@$׽{woOpTV |kn{ɀ ٞع~<;d [s<)j/hQ6㩶vݞQQh6b-jkI:_ܨٱngD:9VͳɏO!f%⩹CĞZ{$d}RgdbvVisyEF:e{B@!Gn={Ճ_) eQK_ 6`hx]0,(AD~5ft˜oÎ쟐r??S6F- (&גX ae8{)^Y _t?p?d ^;?:Md<-;'ϓ| 500PÇqd?d9[St `A}6zi9C/0w`x/Z񑷰N'/c`/Ѯo nx|Ox u "YZ/3PW:6Rh'8xƧo}쀝8F2}8wãYB:⭌pL6d _|A bн o Ĵ!ڭ·ゐa2 cNFFL|幥v#G;+9Ǯ1ڬau-NIq8W`h oC^_Gc?X<9dt k,ϗ`p4G&*%ZCC;oz|M_->5`~nmN0X#hQ߅LK>؍R(RC~)+%gLw:7Bp07Q)#:Eçd{7W_ uG*Fs80 8USs {d3Yߴ݋lH njd/˸,e%뛖eVEAShCD6-['~RSY <XJ"N@ž1):%5>y i=q6k}婋^Wtja')\;i BSa 2{Q./[H(ڽ >> %N_sjL} ƫEj:5| O(i+)^z[zhz奯.ɞa t5 =sfn*R_('o ҞReE?>Qk$&pj`uW5N; )}b|qK'IH>3YT`Bg>Ŝ$<(gXĚ}_&Ě/?֯+5ͨP\c%C@\bm`0e ,}q@n%q*CwҳָD@]z\Gj\Dc_⃥#'?Sxqd!|M<|gk</}7Dwo@}GAL%=)KLċ wơ!SrY YwK_^3&#gpHeg} K|gGA-BK6GH}: ?xWg9̎ŗ^8e-b;`8ݲ7AjVQ4hsC;Y9vNkVG'me-?> I_aϾab=?/^z}hm=Կ=gG2e`i= G`SSnZ_aHe +&Ze4l1пDkSE(:9Q} )b7cCl9} ᡁP&m 'Y#×#NoG&7J4sB6?|=A;CMܩ X 8Fz߅8jdLϑ\y^.EJ<6dNadVn˂2f2߬]W62sVvƬw: wNo84ߎ IS󎽨"HB9>'I혘NMC>k̎V}Hx}h#@#$1>DΙ ImZ7բavwS8&Qt8^"t2UGyoۺ( |oAl8L?p^9S,|耬c s Z<=X{4Z` gַ5IH}Hk Kyl^y#=:?4x$ُCYӋ8Wv,|hX`P#Mܫl2؞!>o&R>È/jΥ 0\UFZ١TM!(?F21M|7߈oO'c]6)vg7&II32/4[zА~z`;COP} iv7RxmxGV೸9p㰏pf1ƍ]Sךx8)VRss\M~:3g:㣏U! 8s-R٤KvHvTvF_ZdZ r (]\vtp12 /c=ЄZDN&B430.Vv|b7c ǫi1 A㝵S#/ogޤi\O+qҨo(w/ ;/.ZЖEsc"V|kФųyRݑ{ԤilmZ={"?Gy)%oB9f2żOh xxäm3h\˾>p`]^ä1*qo à=am!Zam0unB>PΑ29G}.mc˗OlD{hsr S%BF[ٷoFR$֘҇=P+6wI[ϭPH̙lc[u#/coud".jR"7 1f!.m./msi}ʴ92sfL} S]!Og#c,rQ6ʙhgV/!|ڕ۹.dfy+WuVst"H mZ?g?m(Ԓf/1q;EBNy-lǖ hEi1ןB'KvuW}[9гb=t__%:]ZRy-,AlZEtg/p:n{ W$[RK(Hҷmn9\A7OYԢo~F=t%1g ʸ* a MhR|g?k֭ѨEÉ\k7?~| 7pϭqN [{jr>2x7?LXu~e9]95qYK·B(Ln36uMM7iH0e/{Ons5[jdž-ć`_%g ۔à]:n  NDrMl8&. +.v 3SY˸^Bl|O}>.WKxseN+rbpp0:wm۶݇⡇~7mLt œ7s8•= Nڋ̸0>UsOzd}˺g! b",0+d܂]ۤCCC{@ݻw#==GEJBOs:"x\N O@8* dr^iVk">=QW`jրQ28[R?-{Gy|m3էxVW=)TR(z< y{'?]%Ըqc%Mbxw'WA]Y0M4DXX*"\ŰRs5Xוݪ"]fΉIrЗe|S:ԫs]Jnk'p W(B8^HCg;a9Q wux=.~"?|}}+\zX\q #!s WyT,ҥw]i|e4 =A8]N> @!`d5;?MثC5=M=ODJU /G\*Gxj1SwZ_^)bF26s:؆FOT~i$/ 5_Rhz4 L4 ¤DJES^_<&eYǬMʞ.فrAuþRj'?𾶥}ëIav}bI5B@!..&\Uf'+,W _t IW\6#}t!2T?wsrE!P($92wiâKsyQׅBu,EQWB@!P( O shuqL_ӫ(l\_r. zS( B@!PYF_qYH%tUP( `T@K WW7@YtCzGd'1]&e OH^&N'OU^ h O~ٳxW~sF7B&r%L3{KL8'L:tTD[oj׮xyRV(Oq|U2] 3!8 碟:6uoIK1 ɺf:J~hܸ1ZjxtC P( B=zSydN!D>g]#r&]C\@&*UCVZU U gJW%xpZs5Q^U& &f:,Pq>~t+dZ.^+P}WFCWhEN:[egBмe$EFeh2{|([fB@!P(W-x_׷{J̌;ܦﯯq*zxql<ÇLlX= }i]dzRn Q&v s{Fᳳ,^vКRW( ?( 0$rM:ܰ)ȸpl^9s6`Z4m0|fy ~ Ģ/kH[tȟ"dܐ-tC0b=I{.a>[ȦPo=qpXyō;㕁v_&}ֿ-4g,ssvw\4-DeMٖOGcy6 ;5c79,[ l݆· fD B@!p02^__w5 %],& gh,~ d{f|CZ!!|lP"exױ!kۆWz,@gQKРA(Z/>Z_C>;+v"{hh16]'мAR ڲߥb=ou_P- p{@՗`mB=37 \i qW8Xg$PD,m#,xl mK>;@"? ;F()- cti(5y>(“#\  )8z_he~ c*W( ?z>a?\FhMee%]rׅB^ƱʬԮ7 wmu߲gв\uGԤn@Er0G$^Y3Kqزtr BdW#"$u`Z:4iwꎛI&Y^- s?li2(A!IŃǠ6`ggWբ'գ;y'hw'gvTL1Kvx!uyJbSز$ Ei]?tn蝢\ߠob=!UZ;Q iJK`z4iP(|,gu#q =oH &ghݪk =גlEg\9Z!Ev>ǞNsbRӃl+ZxŻRq=KhxʿhԊ%}GQpkA>6mд {_6 N׼8 |y#yS6J%^DnH$">=Djk.ZADd.?ς1o5ooG=]Yޣ;2(iD``úGKïh߾=ڷimBA; R≩},-oSݝG,-0`,6!$ikq*/ Gn,1ӞW.m5՛B@!PTf|27\^b3˄\95q.Y@97z.E.ʢފ0+-ZoVt?vlيpFw>!Ec%}V4pO6i*ۨl3˚7}uՖ=znݺvUzdD:3qih|W*'Yh~ P-/?S +)ZJ B۹=1_f\R(OҾ%QqfS80maؔ=o%fOIyX1UR(ç IDAT?[JIǎ͕TA<0G/Hz&^222!eEZDFLI,>IOΧM&z%"tE>T#]&{ \= :ƪ߿UTDB?cćJ B=r+tQE#MLKLdzTuDY+}N*IWUmdr/zB_t(2XU|}XItnl,r2P(Wp^Iqʛd^&ON&e=o|Q} B@!P2;%Bǝx2rH&X&9% DIWX7źR(s7=wAhA$~";/\ֽ%]. ;D*&`$3'(D?#||Jou"].!R @5# =~tU"`52zM^zU.!yB. dr^ir!Э[3,)  6xz͹W@d=W\È;r5$LG-e*+ B@!0B02phLeEN:n; B@!P [E?LSef$6}}sP( B<2Gar,ݑudaSqE!r/]ĉMzŢgӫ,~+^{~8Ҏ^.7+1y.b_3s|N|w6az'XCR1K) B+^!&*U^Ulqn7ӑ'"eYt/M]J 1.o@m_) QnBph@ٟͯS$I*Pj[]@q#o:DzjUs|a-R=w*.ˈ=~;5cȯOVM<ƔqhwS}4nҌjX 4F__Æ=P& B@!GA02pտB8U;j.Th^w.e{D뇩oo"QLAhp}(q8rp{l :H%l^LD*]CNfp_hlGNOs~Ѯ@XdD|ڢ-4ng$aQh{?QI!P($\q =׷{J̌;ܦﯯq+G{Ƈzoc􇑻l5 >z(F/u}2LXDe~q26N\${*(\e&Yu\mW&RE|0ծMK$Yf Ҝ P/xGoC B@!@@'/aʬrѦD:ι/ʔ9T$;$٦.\* B@!p__7)zg㖶y2ԠpPߟM]o7nXԘjP( BJmBuE&Mи*qP=MݙoZtNˬ/}MĝСC@EJQB@!P\0*..,馛qT9dFC I̸pV8ϺrYerYz^GAÆ 遦QfMEBQuR( @!ŋ~e>{IdNa.eFdY&leY2tFAAAh) BAI[ y?>\bRI>>Zk#B@!P(ՆU2/qL뫷w/2yr6. [uy; :+ B@!P*JFCD9d$m,6B@!P(2FN"rcԟ=Jޒ.w0ٓutM>uTtF1@ B@!PeN!D>DW״^{'^HZdHHH@Z0~jS P( G˜kaǣH$LGЗe^!8~*0} _윣U#fՍ@nn.V\N5** 5;ZkvWWˆ\U ͭHIWvYB0,0je|{i<vTZ^b֧@*T vaU ALl4W֪U߶#H]Y[6dEa{M#v9r$tt۷cŘ0aB=VK˟bƠpx%4Lŗ`m'2j ;K|M%xELxqR d= [E?L=]fƝMRn8W~On[0X㡓Iډ:r,<][{xoETPZ-OD K2h/k,Vg05eo8w *"\I1 ec>JXn5-'bpTcb"-ՠ3]d>ډ^XOYCr_~ƮJe=Y1*!C GI~IG/TڈEoE"yG4k"[c"k,T92OqBES^!sL/rZYG=%]7Qs] ԫ^'Zu|qsGaرh4>u>acz)8?w`]Hα(/"b06nsc;lD`Ƙha܁Msg#H'̍E97`aR0 Y=]菲 $ )X ^;.W/9ialfb}L~q`0aX(a"T Ѩf Z)kWz^?Mi ((FPD'B:ODx'>uw׆LmO;wan0OeSU^$l@D_56/4 ?Nn`Bg[rY7~n垒.w' ymF,ėAjR⃰[n?S'O}{!= ]^,L>fu{bDؑv#"KJ##A ^0t +bJw|S"9( >6ҀPj'bd$#;zZ2'g4' I$hߜJ?>l-o6\Ѕ'[&#OɥVkD0b/lU5O'^;r3]JJJX )_U1 įYJ"/Kr2X#`_k(@J(OIA̙py"Dz-bF#iLڂܠuEC;q9O_4lzճXӚNKH9zYIU>z< oø:2 P}˜C.3Zz}}.+JDYLB_ Y& *9ze"M܉3ٚ5xcsh2Dk#Q1tz88a O%vܯ#n37d1#Fj $̟~3#pm08>fަ2rl~#N {k:?7 k$nDvvnSSIA$MA~H_ IEx~{r3|$fž1;`g3ZRS,C){'!&1:دG#DЭA~̋'Iw܇=+K XIcǎK.];>IwNL?1Og)(0*1 7^_6^9YS6bf\ܶf+ 6efD`ʊ]lE0Ȟ}(v RT5#9hF03'ڍ5'G ==ox>tLDfn6/ݐO6tc'jvdg/ΞN T&QudRgis2 tLJœMIXXhi9iZz%uID™_ %c{@t$=50,ftد;`kf62'``LMGxǮ8e#B\Թ=ΞDғvnv ^$TE!p #fCȅnБDYVՂ2<\f}]8(˹,يR'V]_"] <&>'~ܱR3k勿]q,&wWg$s' ⬶:]}pL4jf 餼 [}'ڱ|lT9k mEzV+!&cu-&"ĤbGS Qڒ4_W =U4)A;1N⋷eMz|:5:@CŦ>5!I0bX6]Q% Meo+leVtuDj=?OGt]#Qxԟ.gv՚9ԟfipE1im|єRާklK?2XB_.k92Džc,<c쳴vlY_"[# =Kn չ!tǦ 3+U~lc+uՈ_1=b ֦(:h6žo 2sO֟U"]$"XD`d t p߈'2=u |':FڼY B(~:mEڦl>#V 񉝣X~tvTy"(H˝cbB1 @1{hdLe}%]* Nq41޳B?Yt1L3-jB6=5bՈvBǫ#/rDXExD2 J,{V}kcWz:,Ri֎ \FAc9+9ָ9lx sv\(ŀtI^ {#`|\K%4V#<07z%E[)T3nv qهTI!(SC&wd=nw#뛖(;ifXvL.p^u6wvbmuSK{wZQtSiȟJ5qT(Yh/I1}&lCf6T3;rꀛ֧D琩Ԣ~{$q+ CMHbDt)Ka]͋W _FjYTZܳAH:_>Ѝ@۬M+NwYpQcZl':tf]j!*5nq_n+VS¼K=QN6,GS8er sgߪZI7HM+%a!y6)}We @( کF7B;)P5; O6b т4ׂ b;8yiduYVAN*͑LAj 0JǙ{`uMՙ3tLv$bERO vF!t ,:zGkcߥxCѿS ؎fkǵ{4}Qt\j+YSv"NZ41t'l6Prي3]CBF@9d(h|UU r6pV8ϺrYerYzՒ9b`#w<_Z*"<hg p=S3I>iE7;K PX>;'^i"qwҷ50I IDATQnz9GƢKb~f|GSe2z9բzKn$W*ݖzW\Ȝ]. !ˌDvMndeB.8חJeuQ:E]:|LjwҲq7e6<z9zCX0 g胆w̶b诣9֩1F[q8μYm21&Z)seR|*.(FMߙ´h;v=y}-"7+ݻׯǐ!Cl Jbb5ĈUp-ʏaARA"rMȲ 㣸4lM\nצ.1? RJeL>c_Fzl409Žҏ!S *F??~rjW;$$ubxsws+s]~ B E.Yf"qZJ9K. Dz2a9+hzy~ ~-6nܨ=r0M{N𼏨|f݅!*q\O[v>, +? $\շ&#*$]zfDD d%86{ޙ V,e\,E VKn纐UNz,oOOg]#ruW]IS@&*UeB@!P(bҲ+!^UE& v3y"B_B@!P( #\q #!s Wt[VYK狼 pJQ!P(  x_=%]fƝMRn8* B@!P(<@S^!sF/rYG=%]7Qs] ԕH!P( aArY7~n垒.w' ymF,WI!P(  se]RK@$uᬐMeWB@!P( O 3!B__7Wm,+S(<.\2B@!P( JDrN_7)zF3pPߟMoGoznn.V\3(:SSmՈZj[ P(~9=mLY۝eoH줙a1yDK*t1rHtũ۷cŘ0a[N+t.,[ ?/FcoVN_|w"TmۉL^~oIA| k,Ǘ?ŌAEφ'N חِmE ۿVQP(*=琍.'E_^^$s\L.B/jN:Z󦹏}L,$Gk05xl+p 9d)^XlClh8uWddB@cbѫ}uP(*)rYYfL&kJh̜1+xcUn]:Gڴ1jԨA˩"ۓӛiXHKĠ0 "6m셱qm+eLjvو1hWI60F ¼tX#a+.@~^!kmM+PkX#iY!Vvf5ʖQpWJxpGv`P@X^-TR( O}ťneGde2/zrj)%*&R]wJJJX )1׼ѵ>v$'`툤HPFW/ #JT]I(GX\/l$Mbbd$.EOKF~FiOHAIiٕ#aW,¿d!&aFXhCNh#|̧'.wo)ri GҏE[+J]ƪ@Wt`A˘<<3QD*v)VNu#k -QxZ'Ldm7x p1d7CN.o_Uua+IE,GZyG%k㳥2YB@!Vp'yOqt '2Q}\j:v2rqpX\k;|mμ'aXۇhQ#fap|}lΥ=;#7e`GŹ"5 5g";k;Cɿ J/{x<= kp>nQkFFS,h=tAD"Iޑ1sҲ{ڑ$\iY/"Tt+\εgcd,{-~@"7^_6^=ul#fmkbٰu'"&[4j9iM$ٴ,ڐ$VuM@6ی'g*) k #!d"wKWyK2 6ugt*ѫ5kj/>р;B;4s' Vm)k+>5EX3RYز+] QX>g6-~ʫpȍ_`z!WSӋ06iQt1L $q)2~4v;C$$yK"pTy|4­7$⠦mWh_hbd&mH:O[\#DF?]#֝HښcwݧPnHukJ-7p6֙`I\4]^FqF/Ghs#]4iCM/.K БIO>_s=P(ODrAc0g:mp:4eLl9f7TEյv͎oEE ]˥=X) iVsC5Fy>B;2]>F޴8dw)ˋOaǶ 콊CB0)ڐ߈;1f ]۶FNίsfΙN8 iv]!Pp+e=W\C吉WL:M@8f:I/*,DyԮmOsE>v[Ð ] <'%1G˚3sWbߘ6(Bt8,<;SBK&s"u+: c;Bj]bF,|m 'Θb5^/c^ӯۺ ᵨ.ne(EFs ѣ uj^3Dq1ѩ>qwZ_0/b2@m/wcm]M%U(W l_^?ɝ2"R\(9ń̨LbM:AD۵.t H&mѦ y弗]vGF8KjB޽_Fz]`e DET㸞6}X cbDC]=`MZ!UCpB{J&}>;RKW͈[&yt70J$cu^.*W(w<2G6Y.c:fmV F (sbs}Y/92>[|A۹.UoiO?y3hIJz9]|wuJ֩wTs)P(~TqKD\H>Jbыr.k*"'}ӗn*KL.G s7 zh܌w8Tj}B@!EOx?;å~EI<( Q!\W[66@"]B@!f sYM_N2_)NVFר";$YW_r. }%S( B@!PYF_qYH%tUP( `T@K WW7@Y[%;$dGmr]TP( B0B&rgDx嗷!#pNnc\wLG) B@!0fCp,uQQ] &;'&`$3#TX+Wj??>** T[5"֮VC) #!9mu:׫tr!JlT._tI#GK.rS۱xbL0A-r U$8 ˖O bbѸ:WTfa'྘1XteP(<@d=W\È;^^t5$LG-eY/^:uhϛ>>>.1MEìPZ-^XQL{Yc:){,k0V-ENva$/Z {ƮVj1V·~|.]t-oz.e&3=7z( k Wˆ\U YY1&N&QL֭KHrfF,00jq~*"=ɉ[;^ uıL ."bFX^RFm琍v8C9Mb9%xm}o~3l9 wd!:R,?zαBG06Yhbq`0aX# %s\|""#>Z_;3GŸIEe8'yz}YIPc) GO~2uO#]fƝMRn8WDDCII0A>S>fᚷ=#ǎ̟q_R jꅡcY+)"9( |@* "DADEeFE@ܵE(ZEVbmkZ\@T,Xp""D# ,B !s&9ɓ{.(g\99s;g,rѓٹKW2ΩX[T:Ɗĸ30[-d^p2rVLM]95Ȥ3I`5BC bc^~!*厛Z5b2aƭ?|_kn)ݒFb烤M`cxƸxh c{&A5da;:>r+XF=/Fc)/:: ;Sy5ytJF&w(u񴏶c]1 3Kܖ{͘Dtmذ"ڲe|=%vŻ Ḧa|i|I缺t|y2z`4#sy\ gkWbK1fr?ֹ1EmpoŘ4w)b1}l_\5&>k{Oâ)F~8\77+cb2V;R7H8ꑹd='e- 'gcM'ؑOul5yxq 0c1+[ڲY<Kn;\"MfapKocy?}T8s6I]e+Otu$774Ϣ4ޕ_CE1#iUe Z?Oܱۂ7zOG^6?+;xZPOU*\E~{8yv`-8 /=.톑"9R!.V#`-bgv1m^^L C~n[vc~MJV#jXjZy09X7cΞy+z,hZw6}%/e)^BKJocGFrrrоM3hiU & GϠ8UCgQ(l:Vnm썙U#g#AGgoz-mIߞ#`!Eh;mX?XGtM8ꐝp.}ݫnR,ۈauRխ0yr&x* IDAT.Zw=7=})2).-M89r0y}=B-^nmӍYY3o&m{=!7`ʑq['RZIt7XӜ;!@k; o?(-޿tl!ށ1dL9FLHM/ d,}pgzǦKKcQw+ywsb!e]ΦQb}Ӳ;v#}H#/p5n#~|`]lݒ۸t)e}\JW%ǰ\C׭[7Q7|jՊ~OEL4 DΝ#:/[ : ;rq+qP^RT"ZHoEʾ/EI hP^te.AA>Zkkc㰢"MIaJێNTױ:l>t ΜmFСEMa-[@~ys[M|-ɃmRg s.>5]M%^{v /Q>VN 0ϯ瘗0m=ɺC_&trGba,HDyH 3hYYU}z /=ؚcUu,{f\u #`~=ݯ?/>&Aop]nnq?!+Yn'uYݒ[VJݻw{Bqƀ" 4iN#nE[vfZ%JGF#֡xo ر 0?  t\NY%Jv벺%dEXPq[J]g߃v{8 Dqۭk?ђETFFvvyihݖಭ رn60FC кct;!.N@'II~O_B;hphQDtv쒎4F IIhO\l\' O($96:$>#`0F@AC4<_<۵c]a'قӾA>f7F#`BFk >׍ lW;wJJF#`p Di +q%v@ #mV7F#`hOh-oжd.7h;'th0FѴ?b/n_ 7mWJF#`@BkF>mhm*bgF-uw3#`0F 4AZs%.T 3n:6#`0F%'uwzNH1ǥk[W\iӦy (DC AVVV$7AvjMeyp :]xM|ͥk[zK'2L~QTG}Ϟ=KѣGS̝;O=Ǝ-ƈIܲz!<7_p==jemJRр rM~Gjo;v%SGB։"6wffA0F  lL'ulVF:@sЭ[Wdwĥrբ8^MTwfM^!Gk͢?#5hʦcCǧk:NF4KX߄e7BkOH>?s ku}d 3UȪ_>#K>jժg~q׌+@V֑p伢|Eu#ȣPq__D9:2y7WɊ$G c0{ =iI_Fx񏫌GtEHW%Vt]ůKDBv(..`hSu[? ]z6¼C`k7L^\tHf-ye(庥 '+[%B+ccc9 hOaWˆ9k+^&do%f"NF.yem%^%۶{Mt.\8$m3V^˗ELay`E]VVϸcfҸ㼓{[:OMTMn#1r0w`񃲑5Lf#w܋;|Ƹxh cЇز7~4xji]^\1u\sV>V8 O_G+l+pk1? 7`~-6#`/~;u]Nd~ϞlN& G܉D;Etmذ"۲e|=%vŻ Ḧa|i|I #u3H<=0g㑹Ѐ\?O8{\#Kg\1C% Εo/mէc+i͚ٲ)2x~cWtsuZk íW@ZhhJ7_p>&?|FTH7@Q=v %KDRڱ͛)}k?g'q}c&-Z5(Ic!Ao˴fhF-i踵=li9}͇i iOsl~ t2Sg5iF7F$v>*[#'Vh]c&8!7$'>~ P<W#x)^GK[%Xkt̤zga {.N=)FANCG;r1zn 6 V!z x^o.X` AДVrsGs_9r c-Y9ݼʕ`8;'l_:i\<ˉf-xteh&5W0v(R&e0CcQ#A{,u  G*20F@O?$Rų]p;-^v쀟-h<䓰/G+DauV#0>CäsOE1㮿㦧/E&9%7\tka u{=9N7bgeCWj%ӠuxdJM9r$fܖ T71wҭޘY44hц0wtyaܶјq14G5Cvo|sw_lǒ8GӍ1j$41;ws5uV/ZPHBo+Om!c"b?b* ֭2H, tnap =G:;ٳƠ+ zZiw-ɦ0[˖-iE7AwY]n!u.d.sX*9MI~>&ږ:յkWOxOFDԩxܚ6d]!/ACz9N#10FYnaXR;3"oXlXVSjB{۱!#L LkIۧ;>vS#bzg&#`π@eJ= 6K--,)هgbYҥ؃ʎ5bntw~~ƍE;A*I&t>VkmNGF#a y;04^0YU/`AW'su>WFxd&u_YDedd*BEa7m.۪&l#`~VbZxݧi?N`! / Ɣlr -łjc#`~vDg%.u]ⓢW\'b*ݝp<)]>?f0Fcn;ڼQ]zNmIV~;6+0F#+WOW|tk[zKO<ۖbX" -hDLd|5F#`~3nO>R.o0In<ۥu}ۙضm3#`0{?\'<^ )p|`=ѥ X'/Kl 3S^6j۷{*F#`^KԜqnKĆ.]d%yu6]xA{^ 4F#`~2ZS%u]$>߳'zO;xP::cm#`0FB c"J$[tt:tՍ0F#,a%:&<]:!IµD>~2F#`H6?!6)#+xK&>v%>gH9#`W !K}ܾxW\ ;M?[x7F#``~ZChM!~疱]zbw'Ni_b#`0.hB_4}%>DWHwDF#`#M[5ږ,&m_N0F#@ pGŝ֍w+c]AGIƻJY#`01UWhxݧ:XEWL(?f0Fcn;ڼQ]zNmIV~;6+0F#+WOW|tk[zKO<ۖb50F#DACy:S\Pi~Lt.}8o$pM7aÆ];>5`Ϟ=Pͦ2Fy2mغu+xĸi؏#hz܎iWtD'';g ODg>1 {<:8N`sEfȇ1-d;NThq剼Fo+ēK[(\1'V )|Kn˷׀wGc{|K;q|NHSnˀ;9'x"=ؿ7"(hO^3jF#`~'}nخnѥ'pwR/O_#x QL+]n:gxƏ_ z\t2] =S >u!^ ֬[_.x3_.-vj;j\O*Өg[!.vz7,uaĆk8J\OQ2mqS!.c֊1/J4E_ \vnk8a!=#7E ySoُ9E-Ќ֦5]+Y$pfCoJ#`0?_ѴZ#Z|Bd&m_$ao釗Wo:Qx /鎇O}e`0#Wt8>,yai+GRK4len%e+UPWڙ3C+&S8YISx*̪F#`~Ni WĪ_\n_ 7mWJ.iuooo݄3~s=D {cXW>˖#.<tP v(,)ĶmQXvP)|w_KkWehH[*uJ"tA.F(wv #]EAc#`^N V]5 }ڮhm*bgF-ud+=Z34`.SkٝSsq8.7ƁĮK;طuSJ jX*22XUlnHZUXH-~]JU5.B--Z~~Ʒ.#`0ؾ};z-t-T&X? IDAT{nwvӃ9lg!6>6ypoM-_+20IEonZa>ǥkϦAk[U {O3; 8D4${Ӛ0F% %_.}n<&>R⵭RWtBcmIP۹.DX#`0FD"?ݶNq}"[|IЍgᮯom#`0F!j =>=Ex./䁃RNL9㵍>K|f{\mBC_4#`B@߹gxc|&*z#x ]#" .Jm.g^D_~%Ҽ?sf&bFfF DEc5P_Eh_|M={EWP::'q'fݻf&Y0F`$W~ǣ?tLXD瞮H>=Sn]x#`0F YKtLy+tBkӉ}d,+0F#l~ClRF%W^.lcnGJ\#X0F#`4??DHų]p;-^v쀟-h<cv#`0F0?!d?sX|vu.=1z][i0F@4]!/оWY]+h$q;"fu#`0F- mKrܯ}B'lF#` M[#VNƻڱ#sva0FĪ+Fitvvz+}fxIRq70F#`B5P|]B0;y s?m3F#`@X~zBk]1]mި.=e'ܶ$+vdċF#`'m+>O⵭R=Qѥ'umKuWJF#`H" <)O4]~Lt.}8om#`0F!j =>=ExDL8(utc8^۸#[J#`0F`&'Z7ŋ\e<+D$Ͼ.ڦ/~V#`0F ,)bt6 {ddu2AuN((>NX0F#`GHÇ/]:!Nƭk?ou#`0F$@XuI8xENHpm:QOe0F#`MOMHD|+^嗐M}lHK|$3F#`&h)yxknǴ+N}|n0F&5'}nخnѥ'pwR/v+0F#+_EW*Kt$A>zG_۬n0F?ѴZ#Zߜm]nvO#`0i WĪ_ixR;V4x}nۮ50F#Xu(<}ڮ>[Ut4ό/s[>f2F#`@h3uK\2VfPw'6ugmF#`KOOh͡<ﶣ?Qѥ'ۖdlx#`0pDmyGIU'*ΓmIP۹.JY#`0I$?s~: f?s ku}d 3Zi0FSBKFx񏫌GtEHW%Vt]J#`0F%5_ud~ϞlN& G 4F#`@iP%٢K'ɸun0Fd?.1  IM'4F#`@ IIO\y+Irm)qc}F#`CM"%v혶xEWItr~oٍ0F#њB-cuc-ļNҾRwn0F#`\tkhZCJ|\euĹ?GkՍ0F#G ZkD3-YM2p 9#`0F @4mX;Wj*ύwە0F#`b Ou:G}뱊Q%ynKLF#`M@tFP.AAv U* 1t}~l#`0a 9ttvy'*Rpےvm/V#`0F Vb7>׶JDE@y- j;^)1k#`0F tnO>ҌGtMf2IЍg㸾n0F#)pxG]2yԡuxmnla_+0F}@`*~Chވ/qHI~2F#`H6?!6)#+xE_B~6INM#%.|#`0~Iqٮ} ;NNv4 10F#`2ZSe,nl`EwISWꮿح4F#`K Mkh_.8m0F#`D~Ckh~s%KtIF>6G#`0F-\~quJXEWvRnRr0F#`@ bZ4:^iNGho=V>3J$m#`0  КC?(>.qXEWAݝpw0F#`p5nO"hzqK&>v%>#`0F@AC4<_<۵c]a'قӾA>f7F#`BFk >׍ lW;wJJF#`p Di +q%v@ #mV7F#`hOh-oжd.7h;'th0FѴ?b/n_ 7mWJF#`@BkF>mhm*bgF-uw3#`0F 4AZs%.T 3n:6#`0F%'uw꟨H]vmKbAI[i0FX z"H]ݶ߼$^*]z]Iܶ$\{Ĭa0F$ӹm?J37y$A76F#`@_$XGt䁃RNL9㵍>K|4F#`mAz%z#ZU#"M$Jm.g0F#`К/FmI|PgO JV'T焂#u#`0F x􇎉4|(lѥ҉dܺV7F#`@Z蘄Wt$ צut[XV#`0F ؤK']~ $96ݎG>#`0Fh~!H&gvL[+$:9?[x7F#``~ZChM!~疱]zbw'Ni_b#`0.hB_4}%>DWHwDF#`#M[5ږ,&m_N0F#@ pGŝ֍w+c]AGIƻJY#`01UWhxݧ:XEWL(?f0Fcn;ڼQ]zNmIV~;6+0F#+WOW|tk[zKO<ۖb50F#DACy:S\Pi#&3$Ƴ]q\_F#`CZ{}z<..RwK*㺷؉gQclom9g]f6F#`/3H&R\>n_vr'a쀟͍F#`#5Ok >׍ lW;wJJF#`p Di +q%v@ #mV7F#`hOh-oжd.7h;'th0FѴ?b/n_ 7mWJF#`@BkF>mhm*bgF-uw3#`0F 4AZs%.T 3n:6#`0F%'uw꟨H]vmKbAI[i0FX z"H]ݶ߼$^*]z]Iܶ$\{Ĭa0F$ӹm?J37y$A76F#`@_$XGt䁃RNL9㵍>K|4F#`mAz%z#ZU#"M$Jm.g0F#`К/FmI|PgO JV'T焂#u#`0F x􇎉4|(lѥ҉dܺV7F#`@Z蘄HsNMD'~O_hX$~uvmGC)}dFسgvލ]vy1jJJ QvmԪ .a[U̝u Xjcc B~TTQ0#$~~s7RIv)]?vKՃ$96cuwq? -ѷ}Y_/|k0gǸ_ܾGY%yqFŪUn:ܹ3yG[.ZjmOG&M<Ȯ bǎ͛m6QIaÆDvv6իW-"ӰI]i<cʔOܵXb o`Aq~8LMgz}&~!H&RtS>n_ԶL&v%SqS]R~MnّN?) .nIg݆M-7J~Sݸy+ڎߏmRxGϞ=ѡCdddXc޼y3gzꅳ: uԉ'˗믿A6mxBOZ^֩S;N\"~ɧ^.dWб%4L 1;ض˾ŻoNjV⒋;>Bmٲ dˣ.zD(2ظ:إ.v${+is)K&+.L."m"&2D׽ƂkW櫇nlڲ xeKoهO8kT<#3I __JOOFxGыi7.8Dh[jԩXt)4nܸ|YOE'gpwg ײewߡ_~HOO/:6i.íT==wE[ic=ֻDȗ#m<Ə?];= qm $SRR=dn5*GSNJ 7cӦb jhHӓuf{UZ]0W*}ejݺ}NO4mER)`A#]>8n jN1}V~>>EϷCOJLé'LL%ډ/%7ϧK @~6>79-1I+?l%ڶnCB탏̆qگ5| xwJ~؂mw`:E\]+,,̙3KY-[UB_ެM\a$w{tθpu,WǶճq@GzLRɄkayx70l04h lXbwC~F "G: 1GaQ"tլ'pH|0݂R ŸS(LBWۮ:t?I+,v#;9ڃ S:?'ʽwNtXR2PX>< Sv0ҡ}XT"~yfUI W͖b棵h,XǘID;?xt]2(~tN?b9Im;6W_ŃZo\=5;KO:AZTMcg6H/Wd[H|2o "}A FGz'~Qjيanō/.G:,ۋhlPV:7sKps;=[*Y7YwCز7v>m.Ƕ Gro,!̔O̸iӦ‰ߠq&ol~yzĮW7 ^ҶІ$ȸ9Q :mlFj.8shx٩fqVCB|k{*<,xȽp0Zk}UӞV01hHw&gdf)L-[4+IR{ϧɅ8t4?3_͟.Og8E_LǕ+'}aW|wmUN?cFqga\:gLhJ;J{򹽘DKuizy﷧CLJet9nLhˎboվiHe@Me7.lUX8)rhR_.=]QڬIҞs [n~׈/br2[O0kpqٽ~hsUŸۀGtIkS'c.;%>= >kp1&h\__p a$ig3:~-Ffm؟ 4~f/l>2~5h7w ƻ\{fN}=`D xv֭%z^fj#`68{h 4u<>zkZ&Av0꧑hɥeᅢS@q‰=8"`̘Y{,b_'a>z5Y5ђָc |Y87q̜v#f>YO=w}ֿu' G01Scl Rp yf`c<{IG1x|h{:svP5-N"6~FϿTJI@J[ zԪqPC*n}OFblX @t5̿5}?bL~kWca]ګW/;hnw t+NT4WUݨhհ:kX~΍tbsF;s]/VRwH9mKuG+~~-qM}u=J?yahH/*oNqgo2_p|2b'}}O㮫35_{Ho*+ .x/>q㍩kȣ}W^2$FǮ=2R|&6ˮ~GJ]̒7.L-3~^[M K͏7㩙5nNM4a!Y~pˠwKk>Q g` O B'-]Jx̝Kfˌ?x}=~+ug^;U\CGImVw8j|hI⎽Щ((.x {gdddK +z]_^;{%i:0$8kP iA^:)jM'JG%RBTzc bPu}9܎~~[Ns]s7w0|SEj>ؿ87G"vʽ+xjޅ;vjqx^?! Cq[k]\G,-,o0Nl>wnP?Ӻe'V7`W+ߥNم~> /ԋ? {bG咅'/e_Zx%Q1m7Њ()83SPV83+Ц׵W1|2zsZegzzÓN* s@֜زb]U-nqF$'9׼E YU /~.4=ËJд rBOtAZ=̒zhP\O~ $Rj`Vo>[{n8IqC,cju1xp,*o&_^Wn#Cnp]G0[1 HnϢ^_p>z :skxP?U4=BO1jQZ╞zt^!{"s4NZ0[tR;6 z%7уkcoӛHqwu-bk_Ӄ[!TZ't@JHɈ]jit[}!i^~"Zj Buʃ~G9%$։:KiG%?r-xWdkӪ)pBnm~ɈhZ$BoK`|Aߤ/YeS3'z^*p?q)]/~äu|!AVCӱ7r.>~o)$2:CVG_CQt'R#'x^6d}܉eEx^e4&'y>xėΙY81g^aq r-^t qPA8'@ ӷBk#e}_5q‰|.|wmZf}c'g+1t;CcV݊j;xOQ\5< ]UϷʥ_l~U3֖4ꊫ|9|Q ڊc!\<?Op4O',|:$xr3c0 8n|E 9^e_l[¢^_(u/A)$C7=_ĉUcCڅ{,Ri߾lӨ{$6CDa?d:f~.xgz %I7H;}'8C4G+\|}8!nC7!?ߏOZx%,v ńw½W cbZCC[be=Ѕ>yit6 ;'Ylune|4d/64N-z /Gqvehr"ᒟ|boSn1Kf#I}@#Rle EC1~'fy𤤴 ~~7|ѿ!^z yNUFգbWXEnVR18Ioh{McXհˇ7Գڹq+nGky2!.CbIE# 6K-6.:Ê]&msvˤ" 5jV53yE.4ҿ(^I3nI\~^lִR5(((G}\deey(8HtѐZVl-,Zہ:tgRU.W_vGwXПv!U.o+_=26&݉O|,Xnٲ_|ǓW1[q}&)7&|#ծuJߖ=/J;~xO RKrk|/~KeAu)um~2۹mIM?ݺhv[s}?Zz7}WɁ?=L|?\m ~ڠ5hJ'JT^Mx/+2K~2[fmU&Mxck׮>UigKhyF&>I,Q%`8z6lL5U5tzΗSP_սUy:%I8~j =]Ek核 4ʬ|D'8'|i'GS ǗӇ.&Rp=Hh{$?gͰ!w$NH':In~O%}{L}5&M~6:_7RNOf>XN`9{aڗT1g 8sQpWVX-y͗H* Ν;{uĨ_G7{bնm[m"us*,5N 9449/Lmv&@/ًt-X`:7,"≠7?!6)(JM'lݒKkb6{lVfӥ{/){xQk/= ʂB: o|OO{WRW 'oLYYY,Vs ?-;Gu# ƍ1X+5[̌/sJ #|pIJ>|@xeeyhܾ wlJۂ loV>;Xˌ"_BˆRח-ҡX`qm[g߃v{+is)K&+.BK.K)"`2)t6c"Ƈ:#cʿ >!ݹjeI (YLO|ۃJD$J ߈i&OD=m &| ,߸18Z=L't{H=~ūY~>ƷNkU%| _3t>֢E ﵔˊ$n'[~%Nbq%vVb6Uuocn".uGt /WdtɎ~{|l_aA^ת5[}{tA/|b7'q,u,Wo^轕^:y<ɾ' >O\V=q:V,/|>ˇ?'ѣH/TZb+]%bKJWpq79ձɄ"$:?;>͛ှpDvزwl!9_d'z~O(du~$cqX<1NUEAuN>96~TLJ|*fWM[~C/U&KtIF>q%h'H7Iy鲰>YٶwL܌QDSY;2hwv7ԎUj i'u+%g #`0F@ V]5 Outc]1 3Kܖ0F#茠9t]Ut cun0F#`Zs:hFOTt .;%Y $^4F#`@ UVz"H]ݶ$^*]z]Iܶ$\$m&}V#`0F _~]VAC9miǝ߷\$ȿk7W]_[i0Ft⋅#p$KED1xDL8(uhXf_OMo8rXxGsƆx ;S|IEDmM)W%B36o @+ ]~>pɘ1o'&ku 93tޜ7FCrzǭ@+ @+ <?#W);P"}mp6G#]op^ɾܫVhZV_?>*!g+9ɳ<5Z{_`yy3Cϯ}m@+ @+ `駟c+Y™D,b\ZWNt˯4+kg/;nZVhZoLb$`@嬡2Ps:tn7*f̛0fJ.C- ZVhZoY_~.ƫ3+Fmu6gC/2tᕥkM#&F E @+ ߨ > Xu"d[f3 w8w액+ `^+^v @+ ߀ \+^pppnl%Ő-&>9s<\?9Nͷ@+ @+T<u-9>/s1ߋ 9_؄AM1rnJ9?}b(3V=g5%yWU5VU7Vj_3I|qXMr0|n~[7}3zފ_a6axp046{3]X{[x의o3.O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 O?p3 _ ^ N|;XeOLSǬm\;ވfb+'?'FILl' @ŎxݵW'㝱'u^͞w:ʞ]{5{2({2^wxgxݵW'㝱'u^͞w:ʞ]{5{2({2^wxgxݵW'㝱'u^͞w:ʞ]{5{2({2^wmUy1dz˜!+s!O0[e{[vuMh:g_eGh#<\eOƕ9LsViIDATfq2ns)ϯJz>Y_,6n7\kzЃc䘸ZU[jOud4|n!(o\׵/X1/cC8c]gxr2/CseO??y:?犁csQ3˷vs9~f:U?oy^FLO WR<׋ȫ^<qel0%EM1=K7B^=}` MEy?\Zba?w?JlV"L0Fyӷ(YՊb0ZOfU+jmW>}U+ Q^1?JlV"3jnNs1sze81y5_}yublB0Fi=ubx.7pLdݽ_.5ĒKK,Ժ3g%\j}~ȳK.>?}~LY|`%Ę}|>crp3\y|Vk7耙WsSB^ԍrS~zx֌s"8xbmsQ.B]uԻG??Ql0j^EkL0Uc0.ȚQ<#[ߠf1s;˫t7ٔX 3[3J7KK2uJ.kcI,&_,3w5\:Ļ@4ix7W u?q\X Fl>֭g|ǭ%Ͻ`o+3=S;ܡr/pҋYng䭧'׋&O+ou~~Y?#G}~/LoL&气xvV~5s g{cxqrc<߲t `bE?5$}y9hϺgzc֧7s# aϪ;{bYaǮ=qGqFvڳwhaǮ=qGqFvڳwhaǮ=qGqj^`46z>15T{bp_w.67/?bnI\0{}O,\z7΅ϥe,8ɯq~}~Sq=租~~?/M#_L5s̍\c'V9]`v؛#G0vb׳ e0z|{ܓcj&>5v%Mo?oW΍>?}~P~~VS^73/b>YC sm_a-;jաpk 70߂%ܵn@E1F=/D׺by9r租3Jwy~OL1X^ԜGK.ro#?cxƧaHK7e5ޤ :f{]y`^l[b/_ծpgnFZo 4ZZVgdUm'f3(f^N<{O[ò?O^m8WC$ɛ!fѲw(b9 8>1{^X'Ƚ@kcvZ]?ݧwKi/F;D%*`C^ܾm}q|}?k-㳡s!ܰC1FB}Czp^ȩsqa5*7[VhZV)0 xꙋg=k3'&6? l›azbxs}0cjp;'^^=Xjݿv[/WP>?}~^}jv>߲-ggx89'nKm[{_ؼ䊑c9,g<^irsYs_;|Kqx?b`m@+ @++罞 s~g &.\>3fOr.5gXաF6&S#7c-q#=}1rKl AGQ5p֤hZVh<s9ws{c<|,1Fuf仞[yo-8:t͖&r!} < dl &> k8|O~aַlN=' k`*fe,sbLeϹ_n'&K?180+Fu<1 zя3#Ӄk9<1Y[qVXi~ ȪO{~x31X<z3_7Zӵs1Z4g⊑{&\+1$>ligu*^52voξbE@ brUϛ15֪5,3`Tl]zY徊Z'v{4k#jjݿ)hUkZ?XUO>?sWM3~VxX]bwҕQ*'sMlψFn ![.jd<VU͵VU7Vj_3gk85Ym>9zQ&V<5L* WQ;JP2׏0k&܌g r=kp3ުPH[qVXi~ Ȫϗ8?Iyq5c׬.G?78FȈXy7NƠuKZn~;F U۫rj-Ygx?3F֯=23z2a_Yr!WZV u,R^,>emWL|qƵkjֻ,oZ|~K>y~e>3XG>U\kOUnM㛩8Bmr9WW~+_ʯy׼k^5W~+_ʯy׼k^5W~+_ʯy׼k^5W~+_ʯy׼k^5W~+_ʯy׼k^5W~+_ʯy׼k^5W~+_ʯy׼k^5W~+OG|].O=֭bFucwR}9@?&6Y+^ngL]br=gmjqϞgO|d|g={2~'>ٓ3=YϞzdlgOg}ֳ'cg>{2>볞=[?ٓYϞgO|d|g={2~'>ٓ3=YUyUծb5[fa6ap5y;hhVZsVoy[яי220g=ԯ7ʚ+λr+ @+ | ;0 G_ 8WR+k&VhZVX :\)[J+{7n_q+ @+ | J}hK_9|ޟI&@+ SsK8|{zKnjZVhZTdax+ @+ |!jZVhZVhZVhZVhZVhZVhZVhZVhZVhn g&IENDB`testng-6.9.12/pictures/suites.png0000644000175000017500000050201312732165123016302 0ustar eugeneeugenePNG  IHDR iCCPICC ProfileHWXS[R -)7Az;FHB ˢkAł+ (DTu7I];Μs? o2QyH/f|B"(@xFD(ce@usqWQps 'srYWg y:^ov@A, 8U58Y-%6ё@XTTGN%C b7vqē!Bl]ԿLbci.!rg9deЅ&  V,Ɛ;O X <^雷bFٹްf=pX>Z QF(f % Fdavh|42ge7p ss}lRx~Õ/HD[yaAܑ< ;lF(sև]/RjfYYT!Kb1cFapuyE 2#Frnؑ1kypI=NgEHcCh)7!& A:_?B |T3'g(B~^Q.ȇ/ZHF%)Y:!5;1f%}D?86d .\ ,oO DŽ.] HZ- BA7]27fBv C8W-wA EܾĬgT/g*g7"yx[q`%;bgKX#VkNJx"Y cEJe81>5@(y ;'O!sԴ<'"s|$!n#t9M8Ae7KO}齁k:"aT!wzd hfª,z6BP ցM` *punpm` aAH #j6b!ֈ#"!H$$!!eH1RlCv#ȯI,r D"Hb(UF5QCt2zh4:MEst9݂VZ,zv/A `1G L-ĊR;5w}8L<g9B|5 k:ލ_ 4L$R R> ywz CD"A4":@L'#& &6;=AF2#I,RtttK@%k~D2\JO>MF~FQ1q ̕Y+WAL0EbDqDS)K([(()(oeeeueddn="{Q[#UjJNk&][fH%hkhմsGrt9 @9"2Zkre =gȗ*߯ `RXPpR "]J1\1Kq~KϕHJJJJ{)1ݛΦ/寧*ӕ*+(تĪQ)S9@F&c-( VM84ڄU=TEUo~RceWS{OU^~^DENjjDjأѦ1)ܪyN_塕QV6]MQ ӓlahtv .=P稗QYo@_[?T~=G4 W>7R5 4*01z`L3v710aB4q40aaڙ^5Cxf;:'&9MOtۜjio^cmXjQgj'Njigi򾕒UR7֦l264?E66mlwvv+; 9;$9lwiSGg{<dwy>h w)=,ݮ]nL$]n]:, z}E?j(+zmQLs|q>q%q]_IPO%'c%NiZto01gƥ33g%?5X!).igV85=y~lq]%g))%)S]S7yxwϨɌ5[G6s􋏥J| z56Uqza߀f pzJ1,'.gdSkP d 811.pcWG$F!ҵ[\h|ث1MwȎIB@@ 0*{r1(BEH{ pF%(m1m?D`߸iQIBBmi.4rlM̙38ybppF(Gν'$cZn4hw֟z ZE )@[JB^ďY\! DVj|IܖJn? 'IHxYSOY}O7 O sY!ءhq߼ ݏc~{(9B@ gU#TC6!-jًS\6\XV]eebtp)4RW}sˆ ;U1:ATlpn3购qrˆ '*%KQUݏKzT*'u70 }`G%^R482,N.#0Dzj7 _*֬YfˎB@@PZ> ?>F{+R2]󇚀Rq1lMC2WѼ?B1:h(KTB@<Aipl~bi5wbgZꧼV]uC2X Jkҡt02}1z*%M?a1c>ǎwcERdgL XqxnơV7817wt&L+z ׫A]Zq$[|F!:!|XZ 6gInn(2[-AHg>tPW,Ɩ+`sAǏOV DZrRqB7 fPX5]C`TA{M<_7.,~`:uRy08Hi9eEoc,I aUZ5N Kj18J s"0۴s4їL0/7*~w4bލTLNK1LCG'_=bލ˱HK<btp|b|D]ќlT,RO(ܯO7.y|FG1?[pFC l\鲽 W#J ߃)}8S67۫:~4e-zftdf%[ZVz=qr<Ó>C)ʳRVnt)j=E{op(?go{F<-^h _]w~rǧ~]oほcW⓿k{Գ/f'n[j UGi|ӣcߞLuG*9 ߠJ&G{ӆ?r[a񃧞Bs|آ4܋_.vB5B}/oP5a6TźgPy=u#~ÀpCarNV焏{[3#:Պ>q%p*ZBG*,-CølLK{-hjMoΒ,֯^a<?!г =ڽ#4\skvKIJ<VNƸ~Z1"oNC>W D2w>O_89`HB"3$<|2ju1fZ:$%{ g_ -OGߊ3lPL+D$`Yw^Өit80ˤ9_ gI DS6LUXO>fWW};J ]?[b"evR%tL jR-H̸[؀G[:񙥦#;a8zzC""h+44z ͼUaw &7}"== ?y5%;>-7Fm$U0iL(,Kt2~u]+[sϕ ! zY*[;v~Δ+m9' Կ@gǐDH`}s5 UQmg'1vZCϳ uZ=tWS\`m7$ЃzB;xqHysDԛ?UGLFJp,A*T!S.a\'P#?;^ofWN9e/L+N2Pډ_ݎzWѾ3cyFz|O8wF%Rů nV鷌Cz+8>VFoߎS5.Y#%gӔVRj"tΓXց|$GjiCz+44vv{i/Ņ>5pHX,JOok˰G[&c fHQǔ_=x#G9Jt؉^ujr棨2{΂1~;ί%- n;1I_G3B@N6<0|܄N5`.3H0+8JC6qSٿc^gޛ=˱L| \NU1q%i+H=I0QFoKXvG Kqݕͽqe6:FA߱?4> 54.rC\*5_V4x1RGURhҬ!U54dwbEEEV\) ~o3㶐~GVV9Ho{=^:-/1Vdt(q(gF].$N}qV=@3T}G >|}(dh ٘ I\n5(9VdnlwF?o^3m38g2ƣ#LNr7ᇾ\w $ i cKH[#^:sRflA^ Q1VspV-o0PmN<5M\7w&op&=SYq+&Û[#E".o4-^ "ZglRKfm`sTC= (2$%Ze?`CBoK(2jht&&'M ЇUbÃ'x)N;VWdl"[@$PCR,|g,àpΩZknU 35ۙgxMr(z߿܁!ɔ9!LVzDϻe^Ô >qug3vA\ A(mjRWG4-g$z?и7p}l%}Sb1$/=ef4MoT7;UPv-(aM׳ ܰ)SݦaflMh4NZ..a4^ QV5~21O-{ uUoDZ8B@b7<(wߋS5UT"׆hWJw)9KJ3Ftyg7Ɗ+ ET=U*tAgϞŰa^eufnw'hn "17EG[EO6R0GeNsIS@%`( *m,YPk;W9&,B,qè4gT~(RQUvSuJjz<o8ZʴcTpٓ1 <%oZl;`4kZq3EyZCz%5HK1U}~jtUtյp( \o?6Fv+N} OG1k~>^3d5 ~psr`!u{}1S+[pl?~'iBavj,eywxn.VEYb{h^0pߍYUW8ygECEal~Nk .(B@JAi7O*Z ;A|b_m5s)S2iW78tpjh!Yg5sWi򯪪R\ݤJ;[@$t>}n`# ,˥;osX_7_T4|8 }np-oN}`YtPM.z&)3j0rpB@,q#?)?{ Wި {F^o0R] k}_R?%W;u2Q_<şZM<[Rr_K.6R|&HQTAm Nw#{K^Y?9":]wPRQks 3np(# \1[WWx6nOpMsvB?۟iYǐ4/ki}8w"WL?PGH1FԔQ+=%>LtoϹ^==9@%~2X:GCt "Έ>T+V?s G-rfDmKVrxf+^̙31FuKtWL68]ȉ }[h #?C'k~)S?){JK KxeZAMv7uǥO4&&GETnK.(w?Br4 &E;iڄƦa5לu3ir#SFM 8B3&}8ZͺO9/p=5 EN$Vv2[v^o|PLJ #@-|X{K ӈvīXz']/+sgo_ ZŦ}ZhʅVEo}>x\$ʁBg/>A4$;B@JBF yASVUcǡKvT $M _ fd w)sL*}hjL'†JW pu|x~/“EZ-.:hƫ+U\ &UWUWW+F\|b-9"-ȌA"F! B@A_7]lA t}v(uڸ$Dgv 4]u_06:BHMMǂP-KXn9C! B@! D@kc j8uuDThf*G< &Z 4UܥC0jra! B@!Ѕ<"C1 ! Qa؍dTPZ?nύ [@:2W$2\7b1:\ȁB@! ^ c#6.VmֈŸ@u A5J@~qHK[:GZ{̷ ! B@t7QGRm]iL\Ƿi|yP Rqw<{Ud}hL8! B@! zvi CKs릍&jjo2Z멌LDXhxB@! BLPرc8}4qqq0`6I>E[h]Mn)1LP UrVJޜqB@! B@t۷+PK♩k߿_jڴi5j{VǑ!.W<9\\wq B@! B@ŋoЯl`Ceƌ+9_Kp)B@! B@HumtųqYFw;1< HB@! Bn8uꔏOq\N B@! BJw8p@(ʸ,euã;KB@! B sŃ>7nfΜxUYbzr{#H,4V׈pdx9[+QZr5axx e"=15hVj %1[QZTzbdcD:ΎRIDLr223ZAvB@! O.1 $&%`o'A#7bpff!2/z);B@! B;^UTT_TTѿq*O8W_}l;O2tq4ʙ)9:=.k-D;,@ͅeH:6=]y?0g^gc\CG:l,tJ4]! B@!/UVV[:x@6>͛g%%%ظqGey)`RÌ!qhvrh*yrbX`JTR6oތC lZG'7vT4ؔyh%Hk@bkQ-;6cCM"uē\B@! +{:|444 *Jϋnذr|N0zl{x ɰd"8qUYc(-+?jf?Jc4Z)+va͂H$sȕ֑( sH=ZM剏B@! (AFJqY+g~0)Uo~ V*ݣQ6B9Aj W|MqȹJ4ؽ h`yzs=! B@!(VuW_}2l V疎}">>^/{]ev݆ǐTg˅`PLX5Z KtV :#3n5= wȝ3caа$xu@w9rF! B@&py$nЍ/ٳʘ^Co,\6|] FVE<B@! 'iӦDhjj+׻z 6>֮][^ƖerݗrrvH7A \M e!:<I?{g&c,\.?saTNjC蝧dx karh>Vwzi{izm{X!B@! ZPV'wohYFw38:ن:͎Q< 1/`\pw)QcJ] d#%d@hXnHO1 2/F+)iةU|:fSdyVL'B@! C?]{yL?ݫZ~w> M:O.Yn;iQ+ $7MsE)+FG-"B@!pi`C+DQQ;ӧOC::<jη2o>rV! B hu &6t|Ej*:ƅ~TRGP FI+e k+++X$[aAf|’B@! pfjqv\T):'#rfx$D8BUs-8N3R__LU]mٯ懮lB@! <<+O㱹{)v!Hm \4Ã׎Fj9~ź*)B@! B@t6 ی}`A\M7[$x3e+B@! @QdxD8 \Kyj\P"]! B@C1\ W&DVUևBXB؃'B@! @Kc@^E-܋3\șgoΘ4 2>Ҡz{(l ^^eW! B@oh\G41O3dQ:ЕHzZ4 =tu4B@! ]F ԥɩ I )U qƜμ=! B@! @ǥSW\SIC! B@\oɾB@!  bxteIC! B@\oɾB@!  bxteIC! B@\oɾB@!  bxteIC! B@\oɾB@!  `QqQW/i! B@!DYò()JZ<,dO! B@N"i-&Lwe+B@! @N>Wrp>Թq8EXVſ`yJGH! B@! )k'jkkQRR'Oٳhlll+( Bff&\ˁB@! O[ SNСCJSRzz:,MI\qW_cƌAZZZ B@! 0t- 68"""X;>iڎGY1ZRSSÃeJˇ;09B2&`dPymE~eoW@K$ !p 1ܽ G1mbb5~z=`Y,e_H{Jo׿{k,݆sbّ۞|s.bu@]{3Y~{uB%_W1^zs͜97]p$P3 waO-FDܻ/t̢.K&aq޳Dfϕq;򈎧 Mۀ,z?kCSdz;ˌwɚu :(wGgv7U6J̝@IDAT[Ydue{97r;Ttm7_x9+muqŲs8\vlEDM3U>~S{kͱ91슼꾭ıngً70>E? _3߱%Sԟ}X ry&~Mh֝*˙2tڽl8W%\{e[5"w|?c\RSOWzҥFӐ>1J֪;Zr` |_ܜ$Xк/hME@SWj87 w<%5sGbB'y\̟57S-JxWE{_=}>_49ܰD.P$kF)PDXYtM3EGo].<\θ7:Mj9[a)'yZ8>W]sl}K slW9)!؉yR<{Ď-31{z#\^7^es'p~ ,{8p 8@BvQ~O̐(O˅#% SRS9b`@|S}Μx{XǰURGC)P%c KX&gʩœjeNL{lܩ?so|۹ W˰)FyHYY $ S90[p2~aOE#)u$nG)w^uCzMMwWh,k >9vT4@.ؼ`4yx9XC4m!l2[,3/9ЗKMYuqWbVj+~ݶsX[;g8gS<7哼Xf3 %X_$Oϟz_?glsc ̌@֟v蚌[0ׄqف 5Y8)㣥3F}5EP;-j'1\l-cfz" #Z{X]7o![6-ny8n":ldu>{-iy#ynv=@'t^4f S(+}_Qu69ueibڃ~7]z(CnY:*v[$׉ƷOǛ6 dT<㵥[uVNB[;Z*8|At$n"a6f,2>4(?ѾX#]X`*K R o݊2cgbVuKTn޾qt24uKՃӡg8KإlyxeZ.js0 Ze,)5Zv|G&[#x 3c>k\Me^7 !}xcYΚ!Q νltV!h= 2.$4 ^yӘ9_NJ*ÜNn SpP1آ<%xS%3G2E_`}jǩ'>']bzKrsre5>"QKЂ3` v%ϙkgvC*'>S[r{t^ݍ7nGVceXFicpib׺#bk[r/R*H∙XS;wK'OzߥG=jHs֮uvkA5+s1b,Ykr@Dg5wՃ>?-ƂcO_B_ɖo_ZtaVXmF-0LC%UA0cV8,^\42#F[uu)nڡ?B\35y`4h9Xb0n֐GpS2à]FY١ꮗsК0]PU6*%d_A4 4A=ϱQF!Ev<\2]`=ˬJ[Wmig/Bxq[s d1a7Qw.ˋ{Sʧ s#WSBjKHK#8Mx:_So~IS 4eÀ[ᩭ&TFqv,|lЛ8ن)j|dx-uǃZ̞lՍRT]v*@5P}[ˡM0]siOc:fOu4edsiPWPCf ]o_ڊh)+g!K3^ Xarfs|,d./S|?\{'!\I<QPZK356jVj 2R-3CnJdxJRm,sCyGmX;R`vrjxzrOy}n-|"Q= S0h]Yy/c6g~猴TFj0&_D"q'5OQ!7>¹"~𧭋w^-ƺ%QA %A@\9 F&C0wVx}z+o3vUIz4/`>x:럧^rc*ͦex>hǾv\o[غuIVy+U%a!Ij5s^} COe3)`;v;$'k%Vq@'uG+%whcF$/? K]'ek8>g`7Ie#T;p$=z0Z5̮08;{,CYP[4/ms.ʪ?s0]uL%-i[++ ݺ ״jSts}N9;T9b>dܯ:gXu4#upr$ xz.Sݢ~A M*>c,KE7g)3='yTOfiC/<+p.j'4cV^7:pmeZE~Ak8YYZ3:؊gs;X}D:}SH{^B̡PA3.߽qvKĒסSBGL^X@˧<Om/xS5܅_<[]pRh\Oǚ} s}L >'(5& pJk,iͼr;}?|wZwp m^) K .7N6b_>`ǂjl1[f=KA :zO6Mm"ܒdV>aVj"ZZ}J~7ng Bx#n?[ ZMۥ9;%CL5xD-ѕXMʇiSUZ@iG~o7 +okYϢPg\[aᑝ6P]O q1ف^5觍h6:\__hř#vv`. ynB|sO&̉ ~eN6rO,GYmq`k]Vzõߝ?~v*42?ޑy 4/l?rKKtNJJ~^;"&8N=?sCL@ rgb2>[xDScZ2ZrJvZ=בES;/MU|Y젶\L{H7#[O\̓6͞ XGtn J~gRX#Z+W1 .p5 f+i'6kҨ\Y1erH`!eĈ* n5 57:M`m+1'F#[Y noT=M{7PL3# #?jj(rIUnQLԾO K4."a~n*Iߊ3#s3줴mDiJ9?n3gWo9(|ǚQ@(&.=X<_5zԥ|% DV@D?ep5Ai .V_kg[JݿҘu}!p謕 -m6eD^11Xe,=brm̋ERεpWuIbˊt{9(%yV6Ϊ; \ceSZ"jG09n+L/s]Wm\u}h5wOfV*)<5a zҪF:p8:Mq/l*orνhE97ev6}ߏ?wsE~JoC\N9o= ~J'3O[6_;KAd\L[I[H#sdHEϙ2*gx%Q6ΰҋwYp[pi+sCJ FYj3EkSV8ʴ3ʷJwӹp*-{=@[+j91Zz<}r}{ɯ\@nZҢL7b8u5(Fhb>*&<Ƙ6!\tK5e6}+hjRw7e*(kLeJM>Ku"wqq/yh+= F\شOKxGڣXHY2Xa)e=׺/ t"=@)n@׌O;|MϽ{k*7lS8A[wŤoMԬAemS NsKk-p@1ֹzQ-S[ޜ9XY2tm-B eyb4ֿ{y~.C~N"zZ Tn 3IRr6{8Ѥ@[YyH$/msQOax9t(6h7;%eV7*m~X2NK_8SK7W`oGWo6 d33YFzb<T3fҢ.&̈́WsN7M]` D!]a4ՠ&,57$#kf'>V0ےqrԕyТ(Qt []CSv۾7܄u-"σm8Փn<㰞W4^׻SֈIlғVWӽM]$ ھsܾy?z:){`V^ڼ*pOJ3a1 u擊 =95Ϯ;2t혻 B - .$pio߾ʖcw}nq8 (oFx]aalg]4؉奧(//[͆; sO ;βl6"S@4na-$,ч6jpn;HxW'`u=m՟z,tMЖx[`ܬ, ,366VZ>:G!Ԛ *oﱗ XB nݫx@>}!))I&&&*[nqXb,pF,{wo׿Gze#5(zX ł_o#g#=(]-ѳ ndA, Gtt8R\A\ 1O׃|99p%pY״(wm+:+9&mGEEﯴL𸌸8z1F+- p\?ɲ{hbr;vTrhEuu5&7}owV <[aeR]kwB Vb(YPX}_.fsj|Y#5Jliv^ 3m-ށc(wm<U;/ΩƴOlG55+ YWOFԑAW֝Y^56Nםu_VfoӻBw )/\Τ3ΎTwͰda4Qiw}oGQy(a CVxщddQcF3}[;O^G72My^z'Xe/d^} 993/Ɠ׍]h eV]djt嵵s_В x1ޮ;хx憂4@JcDNG8xa=/7 n$Ze̻dFo=}b ?cmRqCtqy)?\fLrS2AY#Lfz Y)Ct#ذ\tTS j7xcŕ'2,!#Nˌ1t1RUwx˞K_{ep5-l.p&;bf -sr&t]z`>eT`)Ҍj*͆lPSM^( 6Gڰ!i"T{L˛X<1xXGNP.4tDp||իASߓ6`<m[,/ofټE0wY9V`T[:͕n0ڵ2(Ki.}.)ZzVU"rn*.ǮRRQ>=$|Srr]+݄CG;kCQ o iJ.6Dή4jb(_Z&j {L/dqYj)JB'|l\WhifJZzJjq*EFO#[)ynSj%M>ȯ茥#GiMQ{FfcgM}}[3-'t 3D2gu:w5 B2dɎhzX]~^~]3=5c0"_.iETlϓYtK==xnw&G{ AkWCOmXf=4 dKA.a-_O'%XB$ eҪ(~yU:O4=[Ȇ ,o:9ZF*6Г+8oυs#u/ߺ_eb"@=+n%~AZr6} ﱲ.Lͱ 榼Uⵔ,L G6GUu+ I>++5_ Ӯr\aFyY'fʌd:^22=`TԢgڜ.|l\{Qm}#3Atwv#8=&\>{9zoP54`w'թ>Lx:WTh.:/~DtvvonUҶya,cƃs,p,nJx}dVsZRU}y;'^vN:;Z%= vu'gC Qm ּF:BYTGpn:rPOGڝFcva#?V"}?1Ց 9d*޶w 5cgSj\?!=Oq#)~ & pY[0 c2oZljvu(U:z E IɍsDgnT}dIz7rOgQ ~=2u \XZNƦU}{h!E?SC%ޮ>SUbgdܝKVfOcx]1vVãØձLw(7}#WɗG0X!=bO&T5V4pO~-EQQ*?ӫ9a␟5_&?.-~ R,@ b !{:*yqa_^t.))vF cxFmUtVMSgxŷh+0m ݝY ł3F]wU,\Ќ]<ؚy}:۶є\kϡb( LkaAD" #\tڨ#saV JWZ3*}L/C?>?@ŏֹd.dB ~Lr6׬/V<\"а h@JJu@˱?8PG$Awr}`;R31Eu̳uЊBr܌tD Ac e"'Άμ5uTBixacnIx'v,uK}JRݳ~3u g$3gݵH<[3^q?wnů*٥ڹ*Vo5gžA4.q!7s#Ma._]8Ц|8:qnc|0<֭Y_x!rTNiBgx=˴h-{y m=RH=9PYha2Q ~=>Gw^|lllXbsO _}@?C,9uR֌@wY\ p 5j+Wޅ ٴ@ﱃQXwkn`zp5mCy>#Q,,%%>ʪpw+CݰdiR+w1 %EI4X4D]>`qa3HY&iG^pRlhxDw>"weg~=4!l}$(;LY12[ _J[L :u]^@OE cdWß֧Iem#د> /H;x蔥&TdX$i2[q@sIho񀺒_([ذLX"KKghoeb*yE(}\_wb .{ yI s E-VF z@?zܪo^8%EɁ'F:Γ ysv퓇̓'{:.ge٪W#~v))<ZFIlb3$9C>>[>~"C{-+vSvN 54x- kQuDE(yh, >ňYsiӿ n@FN{L:IizV3;\N}`W&ۏӮU8?-vAxEW23hSt1MX_C~ZL`|eh;u1y @=()2ZSN6նn,6LxU-{aPY5h94<֭E[O-fR m6:X4=7:(l`™El1G6BE9iFjzhg$1eq[#b w0Ӝ?Bk'hJ$u[4z[ ~$dz= >Z{- +UP^btnA*w#Ց-4)3Bpy:i<@߳;wyʸS޿,ܿ]fsi,W5$q`B4yOcG>߿<ן[ތy-G*ڬh[17ξYfZK?~dV*K~B(n[݊$k56Rv=SF#p2|l썶5`G0K'Nwo6kv%O/>/zo<<^kYCM>.iaJ_SۏPZd[8m8{oSP}Vn^bڵOIF[ǎЎRty`w3Yg (+k.Z1I|K#u|<}_vFvnXK]Zz7pUw\aȧ?p 6eAad:MK͏Csh,CGU%4ZJ_z$|HɄɇf'=9sF:!(xSx܀zbzr+tzz5I!N 9ќ,Ѣx NBev¯Ƌ?mu&UNeLG{VɟF=NTu-X맶6ϊS)?EUfD?7ez2AqÕ k(\/S<%A7dc3BLj,ˌ,w\^c+?z :aZ=8r_8W}ö1)M4jό|ye_Vd$0FbWcT4&g6~7{nq5cM>:l1t ) leq}pL f߼MIDgºu/|r n9_gF%^Z4ńM3 ]ΥMS`|c$p4f5{Mȳ|m2ەx-g@k[Y1 RLut(J:aVDe$غ# ،>|6լ܃fq&={ {36Iө{q٫r=}9 鿏3b1KM6n@*g49Xt8Qu$_XKLE`۰O~ߤTӬ>>MǤBF|gpa8sq/HQqM7o,^uz0Bɑ|x㞹AZX0h_/- z7xW\;hg'(Vr @`s9_x $=4V(b0f_8ݰ^zc9vݸ{FO얙#DJbA;k62GObFDĄc{*TTLiK-8X1q,%~_8kqDc ?z^lM$5,hf .z>UxKQKWN*ė%;㏩GzC~ql|'jn՗d˷hS).*apYCxIvy칅@VtTԳ(EFcYb,`CJlx\ql C1^l$,TM8v0Y T10[2i:֠ȉwйqr6r񳌗L. K$JVQ#,QmC%@@ XTn5^Ԣ @@ hxZ y@@ )hx` @@ hxZ y@@ )hx` @@ n}|ᇘSbt:Mvʕ뮻l;@@ @@ ,j>@__tv;C=rvG}w}W:{ŝw޹Љ$@@ ,ZÃtX;[n~LX`>\j`/@.^|xd@I3:"cy>6mہ;v`۶M(\퇚1"w^y>\J08ډ()hotq5 33Sjd8|ҏMSY\PaO;]`Oh2q/q`<%^o,*[}}<,iD[ =e}U?,fN e1tΉ[;.6.^dE=mnuv*}MIw.宧a? 4X&Qڏ pZ*ss?5<5)\8Dk=8ƋTXTiF_Uyג"p+ycɿҋԣ"Er^TRoQ.>۸r0's\E<} `C ~VF^nNŌ8W~+2Lr4G$ܑ,J?< \\IK[ Jy%A#-s 3,IY9p,Qwd:WQHzvL9W&i7Q@IDAȚ<"6"@) 'Xt`YvG*q] <l}{:9܏gbGAH˾&GG1~7o;:8QbZZ&Vܕ\X rqot8^}eTvB霊hL|TSe>\%LdDTeݙUccti_A3s'sssf$3^'tAB5 Npx5Z/hOu]aoWYBE116)ʃ!i<ؔZ.3&q,^&3Jن,Ԋ!i|lXF:*e)5txep+aӪjP紹-55ZuLq߹K*F:k9GN 6qN[VHpS|8w9vVƒ9R=^A)їc_cR\]&R/G4_QF-8)@9Ө2~zwhe62iȯIF)JB'|llN߫mM  b= X8mb7)`ߦUhW[ґNW壴FNn~6{.5}5m>n^dTtҷhd>22kӍ&Riʜյ4 !o\tm';Nxc}vyãu9[t_nԌE&ÈN<=bBن%yR,6 >_v)kPzvݶMǏyc.v_&=uدe)l.Pf~Ʉ߆=?"@"(R"K⸪y+byodC7-x۷OBӹh뾾 z;~~!t1fC<깔\qc/cO`bo&a=V؅9y^ܔJҟ?N47w"83z#g%}%aU 2(4^QlRq˜\&Tc'2ٿjZL%B7"?k4*pUbd&nD]kۇ_q/. c7:Շ ^~ʛ M@GE]LJΰ9mxXgp{:EqLl'xzf) Qhݠei ɮǼm/GNl%ׂK?˂3/F1pE"'lB[ָ͚n=k1̩;b́`tAoClH0w#HH?nE Hk\0{W'H!^훱&K.o~R{P?¡/|5J/oUW*=,Vu)/oaBEaf,̡\f7ߵO;pNYp87sDYTg;j GK_M~ƍo"΅aƞۗae̤2QD=<y WpAo` q=эcm>ZRU}y{5'^vN:;WZ%= vu'gC Qm ּF:BYTGz-5l?UziO<8oDkO8,Z}bsSHDTGB( CYT;;SyD ,H=3~1⯻`E<JKY%q d%h-SסTdl'ƹPͮh7ER9gut 3Y#So.WzNAL ]_ }@wcӧ B_,S󰜣53נ4AbGz'+*e^#+xtoKOtq#?ibI^+A4ԔXlhUP Vi !kN bDd]|8l-v;#QgP.4 HƉa3hM*cwPtؘ[Ɖ(KE`fGtl*r_La]AcAIodLYw- flV،L:eQ}KICMkWV]-bC!渉# <΍87guTCЃĹSتOqZXXf⅄Q6; ,l}짷x^BW)ȟJ=_g#b4Ng凍2D]H&Xdi $?MTf+Tq=\"cns< Mcm?PW}ucek KUDwm= AX%hRM^>;b${9?KN=FPPn7/qaZaCQ慅X9樓= 3lի|?;\_{r#$1Pwǃ!ǃm|{c 4-x"':]Wq`Ǐ1Ya8J @`I! kӧhV;. :-BɓDcL85-F4Ϛ{շLMp{22hwVgjcLIJӳzܑ-r2 c2~vjQD(Em1+zjm/t@⥋iĂ:0_b[e+[D9&cڮ&ܣӦhO:Wۺ0᭎V9AUg\/XBo=hHQh`4` 蠰>1 gq>Ξ&BMs\X MڧOd.Oh%Ͳsv NvKv|v$Xz*p.OS.bߚ]ʎPe4/4Ё~t 0JnڰUOB@`i" jPos=hwWQCyig oܕjWG޷Фi¡*#~Ԟb)N{pvicqViDā?T u"?9#~ +^No{3_O%^~=䏦 hBo8f9 vh HE*YL.9 FmBVc!enc8ui@0ohz!SXh[?|tJp7*faz["#‹/`NgF5d*>ڻ)}N]l?BinqMFB1Z} y1Bj>&}o ;B;J ߃4Fg (+k.Z1I|K#u|<}_vFvnXK]Zz7pUw\aȧJ~?-mUYcppcޭ}+a|@ƚ| NI\j~jNGc6>*R ' @N&TO>48QztDvbbN]dqɵt)CQ'ᆤ;q.DP^2ߎ-ʈh-Th'jr'jىaJ4t5+*;Twҏ%~jS0h9S$[eFsc]'=\0_:[St#L66C.tJr8:ѹ(aϊkr?%8m |SN.Oh1W:l[>/ٴOsʗ7_vZeEfN sn$q=FH`Yzi]Kpn1Y, 6cŶI!`# :΅1pSAUVAO}fxAKe͆z(l ]d鲳iM?׿JV0w<(Dq%׫)ӞB*&-S۞6;M}˞ikpW\ވޱnpk;JjXNOKXYT >6TɋptzMdeFhH$]ӏ-Z2}iͭ !mOqmѳØYweýT]uvАIk>O hr @T5pսM੕G.Ԟ|+subztZ[KGXAyk NQT[Pm3q 㯦jWm#'aʼ>H:n>9 D/j5dUT&B9w3Vq,-L%)vq[xYFٯ~ăqjJ+ d b s2 9QN/6l/TfF7>8k#zM95 Mˢ[?>L@\JO 8nb#}¼CCzȐ>#[_p-}ho6n6k!;#/;tp1~jh? qBzQESL4\4G0FG:HCQLgSa$,:`5<!"}v'v,@Y)-gVBlNeQF,nH6!M5+`kI^ތMtiE3DATH}0㌡^jѮ~tfOP$av8GJ-N>F0i"V^b/K߆}&fl:&=wG|1r=dFk`= &ÜP Ù{@"0>>n ~te`{To+ȋDc̱;ZbbK F7+Wى5<5&ڞPŦٴORC82fPS4{ɪht%D@`"h L|K_;#?z>F9X+Gx2ީF_}I|< 50moܟg̞[(nL l `ElaHE=aRdD 0F`L+VH[ʲ 6ĆwȅFJ0FNRjK<߄k8oŠMu%c *z𝏜xl}/g#w?xBJXѹTOd,QH >E`x,QIgw8̭^N-g~|Gxw^y HB @@ 53UVI _@!d]4d! .YP`@E[WC^^-[&5/_.]Nte f?Fx0^'}C,},;}I;_R`.0l# (={Q'rӇwoNGcbK) i8rz8mux22v ά=\"N\ef}t8'giT)rM~HXid˸Ř!Q?e<؏dSq(-0y>.7~|>,Z{jfsYޥCR}Tw~ iQhikCKaLZ0rm~_hQ{=VL~>T]R: z`~fUg}8^d,Ǧm;cl۶ P3R  h=Tܯ5qBvrrr)52nfǦYY,.k0^'.0'4HyYjn8lQop7EI~-߾>w|H4]~ѭڇ„\JEC3'Y\{:WAUudfdgg/"`V̞ƶt7:;S>ܦ炻 rӰ~W,IcFii&/l8v-O[K3BpDk=GFx?Rʢ#ZR2}$V_\EQ+l?/*L7([fm\ssH:WQ `_5 , (0a^\Ձ>tD:{ӣq i5[gEڪͨ[TQ (څ5bD4:Ty/Ɠ񞟛ŕ_a|a*Y9N 1:4琹zryA^ܜ(xCqWd:Z/៙{ԧi:I#Y~x+<  ']<:K#GZ !gj+}Y#r$Yy*ɘuO3v-sL2ӐMy˅DlE6YSNhlbVU5y*tr]2P=Yב}Lb5*o{ vt?ёq\#iXqW>rb%y [xqfePI٪ϋs*1#$QMB"px3}udPugWui.DaėPl{](sJ 3)c,x3,bh&=]JPZ*AJASm[:z7rjB/uP/c_Tџ3]`zަYd?bW+D.$LzfӷQ^=Qố_A3s'sssf$3^'tA*П*;:kk5?窿%?=,wb]eAwJ i~Lj*&_q4{*U_nH[ eHʘw^z@~ۤ*և`S~k̘BM>jCDWVl*Ti:H`SYd]*o:}4 MBGNǃi@O>~~iP+A+sG^^d?=msѦZr_jƚQsíSMj0CJhqXԵ2%KǑ] ʬUbu2 nr@l㜶r"wxp|r:ף}{B%WFy95WW !gkCQ o iJ.6Dή4jb(_Z&j {L/iFlʅIn$)4Cm++5_ Ӯr\aFy i[~bf̨L6WD( crPdg0 j3mNH>6lҨU iCwg7Ch_ɵï1MFT&z+o*4aaS 7tvnMUXƺXYDŜLŋ4NHB(K@NHv=m{9Ms׉-vPZPrIYzFE(`^u7fØHԡ ]V5nTL# E #w'^y̵n0m5nՑn4z%zu4rn=|" Zצkfw8Ɔ000J\P8%/FB<-Bu)/oaBEa$f,̡\f7ߵO;pNYp87sADYTg;jGK_M~ƍo"΅aƞۗae̤2QD=<y W f`_GٓH>6U*]]G6*@ʼnN1VIF&~zPT[ßp5i.Zj'~M+˞xp܄О0qLۧ8a0PXx7o;ȩpp`CI5.˟^rDb<[zfb_wc䋂 آH[p)k@^c1%HÒ &D%h-kvu(Uz EqT,ڍ*גR9ʧuJ~=D,D@3g/KZ-6rqZDnAPt7?}ʳ*T쌌zɪ#/2I` +Fjcxts4:6F]8砅b+g^߄jsϣ(*[gz"_[էpC~Sf|`kh2ԺK Ƴ4hQi6$D75?c}^X`U}(Smt J/"+봉u 4HGtQ]d-25\g<'U9cQ/.Mx1:'dfj~\C 1=c۸//f:t;B|׆1"weg~= 4!l}$(;LY12[ _J[L :u]^@OE cdWßAa֧Iem#د> /H;xa|0I~$eVܩ z<&GE|y|=~<ll<*6,F&z[XJ{ѤΛ³Xeo#o{3yN(ҨSG/5<"ԟ[ D(9dhtX8}yryaa=/Vtή}dBL,[jvώ>e:C?_z$]>``r^GX,ÅF&MK&iضh p<=fLuVq+X\AӧhAU;. :-BɓDcL85-F4Ϛ{շLMp{22hwVgjcLIJӳzܑ-r2 c2~vjQD(Em1+zjm/t@⥋iĂ:0_b[e+[D9&cڮ&ܣӦhO:Wۺ0᭎V9AUg\/XBo=hHQh`4` 蠰>1 gq>Ξ&BMs\X MڧOd.Oh%Ͳsv NvKv|v$Xz*p.OS.bߚ]nMe4/4x" +>g2cnUOB@>bFϹЂRl]E%F7TrW1^y#}.:~NЁ>,NU,F2/ o>nFMTCP>+rh?Qǰ2h7Et^Gуl6+$Z{af9 vh gHE*YL.9 ʼF-ڻ)}N]l?BinqMFB1Z} y1Bj>&}o ;B;J ߃4Fg (+k.Z1I|K#u|<}_vFvnXK]Zz7pUw\aȧJ~?-mUYcppcޭ}+ao" ԣ&?khdRK͏C;h,zEWk)^}D@ ::P=X3gH'$/v"POlVON =WRrVOF? 7$݉s!'v IǎJF<'F0Nr{Srg]Ŝ슿?z@;!]vt@;acɯv ?+ZNVX2AW&LpKbkyJnimml4]Q^qtsQÞ'])>n,aG<:A'L\Zl_.ծ(Gϋs6Ӝê=3͗VY𢳓œeG\AQ=8xc(uR{%Q6͞pZ;/C$ 6cŶI!`B oOC馂4sC=3' z4ǔhvۤdοxaf ɂ'eggӮ~~a<x\QQ t5щJlWcS^A=uULZ=mvP#=9[I֤᮸c3~wԠ2r/Rҩ0}t7m੒*ɴ(Nrq9:.Z5H[,eҚ[uB۔*3g%u2)3.{A3=2|,b}C}k4 r{. S+O]=ًWĨx鰵* ?׃pw; N$&$%DA*dhg$'_M=ծGN[ly}fca'/1u.ݦ}r^j\ɸ tIEi1ځ.s1oGNRTbwy=.աl.̎7 1mk^G<YfTAIѭ9H(,ŞDT[\YR%:W96phv:-gnMV|6bSNL7d<4<$}衇  ᣏ>ºu/|r n9_gF%^Z4ńM3 ]ΥMS`|c$p45ʹ!z6F"Ϣs< V"ҷ)?oW~aemqf(dJ1yС(TYehbF$`3zTr暹Ʃ%$MjZd=C4YD C1&Hi_nN'i3Ym֡hZ ÉLj&pXKLE`۰O~ߤTӬ>>MǤ)F|gpa8sq/HQqM7o,^uz0BC|x96‚}GKL b|iHУ\r A;;G8@c;xIbŋ^ j@,b b0f_x!aҽµusq7si#ٕ8-3uɟ ڑ\92}K7""&أU20bN[hY:$c)Yǖ'RmO(bSl'!gG3kptRs]厂dUXv"@@ TXGff&/wL=ԃLlÎcO`<Ts$\E[lJyHuS Kʶ[3f-7&O6s600E)2"#h &Ί+-eHRb;lŽc#%lb#'`]oտ5ηbЦْIӱg=GN#{/N$!@@ XE`llĂ58؉rcj|Fs}tU/~Q|H?@@ h2._IɃ[,B0@@ ``ӫX!//˖-˗/NSQJa</Ɠ!\`>侤/)0^6S͎A޽i9gqCػʣ1yLld%Tܔ49=X :iHo]OpqbgV̞b.'2vQ\:ߍn? ÓFY4Mܳb8TF`; .nc4FAX`?ƓNyơ atheEx.IqS+E殎 -=`F33 hkkȵ}qZt?EZ  s>ZA[<2zSu H$sMT{<;m&CNH/D#QOYĸqXǵkאLp8p7K?6OgqYCb<Tw?AĽRs&L~@4m'?pnIcN\gݦv+y]q%.VZ%٭!@8UoRCc'_leq˰ l1$832&={gfHϑf=H`_2@IDATy{{,Qp7EI?^o[3>$j.?xCa_O5̯RG 5AkOx\s< 2Zl]#3[d]=\#Y=0{,NU,p2]O~|I[ƌh!0K;ye6Ikx)Ql-k4D[abƃb<V-V_E+/F.usr%~4+H="Qx$-F$K 8J'vg\&I >*F}7'@b_V:01ׇ蛛@GUxa9d^Op9߲իa1o(=ΕLG%|3xﲜ4M'4 6w$ͱ;W@)Ra|d_g~+ 񑚱yJ@~$zIl8H(F޻J2f`0(=ӌ]Ke+TddQss`r'p怃,qA0,[Ugr={3 TOV!?Huer7o;:\#XqGrby [XqfSI٪9Ѩ zff"`}JȈSugWui.DnėPl{uHc 3!c,X3,bh&=]JPZ(AJ'PUuo*7(fxʉ]^G;gRf9 ]9{ށGD2E->DO 0?>a W_}5~fv|>_`nnΌsƋdcucZ. @\U NFW^[Y(M'_eƄ 756.:BdW)Pe^zZ1$L7 HG?\.x'+a:V\y20!?rd̨8C3̌N֖ꞑ Ӟ&+#*V\{C=AƲǢצZ`Cc#Uu8{Q g\ _6-gni#z h@N?'g"YK'N5fcZCx]p:mӢNjw5Fb4f4;ge`C7ydSMvcr1h* s!s ȉ+WFO?~}Y@+sG^^`?=m3iSDXy.5c}p+RF_CѪjP紹-55Zu qd2kpXLi˹'8\H]$^k^߳;+c)vGE KNɱӅrjv)!gkCQ O iJN6Dή4jb(_\&j L/iFlʅIn$)4CmY՚Ll=1{ٯ38 Ò殺;Y)23K/k-EO|HCٯ5(=hn&ʼ1gUab;/:Wֲk6]@3MVadBZ?_SA& }&ORcgULftvg'˛bbf4Ί dS9tn>ں/ߺ eb"Oz.%WKؼب؛cا|5vajN=7AfaO89:<į̌͝^ovKYI_ɬjvu 3r-?1WfT&Eq˜\&Tc'2ٿ)jZLC7"?k4*"pVbd&nD]kۇp/.ϳ c:Շ ^~ M@GEULJΐ9mnxhgp{:A 1Ll'xzf) Qh]ei ɮǼm/GNl%ׂK?˂3/FQpFE"R6t\[ָ͚SŖFJs%SP $_ז|Q Sj7O EP߅{wBpr co?SUbGx̜KVfOcx]1DVãØձL)7¹ZBz"T5V4{pW^.-Aaa*?ӫ]?ڪ>S 򳆐2[CEӛP<,5hBlZ n,6j~^&2}QBAB] j_E㘞봉u 4HG4R]d- 3*(E&L8^w o !?CȞJmLXĖ3K}bQkQ[/U}W3m>~8z- =DHwgV5ml 6Q,;1]X04c <_`neOk#[:Bfާϡ݂R*6 ߐxdClL*ĪeJ7:.nB@4<8$7TCk:vOv~Q:x YH!ׯ^)\XFEkPRv@enBJ8KuwK;z8ŮJ@nmIi.X'9Y2ĝk%( U1Z D*m!(`mtO  ƨJJŋ3ObA+ ɱ3%7x5D<π4Oo8:Q2vcJÞsKSe#\S<K,h0SXjzP~87q [I>n_ y֬/ZpW9fp4s3eڃ = <Sl^I,Qfz ICn#;/>66R6V1й' O>Z.Y?v*SX e{8xSM [Ez5G܆+^mZQو{n;ԏ5x7K0ݷ}`_%άV`Ci4ӂN]9ГarM.<\*:(>ϙg2Z48~RC)BU߼pI$%%y֚⧏:O7/,ŊٵOn6GYW7zQob:pS ~(3Çt@⥋iĂ:_ b[ek[D9"cڮ&wݥӦhO:gWۺ0᭎V>AUg\.XBo=hHQh`R5wa 蠰?{1 gq>ΞCMsLX IڧOd.Oh%Ͳcsv N vKv|v$Hf=c8uBaȧoNeG2p n>Ҡq 0_s %m*A[q_ 8 \nZUͻ437UJ5FkJwѤiġq?*%~Oo՞b*N{2q6icqViD$6'?.79#~ +^Fok3_O%^~=䏦 hB"o8fo T&R\: ōpۄdF!en#8ui~0okz!SXh[?xtJp7*Yk=]yz|0L3qZ#j2qI Ô\.AVPpeaަ#>ǀݼD!kVHFSGЎRt`w3MQ홵 nL/2ߒH+Om'5|%;RWWnꮚ+v]8 Tǡ庭*k a r~ һ5o%mLi&/khaR:گX{U%ZJ 7N:P=@3gىr;u '6' TDܯ*0'_lڧ9]U{ft˛/;"3Eg'i97͎8nzq0,P= DQ.Jl=tΚ`iv(N^fbKc*@*4/ Ԟ/Rj6>0D&$s}3 ?gqr9Yx,uӇ/oU>'+,9&:Q\hl;'IжJUj'{+:zښ47wl/ܒt5VSӰE!Vj4B: c"Z^/K߆}y'jl:&=OIK Xcz>Ɍ.,zF{ 92%+Wp 7[o,^ux0Byᅠx96}GKL |iĈӣN P3^sssh񢅳HBx 1sD`/4ݰB^zcvݸFOYJ&łNDvE>aMѪ`gS1Y-}K,Vci1ōcK㩏'ys6 B58TTb.z^rGA*Z4];G X$ᑑ|+xw'P< Ӈ (ky5:O{W_E.ߢ-6_JyX/%./(n7ט=Pܘ@<@`! S"#1Ikx0qVX!m)F*ؐa#v)aP9YU[*_|;$v˟ M)kPq֍}f;\]Ÿ|9 9&B[J IG X$m"C%@@ H*_5NjQ@@ hx, @@   M,@@ XjR+1!@@ @` " KЄ@@ @Re`MOOcdd>>#)v\&rJqCVVV @@ X'PO0zz9;wߕN.q/t" @@ @*Ikx~ `'tMҏ }V痿e1!#CO {4h/$n]  I[WCnn.-[&5/_.]te f?Fx0^'pYXwRQ°i4Tك_>sg<={*pz7<F]B HOOőgn s+Ի` q.[s[%Yn;Kݍ/axr~v~~#xW_ `5<&&&pmI#l]-B/tiX8,.~'R r3E#V7ˊ.^FOcQ+E殎 -=`F33 hkkȵ}qJ+hQ{<>= ?|dg>,$sW{<ElE(Xm1d<^x/ C 0v!52RRRp7J?6OgqYCb<cBƇ6__R.z/"y GKRmsgDM'}(L&חbT*"T9&Hr K2t΁QAYudf,˳|{Y0fσc[ũpnSsUSi؏=qK$hx$?B>`SZ hJ0㩮oҌ,Zy1r%Eଛ+yɟ\E#l77"\mQ.>˸<2I:WQ @_5 ,90b2U\Ձ>tD:{ӣDp#`hjH`PeO{~n#r:󐛭g}^)vP߇ѡ\>P|4'[z5rs#,f ǹ;_hof]Sd^&dR9{1p (E2^4U,я$>R3V Ќt*; ![9y:">1B^/Ld,_77єt1u4MevӍ2{mϺur&pvlk%_ DyK B%V SQD֠\F]^=HϤznjfz]rw=x&od))r#DO ʇD^}9|93/ƓՍ]h \Udht嵵s_В ;Cx1β3y4@JcDN G8pa=/7wn$Ze̻dFo=}b ?ciRqtry)?\fLrSn2AY#Lfz Y)Ct#ذ\tTSh'pcŕ'2,A#Nʌ1t<#HdmYX0ii2juu7٘Qo,p,Hym*Ϋl QyP19n>1RUwx˞K_{ep6~oCr&;b׮f -sr&t"]z`>5ܵ(?6-TV){WcpYk$A͆l`SMY!TEqU>܆Uu Q p,o:"ʎYtБ+WhӍ~*>쳀{V~Ν ?5G^z5~{"gҦZr]jƚVså]U5֡is[jj8,e* e ,F:s9O 6qN]VHpS8g9vVƒ9R=ZA)їa_c R\]i)Cҗ#/(@VӔl`]iVQ D|+L2FvS4_W$ٔ %OAœH<6R6ilUy}6&yڿىy*VVARsJQw{m29]TJЃ}E>ȯ挦#~CiMf2v,zl)]@\pk>v"bsE$Yf49JߠHU欮U箦b]~\l;Mu2}*ϫ5ѯ˙zc_w#f,,0q%=U-vmaS ef^Z0O~ݥGu3y?Vt9~5aΤX@ %ֲd@`!vV35Gs?MWrSg= Xt3sQtVl'8oωs#}}v@W\.3c`}<y s)^mFŦMv>{ Ss)jx-?%5 QQ!~hnD`f }C[JJf Wôg&0`Qhm22)گP22=OaTԢgڜ.xl\{Qi}#3twv#0=&\>{9zmP54@w'թ>Lx:ThB.:_/~DtvnsMUCXFhYDŜLŋ4NHB(K@NHv=m{9u"d<g.T\R_x6 Wݍ0(uh< j 斒wJT7kٚjV7CGAni3zO*KJϏO66cMȔ]G164!ة\ԉ[h EdvE(U]]ؚEX.u-Lh(Ĭh=Y6IyN5 ) ~b8#V>S88:\<`kGCWG_qsagX)3Lj=7!gxU({F|J8xGʼn絝}u_G#Î|do(?O9ޚHG(0nXƑ~gJOZۤgM Gϱ`[^tξ}hH}c;  l(ƅz}7BnHg Rό_Ln|Qa]bcp).eM-:Zt5:*MBCV.k=$: wJ#Kջ|8 KPTOa%ŅuJ4)XZNB*Tw]܁B蟩=ngU3gG5UŃY_8e^W0hFul*mʍp.y;U4 ܕK -sPX.jE~pO!d2Ph2:K Ƴ44V Wenj,L_FD>4p|?{ߦeڗh8g0s:mbp1)8 Tc ;ǧ133Ļ>,Jń S8[xBHffOj!!wLb‘nGh0iVKg/ajibۡ?BݙF́ma[,H=#lNuW"5 ł-kX[F-kOɟOCg42mq9TlT!ɾ}#$(cUU!˔.ud.$\ =u|xhMnɎ!*~Zӹ! )2+9h^޿h0s J@n(v4bMh-?m$2^&s|ӴSS\\tcJU=F;]3ݴUBɺxqZ 0+stC"JGP_C:6Vg6*&$i|cc–·6WXUY.|jS|g՛ D@+h6xXUmw|g~4>}`_%άV`Ci4ӂN]9ГarM.<\-:(>ϙg2Z48~RC)BU߼pI$%%y֚⧏:O7/,ŊٵOn6YW7zQob:pS ~(3Çt@⥋iĂ:_ b[ek[D9"cڮ&wݥӦhO:gWۺ0᭎V>AUg\.XBo=hHQh`R5wa 蠰?{1 gq>ΞCMsLX IڧOd.Oh%Ͳcsv N vKv|v$Hf=c8uBaȧoNeש2p .q]OW\r#EiAiz 5# jSo3ݴ0wUQCyig ojהIҶωCI~:Kߪ#UƝem2ӞMcҨ$I Hm,!O\΃orGKaVMRfT(K|h9zPMfDJz1p2K߮5 h#Lf2t(p)sR"\"ZC\Gp(~?aDBo_7Ѷ/f$nT|saz"#aNgyȃF5d*>ڻ)}N]l?in1MF\1R} y2Bj>zr?fR3k mcݘ$^d%ۑ:W2n܋*RN#n$dBC Ϝ9#NLcةw,n@=Y=N8%~U!(iDkpҝ8ty0/oЌempb*{~5\^ܙ@Wm1'//ONHWes0]f'.ROmm -`S~d̈~ndb‛+&P^hsҩZ@tcDUr{щeFyV\˟<pd})tң0mrr9u H|}EaH9:g>:3+_|i/:;I+̹hvp#gY _wy,We} uKǽ(C-t= pa3'5~ zf/cJH$iRN2%Z< ,|qr9Yx,uӇ/oU>'+,9&:Q\hl;'IжJUj'{+:zښ47wl/ܒt5VSӰE!Vj4B: I皹Y]=Ѧɾf>̭ J=ô |x0 ؈G"쇆cݺuҗn 7/A#xq-0]>il=-Ә?룆 S0۟pn(>%^Z4ńM3 ^ΥMS`c$HIn8jiCl*DIx#oS~߮n 0ZȌR4bCQҨ 3(#џE׍ f!䱩fn5sS5Kؓ^$MjZd=C4lD C1(&zIi_NIڑŀ;lp<1>HUxX6;)T+Og1yJZZ!#Ifdva3`n(q0,Q\nzte`{To+D}c̱;ZbbK F78?vvb P%d 6w񚛛E-@B;NEBF Vh K/\_w>=}O176]2Kɤ2RX)αH#'t#,bܱ>Z, c*&봥O~Ŋ~C@??/1zlp<19/6uΦ}1Ah4J9*U,Q؋P(HTE+`'5<222|>ꑧddv`4/~Fx/57 [K)K]uee-X90}aRdD 0F i &Ί+-eHRb;lŽc#%lb#'KjK߁c8od.u٢I3e *κl}p/g!g?xBsK)?UԳx!)Xx@@ IE#I- @@ @@  VbB^@@ D@4<` @@ K Xj%&@@ ,ADc Y @@ Hv iG}Y:%֎KdW\;yyyʲ] @@  @R|;Y VO/gs?>cw}7nN$!@@ XE i 66bnI15>X?\:@pժURÃ,F>$tğ@@ `i4dofm1e`T!@@ 0A ik<*xŲeˤ˥ᐮlҨqƋd?K Nr_T^/*0^6=={P'r̓gONGcbȾK!8rz8muxRӑz t=aY=0{nD:&q|7q% O|cJ# "n6id˸[Ř.Q?e<؏dPj:a \nf}zHZ{jfsYŋCR},;x(Qhq0zmm-6/NcZBI~-uϜGXxd l{>\_@QER@̃"O49^PSM/ŨTDQ14sBMd[Ydgg}/#`V̞Ƕt7:;_|[z(+sG7QK$hx$?B>`SZ hJ0㩮oҌ,Zy1r%Eଛ+yɟ\E#l77"\mQ.>˸<2I:WQ @_5 ,90P#6Tt'Nt/0zOZS.H,6IY#-&GCb<Yʵ@j*VCny Aa~FFp2VCaO'~ќoɎя7|M wYN}yi;I+) ˰z]>TïD?HX\dLmo ?Kxx$sf6$or#]%3Y]AsL2REýDlʅ6YShlbVU5y*tr]2P=Y ב}~LkTބ o#Wpm8f`ya'g&lMcQNe'!d>'OTD'FH6륚LE+f##NW֝Y^56Nםu_VfoӻBYw ?!/T΄3ΎTwcͰd㋡(#@=jnFoPҍ0pڬ !Wi=HϤznjfz]rw=xȠS}SFz @`#3sn;sssf$3^'~\Udht嵵s_В ;Cx1β3y4@JcDN G8pa=/7wn$Ze̻dFo=}b ?ciRqtry)?\fLrSn2AY#Lfz Y)Ct#ذ\tTSh'pcŕ'2,A#Nʌ1t<#HdmYX0ii2juu7٘Qo,p,Hym*Ϋl QyP19n>1RUwx˞K_{ep6-l.p&;b׮f -sr&t"]z`>5',^~倕߹sOQW^ 㙴Vl}F\}f>\ep[Hr:uN-i0ڵ2(KǑUʬYbu2 .r@l㜺r3Oⵆ =˱󰺔4]Q>=$aVca7/2(f:G[O2iFt *TeZuj*7e:_ɶZ'܇>Zgz:f/u7baXRڃ [k.lݐ=S=K>Uxe4KY҃폶vg<~[~;~5aaنk޹ h*엂Z?_ , 4$_xVwV35y+tuxP`Mg113uAgz2c)h:7 v0[w_sP1\)Pϥ{}6} ﱲ.LEdRhfт4?R<~?zxfGTh)Ո!ҭn4 pպ11ק̟ޓ?RF@4<eMXHBr= NB Fq9i{lĩ/|Q[VՅZ%hR^P„6HzXXsn,^jwāP؀)͍=3]sKţ1}4)}5z$U :{n_~2DܳxxS*r6>. ̞\5'>xlTGT :{+O!|Tx^9pKZWJz42;Nyt3i.tLFc?Sz}&eO,8[fnBhOM8R}bsS0ESGB(L y1ԌC 6TゲH}7BnHg RhI{ݍ/ ^0 #v#(**f>v8q :%(eMJ`S?PA\8zItBG_w![qNѩ:*؊@@^&VZ-iprp.Z@N~!`It7?}ʳ*Tzɪ/2 +Ǝjcxts4:66o*ri+g+BUc5MwB˭3Z:!d2Ph2:K Ƴ44V Wenj, cO i'mZv.}INczz3ׯ&1<Ş8#HӐKu9s|j333xNsǢ!_L80x1:'dfjb !{:*q1a[^t.!)vF cxFmUtVM\,xh+m ݝYmł3F\wU,"\cЌ],2^_Lz.ݐgz}MN 9t=@S[PZ*?-=j4ٷoe,[# *-͎P.*k3uc g$3cݵH,[ƫ \؆})J8׬0&ձ骄{BkVD7@@466R6V1й' O>Z.Y?v*kFX e{8xSM [Ez5G܆+^mZQو{n;ԏ5x7K0ݷ؆&TCdH4IR]AsyOy$4}ؤll<*6,F.-z[XJyФ4:#kp[p۷L<9߼+:g>/]Lg$9b*5_ۢ$ڀh]:P~]DŽͼltή}TA򄆑Z2޾,;6Ǚ?nGpLnls09xhd3V]w.|Oq RoF{~ِ;VrDq]ơ}.yv6mӠ'kF@4<ҧg\iaX)6甆ƇpT9+)E2#mtp=U{G*;EĽd=rQIlXCD0ڏ1#z)ͨ:~Q>x&r?.H[17ξYf)۵d~"ɬT&N.QIjRv>SF #p2xl,s؀:,;9܍on>Z}W^}$_x9 ө ;yypȳL}\LaJ_Sۏ@Zd[(m 8{oSW}Tcn^]E2sZ*UWUsŮ !*5[){;U-T?$w,AQAӤ(>2n܋*RN鑄O ׌@N&TO>4;̙3 x9ƋxՓk3WԣO Jw\Љg_Ќempb*{~5^@vJL8,4+ӨUg Unv"M~֦@Yr 6HʌƺLO&1(2ar ꅆ=Wt*F hl4]Q^qtsQCמNם 8>R|h:ʏ^QxuN69:$>>U_m}pJ{|itVѕ/oˊ̀H4; ij@,Fٯ<+i>:k avYlUNWYh'3Cܫ23pRE *9e1%$}4)'-QX%E8,x<]VV_7_*Ɠ@W(x46t`WWŤfhf5rٓtx_=mM;6iKMj9]JM(SgQ"z+5  J^qGwK+4U', >Hsk29*?ô 4og]&UxX6;)T+Og1yJZZ!#Ifdva3`n(q0ɽ7ѱ+tB6}<څ*$x,X\nzteI{սk7╏ipGⱎ{kA%&Q bQNNx ى߬ P3^sssh񢅳HZmP 1sD`/TݰB^zcvݸ{FOYJ&łNDvE>aMѪ`gS1Y-}K,Vci1ōcK㩏'ys6 B58TTb.z^rGA*Z4]qR2/nXPqC i |+_;#O>z>F9X+Kx2K͍,rmRR)awYCxAv˽칅@Vt/ g_HZÃb iKY6RH bRltRww$K]d`hLYn|c3[A:*YY2^4,%ROd,^H >"E ik<)B,@@ @Rm5wRB$.@@ ,5DcW @@  %XhBd@@ RC@4vz٩܏?trwߍo}I@@ VHZÃtX;n~Lh`?\j`\侨_T`.0l# (  K!8rz8Z3س8 {Q51OhplW 5=wV?gqCس}6%ULe6ί).  2B i vm[q-K:]a V,xx/yơtAt{z"SXTw~ % Z9;ٚ:6|'?|d`역g{W1" cʑpS1i'$3L ;d@Py *~ExRA&$"+T"D+:Rb)HeHEk#]}{ww]Ips=9Կ>\9ل#lFld[7ڕTes#% ykx\|eee())Q. 7xcӬxx5T-F^.6+4^7M/U)(ϗs,~UOזρ}uzQȌ4iPJviYpׅMɻ8Dzk55,U6^a:׍9֑HF"y)Ql-k4dZa'shv-0#k!қLg~E 6SGjMy)XJ(_S)zҢ̦]U?v 9׏]/2&ì9fMF{nn1v PT*-3{8"1<`dpDQj 1׏*V[^fa` o=u_Gf-iN6EӞ 7E_HYXUk*Qs|GQrTTy:J߂$ј"e/ }x,_u\zN~#33LJPRJy "6$F[liPN1{rpjS <l}{;1to_)RP9Y^87bإ$o{y Hd#c%E%X~Gʙb%44WB!7҉0ަ҉R*t&1g z)& x]U,O*"YR?;7ߡ|KKֶYlIL?w1|ެʧUfiz(:MS]]$nl,^IJ]Uw<^7B&fSRظ9`[LN2b9f)_f9n[%;f˖}'Țuy˝!g_':?'QydQFete]8k<(džjNӟ`H14^SKoXi%阿]`iWjJk_| 4:237$ʞMҘcWZji .WF,/٢^P2-5-JogEz7Mn}Q7V l|Zʇ߰EM8k JԵYŹu^TR8焇ld;ݧ뀯ٴ9tH7Md#{Z-SZYY㧽0\oA[XfkW爰7Ho5ʜ'7گoנa5^JϨauմ 9O0t266F/իW~+v~===q8~t~|挧҉_~9o F;7o5A%WH_M0?di>O3:ܡ:ePAzePLSU$&Vʓƻ_]l|PxcPFH]hX͋5ԭg>Jap?}XȌL&q2kVM93Ѝc(FEZ!3BQVeYJR4]t8PoW#xzsaeC1)Z?M]C<=#3w+V'kTFFCȣOz+<ET[=ągy *a(+˧EeTv,3Y?Io咔ߌybIel8Ii/ r/Vy>3_C-cfQ._[:\9רYoڄV^4rSBr c˾3q6J+q~Ԡ5ȿlx$s6x: /<χa(}Nh_Ҡ'8iǛQBG~d q.:z]iB 8h4M<htpƣt?pgC?/O*78MN_{Y/.EDgj pG9+n[Zqd@hVMsY٦ҭͤ7Eb~lϷs]VtGpsGZ{;Dbz0efv|vb_;:BvaK"|Df RCGcocנ9Dghqj e} S8D`q" b$|? s~o| -k7 dvUoD^-0߆NwvzMQXat@Rj7i!؁gGdSZ:ه3/cs#Oyt0talf\fs;*ⱍMÏ{橁XFIW_#J~'ƇyߑMdG?J씭ۆq+!/=8a|MtaQ6%S u78GP[m8WNu.TpfƏ:@3hUuWqFH+ټq\Xh[iZk;t Ɩj3κmѫ-FJ='nu-2wHZ50z:c݋uU7},ڳٔ)=1JF;Ӯve+)ԃ4tu≍;Bݠi du @Љwe\-pU!ܪyſ9Ђ~"s4+5?[\#xlG/_%SD`HBoY+t.\n `Åzh!0=/iQ%9f?)l8'Eu}jchdQX6%?^ߋ*hѡ|sz)v|q{ e?x9(LdMoAo`ѐ'?&e;לFy=vb75YXd*9=!*] j_1==+Wh+dS8+Q."sli 9ϴVS G4?ߺW]+,J/~ hK̪M.K*uҀM WU UyG)ҩHSShdG󁰒[`:\-)PJ9eWm %4c?`f~m۬ʔ61q0ڗm\ g㛓;C c_ ɐ';ަ, =㸟lܑ]z ]߭EY1(lzq`,Kg6'B^朇;u6$:8jC!5+.h!^$!fhe)MQOG jsoDs{|;X0nux|w-mLrOD,Lĝ*{xu"'Ql,QOTmf+͑ -pHU3J]ժuuY8OmE)!44!4.ґ忣)U¾UxnfzqPHd*2}wS޾xo&N$VfVh@ ko,S,T61p [1Z+ pqVjZ<ߐLyo"OA=5Ԋɽ0+xy\Ȇ(Uz:7';vXS-NG1 A,8[F_cFux9 :C)=ǡ&Dm>M29S6,fupܤX'PZP2%{[5#3PSJVew 5)(]K5%Ԭ +V܁e}8p0?-ꁥ${0dO+2 Hx k)4Bol:)SD>d$&Ol^ W-v8_fsif-( d# $oyL?Ԋjk4AHjlóX8C|i4-Dk荽g1x)U!4W$anxl7G+I>x nGAB{0|'&IْuBy!1Z[&ڼۍ|%αnAvaHՓ3%z >|6 Eot4v́Ch+W]zZ<cG |6=h}7֛I.;CeágSN-YTj瘇t9y,'qCzboErΏSGӏ о?D@"\\n`pQ\Wc7c,}#{x |RС(..Fq+$m8IJӳfƪh_K/X4/ѮUqz$Q{c1«޸ mmVNH> `N'r?;ɉVjlJba?^Κ.}<;u~b:֍`JՓDwd :="gpDkkk,+&c5Jl6:X#ItN!SDyߤ _g7۬=tMh&*'.*ujnXQ*܉Z&{6t(kRm%7A]ic׼Z1AS]!dV2EIg *F~ٱVyj@ؐE_7d՟nТPO=C;H'1t.;cuEV'"gu-q]qk AMII$Ot2әyqd|E3pYFE<1E8ɛˆҼ,CIC{Md<̋{bӎZ#3ߞhe)wL2b'\_īȋu~ Z\NThkjFDiC?ݝV)tNCq{c?o~b ͵<@B.]ii)G7Wڜhg㪷Bg z´Aw:0YTU1E%E%_q:&Mt`3FgOvu%زUa< F@_>'>Tt?Z1c ldDG0 N?3En}M ٍC)#QxWt3X$<*1dx*}jk@CAk1O9 h~@^|#Ԡ}hhë7 B@30Ba:Ȯ^{#{ͤ#L~? LT7܇z=॑OGM{O3-A?͂}H #zz| *9_]-xu pG!N ؈_z7!:<]hDo TXfO8"Gt޲NTfez6^XMw~ 3]xC8Bu̒d7L'NW~ے"1N?mU >I0P36 e}?Z} ѩ׿(-I7ˠ#:"X,F<РJ$?88>k֬>1tMf~FG}o[oUUU}s\p{<nLp5hX$C{CZglјLf8]LS`F(%x+VBhGT5 PCR7)Y9埨8Y SZ-w!Ӕ ΃>KH$Zg%̺@!،؋ 6,B8IϞ tiEo_SO!OɦFHij L.LY6HsViEp-YԘ+̸n|Xm)g61 , rvk7$25";ߧ l9U-n|W,"{%M{㰀4Fg>u3700^*krjw0W^^7x/^wNP& @`sh4/?8/z62"b48iejXx~W ;?` St2sI&j6rf؄{̤Iqs8&XuU,5UWòXÏusGRw-9-sJf\7y6ʔS瘇L=@^w Q;+%B:c 9ʒ$#fGII >O=>Cꑧd'rV~Fh/67+MbŔb:䅅[q׶|e$ 0o ˗[ʲ 6ĆwȅFJ0FNcwZ:ϟYn99d}GuFmW_ϤZAg<…R/ˊqקe%"0okX>H=@pʕjÃѼ[ȇHlܼ>nM`2nVH# laq c4EbC[TL<)!7LMMa#vOſyp9W-^L.`"oGtx94#mm8r]́\S KSym5K8C6ǡp>bi>vؐ V[[(++CIIp\feóh1bw_I=yn"xJFyeӷ激ʤ@ ~ڭ߼|tߨӳ_U?" $Ef.O翇RKJ3bd6`~G/<,׍.2z S_(wMbk1X!z;`1؉PÌZJo_3^N A6MTz@`:"w(|m+O82v6D* 9?wՏBH q?_΢J[VX#-&Esh1,. cWU[fpڳ)Db.y/0.]dTcDcGUzKW,"{)-%̌ Z4l 7E_HYXUk*Qs|GQrTTy:J߂$ј"e/ }x,_u\zN1[23s.Ȥ%go9 bSHbFx˟ne'6@WC,yi.]L&ۉD&02~~\(R"FSqb4lhoؖY@7.:6{k$?=ة} m_ On w kii1 jaޚv}{~łF(ܢ *qi<8ږcdZ&Q:e2ӧ6gCt#ذ\ wi ) yj +u$׵+,q=JU_i틏aFGfYٳWZw JKMr9 *ô5%Р7[S_+Jf:ܢ嵦Elȷ?YouI-4*j ROK8˔gQt~{Mt=u1wz*~g 6bˍYv;)C 73F5F /C~;"䣾75(d{u߫נ3jXn5-Æpȧ9)ԸP^?(Vӣ?tҥK {>&E3J/rv6n/jJ@ب}~şm '|)ftC7Ruʠn?ʠJF3HL*'w`oJ0 y'ܒ\x<̰Nƒ$NPZz͊)瀀3UsFb#lEިS+zFS?7>,kZI*S~Uj$OQ{#?Ag/(>1|MbR;f>82sn([b*D}ʨ@ڨ4yIog jˢ'ٟ à-|Z*HF)~nɢ9+^.Iho).Kg75s\FL_R~{dcGcj;hp= 4 [N\X2-u^8רYoڕV4rSB!ðMqvN)q~KH~A eltF`*Y(ȶӠ_4{ S#'`K2>FpFSZz k;dXi0*Bz0VZcIMz'yxCd#}}s ՐRjW8UIfZLS4G2\aJ{Yk7ej`rp~t5$t#V1ȅn=SV=+!OVeWZi>P:26@Ŭ@x29Y2kl,;qƸ #F3Ьp6ȗ8h)|aϪhXT)t\ Jx\SW0* RM^o~~3Nôb-7+ mQ!VXF2kbq*]k ĭ7b~lF'2Xۗ,doS/Z{ıxuz*ꮑ QG2$iVoF6L΅hQ~:|ec%e#tb 9 / L `Hlx8!^e# M[ÃHh_0D#+Fe^4ƄS#w\NO>qV=ѝQhG'c^'{Jňv8§tQo28+,']FLs ;YIg=Nd&ʤ{l`y( Gnt#ҳmS X17MkNDM103>0`.yFV4'yC:+ՙ #]tk/^fY+@&/2@|UcT"iO*z'kdz7bZIlc OBDí)U"8ڳٔ)6Z;eɷǹ륨q^~Z) %6<譨Svq̔9 "Ү4dc.4|۪tI0ȴ 6$!󋀝_*mClx׿Njx[G ɹrpS.cE =(FE$F[coEٟlG,v6\ 042 [Z9Zcs×K߀{(I V:{GNS[tJo6 Mt~hJo^/863,N 1t UFX[7pE 9P2*?fw_62Rc RF+| ,\l<|;?'0qwPO bsrOAJ3#>O~8@ݮ{?qF;n9ǙWPdC߳MbN8FSh:~3~ e(&Ns@wXrL=w޵6޴/^Ach;8DM8܃4g)4p 3S&3Nt 6*6zrp T!q2E${[<m%+pG2;)\lJR?wjV߆+>8"'d?-1A'vދq s}R4M!XeڰZ318YH!İ>Bff~I"l\ L QFL,WNJCYhARsoGydkXD eA/$n ‹<jAt} Q4-3r<ϦGmz3Ʌzg:8li2+\g泌,;-+NCV%JB#u<(}$vol/o%wtC23'ѣ83BsS^mhF߿d_}O =t(.zC|g>IizQDZ2x#ڭ?/8=QGFΨ=z 9WqڬyO=L@Ys:I,g*9OmғmCI, KO0kh#G:8u0lR#_Y٧7<,XPW >Mqpa%cN+ F ż6:Xř~/Hn>z\-2Df)SM7eO=PNCѫ0SNl&.Klqс~C#o&N1Lg6QݞGX % J/cǎzj|ƍNI=߰שWi.Ѣi{҇/ct{Cë;eqvS^@Єpj }7+E-!}/Ў'k. S6&_Qv0*2qGGS1#ҷcn sPfʇd* )҉CݨuB'?Zϰ:g^k4졦2*4h3GAV k7xy|=:s`׏٠44 ݘܩ2+Hd+#}G"wh՟nHgat-Fz=}~?neJUOxJWb5_9np]qk AAM CIuɓ'6^rٶ$Y1'ZCKwVh:atbt8©qEbǧqa_q=ط\Wdؿޠo~,m0HfmHWIr0WBLza_StmIH1MZa nib8sA8 %̤#֛tLLdɷt~nzgl:^YhS2mqdE3p`Oh'p9O,CIC{MJk-P9V׹:|]U_neo,tNCf3qZzxvy.c:LkZrwpnc~:g'?񘝴󊀝tV *lӝRu3? ǜh2ٸmقÍ0-r]3ϢR@Q=miCײq|2Ơ>OK7:m|gl(Keh{Q?_>mB%84ݏ:}^Y;LkE*yh:Ko6yHfUL&52 OG hUn68ekXyʹnMl }ZmX]Ko?B Z6B,օ- F} 0a&aY8 /f>ԫ/3"7=jJ34/G7 !/:%DTJ@Nvy>4$ElD/hMa $<]hDoUGp, #wdoY\e*峌ZzI0q42\~H׾P}5Gnrgp i2ުː{g]5ȝxIflLm5} 6]/)JKRHLВ"pGC*x >YpM7kFG}j7ĭފ*tdgDԹ.=Zn7ulZ4$LlrO!콡JQ3 K4ńM3At!$MF x<+!4!l*MxQ\(!)}OT,FDX)-;i8 㾄dNuV2ͬ ȉ`S͂!D SY,ހ6znnZdwnOG?3b<ԋ'"ݦ$203Vf UϡZcE8&BɌʇMV``a,쓾 }drpLM67.E-xcccl;\3:A"1 XFg굪J/k)镗7ŋ]Tf DR=3Z4/?8/z%2"b48ijppFTCv—9 /EI=ŴW12sI&*6rfش̤)xa9ƆӶjX+wbH?ec.X588BɌ&O7FrfFa.3}2 @;vxإ!\:eQ cDZ@`%%%'R< SE~8qlҦ5:!*bs#d,6_LyX/&sklnkM^X(n@\dq\ s'ykx0/_n)F*ؐa#N)aP9Yߕj<gI1_a;ۂH׵]!|>j}%@ JQt.+D%dq8TFH?m̱D@" H$D 3VsgKH$D@" H$a@!o$D@" H$|! BVҕH$D@" H dÀBH$D@" H$B@6<򅬤+H$D@" vi wᅬY:։[BXwq***PZZ$ +H$D@" ymx8wzv;`nrvj9;>[o\~=o/t2 D@" H$D.`#ϟ` vbM7ݤG} rJhr-rCEGI$@zb40={ W`D!,bm^^K.U˖-SGQT?a4-FѾ&\l>Nr_P^/(0 HI I܉o ExĐϬhQ'ۋ;kqb(31*_j3R]7)pZ5QӖ$mݦLuz+bu8,.~&]l{ =%f6)[{n"o.#q ęr<![1\ i"1΁^69.fDG_< ^̆&tD|-ž_OJг$Vn55<._2 ˅oQiVv~<<*h/vL&lK9_j?}k ȪLjpjk@GF_nrlŲ/ Q2;'d)~ajܜao<t5sp/)q"_ [& D`#`>oڠʍ3jvCBGۍp=ob:oѡ֊X '[Xy.wp=[@J%*ma@a<1h2ss84W",_UofL!sC~FqJ%֠\ #z{zU-/Cj.cxCq§p4923/hOt))DZ0F,ɥXeK ֓nf);c QTU^EҷH4gwt2[ENZDΛdtTz*D b/j~ cqg0;$ϥXMk Q)¦B{mh_i/md4"}xhtZ<&ɭ=;MKɉ*/i0rlmbڷI6dK_ 襫PUYn~7#q7og[S ix^k)ʅB!%(h4U-F֍*m +}3a#\g|FӃJЗ@(.&:~ǰf9Ϗ_cO*A˰~1vVZi׷OQ,g-z:OȃCm1&Me#Q&3}lqhyjQ 1M7 pG?bhް^K1]2?ӮX־&itdfXioIJ=+ z19^} ;$`K+r_nTYXYak444K~CS.Ps`?-NԴ(O.Tj[F}=6hr0jOie"LK6ݫ (3͌e'bfcӬpgt;egV/7`k +%X& J?^]oJϨai#}QOR+=$9@PڄBz8KҥK {>&E3 _~9o F;7o5A%Hѧ*h O|~şPkFR`8:ܡǫSu߮W4UZ5JQATZ-*Ob#*.6>(ả_@ !ua3{k[+}oc80L&q2kV@L9|) TPFUT 鍊:B5E״*zTO T-Մ2,kLEMULgEӟYF|5grWn4u2 f{•TmC'>A%,I-H/4 B>|~*3P❪BiJhx4smSɕi_K"#;he6ͪmKYlf9i71d4; |ra>Vck:RLy%6UB"dblx4(_4{;̏M#'`K2>*5UFOi*o0Iw=jIwoK6`|k;dXi0*f0ZcIMzyx2&H\F=#0b:柢9B21>4~wL2i7ej`rCn܏F GB7򏍞U]_]sKiF0 (&2h1{| <,tDc^94vW:yZbc\hV8lK 4>9o'l@UܖیrSeۄ^hJg?o.FpiG*"XP8ٗA3O}ml1` AK,d n%`Z++fq 9ud q`R"Fϲ+/s>GcI GTi7:ۂЇ9F6Ef΅IƔWfj\V-0ÇcǜunhY7pfZC2֗\wvAIU`.qюBi; ;2vM)5Ywoς˳d FԻXa}k{,Qo?;w;MGO?@j΅a;f;*ⱍMÏ{u߃85mrF8R׈:|;о#?5QVU-f)[ Ha]?Xy ,lꦫ ۞{d"&6/lxA=5WS su}l +2(Wc0T5.۶zC{aDO"짖fl4Ѭ:2MkppPՉ'6rBݠ,"3;hԳlKm Q}xqAhӞ[&Ţq^|cs%?Oxd]Ãm7sH`G>Jku ˼ +Wi pwp.ZAye5jj(5$O~fFRY7'FwRNu.⥃/w>HLs_;@y] ds8Gݶfƍ'GcЃ [ uc,Kw:Hrlxx/z8t9q~ Bdt-D&Lv =Ei;%soDs{|;X0nux|w-جUb|Ew6NdY&n|N d+LNth|hթTmfμ+͑ -pHծFHTe 'o=vRf#wd$<Mvno\ґ̪ KNyk*7T Q@{a~R#R،B9>fsrs%<O5JmPZ3oЁ$!kzZox86共yCh+)h` +'@VȆg=Γx?;qM7tg1ĸ XCGG;=HиrwXK=w޵ C޴/^Ach;}Ns ǛwiwznB23ebNAyf|19q ['ب3Z&!}xY-CjYb8ϱUcVwT.C߾{c#'PjwY}Vˊp`j}<W'rHA"u>h&%0uЇ`ݗiTgV.0K`ΣU/CT#L܈Ʈ7T>Jq`ly>Ǻ}iR. MШ\0l2"IJ$sE@6<`C8oa6 I?ăeX~;ڥJPź/i4JNk荽g 슗RAsu_SF34=Wb\ShÇHD}93b`Wqڬ}O=$J> `N'l&=&>>@35w]wYC w<NYřtew0uEd.rG鵮5˵A)͓O|fف>6,9].l7`g%HYn@Sl?Z, ‰dkVmᣧ /p\F0P{ $:#e#)/A[\4ZActEӱ'Lm\תyv&Č'$lxpIPoXmiϟ7ucgG#8~Ћ̤}th[> )CݨMֽ_ԦޟCtj=nj4yxK Vg*2!J_+Sg>*uRB>f!5t&[3 ݘN, xy:sb׏z!2pU~-8cf?T@ؐECz<Aئֳt;v$6FUj=ᯃot4נzׄrdǣ8` D@"'O'$s-v"'lwu)hq ]!2babQ:Y$Bui Gq>}.L'H2gf!ё(<;ʟ _ 2a{s??5 N:v$[ ar;c}JeEwT)H GL:wXBڦL2eg87Ķs9ҕDzc{X™,LpSB.^( qY ߞQ) :#';mZsk m F:Iwʉc?S^eWx5ͥ+--]7#Ja4l\ClA@B9.؁gQN؞kك8>F#mMf`">»:Keh3hGhERGf[wFAtZ}s?u/rӗVlV8dF][dRc-xĐ\o]?wE{:h]ZSu%_lb#o#ujK !-5h#ok͂l]j #Qf&C2i'xihiiVW1藅:bd]hDo%ZFw ^CCϢ16wxDzK k/~2uE*NNgǭi`h:;>Pq'Ra>txuj43M|b^},~z4?Ƚ\SvV3%Qgw.T_/-H2!p(A5<`}pp|֬Y}c馛pb>47|z+,ӵQ%xhݘbjhѴf{a UjzM[!~6$~qLQ#k <䊕=MQĕq)|bO "Tf1'2LiֶxLP&:h-!d [/2F<`3rb/*T`B'={;7sgSO!OɦFHij ̓.h~CrI`- $clJ!y,Ij`f١`G\K;N3EI"b48 epPc˜ws n_9(8MA(+69G)dҍ9&hU<*N۪aY:T#ҳRvD㦹jp(NˎڙQ@{u)@p$۴z'N|-,PQRRO~?z*lÉc6Eh2ڋ͍rp|1a󿘰9Ao{>5yauV"`i/c%CJ$k ykx0/_n)F*ؐa#N)aP9Yߕj<g fމ;NzͅuFmW_ϤZA{?…R/5W<\sX i/ LD" ,8mǂCB2$H$D@" X\k<[ͽ"YH$D@" Hxd%9H$D@" ,ZdcъN2.H$D@" X<Ȇ⑕T" H$D@"h E+:ɸD@" H$D` 021<f]'n Ļb q@ii2D@" H$D@"Pܹs,~٩܏>ozr=܃o$$D@" H$[Ãt?lĂ58؉7tcgj|Fs}zʕ+Նy-ȑ'H$H;[4o-_ӂdD"5lzkE|n/vʼnTbd@IDAT,wgϏ boRഀ91klrIN";1>>nM`2nV2cqX\FMF{ѻ&{JlSSSS/dE.\FUㆃ.3&y!Bb*ĬwEȩw1cMțOlhQlB[ _N`jvSCsu7l$ҋT8i<.=;XleoL \[(++CIIp\feóh1bw_I=yn"xJFyeӷ激ʤ@ ~ڭ߼|tdT &͞JV,+K'|^ٝ4ۏ:=ZW0LmSm2;t}zʧ F1~Tt*xː{)-̌ Z4l19nJ?Vl"/?Kr)VDY ?},GEn-g))]ۗUǥw%33LJPRJy "6]%F[liPN1{pjS <l}{;{6+o$KʊGv!v46q]:ltA-Eh\.RVF2U0dM?}JVA5 USI(tLdb!Ι;s93IIνps=9g;W tl<7Vrpqv/]Fy#Ev#0Y 7A)ٕ~f:1wpuqwBcKʍ}ٖӯE^57ǧp)*Z QSy fZ7BOwżuzBYE{\~ 0ֻ(϶V؀kuQ1 bӄzm=BH15pniEw7xH=wu:#~ذ{>@{#~:vJm''zf&445K*~[0~S Q3[fulkotze|7̛(gm %x^Ͽjqkb. t:Ͳl -I+usSgk& ғOƙeE]^$py%fdȓϏΟMI6Y b@9g~kѰ~ł" j|,KȃCmѐL2Ʉ5ٚqViy 2] 5ӍcC 1]<"lUcQPaO2U70,#8Oeϊςx`Aoa9' \ٗrc&dai{PgW(ӔKx,+q, g*T ! 7ڠ[j(lc[( s0 _!-nsKjrr@#Am;XMɶ9Ͱai77,6f|Mqr\&,HLizcyJzR]!xg zr}Euc*ҥK.^EۀhBsƋaK/լA+qpx}̣}Ԇiz 7<|2g1;*b -/ $<(ߨ1G\7BCq3{髙|"J!C!''2Ld'c`)b#LNϓGD7j, i~BeHw>whl<`oF+txƳ,2fhgj/DOq/1#OQ`G9xPrVpp+e Z6cZQ W1q$3Q&y*)9TԟFѥg1ڦ yW@ 1 FfqE JF˥ufX\)qI&yCZ0ݤoJo"ݧxDͪDDT ++KXā-Z@=ȟ]i8)ɆQDوy(z 6NDZӂ{&O0˨ |* JB/BދDu &%%1:j4T9PNmTE7 "?Bz`ߐU鴲-\ J`XH2r713I5)_+Qn,hd 2 \!5}+EZc* ?O/cs7yT$Q%Ҵ/sVg`f:L :n-ބy\L[z^9Jafv7p|4gn̿i1B?,kwj[Vxs;LlE"I$E@6<`+4 sX$z'OQH!1+Ѽ'7wi!4!e@r(Iy4dz^Pnl' FW?{~*FF+xjm*GrYW3ჇYw3;hI/EYj?nnS0|`GQ+ITzJ$! "l[$;9/8880x0xvtk(lǹ,7[ދ=÷ѦÐھ^ _gth;.=Yڨ2Qd٪jķb8lVQ">bZ MJɧ vk#xz[`cZ?hwX%KЊbnne#m Cek}z%=8݄jAHچu5,Z EwS^Yrql<9Z64F#x~HuMC=njYĢ8;(&fI|[*1&\QadDH@RSXua뮇aX#U v<\~6ůK7_샻_-pO]l iSVTÏYTx{+<$]`*솞i࿐lɬ6 YG^E*_ڤNB3|CoᾂFOuc nk Ýo<Q׺p;֩|F70~{ gwzʕ}93-cbo9wDhӒPZ,Z/ ugN#z e3W{[s8m K=y7t'[ܿǞ4UϦ46u>|㑣BB!xo@x~ HV:vr& x;b@q {cPw[#:WzX45q擔Rn؎{h<=GWgJ~xS]{},M)W?Df]Kv)`a_\q6aVM'"3tu;Zuts0m]~#[:A)͓}y{^rpax4FgktPɁ"T()G7,NZ)V9ˈ#4* }ϽZģpD(jw98<#<8B}4*{bnɪe8yzff/%N-xܣD C4ŌCO<- 7+kQO>z nfؼyev_E-nLp46]i?3u8oE2E sxn6(4Š=~+[ɼޜCM : 8YIS1---eKEZ5(Ö֋a"SlfO< <=/#B'x5m?NȞw-P> ^Fx*XN:aYir(,7VBDo7P7;M|^p]S`i?r]wYikm9nƷ6HQo%y೟rg,IP=iu͖LMk7x.\܀;;Q Pq H VV6U蕋WΟ>k;NE)߀Kt$EJcAw: /ƅI=r?Rp*MA7@gͰ9*nD:6GygUUWRG T@E; xqKX78xeG̨] e׿" 8emZI=nAHV(hnn>#dGJ[OjtMk/,CJĴnECxnLB" H$D@" 5AO>Q\n 7tPБ?D@"P~sX+qZ1HV1˶ƃWQ㡻ڔڵk{{{rQb E45rAtvjEYfh#(J'K'o> =a7}kF3z>+Ӱo_)A. 3^SN*97PƊv?M_ekx$ [ Zq7oRF@hEq(.ѠhUr3tcbpjAb`#v/ƿr}iT$)Q s؁h-؉R55-7.//r/S/@nN(A]2t@r㌚Э ԣFjr^6{.8"f46w"u"XX@[:yI_;fK)fKfF47Bs+湻 *9D g=Okڡ]v0:Sl~gjh}8s޹ mc鼁02(I_<\"fظ Ḫ[6C.7ԉͨXK[rpTn˶~-9>4OV!0M-R[h4Ժz(S*m]\E@y\ZЎg&k B 9=[7tM+Ҽ86L@j =%~:$=ڳ43NNVy)I.'hhB[kTN`fDfotze|7̛(gm %x^Ͽjqkb. t:Ͳl -I+usS {By,xDpSz8LB.!c8?Wӌ ys;>˰PT >gloM?OXO"A-t yp?ҵ-3b]2 x٘Y&&[3*-#OAfQ{l(W~U|!kT t?*,yQ*f%t$gނYtY0P?C~,-,ँ+r_nd,,m[yr2MIaY'BDz]?{~"AU'A65>d6V1 Xʵ.6LWHelr|O2Qp#AknVbӬpgthv3lu&߼`DS\A3 KLizcsCRzeWzH9n®^\1szQXſtk6 P+œbؿK5kxJ\*o<^h%!gZ;14k9`8i褐g- WA%Kj.O"ʳED |^W~!.7o?P^T"Jᑘ zG7_+}JE(=A,;iV8312M*ܸQνFOL2vǍ=BCyB!JkHH ⒑>B@6<ƆVrY$iv'MMF`ڪTp  Nx xƳ,2fhgj/DOq/1#OQaz[W(uZbF G8ȲZ-) Y1,7GGvP6N\)=ser㣱2ezg6ܸM":z>U&hd]F`6};ˍD6Ȇ5Ȳq(es(Fcze^4jdeh27}ܱG5T"EzOUa}c^F)]hp(UNJ$*=% plu^ьiZ MJɧ vk#xz[`cZ?XwX=wb;n[nkpPZT9M4m |_ iBn]/{aWS7Vl ُ\uvCK<|xfNmPFZ#7v5,bQzaāsjI|[*1&\QadDH@RSXua뮇aX#U vy븍v .}q4%SsG8[&ԆU0©eKVxI0};;?j =5Ӿk!'IْYmBB\j/mR'!ϷpV~#\'Ǻņ5Z7qW! AtSGjo`.h,t +.rgZ`/Ǟv#rᡉx_%ɡY$)^F*gn? ql [- 'И2QЈDぃ8M1r6MPE{ٳ4T#ݦ·oS̿<3UwwYE `6xԋp*ӱnhѽ~j][:A)͓}y{^rpax4FgktPɁ"T()G7,NZ)V9ˈ#4* }ϽZģpD(X; 3_fEZEnKWzգԯ3;Hy%MK8}<q:3 zXLxI" X1s<pQ}{W?k[fS,2nv[;fXrS {O$mI"!}KPv*vBX?HЋE&.սS–xXdNC*cV!qХ)ҶUI%"lH98K*~9wKgN  5;`d)IFIXBCY⶞6+Q[ȂL tؔM e$䉰j8xywF8 ;@7hYGu.Su'|bmAiOs2qĊ`9ɫX&©/HRQ_I?r rʍc/JT8Lpz-a͖}IgiEp1ZTv mV* {\_.  а +VBhl` os<+'Bcxs7+$Tf9'Mƴ׶r. i~֠ [ dX [/놉L =4l _G)Oz k#('q=;Z;$| 1<#zdK TeȆǧL2D@" H$@`Yӥ R)|x®ƺ[`ƍi&hmmu]H$D@" H6<{=8{rvO0{z9ZN~|o+'}pm:D@" H$D@"`ekxHǹsF,A'p E̗k|P'| n:A4o&9#$D@"P]r43Vnv$5D,^EnhkkSk׮UʝFA]< C4$ׄ-3g'|vWg=•t E}p^b*Ʀ&haShgOB߾}lb%H$p뭷*#.o&4f48hE4wx 1 8 f1 l_Ȋ|\̾Rzu28[nV,zd7^Wǣj!x5bv+|^##p{&4#l ˗/Cgg'477+ 땋YٹxxKE4jwA%wCw MVQ Yǻ#2% :ygȨ*M5[@=#YP 1"Y[ 3q|:oNg^L/@:Kl,dy^?*֯ r/ps:wΫp:NcLߜL@y}ߝd;`nh:J߂Ji,, -Ў/BKc3lq/%3#LVt"l5.V;@)6Fs?ܳP5O^9\i6rұ zt@Z}Ytxwۉ/l|.gbc3tl]XfW-KtfԉV,% -98*7e[NqzrdhYcT[h4Ժz(XI42n|E 7ε J=EZ+@ˡ|2G)&yjysƿ}-G&E[D]9Py߉ڷm=l2 pw4}vзIH#k*BK, ="DR775<eVpB5g Lɧb2"./ Ezl`X\M32GͦRb$,BQ1a5mhXo?}b?t\>K%!H׶̈ thZ&ecfdšl8<.F\U񅘮BS6*1w(K'Gת cxБLx ҧgŃNg@a04e'eR6 gv셐GƜ臐%Z$f?6ʁI)#"ˆ  ߪTxH-{!9:#^](qwk6Yȇ?4p,.1ӭV*9$UC` 7zaW^U?9n,^_thMax1 K5kxJ\*ox<^iz2=|2lHŐm G fYLyQ2(N"Ɇ-*O#a>_~#?Wb/}u+',a2)Xqr"3JH&y22>=ī8gk-;69/M}{4IhQhYI~ >[{doxP/Zqq SLʲXE12/Vp/FܸqFP8+)DZCa|7Ɠ1IG1sZ%.!FYlWHȧTzLs91S2VHN a>DhUn.bU+5wTq$S2.aq,ƍF' HsRTg77ptSR{v+Q"VT []'qj+HXx ˂8S#\5^ytoCH Jpˊ< k#Xqձ\ݝʈ ijx*GTĘQ **#LVȦ&'ߘݤ(*¦|-kᑿ >֭Ws~8q݁ ۡm,_,mjз0f׮؁x@; VPn~;klí%|СM?t<{Mݸh z{ HpoDAG2e3>/ Abj51oUt͝-P^S!\V65Ek:W R/^T*+Wp+0ZܭtD ,)d2ph&׆*!L?H5m@^Xg ܦm<*iZ9 FY 'g`f:L :n-ބy\K[z/poq$,6l k >?p+uP3>SY]UTm1:_BsG nI}?֟ƛ@ۋH'Tv:p*[o6z$t:7< }z z-,lQr &sVb; Dˠ06KCzGS{Aϱ}mB*8YynWt wjn5x~i}75 ׉;no'GhH*eN>;-;=}~s7 y,Ax PdEV h_wG,`߻mspyd/{++,+I͊$,8o޵5zS?M“ vA#pR8H'^cǎ P\wžpc|rs\Vn%Ft ̱>hjj eǙORJ-}H n؎{h<=GWgJ~xS]{}f4?[a})yT'8ddcՆDzMjmm]7?A-q:DhWzxoqKt55鱔kr7 8+iepPN‹qѺr=r?Rp*MA7@gͰ9*nD:6Gy*,gUUWRG T@E; xqKX78xeG̨@0c8q9%2R:l.±<2D@"Po =|G#=X'F9 D{^VYmr+1oixemv['+e@GfLR" "Autt([H )\8q4RBPDFNVcn{ƾ S!`aW;ˁيIaM×&Vj3V<JA<w}>Xv5x0-7nM6Akk2D@" H$D@"P{ٳg;,~r:?~[9n$$D@" H$,[ÃF:Ν;4bA :nP.b\>u) yM7ɑ#X]hm²V" H$ e[Aӫ mmmJaڵʽ](Hq"DpEz$дGP;|465A3uLncB'o> '{j̫)^JpOþ}}pb&JxlJ$#l D"z22A2nfhJ8(%tM]nnlBLN4,,,G_U/OGf_|Z)Z /<9F[Ҩ i ]'Vi2Kptd~2Bz9غ= < ]Χ ٓ02rW Ӷd-I$j"l ˗/Cgg'477+ 땋YٹxxKE4jwA%wCw MVQ Yǻ#2% :yg8qxЊ:kqBp޴bB'~=rHO[wzqذ0J7}Mt9D@"P ekxД(ZAr91/'Dhj{k*>7t׭7.oʥ_^^,>Qldjz>|X)yVLZZ^xpHMH2 _xN$Ca Cj!KX+`&LLV`Q]0j>S6*?㓣 M1tJ'4Sʫ[K©{ʂ KѱU6b.MQ 11oXF p]q ı1&#Bp^=-nJ r/<}Qy$} 6??pvU㏙ӋU,K]^\V>VR3G`×m<^x!ض08 zmJ<w6k7~mk-<pҺUs-kBk0d߷v AqN;6-{6t| umY%UV>bxh` Sqđ0 NOLaL.b|<剧Q{llha_WT:*.eࣆ~y%/fUtDf~U./A5nN>=k #?n^Oi!#b9M;O:̥@E6[jShJ58OÃ>fuU۽Mto>OQu9ۻG DO<ŒIOD@" (Dv´V|*|#pn;x??6D& ت}w k\;[Ee0P>~Lqb}:= A #=s_Ч \<<~?;4,3�Z?Azȑ2qh줯e~僉hapfc3L=ѩ9U&(.'#*Q{l4i}V[@W#aӇc.8#!ZD螢/(e^ѤN*26; ў+!ap)`qEq#OJh:v,$"FfQF `4&xCG.{U{t |ĥ]C.嘶A#S0o?>]>gb[PN8"3g Yϐx$$DÔ}'];w߆XK%po'hח,N.=Cߎn=F=02Uy_b=):5> O?OjpZVk];9!<F!6O)>^u.w?U*L8Cеa)yz =TG7j \*)VGB1ΡXmlZ =0ZYOÏA7_}/j.?+VNx[8gm㪮|? $h9m[ZD6WN&EI 1I;5csLٙe^%Š%N%F64׆7r1ri@KFM[|wnIڪ{{s>+n띘41D:4+AppرCء~i{TXřвY5ڗ݊u؆CMuvNVz9&B%`*=yX\94xb jxqDiybHy/GQՠjKl-e6&}qy&<,Fs+Aes_'^5%>S[w( i/*Bv̜'oVD\aj6 xESc# W W10n0v^Ȍ%L: #%G>gL\KܒfDC(vP{ΠjV) Cϣ/G]*ZB(Eʤ2u`L >xج:&ӱ~qT}pצ#,+W/_T|x]Xll7d0yj@vz{$ Xjwڷzx|ovmWNI*lĸt'!v,y8p2 &h֢ F(I֪Nt5 w)BC&&{9~`Qp-3Z.a^0=*'j#R +{Q|/32أtJQΤʶRRBv1>tXI…79}XP97?AsGo\h$x5I׃ZSxqEىwgFc W~.l795wEX/w߳H?\Ck'Ll؉WqtR\Ah{uIN<3DЪa7yLcwFrl6r2VeV@`醯اIVj?ȋFz!DK 䊲GO0NQɈbQۋ>9*&&2(ahK"85WчPG(^tkdDI.?4dD _fL 0Lzg:y&ω[閟b< 5޿ޏ%oXr(K#i[V]W9_.⪿c<5nRZtf %4kgoZKD jɒeJf(&QYߎ4ZP}ށ_&l/2MqP2½Z^Vˈ詗+G&u%s}6!ч&9~MJ`L^ t4eLekrL!;W0zۛhEq5t@H6ZCk9䦴#@kSBhԉwLcXUhtv5Cm|bc-u:Eוy9Ʌ[0r|Mo K}=ݔ 0& Z<_ZUVoM7݄oL痨t|g۰rJxS=9 "$ȃ੆ QEe&3F߰R.glKVP>Sn& N2a-D- Iy7&~eY՟dͳ0 S\-N˙uLQ11΃E)9y+R*0b)B|Oޮ,Y9Zb/aYN~$*рE(w/dMOOKv]Z Qθ~N~W[A6 8`L 09D`*%K)eEKhR;Ž-%J-'!һlCm߀Kaم; fs&μ:Ƿ?v+V;挢9VOyŋ(]d͟c=8:&` Yqd0&`L 0^x7;hY`L 0&`;x\9cL 0&`sW<@& L 0&`Lz'=9}L 0&`L`V 0&`L \fu:]wbbxGaV& hK;DYYgL 0&`L V<>kw8S]\Z.?I^{wܑt`L 0&`hpDpo&'OV>3ye˖![oc@Xx3aL k`L`^1{<\.,ZH<,^X:Ny+ZA4?Z!C2…뙽Ts fA1g U/,DOa ,9hjvDONy5yeJNlaT. /V4L3sgNA` UᑼE˗UZ`mo_EM⽋Jԝ,HݞD? pp/A|4_QRi"_%([,V(IF0H:;J$]BcC|2XUɞJ)7IQ>)ͮRX!|D؊'&`ٳ h3o1Zq (ڊעK Qs8(!;_"+$JNLQauEPh%WtߪY(w9,OcOGCϱ xj KPqGG.]B6N6$ٱTeFkq&7^ַb+ؓ(Hkᤰ ʳN:M2h(gzV5ѳDS#RcL 0h^P7ߔ/R(y}^2tpWĔY?o=ju2"K~]d JELKDmP3G#uMCK>K^GezPj]ڭO=~ bhRq8ݦ4ԟ䦜gB r~dxlEиq^v&>=0ݨnTX{nްM!s>Kz(ѧߤgSW@jvWViBVk}BI,#s"Ф1٥HX{CzӃIM?xn[6)5{5HĦ"XQxjʘi'FJM57b67| 0&-9!]tI^k׮ɿO?Tec/^˗/K⧕߳Q72-+Yx鸉nev>1^6@$ Eq EަxwsÉz֟3ʓuZ7Z<<ndbHW4ŝ2ag/w4(#|#wذ$R,X#dZd~Qi}C{|թᎢ'cpW7cpRBljHh&ٵώqi!/' uHF}/X{8"s02^Zt uKUE_{W/"O8C蔅-F>sFmuP>Q(u~N׌<< O`))Oy'ݛjMObd5ToioGFSmhiW Eh4ЛʌB=dSb'P6w $9נ7gԗ/v*d7޿Z.<}''_ H͏{*8L(T39OTμ36} 2*}ZL9mfl#laV43)D86gmGBӑ5jU!c(>= .(GՋ/C-2YwG-SfNp:~+{>g":&lQfm|[Wv7-;ǘGxqy/rVlErkD}8+jSo|4L 0&C(]\Zh'l@.֠vNW(Fy/GQՠjKl-e6&}qy&<,Fs4=iEX" `{:4hpo)**bݦ;$JB(R[yfΓ7F+@W}@0֐]QJ?̈m䀍7ݨԲb+Z3yJW0G-h{&2Ǧ\Ia<鰍'+z N<?bE j(QHB2ȁ&6pW魩wrⱽW {N㧾h:Vm7:Zџ:IgKP {L_MiG->PtB3wCX7.޳m3TوDZeV鰍IXMsqR_MCXo+V|qmQa_9{Աv04iAB$m9`#RʮL_SY]iԂ=OM m2E!- }mȱ1zR9yi?tGUKUթNUO}9HGV:Dl@\14E9phƱ-CiWi f~t{L 0&0+aݿn;|'Z©>|QT p&9[vxj\y_"r<U;ˆ=Wؼc7ك[ӻj^8MBcp>5}EE{(ԾB-6<+߬W SQLyrOҫV;4mP`ͤ+..(C,f*[#d 鸊m:_}-4 k'5d#N}45i=#D87ZZ&=aE k3 K2FPlHDm}>6Ck9䦵r; r*4޿O1Cm|bc-u:E]1(As a[LnQ{)?`L`aAxdA@,ߏ?V7ߌn 7ޘ^/Q@-xwqmaʕzr*DHϑIS i/<u7bMga\/ؖD}987u R%LxA^7![Axh_AL67$Y՟ͳ0 S\-NGL;cb-R@yC$;6$d(]|~L1UNmJ(8&sO3 qtWPS  ,iMurw 쥉sg9%Hh2tGк8$?ˆ̨H30J62&@j.]n%0b)B|O|fhHdV`3?_ZZ~###y4xDJ(*߽5==-K.uQh)F&<L 08"fÊHr!FIG/<}1P1)0ydL 0G`*EEE??O<}AhD+A!d o>|>a?Xg\p?^Up+@ӠyV 0&"0k`ɒ%򔲢B4)ralj %dX] of(;wV؉XXX4)z=x̽ /`L N`x"dL 0&` :# '9L 0&`L dW<2E0&`L 0&W<L 0&`L dW<2E0&`L 0&W<L 0&`L dN+ }|GZxҥ;QVVb;/`L 0&`9 0>===b-mTW/u?>cOW.{qwG`L 0&@f!Z:.\b!*bnI U>DC>L^@pٲerCȼ[C"-L2&Wfm^%*. -+/NSފVx?͏FL!p)zfo%9{eDGjP̙B Sa9K`#:;Q0w^wޮj;ٳ10.͓N=;wV|} f5.Zctt~2!evm(BhaDX!CL!{޻4f*`0Y\%t-y?s y4 {p+L^x|J=(yn&fY@ tcitNx=ӣh(u'fA; 0&AeJLJ&[2왹) ҕ@~>,/ɞ  I! i-_R0ťey/$0V8W㋊?/{';Y=~?:z/^HIXQRi"_%([,V(IF0H:;J$]BcC|2XUɞJ)7IQ>)ͮRX!|D؊'&`ٳ h3o1Zq (ڊעK Qs8(!;_"+$JNLQauEPh%WtߪY(w9,OcOGCϱ xj KPqGG.]B6N6$ٱTeFkqƋvR ކc^ =݂C+p ^+ᤰ h"Q=tl GWD~?ӳ/!|w%z`L D҇R6~o$~B4==ϋB)d놻%/ ̊ykQݟN]z%KvWJ/bg_N'rmJFo>~kz\jY=*ӃRsnS @'G6$7<J[ *Da_JUՍ+v hDFqMωMDM{^^ Xn54VUk߽[ FәAH=4]d6=78l1C>&5I'EU{uu<-J%LP;G8E8;+k$9irZ_*񫉅5}t(N( Գƶ$^QۣAkװ'ݭzyY 銦3_&l#lT6l%>h, /=٦_1q|;._蛹쎢'cpW7cpRBljHh&ٵώ)?2-E{hAk/3GqF(?xT\(n\c-xMeyƱ'BӇn1C{OAD-s'5#O=1&@Jc uIکCm TzAŧ /- y5eNjJ:<*ٍcA O)o #ʼnׂ'_ 1E0/ vLU3/ƌMko fgV;tNo>-uwطMbL уY[ltaͶZt+EHloK(GՋ/C-2YwG-SfNp:~+{>g":&lQ&;x/la[=a0b:Pn[;v;ԏ1M KQ^i -[Q}yڭ(Q_Ίm8Tg[1k>` Q^(yX\hb>=4܉ HX>t4_=Tm YƄC/α>#τ4hv@G,^5z=e.[X5yqGn s+5dWEEdz!#6Zz{TvfSˊh`k)>\@ih,ӬD#g_/CRuM1 W0E>j6 xESc# W W10ܱq&2-#2L)xn:l:~f.,6Msp5Fa;VZ 9C˳Ȉ0o5[]Sso:v,y8p2 &h֢ F(I֪8mY d׭LI71krasMtH1P!?Q8\ٗMhXً#}10Vr&#(۬Z.ͻUм&:7?Yj7c<|sB#[&@FpÌѹ{ƱT;^vohph8(~'pf86jQWר}qN.ׇ"V,֯ӗ׻Y&6+W~8Z:Ipo.IɵgF]wFx[Z;3c#o*Ӷ@K7|ߦ>d?z,Ui'P_E^t4-]|A/}ԀO({(a5QHB2ȁ&6pW魩wrⱽW {N㧾h:_ |bvNR)ْ;TBiS£QK)Ќ~k# l 6U6"VٵO^o$-)~:nwHcõ37%&2"T-'K)- xIc;iIG6do1+S^YPH:'sϤs=JB c|f!ڶ)JZeV.4jNا6|CxbP_lGC'ϣOOs8z@xZNu*zrW64mP`&Ȥ+..(C,f*[#d 鸊m:_}-4 k'5d#N}45i=mX-N=.M iI=oZ8<ыjz-NOLJA+R]OCC6E:DTZI`5lZ7|۳nU]1k ks2n" ~}+,ٮn7 ]^ 1HV]o;|êUqe&3]5j͊kvvzᯣ΍nVdy_{4hQy~L#Q[ϳZ)Iwσd>|^8V}]ܧۘ?ݡH`XoHuEnR=&z;hNrV8Ly2_-jHm0 0&7l>cժUqM7%*}.n6\2TON9p:ix!BTѢ&tY87 ے" A /+56_t ;h1,j߮$nOH$mq:d2uYCT:-[&W<[o[>d: 0&@X4ӳx^UeVsL \fm^%*. -+/NSފVx?͏FL!.o6Ys6N=;wV@hjkŮ:;Q0:yf.ϭ:w*"ާ0Nw6 ̓㶾2wXO]HΟ@GEP0Ü?,9\Vp^(nveB˸PH/?b'ˆB Bvn*`09N/ma(]Q'g~9/:kzxS V:ՀrEZcmi@ӗpG;?MZ WG=p\{.Kmn~p%5WXS?ۧcO!x=7CX]y 9HF`*W\AII F^^nF'Y"d Bvz.[?;9j/PLZ\-3-b եA23>LnQ<|#sU(]ټt%ٰ%\?2xXʷ%gaݎCz(oe%]RO-͵/,sdss? s(w 8*5'@&bfL`a|$䙨th YBmۅ{]+HݮD 52!\|T/ZeRDGJ2A(.Ɔ0e SU 8j轈+ӊAa!E4_+AK$_QuֺMPW BMdոorNxPOwq iEwT2J">'+"v+\(pgS=P^igwK*ptEڍٳy(C\";6%^ a(_42O23~?CcDݡEXrgJM1gL#Nn¢hy{[hOV9]^!#KAR3~Jٜ'{d^pR`SN;mj zC"\ 䡄}P .Ch*TD)޻ ]J,-}~iYNl5_Q.pqz#׭ =k al@' ƻ]?K9J% -R"Ơ=) *\#2cs>{7%~ x^lL!ۮ 4z4Y?5aH<*U5wi/Фt|wM;&nt[jTj-IR{B_H^dDMŖ݆?uoZKr?f㭗zM H%FUF њ]eȚ݄; $^-A9f N5&eq~2cSW@jv䩧U;vt?MJu1{J@$&?υv8[WҞ;v1rwŊ7y2ݨ0p7* lsvXEK͉6EKkT6Kݭ eڹ/Lv⫫mqνKws4a϶'],}恶Ӄmsob;H~m)>yLk$_S'kqK}fE\IgeJ=ZrBtDkH׮]~d'_/_O+gn d"[5e+mn,W0*n NWz" Yzԁ&@2UouQ2=Ǣbc.(JV!ǤYLWuUv%Zh)nLIEG0HݑOoXkFJHXv'R֤PrzeIG#s{%\qTHcGba:T+c h: OB? AzzBfY&P.ilY݈3hQ95y3𪕯9,R#ı9 qe.Mr#}g4E|y_$"ǽ;ka׶OSlgn={Q^}7[_f?=n<{蝢?wF5>֊;mGIV5p`o?â9L+6[F[CqI-z,^ZA+GGmd#^qw2ZtD:BR5կusAaQYllUyN/{ Մ7EPiKᇥ:{6i)fj~XSYk$KG4x^k5>8~=xҝa;YR[Pqٵ[=PjLCjYuZNqiju_j4*gW]I柳.Qy5!AI/ta|fJl I5="S>'tL|ga7-l=2ŽB wQ{_Dk:-N*_L5޻*ֶg߶M޷G0RO-+ 3ZX'7{LKj/'ST-opy¾ Oxt mLGlEWѾ a|]Vk m]p/qc$Hd)ʎfi? .A)= @n6&Z=[jn@ Oeo NN C]6quŗΛG_˰P@l'8Iv7|Wm?[(YCosg7}>=gEzigsvX(R;Wwصޥ{m8W gp_xH&7([ꋆbLՍc߶J+39U 1 ?Bm]|[wn[;v;ZGE]rc[G]bVw5?~n*ZAyf$%S%.P݁ $&^W10 %~9a6rDZaz> a(0=)+svug2/&tpϛ5.1_=L*]@ߴQ/i˖+A ^X=^R'J+`Tk\C_C?HEz‡WWq8\P)Ȟ-Ko 6\"uis)sRTTDT죦^^4#!/޷!D"N $ {tO*Sieg>8SWH$:霶"ij9H:iL'}.K`҈1Ns}ZF:(.G ئ}FH>H(}ϾMfM|35"?hy(vPzΠj3nGB[B=,{- YpNEĩȾ{ZMk^="܉,ߢ&'a;VTE ;>1{Fǘ3W/kQAyʘV'Tb(m!l<{UJ{8|̘̗??P*WuvwG=Rڷg Xjw оTT[Va&-jZè o=*0Lo c.1$NSt8[FR`[vcYvN~Z؜{$;b6A1;ylw??R:Rŵx4]=wbGܥ= QvWIB @J.A~yCPjCTXFGu k7Fy<ϝ*q$R1J@~U^a5<"Jʪ ^w/FW&Z*kɚE'q% 5wV\6yw߳t"ɮ+_M-nMFX}nvq<ՎWZԊC' =%)h]mەn,Z7,IDATvS+ˣv=-LZ[abN'SND#}E۫r?U7kՒ݋Q(gi dFNxҭOrXN,.C l{i7Ve\Z,%ٹGJfZ\؃uV?%LcJ4t[r}{WXC]_[Mi/B}T_z|_HqI.O$R2>X]G2PMj=iQ-z=-b]u Cv>XΨ#Я.⪿c<5ۍNԩYrѷO[ta'ʼn[閟b_nj/ gab'EoUk'>oIZ_-9-`}-mq+1?&% 5P8K\%V. nxOץ9*TUfnD0[D~S+I}'}%KR6'ض=TL88Sjx2NC,ܻZme여݆=}qחq뗧z*0שp6Zձ=w'Ro51]&0 ϩTgA*dL 0&`L V̊x*+XY(`L 0&`fYk0GL 0&`L ,lⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&XⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&XⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&XⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&XⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&XⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&XⱰS`L 0&rB+9̑0&`L 0M+ ;9L 0&`L ' `L 0&Xj?>$Ivz-L7pp馛p\_ 1ra=پۚ )-sk׮իħ>U*ʇR y:0;n?QQXP"r-cL U Wy}/\jgɾo҇sH/Z4B+(,ŋq7g; g 駟b||`SSp8O8X`ɃC`lOI =g*Oe;"G>~8[oHsV /ޘ_u=h;`1+ 9J4#֎w,JQւVq%wħ {c9xZr|gN+{8 ¾HX1C;{ : _f~޿ygо =p A'M ==H$}Zq u#t,ҍƾ::dn[kRRCG-( }Zq u#t,ҍƾ::j/liYHBG׍бdK7F wNVG\x(D o-ko믂?5ƾ[p-ꃣbT=͞A\bapW੅kp@{_ƓgS}_o^psVݪjq#=}&fJè"oMoP$cms~0kmHO&_M41՛W g g-b3&M^ħM9p]g2zjՇ>hVfFօ*z%g`X׌~yExhG6\ā2i(|c3&<<էgN;Z3Wc?`Ղ9F ɰY87ǶIH`|ܱMrGoyK(Ob8pLɷnq`Rh \bl6/J]BF`TZh41L-; 7,Q.D߽Y9YȴSY-ft=gE=/bM x ƑýDG&2g|(Ě_j2ձ n<' l@ѡLʱ#w6?Iydw7=#:rDR(gG)X=k^|7~ݖfsȴM^w/@v<:+})\_Ulìl#ƒ! K܋O#mX|v^q4U/ yv㰜9jBnWKX'?x:wG:k=vN};W|?n/Nل-S_>F`\ʒ2͒q7I\S%kխV}NэAR47U\񝘵h [6JdQEb>4ɾʜhg\A&ժDxjqRtS1}Gn|o'ԋ˕dW?Gw:Hs oޛ4 )_R6ռى)rL EŻóm9SHH!9aD劫6k39v4!sGTçyIo7[/Sι8mz975ɹە  <;;s ֹ=^S3a]"ay|Gq /xz:1g:?q' PsP^V#] 3"V٦"4zV^MCSx|}&r p0Ƕ{qŚ?5MRk(}shCg\p\3hܱSc*eO6cbŋX莞Zp),J]# !P͑NKO8gא+C7yơcKb.Ymx9 9}N>vg`.&Z73/=wXfNq|?!o}Y`/߳\ (߼O/Gt0J[%(!dvF@ߤRu{Xc?X,߶7 ό1q#beR,|(⡅O᜚$+)êSu7^ G-ZEw}HÃs|J^yd)O ^+X&e=#3kZmH}[|vM7< ZpCxyJ'} c)/C2#3+`HL ܺkL{-gNԩSP'8{Y/ё,/قG%u=ZY렲nxNkUȒ] 7aq!&=%dÞ&9EhhQÃ|-z Asۦb>/\OD]3CB`\dݛ(֭kQ|*%>C gV[ e|{^<)nf<ΫM*5Uj=%O[VxN|iXte{sT kJɜUXNk~RWBWQVo/Ʃ ]^Sow`nT^|7 D0UGY) J{2هVcp$ Rn: IӕdqKʐ?(o#=ɲxwXxuϭ8vgڀs{g/7lg  p(\<^pu+q>h !<~p#^Iz;1#:q!KGg6=Ç/%c^ jҔg[< \(~U߂S wdd K^Hs禙50g|kQuhU 2q:r=|ˇ\ 9/`E壵ߨ>>8Y(f̵dAJGߙ?(޹ƻW9ӱ X7IŅlKyԴHގ y]CI`0mʶ*^;o[+ U8e:Xd J%8 882[FT^Vd^bֶ۪ 2py *ֈ)}/$lY`{0{zcΜa~o (vC ހQ$&4ɳegV$QTk).r*]HH`p"cQ{hokC[}u~?? ~c/wN@$=E;y 48g z8'I`;rnvJ8Sԯ g@Sȷ37ǏޥIoKRA_5+>rZRu+D赔lyK>Y##bY(Z ̑7X0@LvWb߮|30r9߬nHEmHJk׸޲9Hn֮=b}8~tJ| X?ϙ!Mz88{^^;Ϻ~/ng2ޝ>ok5^:M4=m(qn%;.qXW"KܭjcYnV_҂&wXUV=xӄO`7e:GwE#gl<'XV" %0eawG%8xk2Ln_'M^,x ?7Ny"[_Z Wo"{[(pVue72w9{ڙX77ȓ` K4טP^\c,2^9<kz޽c{v{[77Ye/~̗yǚ= q݁Z7g5|Z[Cv?_|/:dd@WÛ(,*D>Z<5ѡ?s^u=h !Wqe*Qq!:E3sķnyޞm3gsGL]k}J6=U&}έFk;i@:)1o@!˪7/:t#rn_Bxߴ>5o>ϟGP^ !r=U>LcMF0UGGrxFs}b?  uZ0L6-CspkQ!lz(;$WŎþ6|bNE7XJOoWlȔOt(/Z(9`llpn-[`˦GuJmw9x^n:R)u ɪzx<ށbem.ƹZpWW[ K!=5 bY6Xċ{eːx> +6:!=6H$@ 8 ȖeXxy|qJ⏭Y;;ɔrf׋OTCD`LZOCĪO3/)eynz}j谵{| Nq> M% Җ~˃ uK>u9v){+2l}T0ʞ:>8uPUeR1g\ $IQv%aWrb\+De_X{gX1m$Y+Ε8_*|K^q OW~Qi;rŽӘk= :d:fӻnEwe5+}' =DE!2D鳍X`(Qq<^r- ܮ+'}w`IG/ޣp=?~\OR'TlBl̰DNޭ%lD)W[j9`x镟 ٛqk-+=_zڳߝbVڎ =Sޝsa<#AviHr;⫑ oJw'70Ɋ^Pl[g"Cڃ '+ :bzx. 9_7 h2|~ϴ?(N @ Hl{r3~kw >#*~p#x^x"K$|Vr$Zgݩ^ۿ{ _-rnw47aj@$?ykv#Ց{M ugop6%<IįG-R`<qWhyOwcScbl8 )Y =bs=Ok>B$:n%[1<wµBG ;#**X:jt2\_ _?z|pa0>V<,$@#FX#;}'\+tڿC7ޒKl-w 7ȸ\3k3pL 7/@FAk_>}H x=S84#q~gwZ'E$TUUϾݼrcȊ9d j_NNI6}{$mx!xGq{t}eoFG|T+looG]])S7G5ViW^Ejj*L"2Α-J׍[v;Rw[ܢ;{nI7uSi׮]c!F`䟌Z8gpNQ`N';FSxS_;HٿG]S;=j~#:2CXH`Pat+C1ھ,Ϙ$ƘZGAv}>wQND*a]NlNh#`X?`mg<uc<|#{=xZ.oRg  1 ؿ·cPL0~@$@$@$@$@$vaG Px Gs$@$@$@$@$@$@$@$@$@$@a'@v  @ Px17@$@$@$@$@$@>@$@$@$@$@$vaG Px Gs$@$@$@$@$@$@$@$@$@$@a'@v  @ Px17@$@$@$@$@$@>@$@$@$@$@$vaG 8n%׮]~L[Jth =A=Ɓ(ywDGU9I$@$@$@$@$fB׋jAե:x;qj.ap%#)p:cp)sb䉈B$@$@$@$@$0rFpx5]hniCǃO:Dph m,dZ ţ 2 #&ցؘhY%JɨF0r=["    0wݝ":.^l?Sp`mHwbJZqqQ nwxEtKW:8&h\$!     C-"Th46چ.'#)!"&$xqRˆD]7J:DDf7$qrH*\$ HHHHH &\M Ahko]@SK+y#Eb'!9)BAX8%/uRkGCŅ*%%TL0cu /qY(0us ooYHHHHH`(FC-mAX*q11مTn$˻ Og:v{{Z0Dx8dYtt#yw(cQGjKe;::&XZ>mXHHHHG`TYj/_ax(u2*֤IɈmbCTp^3bG a\8U MN C/xi\%^ڸWMt5CǯPFq "iAK51)5|3Fȸ$@=N b9ߋV7&;uivusk M Cjhf &wHLG||ڡ͵uԝ0^BLzXcc34îoxE}[\%]֑XP֋hq1$S&،N$@$@$@$@$p".<4xK[;NZta٧>!AHB谺~}c(y9KՂy2*X(1S:w-3geT6\xP[׀vNEe|s HN.IL}bqqw.vOK37ɗ  4tTN{%*HIUvV QnY]b6#mb*Bq <>.ĆH9j4">4U{L_McbM}K{h8B=[!    #Qᡢ4)ɌB.N$GXizj\d;uJX.7Bڝh\ ԿxĂh;Nȵk]ƺr-׾7{Ti''^1kdTv':/  M&T c/nO1E\-E-Q2O]$Z@2Y%yKvu(]˶՝K_EUkINE-nYvO`}N @DM]X'.1c"$DDѥdfwʘl2k"A[KhiK_#qmMHum#$njMFl`%N @Duh@@%HV#XP^U]ܭ<=dFev9HHHH; mzGu&6cf![EEx۔  TE~ I{U4Jfsٟk]duHHHHH`p* \Xph$=K|0nRqڛgd6 ѭ1]FJ93!66a^'vt{nCJKƉpc.$@$@$@$@$08w䃯sCݙ&&'J(eiVfR*B<"4oG0!j ׷,)tE,W\C$}a!     = Hs,fQkoѱLhN`$c$Cj%.IIv!HˉCeWpĆLQԽki&6!     zzc(WB7oDZE$X,{U|[4˹%v[L\"D_o;L$@$@$@$@$0tj.C!j,?I-CۊEc'2BŁZ1nV7 ե*F]Dhzp ^ՊWv Dl0q1XPm @ K-qN%AmC%CkP7(;+ƇS "D_*LCbA:^46iLGăt`6n\8fY):)rHHHHBC`TY$V [X5%^+!*B|֒n#\z#I SD\ĉش&?ȬSLDvk &    yxH*2Uh~D< M-Ʋ-W!uHWS<2 hhYfD_fr%,$@$@$@$@$@#C`T[<h.huXB$P\bϭqIxM>I%bD\Txw_&b[8h08HHHHF--qZ4 ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx] @T?ì,3싀႖j5AEMJ|×&I撹hhb"$(lwf߹wfU0sęs};wsνj A @7;X,*Ⱥyk?xòƷS:uyT*5KDcײ$TJPmmk/B,?a.NQT:٩PijdA^*E5- ~KoA @ XA<%  G?-KV>c_u_?r*(Tr ,A1Z2I;Fj҉X5OA'5&#Gzo/tDB!C A#NPTx`3L] E9nΪY&r`)AFÐ ?(ϊ;G){|GH8TO#Gd '4QCwpEw0ҁ2rAdaUUUOd#gA>F  h4,Iqmaq9@`V-N`os9XRll|NWe\v~]  l"R @ <Ta T0&qV'alg''ݦo5}]xFeg=3-+'x_aCFv[DZ^RH3 Bv !ѨT<`A)n{ |OWxA К1ΟJЏvB<|ŅU3^ roW!䕕'IiY\Gv}:7n:dtj l۹;{Qtҽ@a\i'Vi%jV-J<#H; ~0ah*y`l [TpzR 44,վCo^!L˺l;_ L\s?H`(> 9D>QW$[`myyEII\Y}_P#yH^yJ0Ϫ<{ΟL~^y&Upd/^ W͑m.Q[GUJ* oڑk"Z-Ne߷eϨyM 5!Pz<0 s .f˦’чK^GF\+@! %%eUݺ>BȫBN̢>~|-qm<$h'I@6vIK GFA!bE1eCs@$3ف gMC͡vyy2gM'N_h.J Rg+қ${x lR-h|k OOT\ֶ"}1x9e%UF&taܕgݫ05~?> 8~ZSP^P@(8\x T҅mZQ`MM!hp =ruvq_h43Gɖ)Aۯe] tAV%MT#r#"bLij+@6+"ˋ~8gZmAA:!F ibM qh` ƚy /{Ѽ/XAWϤ+sSB#"d 3&NZD5Z_G=`t&Od,J]5:fTnN+n-cq %'3$ҭmhAgeDJBgp<}:b5?XˍoEd_dq7}R-ڝyszƟ6l~?{Fc H9сE۲^KlQ.33oʴ1D^ D` T_BP˿XoqwxXRX^UY_}gev@@eu|mlG90@N"[g<kPO_h&ٰ<3J6CB.uyp$\.CF~BbmEV$TTȴ91NkU9@LRJ+K/HD*ZX%I GhnRNN(K+rVV+bRJ$iZ-$%GZfl6vB&+χUFօK% ac:HHvt062C["V%РąIڊm(|SE`IVM(BX#ӊӢvOYN#0 :$V/cE T%؀&XHUQA[hٟSRQ'I9DJBI @1r?"?:ͅsd3V 4rpƤe~\+^2(.MW MP X}ӎ6T5~6'9N2Klik)6>$ 5b6[%UKVlNu_[>Ա¢"㿟/‡R?ڔ2~x\ɏ{zժ3??_^] KF!UOU+W*+T'?pߘ ~לP|9v񆗼=(bKBղPݸ=ܝܔU(򛡐):kc`ƎB傼՗r046!֋ '#(r흗. ߴdBQA~ٵ.~3`]Ն8 `_#^C@S() :ΤQt~H4db9\%.TNLߺm/|(}iu6dTu%bv&;H7R=e;vE7h}`w`;Z +8:*JhC*2.вDYFx̊QS_"''Z|0QLP^]~g·qxԪ"g';^]&Y(HۻeYXଘd;-=uWTՉaygF>fA50O:ue[P܏N >+Ffcfo FFSoՒF-qD1Mi iD9#=)_/]'-dFC Ս9!="s:|%9DUe-mv<6 y\'&?t=%GA6%dt??:Β[D,D/-w9("̬e(!mÊm.GO}6câC`( x`v\dOYir(;7sČ}F=F3sco,zX: kwrU)#ș};7Vb )b[zPoDI@ILjFpRV剳 *w,r]F\H WcS,6pZ:#=0r]}Й|`G9ilͳ^(hoqLU7|W0>ld}JG𷑅<N42:cF#3I %׎M|}w~6恹siRiSoުں7?'zd<((MjJkOrZݬ|;{gv<۵sَ*?Y3S]gi Q_L!x筈,'—hvzoꆔEm10dI4|xIIX51 <–[ t.̇ l Yˠ('`ý m!HL_ybsR<|f¶ D}DlG%| 1E6z@oڼr6 EvK*$Dɂ!F-t(R"iF8Cq}>c/DXA #SQȇg$076WX!S(񫰙P\ o<=ޖ)U-@22 @@ # x$`bL4Zc(a8XkP B&b̌ Qj%M A @ 4 `4XSZZ g?AX)X(|cDp!&) +}y>!B"s:NEix-kgˇ py{cjG61dP``,A @0G0qOg(Jt1qA~E8=扷8߷F?ϳ~*| o !kŠ XRSZ-pPP`% SXJE! &z ԡ0zQPf B|ԭm)@{儀jrgJ1v42e4 l)ҤA @x҂l%g"}xQ};Ór0ĉ0?YNzS1=&D A @  cZ- U;"=i-& @ <'"4?Xt+T6)I(L7y@,f?. F(}R A&mO, s-Ao|hAl6GP`CL5*ЖߓB [xA Yzb]@P`=DA @"v-?h,q_ 4F AU+HM=a۷?a&sA 8 ~(A ")))y"&A sm0O O(Ў!f@[#@(& A EP1,A @hkL=~x[# A "0j(v TjV @yUY.K?yY-P8PeΩ"֪+vA=8-Jרmݠ[H*spssKGT-biC^O]\ϹS7vjJNQ֊,5[yِy*[t9O< GF9m0T~AF! [B-BT"Uˠ '4sۿ{?gjLZ,-!Ϥ|\ aY-7p.Z?$G[ri[T -Sȵ{gqkA6(ů8qI AFEj).";^싋~Ъ*S5"ЩϟVX V(hnN.dX+|x0?#g@8f1>j IDAT?0c}2ֿ==/QBYbl>iZ ., ͘{EEWviKc{r=2c6G@ \r[Uth%mg+`zOq( Ry; BbhCH\2LuX#oa.xz7z 1+iuc8\%ϊ{2ux\(doZ5ttκ%{is ?/"¬NA @h{H-AT6} Wo\,OB@2ŷ7}l7 uv}a!BCV#R)(~9ɢ7n:;Dܑ;u7Fnqhǒ4+RfZ,oe ّ蟑G-,:4v{i٧jGTkqv#@=J zj+is.?g\!>ʈߚ?΍=7_\CAKl/.>;/wԻGhީTQrOHua$a·'rXܜ5N]aFИ=`ў+>ߩ(uӲs$p,Üa%˽ڔqkRQCvߺq@Kk, K8>|9z9 ɉ=b?Ï_2?/.,GNH0: F*wں+غ@1O Ɖ P K! @ `KÌa"F@- Xрѷ˟`Q0 h7XLՄ#;JYx*V4tXwtZܹsvvvg$X~Kz A({c}7T3z2I _. CK?@@,q9P 1.ӭaƹTcx3ܳaZ1Y2q='ُ)i1]!e VaaTc|ʌ4GdWdi9LaT m^ pdHζzNHևG!gUyz(A @h44fg:ј1z3zU qݻMT`AM SJݜD*Eg$cZEࣟ/:n~bccVBbN=^2&L\^ )yUzj*3e&K͘1UZ=.gWL}1 :B΁zQUYYUC_]SN Vr\ڡb Nc#?qX=\ hJi0z,)l:q!OkknZFNQbc<WLT)Z[ȉ]LҤŁch-Xp Flr.|$ZFVEX$ibZRsYs05Gּ;?/1 @/^r;?YTb-Wau(zקO 譗cSK;$c>~^\qȇ >0QahʳwE.R qrphnWf'# JAxrp} ~×D zz.弼7AQDox|G]sq7 w\y qBOaIy>dBPI*w3w, b͔1#:{?=';cЍ5Џ3]vヱu>܅Ցo >>lTD @!0tikcZ' "jK-!˚`LZjviZ(B6!n`š|Mg?6,w/>waJќ0f≙eQRO&uzx [.$TR(pkC*H\ djyf-bٔI}a,M  +E.,x5˛PlU7tdUˤ5\3&!qr)vrS@$@{㺁#bPPir˄4vVAqR ܼZㅣ-AdVCeeP r#'8^r$ A fᏮPcH$Bn#F#@(1$A={v+HiYthR @ tbf95k{[A @ <RSSU*\Q,s\LV Ihm033s޽ }V ,X°+>pK O@o"lB 1phd2FK%ҵ_ySfc0x#/w+c[бcGCzD^|L}rNm/SP 0`w$T D~$B. JR`שQ_sA:3?tٻJgWɲzZC5|f4Y~Xrȹ^C[u>OzS}A"P&) KFAy<!a4~S:~PI eH$mټIAs.ٽ?h3Ƈx޽8øɓE=`D5eʥٻs4Nak_D3_jYM;>Q~I;õxV_|d{*r/w)nAh]ܮ}'pxfZ/.unM A @x4tj.ę"mHWʤ][7n_ӮW42͡ߗW Wg% YJ4NtPC"K&z)9`Aƈ?G DGEQYXd2GB7x]Ŗ{ xPk{*GWK*nǢDt]&On!-?*(>A 4"nhR,X,P& BcaRK(]~{Ӻ*g tv\AeC2x___>};䔶3bk˾JM< Vݹ*p ~@owPR-k'g_) KNOSX7%g%3lMIE8r`E.)ksa7ToK]+W0XۍUjTgőbFJ2c,kt5yyVмL3G 'G: ^ ʊ&7PH ~E1x10L5xU^`M?_Ԩx2rh @ 4Z Tw˗/>}7o޲e˾}Ξ= ÔƲS U8v~>l-6ofgVߋd<;VŇ ˜d&#Έ{c/)ԆJJ|`,e˳lB OC(0vgv/83l=Vhřpu-8lgrJ+V?>%.%g_.TIoOr|$}aҲpNt5-G:y>Bg*hK]2pZ928?aK%x`J3zi}?ȦPe;G`vrc|٭V,*L$ŭ^M&/6Ǐ0W侘Sr0H30sQX&.ɇ3Z 7Fڽvƅ{ڲMe>sw w9_pT5,p$*;yVR=>v拵ڒMmV^I n߾}8-g\ZKCO-ɳ86< Tԭ }\z)߿Xc\WP٨C='˳\LV!W/ (I(؎ ̴B݅!%}T~ jwȥ\fm[Ց=3=:@wg<߽ Y@ uX} ?غdHb7>_[a嘫6߅`lPUpx? N*;eBߏr`JI~<魝(ɮN<}Q1v\e;p9Hvx(΀A \V{3wqY"^ݥnN~~~f@;{ ~cV EaSlUj Ͳgkx3aPPݻwa|ݽG4$ e7%+Ne/UAi QY\4tO r#_j#,' Q?neabU+GbJ$G(ti+Ջ,ΥC/p `,-a1I9b8!Ud'^VvLx~aAd,}e#%910uJ5G2dbiVVg"I\ۻZwG"^'Þ,9X<^<nׯ qw ]d,t=9Y!s7pp(q*4+\ϱ?>a|VXPAQh٬U7X\ƅ=B7NJ.ZnUZPj4Q?eɱgw!46|t,H| Btf ؅(̬9r:Vp@:_#(IiUq+8}q/hC 3Xݸ]/,;E fcI Ff/i!sB0%9p=BY"jSǼ3R`wA=l߾/ ^b_Aڻ+ KT 4\VMQ\^xBxnDM%xfeU|{GOJH1D2^$5Gm 0oXߖ %eu@PuX koMt/wcF3QG9)øPŝ s ,ٵ)p}C#X %rHH\5у 8x[P+cgaVr:÷p8. *S`zě7h[zEe~\00>,STFu rH @ 4,M {^D_AA|okkhoD"-3Hd7&?~|̙9 ֖ŠSݘ4 i)+ O*?1̋9b|h̼o`'*`t;=M9Gw8PrLlpcJ"qm8 #@GJ S yWB]NN3e( ]L WH 0.%7Ee7*%\gB #l0'1vf9o3n\"Q Xb$[7ɕ Q6Yj 9p*ϯpX}n2pS@^g#XNApv *dD̪d "Y<6:^z 5jA t-'Mڏ]Ĝd`=ԩS^bYY)j-Ki??}n^ɏ&.yoYL18B1q@)uX eJxNMo ZGVgc,~tI 0 (G!B@Tj1)) eD!fA R—"@Lf[َ'#a\()G>T㻀VFtq̳ o+X@ ml}<6^a/T z`C?>i!f-KSu:-sU>[Wkk+~L}CFb).-jQ9wtm{!@΍W,+Ba/eiy68 _GZ zEeXU(VB$2w%\ YaݥAJ3FhO_>8Q}DQO>g}ӃE 'jlW'}RP-Bl>2qtl}Ը._5^UJCGkJOS È{g ⬔4H_++͗UZ) 1lXur#Fa<ҨF%{΍zMm(RPiW Yk?!a-X夆-snOǍBR]ie.&Ӫ= ¶IneK'ZKg\`L9s`JOup̈́K'*f52;{rP_?69GVEnV]19jٱG9NpcE߯;{1sAfٺtRC%M@? Ka-ml8663Ž uw?8h=▹4LuUZ ~ri`PTG#vqǞnt'B2jMVzL̢N=Nv6%>s蜲T;9PE^Β3zl'2_+^/*4gvRyT6b;Uz ];y B}8Ɇ)B{ C/Ysv126iT`grvVey2J5WX@'ʸXuO@G9eݭY)5ʨ:.zszŇ hSNTtiTNH:kg5vř|@QGn<3 _y?P\n'q&ܩ$8쭡VpiGeRQs$c vw) ̠ {[ZUֲׇw'½#Â{Ή{wW5B\<S\{# HTlDaƁb\ F9^/+Lʪwf/z1. q4r s繢;_ \{^]h%Sk4%9./> '굱1e/ͷ2(3䕐clgPv(Js wP0vNV%WT}&$~Pߓ/{;[UPF5ȋӈk.51h*@W Bm``A8h^ eǻl ;ȋ`\7Pfk֖MmC΃8.ġI'f"a ab_lN u>Fݑws"1wyXYH v1l5WOˀ |G^T}L l `9*4;k4 `i8cLM0T#B3Kcz7]ZM@k2tt%Ջrǭ+Pxm`aDE)+Ub)]AIBֆ[ک$s78ͦ[5 /?˹pC-z Չ, ]?/7d:L0gHуsvr^L9c6D*AOD-Cz5oc9DXCy8Nѽ~V n(w4b q lVoE蠑[h*~BǡڭWt{5pe,p_poXݥ>$ME~9@xA !Lң6Z<;/ˆ+PO2d [f<׿JҺ[›fawӟVEQ+1[;=(yaZ]RAVCn\eqcðIKL97+:Xk!^ 5ƹ\\r·[uHv@' w+ J|TdfސוE۝^~KzwKwpK3wUY97})KKIPnOձIΤnf wqttfMݖQ`$(oi9eTw:S|ggf33L!K] m7,0-;bK80>lpӪ sҋ&W~#O;A);~}u#\vϱ=d]I}%c$clí]$,\4QzvZS>`rs}k$ Tw~~j'F8.[$WS{\Dw38|VS0p{T;Ma}w+j<Ǚ_^wY5j9 &ۺ ] VynT?ߔ\X_Ig)~?: I Z K>ejSx {}MåF@߅k`܁#2|ݭz)P .rEa\== lh*1ulx;{3ǜgTvu1~q {vi&ئ/`9S'nYڹυuP`]+ew~]ub8Yݱ;nKiWL|}G~x 5[Diy_n}*EgU}y[2%NWebzRzO SI@?/ؕVjݝkwZru ٵKg"NH'aܐv_JN1/}R`QK'r<`ۍfw=J椙݌7F;\Z"Sb WλZ`ǵ" Wœt>O_x~9Ls 3r _ @onɪnҪ]jfrUdI:-{gK9ePGMp,aߒKew:5@!d]|+Svb'm՝0'?]m|fJpLL݋o g!]jh`XPk9#5mL0|saenb@PQ+.5i `6[R?pI l 5`f ٷ> _J\RU?:,Q?k=~#K+'PX?ŧKBE37\ J z9EaUy]=O_2 qeql2a9$!ݯв ,hu6K;U=\YF*Y{'V_e[(zW‚^j,<)mY5+-1+E$tvdX$Ίōo t xGw Gc Zs~5sQu {v)ﱫU_ǍF?hRhI4Zֱ),x!;Zi1 4cKf) @ O,'Nm0-5,xA ,/bi Z<AZ h5k$''>%Kfyt9C'*M/в-̽{r8 XJ S̶F$,vQM _`Itg/kx)yoAǎ2喹2yə'4bA @ %-/^/0T/X2WJ߶lMdf uW㖹Tei%8Bwg-gM( MJ\;rWk3iP FpǖX/0֟j(;e o{= p2[81-s%#XU.Ak:BYLzkZ</jH \.r$kdB &iL.b@vLZ_RZ f*~M,{/x Mn)}@eY` ~Z&` "*.{pg=_-s<9;,qjW#A]sԭ qI ׺YZiuiqkCJ! o{^sA5hv/ڹ46W5+:2R M.m{A[)픫W˪]5*崲M᫫öEo=hڢLGt )#|}&2>^sGIe.ds Kϟ?e.DPL@ن?§mFS[7U[!z,/k~`6BTn!Q HM?RE zxu"8Ks fŔxjP 2Dc>>X 1P NUX=p,Y]qˌ=Yg]ZxHBR?NiOJQ8$=RS9٨`KHatCeHr25UDa}CBC[B僴.TUlɺk㢲Xq^ ^0"d+Xup YPLhY*|b#[䬵9^6`6,p+U#v=b~Gq`b*%TAg׆:2cFA"\Xc?J/=ۜ!+*|UVtp*h O!ABXb؞*D<+[<&Æ𵹹rY;0Up  YXn`fH`[0B.S]ڐփ_ g6Ua J7,ZYȻ 54 Dgx!55m,z9/dήxhJ̝=AQwٺd&濑.Ӥ}YHM11'lHXI*5\dMF:2F9DaЬAhb1rTX3w.vTd "JuFPjBRr*cm ty %Foė8SV%B,Bm%(]'k-d K-[ ´F-=ReN lkanY:`KlJjjzm2F1,PaD\[j䨮EFcMe%Y3* u ʚD<Ȋa&:d0A&P1# tdPjAbM 5 UFW [b uF}M%[M7v}Ij #^Pa=̕j %Lc u*n*Y7"J:' ez3Uꓱѫ24e`4uNo-IOeP#oցurj{lu()R V΂aW'2}d0Jtۈl-9GFav#czxβH5=ioLv'DR{.jQ7x9y@䊘2Xb5E.`ML[EgBa.'K*]8{`#=X.ХJ;d(Ϧq/indWd8⩚Y8YCŲy D[~Y 9i3Ts ˞:>ъ@ _iQݺ-Tg@ePUX4P掝6}W[H`?v⾔sɷL["GhXT* LDJ)f 2C C^x#TIQ"/!Pt^=|OLz2׷g>=Hhr3lbnĔ;_΂x{s$·Q?{TN '(WvLEEUURw` \Q$B1̈*Jxt=,}ĹuzmE({^5"iLUySfy/ <}T{5W²#3Q]{^< ⸆y A{=TRs.z ]W"1Ahќf- ֢;[V?ࡐ&%0 a8[eZ }_ 7ux g/VV#Ž+Z[>>f0k1ucgrU]8^ ,M9\b:K[#lݍgu<ܮ| [ #{۠U>jbWƀ6_ b@i,N{'Ga5 ^yvFjIspO2UV=r{rGUlҶE ƥ /468Akko^ *<󭭍?%rl2m8ؽu&Y0>^TxƠ]^ &T"UoԒ[~n!p6./ZKRyX%JxKϺ+`ua>5ֺhI`UPD] L'\`;UdL$!8U2&-4z Jࠃl&IYr ;CXB>0:~d w he ? ylu\4U!kr# ,$2@,T&; 5qkޒ'vm`c ,Y7P!X{'Aj Bnr`GȘؖAb+$%8J6EJFϫ7Rey1I֍yvLM @AÙ d聒L+y)oЖL0o*6ԅy /;^1_eXy+e2Ț ~x9(*8oD3ԭu鎴 Ǎ՜'O !qA!VG㶐=i$j,F@^>#,)`W.G|Tq)cŠ[);|` V(ew>(e.hQ9ZW9 \Q .ۙi)e.a+ŭg4u.x8H:@Y ̽) +h1,2ڈ (6(e.7nHGKLC㕺MFpRg§Bc)e.|x,/e.b]uRR\J 'ns7N"(eit ]c'g?N{za^>WpiGi2@E)s/nҬŁWfhkN4}s6b;pG)s)e`pDmd2Wyˠq?_aϦ&|<]iԗx}JkCX^7 Qӑ2فQ2W92R wt G)syzQd!CMp~f3t.l|8)nňpKue*N8.{AP9#<2RR\)uSbp]sw14Y.7Y, Pjg2]65ZLFTWS߹sgjG{2h1o0e^ |iR\"2S\Ɯ|Rl2} 8c #?/T>QLN;BVr-)0$1暈w}' 'KǮ࿝ǒRYNJ)s%i)e.عc^ k׮/?|tRkGwW͵KNn?g?C'O?~<'E~/Rr#vKJK)sк dŔ2Dl~>3-̥G Dԩӈ.V]:vur~tmd ۝\ _,rP\>L7?N)sAE;wڝmEEEKiQQ'tup޹cڲ.ԳC``<7J{kuR:Viwe_Ҹĩ# ]O_㴹Åjt<۷gg$^/rI_!nE"@Pn:p2^i0O-:tڻwo566mrs2F(E&"@\{.\x"$œ[nxJj\ ̽MP(> 7xf{]vt"#Rlܡ Rh E"@j]@+={`3?]`{5ԝ5Gwo%[+~.DskuhCF(emo=*l7Bwi0JH ]xZz.Qʌz4أjUgw Z[WQ)8д;o6ܝNY}\aW?s1:SI_s]6,'"w=UL]ڐls  5寚VRy|ClT0%$ #fړVLj9TtÂ[Ys*2A|pCŁH͂b ) 3nI[@ p+i(bȈ_>lrmYMH3~)*H`~Gq(S:?pB*74Í(*|b#خ]fP+ >Aš$|GYɊHhx('<+[Ugz, ƇˍuMl;~y{e(,׷B\K3 RV_Ԙ`܎fl[^k o|xCJVsd:473r_ٳ gyT.K/m)u~=3"EyVR4u=-A<{u @oҝf4|˪W3}`\ {F*Rz܍T>^J H.~1: !}> s %jԣ/ xW&[Ba85ŵJWVytG؇ M"#aFG[, 1{igBh9sqs. ׫g~{"4nܜąϑAcZĔD(sqd ?6_/XM|}{L D~ы}*Dvtbܼqgg(]7%*nPc,j1+^;9'Yl$1rbы} o;N~WԣS4W1^>^-53~tA ?U⋡x0-VS۰ #wYUbQ(sUeIƏ$f O0)1f"~qA_\\ .9S@x+&3ܾ"G b{,49UCm{lR=saPFD]|πIs.z^ug,,Z9&m\eP#lxVo?gxU4R;Am[چ؀ZZas얱aPw,PL ϊXOn9m6#rvG`9 a,6 bTֽ .ֻR׶0mH`_mV1P -:1/1M-;JV,#Ò6.Ͱ! 8Ch۠"M@hڍ9 x&)11X~2+ˌYpHl++XD0 3jSm-Byx5E_2Sar} IDATҺ&ܨKd$>e\uةxeo!2 v} Hl%JRme` I)2N;MNn1I^[ٕTi"gW &d=mN@}I&7J28K~J I΀ ?KT.Hl$E\Ȃ7^{mdb1q8ȇyۀb5 ."g2,iI,@Oq68qẐ)|Xp_Ï?a.xi"YŭXskE]^!a|v߶ 7 ѯg]2~uhNh׿r^Mʛ.D+=P[S ?[ 41*ViqA mqy䴮Vrlmf洺uW͍00؞չßw1߄} Cdb c.T3c119ȎΫx97Y컹||@ eB9=$ODcB5 5B k^( -&3ޭD&/_'ík816qaKmBH[f(i%Nlfjnۭv}vlx;e7nܴiA~?!lPt60>^sGۿ9h3F5*!M+E?&row/Dgiρ [4s_Sd@V5$REtV6CRX5$=K| ExpJDZ ϻ-VNZ<Io/*N.CΌgɄ9_Ŝí Nz^% -DOu06t2x^wZ5>i{ 2/30T<^ⷶ|"pPx;OO>#ɞ ?hg߰T8!:Epskhr֮9 E#z{2$Esn63->s+ صEMIHO婔T (OKII](PWkTF ۩qYބLMMM >;2,VqƲT8Tz*ge%eYZTk4TVrǡX[R$D|z^#l$؏+ %aB|V7 ;m`<9[T +/^V̈́1vjZ} Cl۰D؆-vubެ#ɣ@SJ,%[~8ENw3fe)SvdRPlP2Zq>fF${8gbT=-{ z:8b'֣!( 2|E&N]=/2P a{PCs Rv Pq(uez05xloܞJR!L",Y1A3^ǃ/b0^*hi H0fѸ*b%z7turu[ʈ qy+"UmC*,$X[2B"V`eAŧeȧl$$؏+|.PL4rn:zO(M92D%|G:d$fW~ q/a>qڟQLθ@> Wjϖlr o5>Sβ(&p\k0 40,HBLP\[R/Ln9U^ a71ŀDxe3jrrtuZ*r,u%%V#EHtq0@ Y)ǬLNVdu欰Zh+<,/̒8Z혁138I& >aɕD! Kt'q4r6m 2(&#O[5kE`isGpvg ZP64+QRڃP?N\+{:Fȇ3 ,Z=5'VBY#Yl1%}>n /!>k6f9jXƯT-\ۃPY3m] 3Dyn3 m!!ԏ$3Av,HQu>.l&b1K *PS@C֚wmBن=I}^ EfALj-IB 'k<+b3a\/@`Ts(s0;[[ryц/!`Cc x,5+g-IWbҖV?1nJֈl$)j&PWme ?>)p Yj^Sh CLj,c9f! F٨q !.Qȑj 9#658(olU%W>\nAy*]OSx ]@wq/q1 QBk^6gB?f{`q,Kp0;ܶm̕ >&Ig h+`|(Ow{o#%.v`r,Ƶ<0'ăc) `T4D9%E"@PnqN>} B<-BP(3BoP)E"r l9V4'E"@+{@3ѮGCP(!WE"@BݝT{E"@j jhAE"@.?=E"@\5aZ -HP(5Wk6̖'xeysqUwliӤll~ͻϟ-9dtHP(v|wvj Ԧ?̮>sf\;zU[DHb 愔]`YTxk^P P(#R\\._@G?Dgr8ݮm>w z8GX!>EV+ 祏wI(??o SR/H#EvD\>B`",>"m>OYSx2Џo*yt}[>WB`^>e#%ñ.e0+r⿃/_ڵ=t+150T[E""}.Ocӕצ /Lr܌7pLl!b,f0upRw捅d3mC,sGW`h!CvYoj[ׄ'IXR0Ttxr(dyy<<[91Xcw+_^a"d1b: α;K0W],Ҽ%$),`D/d2<8-gϿ!nzm[l>^yUhRr]iP]B7Dh褥ݞ=ax]=񤱥W`&/BFp,y^B *hp?MNp~*͏o<9hɖWUM&p羉1Տ.-Ѫ}?TŃC苂""G\՚VAE"@prx3zu`?-OKyΛ?i\Ac}F-G8c?߬[z>oO]}2f~7egN&.gX27gf.ډY[8:ub.hݥ_6IJٗ~^V/[r`BlM>&FtdLK r(r (w}_Wn/?i@xA.+rw 勤qE"p#gU 9ras]LL?\v?ۀײL#_<d_eaK''V_]ge"gX\MDck޽yk| <}#{_NԤljI\ \Ewg6 ? %GSd$׺\ J*HJEVA<7+kSIHOH ~Og} ߰nϿf4^'\ct'gN [LCuu[ԙnmPZzׂk½Wo\C#E">`VP(E :ޢP(uwi(E :ޢP($ӶQ(_-vCIT^R(=|n@Mv Q+BzIze9(ypP3MHu}P(!@]FKQ(mu}P(!м l?W]}]](TݩFi 9 yEh E"`Eim`El슽nH!GV:M d@XelJ.|70$d`>+6ke~iHT^R5p篎zgn:'멖837]y6eh7LMJ/Nx/ ?M»"pCp8 l(>hЦzs_U#t|s|'[c}}՟7V}~ +}jo%UϚ5iRf<]m;wgwS'%|}cӋ|;5՟GzyC7q&X2Y'@ [cg}u+il~-;k#6UDzn<[@E6Cw^=C B 2 AQdR`NwAWL%?7"Q}|c7€k'B>ndMz}Õ*c<ޫ`_L+*o,&ˣ(JbձZȠ#%]vO{F#8+җp}32sFlTV~3!8.`5KN|rW-; ZϜ9}yzGǦϊ Wú[b|M ͸#у3?`Oښ܄YpV%mTTzq%:"dPTM?dEOBe%{7ptf'`b+ϔq_P{tUOcZz{M=(}ook'LK7`W2|ږʊiO!d,\;_C ߨ!0 !/x\"z ˏchh3/^Qo7PO Z^]؅Px6lL8JT=<^ȤpLyO|]T}bsf뺕/dGޙp('%(~>KFmc˂8M3'v䤠"c 95>[QE*=[~Rn#` )G:\ 9 V՛>@=ݺ!#tdΜ`< >=`qλz+}cmEvAuYs(%S(c#Zqhe3GLN'}:^pr71"8v,h p8 #2WVbU":tre7HLF #JrQ#aVtepl;(jKu%;ۛ"i "]9ξ0.,bSOs9ޡܢFԝQԍxO46{E :7n\@b3cM0"1n" ;w~;c# Hj;2mU ˸r'N #8tqhEd}v謙g5%ڼxQKpL5FOj泤EL5jHnJ< 2v}"&'ޣLC'RP[K>W}N㱷_!țlyreh"p Ш7):(z"m<`6ht}qIo-qp5[&HP:k8xVދ `){E^0{Sߖh4]q$zP}a_1$jQ"4r8tc 7~)+  F@PT靊{fT⯑E:vgw!CgIZ?5%N,"h.-'yktH?CltCwzt~o=|rxvDT4^70jPi6,E?md4baj4n,@ƭWXn ^Oh6-Oza ~3X|gJ/k')dcF[(]ae֎AXúӻ!y>oԑuoM _΍g#a@UcLoaE]Μ9é}sl^D e7w낢N2i?4:IߞcL{\ih`{ L ۸(`kK$bȎ ٯN vrᥰ Hɨh#S!(423@2є/TR/Tshh ݜ o7ݛ[ _=kA_X;,qE7d7٘$ T,-.D);:.і<-"63H9`rykZ46Ν J. )E%ԹKWe QVY#"0 ّfdi32ӹUM׷'Ol rNhu`W¢552 x"_sC Cqnɉ_dH^_cf2-S6쓧m7lيe%wK\pzLx ].]z 3BBD lDZ/Ká}{Z'tWwwu-EȔwԂK=WtP9UR{Ns7nլ45P ɷ=!y~o\OrOV]{wuq厫lYey]Ya?A"xDXЩS'RZV ӥ:ANZ ׅ(qVX1͘Zpp!O&22&u{xMQ&=0wtvj [aqٔ!\п_ 2aYle`i%dL̼##qq\ ޶HYD`:S2O\NRUJ™y&G 뗼9rlѣV)%w|VwZxkzEyJvܵl=bh:ϿϞ؊RRo 3?nkc<'G7=)<;?evS|o9vϴy>{jL,=OSd)ڟV!ZՎP&Pi4hءп~sfca ̟?dole'e\䎅+p_hH6[OJIXuЁ#/~;t5N[F?GMp_[jo?8~v:Xy#, $$$ M-\㎕ol>֕a?37|:+ `-\e !SG'|< ߱c/ aaWFϙ>]\HrʔMi'|0NVFƩSZlN'lETB'm5bYOdM?=[wB3gzis.̹sΟ?ol ۘg쪄`>^l촷[E5A :2j242L9Ƹq9ƏG #4QfpT#)"QC(]^?}ڵwuy]2ҹK~my.:BiYHmOuAԱ}¹5s Q }K䙣/Py'NP\}&pn~?}*k1k7_lٲodl"!VqZ*2{Oܗ|hﺀ0Mfv#|iޅSP^jRIXv]t|x'E\mʳbjÿqF9 >5aGw ǂNI%M1.?Gxhq^ϼU76Eb^9Pgߚ[Cgk ̳:ǿ պ࿞`.56u OjB8B>̑aBskkn]=Q9*p7cXhP5B$qSތoFG(>#WvLy`&gMx&L@i(_ (Q OXZ:`_X~xkNG"KJޭ+(K,2mkW5ěiql!3sM9%ޤQF7QI[%$$@)oП)I#_8F:2A"3]gifv8z'toܸqUՑyyy5tqqܛ&>eɟ׮J ѠKh\炭sh'!OradQ_{ ĥDÿ8plp\@ȧ~e47U*Dp̨-B=r-zឨ&vZ( 9_B_Mn} w9`+o0fty6~Zp!ny}%zˣ/Vέiz' "?Pl=z5ܴiQUb>6uWǥHX p_j9;~E3ne7!{K>M:zDS1p "DPs}IYG-w^c"'o8#^xo'LB{$ @/ʕ+L}5n@(, ЯS9T]RK%mZƚy_>F+p"Y|Pw5c!\6̮wԻ;p]Dgb~/{>z_"&Cr7% b͠ex}Yr'*Ve5hj!-#<ؒZҋR㡿vrUk%[_.Wc@j4wbO^cBvAW;\nTE_^?M::`~GkFKHũWz/7-"G5gFq~xUdnz9赞Fi%UE1sYC u ߚ\3'#Pe'Y5hֈKzTBӪ;)Z9Er ~=Ua2٢>#?ZV[~` 6‚y;wCBDbee{mmm!I(uk>h^s0mŽ%SYێV};{?3i сK+_Ew#??Wa9G i8e҇ I? Qym*v̕;,iS"ٴ#rTR!c7%M7bӌu^0H jp(J>⪈ZC=NO*M\;^I:<7YI%Wdt?b使 mMtkmco:%ȯwKQ-Xl~m,dIR'adl/E*X`0:/E}]S^զ2,#a%xbsKXlu#Xp"caWndW6+չUۇt<;[!T!JKp wC'/|uTyUA;yJ=> ھ8-Ox2z۰a}$ l*C8CIO ́f"Tұ߸8}!IS J. R"ZQ*bRyPYA$Q:$L5nfa%LN||`B'g!á á!cZ77.:fLi/HI1Y, IDAT2&g_eXrc~AiwТZj..522c>Fך\4WRS\ 3m,~$Xu25+M!!(?26'?ۇ3\c飓ͣCUC珁dP :2 ^q\ skBU !? 0$j.]Lﬤ?PSiN'g1\ɿQFЕBۭROdgAE5FXQjs}]Sqoqރ]G߅tztuD𠄩DJ!lC(+soMU]] Θ F@577b8@֊  $9Bv E>Iö;3Sc9/B~3g|t]諛_Jfyx\ELERbJh= YGK_t[1$7@fOC(dKϯQ9f gg.>aQ?lK#%9 !֍ ěp7( :K53hB{SgA@U%bk3&1..Ψ՞0Ewj;SY#E֦HڱĴE.L-:*A_ʃBa~ 6cL W`^&^"~{qu@Mb;KsGiA< v+@D%,$ o:A>ȝA $Fp=(!a83RR(. 2+Q3$Y"5\d*65Xdpn+LZ8 Q8/jU $ՃI=(#JDyި68歁{J#W;K:YYk+VVVq~ٍTgI@5Wc})9͐$["6tBt8ț)B֊+&,I!HtjC] $JijjR+%Zͻz)/EE@x:LFFH<ӫZVpzbkEg T(5o믿"OY.N$gIdod aYnP̭~95$Md$T] 3LzE3(@@"v4 /`"0A48 Fh*05ŋP`u"^cHCj )Ծ4FAy%1DE)!##2q817׺b<%5 K,D&R(O 8StQ# 쁇#ѐ=jD,$ֆv1U*G^MkK5S\0x5n#CAq tM4ȆD9zW,JtX˗%d,ü,}y* ^(xBoQ (E1:1Q!` Β A!ȵk!l?BO\EF1%~eG"Z,#?_?02[=R^ƈ+`b0)s""4?Eg)<6`G.l8ؿ6"cގoEk#T3nRkYmu  =jl`#9m`(CkSЌbƚ@,0UY$ sd.}ŶG纔eR:ѫw/sf#L[{/Ro4P %3ָf=z=BN4)m kxdCʲd)K'Tw}O]9OʦsӽrMHD\~AzkVM"q.loaG*1킺4 \g=fzb1oW3~Aw] tHb M&+G Eam(EɌ@,?C \A}g K~ ^ PBF&uǤ*(Sx&M 3qh*Df~07-9 eee7 -fs?pQtZb[tZ)T'GȕԤkյ`M?W02MBsiHz(s4ccus =۪aYPE3Ds "b=SiLJ;ihW^+,ކ4&/mdCFDe vEy bPGSaS/t4A:[Q,Ý%qUO>gIR *gI*kijLY65%"ʫ/wGJڈ|4w>nHDf\IY[﵉ NB:,i‹jב)Zh$X$r*}r)(L? eմdRx>R Ӄ*$j=M]WSӅxMJBR@\kUV~ӧ_+eg=7GdcMh<1<8 zO5™i` M zYڎ9, ݠ)).DlͭV^~%F9 N..NEe)LL>&k?Ԛ}o016>{RhF$4hgY%L1hY].%HTVF@(yd^#Sq=;Wo;O%)()!zb 6= ]/ņZvra@ebS qz7h()BW ϔwedLL̑#GNnEh#\xkV< dJ)x3Hb#P\Aa_+*-X>l`*P#LL&&3(v Ep ΒX&X\J =f0N?y%Nmqu>RX #ܻḿbpJ4t뾅 R4" p7%(Eney9}bSu_AH? aS׀}}.߁\UK ]r笒dh྅e>8uf֏3qKS0K|`UcNmÇWh-/'OCC9ۏUyAs' \ B/Po: , :KOY4ZnSQQ'K$jS |%VjiduHb%Q(\$p^E.K'@j[Mԝ%w+SҰ~4p8JF57;ŒF"31'"jblFVz"k{;GBx3)gr|x齄SoF Ư 3Y.lD0Vg}Wp$Xbs,Й&M9r$ԅ? FU8@uV= ^ ',VMzsQS 0+ 3_N]NYH^ɄVVAj ac1l.j%QOrnz$6ܚlyRP38/4 x9/'dOLXAF<;(>F~z$SgIyZ9^vD{trqYYW:3-" ڒyU_ަx8 FSQi.&:K{:P3Զ,)73Cpil4yG<0υ1bӐ5xBC9~GM P(E$(A9gg9޽{8!UWlZ"2 @*NHhW?ңG¥QFCZmlx?l@4P(EF>hP(EeB@T(l_w25#ZWE"" |ѣ*S(sQ-֖%P(_ bk'/TJP(vH_EOPulDH7E<7GP(F*ЂE"@h ϐ֨OP(E@:[BQ(Bbg ^ ;_!w1:nCP(Op_ 8n0i/L*"@PA9hL(-E"`GQEEE4BxaIkjkЮ, <湯;+H(7] -}TUUClu5ka!*,,||crdfFR^5)w5)cO_Rtk~e*sD,#BȊ qQaO,OQNF`\T F͜X|W,w~sV(;Sx8d8gG~qf^z4Liqs %EIT bry]y׼^3 B_X8mIkhꃘPY^udQµXvF2ӎ <ْu$OhO*sca"L I:-i+r7O+//y`nkkf0'X%ql၂% pTOKHԓ='͍̝wfu ~n#'3h)ž KVz~9_A:65, [jBDl:wA:7VNu7rZM_Ivi%E.|]~3)UL.J \NcsmsƞX3tHDB<ܪfAAZ+|o{S#]A TX3H[U]Bt`6/9U4,apI䶄g&W YZŠ&$4lJ|k镧߰Ѫ6 WQ +gZ0pȡy_XU*2w$ҖUM SݓCN'.HԈѠ$Sa,|Yo|[BoiJ"*KkĊP&wHTlV !qR~ǢGL&%Vׂ~[6iw\ M7S_4BsufJ-A@ϖfl t?7Ѓι'6Au89ي1InmMTKj.ڟq&NqO.+MKN/CeY)iiiiم,ǧ"mq72o4!^?=ˣ:*_9彠̻> ׄ Kb&U6%(w~_uQ޹.@[I=wܹs9E<߬@״U~NnnnNN1aqN?r,[BT^ÙNNn~lH)ɋcW9Sg''-rTS\GN%̻y)33j1xMA̪NNN됇^_D=9IQOyg8}-?`Ptf'Fr(|)0SLz1O[pfG x^5#EG3Z IL^b* gcH$Ab qa|0.,z!Kؼͱ;=ad{铛zvי粨~\}^mZEI۱% LVAE9soVMyVԔ.ZMS2ٟںxoxgo8l/ Uܜ3&&6IlMl^'߼{ u/r؄,p4t7?6˖'0k(die(}=/T# FXu^ eULz pks֭1%;@47>77uj{gnO=s‚ 'YCSek&&Ǯv w0%UAޫ%;feTvy(/5)cҮ?٢-&K?=Ucs;S&QOt bzٍܒ6wRs5v'6JIxq@߳xr@C}$Op`'^t @NOIގlu面;fhzz΅_SƳRUqo+Hp[G+QϿv:}I۵"z/KcG,P=ͭ zm 4Yu[\`|Hb!{ '4 8'H_1:Z3'5*."r")åLYr )Y9fW0/uj;M}ÉCWEض@Z!A0,'q#e_C7M f9qZaan6ٵ4%ƂP IB4eCFDe v E5 U P[[{Gu1LwtQI?<Ȱ:? ~]|deQt]a'r4Lx~56'Wg Q59h^G&L@i(_ 3W, Z}蜷SF"`4 vIV9Kffգތ7cɢAJOG"ځ(9D8p`Zdg}$=k z: BHz"y[^En7=?wS 3 glj7s$wv W>cbĬۙSk۩Z[R;qm{-NZف.4̦w>dL<]p H B66vFWy&"7pُ}gׄ\o ޸>JW\+eՀI!ZMMR)YwU'L,YtwQYpr)Ut Vr_r:~ '^us#Sp7Z<}̬^7f ;o^y7qnh;֛ ޵b$;9Dԍg+K0ir5A;<\Ju@X\Q~i-[z߻<ܺpz>w 9ʫ {^oGNt <[#૫''Bh9B<\=rU:.eFOX1?z\OeP2# ,ebĵvWbIBﻐ#93p ѡ>z] 2511`h:4BI]U l7DkDAZV=(<`̆yUrL/a@XJ#cp‰r.oyٹj<~J-ALAI #@O)LL>&k?d4~@른Wq-; ׏a@bS qz7hׂ׮BBo03H22&&ح=yl釢4889Ha~jA'+ nßNG$z~(WE0ۿc7zJ١QyY1튻KO k7f|ԇfSAVS@˹StaQ?6wbO^cBv H=3IIܞ. <WG^Y*Ncqtfť=FYyUՂDZF./,).&$K(-\QUIaO K\ ËoV@(Y$DA⠡'kx=\-<= 8 $OiTyqjU6ƯMQ3vD5B2Z9޺c-9)K~o❏ɯ84[֚S"[ƚCKqw\a^O[ץ}+(i基~ ,SYE*f Iz$I' "n("Kx=C=NB$εTӎ U8s<V89/f$k:{j!6^zL KcAc2q{8u%:z^kRqB 접X캀ۢZYVo ܻwO%'LbkGwWa) ClE ֊i~V6-  taD=#9`1Q]7>JvvhC2^Z}b duG0uBDV%}5zA)oF 4.Z/~JttԊ:0 NIط`NInZ1BtM ;t$d@X6BqbYR8h jF'Ad#z=~Жt[(rs5Œ_6`uŐ*T{mI )j|e {U>䝍'6rZÔcHTR2Wv 4ž1S}*"2 CÇ*Kܶb =a:vx6QsD*H3!hy sY"`@!&E(EI (`d>h;Kzj(CכGXLӁXHe422r]ufmld/ШM(O(#©$gF%a-Bk/ ,llM9ۗ=R^MdG-"-D`*VT;`(,{HM M"fq 0Ok@CKv׽<Gp. l#,mu&тA!жd ,m:H޾KusD52gzF-ng6NplQr~]:vn*qPu;=էW4An+0#8l#1AESzhI@ hHQ2ʨ_n7%v@f=o 0li RK\ZW9u.e7֐wa2h(=,iMrIШT;aџc~Gs+0\!Rtah{>{ΘC^WOx;~b#)޾B38WMDb,7"g ي܌_sХԔ И GZA4mq7pKA,L v0 G?|$g FYT~JPh$`"Ц]fVgәh۞S7r]RQh0;Yvd߆ʄTwpDb*U khjƖ)Ԅc=u->!voC;O_{Ab>)HvEk$AФp` ["GQ'|<ٍ Y s/lI?GV燻.x,p|s˴^pM~4EYb|i|n*xtv?E.ǔ=PKЎRgaڈ5/P➟_`GXi/]oeNЋ]Xo>J=R/C+$.8jwg& R8m)>G-A%И׻qe87m:`Ԏvԩ,{;7Д㜅%@5U"( 4vv0gk:3U1^*5cFKP' ѴGPU_2`92*4h c 4+JIhBeܠLkib'JOgӦq.!\BbCb $Z ]ٸ0OgN"y ¡A[<mA^4ά0弢iu) ^2!zmZ㮞7v', Lqax.psݥZLj-]aKiAd&)w~c  )- D@y]3*5MZmk V6#;r`233,4dFE*|E4YfaCPcZ*5eZɋ>9a݃IbͶGg&uŊ=z\guZ z^MuvV?uO~kk33&wWN؆zg>Rk2=IkQCm*Y(-s|sv։%zY_N E@0lK5`@(ڈ,+aL6V>sMMC{ل KN *KX;_\-+áW YZ=9F!-g7(4>կ[+NEq)0'jҘs12Xy̳f\ذ  Hzn-ˀ?]Lh Ep`ӽMuյ1LZV]@IR٪(2j{[gY_M I_W%P+u|Sy2MVV&d6}Kyw)JrO}w0)$潬ڜukhɯ͍=~x0v3;',\p5ak&&Ǯv wXRqX콪nZb:غskZv@e>RO;v,:%gO8(x.d|TwSu面;wMOϹpaݿ}*?>*֖4⭴Sy)Q.~(0")tZ sn׊!]<%sJ磿]D;y-ª|38c =y/\or$jCJ+**=kAx ۂGz:6`U41G9;N)܈`(KSdr|]/%%~p|5O24B0 ;,vaP]m LCU62YY~+&{li$XsDѪ4Bt12釣T o,8N+LYӂ|}ۜ~}~؜]ş_3D5sBS4Fk /#s?e&4/۫S>tێ SsG vIV9K3] QG]{oƒE*;䟎Dߵi-?ȤĬۙSk1-6=G ]k>;ptbQVƈӥ_ @&ex -ll,캍+C}=oBKb>x""40d`SʃbWEy'gN;*L<|TC?ʇ+6*3jX Nl $<;s3,TR.2ۃO th\]&^!:3}QNaI;OonK-aѣo}l-w8BCxkC-2Tlߐ<_ٸ}Fl?FQa"~Aة/%/ IDAT֛ ޵b$;9DԍwS9ޘQ^OnqEOdsEw(רhq\⏹P{ۧ>;ɜg7)'0g++Uy,#Do#ɿcj䬼jAU1I-JK$Iһ/J;WTUy=RRVWwDp'BqեEU089X ˥Eg u!NTX.),M<9J󠚩V wf4qEx(T1 c}WwⷖRYYy,YPͰLeAN^%<6%% [Ytv͈ţ0ZV t_̓6~-q;gc>uec*98Pz ~%'Y/E"Іlt]8oZ}o֮t=rwvv~W`Z!Tij'"΁#o5KkJ)aǾŐ迎X3k]wpJuqy!^ѐMџ g1dVzb6; [w>U3~hS N<3cJk9%G ;41s$S>oK#d;!y8>ҿƃfVlR=V7#7g'caI3BaLoH"JEP#Б׍^<[GG/ ͕J'ћ١m֢M)A.qAY3Ŕa_plם>s_vzecm>W^wRdG;k$V|Z \0Hy !)Q#wL # wq]c>J_KK+ü#-K(:v : AmS%&L/'0KUD;%Uڶ,SYEpKIf+88Z.2=P|<,gQMi:F^U%hv0hK+Oə 8t(TU=D:IUұJL$BaMtR]C횫]⩖bpZ,NP] ?݄s&/}nEGƠ\(4%ե&DUeIO- FNw@ncS$-K)2*3???2:p.XA*/n>nͥ,Ttߚ#Dv?R9Z,pexa 5" uB3&˦E(N,GI2JOcdn1SFh^~DR T@29^SCIO]2d4"@h%`x vuZqӉ5k0%, |<QcՇJP^$^غ["4ߧuEi'Т1OH-*"@x!hìuBkZ E"@@@ aygI&jvj VV!CbD[]V&c!VOdH"12'Ό*vPN!@oc YP(1=1 A5)PSYv-YF?6=R^MdG-"-D`*M7U(s }dTA]*5L M"PP7:0! @SdYQnFQm|NBզ!OdiWG: qPu;=էܖ707Og-R_ mxnn',߻wbSZ6AM 8iYOn%g4:iN2g8Za2N]-zK 5]+XCގ^˒$zM52*voC;O_eRWS*ZF/^B˭S3Ӿ* 7LϪmHn?{%:ě"ٿ2F#"gNk^8Fc(DI vB-G ~?wΘk]DZv4xpWx% eLe%\[wE5s7ΚNS muX{e-OSCeiE@ˌ~_ᒐl E" ALבIƾ3 b ᯏR*WU4+$.8jwg& 梔(Vy9ZJ .1w4)d[ufԆ,:uj*'Z2aM'@t1:04n 6uMM`L9JKxah{ [Qx&} o. D؏RLJHɡs*+eL} Nszm B?TL Ä&, Fac{p#=f+ž&mϚ$Md8%}& oB~hl/єsTGr ~3hKD0FgK ˎ@@0׍5qzW czJ.۷\ %$1$F nB+)N"y ¡A[FV | aGgVTZY KRJڴ]=oNX7a̽\7&KE6ԂKB8sPz 2[,ϳ >@&MuB0rt1ok  ӧ=N%(6tqx;w_)OV )r3>0D0Ruj8_0"@бGm߬+-?Ł"@B]L z%^R(EB}B:Rm(E"@@@(4"@P^ |2#E"@& MP(j_LHP( $;hW1Mzy߫z("@<@O$# D8!@&  "DO @&2H N t D L2"@d@ "@d=.D"@'P("@<@O$# D8!@&  "DO h2&O H2O"`ңjj{=вuҡk7wN^^lkxo~gjQQ%ʔcōFDp ]dXrS'-AP @G'`Jr*f2`ۖdz\{|B2``^%-ҢbL'@ ( dL>0P)@G&`y;p?:}^[?)!s'Xfrv`-gu)B&ǘB:8a7T_Li'M`}lAvJCy"HtqnA\ׯ_9o.f I" #r$4LxjL'fO VE-a읤/|X/֬Ynv3ދh6oވy6'c`tliPnlw`4t)˴ F+&U *}}%ML/'Mvn1X?v1co^{JA=]ꠠO'g UEDlWl ;:EZ[LuuE[PJ"@@p-(F Du l] DdͭHq%P7e=Lz*<6ߍ U52R(d=D>},f}G5''o$dٛm-hb7ŷ*G edHXf1Wgxܲ'51jjfҧo^r+RkW[uR i!cE ߦ*8y7f @%K=(eUbxᔤGu ed3e)NgmeO#k&>+N,+m"ciش }?V5 هV떜-ź_ u?FJӱN X!0`,uPILV 7hQ| Ҭ/#fS+l%=Q Uo̲[\)K >l_#ኘ%W]]- kXMod.!팀!/m=mz pjϢ lc u ;bN M|$ ȏYQO'{*_SܤWA5GV0՛>c}x G/f L"'7gO#KFPo%vH;, >: TSM%D&(>hF};&demro\Mtb:X:j$BI ˟.(mƭ~| Y"$:iІj#3@^ D.M/QG w5ȵ_4G/ߨCN017`Zw3f=p. `CGI见PAQ4"О ˿n0Y8 }ΑaiLLIޠsၕ@OPM|yS&baGzNzi[;3~VLvv08ֺ;E$r}ҞPȱ l?9-3].UG512T$n7pE:,`_ 6h4VUUWp͐L`3%Dy[QGZWV脷#ǜޱcyHNb֜`'kG`CJ0&u k؄)&q(c#8 9ی%'8".ez߀s&Q7YRH. @q/L~k2upn͋mut+;'Z>/?Léf]~]l޽&MB¤'D)[ Zؼ* WjNaÄGAA6ā!L 8R&&imSv)%lfSW!K[Z'aO(y^$,4ӷΎdKʒ=ɐs*镸eSro%&p!|f u.U uZ}.^RNT*CpBC^;dg(1@?#qgkxXFT! ՠf?=6 D@\ r;7!mE e&,EGnۄqaξ'.}ЖE?eI`[&\sS,z3Dug]>i :emePD% b(M[sqQC.77]=|k '1:8C\ޫW/XfK&"`-T\"0u<1````?64mb=_'?]E mBgxx8Lzbf ~#oK 0;xbfI 2l]ox;S-[]K "֗|!!!ě?@lyQb [^IN~1 :x_XmJ;w'D/@\!שnٲiNH mE1'jf&дO~wp~t۽\vuOL͔,jB1k'CoYb"@@) IDAT' bEM &tqnA\ׯ_9o.f IJf*+3>Bm۲DR"@@; ;'|.ӅZ;q Yޫө,[vbc̿{B;ule%ɋ޾-K""@@[$fgg Ef &]9NWR>x!fҎ[IJACsN|!$Q{1]OHޘcwԤ2IXɳf U̘&|Um۲IT(2 D9vعspuѣGv~=qC+7lY;v’|=vPم B`~oߖ%"B"@@;!ì>L< AumE XS2l|bTn]Tꗧ}hqE!툀^j0{JTT&ݑw>hРaÆcƌ#F9r$~h۵kW Rw십WZZ*Zwh{N1mqCuKΖ{/u#ӭA@;tngn? 5JLiB&dpӺ~$& H hQt%# !jSeģGD;f{BsGG)1|#{Qk&5)^BvA@]]HD$-$h`K[nɔec(%&~ Ȱِ)1F`|"NaKW78u͑yq2Ҳs6Fϋ{9Č7voYFfev1ʥ s\xӤȅginN|G>5( lp}>8k1L [ <#S CvQŔURR;3nߞPy+uo~y3>nG{V*d Wq&'7U."V-F 1KW6J cG1 !?TdNo64T%I]x pibO~:jxф?EbŦ?z~aFv6'UӲy˧;H۳-^;',hh@H> u)${B3C{Byn|u")c{B1C + e&ؓ>Vu›BVN?5s-ORx DYVlmE2{2{ dcvĉg̘fclv 1=U7$Dh5EY,/5("D3-EVD&lK<{ށbwv_:Gt&XWxkJt2e q܌pҸi>xq'}Ƭ?|<̯ͅ;z.yadp@L?~C 58-H-|&.Tsde^SWwL>NVs4U<~DoKJk5 =/oD,l”Q\]I/-`+ccgƯ[=j2{ ϒ^ߛO _u-env`c[ /יDoO(E Ush]Yk(a=bd}Hn :nܼf>'JSA=,hjc=&il @2R jgG o'ŅG9c:Ys;_|͆L·njWjQX$t@_aze],b#mꓙxP&|klٲ>}_pJ רPvf=@#qgkxXFr4Z"5w)/S_FQxD;{B!EuH|O*4eq.:r&Ds>q郶-Jm6z%c"ӨRX?ԷvO!>={|g###aGDPpDo$渑; gRX:emeVTŒ؄dsצέ Q6K:̢6[<*p wߍ_f[A@E5u(& D'vN8m2O# r l,S:O Dqpb$W^^.x/L*/#;@e| >|V jK%oU>rtwY> O*x3"bPo_ H]:_:Ο? s둑mHU&ʄ1pV:>Rb.@jo >b#Z)x}]6;LhBSVz 0Qe 4)*RnߣK&- RcQSZ@FT`(< Y慧c >޸qׁ>?Dqsh4oe>v[Q]TUU^J/ Rx޸p XE"~PR1GСCΝ;*g;i@d&N>=22鈙rUcGi~hT'Hv#%REesQVǼd>UGp'zSeEQ"Bˇ/%;@DDŽ PT"RV僑"|.٤‹?U}+M~^>Z*DBECE'm }>Аv!H_] DӀt';ĥ)ϏJ:mRTFdħ⸛^kh`;'(@LfBN8%y=&mϞ=sAc2qDLAoR&$`"Kju?Uoi~(T).L Q`bVUWap(\z*4!B? TX{,yc֨ɢ[fդ0YLJzYMdJ Bkڧ6݄jC& "YEY~V 3fD᳛"Bxpv]F!~J6Ф(o&{Ns #?h&Ў`ũqbwU={d!P>I穸iae&/A 3#]EV~]c`b]()(;ם ԫG@wjCp aTw "&Xp;'\" q"!idJ6ФTCпHTLxZ˩V5)6ګEcVZZ{ x }k ˺|P)7G'gر \}f!1J/&c==l$rE^o2X@B~Ań`!i΢ XX5gTM9%G:#$+(_t#BwE G_ȹo4#G Paͯ0Tފ qFif/mIDAT $Kv6ΪpBisB ~Օ~w7ɰ9`׹Kg~kk!/x{d n#Cv|^թ+eQ|iPRXeRº=__R[fݲX\.\pyaz.dhd`V4[dxlf& 3U[L;PwPnX.Z-(%Ֆ*3VnҫT?!>>Mx/4E8qgD~x M=XUexp_Ȯݺ̘:!WPxq þ?~QH;%?S߾};u 6U{  ǭ[ͷ˛\JJyG]R$tP*S ۏ?D1Pkqv9rG @bCu-c`_RiM-mmN7?O-_gy?~;@*\m0 e _}`GoM{8t֘hd {>{ !W~!d xOx(=uV~~<f fC]=>Tn\3v 3Nj5*Sw,n!px1q!ek8 iQ_B,,b GӅ B8F&qwނV ">W!YR"Y>]p_ɽ?NjG`njB\K?$0oT rMՕe^Vu=k i8e'uSHfffpx])BL++4A) bh(I1jY&j+"#pC:M.s. Qfb ASBӠm-x C # RJP"뒫| 7JzYM BjUU22*;R&mUb)2_e*0"r8}yʄr=ji&o棿hu@Ugw1\ؕNٳ 냑PAÉ]B.׎mgؠg}S!F<<: .*\VP]ZUw@.1Xgc:!UF(Nouevݼ㆏DH ]'xx"8v9rC 3F᫔kT^S&Q_WGbxVa,.2j9" Μ+Lad?f o9bŻN?pdVj?'0wH-"!U"|U^>*UdR(\vM"Y>ܹ{A{Z_o1 V\.6EcxA]mop TruڽlkcB;஑sFfyt oPm\xmګ:wʓ=ʼ̾_tSlb)Zsp1 po"%_]IT*~ק߫V٭.ǘ{*JJYiy)By}]fR_ РAumqϞO0LGϚ1qćhAJjЮj/9("Tyb׶>2N餅(8J|Yۻh+}z~Q͓s,9 B7hADP kӄqIY)rL 5UxOTVb)^PKexaPy+au|6i#c;[n`A8>hΑW/\=#5r&Wb]9=kE07"ԓoMZqCoy1Fd QJ[ 5x9Φʼ|=6noJ1Bx,(* JF)X>Vaڂ0 _esԋs.sV8O4!)]}ڕ2N FuG+ܽw5F1v.z\QP0؂.qP<͇X2W)4SHa(U@g0f0(QSyL7 A(^}=/?A/=Ե࿏5ݝ6V buJ(s{fLHνkpij=Dyh4RJ((jfiFɡ9C&ϾWW=U 9ok;dr@콯\6ffť]HT!Mwaq9hxKYiE'(q=զ3]]޵1H(z(f%;0|?غc.K3ŧ?7wocЋٲ̋G}T c̙zxÏ}?<|EBF TѨWw{_/4@F4UB#Y  & bdC1ElqÃm;SB^]"{׍c3-Iiٞ23ALan1#_=cTFz!x"'%~!> ¢x]/<ϞJX0 1]ɐC7|ž߂y/r+An|?<{O\0<ZuHم#TRƻh-bgaWi.xt}7*n[!G 3GP: ~pcji ;?x׾*q# K[DdYUԞU_5jfp/sVFCdoĄ(Ҕf+k9t8mP@L0- /T 64xд`XLKAJ}wŏ|Sw!ioH ghm0X BXG#nC^slC^̸YMdxS~`޽LO#Y~;Y},"wQуth,&k_ c_8?(ʅ@}eK4a#=l/C grMb= ?3ݏw=ף x"o'$w[8iP{#Έ. W~8yscs6k ~ΈO!> nq5YI:k̀Zȃtg>= O/{a`#zN5漺=j/NimƬw{^Pe<1ook_H1\ըv9M3uT߲4x_^ fXK!X@xB=S?ĔjW)|FD>J@V0TV{x՞=꘵_?HUU`},JmaV JcomWz?p@ :]@CEU`u slp~a^]uG{Fknϻ5ՋsƗ s2ooK-}K|wÇ'&&vܙ3kgj =BXd1\iYse̤ j? Fs-ɷ.>όoB6n8f̘Iϊ~b zzg)ٮTMjNIo:Ge,N$xpr ighk^ʘ+oI[ncO)*ri5tV%፬G8ٚ$\.%K.J>&N1#%Eq0wVAkm zge Zlqʂ(BɑXS'Su]wWRx҄ؤxIʩJK^7{ZxX??Iජ](;vx01RnW$ eK[%_"6 k$%%A|@2“` N+bRHKp_%KuCTwM>"D%BgP4Jm i2(4B%WCX ˄pB1\Q*;C v֭M`')\aKCeI@Ԥw( 5v@!H$I\.G S/^+-1r5UjQ0);•߼ӯG\\j#WsL hiyXy`6c ޑ1[V.ǺIН''*_`P k_a Px;ؤGvD={B'zuʕcxocXXl. 4ZHX>XzuA1 1 BI푘 i+%=UG+Qú ةKLt TxZW6T̐?4O{RN8nXTubcvcI7IֱmsΡS5CoPКۇAaƂIq6A_4鐔Ppۇs-]R-rݏ"XKӡnaPZh]Oģ^.` ^G,CO}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP(+Vd^yl]z͢Zբ71ߪMzi]zZ2D1A!R<Il\($$!6ZYvvvI2L|oG6p8"O8>eA̧-c˩]Zφ0$tT7 `ѱ߳GVG( 18 'lʣRҧz ͳhFg/`Z)d2GZ26L:Z Mny?1<݊C<%q@sXOWN~y\q'/JN:M)g`X)z9y}<׆ߒxsK:XiBE)`ob]K~):9hk҆eثDiZ )if{l?-ך .rB.!#'٧"r)G~E%.u}{)cE<޹.WJ*·O}9#iMRpy:wDA@F!>n2Ҡ;ͭ_vM{ʎ8;;񁡶?_myv*̮tH:J2s0!|| &SGt|T8-ztlQoXl,4jh ;oS\{`?b3Ij Trqu0QU23 ;^mZAkz!@pڂ ݊K!= $ DXl 'BB,U-N0AO e829KoWgd68.xBbFE{-9Y:Ov8V[}9+W!SF~߰ϻ]Xpa޶Cjʫ3~Q T^ G|C]؞0B/>Jh-:fhy΁%wM>PGJTc ,(52s[& 4yQ(O({ڠCkje2cR\ՁfCz5ԢR6拣: 4^Ikij[lRh9#%#3B,`^yPn}0VZ(!*o.Bi4'lXvSZ6ԦQE]DSмHc}%At,Ĉ20Qz22XZГ}ŷYX^%|y-7ꇓ= \)3yW[c20{,mX- O4nnisF뱋>cCT=CbYx{{sj z]h^|sqҙcq~ʩx7!Һ)sZ-NyWm"e%;3ӵ ԊM WЩl~ fʰ6&[7pGy2L;FÔ9XKղh&N+hmyXDwHR_xʚe_$" /aONiK Ia ݚ(NK% &Q R?Vg" r-^c(˄9pt04ޜ0C7^z!A(L`.ƦV?-7SKul98e9Bt6cplYBEqy+@}->pZ9<c]IJ}.9ȄV>;x`Yf dRF1x.F dTQ^2.(j P.{刭(UJք#pFӫZ(UsjջJ(e "ƻ9=b0lJiߟ=̩{P\Je#'ܻUz%spS YrD?$Q,>ra[Rc5]uM!nܮiK}bB[v. jWH"K(Z&8I+@6m6rDEtJO xUǩ"Y'k? )hd)| {4۷<k]K|+ֲO'Vrt4ѾOZ04bSr0y(K`ˬOWQ"ULP**ELܑ$K.X] 9~Li?=x_ϺB"gϞqԌ6D{iA ;1Dz &, Vx 켃^|?0*(Acr,L=ŀ]&N5\:M-JdMv3V`n^-k/=X28]A+@D!X(/?],y6հF\->˻m7֙3gW׶|vJ1(1E57MdOrPd 5&&6_thpbI!Y"(IIB4]@ݑY{ hwW~2 bmYN[KLIs$eJH v*״G$c֨Ȓ!2Ɍ!' 674mS CAcC5Anume|Qi⓻cQ0i]Q3'!--(*R NUQ"2B\1ɅwXAVN49:Z;g)*vϺb e@Һ^He )^U5x/k%$Vڵ Ɗ0gc 2vqRnl^K_ozaɡ*p AJR=ˀZAY0.79IYYƚnM^ :W;UK}M8sCxh'*ZO~1 󚙝Z}Wwowme]tY#ߊkjVJdklf[TCů۽;ԮZ+Ο|Na놝1 DJ?-~e4 \{y4*MԮ?M;Qd "ۓ3Nh6rVq2[!ă{J$HQ *+g5S5U‘R5UJUӽщgr$$2;t1s^7% 9_jCh:u&DjqjՔ"hw،-{eE2$UJD&˪>v0*LڥV(j3H#25YB7s˖-z{[ _O[kMQ\w\x9}??dTJrcD2/ޛ{܏E!l8{uؼ#JGgEU>^v%/O<_{wE Ƴ}Cޞưq gKF1vL5J(MRMuk>|FXW1g.K!LɾkīxYkC%nJϛmS])k҈Rr6E,=r dXc&֞%ګuښ=j*|')v zõ27tMySldղ6#o|MHI%<Q#36TIΡm0 %H͐ɽqŃ3>"r9$|'`յ<}j\F\sɜ@MYk'斋JC>RߕN:we&=P5)K. ܦM0_$k=: e!^J]i#,@eտ$w3GdhxԽ!6kl]t)%4zǛ~~qkTZX%sB>Yc*{d 8YaQfjUҽ?1\ f\GH4UMt?oտ]{卽ٟ%[@"QB|˫4o&C7Ur+Sn+qy&Psωvѭ߈}844 ޜ)>n/lܶ裿=xp>;(xBcA@ޡe9筇~!t0!z@tLz੫'\/-f_韎Ԯ64PvKp| jEW'zQ5r Eƫί,!WH\/SC .tV'[pa*K<`Ā*7x0oR.1Zw.gdPd?x?w<*HʏT D(.}A{jqM7Pl0V\jvE'Kg(t[X5ֶ%јM\AN5_Zȏ?+;U7Am#{y]G> r\! [ͫY{a^/ (p(ߌ/L D̕OG(nF+Łǝ-f&MBnr%GiCd A9G/뿣fn]Ϡ dPfNs'ĭn ul@ R~;&< +M"rnAGRH4²qx vAHp }5XP+SP I(w?=;miZa-|ũcv{++|'~-uZLb,]Q.֠Hc;jo~djvF1fi}W A@uUnr~mL"/7 fqAx fY/52A|TTB9(XS-^V6kP#5[3@6-nj1Fnb*z9[)4 =_k5w?EݻVf3e!9Ey "2~A#lzuQYM@'㳉 ># }EIB|$.LnCRHA )DhVrvS02 1-Ŏ<6v\(Cr%¢r}U-.Qu+$ruGbG!3:Uհޅ#B `ط %zW!Cx&2k SRwIp}Wci;Ȼ0wB9E >"-Z+#5%7DK3tݺ/OqUS ۶Ž]0TBt$N_g^bHoAc#3bg/ͥWmL󷥪.EB Bٱw2l"B3 1 %wGCzY޵ IUvTFf@{!rz}Owd^X5,R_+w3T/W^3}~{OHo6j,8JN'S=(HRO-pJ32sL8Ҷ_/ed_x&4bM@| /b:אa@5$""(<*wf¼i]&g% E֣ZA M7t ":|i t+^7Q~!6 vFJ'N,ߕ{wȲ5cՍc7'_.!)Ym!1I"T3f:>\W\̴`8L^brou''dÚui|炷CJj0^4 Y%1=EW [No4?59xqm[Ed6Xb9+Fҹ۹^ggC>R*ޓЫkt dEhck[}%Md҇>3{U2SSKl#{g՗ho'>U2?6.=3j ǚSu^S~B'1+{p?(`f&!?uy<w O X8I /W?`EP˟RYv^,*E^NKeHP+W/e31:SΑ#Gdzwr}?}cezza0:xdҳB7Ll;%߃/:`dg p Jx~"IdF3d]^, =pfg.LQV1n;gxؑ#ۏۃpXa^C-x:ulٶ~ڬjztmў24eJu:e4 6T\xJW},eQ6lj8e:i ˾$jO$鶰A3Z@-3vgm8~-Iev~m" Bz[&m=ʐofN2m Ҋ;PA{ (|'Av&N^|˙lRz}'[sukmYR+ɶ%b0hKDՊj:k7ZiO9"P5_wE{ފ/Mʴ2p^X \At=UkkZ3\P eXkTZ}P@06ILMZaj ťmY6]aoix%tԪ0Brm[𞕫SoGs^Hg64WTic!ZA)gv X,ꇵ}U{D?leW:5aDG7V&Uk }\:|N=~]銐g ϊ| }}/݀Z]cR#|,j\ZQvVO m'5VZbWC 4j3.ţG6=?  jj|# Ji3tNI80\}Z'|jŨ}x vVwS;8a3*ڴr3lsh@[o t ow!+L@~ Sz>N",lϐ3|zı4ƻK8~HJ;@[Cj`3A_hjT{I\@J+A"ϼgEѭwj(, Gfqb:5($m @U,A3x3j2e&FCLa-,:IxRXC|rN +6$N < gTˬ6IЬgY-<,,0cn~+҇O AXK-HF,-- lՓӿ_lVۘ{K7iDS DA ʼn(|ȜY ACUSʵkZFŦYoiI'A "Ym wń6,A @ Oo'YԪZ8D @ @]_HA @x>R]BN A @ :>XdePB AvyHIA @ v I!A y]cBRA @ t®:)I A@&o>b$ @x?۷f$HIy # &t?_7_@_P/QI A)FOv>C\ǎ1NU2J?)ʺ:JΈI)_|HurNE2DDE;J)Mu8"m^N'-kZ {<*)6R+#WJ(60JEH!@*(E/# 6 yٿxRiO}!R{AA uۇ2ં3:YpdytZmůN#9UɎ\YQ6hiw*sn颡2+F[pARP}YT>hA7?߿pc%UTݿ59ݘR˻oWPJg)b6ntR7m-y>ye$;x?S 7AIZD}sʲv JʤE5#b9&"z ?fu(X!۠U:nGqy'ЖQm tMGoZ$ ]ǥ2II> qh!'[E]ZQU87oq*~?t7`g0BVF&̍>y[г E" \B!酄/"qM #MuDZ5*qу[~\&7v&}OmEװ!F\ڻV] /YqޞQUg~͍y)YY\Qֱco˩eʊcG yÝeW*Q(*`Q[t^)uq:ݶ۹mXwnsԺ9w~uZ%Q.nuBvgEwyS<0؊b14N |)_†\* A?ck g=/!}WE Mx,V80;*UUrD MfY .~1P+H3LԄez;kA|cL _Cf\lzf ),]f۠{7 \{1uI=oO IN 랎.F> w_w33{c\T*\y^q\S!ch}:3ܕw f'4>g``/]WVVQK$}9H]\JR.d1t11ɕ^mJxdqdLfOS(p G=X@!jdj}#T|Nn{/-rp|U]'P붟YvD']BƇ x_G=@olq}eWUMe }F F(L՘{ k1Ii+gƂJ$i1s֦4p]eعH_xc]t1JWdff8^S6^z.1GQC_~ijT+:z!ya ?i|sjƚ7^xob]qu_snuMŏ?9*1mMI6ҵHU5fvi*7r,1(^=u,~ر{b.b0{5/{md)'Mz vT8oXLDm7i)\C NlZ4rW|oY.pZK|p8t;U7ws 0l.f\m HW^΢ΔN*Kh ^-N<l5㕞8< ^&U=rӗLP\^aIhj{ǎmش;B.ESChFkg lmS(dGK/i{N6be_/T]\3OT[թ{Ţ+1޽:ulN 'l4 E]~}'_~@T.ZP96C&JZ.6sT'pE Qa+S_͍E f{ýY ൺ$pAnCb Q<ᬄ|X~ Twhekh]l[*kʒ]|!P_$M-:kqW٩ؽ<ְM/fŏ8 UX>;eئ{6G~!2txkD?Te*ٙ1DjnHHM4O±8K=T~N&;O~gRV̎KVQMДrlE"9z'♍FhcwܺX! [c-0~y]@&<[=uh h_TRW\9MT 2 *g./ E_^Yc/'tZ|5ie"yVjJtNW z2 (V:[*r gG.qm&۬׾aMC˅lH@Ȥ%0[KL,Y' 0pyBdp4UmmW{\[l?Vf\v߈.݅ pNf ة@d@GD,SO'[dTg>($zv1YjÝ+{Z>"NtRIoe4,Ѭn))7ϊˌ+W |fHzMNZzOUa0yo_ߥ𙖅3@V^R=x̯, ьHmsۄSvv4t-P(?juX(6}KLP.G׫[:W(.U| UF_*xszX;4mY{ؗޙP),WJv"Xr7ZG?'+x|vw*]ǀ^v 掉-NVm#8ޖjITw+;a+ã]+:laϣgΗSA-g<󛪟(`v5 _253t1<8dS[dk*7 s#JEEoK„* nU5ǀE^ _7iQ3ʏ!k L6wǡId+ϟ/hk?i\Zhҭ7& Z7 ='#KO!K VJ@./:++Ezxϧz];Z ՇE w~[ocg6!@z3}VHqC7,wbfKtP+zeNggޣ,RX>-Òj5z^޵ ǰdEͧ  ?~.g'swvp̋Hgu䅜L;vm9*BًFWsZwt]q>ڋ\? b&##hv n >:;:)&eL9B)) 8/%or|,`iRlHdy(pf80m/œG03!@>㚹q4}opw3-FRֈ{,#UzR5,hS{[V #òBr8یz cA;4~z0ȔK=l|iĉJ|@SLR^o|vAT2e'BXAIT^q)N}t*ંbcV˨$YAFv Njv~;qWDnbTOv s} 8dH Æ[ ŇӀK$2e2^,2¤i!mƁ'[C(övk #m#"k^l𣂤Eh͑H5sHƸHT#ӹH)MvUSY e ؛*W_˗CBB3O0W5?X*iRQ}Ӡ)Q$)++ hS`W1 N 4?r3:Rfب)`ĵīڴY42Ҏv}\uP4ҵ˜'2%Nz7'6ky=`!֐N# J#fg.#O jDŽNgCb|B<-{XK7V=4 Zja:cPlgi; 15_oDVF#l4\Fit^WLxϫJl#bX b,mj}Ue_mc%/4Ȩ'{B +z(| zOC)! >>sK)`XdKI̒fW8̫UxF`(-jQN?cNϟA @ Fӥw676٩Վ*52`]y ;[ؙt IA @ k3@A @x @;ϮTU,} ~a!P_ Ӣ^zҬxT`y,>*<A @x6YQdW9VvNݺ//}wTU kW3>ݧx6+uS;;Sk-kxlPt] mT*%ߤN&5¡~a.TߛLb@b1pӨ[?z SioLٶX:H&AA`oQ9*|01Hl>fU ՛'N@)5/ 0r`N&#0&&")9M$K,`yņ/Ah,-*VibAjrtƷ`Q3fMhl˾Goɑ^v+{.-6pt6e̴YȊ5!hwFΒ 㑽m.]'i5uEgC{:2 qgugJAi@]ך0\.,t! uHjǺ[W˜110yJVǤ%dPP]hJEi$Ś՚_yJE爱p<HONBzB:KIJK^AOps6TR2`_*\(a5^v6y--|Er9=m$:7J`F|GsTڿY{NGz 궂\ׇ}fwkG( Ke\mDVrpŵ(m%#&t$4a!N6ۙ+o<٩A{ˏH+k?v^cfG.X7仭o[K"yr3=U>/Vxgјߍ9(??"i%<~f<Sd;zxpVB~lRxGS;N -̪*<(g0-nߝxAf^E֪f;ϢS%:cƺ޲hdԼ {,-+ !Ʀ{8kmMySm+e|DeIIn^蜔yqs}ܧyN AY->f2t jvEIo}w( 8vb pBoN|w$:9M~P O iꈐE / 1hdMkm vŽ>o}ꗜ+41d3Cl|ڴuB*p1}/'>mT?-b+8<7MDǏN9}|"[&'wS50 CI:tӝz/F+6"f[uY \}yjWathcu(pL`?jpPژuЉeL^fzg $`䡸=-KR9'>S|WC~:T^xBNa;~/'+  ߄q_iSoVo-omB@q%VrB{vָ hґ _|bl/X?Ԑ 2hy(\pfl8ьmVحxMĞ"ݗE dzmTzbw54dPG 2ǭ3U^ﵘqH/JE AL$M{*޹dώ_AnECʿ x.\%BK`Eɏl޸fܲ( $ck7#/jY܄tVWuٞ9kgpQ'g|T ZZ^LDrIa֓&V}?%(7==qO6>/ kmc'!C=i^L8%}Ə٦[[XVEEj@ן0Y g_?@ܻô 9\=7Wte-bs'e-D=i4ZPW^yٞtmJ{Q;B Tj#kFU+up6qv:dؑ[Ukْ,A4%K phO_Wqwpo]aE,ydCGZ̞&KFWwxJ"YOwvҔɴ,D[s2~=Gv>nZ7W);_&+ӧŋJsW?7nz)ܕ[ee%U'ט?Z.|pM }iT7 }-{Xz3;"^Κ "&A5~0Z-x] m\bHW* N#@,yY+N NFNk_7֩Z(E 6#p+:[oT!SvhW lH]xa100X#0Ruտli: 0'R< Y$~ [ʷn2k3000000!ڕn`ܠa[/nso);%s#>f,jRh`VjËC[Za@2ܙd6BMAz"?*w<ד/ËAAA!0jCfA+Um#~L,~8>erF#Wׄ LԲ(;';Pl ҳQ(Q[ (Rm%!,ʩP[%vYDPyԋjԴ?/Tq K/hH `Im>GhK M/Sȿ!+Tش2!Ձ#,Sp^ IDATu9°@[.9J^aFP *Y uB8ҒM[]Iq,C{#0:nkpr믿N޳p`d߱ åin,⇼iJo U?6%ʏ-r@sN`"+4LSxW4?5Xݛ*Y T<'BEmi.lQ,әT׋d'/E5Jt"!>+tVtcz;2#ćFL=3$v8 Hבݹ}l9PrҤ +`kAU)FK ȈD"!@=yi36lkҦĈƢ8!eP[sIruK巇r8/d<5se ? sO>@XDn |X~4d;C_p OKװp73B:Mn>u{(kaԡn~fe BĎWvH(tڨ4rfN@"tٌ2[ZӖC7 G@$ 00ٹI@ `.ZpoN>!oUg?3 nB1H5wwD4}C2JZD SNDIY0 rqMB*~B/ lpL >dSS64e}/(TkFL]--hWc̙3ϟoMk)n@00xrBX{vo]t^q rP*dy!R sE(ϕػ i ?:[ZXXj_U%6wFhÑ38K&YYG(>_SxlAa&tiGٹ%6N((CKJr*»?;qМ$5I$-8^S(li'CҺ:X4P)fH#/r}KF{4فYҖ/ O @uum gh^e F'h3rvV(S)$X̾O9JsPLGhbS>">^ fgWpSퟚy}c2 ÚW3BkUՙhG(B@I~^Oeɜ{!)1 ;UQkSkk֓*$xH }EӒe5-H:Tž~vMxTj!RJ T:3?tG\xQ(2)m@G_fX#7MǨ] ê+&k@ry~^uedv[aqOkqnqp\JP,m\6mL{"bzwu~BIQb.swK[q \#iVfKLH߃I)p NfyR\F`/|i(%d~ɞh:e3}("Δ_'krP#LZiИ Bwd&S̕Az"2E8Ϝ(D(.nÕ@D}nHDMx嵥0>$˂3Qp8&#T+~00 ihkZ5vKRmZS+M=U! ,C5G \MD/ʔ@_l̝!;{P0;A E"cJWJ96.93A6GY=pDvZ >xm9/bէ]պy\!]We>Ů>5ɁӨ¿VCԨ4`d1u4O*JNHNk.4**HaB.FbVHU v$4ScWgKi4W3HPk(i!W-y2 #C||ӱM5+T o1gt=u%'s Y_֣硭:=78p @-5 ULH~.j9-5=.jD4-vcƇw"pEgH]KVSey`}tDl5D<h$v<%,Ȩ.R,tb"bh#!s'@JAcgD%eّ Q q(95buJ5 Ym7[uΠוC+WN>-%[H?[XB?VYY ,)G{vssgdflUzف^oc ,׎ ykcbϋ]7,D/S p \2|`a _t.6|j!z96W5$q$T+] u~rڑ> R݆% 0`>-.&gvVbR6s MlKi͔1ԥ*XcwccJ$b``}c upM9*e!o >NnZ|C-7Tbu[ p3 .Uxw[XдV, Ѯ,`n?kv8pl3 ss\ Λa p; @VXrZ]44  `\42uL蹽+ F=S#w+b&Wlu  pD a+QWH3=6ӮaD?lec툫KhM~;?ݶNh[Z "7<G!"Ǽ R&#[Mk 66/W+w"{Xѕ{خ}ؔ DAkWE:k,-1K70آj3 p}*mwv oP,8]^9:*&8< M]Utu1.v&Q;8b0ű˩T# + Iñ#ww K/32'%܈t!ՁUaFȊ"EZE@R W3׺KTc)s 0 o2In8Zu{{Lyuc9!pNwr9UyUt)/s800mvz-§l5.sɖDIFuA{>z2>PU{Ӿ<'R*7zٵ*_8ǥip;<9=ILTj8ȬH|e|6yiqwd:b:sZS4U:;cjp-/p/[y*SHy&t;^>k rMGp?.򘽢@Uo,0#qn  )iEf-U]-0DC8<١I_1ASXOvem/;4;9q[W>̎oYoSGby᣾ =F0FBfMc !pH$ ):{7{4%K5Cwz:ʠ !WB>`XrB+⯨Ì&L+S)5jm(b 4jYI + gxeY24Cmm;O# mMVj M֑SRòI"8t޲huHSYiʌ2i@l`ZsR '?$/D?RQBO1Zˁ=VE(a7ie(;)Ȃ:_ }O"#9|&Vv4 bCh`d%15yS}8\<3YAKX`F Q: `@<|]@z2޲;4)Aǡ΂9 u0R3q'&0gG4] =8-~Stmg \N\obFZ Uq>gsIrB7T͍ծ >k!PPP7~SNΡ~3ep{0d* R1q΍:8jS20j)ZQ.-DPdN-)OW<*o2HXlC禋/8) KἿΏEX-i M*,m j:{B^51q~tu\NE{ŗ@:ټxdƶ6i$贩2o Iٚb~#C6UqɤdH#7ܑDpe9[ckshSbړpBq ]tu謊߃((OzfYSY.5.Y ?aC0VCXq `f?*Xq8e? ̷ ]V-YI~%7N ?ڱ娢L[B@]. GI(c8V GkeJ e%7,X- E(aRayY=)S.˟]  yNS8RK5rfP0+#!{/! 6?[4uqlXVq1 iLqEq:a< \MB.\ {N;Ί Z}a00ORdj-BiƑpgVBQfhtBqU `8?Iq|+V.79;:9c{vVb$- cEUߴʂq\^xNqቋm۶ a3[_MÞ +!/(2-_FeiR)u1>Y:ȑ` A8(XYBXCK;,a>y*:C'ŒmR>U/"9 `!l$ȧ"TR-tVT8I6kTp3j0 cdAݣ~ϼz7I fhո5i'5uK!4v\4t<Й/B} THw)ܜސp0OJM&$ ~~iar(@}o^d@F} (/O[Ц 9~n̫UEV&_m# u-*ilkoMьAu'w,Fo~ v?u(8"Zay@2]g#>Y];JhJa$gV I>P IDAT(Ajh||p87VÓO.mSt63o'pq|;5nU3 GqHNq6N#sgjFZ tӦM G 5f|vz%]K \;">] &p5Y#.k^za~hulr&ZB{fRO0}!=)XLEZqӻnX结BɥBp0å~v"Xw,ɀ!.:- xl8l_Ds)ɐLNniA?/\*%S}XÑJQ$iMwF@^n3r/Ż#_8HA@V('ȱj6(&a5#p vW\sj_,?\\g! ^nhFL(~έv%HԍעRlFH!$x{U0J Ą^@SX~B{/U)ނ{5_m8^BpziJ ۻQCڇukBMߐҧn`L2sڷoVveD$M]1\d  (owpwDV: a ν, /Ϧ^Ơhĸ,ҷk1l;3Fwv@ ӾV AA;$EӼ4')Z_+:pJZ!-v@*v'|*(+Vz?cӋ& jj9#mc{̄7tƜl:FN/ gu(Sq{K;vMrnN>]y͜9s֙v Z{p?U hz5yh:5w HRz'00 σ%? eaɕ`2w p{Wdv!)R/kUJl:.5b'v(FOb" ASFp J̪LDS_J|0׮4jS^ zBZ&TS%=W-;]I*X8!xTt},U=)dvJPS1ɃR4s ͶƈFW@`.q >27^lN ZkSkkCRnX#-% xht/x N7(a>`>SRdz1is{d$$撔ӏlG d0=ZiC~eF(! PsD%-o4YM^(qkbkkB-KU"Stίv%P iN5oL7BP iqE+ zͶÚ묫]H*^zDT hL!̐6o+$\ lqT)=ɥ ~VdȈ 0Z5jC,`M <ϔcݖ)>u_6ZR&Yqa.̒XF;f׵@ZDC2%.cv9$(!n}Åe@A^[ s!Ãu!_!d*{6ZV(aڪ,D[]nVni:MBly "Tk39."ŖegOG grlVzd4)1a<)M.*NK@.552g0gO#QRtFE}]qz) 'QѾg,GVqTqm/F6Ow?BYzl:쾂Img~gPI -M*D{ >[ed'S`b7f2q5]V9++0 ~iЦ_.X;l4p:6O2'$1-ތYo(&0SU󑠖./,v:Èg6ϖNh ),SVl0/0vAInwc'pȄHHa&]s9i_bfx&,=F^-,Imh4HmdqAkj!ZE!?4sԔQ0 NleI0Ŷ|@Seݴ `(eYҏ j ̷Cu//&!ƺ`MU/ؽKiz-JV -`ZMl L<7]@J4:AJ?z`welsp}`DfaʃEj(",H*f#l`/eG3F UMvW`B85T@-6bjmdTV@y,BQQ|RߍAܴ+|0j9^Wcu ⋃])-Ml!ƛ-˙5H}ŵRhs낯XµsOe 3ޒpU7;{SS@/x"Ek1l<\DZ!;CA ǵ|JZ-b= ǎv0Ӫ:-c"7eTjxC -"Vv`oH.&5BXK cj׉輇4:i?πxti`WrXJg2T"^IA@<x]9rJO=cA)EOCԁS F<wm $   Uԛw69r2/.wt 'ཀྵ8vãZPFg6&AAAAAAA`hd kpm)~>D? R192000007#pg]~<g[rG[&PR]Oe    wv#u_٢j3b66%4{ƿx- [bgNuyPG r,4žre/noy_y |\N$G;TfuˏX[qO{|?Y+r_CKҩ~ݍXPHi"|hݡhU_suSh%V>ٷ+>pI3Zn:=Y?-n0uKGu:|ѝᮥ9uvΞڙvamgן+s[U}!0QW݀f]i ׶?X?l8қd]sesvgfs]ɮ7#PYk9s礦c5kdkfpYU!5<ƓZ7󳏾JjCLͣӁz Ŀ,\mӟ?۲\KZ~;u#~Kf-z

5>'9ObRRHx.=|7Gۻo#bj?<폓z{gkro\9u]|1B;sjCS\0~*cmcm}ܞ7 ߥs^?[6`~#ښ{{uiYphh>3Nʵt[{~$sl7+e! TvFC~[p}JmmI[k½ZB jbl)A?h=$7 N 9ۢ YTscQϏ*@m$O#x[T =dA ${6]ظ¾&lA-xV+ iLt!i# _Ю0QaPJvPR^DJXE%͉quc& #箲?YFVg=w*0k~N}3Re FUw)+Tw/&:dEL=\KJlu^ם82i~o9/}KPe;=il?=y禊 %mvfxٗ]c'Neg޿`粺PVKO$81Փ~]C)ï.[s>fhj큕Q ϛ X/UxU>3}[ - ̄%fpj[7x ֙7֟lt~,}M~yn'q |Ѹs2dڂѥ/$ShΏxg,g/J7#Y[6{?1r-lEξ3̝1Qj:5R9Oq),<N+S[a-Avz@)&õaTE!+"O[SR9e 3b1nQ#mKU,LXxE["?vh) XOemt\Xx,rLvRS\V.'HȊ"3*(t~8͚oNUq^[P׉0R%RM`u *ŻV‚ (iehPvXÌo'be4i5[$,LJdT95_ddAa!˖=CÌV%JxQjYpMUd]C_I@/$e5d0h Hö CmkItsrOՉu6%$H]A,+j5MEX7 L#2 Hid#!ʨ0kD,} 'ǼrǶD >U{%8dKi&.ޫsǷl?aRGNKC[hd =='Ou~4?*tl[?k~+Rm7=Hߕ0jOso#]/|u=<>}|+1U]=(psWmړ `^9^݁Nuci[/Q+ʂng/O EDG<+/hZa5Z l`KF@Am*5|i>sQӛBPpZTjiDThNLO)m+WtTԀ['m8r)w%0 tYD N*TGfA<ǧ|yHE۩^3VOM: 0{]=~L=v}3?3Be+pyg5ʋ+nPs(j?824Y7\et=B0GuFڍty"ɔmmIRikԒtţ/xd鍐/!㬽y:<GgGJ7xG%ϏHͯk4 "KT _U(\ M/`&gAL!YT}rk)9ػyh./l>$gpZsBǖqr =|Pھ\~e|9(8ڔYmQ\ܨ7E,C[4jICۻU\RMZ$koPrJ/"+zFT U[3u@n՝M[s%Vv vD p"e]CxDT/lTTыKT]T#Eu5.ϒ"݄ M:gG>;}?]˘UpYc=R?Mac7/vs7~{m). ~șT0E;>5˗KN^$4v3\?ZfI_0h2`I Md vWp"ƱH*`Rpo e(7=*LÕ s7R -I]*Ixkk3nk|wuFel4cfC]JSiO?^zGezϛϩ-zAiƀ>ҿ\Id(lO6"B P\Wk! |X~&Csq:͉A(44:?3qu\L/rH(ݻQ~_>ZكJM-G(wGvn;-An`P*k}@(!RVk0B ((rT9"VtF&b5sf % f\H/WuXv@AtWG|ΰqÓQ)B?T菈ӪQG!BsU@!I"A=҄gJJʉS#p6^f+LrhQ3Ld5#m\3ؾ/j8 )QpZcU r,BrGI;K7[dn AVcYzq|8 IDAT0EF;'ƭUkQDȬ~LylAО<ur[0X!4Z~yv@4Ac!CpU BЦ.AZ$cu~eun!S7IKk;6jiojݳ ^AemOMb9nC*њ-kNPgTyDwo^זSbPKZJϗY<(7}ge\vWaچ ]޾ ^|w+PbK8SZ5qyT8ϕ˷Ѵ)zkΣ =3N%)?3-b(%S;T)W;ַSM.ǝ7YL~DW(<( MlM*mFP9EA .P 枨? ptت(T {5*pс. {Yk.Û|.abrUbu$Q/V+|q+ʹ?/9 H@ȧ׬qՁȯLYX=19bI2$mErV?yt@ I37eȁ¢3augW(ZW ]1qR>8Ty, "2#&kOJFKeuE ǛTsDr7(2C_-y[SBP_K3b$rGDBıx8O"[Y ꆱ:46gPV4i~) œQW?E*VKՆ \oIsywfXssn o%oߑY_88+ W`w-(qvIs߮d9{2Á7{~=%OJ]oUμ7#VQ18.n@.{Ļt(_/ztG]!'zƺ]p`6baC5xz[wOg@:w^2kÛ|IF08* ]~cgl&Q3LxE&-ģnyZv}O>j傴T+f`I Zr2pgǚt0s8`?{7 co#!Qг*cփj{&NR@L8ϑ#L1ȿ1]Ϝ({WNзwy  YR+BX*3JBQ$e|Z" Ƌup}4APt*u/ߍgT)ӳg?$  sBP^Jq=-`q5+Tʶ9޺jQeDl䵥 >kLAޝvSGrf+7a4LA|+ #"I/\%BKqޮ4ɒZH'PVY"T*22SxG(_u(4r HnAg8/g{- EFMLS؁o/85ȃ,y<;~ժz?-XJ=`$oKW $K ByH) _TM8Ɉ۴a;p ?UYaeO%vADļvID|'V\u PօXCct{X"D]6~VwF>F$16PҩWחȦj`ݣq NzzVZ=Q2ol Ry6|6F,fi"mܕ[+O\(4c'$DJCa1UnB;sQV0-iNoK;N!IXX"0=) XS(_Oiinjg Yo[\seg&L;ӷ?SZr)TJ{T&Λax;#8ׅۮ9,{oun'5p|SHː@seXcDIn@q &9oAN8 >\>4u =9<jqbQ 1RlѼFd%h{k?_swWJ_H0@a_}[gW_}\k=G^Gއ~?؞~GdjRZ0rgWӿׂG'.fHW )۰6H A  ^xK_{WٳRd+3fW;fQL R W^b@ہA A`6Hv5Byh?J?ڃ|6I<|$Rw/ IEެeeu4pe4gLU;:e!ܼxsCؚ$ٟ&cXOU%O:=p22PIXhc+Is~#\jue\_X%~M8\jŎ_(Uљϋqv id=6n;D; ?QN ̀<} "6ZeEV}ْ^ MlgQALTl0659{s=ߛ3NrYy3c#)<~֊,F Ɇ;nC<_T$%7n7"kTІ>=јQފ`c ݈އ44kX23ؚJj[[*!W,ڿg%֤ίm1^t0.2OKT1Bc@Pjfӕ–͸xz*1'|K16Y E|'%w{-Sgnq 쳧Ҋ՝=jjLSa|bq@nMiv"%BI3=xF3&)&,Iu+yzMx0JVi HU`awqfL i:eذOH//7 "Px5bFpfJJMݜQl_VZౕf൭R)eAThgۯ/Cos;QUlVQ 8`sdPYb6^jTUA2^͇KZQ7\$=zU(DtƌZp "#NoUpq1#X!^L| QWu!W&[ʪT*xx Y5&Vyw+}'a>aAxgI!7Ш@Cy}Pߡq&z=3휚rwT}؄룂OrO9 g8JAIB׫LcK@J{sk5AJ̃AT'ަU(^4K:pj豻N}뵃ɔmZWS"M@ ,:==嶷Ϻ 'wդ"}렊) Ms np^ 9' Uf;PHe0 #کN9@e;ecN׍@{\bYvm7݅fpPQn؀wS*2 L9@† {8X!&&p %P^: }kp/ eÜ}8PIc-;=)k Us}l Nk!x+XO\8XA(A!eH'pD-t(dp\ g>0U=]w>8.9B@\KCr*AG GO) m Hク|qqh;S^{32۽ScmPwٽ13tl|B%W!gQI}s! N_\+hi+5E A @[uW 5EZAAH Q1A2?;AזTnz~*zӉJڎ˂1d ] a- ә7r`X7%z.9j~~+?tՠfRK9׃Q(h8d%-p$BҸ?pg2.LgcgtL<0GC>|?癩ԡc@Xу6"n$yŤn)S%2." 1N) byАv RI~j' PFQ.܃dz n۷vcPT_!c Ɗn ]X!.lد݅VOYWd>2lM@׺7rbc,`Rx ,p=!?.A}<'LY *XL ҟۏNY6e5 ' G6G_f4H˂ҵJ3tc/%.u=cM/ȅVʺc (/E)Ǭo~2zXI<3|.kAM*D #EfA=U#߇L|u<C(##x< wvU\q 4  oa L% @ ug*NT~rwfh'ݎm-˦ tm7`tzrp硾 /ΝS+B7'ز IPo{^sۛ7[0Q֊MLuU\Ni+r( gDJ=ߠJ}WՆ +Gah=\L~5` ^1|ا۬يS`9o@7r{eEb8Z ~t cq ݮ2nܶ"]bmuZg;0(T(ɻmG˨ؚQq_+osӉt0+W Ŏ(! 1m " Lh! _מA^,p+n}1;4# PEכγydH?V SPAƳfjhQ bXIE`gm-spQs5S`XE# sƓN' IJYF Og{FS $°bVQD<{ueh(V'/"uOAx\>iF%3vԏ[jpB\G;DY!MYbಝZЎ5O T8{_w5tl .mm:WAc1qg'b\.f5~T!2KBwGS= v?t+SP*eH$OY6Tx{sŒ )Б QG%[fa \V[w@~ Pn-(˟e6вE^Ƴt6-Uz*e1ߺ6VGuWx壣*NL:VV'4e&hF| /„t2Nmw pĺE7:8.`; X &m2125'nŲ$i]0utmШ #y12 (47"d?Qh)>>-ʥ𘽠1PݖR"AaevfDtk]4y]sn<pÎ:g}D]ԙ+`Ӏ_^zFJ*N-~pGdUg'{C{ElhX*~c)zI8kll* ]~T%* 0od%0-B&b ܇gҡfGCkw';u<*F\,/k,inH IDAT×-W6=_T VUQaϚ_]dmhrcdxq.ϧqqVCPˣH%B\5%S̳VKPaxA˃rx) ,Xe`<.|ar{Z<7bfay*Sl(L1+ D1[0IW1GY@!@!vM G})h-cW3w9Z:#:,<%:c d6\C0k?r ⏰kf`Κd/= Ǹ 2'^?ȸT9YTʈA 0GfΜ"@ʦV@ ϲ)RT ).FX$RA\ Z13'e *8J. nP7@za=?<@'[t4vA҈9Z(tVK?})tڏ:lq1P謹KhϊX3⾴j4A @ |Pu;tr(KOKLFAod A`r+]",>bȪO_OA @ A @ >ӗA @ d A@XLne?{}IZ"S^I [i}-3}33ܳ~[h~|aRJT ~~a]G5܎ܟ)`zZ +~/gӌqxL8q+!ƙ.a6?*]/BM inͤd̝}1{/l-9{JaIn!؃Mfm휰lqo^Dg~{R<`;[+=|o,% tW.3oU]hnJ%u^z`/==y^1t}uϦTa/ޛbqOQϾ p.?'덨6sllnj V?Q-H~-:!Ngj.{ݾBۇ5D  ltV;YEFH< Wk+*Z ,|vnjVymb5tUs,,F+hTZ% ¤"umkևҦVvC6ZL:u NIccuep&RoZ]jLS'!L|'p UwL)Ga5Gv򸨘Ettڭ fDXqp$C.8#' v(8x5uٸc,ƣHIw\$Z.d\A`1,xgP{jjѶ I;`ZT10vvWNt#6w==xo8-/΋5x]+% 76`27W}7ia]JKM6$O}MPV\&jWTzK^zw#uy =v0<}0ҵ93&NoVSξLCPuL.Q{1!odΩ1Cԑ>5 dܸrp\hV5f_AGu C*kUDÍ! F@tmIBlA}\^vRu[:S.::YQ{t5l_l[u:\_XʋepidE}8 \#S7JC@^ᚦ f NTq<U|Q14mȪH%Zyzkj_8oPDǬBTL|t>e"]Р߿kK*VV WuI}Y=Lk4]q捜h#._\ 8`g 9Mc.of+M™/4Μ74 .'D6A PuFXݝ~hg$+ +frvEezbËpgmFJdJ97[8,\yc::r=% xCz,gc!o#[a3>+ndQr:7Էra@'39ɋBCS6iF%3v'[>r<^ V4nOFpVBsz`/SXK*X"~o ͺ} X5[0Z3uo+AUէl<|e\.j\#./=ӶQLl[ ObV/*8.'>z6 L=QJƒjŒY"`B ȓާ4kURW23kF皡'N鯖Ψi"=/9r梿Gb<[{QN{wu;'a-+`iF*>y& 4WQbJf6YRw*5TdXܺsHsn*:-QU12@(Wݜ UCx Pe˿1hҤ!`(p8C!nUpT8šÐog$GW Tm&?+|n6rް漕!2PBΛfE GzxE]GϰV7Xs=w77QPzs|,,,>%{E}"vFz9ĉ~Q&"cS/A6N..CxnYdttSl XVD8A @#poʟ/g˭+(3e.Rȹ:ۀ0,L0ĸ&a6gDBEey\0G#I hx&Dg5{A p ǜh$fG&$x)j8}?q*3_ڽn.X#ፇd%Jx [o Əv$C=\j)@b2 /gQ~3yga$OαUى[ALJFBvLp;:E\MyV6gcyJZu/16랡xd pm_=Ü[#@[Cwx謯[f3%Y&߆~t/s n^'~ZaQlzP0,q+ŌISw:8f\q; ")R6&eb!`n<)+;ii mۓ ʰǺ\}U cS㝔x0TV1oN~`|ztӁ cRHaiv TU45ѧ1ώP/snHvw  vscPg),a4S>aE2[qYxF*f:?p)2m4 P[ m,iYꬴ"S4RR魓62J{a b24"T#)27{yGzyxHfȢ0` Ȫ;͎1Qm2"Bл^tAiKH|^e*[\ZGVc~ t"*|'4cl<L~]CO"tX3[r#q#F#L0iqvҊ ll+۹lהs{sg@Z^~iPs|t2T۫I+ꆨUKqI:h zU|Іףzȟѩ$`O(a<'Ma.4WOE"@EH eA`85_qy:mpɓwNŨb`쮔'DOMs[kBܖ/ltb#ڟp޸dQmn78FÞs]Q{ۀ5r$rxaEO+*SStu/ %>z(ء]^MVfԠwI'vƯˋmp5p 6cJ7D=e)DU柽bBH($YrC[WЃs [Dnp #,7>9^:Ȋ*֝ c{KĆ5`U 8r̀y_fEK3u a7e>vZUo+pCvFm=Q41t*Tʖt'e RFl=Х1^BG:+6jt8-n~g ,~}guO Ɵm顶 GNco;Ne@~e{ wn%0y# F:UkAh+>, sN^]DA @+jB:yzkj_S8yRDǬBTL|4^H!,s{J=X?4"r` nKX9dvmvϊC߇F)||d%m:yN g,KǙ7aԁz!= fdCm1Q(*">a0i>P)ܿg-%p,:21c`yŤn)S%2."+B;gnD԰á*Bzai{)]c&`'b|,s'ZI=W,o,C: }lƊt -OBG`7/6>ܩה( ;/e%m5\YPe* EttHGA\zw{;Щua;*RaIa`#)t[/%L\ڸ[w'EPN9Co*B[ˁܪĖ8_q-hӑBP~G  y-F [1 E (GUj1P~c8hʥ(tG|2 H8/VBj#R/Ro{^sۛX45O_BjgЍ^Y0Պoy/b8FV&ݱOY@N ",sh./mA5VahqS տi[UTbV#sl 5y=7e;(/lSx}j=\כ0t Z8~'f+@gS _z/>GQVzsCQ<qS!W:پ~JRi\VAIgv')I;aуɶ<71n_rHjCcџdfp2 uW606YFsPcEYOFUv_IDAT -hlT!{_LJhbK< LJZOc뭰&HWo+At(AwBLv=| $Bvij- 5>bP H݃Uy(bc 4=,exE N.6+\?EMʽ땨qхʳVB1Q!O^v{Sݞ-,t= N%*Ͱkv tA=8 Ꞔ-Hn}{Bi)>?q u[w%@+\>iF%3v O}BY2kN< @HFm<~1#mG-h#l0.JHNMb\9< `2í)yGt5I6KՃl bHY,$Z, @XJAJ#W֝Ï/B)JU'4e\vug1??<_.{{#X[ m  Vfܖ.C0 \CU.1{Eɠ7u,^$M.{02f(LYr4.R܋:6G*CH^LsHWx壬rB[3WRف'1qsEdgo*1`Yc dBEA? sl,t'1 ^U-jܧDiB@sE )d)JmPPa_WDAF[uٶUyun<1QtgI a(V. i B>a GFD!ET 8.;=~!BN$e~a%AD&{*?10Hӣ`@"Z.dsBe‘7}O7( A`fH$;@T7"fJDEr;'&0,>heUK4{Մ,yoĊtaZvG8@ |*\+""Cw"" U~ӴUߴ'A jy% A @!@oZ A @X^ȺŗH' %Fu.\f],@e'sir@s_{r`>jƭ\OL;#qۀ71o`6b]9] oA\dfpA&A`]˶= ׶/hGلNjr3\H65AD&vLA ygQx) x]4Io1;\pܼ87-i?-F+vX3裳bgfl VDFܱ~Hбs0aN> [sB \qJj'CIs9+i.d!b#r!O5w6Ze}ϝo/@ihzLϑ`lpV/lJK`;]zXVv{h%Y%1yX(-ZV( htsz̾Nr sGp*{c.~guTu GO4Jj |3lJvii mۓ ];X7o :V<ρ8]2l߱P$Vڄ6wCf1oQ31j&dH;A p'X.YC*2/]PSJY $i}Gza@#-֤ίm1w y;<ii!b=ݘ JegR96.6ҲYFYM,u VhVUR `GL[w%:^lV;C_V;΄XzζTb%!gf燤%n4"'qj*46Y#C: e˭UKI:ibp&c5 1}X"3ܡ"ppH 6usaJZ^-RM~]COB14ly\3Bt6 \,WszqMeZ^ߞ֬,lt cxJWKR5(#!5,ӪV/xlZ2`Axg" @ .|@;a߇׎CkC X|nរA휚rwTb`lQ W)gAP}jIC#k9~Ya6]:ڀVe i ؽS1'DO׃F1t@W315JlAtq  >̌4cts!8t 0<0t{CY(]tOimfSoA e#^Ea23J7 @8l08VW]tzp  .=`8؝ 6.ѕzQy964*+6zE iwo D=@`u`/B݌k 3.4=ł8B!)]ۘ] $;Pڻ p Q8F{3W`=IJuAśЌ8o3k8fV@Yàu 2t :h—T4ҀC_UuPCqİƮ>a/Q5i 5rɒQ''  D@ Z Y1C A p!jzOqUy#'~h,تDd$jvz6'&>Pւ0~T` NTv|_I5`AIڴl 98zn|Hz=cX:μA ՎBqc)C@Te4XYyS1c Nq_0#Xm`L2:}ݍ+) X80YeƱ~{L!™&#MvգH&Qsyy@O֙! 4s`:5`?*%b49];bua;*RÇ Ű{Я[|nseFK3+Q>_RY;eQFco: BBgS 0}xrwr@!w`=Pcy5lZK*f1#0ӅB6=BԯuVzC} _p%hfl3:T5ZqUA>`XBaB/׃(_L:7e;(/lSx} xs1^@mwbq]\U+k*SY!z!yиr߱q#oAuWg @ ^wa#BZ@'{[ ~;Sbт4V1=͓Hc Kdo4n4X Va[ 2]_ _ö+=mĦkPYAUgRULxLjZ?%x;? ¯v'"q`o]#^DӨDO1)Azb,X%KWjP[p[4;2SUbm?Lv \wW٧<1Bbg=lX|=`>wa eqʬ9 ܼ&٫+ۇ,%ZH➃, ԗs9(Gk}> ?Ik ւvdO}k5~ݕb}xQ&WXdlI4B= +bjlJKIkuWh}0"x,A1#9kxØ1k}u>SdW,K , xՏ}^O=¿~ȃ ڡ胢  tdH$OY6Tx{:qiB@sE }Sr/6ӵɐVpE\7ؑu WmP"'>W֝i@q[ @,]Kb8k-4i 2^_*ϩϺ(kxiZ rIOa &m212xlA1@]7?ٕ?-y(?$y.>" HTxx-  *[_$ZGW8pSu͵@tesőQPD/݆ e uq Yb8];ƅEbK1/+|n6}O.}E˸8o~C$1\5%߿Og˭R(y\si)`H\rvuˤ62v/HIJд4Ar*NfEI;R !1*`.BcDq &E2!*Q,4lϤW(S`#|I{狼.P#-.⋘yAR9b px\*L@{갌ޭxE- OAgA$""Є[h!]iѹ/M;6` H L$Ks4KH!C`i.rljPqiKҧb~7<-]@HjtAb„Bz5C#>Jg=J ]D@P7!Ѭǡa$A+oy@Ta]큑a*1uGsh.j\H18F7@gcN7NPܦj6-o s CǠ>>4S BDawzv8 ̀)3ٺ;aW>1 W>aQX^` =RU T'@(B*OEs^\+4C9t.=`c qG_mgEz| ௢|p(dp8p GpHwax8 RLtBՅ|6 V pB* IqjvbJI ww.o ͪIENDB`testng-6.9.12/pictures/view.png0000755000175000017500000020631012732165123015744 0ustar eugeneeugenePNG  IHDRmRˡYiCCPICC ProfilexXy8To,c'=AdߗlYc`%I)*VR)$f"ٲZDJ3[zy|sous,|@?H&j`mlԯ=8kp,o0, )- 7|sORF[QC3`@0G)e[Rp9 xQ Ƒ0$Yk8ƌ]vqzRtGb%y{+M$j}^w $+0 <ïe8f?rhÉ;zV?ܢYA=r;=mo/± - ~!YF.zk P ChBnOSQibisB7cY2e8Zxo^1_~`dTAN"C3򛊴J@Ն#jE4ifi~S[DAaѐɴٺ9!kf6^v'9 dqtvlE?L &'= ':<-uYsߍP{R}\WēSiW_Ξzpܭ쌆oe'u?=7ATWs#B"bز U55j=zjLAM^\imjni+j~ûٙ%۾ץsuPpHh+̯$5c{.v\m|y{l'ON>}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP(KPnoZ+kZ ^PQEVZ+*P y%@NZsNٙ3o^׬95{^--1'9bOZ@݉t^ǻ<;~ \ r8ܦꑬ<_dec'y'zio|W^)? ȸ:5E˶Mq܉&›+s4fRţFM׈aWV~wOXDKT$[#Puҿ^G>[[ X X m s^t/? 7Sׯ s;|"(ZZķ@N7(-ǣ _:Nѯ?/7dhlƻ2]5o"o{?{ZY{<~wVEgDh^^xkʅ0; o̶m6okkkkd-s6Ͷa6w:˟!&f~v5k*m /GlD^x[1q~mI`K'ּ^VC0l P"V[yo;YY#^X~xLbͶh|4_X T7xɚx0+KmͶ3inmy//>8q-`:`35yAhGìnkؤi}M>Mu^r2&oL(gyq&Zx54놳p]:F_;'le~d .ֶ87^ f[4^xh&|k̊hh7kI[ӂDž`H~Xޖu7/B#m5:qx['6eښ&W͊j$4 m>] ]py'Z['j;Hjţs?~n!r£k OF'[x]K*M*m|\OYlGG s\_Rj׍gO{<~~Ai'a)"/8.[8W|tT#4m-x.~9LGIQʬYi ݫ>N|9ttѽ{oJ8[{ >|x_|ŋ<#ItT!>NqqnL^fZ‚qkxӔ)S\s5?hժ7P[SҭA >ӏ̜9mf7$ xլ/EF`ZL1%w ^jTh#5Jف^Bo:tlh1jB( #>8{n L`02a.&>m2B['̎EI6^'*N: ;rkkkkkga;vNs2ZnNa: 5Ӓ.Xiaf~ū%p-pZ]]ݩ񖉈p{w/-Ž>BUYVyyrYwFC.DZ谸>yr|8pjjkIO@vЧO悧Ad=wށ_ 7}CcÙ>;Uy8,q )%M;׌A@8|s1iֵq Ũp# f^{Wc<;S~fR3 Nб[7g6ڵ(B{ QOmٲ6l@6ѶM[nMϸ)T>Сݻ7a7O }6tNQSSĞ{>\&bĐgVퟮš6=Ч(8%{'.K`͇Mp^ح8cJ8|Ԍ n4 R\Gxex7{6(>T qq;O?կ՟p 3`֭QXXΝ;KXP|g/vld玝#O;4'(xz._q6OkO%e¡rr_AOOZ~WCM͇q*;0ƫW9JU?5 c8ptǫ3o?WzMК`DeV ;c>x.Lt3YM7RLׇ8{X\ٯ!!93\ Ԣ' tr;O~6x3ѩȳ[^&ڹs'v [FFz22СCd#fOo~;A:DmC(ꝋVvgK7.O|͞pm%{.} wUd 9t]Y9ꙍ?qsQ_ԗ#4 5[ߗ`I7l@ h'/!Of3Z m%рա8Dj1 &,xa/h-ːeɶuhv-#4ˢq X q(h35>T+F Ud7/ldU|{9µU89ܦZ_ on#Xf蛼2_~sBl=DN<;Vmx3p/S>}N]Xy8 xQV>wFMCը=Fk?>cƳsh2z`_8wS̹rYY\,_v.'5pMuM=AA"~Th\dP:E41OH`]3,ǝ!9P.!gB.9,zAmd=B3設A*zcw ﳳ`NM"n0/f3kpѶmkdpmɁTӒWuV-:\s{&LƿdM!t݁7OƧY!_}܂?J3 rAyZm3ߏpBTlgV`3§חuK>@M~a|}EU[.SpUx }QQMe@:-峿<{/~gUi~sD+]錽鄗Gb?>u J}F3Y*&&3ϔl&a00Hm^AiεCR3M`]~N;eUfq;aCΙnhmYߩDVQUN+GC1ׯL3V[  (2MUTx:9Ȉ'KMU{Wpf?{ 74:T»/}?`)\MS?Dè)?]{/V~m\rDpmtk7Cr, p_CU09w6_[gYWC_M͢oOCQx+a\F*c.kLe` NF#ڣj/i\$(q7Z\K<"B jHG2anˡ58j9x12۷G:v``@ rO_8RD:UgjVC^Qe]:tE#eBkŴͤҡláJ-Tl&LÁ0:_p;\5+[8ψJ<;kg4.4.gOЀy)^8w 9b||!C!M9H{9ee!LwU_wW<ӠM7tP.2;`^{Fk`h6 fQ@Ȏ\t/b:l?uo^ Ƞ;M_b}y79m>Y^B6GDw< cW9}3zeг!*dTU["L[~Z<"6y>-*;!YoDq*Ty;'^_qS ck1_&8߾=>th\x+~ӻ3#(08=*(; ? z#Il}[}!8v\?Dnsμ\Z;ʀ 倂׵ s9 4|0iZx90 ^;wD, З?E=[Age}|e+h((f'h3x"j?o]A«6ᝍF.vjJ3v¶_g,zk-ꉮYam@hwዝJ&]~rNGWzLkgO;nCsmm+r\s:ש= >2Qԫ'fTOm(jC6c=ݫ;>ö2~u"9tQ^Ejvztāg4V| vk'Nΐ(;k;0Cn5̃PQf)݊uav\0r8zZWG}v hoI"f y}?-}|s Pp 21xE2t*h)^0>Emڿ>IwHj9ئu))8SnumEy^MlґED!et.Y 5Wmw{!_?Xa5G < sѰ/t KF݊Txf~:80]5*?۵kʲqQ{!/+{?e~̯Kg< `΅,lofYA=.$=4s/S"aRp֢oBRY8ƪpY@kN_As~P|e-EsG$oe&@8V\Ix#0,1>#g>Sgv8~vL 2+p0o>2E' fs;%Z X />3|'/Xj52.g1p A55L LO&J+-xaΊ?d-h.T|"tx/^@N܊fu-Νq~ks?Ok`sى#'كИ pbXx|qKbW^̣e?zc-"JԷ`"u+-'p/|ҏZoc83ܵ_԰i-k\ۉnJqEqG $߸f-`-`-В,N|Sp|K-nP 5p[[o֢ =I߶8Auai> &'JJhZ@>9+h-`-`-pZ@77gli"ԌgT1 04aQa1u}۶@K׍IOOKfj| 9Z/aXYFyL0kkkפsc^&x'WmшO҇[2u[ฃ32X`m~5'ӵ6n Yyӏ8p`q&+6&M3c-`-`-Ђ- ~OA`?_gh-}p1TٺOy''"x!4t2nL_~%y|gNjJ`/;[[wJBNO?{.vT㘾&0#2y]dّb#' c7'I~G/A MRlF IDAT59'-~]9 'JଳUW]'&Mj6vN̅GdnpID(4qx\ּr"'9!΂ \^{-:wg !-Im!C)//Ν;ՆG}ƍsq%a qiXܵƙۂ2,i'/ Ȁ܁BұiXey,ZFn8< w!C)&C晁 DkkeIծ];'w;}>{ mOeΗK2lY޷ ^N5( tM4K4K͸eѢEN6l33Ȝ hNJ ݻwm۶Lo,9(*e˖}ͨQJjXcYZkb. \آ܍ ̵"oZܾ};;<'̀`X&MK(ݫxckYZZXX_@Yv-l,쀗>s_wvVx } 9 6O5Hi5if;4 +$+5м誛P Xnwɷ5sf HÌhJvx,^qTX X Xشi:B3[`:-cװIq1AM7D΍Ӄx2)9(&bƵ3,,É}GhӦMt4ڮ^14{Mߝdpi86c\uTiΊh~̣0ѴR~-ASN-}4,ѳ?0>x3%\⼙ ~Cۼ|agKcװI3jXkRkpN7 ^|z< ~Eq-xך_ԩyA%A?,^&`ʖhLBɌ\cQb ]W7fOv5P&Z?3qF \s[K*k$XLf;cX|'8l0vIsiNBxr/ht.3l\~bpL'DF<4~.˱)xy6, ݃C2'`Ce!?oj*,^˱|1bٓp,cv+>`:Zkz/:r 6z"Ș{tp.36Wl%Oy+iX$@8Ean47%]GgAKvB$.ݐ+EXN|gTl"c~;n|UQ?Lx|ZjZN VO!BDѩ4*.DNȦ{w4; @N()=:N Z͞OR댯h+ݻ 3.DP<} >,)rx>c-pZ&\xHf\stIhp'.ʀw~47%:9X> ezNC`yb4Lxj5:?v^#ﴎk0ᱸb8" ܵThI'v;L +0Ǝ]ȴ"gaZ,`-pY n$ H0Сs3@0L|3f zܨ,ZD;v^*`q@` iB1%(nM>yᅞp!/5Ϩo3^h3M,KS]nvs.ױcG3оEyBWaL YWFdBބVpʑhtמH`e]+QN*!_Ih&çj̡s"^7ÝbN }D2 W_99q~._OoESxZh*rp[ &h.1 nAȘmsoM'iXxzȶ^B^֜ w^] ϧ`VBٹ[7ZF}%6?Qօ_tQ.<e-pX2gdA﹙L|$~O^,/Oa($ EIϥPݺu#;3,r_}B}b#Uق'؏2xV-> ;(/h:/jhy " b^ 3h&owva 3BzVW&$(Q},`-`-,A_PُGi oIa1}E¤ah@p*>MAIhL4 j'd g X X X Y@fD_Omb_(ݘHӅq>I $J\' '\DX X X 祊8 {!xvܚ+ x3LhZ|&-HHী> ͧFWkP%}=EFTVZZZiLG^6i Żv4ޏ/:H2@%}jeEFpRk#Nx <`p`PX X X 4IGv?Y êA!_?)|R 휄Gp 'x7p&JL5Iyf<. Ʊ@Z 7;rf!+ijkj~ cp\v|cEr`--/'qzQ\L`?)kkk@%yΪ{WIBOxN)&1? 1/|ppLxEL;hrn=sx9, n|VNs#[Iavg"!!DѾMEJת0q/z`q&M)y`?`\B|=W@)2iý6$?OBJqb-Ђ-7\fgϳIC`XՅ菤'68N- zfΝN:Mv< \ /51 {&f`*h2zplxQ׬Y?^z) Ĺ8E:K}z^oiK|KFŋ`fva zMS0|"cۯD\;=#9hk-p"[@<N8\ .Fݻ7$U$h{nb#&xBgygj vk&A*MqƠrG ʫ+~&{dT @aHx>cӲ XafKDÈ/LJ?L #=^M5wQk(`Ry,jq?x/̒f#CŊ1T{rX X 8;}^&_?+k:`cTDn^+Dfv!c5>‹;KG=zHM'~6izq6ԯU|&&NyoO< A5{PX\wkkg q))ܴ'&=s选~5(ƇNm` z+AF|]L0N0!xn\t OП*;D+nF.ơGo0\]]&LV~틿K}׮ƞ{[Z$/4uDZ"],tF]n ٴiZoa[m6XLta>/Ҏ[{4y0S/y)Koy睸 ](@2Cp W%qGP/bJLϛ-ZgE݇gvnZfDp$2}0yz)ٍ='`]C0{M92z:2k-pXh }ܦF :hZoqrm׶ uN]ԁW̜R3L3:eHG5qmg$ !m=/vp]Ya'//~ \qۗn㔇*i= 1ꆑѾM>LA(;uCrT>x~yr<,ZDO?߼.V<w+> }6-!}kP\?/.Z}:vsqfV8(˩BKNutp^N^(0k1^y`́Bsv:g)񖌄/^EpRKa>2G.mI}?qRsSu>F:J>I"u'iߨ"Zu*>VH+lDa#8[[ X X ] tlCEi"w t6RFf%D:?k/y© ڹܔ4x,ZZZ eh1\[<#ao&R|Q$ۘGAx⪛CeCi&m,æImkkkZ.g!z# GhEطA6IyZ摾4>.Ԁ䓶~)NR ''c;H4AYDoeQPȤ@2uq͑|r^x'\95SAoP_RǓO)%᳠':olgM@hQJfeRiB5T0ܴOd7żмrgLޤڒ 硇¦MLsWrBLY=36t!Տ.߄9SJmi5n_xY bEU `Po1[Y u B<̫HGi\k6o8!ZLZ@h@p*f 覠W`7ϵM5n9[OL;PP]珧Y,^3vר48/J})'X8v.RNv&_cہh&@g6^FLBA83yxOe$08'UH :E5N`O>09|fǪ r6+,{nC~_Fª<+*(,;pȋRdp@_,ik jv6iP/g u{k4m<')--E=&yb1DO pL- ؍?I+BG]xnF?ߍP) Mʌ6~H6+c`.nkkkTX>GN#_(eоE;_*S i<^L{y]Ө^*UA++ Njm [M.. pXN1wNS6?2}1;_\LԋJD]m4rrJHyR@ҫiK@-@ވ, IDATN|Af|]1-\mƦ޵ Ov׎b_qml9 ,АN{CiCx~OZo]ʔr!*Af;#Fq,a 稔.AN{Pv;~5θpƀvAc~kE)P sAT=?9*a Xv $bЎi\{^4 3𣙼 9A<˗&_TQ$d]} 1q8bS9xlQ QH޼װ`*Q>|ǂٹ'Ԫ}!z ]"{a+桤~&Vrnڠcr7#uP;ť 0^7+T7fOn`LL&VY۲h!P/8vnN\p+ڏ9@V~)ށ)=6hقi݆˖.ͯ= ˖lwMm*De#@un8gw>MFEqۆ]X͸9g9i+S1|X b(V2rkh䴠|)v%#vމ:e/_L; rř#.`xf6B2[ޥR_;l"+g>O+E[nSohm);4mQRDg9!?(mtť}JϓҪJ"uvgasd~Q%L^>~~)u5/ds^9Cz^ >\#CH(VggxjC [Z!D-cdɝcW%6J*ޒb(8INx w ܩx.ʶZl>zs1NZ;vi8y7%\J/A O^ɍ d:;Kryy2srr߱?E]'(#jRSP g uKk ul>8ƇᤇKHkBhMuZ-84ϦE&I*!z-~ߔeay=4eXMѤx*֍iY \Mq^2x6 _&RlwkEE^쥙H.w+qKXqlh>zۨQ>!SV RqL5i2[":lhhȇ@3;UiWT;w3F5x,ZZZ edu &m͋jʛt۶Hl>q|Җ:vf-`-`-lmśxv7-uA|o+ڴX׸{qLѰ[[4B1KSOCNBt+,DdWΣ)Md7虮x`fʍж9($y0.hut·vA)!5^AbG:_GjCxEO Ѵ@pTX3G򣙼G?Avi]0S6*wcˀS)DjF +rVg_a Qhʷcݧq3A-͇@td9D">g 6}EVۤSa>h@p*>MAIhL4͗ r>c\z6l494Bv+p]-׼iZ^ tvn' i0?w'osCab[L,3k-`-b |-*&$^Kf E^IK; r6\Lz`'VwazUK~uFdZ X ͇x@l\b%!lc '7z?lhN |)}l:wـy95IkMl[ X WHG2m`!*jLp*fakkk[Ch/c6/)omZZZ l>lg-tj!Ŀ~]َ׃/m[@[C6C0o̶P ,f~,l-`-`-pt-@)#}A+|gjual-+9Gr v]x4M5N4ώ zp 3l&>M9)_U>C\a>bX>8|ƛ"< B/hIky b 7żмrgL@c r*G3tcT7xX"йY&kk-͇@q>ʃpCML A\ 7Lyk?K> rd9x~r~ oCpQgdJlTͻfڔ8 ]`l-l>Z/bډ ,XVXZ QSW5.9gS!hBt9{ 899?s8p0e䯎;_lxgW;oƀĤy+*1 2slUח`YFL0 [J0fL J&-7V@c 9! [c:p/y){K)|44(Igľ/ɘue+qxUpOkbw5~F˯V/ÁƧ?mP=.K6#^Ceo;T@N|1%#=׎_iXuTfMw&=eǢ6&_s^!Tm=cfFqs/tdl|kJ;{\8JYzl͇{ Nj'nu7p͙ A!)(UL߉e:҆cފ.}8Tx 94t@KP)9m[;@t !D|Ik.?wI_Rk9^z)  ʟj#L#7nMh{??_~1@+?8/3QSӹ4IkN{Rl)8p k.+s5}Ĕq^ỏ"GuW5-`-`- '{>zov)iMO9erz!7WWv`-pY@!T4w䄫k_5j_*QGMN!oc[E nX+(n>!:5;XX X xXCHiʠ䓶fm-`-`-pt-@Cor}wf;^&'on! 7Bi'/mѵy=B YNnm3@$:H[ | 6.*gzEӟ Ѵ@pS* XPEIƙJL z;^|-}Xiq-͇@o5·vV rНGtj֖攤`Evծ'PڵEZ X h!&Is 2f_)%tI4zOStƛ!EyXhQe\ <.bc !TE/J eBg@[MC> 2i3-;P^(%KViK;n/ $28f*%|B3e£q)9A컹]4A݅5:'_ߢV:Yv쯊䌤.ocM r<;zl5~z5&ҩ7ǢShd-pC󯍌jWbOÍln$ypUWgϞC~ӕ;bqDv;)rfkT8m2gTO ¼a[lw{v.ĔRqwuHh+Ѷ͇ !8Ax9JF8DfZF9F@&d96 $uѭ͇@aA@vڱNɻ/5n9 aK1Su{@$ 't93_Xn۲H6BNZ˻D_JxVV*kE8sA Gx,GZZZ 1 |7N$p':C] 9t')--E=&yb1FIݲ1;gLka9=(A6s̕ë\=iDЃ*#(YB'YNZCHxԦsw Ǥ5[X$yՅ,[Ÿ'uˢ9= 쫈Me@Rm>L*b;4΂ŵ9U+P>eN [ X 46BL{9nXF1MR&I햙 'PқꐍMVZ6BBPmI[jKd)f@2 oke:d:R&miIx4hYEjvl^x'\95SAoP_RǓtkkkf͇`!4`-`-B,@6BjhG12C0f-`-`-6kSc@q'Mxlm-`-`-d D!gj!C~Ɛd=6=4ݫh@p*Qb2c^ߔ<~4>zW4vkkhEC0}jFxDE5N`)O+.a\ȧ7\ CLቑ+tmX X `gc!_ q\ TӁ{3Lx4.iw8GΝ$JuϏQs6*WqŗifnCnǻb-`-p\ZCQ"OvOnr)åӔ.+W^ye 9 'lJ3{\.g'9b7FڭQ\OiҜdl'EYc0fVC0)_5ƾ-xQI@9۸g-`-k|555fjkQ]]CPM{QفF{2=^>^kA z<'> [MW\\} 4z$A'ɉs%v:VlC޷9ryA Nk*/MCOÜw(_޷g/=ZZZhȇxڴtTPvGϯ>v£in8Mwc]Ybر#JJJꫯFeG¸h\t3۵rRdO 3]u䆿7-EYOcDbJ<kf#x2?:..@1>t"f!qG˩!C_yˮ n@1x f{OēTO<a-;~*}G݆ 'tB̽cohݱPkk@4Bjkk#az@BYB/#7Oqa4^Fv -:UXӹkM(ywTj~ ݫ ٭ aќ?4$ȡ7uF hhP*ť,A ŸkDi(n31ododJyj=&/Ðy(wS@C>rРp-2K< tF+Gy7KzdWAu L5ap;%'ֱƝq8q"N9Wc-m$kh8T)CEq/N?Z Υa|~gNflMa)$v'x:͇3wi|LZaSޤ}晔ҧv̝ }އ+B8{},Ofb`ߐz^cţP6Է(B<[Chz@M>iK F>"t[Png-`-p,-@C̻x_RǓtkkkf͇-#.l oMGl>Ԛ\ly>ۈ֔qmcxlZZYC1tAv"q ͯ <~ǔ9Xo~?(膝{ J2vcW^w]^ijolu޵ %E"Zݎ[`vl!,^9pf D ũRBi?.4]iث6%28K x3L O% IDATx4E &\;/[ԥŲM_ҏtB14t(DBtAfdJqN__}֨=i%_?UrxW=@_UOYr_(j;Y-pCHrbH(N^֎_iXxOg'?& aa_[^!~Gy협ӊw%UW@HA& ED TD@D)b eQQ@ .6`VQ'A"[@y} 013g9s9w;ih_/hPC!3#nFTwC#&*1\d\9<iͭW|=;]g-qw{4VZCd+Z)1ܮuly6 +<\U*wBcW`N7Føj֨Sdl6@4] ]o栭'NHd|rZoiշtSƟ _¬mv6o}C9E4FڴXdfijH{:ǧoÍu g~j x4!kU~+pQ8)DW"؉|wjwb >|%1g`o;Q|KPSrOX4 S9 r!g`w*#!'oX홒f~e9Fy.n;[c VS4mn30 ݇hyWi M:7˦]0i8]tK#_WgL::m[нYMKYMR=]qˍ7Fq7E;gݸ䷐d)vq 7 _!(ͱ5w`I{ -vk |CeS"y⅄DZj@C(7 Uzq \Vi̸*Uwyn6(fO૵(Hs+WH Hّo!X>8^& w`ko?#oL+nQ@@S UR,6ҒRg٦<:|[+=:aWoy.@@q<6B6Yq/sP=3e'Ƕ g~͟C5 q0FĨ1wcÑ6Rgs,u=.2bF>_n"G}gYAY(BV.qP76Rzg۹#п|{RdG㪆Qu#%F '|:}ؿDz3&Vu~Ce7 ;sY9'R^u<$3%wFᷔ%9<bytz"t/x6e}S^;$v;@@tKwڔVigPR{4@HCk(A\ׂ^x'Ubi-~p}4"/4{0?ś*j,S62n "~t"!ZH5Z.O!.2Nd|ʑ|q,溕B x˼$sj٪.B)nKk@k@ktꄿ?{Wa&>\NZZ xY2RP jU:U%P0u|::g:ۏ7/όئ1!$J:,_פbth%3K1{>e=*t<KFNH $W *wBcwA &3sa!}{%7Y)quX"_Z 0#+Yi8j^ &D\UDh !iհ}Ty+%J#JOo\6}oaPSHc1JQqqBèD1'?6~CuIYg(ڲhLX03 _^/(^a`SΚ?-{%ct:ơkHj*wy=c֬%pƢW6/Zc5wL2Z?ݍtR| 3m5p N2Ulk$?۳,EO`QS&ᦲzmʡ!kU~+Pd?W _yS [ҬsRZ @ 4ې38}RCޚX]!>u!`s3q3ݔZ2u1/%Ϗu+I?+6FqS0s(Gg"h91ldGj2Cr9 sNHalTrWWR!1LM!\q})$G߻KkZI$hCԃWgf&(%ɧc|U'qy_>>7>{;t9kGp6UoѭY'oo9 v*x2Ld۶+pd{Wڍ|  8ZE^֮؈LJ]T\:F%QJ3ʯP74ߐfDBh3.Edz*u8_"Zњn~9ͧNz¢0zxTTV܏ ~+~*ObnB'4RyA9HtœE7\uۇ& &VR&>tZQ{@jo) uFปOOإxd:t1t.t:c3&G'/1l,&7)8'ܠ6Lz-"c{ UXm]7zcn:BjIz|x'9TXl@s{0|ᬄ >߰c}&iԿ]_Ί%"cb)Xv6';xu<+JOqohxaHHH@•E>Ik#̊p9q< J:q=ۣv~7Y1`z:Ժz?C3626BvV썮ЖqEei/)nJ#b:օi T6_v[ụ1N꒛5^h;-wsqˋT*ނqGb0hۀ ;/MR Ds>u<)SSq0$!~N_~yq˯5K059M[iI,f':- ٓXd (Z[#ҵ sWtнJ,9g"aO<>xf͝FK+(AiȌܑ0j#-b1g#}![$F[$Brl(tIk|hC`nM.*39:SsxY Sp˞|3,j?oNmȡn^;> 01oU Zt<ۙ߆ją_IYptBô\ \ucp/ٴ ZZ'U|VC J|K9ycI]*^ Svm\7Lt g:yTFUw^waہ*8ZUU]-FFn P@g : a 2b<3;~;z3[F/Atj٦nc4E,p' SF=N W !r]idm͹sEB^"uV|&.S#oeD"9O2`ͮ_JL3!8_ٸOfg?iqW" M7\m~y)]P/Wӫl1>,Mߠ#qY @;|'ЙO#5纔jtW:"c腎i:$Yxjm-ͪ!Z$B-|GLnl,3O#9mL9L#<,f{:V<*~L7?Jl4 lO/uO.Aqv9XN•rXW}si.NkOz.MĽ& AxZ@ xҲ6.r{Rg;:;*Jvl~NO9fnrPٔއ xSo-yuډ:$G&?CiYKLۻ"c]05@ֈ!Pd[TNrtC WVxfuq T%JPY}tcdUe^8>etY긥Uk|s8Ӹ[,Q9-An!E4 )8ٸӀ7%7ј;W':ր씑 5oY5Rzs W۩岜2 \!~xttaM:Y- 4@bdȷ&FyԲU RӖQtn6VC(sr`\fJ7ۅђqg4^wO+Bl3ٞ *ʯf%* P|̴^,*h#ɕ@\-Eo<L|)nʗXT[Wy0f6N"Sq\ܾhTzG`pV i,ι/JWi2;NZZt<oM5¯¤,8_m:ůqZZZ4Ɔ^A|hK(g:yFրր@5!Yp/~N-WݚրրրS xAV_`_`Bk;asێUf /("bJhnPзC_Nvv4\yKO4,/'Yk|i8۠]Tf#v|Ty+%J#JGs#n@FxߺϦ~#\b9tk#|8`ftvAЦnj8s!-V훠nt$}@g9F A75pAkC)yPuCsɃ"DM^ne J-%$2ዥshil^xt@Nwq'f I49+_OuƪYsP^?=zCUS IA]K[?"6k2VO Rlk$?񼖔˰pżk*t:D^ӆ. Ec݅D4xkj vNƂW`Tv$y0n.܂ 9CrcFНCD%p}GOǂ0.%ߞŠ~HrCp_}]H'*l“ӠTG'4~)#_2(jBLa@w|OaD+'C"вm3l-6w=*! pkQȚmXy$wxm^msvaf:İ~]ђ;J ]ѿcsB;~Co,JwZm qláLkՀC7!! I~Cݖ~!u:Rc%Hnxͣ#tEh\ X8~P1])'<4:t-G^}55d-9M|j4^E.S qF"bѰ ӄ2| Wi5PY4!=L'u+or^4U$)8E>Er~=uGoA&w[i4Ga#;Zà CQ;?,-Pvߘ,|jBk'M8d{>ypMqu$vnMT+>8a qIa,d{f#Hp@Lj&*RB[҃C Fvr߆jqe|pbۘF^I{TpB[7B1\.e3vG˫K,EKpim ')~jyv;?œ~6ja'=x7ZztR5j{PZQri+'91ͧQ9fr>}09Tʐ=7ӛDɈ@jRzs W۩2e>jU= jm[BY'c&UQ^@ F B!4 A mw ml0xaa֭1B,֛ZaiкYzc>Ɖq3 a!<讫`' M ,":CsɃ"HFZ9ߍŮ']YjgǏlDτ88]G5+z'C:)'c5DW=! t;7}5 ZeՀpO.mW CPB0AI=\^4o&>n~&8r (7g!uh20|Kf}&^Ug&S-~n_kiTGmgcU`:_2(jB+ $BT8DEKXq/ݷܵ알wg W`S$gc<#b,v}f-Bu[>\.ώAK2[Wunhw4&KT{Pʵ(';ӦbGˑxjDG7k>k&`L8;Ǯn0' 3k([MFr418tM7IM˱uKHYAbS=kSRyHcIk4Ķ1J~2H:VBtN7p#Lao NBPCX@hdLhODBED7vϖ%gܟLꃜ pSxX}kbs_ h@0 /o^K2#3'4Q"+6-M0{yӯdϺ eT<S=0{z ^ 7mlN]ܒBΠxϸ'_#?n꺃1 @Ej@m]>4vtvpUfTry*tRom~16'~2_P޲`zڶ+pdV>۾?Kn,ēѧt˗d##?Ghe;y[zM:uB,9N7}-M/c,6U 9ȆFhІ7чȉ=3[Jj-D{$lbP%x *+ >%ut41toy7u3h7)6Y5S?*p:.d#t1:Q4NZQfu+Cn8wX@c+}ulx4OuGl e>meS%Lj'#E >L+5w_ɻ;,&d I4%^r'n):8tS6{N;iɧ)I$ yqZ*e$66;w~Cv׳=jgyu-V06qsg"wsRF& ysڌYCk'nS2'(e53bѴC͸k#!! W6BT ' 5‰s R})1` n#?9.I?sGt0fW\@m6EWٴc/M'Ѵ5(vKs?a\Hs溓TI1)rtʈ`-j^]Sٴ5F1ov?LyCQ6Kg >K~!#MG?ڷ3nH,zm̟"6u;[M>R;qbs0wraG|r8zl]=g /$Muۀ vC1 /(2rBqӸ 5c.YZJdojǼt ]hy?m*ONƑNNV' @l#좝TVU㲹fdlyf052j 8 JL >S09EV "EF2p2Uv>9e`Z0ڬn}wƒxԧ+ 1<6eQ¹l$6M<ܜƴR39S*e9`o5{QN8ۤe;d#H++?^ 9>)PG9!g%9%ߵT쟊2meSK!p"OAU9'4/(:;&=_tlUPx:)ܶ9G( ^0a<4vBx*L-۵!pᗺܟCs,? ̣ -4*Lϧh>zv;i(+ <3`;5`&p`*Z,- Qv6᪝TeWv*}fNUIB`Bk;)`555`=0gN JhTL[u܉``*NTi̸JUO yIrjsI(Uր@@T;LcYJrY]2Rh/H0 T6/A4ݧAW @u"jsGv6 .j'B L,~iF^<+g'-y z3?mm9m:i h \$PUEb? 8uPRrbb|\z/d5ib:2ҹj!Xei %ƾn@WQ=P<|))̂"!0N~]G"g{t1zXa|BLl  +N5ƀA˺x\a0qm?/<կjQ_#y!huYMt/M556QOˀ= v`RΉf<p*~:gjNҥ-c1ڈ)p!#!o6oE!p̻.ëX"GӨqY<^휅QߥOC\ e&Rr#\k@k M܄ԙƎ4Җ [v[+dpD0I]r_w©Kq=k\AW"jywdz#p{{K=0mk5L>O)"sbc]oBlޝWv.R?W[Yp?%dSY鹈W $$^4mzxOߚ3hݞ608 r.<ZwCNgLI̻x2y8\|îNZUGW x4ANl#Q4ׅNL[`NQ!<*܁/]z^VwAL?a!.t׽l]!.;m42y+@tL8/p`6xv~yGom?$g Z&Hg=X %gP:krQҲ.xy/hrט8IĴ2BԲ]~9@:3gv3;v(lƍ"?&vR$UB`*޲CNSq",Jcրր@P4\0'pmӧO#22k8G]SJ/'ӘqV03_zATc* @9hBh h h O<hذ!g<誙(:*Ύg 2+v5A IDATAj{OY$uMTm%b/%fA <-R`з~k,CP̀Ѯ];#ϡ+TGF.]V t XŒ~F` I^_KuEk@krj7h#++p TfMaim۶5fPI5PvS JoYC5_8+28|qƴϊ [RF AJ6_acr`U/yoKKJs/Dԧ1S(]5KF%f͚VZ1^jqbۘFsb?Fx$X:P*?7(h {#6ָ0ڒeףϔ ;Ix{̩3U#%`.l3#KJN4ؙdoMA)t>K Kd۽ .Sݺ_G4w]`1g y˟msO o9ɋnĀ$vfbk){"le?DM?iw.]jc0p7ڷmI|<{pn ׀8y8ߺOeQ/9)׭7Ivp;qfu.? Ɂ5k( /`Ϟ=O\t1Ϗ{BPn^q(:(&aݰ.1 u{߀:G!~?{4-&lZy @ıj{v{63㫽U`bc G s_7}oh[ݷ l}7&,d/HIpյppK &-냽E=>-k8a2=W{gkccU1LøUarYD ̓[IkЀjSQqxII82\'F@N@jRzs W9ÇW^~;csIpguq{ R,׮[+ل' 7RTH|%>r'6tHNLXxắ1lU">~qչccHIo1.mv5:%G-WpذYG|`gt!0D0;N@xmgtDz!n/>j`cp+X*ظX:&P."yN[0$]h O (8|>e_K.82ݳb8) _/͝8[f (lU!tV<  ͛,/]B11WNÖ%53̡=qx,LNp[螴x`&:l$Œԏ18.mvJKF1z[$'"~x&(7#ËzՔ"^;7_[otMv  GImm΢9O3xF 0Sn DS,l ε~Q 3`!{C֭K\iQ`vvl'N^WN5f%J+Taf>_83m|zo߾?~|)g N0l goH#jvQMLvPٸV}ƠQ?v8!+r4wy獨3Ҙ2)gmmJa-0x80E8xs& FD-5Zy-o¤Ib<'đ6w+x;Dv.Յ ,J '[uxk Tߜ e˖yg\excܜv!thTzG`8L:P`L+e7 s_8Le>eco66}9B2ffu#ickh><:݇s݀*'(zi;1S[4,BsyAtÆ a{u*^ S,pɪ1pv\`ˡnayǽG Jn)KY&.ڶoNB{0IHIâ YO\2aCp`C1Hr^AE OV&oz!\ֲ3F1әRg~K$: tjqG!T|'2N&nO" ÝoȥRэQ/E%=_Fb~`СjѣG;5>u$41\j7*p9XAV&V+> 5@:NZ5B'&4* -˼HJXI,Jcրր@eԀvR$籊4[LpyL(28րրE;hXPCs#GHVk@k@k2k@}8Vm YW1%;AfnOL*&5h ݔ{?DtNL]ⶥ uPf vb@xz"YF]Nejv ),f:pdS,S3%_a "Ez }G٥-G$!Eеm=h(F c2¹IHJ^nqڞN|3?_quHzhuxko*VXGv>߽3(*.-6R缷xwtŃKk_]NZ4\k@NY@s]H\Boj;|]8u8}g{S@iX& oC0l^W>vY2hMUۻ7jمiocմIp(t-6hqQ7EY_}xw4&)DO/Z7&ۨEuN` 3R"BcVAe{Эd Cgcղ ?06ܸQ8p<3GP{ 񫷌1n1ZL+i`R-Zzk܁tNZAр=F2NBoKg^%#sjju'4_aeZfFSqVOODˌnnؔvh<kU9rg;[Խc$Zq[FyL8vw~ |FW.ڕrqo;{|6 '/M{n|qTR\jo(n|`-C?#lza/4% O ׵ϭxַhWxh'3:Zδ6?hNyƨACW4 ZEjjq$//Dn-Xw٩hKp`8YX;df3Ӗ^rAugʥ 'eZ%{2-Ur5hZ- KCɌ3_쾐ػErJ1xkhηS(U^iiOAs rvmܽ]v'Sg`XbA08i ʫn\XkA{ZW ܇0H{aaG`H@+4G+ PfЭ[7제NAڝZVbTZVoY50Kٜ#ajag,pzeØNho\WZ۟E0tAȱQʦdgru$tXy6=zנ IƸȻ iS޾1#-'^1Xef~stC12NO/2220fL6͈3~q-44bZ -);T8292ì>¹l$B(g`X(I*Z|5@NFIp|1!^»#5}Pi:/<HfӻJgf>4[rJViL?C3|Ƴ˧Zy Wڅ E\CP!& UƊ/Lp2qځ?+07 O ݸQТGYYbDQh@ l;t`8YVgyɡ5B'gS@wb%/!`fU3vFYpL/p94٩^_rg^n5Ϊb?2g3Z~ I.>Ue*Lt555p^4@M\g'M'd&w1Lrv\rA6 .P^A `ucZZZf a'~?Oƙ3gx 7r.TۨE tXhuf:()) Agu6 OLZZUHԿk.?~Ool,>u'$&2bg!K6mQژTsB[| J0ǃ^ kTCtd5!x/SO]555D D8*f(:$~߿vy!Al$'iT:'iGr$)CX9_Rj04sQ ٮspi^*Rd4n EJEf:ծFR~up:3I]r_>q5CP?:xQ7]vzSg55P~ 2NԯZ`[`23pʐ;Ν8PJ`_./^pVjeiBs/ J~ZZxπxf΀m83ӛ މC0 hKYu3\m'2|MP̀ZZZ{V=d\/x^\-wilU!t[x.SՊF9*!X f׹J+«03/V׵*6N"ÌS&thTzG`8L:P`L+e7 s_8N*?/Oees' |i h h \Hg'Բ]~9@:3_'NĒ?uX+Lj;pN}p;~Le3 $W!0ʝXQ4 j0[OOIKN v {LCK[ꫯտj{m*w_r–L9xdI,vؼqiev,ஃ`C*/[ v{V]l_HBͼНsZ-Ft3__Pro Yoe>5(?&vR$UB`*޲CJXI,JcƕlJpqWgUQ>.PO|i>>|y X^'0DoD'pJHV7п`wEA#I!;=ZQ)Aش?`?]Fk `S1k3?7 !z:v{`Вy߽3VߧKĮ:ɹ_fTYgԉһ/Sa iOg$SxIl!@Sz$'P6jӇ^p=MHmAO k&߈XfHV<;Hf',dN¸-l9K_ƖC520mDYWQ A @gT>vO3zTW_Gu3p>$Ϯlʦ2\DainSyhc_/^Ore7 ~L~~Sٻ`Nrm(-[\r/V7˗j:$kŃF_Na_"-Z)JʨOdzһy),zr(Kל%YS;2Z0eGλU*1ÎJ?=䄶8s#d_cNGji+9&Ȯ.Mqm3i1(bt4n\W+xnmCbg]4LD oαP#w8IwB/u ΁eԿv@4R︿'n[!/_srE~.X}<ٖhij8~ʲ;v奙_v4ǟ=X']e\L: &fG^yk;͒tC=TwruXORv{)r^5v~맍wzm7[郆~BkDY9C*rPFV,w ?uqxdYrGzwWSsȠү?D8OF5~&GWd}Hwγ'.Ы5ߚ{*!fdɕ2嵒_!ĦB,n,[['κTnGZjH xurE]}6{L9Dz+UWg T??'WN=FgĮ[L .N+oZ$w 8tY3٭^m@[(>yN췮˕sʹ'hgn.s%{g/]"S&.cOwCs}-_ʹygjَ+ik68!^[!Ѧ,9}JOng&ȯ:TMv0;}^G9IͼF=$~tߜ4W+Ym=P_=կlo R)S0Nf?ѩB|GpL駗-yNNf B9o_9g1]E֗p7sK d5cˤQ HEr~3S3O{hd'#0B̶E2D8{Wn'GF CBZ;XyN-p2o-9ln^3OM ̼j}W$ܔ\H ޼Kllŏk3/79bUfɵǏ|鷯 e/Tj>1@/LO>tLuAΝ\*HMIxyUo ^⋟7e#Fn2dBxb.w_KF關}\,ٷy~2"i?9M_딷.WM.oOY9xҭ)\}!C`)qX-`:|V8}~Wүq\FRǷ;ɮLe1Sϗy=p> rc)PSX^ L缞ڢųey=9nxz=3摼)1s 5 K/|.n/ܒ&oK/|Y q+l45"=MQ'ߵ]qUS?5ƟuZjo()%[2kt#ٹ@Ϟ&֫F|0]l3P0JN7eV[Wdcfא{anVKCxU^a6O -/ob Oo}*}t޹Wź5>vxXbA,qt wλ+]Vq TJf(DQCFBC2wׁ!]ɻྗ[@wWpHK&zҪ`@rl}|D2+ -xXN'm⼵%o 5u3p}vV_ct\/qvL7>3332Zȹ鳘9EԆf0;A[:}L)}111)9Y?Ŭ8i6r`BIc j "'8M.^1$f f fMe T:iePWCH۩,cQE#'p|qh(UX'ɣ$[9ì߫!M%&xNr\_cbbb5I(VOwݖC/(*Čn8jTcbb>QDN *wC(gRFPSx333Ж3`/mm8XVsC ]'l9ĢgP9Jñ|^ ||G,f f f`f Mm4n`'mnyѦx혁[G/\XK-hSh$ |2?R]}!e kӦ,111 {nw]*/el]NN|vqOcbb>`5>vxOL!qkY}4cbb>@ Pp9֗JƆr9y}h 5up}vmX~*'}$.ux|RY,fuԆfP;A[:}L)}111)9Y?Ŭ8i6r`BIc j "!6jboP|g[!v!FiA\LE,f f ffT]c$o]X~^7Yb};Aq}юhHSP'ɣZY?u[}>,wCh3,fQDe T}8& KMA)N9En@@@[΀8\bY .v}2f f f[C( z ,b>hUYU?[n-[͛WGؾ}{]vNmֈģ+X=Xi>N<{X}֟Jo.4wS-&or=Ȋ+d͚5GmIvygc=d}N;Mvmd@ re|aCf[ K79ᄾ2n!z|mUXm.kx!N ezK7;b<ڔbf`ӦM2k,Yp|3o~2p@km=Se˖c=&?OdСrgH:L&#M{V~{< s|ҹcUuaFYmydi3sJoW]; -}#N,>g:|VG >]~WҫΟ?Vr- _eH+JES#~}Gj,>%;\qUsvW}mn׊Ix͗|VW(Y0,=i({`lwmg\83Xz?ݻ 6zڊQԶn-[d}\zLrAf1ٽr׎ƦPF"wm߱ -IO!4S(L{D:uHgm`o/Ol8TNwQ>;[6]Ad#~'G}>>W~Gn\t[m'wqHmұ:7CU_ r`ج-;I~Jn rҷomyუ#[<^&N64X̍+shll.}v#񍙝3G<՚ɘG^7>J=hVgW7>(\6LC=ӟ/ƱTz56 1.N΍O볼o }oˈ#]vgիW JM8#/'˘kMNS2/J.Z6rJ-:VRp`ƍ СF: wܹP//_63 ҫ즯kwKrR~웲ߗ ϓ:Ⱥ%+N dQ{NSdHG[dWnSDn(E`3hh]IީH>nk߾ڿ,| -x_ӫR}Eoؘe?2M.?2gם-oQ_g-'ϐ޿4~YdE$'\.SDV;@ GH޻ʥ]v+_gC}g<풲ԆP̝@(<;ir,|V~z45< VEeKqq{X %9yoϐSzHxl=dI؋_wrY͇'fާdnmtY#:C:1Y5ǹyziavZX}(Rj`EΠ#+6BaWn÷u},v5n:.Jֲ~ۭK[@Ig^t>^{)"㟥KCw<(G] 2MvPu/cVlIvV`>:\W+;u\߳ ? r> c CSr [ճR7 !:>urhr7/]:(,(?h~>&f醐jzL^x  h = G?k.!,AZXRυ΃O[gw_7ݰ.W?!}vz'G?_+(eG夡vP;i–dC}GsگGc5a:kn>q}>̍+ :Kx.b)Y;￟ڼMŦ~ȌҢY!2rϯO=], 䐗&П~yIt}fNV]M9x{WɥNsOtWl@Tn\"Ǖ>3hg~ks;Hs_N@:xal.~?? igS~qą򽟾#dg);l( 8ftiic<+E hq-0WJtW~l8 ~W?]Ii-mÆ 'rOOWS]¶gf{^#k76 i\_K*]QDFZ2d_ZK6uЫq C ֯/9v_~KI,*SxwGES$IDAT̙3'[PvX~'iڟ_}>']j;'(i|[W6Fm_LA{4~QVlzA9JV8|7^! >`߾A:6 !}/pICVàٳg9ĢlA7ސZSAΪYiO$I5㚦ηK q TO,xIyvU->^7\+]vK*T|a4 [|R;.-r=Tic^+b>Ī8_<ߑ?cGI闿R*\gu̙3ﶟxInJ53e44>ό*] ll6/~^}ak$U_奩0ځ 8uW1pxȧcc#iCZ>:49V'|2SGqGH_?Z#xgE% 9昦_L+΋歷J=eCd!RH7jX_/oBG_{Q=xP;AKg<2ڤ6G1|D6uHK&zP+QЁ[8un mㆠl ߗ?|ryW?zboʹ99f߾}? #9-y.[>?Zc|^VܥV\/ [rfGr6nVRfJ!:7965MTC >;]J|ڔ⣿fW^m4a|̯N鶚)lmoPg0(`k2">(- |}[[xZDvRuZĹ|׶}i6wm'aNk'm xM7>[U) N< z M7,Fl3 o2Q'ߵKӏx 4B0Ჺ$] m+ּ4mXRZ\mvk~5x񬿥7PZ̍+sюhkpk"+ƱTz56N&H \!,/111m!YX/9UY{ <͠vuS,>bbbZSXBs~?Y=q.)Km ύ&bQhSXbox<۷C񖓧)btl_8Wuέξ x|\ !4#F Vchfp}%~ ѴP5M8>e;o!b;iyps]oc333j2`ܹr&ڴ98tXOv8IR`֦^lk_~>}Q 6(7a~wj5pc<,V  MÕ"333*3t҂;lN!7qFf$ 0O:m+i5|rbz3333bڥ u4HnAG翘lA>ZHO(۪aCFİlhHMz $7܌qU$ v qʗ>Ѭ|[Y)SmnS_Hb87m\ n0ie;;1ˇMAm?uJQ<`39a5̍qv]Is?\k5g=_\;?c 2p`ɢOQZ |Tm:|h!p77 0O'FЂk 1tb(Yol,:\6ZFτsh3Ѻ{gu׽ |购`Vx6F)ys6t4ġQf?}w,ܶ;r Y'N :}C/?P'ncC\7ƾV3?|hz c|_<sĬYWg_/CZtfz8cȠ8$1P6q|BS+sHⴉ1SG1ξaߪ&~04r,蟛t,/ sʙc;khVB <4H^G8p4lp瓨e RBA,,c!ga'8[:qG<806cd1#aLJqHYGC|%xSQƆ14JX 0p.6}\l >%1XHO6~ضY>h PG>C6(ɣDM8e2m6G@>úѸ~3gmr}iH7%heOn,wCD pmP9Yaq,ή6,d4q.ĸ)x6bVbqmĬٌ1'1|e?_Q֛ϡXcXI~Q`9>-'O/gC@LJ(&YqdqTwҬ9Brn!`<ġGܳVOCGXc.7g|'|Nlk}r|`.mNawOgk/lENEt|F৴wЧË/U6n]8|/g3P,G|11Ȁ9æiuYInG?uVBzƆIM|H 5Ř( 7Hz1sB_hQ1A2\/ʼnl-o xG'!jnAv%9V醀"j899N>g\mlĬD f%Vøh1>/?{bbjţVa,ШGuŠ/El4[ꈡSa?^Ɇxs`bxRw'jm,ڌQ)c2 d_.GK|Ż `W0v4{cWiA t!bɅΗC1TwS? ǃN :SvvC@7.[>'F ?l }W 9i.N,gCh (*' c"N% 1,ƾF'Μ>bVھ,V"m,//e{^=G5bVGM6thCR'וÍ}gmh XY+!3_. 1c jc!z9 0s\Ģ&Y, ?bb> ,mCctA¶O[㨻 \4[߈e=67 b+!i,.~C_cg`C~H×֗йӞ?v > } }:F:_Y?1T !)&n'd9by@ȧ.J$|N}c?61ȣD}6ٗr|61i~=֚?ň\H4X\mHcB N+lq m,+˃8p(0,tpyJp %|f`961[n >C><-cҞ+>^<J?ț͓Y0`:yCҶ6ꔘ3Dz~Ai\6<.ĉcu[G`ccŠ!` #ib D(-c?$M@զ񡻍w1.ƅvo΀/7.хvo΀/7.хvkǼ87H6h8Hm+ ~0d)*i[ 4@"X<,m)1&FcnJ?/uΐ 6}VBw96%.uJbYOb|fΪdC`GX(-Ǘ\/lHŬ8h6NH9n<9!iЦ wy) IG2GѦ$/$]mPqGty)Cq]mJBѦ wy) IG2GѦ$/$]mPqGty)Cq]mJ(A'pC'ϧG7,N>a,ڌN-Km>ڜ ll u `3Ww6疵ǀK#mĂccecmάIrf:1Y`@>8?S_jCT0 #>$hfN a#OHYF3vh|r]ywm!];G6y!];G6y!];G6y!];G6y!];G6y!];G6y!];G6y!];\o?9Xoy@Yꮏ6$ni1˱6tkkynw9}c! l~Ogum|2gVڜY=/=yCravAFP<˱~o1-Çجo<0.6%Bd8t؟s%9.Ĺ>ӶϟB^[y`Ѧϧ##ׇs1k[Cs,j~=]S{VR6^$Qfmhn%-ƻ46C}Oky\ 5}:1!a\K>ڮJWZ]J'-fuL61Ť:M>q6>탶w8>#ߕ>sh>|W>̍0]07w8>#ߕ>sh>|W>̍06tbx awyN<-|ܐ] C6%p<ZB/>1XS {ԹWK QӁ8mW)c1k9?O^$9 >B:Iq Xh#/i›Y- 1>?<OˋOܼ)32 ጣ B8(C8ȳ|֦Ni*vtXE||MnhSĭtukxCGsY4(?, !q>ⴭFemi[żOI{XYaͮ,E6xvVg̀À^Ob!77ʇrb<3QZrB=>c|~IrFbFO'FӶlLnps1k[][:6gYt4Oixz3+aR+=kϦxwllvK[ݵEs9YO;"W(˱-7ۉXp&7e@@@ 6xqEliŧJq\)]wȏ2f fV\ٮck8! xVÇks.b82f f fZi]̵9'wPp]TV򡲯PqK"K|rd}byI͔W,ٗP|G>_ZsK%!p0_/|1>X~Hc}1}licfz_916i}Q|>X~x(>#i or4}T+g3332P`W܋œZ+;)BL8vO$ږF1INs>4خ?-ߟf4M?2e PGq J t9qp˙{wGЖDD#f f fhioi|EKiE5ΩƠ!?4C8!t|"33ж2Ъ |J]m@@@@@@@@@@@@@@@@@@@@@@kޔfwIENDB`testng-6.9.12/testng-1.0.dtd.html0000755000175000017500000000035012732165123015662 0ustar eugeneeugene . testng-6.9.12/travis.sh0000755000175000017500000000273612732165123014300 0ustar eugeneeugene#!/bin/bash set -e if [ $1 == "sonarqube" ] ; then if [ "${TRAVIS_JDK_VERSION}" == "oraclejdk8" ] ; then if [ -n "${TRAVIS_PULL_REQUEST}" -a "${TRAVIS_PULL_REQUEST}" != "false" ] ; then if [ -n "${SONAR_GITHUB_OAUTH}" ] ; then ./gradlew sonarqube \ -Dsonar.github.pullRequest=$TRAVIS_PULL_REQUEST \ -Dsonar.github.oauth=$SONAR_GITHUB_OAUTH \ -Dsonar.analysis.mode=issues \ --stacktrace --info else echo "Sonar analyse skipped: No GitHub token available" fi else if [ "${TRAVIS_BRANCH}" == "master" ] ; then if [ -n "${SONAR_TOKEN}" ] ; then ./gradlew sonarqube -Dsonar.login=${SONAR_TOKEN} --stacktrace --info else echo "Sonar analyse skipped: No Sonarqube token available" fi else echo "Sonar analyse skipped: Only on the master branch" fi fi else echo "Sonar analyse skipped: Only on Oracle JDK8" fi else if [ $1 == "deploy" ] ; then if [ "${TRAVIS_JDK_VERSION}" == "oraclejdk7" ] ; then if [ "${TRAVIS_PULL_REQUEST}" == "false" ] ; then if [ "${TRAVIS_BRANCH}" == "master" ] ; then ./gradlew uploadArchives --stacktrace --info else echo "Deploy skipped: Only the master branch" fi else echo "Deploy skipped: Not on pull request" fi else echo "Deploy skipped: Only on Oracle JDK7" fi else echo "Skipped: $1 is not a valid param" fi fi testng-6.9.12/gradle/0000755000175000017500000000000012732165123013657 5ustar eugeneeugenetestng-6.9.12/gradle/buildWithTravis.sh0000644000175000017500000000002112732165123017330 0ustar eugeneeugene../gradlew check testng-6.9.12/gradle/uploadSnapshot.sh0000755000175000017500000000034412732165123017223 0ustar eugeneeugene#!/bin/sh echo "TRAVIS_HDK_HOME" $TRAVIS_JDK_HOME if [ $TRAVIS_JDK_HOME == 'oraclejdk7' ] then echo "Uploading snapshot" ./gradlew uploadArchives else echo "Current JDK is ${TRAVIS_JDK_HOME}, not uploading snapshot" fi testng-6.9.12/gradle/publishing-maven.gradle0000644000175000017500000000526012732165123020312 0ustar eugeneeugene// // Publish to Maven Central // apply plugin: 'maven-publish' apply plugin: 'maven' apply plugin: 'io.codearte.nexus-staging' nexusStaging { packageGroup project.group username System.getenv('SONATYPE_USER') password System.getenv('SONATYPE_PASSWORD') } javadoc { failOnError false } signing { required { gradle.taskGraph.hasTask("uploadArchives") } sign configurations.archives } publishing { publications { mavenCustom(MavenPublication) { from components.java artifact sourcesJar groupId project.group artifactId project.name version project.version } } } // ./gradlew uploadArchives (upload snapshot to Maven Central's snapshot repo) uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2") { authentication(userName: System.getenv('SONATYPE_USER'), password: System.getenv('SONATYPE_PASSWORD')) } snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots") { authentication(userName: System.getenv('SONATYPE_USER'), password: System.getenv('SONATYPE_PASSWORD')) } pom { version = project.version artifactId = project.name groupId = project.group project { name project.name description 'Testing framework for Java' url 'http://github.com/cbeust/testng' scm { connection 'scm:git:https://github.com/cbeust/testng.git' developerConnection 'scm:git:git@github.com:cbeust/testng.git' url 'https://github.com/cbeust/testng.git' } licenses { license { name 'Apache Version 2.0, January 2004' distribution 'repo' } } developers { developer { id = 'cbeust' name = 'Cedric Beust' email = 'cedric@beust.com' } } } } } } } uploadArchives.doLast { if (! version.contains("SNAPSHOT")) { println("Now go to https://oss.sonatype.org/index.html#stagingRepositories to close" + " and publish the distribution") } } testng-6.9.12/gradle/publishing.gradle0000644000175000017500000000261212732165123017204 0ustar eugeneeugeneimport java.text.SimpleDateFormat apply plugin: 'signing' Date buildTimeAndDate = new Date() ext { buildTime = new SimpleDateFormat('yyyy-MM-dd').format(buildTimeAndDate) buildDate = new SimpleDateFormat('HH:mm:ss.SSSZ').format(buildTimeAndDate) } jar { manifest { attributes( 'Built-By': System.properties['user.name'], 'Created-By': System.properties['java.version'] + " (" + System.properties['java.vendor'] + " " + System.getProperty("java.vm.version") + ")", 'Build-Date': project.buildTime, 'Build-Time': project.buildDate, 'Specification-Title': project.name, 'Specification-Version': project.version, ) } } javadoc { failOnError false } task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from 'build/docs/javadoc' } task sourcesJar(type: Jar) { from sourceSets.main.allSource classifier = 'sources' } artifacts { archives jar archives javadocJar archives sourcesJar } buildscript { repositories { jcenter() } dependencies { //Check for the latest version here: http://plugins.gradle.org/plugin/com.jfrog.artifactory classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.0.3" } } apply from: 'gradle/publishing-maven.gradle' apply from: 'gradle/publishing-jcenter.gradle' testng-6.9.12/gradle/wrapper/0000755000175000017500000000000012735760204015343 5ustar eugeneeugenetestng-6.9.12/gradle/wrapper/gradle-wrapper.properties0000644000175000017500000000035012732165123022367 0ustar eugeneeugene#Wed Jun 08 23:12:45 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip testng-6.9.12/gradle/publishing-jcenter.gradle0000644000175000017500000000347012732165123020637 0ustar eugeneeugene// // Artifactory // ./gradlew artifactoryPublish (upload snapshot to jfrog) // ./gradlew bintrayUpload (upload release to JCenter) // Properties properties = new Properties() try { properties.load(project.rootProject.file('local.properties').newDataInputStream()) } catch (FileNotFoundException ignore) {} bintray { user = properties.getProperty("bintray.user") key = properties.getProperty("bintray.apikey") publications = ['mavenCustom'] // Without this, javadocs don't get uploaded configurations = ['archives'] pkg { repo = 'maven' name = project.name desc = 'Testing framework for Java' licenses = ['Apache-2.0'] labels = ['testng'] version { name = project.version //Bintray logical version name gpg { // Without this, .asc files don't get generated sign = true } } } } artifactory { def a_user = hasProperty('artifactory_user') ? artifactory_user : System.getenv('artifactory_user') def a_password = hasProperty('artifactory_password') ? artifactory_password : System.getenv('artifactory_password') def a_contextUrl = hasProperty('artifactory_contextUrl') ? artifactory_password : System.getenv('artifactory_contextUrl') contextUrl = "${a_contextUrl}" //The base Artifactory URL if not overridden by the publisher/resolver publish { repository { repoKey = 'oss-snapshot-local' username = a_user password = a_password maven = true } defaults { publications('mavenCustom') } } resolve { repository { repoKey = 'libs-snapshot' username = a_user password = a_password maven = true } } } testng-6.9.12/gradlew0000755000175000017500000001173012732165123013776 0ustar eugeneeugene#!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # For Cygwin, ensure paths are in UNIX format before anything is touched. if $cygwin ; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` fi # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >&- APP_HOME="`pwd -P`" cd "$SAVED" >&- CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" testng-6.9.12/kobaltw0000755000175000017500000000012112732165123014004 0ustar eugeneeugene#!/usr/bin/env bash java -jar $(dirname $0)/kobalt/wrapper/kobalt-wrapper.jar $* testng-6.9.12/NOTES0000644000175000017500000000423312732165123013236 0ustar eugeneeugene===== Maven ===== If you ran the full dist build, it should have generated a file on your hard drive called "testng-5.12-bundle.jar". Testing: -> Update 5.12 in bundle-pom.xml to the correct version mvn install:install-file -DpomFile=bundle-pom.xml -Dfile=testng-5.12.1.jar cd /tmp svn co http://svn.apache.org/repos/asf/maven/surefire/trunk/surefire-integration-tests/src/test/resources/testng-simple/ cd testng-simple -> Update in pom.xml to the correct version -> Remove in pom.xml if it's still there mvn -DtestNgVersion=5.12.1 -Dsurefire.version=2.5 clean test -> Send bundle to Brett Porter ======= Eclipse ======= I ended up doing the launch configuration, and just for information, here are the parameters: Run Configuration / Eclipse application. Check "Run an application" in "Program to run", and select org.eclipse.equinox.p2.metadata.generator.EclipseGenerator The program arguments are (replace the update site directory appropriately): Linux: -os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator -updateSite /usr/local/cbeust/java/testng-eclipse-update-site -site file:/usr/local/cbeust/java/testng-eclipse-update-site/site.xml -metadataRepository file:/usr/local/cbeust/java/testng-eclipse-update-site/ -artifactRepository file:/usr/local/cbeust/java/testng-eclipse-update-site -artifactRepositoryName "Ganymede Artifacts" -compress -append -reusePack200Files -noDefaultIUs -vmargs -Xmx256m Mac -os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -application org.eclipse.equinox.p2.metadata.generator.EclipseGenerator -updateSite /Users/cbeust/java/testng-eclipse-update-site -site file:/Users/cbeust/java/testng-eclipse-update-site/site.xml -metadataRepository file:/Users/cbeust/java/testng-eclipse-update-site/ -artifactRepository file:/Users/cbeust/java/testng-eclipse-update-site -artifactRepositoryName "Ganymede Artifacts" -compress -append -reusePack200Files -noDefaultIUs -vmargs -Xmx256m This will generate the site in ~/java/testng-eclipse-update-site testng-6.9.12/.project0000644000175000017500000000110712732165123014067 0ustar eugeneeugene testng org.eclipse.jdt.core.javabuilder org.eclipse.m2e.core.maven2Builder org.eclipse.pde.PluginNature org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature testng-6.9.12/.classpath-linux0000644000175000017500000000110612732165123015537 0ustar eugeneeugene testng-6.9.12/ant/0000755000175000017500000000000012735760204013207 5ustar eugeneeugenetestng-6.9.12/ant/ivy.xml0000644000175000017500000000101112732165123014525 0ustar eugeneeugene testng-6.9.12/ant/build-ant.xml0000644000175000017500000000546312732165123015614 0ustar eugeneeugene This dir: ${this.directory} testng-6.9.12/ant/old/0000755000175000017500000000000012732165123013761 5ustar eugeneeugenetestng-6.9.12/ant/old/build-sample.xml0000644000175000017500000000161112732165123017060 0ustar eugeneeugene Defining task from ${testng.jar} testng-6.9.12/ant/old/build-dogfood.xml0000644000175000017500000000173312732165123017225 0ustar eugeneeugene Defining task from ${basedir}/../${jdk15.testng.jar} testng-6.9.12/ant/build.xml0000644000175000017500000004121512732165123015027 0ustar eugeneeugene Src:${src.dir} Adding ${testng.fullname} Sources: ${sources} testng-6.9.12/ant/build-tests.xml0000644000175000017500000001453112732165123016170 0ustar eugeneeugene BASEDIR =${basedir} TEST.DIR =${test.dir} TEST.BUILD.DIR =${test.build.dir} REPORT.DIR =${report.dir} JUNIT.REPORT.DIR =${junit.report.dir} TESTNG.REPORT.DIR=${testng.report.dir} Report created in open ${testng.report.dir}/index.html Reports can be found in: open ${testng.report.dir}/index.html testng-6.9.12/ant/build.properties0000644000175000017500000000366612732165123016433 0ustar eugeneeugene# # TestNG distribution # testng.basename=testng testng.version=6.8.14-SNAPSHOT testng.fullname=${testng.basename}-${testng.version} # # Global directories # root.dir=${basedir} build.3rdparty.dir=${root.dir}/build3rdparty build.maven-bundle.dir=${build.dir}/maven-bundle target=${root.dir}/target lib.dir=${basedir}/lib lib-supplied.dir=${basedir}/lib-supplied src.dir=${basedir}/src/main/java src.resources.dir=${basedir}/src/main/resources build.dir=${target}/classes test.dir=${basedir}/src/test/java test.build.dir=${target}/test-classes test.output.dir=${target}/test-output test.resources.dir=${basedir}/src/test/resources example.dir=${basedir}/examples # # Jar files # beanshell.jar=bsh-2.0b4.jar guice2.jar=guice-2.0.jar junit.jar=junit-4.10.jar ant.jar=ant-1.7.0.jar jcommander.jar=jcommander-1.27.jar yaml.jar=snakeyaml-1.12.jar all.jar.files=${beanshell.jar},${junit.jar},${ant.jar},${jcommander.jar},${yaml.jar},${guice2.jar} # # Names of distributions # testng.jar=${target}/${testng.fullname}.jar testng.dist.jar=${testng.fullname}-dist.jar sources.testng.jar=${testng.fullname}-sources.jar testng.junit.jar=${testng.fullname}-junit.jar testng.nobsh.noguice.jar=${testng.fullname}-nobsh-noguice.jar testng.bsh.noguice.jar=${testng.fullname}-bsh-noguice.jar testng.nobsh.guice.jar=${testng.fullname}-nobsh-guice.jar testng.ibiblio.jar=${testng.fullname}-bundle.jar testng.zip=${target}/${testng.fullname}.zip testng.maven-bundle=${target}/${testng.fullname}-bundle.jar testng.javadoc.zip=${testng.fullname}-javadoc.zip other.jars.dir=${target}/other-jars # # Test locations # test.location.msg=Test results can be found in\n\ test/test-output/index.html # # Eclipse plug-in # testng-eclipse.dir=../testng-eclipse # # Maven plug-in version # Note, this version number is appended to the resulting plug-in jar # testng-maven.version=1.2 # # JDK 1.4 for sanity checking before a distribution # java14.home=jdk-1.5.0_04 #java14.home=c:/java/jdk-1.4.2_08 testng-6.9.12/ant/README.template0000644000175000017500000000073112732165123015676 0ustar eugeneeugene[![Build Status](https://travis-ci.org/cbeust/testng.svg)](https://travis-ci.org/cbeust/testng) Welcome to TestNG ${version} Please note that even though the .zip distribution contains the TestNG sources, you will not be able to build the software with them because we decided not to include the external jar files in order to keep the size down. If you want to build TestNG, please sync to the GitHub repository at https://github.com/cbeust/testng. -- The TestNG team testng-6.9.12/CHECKLIST0000644000175000017500000000021012732165123013646 0ustar eugeneeugeneCheck list for releases: pom.xml pom-test.xml Version.java build.properties doc/index.html doc/documentation-main.html doc/maven.html testng-6.9.12/bundle-pom.xml0000644000175000017500000000412712732165123015211 0ustar eugeneeugene 4.0.0 org.testng testng TestNG 5.12.1 TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use. http://testng.org Apache License, Version 2.0 http://apache.org/licenses/LICENSE-2.0 scm:svn:http://testng.googlecode.com/svn/trunk/ scm:svn:http://testng.googlecode.com/svn/trunk/ http://testng.googlecode.com/svn/trunk org.apache.ant ant 1.7.0 true junit junit 4.10 org.beanshell bsh 2.0b4 provided com.google.inject guice 2.0 provided testng-6.9.12/build-with-gradle0000755000175000017500000000006112732165123015650 0ustar eugeneeugene./gradlew --daemon --stacktrace clean build test testng-6.9.12/maven/0000755000175000017500000000000012732165123013527 5ustar eugeneeugenetestng-6.9.12/maven/bundle-pom.xml0000644000175000017500000000412712732165123016317 0ustar eugeneeugene 4.0.0 org.testng testng TestNG 5.12.1 TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use. http://testng.org Apache License, Version 2.0 http://apache.org/licenses/LICENSE-2.0 scm:svn:http://testng.googlecode.com/svn/trunk/ scm:svn:http://testng.googlecode.com/svn/trunk/ http://testng.googlecode.com/svn/trunk org.apache.ant ant 1.7.0 true junit junit 4.10 org.beanshell bsh 2.0b4 provided com.google.inject guice 2.0 provided testng-6.9.12/maven/build-with-maven0000644000175000017500000000072412732165123016631 0ustar eugeneeugenemvn clean install -Dgpg.skip=true #or if you want to sign the jar, uncomment this: #mvn clean install echo echo "To deploy to the snapshot repository: mvn deploy" echo "To deploy to the release directory: mvn release:clean release:prepare release:perform" echo "Nexus UI: https://oss.sonatype.org/index.html" echo "Wiki: https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide" # deploy without tagging: mvn deploy -DperformRelease testng-6.9.12/bin/0000755000175000017500000000000012732165123013171 5ustar eugeneeugenetestng-6.9.12/bin/master.bat0000644000175000017500000000013112732165123015147 0ustar eugeneeugenetestng -hostfile test\hosts.properties -d test\test-output %1 %2 %3 %4 %5 test\testng.xmltestng-6.9.12/bin/junitconverter.bat0000644000175000017500000000046412732165123016746 0ustar eugeneeugeneset ROOT=c:\java\TestNG set JAR=%ROOT%\testng-4.5-jdk15.jar;%ROOT%\test\build rem set JAR=%ROOT%\testng-4.5-jdk14.jar;%ROOT%\test-14\build java -ea -classpath %ROOT%\3rdparty\junit.jar;%JAVA_HOME%\lib\tools.jar;%JAR%;%CLASSPATH% org.testng.JUnitConverter -restore -overwrite -annotation -srcdir src testng-6.9.12/bin/run-tests.sh0000755000175000017500000000131612732165123015475 0ustar eugeneeugeneROOT=~/java/testng VERSION=5.0 JAR14=$ROOT/testng-$VERSION-jdk14.jar JAR15=$ROOT/testng-$VERSION-jdk15.jar java -ea -classpath test/build:$ROOT/3rdparty/junit.jar:$JAVA_HOME/lib/tools.jar:$JAR15:$CLASSPATH org.testng.TestNG test/testng.xml java -ea -classpath test/v4/build:$ROOT/3rdparty/junit.jar:$JAVA_HOME/lib/tools.jar:$JAR15:$CLASSPATH org.testng.TestNG test/v4/testng.xml java -ea -classpath test-14/build:$ROOT/3rdparty/junit.jar:$JAVA_HOME/lib/tools.jar:$JAR14:$CLASSPATH org.testng.TestNG -sourcedir test-14/src test-14/testng.xml java -ea -classpath test-14/v4/build:$ROOT/3rdparty/junit.jar:$JAVA_HOME/lib/tools.jar:$JAR14:$CLASSPATH org.testng.TestNG -sourcedir test-14/v4/src test-14/v4/testng.xml testng-6.9.12/bin/testng.bat0000644000175000017500000000043512732165123015167 0ustar eugeneeugeneset ROOT=c:\java\TestNG set JAR=%ROOT%\testng-5.2beta-jdk15.jar;%ROOT%\test\build rem set JAR=%ROOT%\testng-4.5-jdk14.jar;%ROOT%\test-14\build java -ea -classpath %ROOT%\3rdparty\junit.jar;%JAVA_HOME%\lib\tools.jar;%JAR%;%CLASSPATH% org.testng.TestNG %1 %2 %3 %4 %5 %6 %7 %8 %9 testng-6.9.12/bin/testng.sh0000755000175000017500000000035212732165123015034 0ustar eugeneeugeneROOT=~/java/testng VERSION=5.0 JAR14=$ROOT/testng-$VERSION-jdk14.jar JAR15=$ROOT/testng-$VERSION-jdk15.jar java -ea -classpath $ROOT/test/build:$ROOT/3rdparty/junit.jar:$JAVA_HOME/lib/tools.jar:$JAR15:$CLASSPATH org.testng.TestNG $* testng-6.9.12/bin/slave.bat0000644000175000017500000000005112732165123014767 0ustar eugeneeugenetestng -d client-output -slave %1 %2 %3 testng-6.9.12/www/0000755000175000017500000000000012732165123013245 5ustar eugeneeugenetestng-6.9.12/www/index.html0000644000175000017500000000021112732165123015234 0ustar eugeneeugene Default Project Content This is the default project content. testng-6.9.12/verify-release0000755000175000017500000000212412732165123015270 0ustar eugeneeugeneif [ $# -eq 0 ] then echo "Specify the release number (e.g. 5.14.2)" exit -1 fi rel=testng-$1 # # Make sure that pom.xml and pom-test.xml test the same and latest version # v1=`perl -ne 'BEGIN{undef $/}; print "$1" if m/(TestNG.*\n.*version)/mg' pom.xml | awk -F ">" '{ print $2 }' | awk -F "<" '{ print $1 }'` v2=`perl -ne 'BEGIN{undef $/}; print "$1" if m/(artifactId.testng.*\n.*version)/mg' pom-test.xml | grep version | awk -F ">" '{print $2}' | awk -F "<" '{print $1}'` if [ $v1 != $v2 ] then echo "Versions of pom.xml and pom-test.xml do not match: $v1 $v2" # exit -1 fi # # Maven # ./build-with-maven #cd $HOME/t #rm -rf surefire #svn co http://svn.apache.org/repos/asf/maven/surefire/trunk surefire #cd surefire #mvn clean install -Dtestng.version=$1 # # Distribution # cd $HOME/t rm -f *zip rm -rf $rel curl http://testng.org/$rel.zip >$rel.zip unzip $rel.zip cd $HOME/java/testng java -Dtest.resources.dir=$HOME/java/testng/src/test/resources -classpath $HOME/t/$rel/$rel.jar:target/test-classes:lib/guice-2.0.jar org.testng.TestNG $HOME/java/testng/src/test/resources/testng.xml testng-6.9.12/gradlew.bat0000644000175000017500000000441212732165123014537 0ustar eugeneeugene@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega testng-6.9.12/upload-beta0000755000175000017500000000024412732165123014544 0ustar eugeneeugene#scp `ls -tr *beta.zip|tail -1` cedric@beust.com:w/testng scp `ls -tr target/*beta.zip|tail -1` beust:domains/testng.org/html ssh beust cat testng/beta/index.html testng-6.9.12/.classpath0000644000175000017500000000220012732165123014376 0ustar eugeneeugene testng-6.9.12/sitemap.xml0000644000175000017500000000221712732165123014607 0ustar eugeneeugene http://testng.org/doc/index.html daily 1.0 http://testng.org/doc/download.html daily http://testng.org/doc/migrating.html daily http://testng.org/javadocs/index.html daily http://testng.org/doc/book.html daily http://testng.org/doc/eclipse.html daily http://testng.org/doc/idea.html daily http://testng.org/doc/maven.html daily http://testng.org/doc/ant.html daily http://testng.org/doc/misc.html daily testng-6.9.12/ANNOUNCEMENT.txt0000644000175000017500000001054612732165123015062 0ustar eugeneeugenejavalobby.org testdriven.com opensourcetesting.org http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=forum&f=68 java.net comp.lang.java.programmer ========== The TestNG team is happy to announce the immediate availability of TestNG 4.5. This release contains a lot of bug fixes and a few new features. It also includes the first phase of Distributed TestNG, a work in progress designed to transparently distribute tests on many machines and collect their results. Announcement: http://beust.com/weblog/archives/000361.html Details on Distributed TestNG: http://beust.com/weblog/archives/000362.html ========== The TestNG team is happy to announce the immediate availability of TestNG 4.0, with a lot of improvements and new features. The announcement, along with a few examples and summary of the new features, can be found here: http://tinyurl.com/dxlbh -- Cdric http://testng.org ================ Announcing TestNG 2.3 The TestNG team is happy to announce the availability of TestNG 2.3. The version is available at http://beust.com/testng as well as the new documentation, which has been considerably improved (highlighted code snippets, detailed DTD, ant task and description of all the new features). What's new: * beforeSuite, afterSuite, beforeTest, afterTest * Revamped ant task with haltonfailure and other helpful flags * Better stack traces and improved level control for verbosity * Better syntax for including and excluding methods in testng.xml * Test classes can be invoked on the command line * ... and many bug fixes. For Eclipse users, a new version (1.1.1) of the Eclipse plug-in that includes this new TestNG version is available on the remote update site or for direct download. Also, TestNG has joined OpenSymphony (big thanks to Patrick and Hani for setting this up). As a consequence of this move, there is now a TestNG users forum as well as a Wiki and JIRA for issue tracking. The users mailing-list has been moved to Google Groups and is connected to the forum, so you only need to subscribe to one. Try it and let us know what you think! === I am happy to announce the availability of TestNG 2.1 (http://beust.com/testng). TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use, such as: * JSR 175 Annotations (JDK 1.4 is also supported with JavaDoc annotations). * Flexible test configuration. * Default JDK functions for runtime and logging (no dependencies). * Powerful execution model (no more TestSuite). * Supports dependent methods. Some of the new features in this version include: * invocationCount and successPercentage, which I described in a previous entry (http://beust.com/weblog/archives/000236.html), and which allow you to invoke a test method a certain number of times while allowing some of these invocations to fail. If the number of failures is under a certain threshold, the test is still considered a success. * timeOut is now applicable to all test methods. Whether you are running your tests in parallel or not, you can specify a time-out for your test method and if it fails to complete within the given amount of time, TestNG will mark it as a failure. * dependsOnMethods was the most requested feature. You can now specify dependencies on a method-based basis (no need to specify a group if your dependency graph is simple). You can even mix dependsOnMethods and dependsOnGroups. * ... and of course, numerous bug fixes and other additions. A special thanks to Alexandru Popescu who has pulled all-nighters to make this release happen! We have an exciting list of new features lined up for our next version, among which a plug-in API, but in the meantime, enjoy TestNG 2.1. ====== Announcing TestNG for Eclipse The TestNG team is happy to announce the first release of the TestNG plug-in for Eclipse. http://beust.com/testng This first release covers the basic functionalities of TestNG, among which: * Multiple ways to launch tests (from a method, from a class, groups or an entire suite). * Convenient report view that lets you directly jump to failed tests. A more detailed overview can be found here: http://beust.com/weblog/archives/000261.html and the documentation and snapshots here: http://beust.com/testng/main.html#eclipse -- Cedric testng-6.9.12/.mailmap0000644000175000017500000000127312732165123014045 0ustar eugeneeugeneAbraham Lin Cédric Beust Cédric Beust Cédric Beust Cédric Beust Cédric Beust Cédric Beust Cédric Beust Jose Dillet Julien Herr Konstantin Savin Tim wu Tomás Pollak testng-6.9.12/build-with-maven0000755000175000017500000000164712732165123015533 0ustar eugeneeugene# Two different POMs are needed to build TestNG with Maven because it's not # allowed to have circular dependencies. # - pom.xml defines the project version "n-SNAPSHOT", builds, jars and deploys (but doesn't # run the tests). # - pom-test.xml declares a test dependency on "n-SNAPSHOT", which it will find # in the local repository (~/.m2/repository). All it does then is run the tests. mvn clean install -Dgpg.skip=true #or if you want to sign the jar, uncomment this: #mvn clean install mvn -f pom-test.xml test echo echo "To run the tests: mvn -f pom-test.xml test" echo "To deploy to the snapshot repository: mvn deploy" echo "To deploy to the release directory: mvn release:clean release:prepare release:perform" echo "Nexus UI: https://oss.sonatype.org/index.html" echo "Wiki: https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide" # deploy without tagging: mvn deploy -DperformRelease testng-6.9.12/testng-1.0.dtd.php0000644000175000017500000000306712732165123015512 0ustar eugeneeugeneTestNG DTD

DTD for TestNG

'
;

print(htmlentities(file_get_contents("testng-1.0.dtd")));

print "
"; ?> testng-6.9.12/deploy-to-maven0000755000175000017500000000035512732165123015372 0ustar eugeneeugeneif [ -z "$SONATYPE_USER" ] then echo "Please define SONATYPE_USER" exit 1 fi if [ -z "$SONATYPE_PASSWORD" ] then echo "Please define SONATYPE_PASSWORD" exit 1 fi ./gradlew uploadArchives && ./gradlew closeAndPromoteRepository testng-6.9.12/eclipse-projects/0000755000175000017500000000000012732165123015674 5ustar eugeneeugenetestng-6.9.12/eclipse-projects/org.testng.eclipse/0000755000175000017500000000000012732165123021411 5ustar eugeneeugenetestng-6.9.12/eclipse-projects/org.testng.eclipse/.project0000644000175000017500000000056512732165123023066 0ustar eugeneeugene org.testng.feature org.eclipse.pde.FeatureBuilder org.eclipse.pde.FeatureNature testng-6.9.12/eclipse-projects/org.testng.eclipse/feature.xml0000644000175000017500000002760412732165123023577 0ustar eugeneeugene This is the Eclise plug-in for TestNG (http://testng.org). [Enter Copyright Description here.] Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. testng-6.9.12/eclipse-projects/org.testng.eclipse/build.properties0000644000175000017500000000003312732165123024622 0ustar eugeneeugenebin.includes = feature.xml testng-6.9.12/eclipse-projects/beust.com/0000755000175000017500000000000012732165123017573 5ustar eugeneeugenetestng-6.9.12/eclipse-projects/beust.com/site.xml0000644000175000017500000000037112732165123021262 0ustar eugeneeugene testng-6.9.12/eclipse-projects/beust.com/index.html0000644000175000017500000000372112732165123021573 0ustar eugeneeugene beust.com
testng-6.9.12/eclipse-projects/beust.com/.project0000644000175000017500000000056212732165123021245 0ustar eugeneeugene beust.com org.eclipse.pde.UpdateSiteBuilder org.eclipse.pde.UpdateSiteNature testng-6.9.12/eclipse-projects/beust.com/web/0000755000175000017500000000000012732165123020350 5ustar eugeneeugenetestng-6.9.12/eclipse-projects/beust.com/web/site.css0000644000175000017500000000131712732165123022030 0ustar eugeneeugene testng-6.9.12/eclipse-projects/beust.com/web/site.xsl0000644000175000017500000001571512732165123022055 0ustar eugeneeugene beust.com

beust.com

dark-row light-row dark-row light-row dark-row light-row

( - )
-

Operating Systems:
Windows Systems:
Languages:
Architecture:


Uncategorized

( - )
-


Operating Systems:
Windows Systems:
Languages:
Architecture:

( - )
-


Operating Systems:
Windows Systems:
Languages:
Architecture:
testng-6.9.12/FILES0000644000175000017500000000030012732165123013177 0ustar eugeneeugenebuild.properties build.xml lib/DTDDoc.jar examples/build.xml examples/testng.properties examples/testng.xml examples/src/ maven-testng-plugin-1.1.jar CHANGES.txt LICENSE.txt README testng-6.9.12/LICENSE.txt0000644000175000017500000002613512732165123014253 0ustar eugeneeugene Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. testng-6.9.12/appveyor.yml0000644000175000017500000000075112732165123015014 0ustar eugeneeugeneversion: "{branch} {build}" skip_tags: true clone_depth: 10 build: verbosity: detailed build_script: - gradlew.bat assemble --info --no-daemon test_script: - gradlew.bat test --info --no-daemon environment: matrix: - JAVA_HOME: C:\Program Files\Java\jdk1.7.0 - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 - JAVA_HOME: C:\Program Files (x86)\Java\jdk1.7.0 - JAVA_HOME: C:\Program Files (x86)\Java\jdk1.8.0 matrix: fast_finish: true cache: - C:\Users\appveyor\.gradletestng-6.9.12/README.dev0000644000175000017500000000166212732165123014063 0ustar eugeneeugeneNew installation: Install GPG at http://www.gpgtools.org/gpgmail/index.html Generate new key with gpg --gen-key build-with-maven gpg --list-keys Send the public key: gpg --keyserver hkp://pool.sks-keyservers.net --send-keys or wwwkeys.at.pgp.net instructions at https://docs.sonatype.org/display/Repository/How+To+Generate+PGP+Signatures+With+Maven Configure ~/.m2/settings.xml with Nexus user/password: sonatype-nexus-snapshots *** *** sonatype-nexus-staging *** *** Snaphot deploy: mvn -Dgpg.passphrase= -Dgpg.keyname= deploy Staging deploy: mvn -Dgpg.passphrase= -Dgpg.keyname= release:clean release:prepare release:perform testng-6.9.12/settings.gradle0000644000175000017500000000003412732165123015436 0ustar eugeneeugenerootProject.name = 'testng' testng-6.9.12/README0000644000175000017500000000072612732165123013306 0ustar eugeneeugene[![Build Status](https://travis-ci.org/cbeust/testng.svg)](https://travis-ci.org/cbeust/testng) Welcome to TestNG 6.8beta Please note that even though the .zip distribution contains the TestNG sources, you will not be able to build the software with them because we decided not to include the external jar files in order to keep the size down. If you want to build TestNG, please sync to the GitHub repository at https://github.com/cbeust/testng. -- The TestNG team testng-6.9.12/README.build0000644000175000017500000000035512732165123014402 0ustar eugeneeugeneYou need to install ivy in order to build. You can either download it from the ivy site or more simply, copy ivy-2.1.0.jar included in the root directory to ~/.ant/lib. After this, "ant" will build the distribution and run the tests. testng-6.9.12/src/0000755000175000017500000000000012732165123013210 5ustar eugeneeugenetestng-6.9.12/src/generated/0000755000175000017500000000000012732165123015146 5ustar eugeneeugenetestng-6.9.12/src/generated/java/0000755000175000017500000000000012732165123016067 5ustar eugeneeugenetestng-6.9.12/src/generated/java/org/0000755000175000017500000000000012732165123016656 5ustar eugeneeugenetestng-6.9.12/src/generated/java/org/testng/0000755000175000017500000000000012732165123020162 5ustar eugeneeugenetestng-6.9.12/src/generated/java/org/testng/internal/0000755000175000017500000000000012732165123021776 5ustar eugeneeugenetestng-6.9.12/src/generated/java/org/testng/internal/VersionTemplateJava0000644000175000017500000000040312732165123025641 0ustar eugeneeugenepackage org.testng.internal; public class Version { public static final String VERSION = "6.9.47-SNAPSHOT"; public static void displayBanner() { System.out.println("...\n... TestNG " + VERSION + " by Cédric Beust (cedric@beust.com)\n...\n"); } } testng-6.9.12/src/test/0000755000175000017500000000000012732165123014167 5ustar eugeneeugenetestng-6.9.12/src/test/java/0000755000175000017500000000000012732165123015110 5ustar eugeneeugenetestng-6.9.12/src/test/java/ConverterSample2.java0000644000175000017500000000126412732165123021151 0ustar eugeneeugene// Not that this file has no package (that's what we are testing) and therefore, // it is at the wrong location, but it's easier to leave it here. // Also, do not change the line numbers since the test will make sure // that the tags are generated in hardcoded line numbers import junit.framework.TestCase; public class ConverterSample2 extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); } @Override protected void tearDown() throws Exception { super.tearDown(); } public final void testClassJunit() { } public final void testSetClassId() { } public final void testSetClassName() { } } testng-6.9.12/src/test/java/NoPackageTest.java0000644000175000017500000000056712732165123020453 0ustar eugeneeugene import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; /** * @author Filippo Diotalevi */ public class NoPackageTest { private boolean m_run = false; @Test(groups = {"nopackage"}) public void test() { m_run = true; } @AfterMethod(groups = {"nopackage"}) public void after() { assert m_run : "test method was not run"; } } testng-6.9.12/src/test/java/ConverterSample4.java0000644000175000017500000000346512732165123021160 0ustar eugeneeugene /* * Created on 12-Sep-2006 by micheb10 * it is at the wrong location, but it's easier to leave it here. * Also, do not change the line numbers since the test will make sure * that the tags are generated in hardcoded line numbers */ /** * Sample file for the Javadocv annotations to Java 5 annotations converter for the default package * @author micheb10 12-Sep-2006 * */ public class ConverterSample4 { /** * This comment line should be preserved * @testng.before-suite alwaysRun = "true" */ public void beforeSuiteAlwaysRun() { // We are just checking appropriate annotations are added so we don't care about body } /** * @testng.test */ public void plainTest() { // Empty body } /** * @testng.test * @testng.expected-exceptions * value = "java.lang.NullPointerException java.lang.NumberFormatException" */ public void expectedExceptions() { // Empty body } /** * @testng.test groups = "groupA groupB" */ public void testGroups() { // Empty body } /** * @testng.after-method */ public void afterMethod() { // Empty body } /** * This key should be preserved * @author The author is a standard tag and should not be touched * @testng.test groups = "groupA" * dependsOnMethods = "expectedExceptions" timeOut="3000" unrecognised="futureProof" * @version another standard tag should not be changed * @testng.expected-exceptions * value = "java.lang.NullPointerException java.lang.NumberFormatException" * */ public void testEverything() { } /** * @testng.data-provider name="test1" */ public Object[][] dataProvider() { return null; } /** * @testng.factory */ @SuppressWarnings({"unchecked", "deprecation"}) public Object[] factory() { return null; } } testng-6.9.12/src/test/java/org/0000755000175000017500000000000012732165123015677 5ustar eugeneeugenetestng-6.9.12/src/test/java/org/testng/0000755000175000017500000000000012732165123017203 5ustar eugeneeugenetestng-6.9.12/src/test/java/org/testng/xml/0000755000175000017500000000000012732165123020003 5ustar eugeneeugenetestng-6.9.12/src/test/java/org/testng/xml/SuiteXmlParserTest.java0000644000175000017500000000243612732165123024442 0ustar eugeneeugenepackage org.testng.xml; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.File; import java.io.FileInputStream; import static test.SimpleBaseTest.getPathToResource; public class SuiteXmlParserTest { private static final File PARENT = new File(getPathToResource("xml")); @DataProvider private static Object[][] dp() { return new Object[][] { { "goodWithDoctype.xml", true }, { "goodWithoutDoctype.xml", true }, { "badWithDoctype.xml", false }, // TestNGException -> SAXParseException { "badWithoutDoctype.xml", false } // NullPointerException }; } @Test(dataProvider = "dp") public void testParse(String fileName, boolean shouldWork) { SuiteXmlParser parser = new SuiteXmlParser(); try (FileInputStream stream = new FileInputStream(new File(PARENT, fileName))) { parser.parse(fileName, stream, false); if (!shouldWork) { Assert.fail("Parsing of " + fileName + " is supposed to fail"); } } catch (Exception e) { if (shouldWork) { Assert.fail("Parsing of " + fileName + " is supposed to work"); } } } }testng-6.9.12/src/test/java/org/testng/AssertTest.java0000644000175000017500000001034612732165123022153 0ustar eugeneeugenepackage org.testng; import org.testng.annotations.Test; import org.testng.collections.Maps; import org.testng.collections.Sets; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * This class/interface */ public class AssertTest { @Test public void nullObjectArrayAssertEquals() { Object[] expected= null; Object[] actual= null; Assert.assertEquals(actual, expected); } @Test public void nullObjectArrayAssertNoOrder() { Object[] expected= null; Object[] actual= null; Assert.assertEqualsNoOrder(actual, expected); } @Test public void nullCollectionAssertEquals() { Collection expected = null; Collection actual = null; Assert.assertEquals(actual, expected); } @Test public void nullSetAssertEquals() { Set expected = null; Set actual = null; Assert.assertEquals(actual, expected); } @Test public void nullMapAssertEquals() { Map expected = null; Map actual = null; Assert.assertEquals(actual, expected); } @Test public void setAssertEquals() { Set expected = Sets.newHashSet(); Set actual = Sets.newHashSet(); expected.add(1); expected.add("a"); actual.add("a"); actual.add(1); Assert.assertEquals(actual, expected); } @Test public void mapAssertEquals() { Map expected = Maps.newHashMap(); Map actual = Maps.newHashMap(); expected.put(null, "a"); expected.put("a", "a"); expected.put("b", "c"); actual.put("b", "c"); actual.put(null, "a"); actual.put("a", "a"); Assert.assertEquals(actual, expected); } @Test public void oneNullMapAssertEquals() { Map expected = Maps.newHashMap(); Map actual = null; try { Assert.assertEquals(actual, expected); Assert.fail("AssertEquals didn't fail"); } catch (AssertionError error) { //do nothing } } @Test public void oneNullSetAssertEquals() { Set expected = null; Set actual = Sets.newHashSet(); try { Assert.assertEquals(actual, expected); Assert.fail("AssertEquals didn't fail"); } catch (AssertionError error) { //do nothing } } @Test(expectedExceptions = AssertionError.class) public void assertEqualsMapShouldFail() { Map mapActual = new HashMap() {{ put("a","1"); }}; Map mapExpected = new HashMap() {{ put("a","1"); put("b","2"); }}; Assert.assertEquals(mapActual, mapExpected); } @Test(expectedExceptions = AssertionError.class) public void assertEqualsSymmetricScalar() { Assert.assertEquals(new Asymmetric(42, 'd'), new Contrived(42)); } @Test(expectedExceptions = AssertionError.class) public void assertEqualsSymmetricArrays() { Object[] actual = {1, new Asymmetric(42, 'd'), "inDay"}; Object[] expected = {1, new Contrived(42), "inDay"}; Assert.assertEquals(actual, expected); } class Contrived { int integer; Contrived(int integer){ this.integer = integer; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Contrived)) return false; Contrived contrived = (Contrived) o; if (integer != contrived.integer) return false; return true; } @Override public int hashCode() { return integer; } } class Asymmetric extends Contrived { char character; Asymmetric(int integer, char character) { super(integer); this.character = character; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Asymmetric)) return false; if (!super.equals(o)) return false; Asymmetric that = (Asymmetric) o; if (character != that.character) return false; return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (int) character; return result; } } } testng-6.9.12/src/test/java/org/testng/internal/0000755000175000017500000000000012732165123021017 5ustar eugeneeugenetestng-6.9.12/src/test/java/org/testng/internal/MethodInstanceTest.java0000644000175000017500000003265712732165123025444 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import org.testng.Assert; import org.testng.IClass; import org.testng.IRetryAnalyzer; import org.testng.ITestClass; import org.testng.ITestNGMethod; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlTest; /** * Unit tests for {@link MethodInstance}. * * @author Andreas Kluth */ public class MethodInstanceTest { public static void main(String[] args) { new MethodInstanceTest().sortByIndexSatisfiesContract(); } @Test public void sortByIndexSatisfiesContract() { // Build a list of entries imposing the same behavior as the live suite, reduced to the // minimum to create the same condition. List methods = new ArrayList<>(); methods.add(buildMethodInstance("unittests", "StateTest", 1, "aCategorization")); methods.add(buildMethodInstance("unittests", "StateTest", 1, "bCategorization")); methods.add(buildMethodInstance("unittests", "StateTest", 1, "cCategorization")); methods.add(buildMethodInstance("unittests", "StateTest", 1, "dCategorization")); methods.add(buildMethodInstance("unittests", "StateTest", 1, "eCategorization")); methods.add(buildMethodInstance("unittests", "StateTest", 1, "fCategorization")); methods.add(buildMethodInstance("unittests", "StatusTest", 2, "aStatus")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildTestNgFactoryMethodInstance("unittests")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "aChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "bChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "cChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "dChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "eChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "fChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "gChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "eChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "hChangeTest")); methods.add(buildMethodInstance("unittests", "ChangeTest", 3, "iChangeTest")); methods.add(buildMethodInstance("unittests", "IdentifierClassTest", 4, "aIdentifier")); methods.add(buildMethodInstance("unittests", "IdentifierClassTest", 4, "bIdentifier")); methods.add(buildMethodInstance("unittests", "StatisticsTest", 0, "aStatistics")); methods.add(buildMethodInstance("unittests", "StatisticsTest", 0, "bStatistics")); methods.add(buildMethodInstance("unittests", "StatisticsTest", 0, "cStatistics")); try { Collections.sort(methods, MethodInstance.SORT_BY_INDEX); } catch (IllegalArgumentException ex) { Assert.fail("Comparison method violates its general contract!"); } } private MethodInstance buildTestNgFactoryMethodInstance(String xmlTestName) { TestClassStub testClass = new TestClassStub(new XmlTestStub(xmlTestName), null); return new MethodInstance(new TestNGMethodStub(null, testClass)); } private MethodInstance buildMethodInstance(String xmlTestName, String xmlClassName, int xmlClassIndex, String methodName) { TestClassStub testClass = new TestClassStub(new XmlTestStub(xmlTestName), new XmlClassStub(xmlClassName, xmlClassIndex)); return new MethodInstance(new TestNGMethodStub(methodName, testClass)); } public static class XmlClassStub extends XmlClass { private static final long serialVersionUID = 1L; private int index; private String name; public XmlClassStub(String name, int index) { this.name = name; this.index = index; } @Override public String getName() { return name; } @Override public int getIndex() { return index; } @Override public List getIncludedMethods() { return Collections.emptyList(); } } public static class XmlTestStub extends XmlTest { private static final long serialVersionUID = 1L; private String name; public XmlTestStub(String name) { this.name = name; } @Override public String getName() { return name; } } public static class TestClassStub implements ITestClass { private static final long serialVersionUID = 1L; private XmlTest xmlTest; private XmlClass xmlClass; public TestClassStub(XmlTest xmlTest, XmlClass xmlClass) { this.xmlTest = xmlTest; this.xmlClass = xmlClass; } @Override public String getName() { return null; } @Override public XmlTest getXmlTest() { return xmlTest; } @Override public XmlClass getXmlClass() { return xmlClass; } @Override public String getTestName() { return null; } @SuppressWarnings("rawtypes") @Override public Class getRealClass() { return null; } @Override public void addInstance(Object instance) { } @Override public Object[] getInstances(boolean reuse) { return null; } @Override public long[] getInstanceHashCodes() { return null; } @Deprecated @Override public int getInstanceCount() { return 0; } @Override public ITestNGMethod[] getTestMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getBeforeTestMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getAfterTestMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getBeforeClassMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getAfterClassMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getBeforeSuiteMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getAfterSuiteMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getBeforeTestConfigurationMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getAfterTestConfigurationMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getBeforeGroupsMethods() { return new ITestNGMethod[0]; } @Override public ITestNGMethod[] getAfterGroupsMethods() { return new ITestNGMethod[0]; } } public static class TestNGMethodStub implements ITestNGMethod { private static final long serialVersionUID = 1L; private TestClassStub testClassStub; private String methodName; public TestNGMethodStub(String methodName, TestClassStub testClassStub) { this.methodName = methodName; this.testClassStub = testClassStub; } @Override public ITestNGMethod clone() { return (TestNGMethodStub) this; } @Override public int compareTo(Object o) { return 0; } @SuppressWarnings("rawtypes") @Override public Class getRealClass() { return null; } @Override public ITestClass getTestClass() { return testClassStub; } @Override public void setTestClass(ITestClass cls) { } @Override public Method getMethod() { return null; } @Override public String getMethodName() { return methodName; } @Override public Object[] getInstances() { return null; } @Override public Object getInstance() { return null; } @Override public long[] getInstanceHashCodes() { return null; } @Override public String[] getGroups() { return null; } @Override public String[] getGroupsDependedUpon() { return null; } @Override public String getMissingGroup() { return null; } @Override public void setMissingGroup(String group) { } @Override public String[] getBeforeGroups() { return null; } @Override public String[] getAfterGroups() { return null; } @Override public String[] getMethodsDependedUpon() { return null; } @Override public void addMethodDependedUpon(String methodName) { } @Override public boolean isTest() { return false; } @Override public boolean isBeforeMethodConfiguration() { return false; } @Override public boolean isAfterMethodConfiguration() { return false; } @Override public boolean isBeforeClassConfiguration() { return false; } @Override public boolean isAfterClassConfiguration() { return false; } @Override public boolean isBeforeSuiteConfiguration() { return false; } @Override public boolean isAfterSuiteConfiguration() { return false; } @Override public boolean isBeforeTestConfiguration() { return false; } @Override public boolean isAfterTestConfiguration() { return false; } @Override public boolean isBeforeGroupsConfiguration() { return false; } @Override public boolean isAfterGroupsConfiguration() { return false; } @Override public long getTimeOut() { return 0; } @Override public void setTimeOut(long timeOut) { } @Override public int getInvocationCount() { return 0; } @Override public int getTotalInvocationCount() { return 0; } @Override public void setInvocationCount(int count) { } @Override public void setMoreInvocationChecker(Callable moreInvocationChecker) { } @Override public boolean hasMoreInvocation() { return false; } @Override public int getSuccessPercentage() { return 0; } @Override public String getId() { return null; } @Override public void setId(String id) { } @Override public long getDate() { return 0; } @Override public void setDate(long date) { } @Override public boolean canRunFromClass(IClass testClass) { return false; } @Override public boolean isAlwaysRun() { return false; } @Override public int getThreadPoolSize() { return 0; } @Override public void setThreadPoolSize(int threadPoolSize) { } @Override public boolean getEnabled() { return false; } @Override public String getDescription() { return null; } @Override public void setDescription(String description) { } @Override public void incrementCurrentInvocationCount() { } @Override public int getCurrentInvocationCount() { return 0; } @Override public void setParameterInvocationCount(int n) { } @Override public int getParameterInvocationCount() { return 0; } @Override public IRetryAnalyzer getRetryAnalyzer() { return null; } @Override public void setRetryAnalyzer(IRetryAnalyzer retryAnalyzer) { } @Override public boolean skipFailedInvocations() { return false; } @Override public void setSkipFailedInvocations(boolean skip) { } @Override public long getInvocationTimeOut() { return 0; } @Override public boolean ignoreMissingDependencies() { return false; } @Override public void setIgnoreMissingDependencies(boolean ignore) { } @Override public List getInvocationNumbers() { return null; } @Override public void setInvocationNumbers(List numbers) { } @Override public void addFailedInvocationNumber(int number) { } @Override public List getFailedInvocationNumbers() { return null; } @Override public int getPriority() { return 0; } @Override public void setPriority(int priority) { } @Override public XmlTest getXmlTest() { return null; } @Override public ConstructorOrMethod getConstructorOrMethod() { return null; } @Override public Map findMethodParameters(XmlTest test) { return null; } } } testng-6.9.12/src/test/java/org/testng/internal/invokers/0000755000175000017500000000000012732165123022657 5ustar eugeneeugenetestng-6.9.12/src/test/java/org/testng/internal/invokers/InvokedMethodListenerSubtypeTest.java0000644000175000017500000000363012732165123032206 0ustar eugeneeugenepackage org.testng.internal.invokers; import org.testng.Assert; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.IInvokedMethodListener2; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.annotations.Test; @Test public class InvokedMethodListenerSubtypeTest { @Test public void testFromListenerUsingSimpleListenerInstance() { final IInvokedMethodListener simpleListenerInstance = new SimpleInvokedMethodListenerDummy(); InvokedMethodListenerSubtype listenerSubtype = InvokedMethodListenerSubtype.fromListener(simpleListenerInstance); Assert.assertEquals(listenerSubtype, InvokedMethodListenerSubtype.SIMPLE_LISTENER); } @Test public void testFromListenerUsingExtendedListenerInstance() { IInvokedMethodListener2 extendedListenerInstance = new ExtendedInvokedMethodListenerDummy(); InvokedMethodListenerSubtype listenerSubtype = InvokedMethodListenerSubtype.fromListener(extendedListenerInstance); Assert.assertEquals(listenerSubtype, InvokedMethodListenerSubtype.EXTENDED_LISTENER); } static class SimpleInvokedMethodListenerDummy implements IInvokedMethodListener { public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { } public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } } static class ExtendedInvokedMethodListenerDummy implements IInvokedMethodListener2 { public void beforeInvocation(IInvokedMethod method, ITestResult testResult, ITestContext context) { } public void afterInvocation(IInvokedMethod method, ITestResult testResult, ITestContext context) { } public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { } public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } } } testng-6.9.12/src/test/java/org/testng/internal/UtilsTest.java0000644000175000017500000000227212732165123023625 0ustar eugeneeugenepackage org.testng.internal; import java.util.List; import org.testng.annotations.Test; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static org.testng.Assert.assertEquals; import static org.testng.internal.Utils.join; /** * Unit tests for {@link Utils}. * * @author Tomas Pollak */ public class UtilsTest { private static final char INVALID_CHAR = 0xFFFE; private static final char REPLACEMENT_CHAR = 0xFFFD; @Test public void escapeUnicode() { assertEquals(Utils.escapeUnicode("test"), "test"); assertEquals(Utils.escapeUnicode(String.valueOf(INVALID_CHAR)), String.valueOf(REPLACEMENT_CHAR)); } @Test public void createEmptyStringWhenJoiningEmptyListWithJoin() throws Exception { List emptyList = emptyList(); assertEquals("", join(emptyList, ",")); } @Test public void joinTwoStringsWithJoinStrings() throws Exception { List twoStrings = asList("one", "two"); assertEquals("one,two", Utils.join(twoStrings, ",")); } @Test public void createEmptyStringWhenJoiningEmptyListWithJoinStrings() throws Exception { List emptyList = emptyList(); assertEquals("", Utils.join(emptyList, ",")); } } testng-6.9.12/src/test/java/org/testng/internal/conflistener/0000755000175000017500000000000012732165123023512 5ustar eugeneeugenetestng-6.9.12/src/test/java/org/testng/internal/conflistener/FailingAfterSuite.java0000644000175000017500000000055312732165123027725 0ustar eugeneeugenepackage org.testng.internal.conflistener; import org.testng.annotations.AfterSuite; import org.testng.annotations.Test; /** * This class/interface */ public class FailingAfterSuite { @AfterSuite(alwaysRun=true) public void afterSuite() { throw new RuntimeException("Test exception"); } @Test public void dummytest() { } } testng-6.9.12/src/test/java/org/testng/internal/conflistener/testng.xml0000644000175000017500000000164412732165123025545 0ustar eugeneeugene testng-6.9.12/src/test/java/org/testng/internal/conflistener/FailingBeforeSuite.java0000644000175000017500000000053712732165123030070 0ustar eugeneeugenepackage org.testng.internal.conflistener; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; /** * This class/interface */ public class FailingBeforeSuite { @BeforeSuite public void beforeSuite() { throw new RuntimeException("Test exception"); } @Test public void dummytest() { } } testng-6.9.12/src/test/java/org/testng/internal/conflistener/FailingAfterClass.java0000644000175000017500000000060512732165123027677 0ustar eugeneeugenepackage org.testng.internal.conflistener; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; /** * This class/interface does XXX */ public class FailingAfterClass { @AfterClass public void failingAfterClass() { throw new RuntimeException("expected @AfterClass failure"); } @Test public void testBeforeFailingAfterClass() {} } testng-6.9.12/src/test/java/org/testng/internal/conflistener/FailingAfterTest.java0000644000175000017500000000064012732165123027550 0ustar eugeneeugenepackage org.testng.internal.conflistener; import org.testng.annotations.AfterTest; import org.testng.annotations.Test; /** * This class/interface */ public class FailingAfterTest { @AfterTest(alwaysRun=true) public void afterTest() { throw new RuntimeException("Test exception"); } @AfterTest public void skippedAfterTest() { } @Test public void dummytest() { } } testng-6.9.12/src/test/java/org/testng/internal/conflistener/FailingBeforeClass.java0000644000175000017500000000061212732165123030036 0ustar eugeneeugenepackage org.testng.internal.conflistener; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * This class/interface does XXX */ public class FailingBeforeClass { @BeforeClass public void failingBeforeClass() { throw new RuntimeException("expected @BeforeClass failure"); } @Test public void testAfterFailingBeforeClass() {} } testng-6.9.12/src/test/java/org/testng/internal/conflistener/FailingBeforeTest.java0000644000175000017500000000070412732165123027712 0ustar eugeneeugenepackage org.testng.internal.conflistener; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; /** * This class/interface */ public class FailingBeforeTest { @BeforeSuite public void passingBeforeSuite() { } @BeforeTest public void beforeTest() { throw new RuntimeException("Test exception"); } @Test public void dummytest() { } } testng-6.9.12/src/test/java/test/0000755000175000017500000000000012732165123016067 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/xml/0000755000175000017500000000000012732165123016667 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/xml/XmlVerifyTest.java0000644000175000017500000000332312732165123022320 0ustar eugeneeugenepackage test.xml; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.Arrays; public class XmlVerifyTest extends SimpleBaseTest { // private String getFinalPath(String file) { // File currentDir = new File("."); // String path = currentDir.getAbsolutePath(); // char s = File.separatorChar; // String testDir = System.getProperty("test.dir"); // System.out.println("[XmlVerifyTest] test.dir:" + testDir); // Assert.assertNotNull(testDir); // path = path + s + testDir + s; // return path + file; // } @Test public void simple() { XmlSuite suite = new XmlSuite(); XmlTest test = new XmlTest(suite); XmlClass xClass = new XmlClass(XmlVerifyTest.class); test.getXmlClasses().add(xClass); test.getExcludedGroups().add("fast"); test.setVerbose(5); suite.toXml(); } @Test(description="Ensure that TestNG stops without running any tests if some class" + " included in suite is missing") public void handleInvalidSuites() { TestListenerAdapter tla = new TestListenerAdapter(); try { TestNG tng = create(); String testngXmlPath = getPathToResource("suite1.xml"); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); } catch (TestNGException ex) { Assert.assertEquals(tla.getPassedTests().size(), 0); } } } testng-6.9.12/src/test/java/test/pkg/0000755000175000017500000000000012732165123016650 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/pkg/PackageTest.java0000644000175000017500000000471012732165123021710 0ustar eugeneeugenepackage test.pkg; import static org.testng.Assert.assertTrue; import org.testng.annotations.Test; import test.BaseTest; import test.pkg2.Test2; /** * Tests that in testng.xml works. * * Created on Aug 2, 2005 * @author cbeust */ public class PackageTest extends BaseTest { public static boolean NON_TEST_CONSTRUCTOR= false; @Test public void stringSingle() { addPackage("test.pkg2", new String[0], new String[0]); run(); String[] passed = { "method11", "method12", "method31", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void packageWithNonTestClasses() { addPackage("test.pkg2", new String[0], new String[0]); run(); assertTrue(!NON_TEST_CONSTRUCTOR, Test2.class.getName() + " should not be considered"); } @Test public void packageWithRegExp1() { addPackage("test.pkg2", new String[] { ".*1.*"}, new String[0]); run(); String[] passed = { "method11", "method12", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void packageWithRegExp2() { addPackage("test.pkg2", new String[0], new String[] { ".*1.*"}); run(); String[] passed = { "method31", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void packageWithRegExp3() { addPackage("test.pkg2", new String[] { ".*3.*"}, new String[] { ".*1.*"}); run(); String[] passed = { "method31", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void packageWithRegExp4() { addPackage("test.pkg2", new String[] { ".*1.*"}, new String[] { ".*3.*"}); run(); String[] passed = { "method11", "method12" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void packageWithRegExp5() { addPackage("test.pkg2", new String[0], new String[] { "Test.*"}); run(); String[] passed = { }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/ClassConfigurations.java0000644000175000017500000000203712732165123022714 0ustar eugeneeugenepackage test; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ClassConfigurations { static int beforeCount = 0; static int afterCount = 0; @BeforeClass public void beforeTestClass() { ++beforeCount; // System.out.println("@@@@@@ beforeTestClass has been called " + beforeCount + " time(s)"); } @AfterTest public void afterTest() { beforeCount = 0; afterCount = 0; } @AfterTest public void afterTestClass() { ++afterCount; // System.out.println("@@@@@@@ afterTestClass has been called " + afterCount + " time(s)"); } @Test public void testOne() { // System.out.println("testOne"); assert beforeCount == 1; assert afterCount == 0; } @Test public void testTwo() { // System.out.println("testTwo"); assert beforeCount == 1; assert afterCount == 0; } @Test public void testThree() { // System.out.println("testThree"); assert beforeCount == 1; assert afterCount == 0; } }testng-6.9.12/src/test/java/test/GraphTest.java0000644000175000017500000001361612732165123020642 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.TestNGException; import org.testng.annotations.Test; import org.testng.internal.Graph; import org.testng.internal.Tarjan; import java.util.List; /** * This class * * @author cbeust */ public class GraphTest { @Test public void sort() { Graph g = new Graph<>(); g.addNode("3"); g.addNode("1"); g.addNode("2.2"); g.addNode("independent"); g.addNode("2.1"); g.addNode("2"); g.addPredecessor("3", "2"); g.addPredecessor("3", "2.1"); g.addPredecessor("3", "2.2"); g.addPredecessor("2", "1"); g.addPredecessor("2.1", "1"); g.addPredecessor("2.2", "1"); g.topologicalSort(); List l = g.getStrictlySortedNodes(); int i = 0; Assert.assertTrue("1".equals(l.get(i))); i++; Assert.assertTrue("2".equals(l.get(i)) || "2.1".equals(l.get(i)) || "2.2".equals(l.get(i))); i++; Assert.assertTrue("2".equals(l.get(i)) || "2.1".equals(l.get(i)) || "2.2".equals(l.get(i))); i++; Assert.assertTrue("2".equals(l.get(i)) || "2.1".equals(l.get(i)) || "2.2".equals(l.get(i))); i++; Assert.assertTrue("3".equals(l.get(i))); Assert.assertTrue(1 == g.getIndependentNodes().size()); } @Test(expectedExceptions = org.testng.TestNGException.class) public void cycleShouldFail() { Graph g = createCyclicGraph(); g.topologicalSort(); } @Test public void cycleShouldBeCorrect() { Graph g = null; try { g = createCyclicGraph(); g.topologicalSort(); } catch(TestNGException ex) { Tarjan t = new Tarjan<>(g, "1"); Assert.assertEquals(t.getCycle().size(), 3); } } private Graph createCyclicGraph() { Graph g = new Graph<>(); g.addNode("3"); g.addNode("2"); g.addNode("1"); g.addPredecessor("3", "2"); g.addPredecessor("2", "1"); g.addPredecessor("1", "3"); return g; } @Test public void findPredecessors() { Graph g = new Graph<>(); g.addNode("3"); g.addNode("1"); g.addNode("2.2"); g.addNode("independent"); g.addNode("2.1"); g.addNode("2"); // 1 -> 2.1, 2.2, 2.3 --> 3 g.addPredecessor("3", "2"); g.addPredecessor("3", "2.1"); g.addPredecessor("3", "2.2"); g.addPredecessor("2", "1"); g.addPredecessor("2.1", "1"); g.addPredecessor("2.2", "1"); // Invoke sort to make sure there is no side effect g.topologicalSort(); // // Test findPredecessors // { List predecessors = g.findPredecessors("2"); Assert.assertTrue(predecessors.size() == 1); Assert.assertTrue(predecessors.get(0).equals("1")); } { List predecessors = g.findPredecessors("3"); Assert.assertTrue(predecessors.size() == 4); Assert.assertTrue(predecessors.get(0).equals("1")); Assert.assertTrue(predecessors.get(1).equals("2.1") || predecessors.get(1).equals("2.2") || predecessors.get(1).equals("2")); Assert.assertTrue(predecessors.get(2).equals("2.1") || predecessors.get(2).equals("2.2") || predecessors.get(2).equals("2")); Assert.assertTrue(predecessors.get(3).equals("2.1") || predecessors.get(3).equals("2.2") || predecessors.get(3).equals("2")); } } // Using an earlier implementation of Graph.findPrecessors, finding // predecessors in certain kinds of graphs where many nodes have the // same predecessors could be very slow, since the old implementation // would explore the same nodes repeatedly. This situation could // happen when test methods are organized in several groups, with // dependsOnGroups annotations so that each method in one group depends // on all of the methods in another group. If there were several // such groups depending on each other in a chain, the combinatorics // of the old method became excessive. This test builds a 72-node graph that // emulates this situation, then call Graph.findPredecessors. The old // implementation run this in 70+ seconds on my computer, the new implementation // takes a few milliseconds. In practice, with larger graphs, the former // slowness could get very extreme, taking hours or more to complete // in some real user situations. // @Test(timeOut = 5000) // If this takes more than 5 seconds we've definitely regressed. public void findPredecessorsTiming() { Graph g = new Graph<>(); final String rootNode = "myroot"; final String independentNode = "independent"; g.addNode(rootNode); g.addNode(independentNode); final int maxDepth = 7; final int nodesPerDepth = 10; // must be < 100 // // Add maxDepth groups of new nodes, where each group contains nodesPerDepth // nodes, and each node in a group a depth N has each node in the group // at depth (N-1) as a predecessor. // for (int depth = 1; depth <= maxDepth; depth++) { for (int i = 0; i < nodesPerDepth; i++) { String newNode = String.valueOf(i + (100 * depth)); g.addNode(newNode); if (depth == 1) { continue; } for (int j = 0; j < nodesPerDepth; j++) { String prevNode = String.valueOf(j + (100 * (depth - 1))); g.addPredecessor(newNode, prevNode); } } } // Finally, make all of the nodes in the group at depth maxDepth // be predecessors of rootNode. // for (int i = 0; i < nodesPerDepth; i++) { String node = String.valueOf(i + (100 * maxDepth)); g.addPredecessor(rootNode, node); } // Now we're done building the graph, which has (maxDepth * nodesPerDepth) + 2 // nodes. rootNode has all of the other nodes except independentNode // as predecessors. // // Test findPredecessors // { List predecessors = g.findPredecessors(rootNode); Assert.assertTrue(predecessors.size() == (maxDepth * nodesPerDepth)); } } } testng-6.9.12/src/test/java/test/ParameterConstructorTest.java0000644000175000017500000000241612732165123023763 0ustar eugeneeugenepackage test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * Test parameters passed to constructors * * @author cbeust */ public class ParameterConstructorTest { private String m_string = null; private int m_int = -1; private boolean m_boolean = false; private byte m_byte = -1; private char m_char = 0; private double m_double = 0.0; private float m_float = 0.0f; private long m_long = 0; private short m_short = 0; @Parameters({ "string", "int", "boolean", "byte", "char", "double", "float", "long", "short" }) public ParameterConstructorTest(String s, int i, boolean bo, byte b, char c, double d, float f, long l, short sh) { m_string = s; m_int = i; m_boolean = bo; m_byte = b; m_char = c; m_double = d; m_float = f; m_long = l; m_short = sh; } @Test public void verify() { assertEquals("Cedric", m_string); assertEquals(42, m_int); assertTrue(m_boolean); assertEquals(43, m_byte); assertEquals('c', m_char); assertEquals(44.0, m_double, 0.1); assertEquals(45.0f, m_float, 0.1); assertEquals(46, m_long); assertEquals(47, m_short); } } testng-6.9.12/src/test/java/test/ReporterApiTest.java0000644000175000017500000000057712732165123022037 0ustar eugeneeugenepackage test; import org.testng.Reporter; import org.testng.annotations.Test; /** * Make sure we don't remove public API's from Reporter. * * @author Cedric Beust */ public class ReporterApiTest { @Test public void testApi() { Reporter.log("foo"); Reporter.log("foo", false); Reporter.log("foo", 2); Reporter.log("foo", 2, false); } } testng-6.9.12/src/test/java/test/invokedmethodlistener/0000755000175000017500000000000012732165123022475 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/invokedmethodlistener/C.java0000644000175000017500000000035212732165123023522 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; @Test public class C extends A{ @BeforeSuite public static void someMethod3() {} public void someTest() {} } testng-6.9.12/src/test/java/test/invokedmethodlistener/B.java0000644000175000017500000000037112732165123023522 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; @Test(enabled=false) public class B extends A{ @BeforeSuite public static void someMethod2() {} public void someTest() {} } testng-6.9.12/src/test/java/test/invokedmethodlistener/MyListener.java0000644000175000017500000000250312732165123025433 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; public class MyListener implements IInvokedMethodListener { private int m_beforeCount = 0; private int m_afterCount = 0; private Throwable suiteThrowable; private int suiteStatus = 0; private Throwable methodThrowable; private int methodStatus = 0; @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { m_afterCount++; if (method.getTestMethod().isAfterSuiteConfiguration()) { suiteStatus = testResult.getStatus(); suiteThrowable = testResult.getThrowable(); } if (method.getTestMethod().isTest()) { methodStatus = testResult.getStatus(); methodThrowable = testResult.getThrowable(); } } @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { m_beforeCount++; } public int getBeforeCount() { return m_beforeCount; } public int getAfterCount() { return m_afterCount; } public Throwable getSuiteThrowable() { return suiteThrowable; } public int getSuiteStatus() { return suiteStatus; } public Throwable getMethodThrowable() { return methodThrowable; } public int getMethodStatus() { return methodStatus; } } testng-6.9.12/src/test/java/test/invokedmethodlistener/Sample.java0000644000175000017500000000111012732165123024552 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class Sample { @Test public void t1() { try { Thread.sleep(100); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); } } @Test public void t2() { try { Thread.sleep(100); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); } } @AfterMethod public void am() {} @BeforeSuite public void bs() {} } testng-6.9.12/src/test/java/test/invokedmethodlistener/InvokedMethodListenerTest.java0000644000175000017500000001271012732165123030447 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.Assert; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; import java.util.List; public class InvokedMethodListenerTest extends SimpleBaseTest { private static void run(Class[] classes, IInvokedMethodListener l) { TestNG tng = create(); tng.setTestClasses(classes); tng.addInvokedMethodListener(l); tng.run(); } private static void assertMethodCount(MyListener l) { Assert.assertEquals(l.getBeforeCount(), 9); Assert.assertEquals(l.getAfterCount(), 9); } @Test public void withSuccess() { MyListener l = new MyListener(); run(new Class[]{Success.class}, l); assertMethodCount(l); } @Test public void withFailure() { MyListener l = new MyListener(); run(new Class[] { Failure.class }, l); assertMethodCount(l); Assert.assertEquals(l.getSuiteStatus(), ITestResult.FAILURE); Assert.assertTrue(null != l.getSuiteThrowable()); Assert.assertTrue(l.getSuiteThrowable().getClass() == RuntimeException.class); Assert.assertEquals(l.getMethodStatus(), ITestResult.FAILURE); Assert.assertTrue(null != l.getMethodThrowable()); Assert.assertTrue(l.getMethodThrowable().getClass() == IllegalArgumentException.class); } /** * Fix for: * https://github.com/juherr/testng-googlecode/issues/7 * https://github.com/juherr/testng-googlecode/issues/86 * https://github.com/cbeust/testng/issues/93 */ @Test public void sameMethodInvokedMultipleTimesShouldHaveDifferentTimeStamps() { TestNG tng = create(Sample.class); InvokedMethodListener listener = new InvokedMethodListener(); tng.addListener(listener); tng.run(); List m = listener.getInvokedMethods(); IInvokedMethod beforeSuite = m.get(0); Assert.assertFalse(beforeSuite.getTestMethod().isAfterMethodConfiguration()); Assert.assertTrue(beforeSuite.isConfigurationMethod()); IInvokedMethod after1 = m.get(2); Assert.assertTrue(after1.getTestMethod().isAfterMethodConfiguration()); Assert.assertTrue(after1.isConfigurationMethod()); IInvokedMethod after2 = m.get(4); Assert.assertTrue(after2.getTestMethod().isAfterMethodConfiguration()); Assert.assertTrue(after2.isConfigurationMethod()); Assert.assertTrue(after1.getDate() != after2.getDate()); } @Test(description = "Test methods with expected exceptions should show up as pass" + " in IInvokedMethodListener's afterInvocation method") public void testMethodsWithExpectedExceptionsShouldShowUpAsPass() { TestNG tng = create(Sample2.class); Sample2.Sample2InvokedMethodListener l = new Sample2().new Sample2InvokedMethodListener(); tng.addListener(l); tng.run(); Assert.assertTrue(l.isSuccess); } @Test(description = "Invoked method does not recognize configuration method") public void issue629_InvokedMethodDoesNotRecognizeConfigurationMethod() { InvokedMethodNameListener l = new InvokedMethodNameListener(); run(new Class[]{Success.class}, l); Assert.assertEquals(l.testMethods.size(), 1); Assert.assertTrue(l.testMethods.contains("a")); Assert.assertEquals(l.testMethodsFromTM.size(), 1); Assert.assertTrue(l.testMethodsFromTM.contains("a")); Assert.assertEquals(l.configurationMethods.size(), 8); Assert.assertTrue(l.configurationMethods.contains("beforeMethod")); Assert.assertTrue(l.configurationMethods.contains("afterMethod")); Assert.assertTrue(l.configurationMethods.contains("beforeTest")); Assert.assertTrue(l.configurationMethods.contains("afterTest")); Assert.assertTrue(l.configurationMethods.contains("beforeClass")); Assert.assertTrue(l.configurationMethods.contains("afterClass")); Assert.assertTrue(l.configurationMethods.contains("beforeSuite")); Assert.assertTrue(l.configurationMethods.contains("afterSuite")); Assert.assertEquals(l.configurationMethodsFromTM.size(), 8); Assert.assertTrue(l.configurationMethodsFromTM.contains("beforeMethod")); Assert.assertTrue(l.configurationMethodsFromTM.contains("afterMethod")); Assert.assertTrue(l.configurationMethodsFromTM.contains("beforeTest")); Assert.assertTrue(l.configurationMethodsFromTM.contains("afterTest")); Assert.assertTrue(l.configurationMethodsFromTM.contains("beforeClass")); Assert.assertTrue(l.configurationMethodsFromTM.contains("afterClass")); Assert.assertTrue(l.configurationMethodsFromTM.contains("beforeSuite")); Assert.assertTrue(l.configurationMethodsFromTM.contains("afterSuite")); } @Test public void issue87_method_orderning_with_disable_test_class() { assertIssue87(A.class, B.class, C.class); assertIssue87(A.class, C.class, B.class); assertIssue87(B.class, A.class, C.class); } private void assertIssue87(Class... tests) { TestNG tng = create(tests); tng.setParallel(XmlSuite.ParallelMode.NONE); tng.setPreserveOrder(true); InvokedMethodListener listener = new InvokedMethodListener(); tng.addListener(listener); tng.run(); List m = listener.getInvokedMethods(); Assert.assertEquals(m.get(0).getTestMethod().getMethodName(), "someMethod1"); Assert.assertEquals(m.get(1).getTestMethod().getMethodName(), "someMethod3"); Assert.assertEquals(m.get(2).getTestMethod().getMethodName(), "someTest"); Assert.assertEquals(m.size(), 3); } } testng-6.9.12/src/test/java/test/invokedmethodlistener/Sample2.java0000644000175000017500000000163512732165123024650 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import org.testng.annotations.Test; public class Sample2 { @Test(expectedExceptions = IllegalArgumentException.class) public void t1() { throw new IllegalArgumentException("Throw this exception on purpose in test"); } public class Sample2InvokedMethodListener implements IInvokedMethodListener { boolean isSuccess = false; /** * {@inheritDoc} */ @Override public void afterInvocation(IInvokedMethod m, ITestResult tr) { isSuccess = tr.isSuccess(); } /** * {@inheritDoc} */ @Override public void beforeInvocation(IInvokedMethod arg0, ITestResult arg1) { // no need to implement this right now } public boolean isSuccess() { return isSuccess; } } } testng-6.9.12/src/test/java/test/invokedmethodlistener/Failure.java0000644000175000017500000000016612732165123024732 0ustar eugeneeugenepackage test.invokedmethodlistener; public class Failure extends Base { public Failure() { super(true); } } testng-6.9.12/src/test/java/test/invokedmethodlistener/A.java0000644000175000017500000000025312732165123023520 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.annotations.BeforeSuite; public class A { @BeforeSuite(alwaysRun=false) public static void someMethod1() {} } testng-6.9.12/src/test/java/test/invokedmethodlistener/InvokedMethodListener.java0000644000175000017500000000121212732165123027602 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import org.testng.collections.Lists; import java.util.List; public class InvokedMethodListener implements IInvokedMethodListener { private final List m_methods = Lists.newArrayList(); @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { m_methods.add(method); } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } public List getInvokedMethods() { return m_methods; } } testng-6.9.12/src/test/java/test/invokedmethodlistener/InvokedMethodNameListener.java0000644000175000017500000000305012732165123030405 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import java.util.HashSet; import java.util.Set; public class InvokedMethodNameListener implements IInvokedMethodListener { final Set testMethods = new HashSet<>(); final Set configurationMethods = new HashSet<>(); final Set testMethodsFromTM = new HashSet<>(); final Set configurationMethodsFromTM = new HashSet<>(); @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { String methodName = method.getTestMethod().getMethodName(); if (method.isTestMethod()) { testMethods.add(methodName); } if (method.isConfigurationMethod()) { configurationMethods.add(methodName); } if (method.getTestMethod().isTest()) { testMethodsFromTM.add(methodName); } if (method.getTestMethod().isBeforeMethodConfiguration() || method.getTestMethod().isAfterMethodConfiguration() || method.getTestMethod().isBeforeTestConfiguration() || method.getTestMethod().isAfterTestConfiguration() || method.getTestMethod().isBeforeClassConfiguration() || method.getTestMethod().isAfterClassConfiguration() || method.getTestMethod().isBeforeSuiteConfiguration() || method.getTestMethod().isAfterSuiteConfiguration()) { configurationMethodsFromTM.add(methodName); } } } testng-6.9.12/src/test/java/test/invokedmethodlistener/Base.java0000644000175000017500000000210712732165123024212 0ustar eugeneeugenepackage test.invokedmethodlistener; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class Base { private boolean m_fail; public Base(boolean fail) { m_fail = fail; } @BeforeMethod public void beforeMethod() { } @AfterMethod public void afterMethod() {} @BeforeTest public void beforeTest() {} @AfterTest public void afterTest() {} @BeforeClass public void beforeClass() {} @AfterClass public void afterClass() {} @BeforeSuite public void beforeSuite() {} @AfterSuite public void afterSuite() { if (m_fail) { throw new RuntimeException("After Suite FAILING"); } } @Test public void a() { if (m_fail) { throw new IllegalArgumentException("Test Method FAILING"); } } } testng-6.9.12/src/test/java/test/invokedmethodlistener/Success.java0000644000175000017500000000016712732165123024754 0ustar eugeneeugenepackage test.invokedmethodlistener; public class Success extends Base { public Success() { super(false); } } testng-6.9.12/src/test/java/test/testng59/0000755000175000017500000000000012732165123017551 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng59/Test2.java0000644000175000017500000000066012732165123021417 0ustar eugeneeugenepackage test.testng59; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; /** * This class/interface */ public class Test2 { private boolean m_run= false; @Test public void test2() { m_run= true; } @AfterClass public void checkWasRun() { Assert.assertTrue(m_run, "test2() should have been run according to testng-59.xml"); } } testng-6.9.12/src/test/java/test/testng59/Test1.java0000644000175000017500000000066012732165123021416 0ustar eugeneeugenepackage test.testng59; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; /** * This class/interface */ public class Test1 { private boolean m_run= false; @Test public void test1() { m_run= true; } @AfterClass public void checkWasRun() { Assert.assertTrue(m_run, "test1() should have been run according to testng-59.xml"); } } testng-6.9.12/src/test/java/test/testng59/testng-59.xml0000644000175000017500000000075412732165123022040 0ustar eugeneeugene testng-6.9.12/src/test/java/test/CtorCalledOnce.java0000644000175000017500000000152512732165123021556 0ustar eugeneeugenepackage test; import org.testng.annotations.AfterTest; import org.testng.annotations.Test; /** * this test verifys that the test class is instantiated exactly once * regardless of how many test methods we have, showing that TestNG * semantics is quite different from JUnit */ public class CtorCalledOnce { public static int instantiated = 0; public CtorCalledOnce() { instantiated++; } @Test public void testMethod1(){ assert instantiated == 1 : "Expected 1, was invoked " + instantiated + " times"; } @Test public void testMethod2(){ assert instantiated == 1 : "Expected 1, was invoked " + instantiated + " times"; } @Test public void testMethod3(){ assert instantiated == 1 : "Expected 1, was invoked " + instantiated + " times"; } @AfterTest public void afterTest() { instantiated = 0; } }testng-6.9.12/src/test/java/test/testnames/0000755000175000017500000000000012732165123020072 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testnames/TestNamesFeature.java0000644000175000017500000000030412732165123024151 0ustar eugeneeugenepackage test.testnames; import org.testng.annotations.Test; public class TestNamesFeature { @Test public void sampleOutputTest1() {} @Test public void sampleOutputTest2() {} } testng-6.9.12/src/test/java/test/testnames/TestNamesTest.java0000644000175000017500000000154512732165123023505 0ustar eugeneeugenepackage test.testnames; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.Collections; public class TestNamesTest extends SimpleBaseTest { @Test public void checkWithoutChildSuites() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.setTestNames(Collections.singletonList("testGroup2")); tng.setTestSuites(Collections.singletonList(getPathToResource("testnames/upstream-suite.xml"))); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getFailedTests().size(), 0); Assert.assertEquals(tla.getPassedTests().size(), 1); Assert.assertEquals(tla.getPassedTests().get(0).getMethod().getMethodName(), "sampleOutputTest2"); } } testng-6.9.12/src/test/java/test/junit/0000755000175000017500000000000012732165123017220 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/junit/Suite4.java0000644000175000017500000000043512732165123021242 0ustar eugeneeugenepackage test.junit; import junit.framework.Test; import junit.framework.TestSuite; public class Suite4 { public static Test suite() { TestSuite suite = new TestSuite("Suite4"); suite.addTestSuite(TestAe.class); suite.addTestSuite(TestAf.class); return suite; } } testng-6.9.12/src/test/java/test/junit/Suite1.java0000644000175000017500000000052012732165123021232 0ustar eugeneeugenepackage test.junit; import junit.framework.Test; import junit.framework.TestSuite; public class Suite1 { public Suite1(String s) { // dummy } public static Test suite() { TestSuite suite = new TestSuite("JUnitSuite1"); suite.addTestSuite(TestAa.class); suite.addTestSuite(TestAb.class); return suite; } } testng-6.9.12/src/test/java/test/junit/BaseTest.java0000644000175000017500000000140112732165123021571 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; /** * Base JUnit test case to verify TestNG handles * TestCase hierarchies properly. * * @author mperham */ public abstract class BaseTest extends TestCase { private static int setUpInvokeCount = 0; private static int tearDownInvokeCount = 0; public BaseTest(String name) { super(name); } @Override protected void setUp() throws Exception { setUpInvokeCount++; } @Override protected void tearDown() throws Exception { tearDownInvokeCount++; } public abstract void testA(); public abstract void testB(); public static int getSetUpInvokeCount() { return setUpInvokeCount; } public static int getTearDownInvokeCount() { return tearDownInvokeCount; } } testng-6.9.12/src/test/java/test/junit/testsetup/0000755000175000017500000000000012732165123021260 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/junit/testsetup/LoggingTestSuite.java0000644000175000017500000000066312732165123025370 0ustar eugeneeugenepackage test.junit.testsetup; import junit.framework.Test; import junit.framework.TestResult; import junit.framework.TestSuite; public class LoggingTestSuite extends TestSuite { public LoggingTestSuite( String string ) { super( string ); } @Override public void run( TestResult result ) { super.run( result ); } @Override public void runTest( Test test, TestResult result ) { super.runTest( test, result ); } } testng-6.9.12/src/test/java/test/junit/testsetup/ATest.java0000644000175000017500000000036212732165123023144 0ustar eugeneeugenepackage test.junit.testsetup; import junit.framework.TestCase; public class ATest extends TestCase { public void testIt() { System.out.println("A.testIt()"); Data d = TestSuiteContainerWrapper.getData(); assertEquals(3,d.i); } } testng-6.9.12/src/test/java/test/junit/testsetup/Data.java0000644000175000017500000000011012732165123022764 0ustar eugeneeugenepackage test.junit.testsetup; public class Data { public int i = 3; } testng-6.9.12/src/test/java/test/junit/testsetup/LayerATestSuite.java0000644000175000017500000000055612732165123025160 0ustar eugeneeugenepackage test.junit.testsetup; import junit.framework.Test; import junit.framework.TestSuite; public class LayerATestSuite { public static Test suite() { TestSuite suite = new TestSuite( "Layer A Test Suite" ); suite.addTestSuite( ATest.class ); TestSuiteContainerWrapper wrapper = new TestSuiteContainerWrapper(suite, Data.class); return wrapper; } } testng-6.9.12/src/test/java/test/junit/testsetup/TestSuiteContainerWrapper.java0000644000175000017500000000161112732165123027257 0ustar eugeneeugenepackage test.junit.testsetup; import junit.extensions.TestSetup; import junit.framework.TestSuite; public class TestSuiteContainerWrapper extends TestSetup { private static Data INSTANCE = null; private static TestSuite _test = null; private static Class dataImpl = null; public TestSuiteContainerWrapper(TestSuite testSuite, Class dataImpl) { super(testSuite); _test = testSuite; TestSuiteContainerWrapper.dataImpl = dataImpl; } public static Data getData() { return INSTANCE; } @Override protected void setUp() throws Exception { System.out.println("setup"); INSTANCE = (Data) dataImpl.newInstance(); } @Override protected void tearDown() throws Exception { System.out.println("teardown"); INSTANCE = null; System.out.println(_test.countTestCases() + " test cases defined by \"" + _test.getName() + "\" were executed."); } } testng-6.9.12/src/test/java/test/junit/testsetup/SmokeSuite.java0000644000175000017500000000077212732165123024221 0ustar eugeneeugenepackage test.junit.testsetup; import junit.framework.Test; import junit.framework.TestSuite; public class SmokeSuite extends LoggingTestSuite { public static void main( String[] args ) { junit.textui.TestRunner.run( suite() ); } public static Test suite() { TestSuite suite = new TestSuite( "Smoke Test Suite" ); suite.addTest(LayerATestSuite.suite()); return suite; } // public SmokeSuite() // { // this("SmokeSuite"); // } public SmokeSuite( String name ) { super( name ); } } testng-6.9.12/src/test/java/test/junit/TestAe.java0000644000175000017500000000020012732165123021240 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class TestAe extends TestCase { public void testAe1() { } } testng-6.9.12/src/test/java/test/junit/JUnitConstructorTest.java0000644000175000017500000000203712732165123024224 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; /** * Test that the correct number of constructors is called * * Created on Aug 9, 2005 * @author cbeust */ public class JUnitConstructorTest extends TestCase { private static int m_constructorCount = 0; private static int m_createCount = 0; private static int m_queryCount = 0; public JUnitConstructorTest(/*String string */) { // super(string); // setName(string); ppp("CONSTRUCTING"); m_constructorCount++; } // public void test1() { // ppp("TEST1"); // } // // public void test2() { // ppp("TEST2"); // } public void testCreate() { ppp("TEST_CREATE"); m_createCount++; } public void testQuery() { ppp("TEST_QUERY"); m_queryCount++; } @Override public void tearDown() { assertEquals(3, m_constructorCount); assertTrue((1 == m_createCount && 0 == m_queryCount) || (0 == m_createCount && 1 == m_queryCount)); } private static void ppp(String s) { System.out.println("[JUnitHierarchyTest] " + s); } }testng-6.9.12/src/test/java/test/junit/TestAc.java0000644000175000017500000000020012732165123021236 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class TestAc extends TestCase { public void testAc1() { } } testng-6.9.12/src/test/java/test/junit/Suite2.java0000644000175000017500000000050012732165123021231 0ustar eugeneeugenepackage test.junit; import junit.framework.Test; import junit.framework.TestSuite; public class Suite2 { public static Test suite() { TestSuite suite = new TestSuite("Suite2"); suite.addTestSuite(TestAc.class); suite.addTestSuite(TestAd.class); suite.addTest(Suite3.suite()); return suite; } } testng-6.9.12/src/test/java/test/junit/MainSuite.java0000644000175000017500000000050312732165123021757 0ustar eugeneeugenepackage test.junit; import junit.framework.Test; import junit.framework.TestSuite; public class MainSuite { public static Test suite() { TestSuite suite = new TestSuite("MainSuite"); suite.addTest(Suite1.suite()); suite.addTest(Suite2.suite()); suite.addTest(Suite3.suite()); return suite; } } testng-6.9.12/src/test/java/test/junit/Suite3.java0000644000175000017500000000036412732165123021242 0ustar eugeneeugenepackage test.junit; import junit.framework.Test; import junit.framework.TestSuite; public class Suite3 { public static Test suite() { TestSuite suite = new TestSuite("Suite3"); suite.addTest(Suite4.suite()); return suite; } } testng-6.9.12/src/test/java/test/junit/TestAa.java0000644000175000017500000000020012732165123021234 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class TestAa extends TestCase { public void testAa1() { } } testng-6.9.12/src/test/java/test/junit/JUnitEmptyTest.java0000644000175000017500000000051412732165123022773 0ustar eugeneeugenepackage test.junit; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; public class JUnitEmptyTest extends TestCase { public JUnitEmptyTest(String name) { super(name); } public static Test suite() { TestSuite s = new TestSuite(JUnitEmptyTest.class); return s; } }testng-6.9.12/src/test/java/test/junit/SetUpExceptionSampleTest.java0000644000175000017500000000045712732165123025012 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class SetUpExceptionSampleTest extends TestCase { @Override protected void setUp() throws Exception { throw new RuntimeException(); } public void testM1() { } @Override protected void tearDown() throws Exception { } }testng-6.9.12/src/test/java/test/junit/TestAd.java0000644000175000017500000000020012732165123021237 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class TestAd extends TestCase { public void testAd1() { } } testng-6.9.12/src/test/java/test/junit/TestAf.java0000644000175000017500000000020012732165123021241 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class TestAf extends TestCase { public void testAf1() { } } testng-6.9.12/src/test/java/test/junit/TestAb.java0000644000175000017500000000020012732165123021235 0ustar eugeneeugenepackage test.junit; import junit.framework.TestCase; public class TestAb extends TestCase { public void testAb1() { } } testng-6.9.12/src/test/java/test/junit/SetNameTest.java0000644000175000017500000000131212732165123022254 0ustar eugeneeugenepackage test.junit; import org.testng.Assert; import java.io.Serializable; import junit.framework.TestCase; public class SetNameTest extends TestCase implements Serializable { public static int m_ctorCount = 0; public SetNameTest() { ppp("CTOR"); m_ctorCount++; } @Override public void setName(String name) { ppp("SETNAME " + name); super.setName(name); } public void testFoo() { Assert.assertEquals("testFoo", getName()); ppp("FOO"); } public void testBar() { Assert.assertEquals("testBar", getName()); ppp("BAR"); } private void ppp(String string) { if (false) { System.out.println("[FooBarTest#" + hashCode() + "] " + string); } } }testng-6.9.12/src/test/java/test/junit/SetUpExceptionTest.java0000644000175000017500000000107212732165123023642 0ustar eugeneeugenepackage test.junit; import org.testng.annotations.Test; public class SetUpExceptionTest extends test.BaseTest { @Test public void setUpFailingShouldCauseMethodsToBeSkipped() { addClass("test.junit.SetUpExceptionSampleTest"); setJUnit(true); run(); String[] passed = { }; String[] failed = { "setUp" }; String[] skipped = { "testM1", "tearDown" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/abstractconfmethod/0000755000175000017500000000000012732165123021741 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/abstractconfmethod/C.java0000644000175000017500000000050612732165123022767 0ustar eugeneeugenepackage test.abstractconfmethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class C extends B { @Override @BeforeMethod public void testSetup() {} @Test(description="Test depends on a config method that has implements an abstract methods") public void test1() {} } testng-6.9.12/src/test/java/test/abstractconfmethod/B.java0000644000175000017500000000037012732165123022765 0ustar eugeneeugenepackage test.abstractconfmethod; import org.testng.annotations.BeforeMethod; import test.abstractconfmethod.foo.A; public abstract class B extends A { @BeforeMethod(dependsOnMethods = {"testSetup"}) public void doSomethingInMiddle() {} } testng-6.9.12/src/test/java/test/abstractconfmethod/foo/0000755000175000017500000000000012732165123022524 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/abstractconfmethod/foo/A.java0000644000175000017500000000014712732165123023551 0ustar eugeneeugenepackage test.abstractconfmethod.foo; public abstract class A { public abstract void testSetup(); } testng-6.9.12/src/test/java/test/triangle/0000755000175000017500000000000012732165123017674 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/triangle/Child2.java0000644000175000017500000000036012732165123021643 0ustar eugeneeugenepackage test.triangle; import org.testng.annotations.Test; /** * This class * * @author cbeust */ public class Child2 extends Base { @Test public void child2() { assert m_isInitialized : "Wasn't initialized correctly"; } } testng-6.9.12/src/test/java/test/triangle/Child1.java0000644000175000017500000000062712732165123021650 0ustar eugeneeugenepackage test.triangle; import org.testng.annotations.Test; /** * This class * * @author cbeust */ public class Child1 extends Base { @Test public void child1() { assert m_isInitialized : "Wasn't initialized correctly " + hashCode() + " " + getClass(); } @Test public void child1a() { assert m_isInitialized : "Wasn't initialized correctly " + hashCode() + " " + getClass(); } } testng-6.9.12/src/test/java/test/triangle/CountCalls.java0000644000175000017500000000046512732165123022613 0ustar eugeneeugenepackage test.triangle; /** * count the number of times something is called * used to check whether certain methods have been called */ public class CountCalls { static int numCalls = 0; public static void incr () { numCalls++; } public static int getNumCalls() { return numCalls; } } testng-6.9.12/src/test/java/test/triangle/CheckCount.java0000644000175000017500000000237512732165123022574 0ustar eugeneeugenepackage test.triangle; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * this test checks the CountCalls's static counter to see if we got the * expected number of calls */ public class CheckCount { @Test(parameters = { "expected-calls" }) public void testCheckCountDeprecated(String expectedCalls){ try { // System.out.println("\n\ntestCheckCount time = " + System.currentTimeMillis()); int i = Integer.valueOf(expectedCalls); int numCalls = CountCalls.getNumCalls(); assert (numCalls == i) : "Count calls expected " + i + " but got " + numCalls; } catch (NumberFormatException nfe) { assert false : "CountCalls needs an expected-calls numeric parameter"; } } @Parameters({ "expected-calls" }) @Test public void testCheckCount(String expectedCalls){ try { // System.out.println("\n\ntestCheckCount time = " + System.currentTimeMillis()); int i = Integer.valueOf(expectedCalls); int numCalls = CountCalls.getNumCalls(); assert (numCalls == i) : "Count calls expected " + i + " but got " + numCalls; } catch (NumberFormatException nfe) { assert false : "CountCalls needs an expected-calls numeric parameter"; } } }testng-6.9.12/src/test/java/test/triangle/Base.java0000644000175000017500000000111512732165123021407 0ustar eugeneeugenepackage test.triangle; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeSuite; /** * This class * * @author cbeust */ public class Base { protected boolean m_isInitialized = false; @BeforeSuite public void beforeSuite() { CountCalls.numCalls = 0; } @BeforeClass public void initBeforeTestClass() { m_isInitialized = true; } @AfterClass public void postAfterTestClass() { CountCalls.incr(); } private static void ppp(String s) { System.out.println("[Base] " + s); } } testng-6.9.12/src/test/java/test/testng37/0000755000175000017500000000000012732165123017545 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng37/NullParameterTest.java0000644000175000017500000000071112732165123024022 0ustar eugeneeugenepackage test.testng37; import org.testng.Assert; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * This class/interface */ public class NullParameterTest { @Test @Parameters({"notnull", "nullvalue"}) public void nullParameter(String notNull, int mustBeNull) { Assert.assertNotNull(notNull, "not null parameter expected"); Assert.assertNull(mustBeNull, "null parameter expected"); } } testng-6.9.12/src/test/java/test/testng37/testng-37.xml0000644000175000017500000000050512732165123022022 0ustar eugeneeugene testng-6.9.12/src/test/java/test/EclipseTest.java0000644000175000017500000000076412732165123021165 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.ITestContext; import org.testng.annotations.Test; /** * Make sure that these test pass when run by the Eclipse plug-in. * * @author Cedric Beust * */ public class EclipseTest { @Test public void xmlFileShouldBeRunAtItsPlaceAndNotCopied(ITestContext ctx) { String fileName = ctx.getSuite().getXmlSuite().getFileName().replace("\\", "/"); Assert.assertTrue(fileName.contains("src/test/resources")); } } testng-6.9.12/src/test/java/test/CheckSuitesInitializationTest.java0000644000175000017500000000242112732165123024713 0ustar eugeneeugenepackage test; import java.util.Arrays; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; /** * Check for a bug in how relative paths in suite files were being handled. * * All paths were being resolved using the initial suite's location and not * that of the current suite being parsed/processed. * * This test checks that TestNG can handle cases where we have the following set of * files (all linked using relative paths): * * - parent-suite -> [child-suite-1, children/child-suite-3] * - children/child-suite-3 -> [../child-suite-2, child-suite-4, morechildren/child-suite-5] * * Check the checksuitesinitialization folder under test resources * * @author Nalin Makar */ public class CheckSuitesInitializationTest extends SimpleBaseTest { /** * Child suites and tests within different suites have same names */ @Test public void check() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); String testngXmlPath = getPathToResource("checksuitesinitialization/parent-suite.xml"); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 4); } } testng-6.9.12/src/test/java/test/mustache/0000755000175000017500000000000012732165123017700 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/mustache/MustacheTest.java0000644000175000017500000000537712732165123023170 0ustar eugeneeugenepackage test.mustache; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.collections.Maps; import org.testng.mustache.Mustache; @Test public class MustacheTest { public static class Person { public String name; public Person(String n) { name = n; } } public static class Age { public int age; public Age(int a) { this.age = a; } } private static final List PEOPLE = new ArrayList<>( Arrays.asList(new Person("Carl"), new Person("Christopher"))); private static final List AGES = new ArrayList<>( Arrays.asList(new Age(42), new Age(43))); @DataProvider public Object[][] dp() { return new Object[][] { // Simple new Object[] { create("one", "ello", "two", "orld"), "H{{one}} W{{two}}", "Hello World" }, // Null condition new Object[] { Collections.emptyMap(), "E{{#foo}}xxx{{/foo}}lephant", "Elephant" }, // Null condition with new line new Object[] { Collections.emptyMap(), "Hello\n{{#foo}}@\n{{/foo}}World", "Hello\nWorld" }, // Simple scope new Object[] { create("person", new Person("John"), "day", "Monday"), "Hello {{#person}}{{name}}{{/person}}, {{day}}", "Hello John, Monday" }, // Scope with shadowing new Object[] { create("person", new Person("John"), "name", "Carl"), "Hello {{#person}}{{name}}{{/person}}, {{name}}", "Hello John, Carl" }, // Test iteration new Object[] { create("people", PEOPLE), "People:@{{#people}}-{{/people}}!", "People:@--!", }, // Nested scopes new Object[] { create("people", PEOPLE, "ages", AGES), ":@{{#people}}{{name}}{{#ages}}{{age}}{{/ages}}@{{/people}}!_", ":@Carl4243@Christopher4243@!_", }, }; } private Map create(Object... objects) { Map result = Maps.newHashMap(); for (int i = 0; i < objects.length; i += 2) { result.put((String) objects[i], objects[i + 1]); } return result; } @Test(dataProvider = "dp") public void runTest(Map model, String template, String expected) throws IOException { // InputStream is = new StringInputStream(template); Assert.assertEquals(new Mustache().run(template, model), expected); } } testng-6.9.12/src/test/java/test/junit4/0000755000175000017500000000000012732165123017304 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/junit4/InheritedTest.java0000644000175000017500000000015012732165123022716 0ustar eugeneeugenepackage test.junit4; /** * * @author lukas */ public class InheritedTest extends JUnit4Sample1 { } testng-6.9.12/src/test/java/test/junit4/JUnit4SampleSuite.java0000644000175000017500000000064312732165123023443 0ustar eugeneeugenepackage test.junit4; import org.junit.runner.RunWith; import org.junit.runners.Suite; /** * * @author lukas */ @RunWith(Suite.class) @Suite.SuiteClasses({ JUnit4Sample1.class, JUnit4Sample2.class }) public class JUnit4SampleSuite { public static final String[] EXPECTED = {"t1", "t2", "t4"}; public static final String[] SKIPPED = {"t3", "ta"}; public static final String[] FAILED = {"tf"}; } testng-6.9.12/src/test/java/test/junit4/JUnit4ParameterizedTest.java0000644000175000017500000000223412732165123024642 0ustar eugeneeugenepackage test.junit4; import java.util.Arrays; import java.util.Collection; import org.junit.Assert; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class JUnit4ParameterizedTest { public static final String[] EXPECTED = {"t2[0]", "t2[1]", "t4[0]"}; public static final String[] SKIPPED = {"t3[0]", "t3[1]", "ta[0]", "ta[1]"}; public static final String[] FAILED = {"t4[1]", "tf[0]", "tf[1]"}; private int param; @Parameters public static Collection data() { return Arrays.asList(new Object[][] {{1}, {5}}); } public JUnit4ParameterizedTest(int param) { this.param = param; } @Test public void t2() { } @Test @Ignore public void t3() { } @Test public void t4() { if (param == 5) { Assert.fail("a test"); } } @Test public void tf() { Assert.fail("a test"); } @Test public void ta() { Assume.assumeTrue(false); } } testng-6.9.12/src/test/java/test/junit4/JUnit4Child.java0000644000175000017500000000035112732165123022227 0ustar eugeneeugenepackage test.junit4; import org.junit.runners.Suite; /** * * @author lukas */ @Suite.SuiteClasses({JUnit4Sample1.class}) public class JUnit4Child extends JUnit4SampleSuite { public static final String[] EXPECTED = {"t1"}; } testng-6.9.12/src/test/java/test/junit4/BeforeClassJUnit4Sample.java0000644000175000017500000000071712732165123024544 0ustar eugeneeugenepackage test.junit4; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class BeforeClassJUnit4Sample { @BeforeClass public static void before() { throw new IllegalArgumentException("before failed"); } @AfterClass public static void after() { //throw new IllegalArgumentException("after failed"); } @Test public void myTest() { System.out.println("yay!"); } } testng-6.9.12/src/test/java/test/junit4/ClassRuleJUnit4Sample.java0000644000175000017500000000111012732165123024235 0ustar eugeneeugenepackage test.junit4; import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.ExternalResource; public class ClassRuleJUnit4Sample { @ClassRule public static ExternalResource resource = new ExternalResource() { @Override protected void before() throws Throwable { throw new IllegalArgumentException("before"); } @Override protected void after() { throw new IllegalArgumentException("after"); } }; @Test public void myTest() { System.out.println("yay!"); } } testng-6.9.12/src/test/java/test/junit4/JUnit4Sample2.java0000644000175000017500000000115712732165123022514 0ustar eugeneeugenepackage test.junit4; import org.junit.Assert; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; /** * * @author lukas */ public class JUnit4Sample2 { public static final String[] EXPECTED = {"t2", "t4"}; public static final String[] SKIPPED = {"t3", "ta"}; public static final String[] FAILED = {"tf"}; @Test public void t2() { } @Test @Ignore public void t3() { } @Test public void t4() { } @Test public void tf() { Assert.fail("a test"); } @Test public void ta() { Assume.assumeTrue(false); } } testng-6.9.12/src/test/java/test/junit4/JUnit4Sample1.java0000644000175000017500000000022212732165123022503 0ustar eugeneeugenepackage test.junit4; import org.junit.Test; /** * * @author lukas */ public class JUnit4Sample1 { @Test public void t1() { } } testng-6.9.12/src/test/java/test/bug92/0000755000175000017500000000000012732165123017017 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/bug92/TestAlpha.java0000644000175000017500000000025112732165123021545 0ustar eugeneeugenepackage test.bug92; import org.testng.annotations.Test; public class TestAlpha extends TestBase { @Test public void test1() { } @Test public void test2() { } }testng-6.9.12/src/test/java/test/bug92/Bug92Test.java0000644000175000017500000000147612732165123021422 0ustar eugeneeugenepackage test.bug92; import java.util.Arrays; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; public class Bug92Test extends SimpleBaseTest { @Test(description = "Fix for https://github.com/cbeust/testng/issues/92") public void BeforeTestShouldRunOnce() { XmlSuite s = createXmlSuite("Bug92"); XmlTest t = createXmlTest(s, "Bug92 test", TestAlpha.class.getName(), TestBravo.class.getName()); s.setTests(Arrays.asList(t)); TestNG tng = create(); tng.setXmlSuites(Arrays.asList(s)); TestBase.beforeTestCount = 0; TestBase.beforeTestAlwaysCount = 0; tng.run(); Assert.assertEquals(TestBase.beforeTestCount, 1); Assert.assertEquals(TestBase.beforeTestAlwaysCount, 1); } } testng-6.9.12/src/test/java/test/bug92/TestBravo.java0000644000175000017500000000025112732165123021571 0ustar eugeneeugenepackage test.bug92; import org.testng.annotations.Test; public class TestBravo extends TestBase { @Test public void test1() { } @Test public void test2() { } }testng-6.9.12/src/test/java/test/bug92/TestBase.java0000644000175000017500000000052512732165123021376 0ustar eugeneeugenepackage test.bug92; import org.testng.annotations.BeforeTest; public class TestBase { static int beforeTestCount = 0; static int beforeTestAlwaysCount = 0; @BeforeTest public void baseTestBeforeTest() { beforeTestCount++; } @BeforeTest(alwaysRun = true) public void baseTestBeforeTestAlways() { beforeTestAlwaysCount++; } }testng-6.9.12/src/test/java/test/FileStringBufferTest.java0000644000175000017500000000114712732165123022775 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; import org.testng.reporters.FileStringBuffer; public class FileStringBufferTest { @Test public void basic() { { FileStringBuffer fsb = new FileStringBuffer(5); String s = "0123456789"; String s3 = s + s + s; fsb.append(s3); // Assert.assertEquals(s3, fsb.toString()); } { FileStringBuffer fsb = new FileStringBuffer(5); String s = "0123456789"; String s3 = s + s + s; fsb.append(s); fsb.append(s); fsb.append(s); // Assert.assertEquals(s3, fsb.toString()); } } } testng-6.9.12/src/test/java/test/testng317/0000755000175000017500000000000012732165123017626 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng317/VerifyTest.java0000755000175000017500000000117012732165123022577 0ustar eugeneeugenepackage test.testng317; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.ArrayList; import java.util.List; public class VerifyTest extends SimpleBaseTest { static List m_methods = new ArrayList<>(); @BeforeMethod public void before() { m_methods = new ArrayList<>(); } @Test public void verify() { TestNG tng = create(); tng.setTestClasses(new Class[] { test.testng317.ClassB.class, test.testng317.ClassA.class }); tng.run(); System.out.println("Methods:" + m_methods.size()); } } testng-6.9.12/src/test/java/test/testng317/ClassA.java0000755000175000017500000000223212732165123021641 0ustar eugeneeugenepackage test.testng317; import org.testng.annotations.Test; public class ClassA { @Test public void sameNameA(){ printMethod(); } @Test (dependsOnMethods="sameNameA") public void uniqueNameB(){ printMethod(); } @Test (dependsOnMethods="uniqueNameB") public void uniqueNameC(){ printMethod(); } @Test (dependsOnMethods="uniqueNameC") public void uniqueNameD(){ printMethod(); } @Test (dependsOnMethods="uniqueNameD") public void sameNameE(){ printMethod(); } @Test (dependsOnMethods="sameNameE") public void sameNameF(){ printMethod(); } @Test (dependsOnMethods="sameNameF") public void sameNameG(){ printMethod(); } @Test (dependsOnMethods="sameNameG") public void sameNameH(){ printMethod(); } public void nullTest(){ printMethod(); } protected void printMethod() { StackTraceElement[] sTrace = new Exception().getStackTrace(); String className = sTrace[0].getClassName(); String methodName = sTrace[1].getMethodName(); System.out.printf("*********** executing --- %s %s\n", className, methodName); VerifyTest.m_methods.add(className + "." + methodName); } } testng-6.9.12/src/test/java/test/testng317/ClassB.java0000755000175000017500000000162612732165123021650 0ustar eugeneeugenepackage test.testng317; import org.testng.annotations.Test; public class ClassB { @Test public void sameNameAA(){ printMethod(); } @Test (dependsOnMethods="sameNameAA") public void uniqueNameBB(){ printMethod(); } @Test (dependsOnMethods="uniqueNameBB") public void uniqueNameCC(){ printMethod(); } @Test (dependsOnMethods="uniqueNameCC") public void uniqueNameDD(){ printMethod(); } @Test (dependsOnMethods="uniqueNameDD") public void sameNameE(){ printMethod(); } public void nullTest(){ printMethod(); } protected void printMethod() { StackTraceElement[] sTrace = new Exception().getStackTrace(); String className = sTrace[0].getClassName(); String methodName = sTrace[1].getMethodName(); System.out.printf("*********** executing --- %s %s\n", className, methodName); VerifyTest.m_methods.add(className + "." + methodName); } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/0000755000175000017500000000000012732165123023526 5ustar eugeneeugene././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootroottestng-6.9.12/src/test/java/test/configurationfailurepolicy/FactoryClassWithFailedBeforeMethodAndMultipleInvocations.javatestng-6.9.12/src/test/java/test/configurationfailurepolicy/FactoryClassWithFailedBeforeMethodAndMul0000644000175000017500000000075312732165123033401 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.Factory; public class FactoryClassWithFailedBeforeMethodAndMultipleInvocations extends ClassWithFailedBeforeMethodAndMultipleInvocations { @Factory public Object[] createTests() { Object[] instances = new Object[2]; instances[0] = new FactoryClassWithFailedBeforeMethodAndMultipleInvocations(); instances[1] = new FactoryClassWithFailedBeforeMethodAndMultipleInvocations(); return instances; } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithFailedBeforeClassMethod.java0000644000175000017500000000063612732165123032656 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ClassWithFailedBeforeClassMethod { @BeforeClass public void setupClassFails() { throw new RuntimeException( "setup class fail" ); } @BeforeMethod public void setupMethod() { } @Test public void test1() { } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/ExtendsClassWithFailedBeforeMethod.java0000644000175000017500000000046012732165123033216 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ExtendsClassWithFailedBeforeMethod extends ClassWithFailedBeforeMethod { @BeforeMethod public void setupExtension() { } @Test public void test2() { } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithSkippingBeforeMethod.java0000644000175000017500000000071212732165123032263 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.SkipException; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ClassWithSkippingBeforeMethod { private int invocations = 0; @BeforeMethod public void beforeMethod() { invocations++; if (invocations ==2) { throw new SkipException("skipping"); } } @Test public void test1() {} @Test public void test2() {} } ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootroottestng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithFailedBeforeMethodAndMultipleInvocations.javatestng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithFailedBeforeMethodAndMultipleIn0000644000175000017500000000124612732165123033374 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ClassWithFailedBeforeMethodAndMultipleInvocations { @BeforeMethod public void setupShouldFail() { throw new RuntimeException("Failing in setUp"); } @DataProvider( name = "data.provider" ) public Object[][] dataProvider() { return new Object[][] { new Object[] { "data1" }, new Object[] { "data2" } }; } @Test( dataProvider = "data.provider" ) public void test1( String s ) { } @Test( invocationCount = 2 ) public void test2() { } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/FactoryClassWithFailedBeforeMethod.java0000644000175000017500000000062312732165123033214 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.Factory; public class FactoryClassWithFailedBeforeMethod extends ClassWithFailedBeforeMethod { @Factory public Object[] createTests() { Object[] instances = new Object[2]; instances[0] = new FactoryClassWithFailedBeforeMethod(); instances[1] = new FactoryClassWithFailedBeforeMethod(); return instances; } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootroottestng-6.9.12/src/test/java/test/configurationfailurepolicy/FactoryClassWithFailedBeforeClassMethod.javatestng-6.9.12/src/test/java/test/configurationfailurepolicy/FactoryClassWithFailedBeforeClassMethod.0000644000175000017500000000064712732165123033346 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.Factory; public class FactoryClassWithFailedBeforeClassMethod extends ClassWithFailedBeforeClassMethod { @Factory public Object[] createTests() { Object[] instances = new Object[2]; instances[0] = new FactoryClassWithFailedBeforeClassMethod(); instances[1] = new FactoryClassWithFailedBeforeClassMethod(); return instances; } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootroottestng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithFailedBeforeMethodAndMultipleTests.javatestng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithFailedBeforeMethodAndMultipleTe0000644000175000017500000000055712732165123033402 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ClassWithFailedBeforeMethodAndMultipleTests { @BeforeMethod public void setupShouldFail() { throw new RuntimeException("Failing in setUp"); } @Test public void test1() { } @Test public void test2() { } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/ClassWithFailedBeforeMethod.java0000644000175000017500000000047112732165123031665 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ClassWithFailedBeforeMethod { @BeforeMethod public void setupShouldFail() { throw new RuntimeException("Failing in setUp"); } @Test public void test1() { } } testng-6.9.12/src/test/java/test/configurationfailurepolicy/FailurePolicyTest.java0000644000175000017500000001103212732165123027775 0ustar eugeneeugenepackage test.configurationfailurepolicy; import static org.testng.Assert.assertEquals; import org.testng.ITestContext; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import testhelper.OutputDirectoryPatch; public class FailurePolicyTest { // only if this is run from an xml file that sets this on the suite @BeforeClass(enabled=false) public void setupClass( ITestContext testContext) { assertEquals(testContext.getSuite().getXmlSuite().getConfigFailurePolicy(), XmlSuite.FailurePolicy.CONTINUE); } @DataProvider( name="dp" ) public Object[][] getData() { Object[][] data = new Object[][] { // params - confFail, confSkip, skipedTests new Object[] { new Class[] { ClassWithFailedBeforeClassMethod.class }, 1, 1, 1 }, new Object[] { new Class[] { ClassWithFailedBeforeMethodAndMultipleTests.class }, 2, 0, 2 }, new Object[] { new Class[] { ClassWithFailedBeforeMethodAndMultipleInvocations.class }, 4, 0, 4 }, new Object[] { new Class[] { ExtendsClassWithFailedBeforeMethod.class }, 2, 2, 2 }, new Object[] { new Class[] { ClassWithFailedBeforeClassMethod.class }, 1, 1, 1 }, new Object[] { new Class[] { ExtendsClassWithFailedBeforeClassMethod.class }, 1, 2, 2 }, new Object[] { new Class[] { ClassWithFailedBeforeClassMethod.class, ExtendsClassWithFailedBeforeClassMethod.class }, 2, 3, 3 }, new Object[] { new Class[] { ClassWithSkippingBeforeMethod.class }, 0, 1, 1 }, new Object[] { new Class[] { FactoryClassWithFailedBeforeMethod.class }, 2, 0, 2 }, new Object[] { new Class[] { FactoryClassWithFailedBeforeMethodAndMultipleInvocations.class }, 8, 0, 8 }, new Object[] { new Class[] { FactoryClassWithFailedBeforeClassMethod.class }, 2, 2, 2 }, }; return data; } @Test( dataProvider = "dp" ) public void confFailureTest(Class[] classesUnderTest, int configurationFailures, int configurationSkips, int skippedTests) { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = new TestNG(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(classesUnderTest); testng.addListener(tla); testng.setVerbose(0); testng.setConfigFailurePolicy(XmlSuite.FailurePolicy.CONTINUE); testng.run(); verify(tla, configurationFailures, configurationSkips, skippedTests); } @Test public void commandLineTest_policyAsSkip() { String[] argv = new String[] { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-configfailurepolicy", "skip", "-testclass", "test.configurationfailurepolicy.ClassWithFailedBeforeMethodAndMultipleTests" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); verify(tla, 1, 1, 2); } @Test public void commandLineTest_policyAsContinue() { String[] argv = new String[] { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-configfailurepolicy", "continue", "-testclass", "test.configurationfailurepolicy.ClassWithFailedBeforeMethodAndMultipleTests" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); verify(tla, 2, 0, 2); } @Test public void commandLineTestWithXMLFile_policyAsSkip() { String[] argv = new String[] { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-configfailurepolicy", "skip", "src/test/resources/testng-configfailure.xml" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); verify(tla, 1, 1, 2); } @Test public void commandLineTestWithXMLFile_policyAsContinue() { String[] argv = new String[] { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-configfailurepolicy", "continue", "src/test/resources/testng-configfailure.xml" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); verify(tla, 2, 0, 2); } private void verify( TestListenerAdapter tla, int configurationFailures, int configurationSkips, int skippedTests ) { assertEquals(tla.getConfigurationFailures().size(), configurationFailures, "wrong number of configuration failures"); assertEquals(tla.getConfigurationSkips().size(), configurationSkips, "wrong number of configuration skips"); assertEquals(tla.getSkippedTests().size(), skippedTests, "wrong number of skipped tests"); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootroottestng-6.9.12/src/test/java/test/configurationfailurepolicy/ExtendsClassWithFailedBeforeClassMethod.javatestng-6.9.12/src/test/java/test/configurationfailurepolicy/ExtendsClassWithFailedBeforeClassMethod.0000644000175000017500000000043312732165123033342 0ustar eugeneeugenepackage test.configurationfailurepolicy; import org.testng.annotations.Test; public class ExtendsClassWithFailedBeforeClassMethod extends ClassWithFailedBeforeClassMethod { @Test public void test2() { // should be skipped, but BeforeClass method attempted again } } testng-6.9.12/src/test/java/test/JUnitTest1.java0000644000175000017500000000614712732165123020714 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import test.junit.SetNameTest; import test.sample.JUnitSample1; import test.sample.JUnitSample2; /** * This class * * @author Cedric Beust, May 5, 2004 * */ public class JUnitTest1 extends BaseTest { @BeforeMethod(dependsOnGroups = { "initTest"} ) public void initJUnitFlag() { getTest().setJUnit(true); } @Test public void methodsThatStartWithTest() { addClass("test.sample.JUnitSample1"); assert getTest().isJUnit(); run(); String[] passed = { JUnitSample1.EXPECTED1, JUnitSample1.EXPECTED2 }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void methodsWithSetup() { addClass("test.sample.JUnitSample2"); run(); String[] passed = { "testSample2ThatSetUpWasRun", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void testSuite() { addClass("test.sample.AllJUnitTests"); run(); String[] passed = { JUnitSample1.EXPECTED1, /*JUnitSample1.EXPECTED2,*/ JUnitSample2.EXPECTED, }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void testNewInstance() { addClass("test.sample.JUnitSample3"); run(); String[] passed = { "test1", "test2" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void setUpFailingShouldCauseMethodsToBeSkipped() { addClass("test.junit.SetUpExceptionSampleTest"); run(); String[] passed = { }; String[] failed = { "testM1"/*, "testM1", "tearDown"*/ }; String[] skipped = { /*"testM1", "tearDown"*/ }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void setNameShouldBeInvoked() { addClass("test.junit.SetNameTest"); SetNameTest.m_ctorCount = 0; run(); String[] passed = { "testFoo", "testBar", }; String[] failed = { }; String[] skipped = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); verifyTests("Failed", failed, getFailedTests()); Assert.assertEquals(SetNameTest.m_ctorCount, 2, "Expected 2 instances to be created, found " + SetNameTest.m_ctorCount); } public static void ppp(String s) { System.out.println("[JUnitTest1] " + s); } @Test public void testAbstract() { addClass("test.sample.JUnitSample4"); run(); String[] passed = { "testXY", "testXY", "testXY" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/objectfactory/0000755000175000017500000000000012732165123020725 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/objectfactory/LoggingObjectFactory.java0000644000175000017500000000103612732165123025635 0ustar eugeneeugenepackage test.objectfactory; import org.testng.internal.ObjectFactoryImpl; import java.lang.reflect.Constructor; /** * @author Hani Suleiman * Date: Mar 6, 2007 * Time: 3:53:28 PM */ public class LoggingObjectFactory extends ObjectFactoryImpl { /** * */ private static final long serialVersionUID = -395096650866727480L; public static int invoked; @Override public Object newInstance(Constructor constructor, Object... params) { invoked++; return super.newInstance(constructor, params); } } testng-6.9.12/src/test/java/test/objectfactory/BadMethodFactoryFactory.java0000644000175000017500000000044512732165123026302 0ustar eugeneeugenepackage test.objectfactory; import org.testng.annotations.ObjectFactory; /** * @author Hani Suleiman * Date: Mar 6, 2007 * Time: 5:03:19 PM */ public class BadMethodFactoryFactory { @ObjectFactory public Object create() { return new LoggingObjectFactory(); } } testng-6.9.12/src/test/java/test/objectfactory/CombinedTestAndObjectFactorySample.java0000644000175000017500000000210312732165123030410 0ustar eugeneeugenepackage test.objectfactory; import org.testng.Assert; import org.testng.IObjectFactory; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Test; import java.lang.reflect.Constructor; @SuppressWarnings("serial") public class CombinedTestAndObjectFactorySample implements IObjectFactory{ private boolean configured = false; @ObjectFactory public IObjectFactory create() { return new CombinedTestAndObjectFactorySample(); } @Test public void isConfigured() { Assert.assertTrue(configured, "Should have been configured by object factory"); } @Override @SuppressWarnings("unchecked") public Object newInstance(Constructor constructor, Object... params) { Object o; try { o = constructor.newInstance(params); } catch (Exception e) { throw new RuntimeException(e); } if (CombinedTestAndObjectFactorySample.class.equals(o.getClass())) { CombinedTestAndObjectFactorySample s = (CombinedTestAndObjectFactorySample) o; s.configured = true; } return o; } } testng-6.9.12/src/test/java/test/objectfactory/ClassObjectFactorySampleTest.java0000644000175000017500000000054412732165123027321 0ustar eugeneeugenepackage test.objectfactory; import org.testng.Assert; import org.testng.annotations.Test; public class ClassObjectFactorySampleTest { public static int m_n = 0; /** * Will be invoked with 42 by the factory. */ public ClassObjectFactorySampleTest(int n) { m_n = n; } @Test public void f() { Assert.assertEquals(42, m_n); } } testng-6.9.12/src/test/java/test/objectfactory/ObjectFactory2Test.java0000644000175000017500000000201212732165123025243 0ustar eugeneeugenepackage test.objectfactory; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.TestHelper; /** * Test IObjectFactory2, which is an object factory that receives just the Class in parameter. * * @author Cedric Beust */ public class ObjectFactory2Test { private void testFactory(boolean onSuite) { XmlSuite suite = TestHelper.createSuite(ClassObjectFactorySampleTest.class.getName(), "Test IObjectFactory2"); TestNG tng = TestHelper.createTestNG(suite); if (onSuite) suite.setObjectFactory(new ClassObjectFactory()); else tng.setObjectFactory(ClassObjectFactory.class); ClassObjectFactorySampleTest.m_n = 0; tng.run(); Assert.assertEquals(ClassObjectFactorySampleTest.m_n, 42); } @Test public void factoryOnSuiteShouldWork() { testFactory(true /* on suite object */); } @Test public void factoryOnTestNGShouldWork() { testFactory(false /* on TestNG object */); } } testng-6.9.12/src/test/java/test/objectfactory/CustomFactoryTest.java0000644000175000017500000000473612732165123025244 0ustar eugeneeugenepackage test.objectfactory; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import test.TestHelper; /** * @author Hani Suleiman Date: Mar 6, 2007 Time: 3:52:19 PM */ public class CustomFactoryTest { @Test public void setFactoryOnTestNG() { XmlSuite suite = TestHelper.createSuite("test.objectfactory.Simple", "objectfactory"); // suite.setObjectFactory(new LoggingObjectFactory()); TestNG tng = TestHelper.createTestNG(suite); tng.setObjectFactory(LoggingObjectFactory.class); tng.run(); assert LoggingObjectFactory.invoked == 1 : "Logging factory invoked " + LoggingObjectFactory.invoked + " times"; } @AfterMethod public void resetCount() { LoggingObjectFactory.invoked = 0; } @Test public void setFactoryOnSuite() { XmlSuite suite = TestHelper.createSuite("test.objectfactory.Simple", "objectfactory"); suite.setObjectFactory(new LoggingObjectFactory()); TestNG tng = TestHelper.createTestNG(suite); tng.run(); assert LoggingObjectFactory.invoked == 1 : "Logging factory invoked " + LoggingObjectFactory.invoked + " times"; } @Test(enabled = false, description = "This broke after I made the change to enable AbstractTest") public void setFactoryByAnnotation() { XmlSuite suite = TestHelper.createSuite("test.objectfactory.Simple", "objectfactory"); suite.getTests().get(0).getXmlClasses() .add(new XmlClass("test.objectfactory.MyFactoryFactory")); TestNG tng = TestHelper.createTestNG(suite); tng.run(); assert LoggingObjectFactory.invoked == 1 : "Logging factory invoked " + LoggingObjectFactory.invoked + " times"; } @Test public void factoryReceivesContext() { XmlSuite suite = TestHelper.createSuite("test.objectfactory.Simple", "objectfactory"); suite.getTests().get(0).getXmlClasses() .add(new XmlClass("test.objectfactory.ContextAwareFactoryFactory")); TestNG tng = TestHelper.createTestNG(suite); tng.run(); } @Test(expectedExceptions = TestNGException.class) public void setInvalidMethodFactoryByAnnotation() { XmlSuite suite = TestHelper.createSuite("test.objectfactory.Simple", "objectfactory"); suite.getTests().get(0).getXmlClasses() .add(new XmlClass("test.objectfactory.BadMethodFactoryFactory")); TestNG tng = TestHelper.createTestNG(suite); tng.run(); } } testng-6.9.12/src/test/java/test/objectfactory/ClassObjectFactory.java0000644000175000017500000000065312732165123025320 0ustar eugeneeugenepackage test.objectfactory; import org.testng.IObjectFactory2; import java.lang.reflect.Constructor; public class ClassObjectFactory implements IObjectFactory2 { @Override public Object newInstance(Class cls) { try { Constructor ctor = cls.getConstructors()[0]; return ctor.newInstance(new Object[] { 42 }); } catch(Exception ex) { ex.printStackTrace(); return null; } } } testng-6.9.12/src/test/java/test/objectfactory/MyFactoryFactory.java0000644000175000017500000000051012732165123025031 0ustar eugeneeugenepackage test.objectfactory; import org.testng.IObjectFactory; import org.testng.annotations.ObjectFactory; /** * @author Hani Suleiman * Date: Mar 6, 2007 * Time: 5:03:19 PM */ public class MyFactoryFactory { @ObjectFactory public IObjectFactory create() { return new LoggingObjectFactory(); } } testng-6.9.12/src/test/java/test/objectfactory/ContextAwareFactoryFactory.java0000644000175000017500000000071612732165123027060 0ustar eugeneeugenepackage test.objectfactory; import org.testng.IObjectFactory; import org.testng.ITestContext; import org.testng.annotations.ObjectFactory; import org.testng.internal.ObjectFactoryImpl; /** * @author Hani Suleiman * Date: Mar 8, 2007 * Time: 10:05:55 PM */ public class ContextAwareFactoryFactory { @ObjectFactory public IObjectFactory create(ITestContext context) { assert context != null; return new ObjectFactoryImpl(); } } testng-6.9.12/src/test/java/test/objectfactory/Simple.java0000644000175000017500000000033112732165123023016 0ustar eugeneeugenepackage test.objectfactory; import org.testng.annotations.Test; /** * @author Hani Suleiman * Date: Mar 6, 2007 * Time: 3:56:57 PM */ public class Simple { @Test public void dummy() { } } testng-6.9.12/src/test/java/test/objectfactory/CombinedTestAndObjectFactoryTest.java0000644000175000017500000000135012732165123030111 0ustar eugeneeugenepackage test.objectfactory; import org.testng.TestNG; import org.testng.annotations.Test; import test.BaseTest; public class CombinedTestAndObjectFactoryTest extends BaseTest { @Test void combinedTestAndObjectFactory() { addClass(CombinedTestAndObjectFactorySample.class.getName()); run(); verifyTests("Should have passed", new String[]{"isConfigured"}, getPassedTests()); verifyTests("Failures", new String[0], getFailedTests()); verifyTests("Skipped", new String[0], getSkippedTests()); } public static void main(String[] args) { TestNG tng = new TestNG(); tng.setTestClasses(new Class[] {CombinedTestAndObjectFactorySample.class}); tng.setVerbose(10); tng.run(); } } testng-6.9.12/src/test/java/test/enable/0000755000175000017500000000000012732165123017315 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/enable/C.java0000644000175000017500000000325012732165123020342 0ustar eugeneeugenepackage test.enable; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; @Test public class C { public void testC() {} @Test public void testC2() {} @Test(enabled = true) public void testC3() {} @Test(enabled = false) public void disabledC() {} @BeforeSuite public void beforeSuiteC() {} @BeforeSuite(enabled = true) public void beforeSuiteC2() {} @BeforeSuite(enabled = false) public void disabledBeforeSuiteC() {} @BeforeSuite(alwaysRun = false) public void beforeSuiteNoRunC() {} @BeforeSuite(enabled = true, alwaysRun = false) public void beforeSuiteNoRunC2() {} @BeforeSuite(enabled = false, alwaysRun = false) public void disabledBeforeSuiteNoRunC() {} @BeforeSuite(alwaysRun = true) public void beforeSuiteRunC() {} @BeforeSuite(enabled = true, alwaysRun = true) public void beforeSuiteRunC2() {} @BeforeSuite(enabled = false, alwaysRun = true) public void disabledBeforeSuiteRunC() {} @AfterSuite public void afterSuiteC() {} @AfterSuite(enabled = true) public void afterSuiteC2() {} @AfterSuite(enabled = false) public void disabledAfterSuiteC() {} @AfterSuite(alwaysRun = false) public void afterSuiteNoRunC() {} @AfterSuite(enabled = true, alwaysRun = false) public void afterSuiteNoRunC2() {} @AfterSuite(enabled = false, alwaysRun = false) public void disabledAfterSuiteNoRunC() {} @AfterSuite(alwaysRun = true) public void afterSuiteRunC() {} @AfterSuite(enabled = true, alwaysRun = true) public void afterSuiteRunC2() {} @AfterSuite(enabled = false, alwaysRun = true) public void disabledAfterSuiteRunC() {} } testng-6.9.12/src/test/java/test/enable/B.java0000644000175000017500000000331212732165123020340 0ustar eugeneeugenepackage test.enable; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; @Test(enabled = false) public class B { public void testB() {} @Test public void testB2() {} @Test(enabled = true) public void testB3() {} @Test(enabled = false) public void disabledB() {} @BeforeSuite(enabled = true) public void disabledBeforeSuiteB() {} @BeforeSuite public void disabledBeforeSuiteB2() {} @BeforeSuite(enabled = false) public void disabledBeforeSuiteB3() {} @BeforeSuite(alwaysRun = false) public void beforeSuiteNoRunB() {} @BeforeSuite(enabled = true, alwaysRun = false) public void beforeSuiteNoRunB2() {} @BeforeSuite(enabled = false, alwaysRun = false) public void disabledBeforeSuiteNoRunB() {} @BeforeSuite(alwaysRun = true) public void beforeSuiteRunB() {} @BeforeSuite(enabled = true, alwaysRun = true) public void beforeSuiteRunB2() {} @BeforeSuite(enabled = false, alwaysRun = true) public void disabledBeforeSuiteRunB() {} @AfterSuite public void afterSuiteB() {} @AfterSuite(enabled = true) public void afterSuiteB2() {} @AfterSuite(enabled = false) public void disabledAfterSuiteB() {} @AfterSuite(alwaysRun = false) public void afterSuiteNoRunB() {} @AfterSuite(enabled = true, alwaysRun = false) public void afterSuiteNoRunB2() {} @AfterSuite(enabled = false, alwaysRun = false) public void disabledAfterSuiteNoRunB() {} @AfterSuite(alwaysRun = true) public void afterSuiteRunB() {} @AfterSuite(enabled = true, alwaysRun = true) public void afterSuiteRunB2() {} @AfterSuite(enabled = false, alwaysRun = true) public void disabledAfterSuiteRunB() {} } testng-6.9.12/src/test/java/test/enable/Issue420SecondSample.java0000644000175000017500000000027412732165123023777 0ustar eugeneeugenepackage test.enable; import org.testng.annotations.Test; @Test public class Issue420SecondSample extends Issue420BaseTestCase { @Test public void verifySomethingSecondSample() {} } testng-6.9.12/src/test/java/test/enable/Issue420FirstSample.java0000644000175000017500000000031312732165123023645 0ustar eugeneeugenepackage test.enable; import org.testng.annotations.Test; @Test(enabled = false) public class Issue420FirstSample extends Issue420BaseTestCase { @Test public void verifySomethingFirstSample() {} } testng-6.9.12/src/test/java/test/enable/Issue420BaseTestCase.java0000644000175000017500000000070512732165123023727 0ustar eugeneeugenepackage test.enable; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public abstract class Issue420BaseTestCase { @BeforeSuite(alwaysRun = true) public static void alwaysBeforeSuite() {} @BeforeSuite(alwaysRun = false) public static void beforeSuite() {} @AfterSuite(alwaysRun = false) public static void afterSuite() {} @AfterSuite(alwaysRun = true) public static void alwaysAfterSuite() {} } testng-6.9.12/src/test/java/test/enable/A.java0000644000175000017500000000324212732165123020341 0ustar eugeneeugenepackage test.enable; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class A { public void testA() {} @Test public void testA2() {} @Test(enabled = true) public void testA3() {} @Test(enabled = false) public void disabledA() {} @BeforeSuite public void beforeSuiteA() {} @BeforeSuite(enabled = true) public void beforeSuiteA2() {} @BeforeSuite(enabled = false) public void disabledBeforeSuiteA() {} @BeforeSuite(alwaysRun = false) public void beforeSuiteNoRunA() {} @BeforeSuite(enabled = true, alwaysRun = false) public void beforeSuiteNoRunA2() {} @BeforeSuite(enabled = false, alwaysRun = false) public void disabledBeforeSuiteNoRunA() {} @BeforeSuite(alwaysRun = true) public void beforeSuiteRunA() {} @BeforeSuite(enabled = true, alwaysRun = true) public void beforeSuiteRunA2() {} @BeforeSuite(enabled = false, alwaysRun = true) public void disabledBeforeSuiteRunA() {} @AfterSuite public void afterSuiteA() {} @AfterSuite(enabled = true) public void afterSuiteA2() {} @AfterSuite(enabled = false) public void disabledAfterSuiteA() {} @AfterSuite(alwaysRun = false) public void afterSuiteNoRunA() {} @AfterSuite(enabled = true, alwaysRun = false) public void afterSuiteNoRunA2() {} @AfterSuite(enabled = false, alwaysRun = false) public void disabledAfterSuiteNoRunA() {} @AfterSuite(alwaysRun = true) public void afterSuiteRunA() {} @AfterSuite(enabled = true, alwaysRun = true) public void afterSuiteRunA2() {} @AfterSuite(enabled = false, alwaysRun = true) public void disabledAfterSuiteRunA() {} } testng-6.9.12/src/test/java/test/enable/InvokedMethodListener.java0000644000175000017500000000126312732165123024430 0ustar eugeneeugenepackage test.enable; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import org.testng.collections.Lists; import java.util.ArrayList; import java.util.List; public class InvokedMethodListener implements IInvokedMethodListener { private final List invokedMethods = new ArrayList<>(); @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { invokedMethods.add(method.getTestMethod().getMethodName()); } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } public List getInvokedMethods() { return invokedMethods; } } testng-6.9.12/src/test/java/test/enable/EnableTest.java0000644000175000017500000000327112732165123022211 0ustar eugeneeugenepackage test.enable; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; public class EnableTest extends SimpleBaseTest { @Test public void disabled_methods_should_not_be_run() { TestNG tng = create(A.class, B.class, C.class); InvokedMethodListener listener = new InvokedMethodListener(); tng.addListener(listener); tng.setPreserveOrder(true); tng.run(); assertThat(listener.getInvokedMethods()).containsExactly( "beforeSuiteA", "beforeSuiteA2", "beforeSuiteNoRunA", "beforeSuiteNoRunA2", "beforeSuiteRunA", "beforeSuiteRunA2", "beforeSuiteRunB", "beforeSuiteRunB2", "beforeSuiteC", "beforeSuiteC2", "beforeSuiteNoRunC", "beforeSuiteNoRunC2", "beforeSuiteRunC", "beforeSuiteRunC2", "testA2", "testA3", "testB2", "testB3", "testC", "testC2", "testC3", "afterSuiteA", "afterSuiteA2", "afterSuiteNoRunA", "afterSuiteNoRunA2", "afterSuiteRunA", "afterSuiteRunA2", "afterSuiteRunB", "afterSuiteRunB2", "afterSuiteC", "afterSuiteC2", "afterSuiteNoRunC", "afterSuiteNoRunC2", "afterSuiteRunC", "afterSuiteRunC2" ); } @Test(description = "https://github.com/cbeust/testng/issues/420") public void issue420() { TestNG tng = create(Issue420FirstSample.class, Issue420SecondSample.class); InvokedMethodListener listener = new InvokedMethodListener(); tng.addListener(listener); tng.run(); assertThat(listener.getInvokedMethods()).containsExactly( "alwaysBeforeSuite", "beforeSuite", "verifySomethingFirstSample", "verifySomethingSecondSample", "afterSuite", "alwaysAfterSuite" ); } } testng-6.9.12/src/test/java/test/sanitycheck/0000755000175000017500000000000012732165123020374 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/sanitycheck/CheckSuiteNamesTest.java0000644000175000017500000000545412732165123025122 0ustar eugeneeugenepackage test.sanitycheck; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.Parser; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import org.xml.sax.SAXException; import test.SimpleBaseTest; import java.io.IOException; import java.util.Arrays; import javax.xml.parsers.ParserConfigurationException; public class CheckSuiteNamesTest extends SimpleBaseTest { /** * Child suites have different names */ @Test public void checkChildSuites() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); String testngXmlPath = getPathToResource("sanitycheck/test-s-b.xml"); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 4); } /** * Child suites have same names */ @Test public void checkChildSuitesFails() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); String testngXmlPath = getPathToResource("sanitycheck/test-s-a.xml"); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getTestContexts().get(0).getSuite().getName(), "SanityCheck suites"); Assert.assertEquals(tla.getTestContexts().get(1).getSuite().getName(), "SanityCheck suites"); Assert.assertEquals(tla.getTestContexts().get(2).getSuite().getName(), "SanityCheck suites (0)"); Assert.assertEquals(tla.getTestContexts().get(3).getSuite().getName(), "SanityCheck suites (0)"); } /** * Checks that suites created programmatically also works as expected */ @Test public void checkProgrammaticSuitesFails() { XmlSuite xmlSuite1 = new XmlSuite(); xmlSuite1.setName("SanityCheckSuite"); { XmlTest result = new XmlTest(xmlSuite1); result.getXmlClasses().add(new XmlClass(SampleTest1.class.getCanonicalName())); } XmlSuite xmlSuite2 = new XmlSuite(); xmlSuite2.setName("SanityCheckSuite"); { XmlTest result = new XmlTest(xmlSuite2); result.getXmlClasses().add(new XmlClass(SampleTest2.class.getCanonicalName())); } TestNG tng = create(); tng.setXmlSuites(Arrays.asList(xmlSuite1, xmlSuite2)); tng.run(); Assert.assertEquals(xmlSuite1.getName(), "SanityCheckSuite"); Assert.assertEquals(xmlSuite2.getName(), "SanityCheckSuite (0)"); } @Test public void checkXmlSuiteAddition() throws ParserConfigurationException, SAXException, IOException { TestNG tng = create(); String testngXmlPath = getPathToResource("sanitycheck/test-s-b.xml"); Parser parser = new Parser(testngXmlPath); tng.setXmlSuites(parser.parseToList()); tng.initializeSuitesAndJarFile(); } } testng-6.9.12/src/test/java/test/sanitycheck/SampleTest3.java0000644000175000017500000000020212732165123023375 0ustar eugeneeugenepackage test.sanitycheck; import org.testng.annotations.Test; public class SampleTest3 { @Test() public void test3() {} } testng-6.9.12/src/test/java/test/sanitycheck/SampleTest2.java0000644000175000017500000000020212732165123023374 0ustar eugeneeugenepackage test.sanitycheck; import org.testng.annotations.Test; public class SampleTest2 { @Test() public void test2() {} } testng-6.9.12/src/test/java/test/sanitycheck/CheckTestNamesTest.java0000644000175000017500000000533612732165123024747 0ustar eugeneeugenepackage test.sanitycheck; import java.util.Arrays; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; public class CheckTestNamesTest extends SimpleBaseTest { /** * Child suites and same suite has two tests with same name */ @Test public void checkWithChildSuites() { runSuite("sanitycheck/test-a.xml"); } /** * Simple suite with two tests with same name */ @Test public void checkWithoutChildSuites() { runSuite("sanitycheck/test1.xml"); } private void runSuite(String suitePath) { TestListenerAdapter tla = new TestListenerAdapter(); boolean exceptionRaised = false; try { TestNG tng = create(); String testngXmlPath = getPathToResource(suitePath); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); } catch (TestNGException ex) { exceptionRaised = true; Assert.assertEquals(tla.getPassedTests().size(), 0); Assert.assertEquals(tla.getFailedTests().size(), 0); } Assert.assertTrue(exceptionRaised); } /** * Simple suite with no two tests with same name */ @Test public void checkNoError() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); String testngXmlPath = getPathToResource("sanitycheck/test2.xml"); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 2); } /** * Child suites and tests within different suites have same names */ @Test(enabled = false) public void checkNoErrorWtihChildSuites() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); String testngXmlPath = getPathToResource("sanitycheck/test-b.xml"); tng.setTestSuites(Arrays.asList(testngXmlPath)); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 4); } /** * Checks that suites created programmatically also run as expected */ @Test public void checkTestNamesForProgrammaticSuites() { XmlSuite xmlSuite = new XmlSuite(); xmlSuite.setName("SanityCheckSuite"); XmlTest result = new XmlTest(xmlSuite); result.getXmlClasses().add(new XmlClass(SampleTest1.class.getCanonicalName())); result = new XmlTest(xmlSuite); result.getXmlClasses().add(new XmlClass(SampleTest2.class.getCanonicalName())); TestNG tng = new TestNG(); tng.setVerbose(0); tng.setXmlSuites(Arrays.asList(new XmlSuite[] { xmlSuite })); tng.run(); } } testng-6.9.12/src/test/java/test/sanitycheck/SampleTest1.java0000644000175000017500000000020212732165123023373 0ustar eugeneeugenepackage test.sanitycheck; import org.testng.annotations.Test; public class SampleTest1 { @Test() public void test1() {} } testng-6.9.12/src/test/java/test/BaseDistributedTest.java0000644000175000017500000000227512732165123022655 0ustar eugeneeugenepackage test; import org.testng.Assert; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class BaseDistributedTest { private boolean m_verbose = false; protected void verifyTests(String title, String[] exp, Map found) { Map expected = new HashMap(); for (String element : exp) { expected.put(element, element); } Assert.assertEquals(found.size(), expected.size(), "Verification for " + title + " tests failed:"); for (Object o : expected.values()) { String name = (String) o; if (null == found.get(name)) { dumpMap("Expected", expected); dumpMap("Found", found); } Assert.assertNotNull(found.get(name), "Expected to find method " + name + " in " + title + " but didn't find it."); } } protected void dumpMap(String title, Map m) { if (m_verbose) { System.out.println("==== " + title); for (Map.Entry entry : m.entrySet()) { ppp(entry.getKey() + " => " + entry.getValue()); } } } private void ppp(String s) { if (m_verbose) { System.out.println("[BaseDistributedTest] " + s); } } } testng-6.9.12/src/test/java/test/issue107/0000755000175000017500000000000012732165123017447 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/issue107/TestTestngCounter.java0000644000175000017500000000125412732165123023760 0ustar eugeneeugenepackage test.issue107; import org.testng.Assert; import org.testng.annotations.Listeners; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; @Listeners(MySuiteListener.class) public class TestTestngCounter { public static final String PARAMETER_NAME = "key1"; public static final String EXPECTED_VALUE = "zzz"; @Parameters({PARAMETER_NAME}) @Test public void testParameter(String key) { Assert.assertEquals(key, EXPECTED_VALUE); } @Parameters({PARAMETER_NAME}) @Test public void testParameterAsOptional(@Optional("Unknown") String key) { Assert.assertEquals(key, EXPECTED_VALUE); } } testng-6.9.12/src/test/java/test/issue107/MySuiteListener.java0000644000175000017500000000102512732165123023415 0ustar eugeneeugenepackage test.issue107; import org.testng.ISuite; import org.testng.ISuiteListener; import org.testng.xml.XmlSuite; import java.util.Map; public class MySuiteListener implements ISuiteListener { public void onFinish(ISuite suite) { } public void onStart(ISuite suite) { final XmlSuite xmlSuite = suite.getXmlSuite(); final Map parameters = xmlSuite.getParameters(); parameters.put(TestTestngCounter.PARAMETER_NAME, TestTestngCounter.EXPECTED_VALUE); xmlSuite.setParameters(parameters); } } testng-6.9.12/src/test/java/test/issue107/Issue107Test.java0000644000175000017500000000312512732165123022473 0ustar eugeneeugenepackage test.issue107; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; import java.util.Map; /** * @author Vladislav.Rassokhin */ public class Issue107Test extends SimpleBaseTest { @Test(description = "GITHUB-107, Check that suite parameters set from listener does not affects tests count") public void testSuiteParameterModificationFromListener() throws Exception { final XmlSuite suite = createXmlSuite("Simple suite"); final Map parameters = suite.getParameters(); parameters.put(TestTestngCounter.PARAMETER_NAME, "some value that must be overriden in listener"); suite.setParameters(parameters); runTest(suite); } @Test(description = "GITHUB-107, Check that suite parameters modification from listener does not affects tests count") public void testSuiteParameterSetFromListener() throws Exception { final XmlSuite suite = createXmlSuite("Simple suite"); runTest(suite); } private void runTest(XmlSuite suite) { final XmlTest test = createXmlTest(suite, "Simple Test", TestTestngCounter.class.getName()); suite.setTests(Arrays.asList(test)); final TestListenerAdapter tla = new TestListenerAdapter(); final TestNG tng = create(); tng.setXmlSuites(Arrays.asList(suite)); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getFailedTests().size(), 0); Assert.assertEquals(tla.getPassedTests().size(), 2); } } testng-6.9.12/src/test/java/test/test111/0000755000175000017500000000000012732165123017271 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/test111/AbstractTest.java0000644000175000017500000000043512732165123022541 0ustar eugeneeugenepackage test.test111; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; public abstract class AbstractTest { public static int R=0; @Test public void testAbstract() { } @AfterClass public void afterClass() { R++; } } testng-6.9.12/src/test/java/test/test111/Test1.java0000644000175000017500000000033512732165123021135 0ustar eugeneeugenepackage test.test111; import org.testng.annotations.Test; import junit.framework.Assert; public class Test1 extends AbstractTest { @Test public void test() { Assert.assertEquals(0, AbstractTest.R); } }testng-6.9.12/src/test/java/test/MethodTest.java0000644000175000017500000000254712732165123021022 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.annotations.Test; import test.sample.Sample2; public class MethodTest extends BaseTest { private static final String CLASS_NAME = Sample2.class.getName(); @Test(groups = { "current" }) public void includeMethodsOnly() { addClass(CLASS_NAME); Assert.assertEquals(getTest().getXmlClasses().size(), 1); addIncludedMethod(CLASS_NAME, ".*method2"); run(); String[] passed = { "method2", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test(groups = { "current" }) public void excludeMethodsOnly() { addClass(CLASS_NAME); Assert.assertEquals(getTest().getXmlClasses().size(), 1); addExcludedMethod(CLASS_NAME, ".*method2"); run(); String[] passed = { "method1", "method3" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void excludePackage() { addClass(CLASS_NAME); assert 1 == getTest().getXmlClasses().size(); addExcludedMethod(CLASS_NAME, ".*"); run(); String[] passed = { }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } }testng-6.9.12/src/test/java/test/testng195/0000755000175000017500000000000012732165123017632 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng195/AfterMethodTest.java0000644000175000017500000000060212732165123023535 0ustar eugeneeugenepackage test.testng195; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class AfterMethodTest extends SimpleBaseTest { @Test public void testContextShouldBeInitialized() { TestNG tng = create(AfterMethodSampleTest.class); tng.run(); Assert.assertTrue(AfterMethodSampleTest.m_success); } } testng-6.9.12/src/test/java/test/testng195/AfterMethodSampleTest.java0000644000175000017500000000106512732165123024703 0ustar eugeneeugenepackage test.testng195; import org.testng.IResultMap; import org.testng.ITestContext; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.lang.reflect.Method; public class AfterMethodSampleTest { static boolean m_success; @Test public void pass() { } @BeforeClass public void init() { m_success = false; } @AfterMethod public void afterMethod(ITestContext c, Method m) { IResultMap map = c.getPassedTests(); m_success = map.size() == 1; } } testng-6.9.12/src/test/java/test/retryAnalyzer/0000755000175000017500000000000012732165123020742 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/retryAnalyzer/PersistentFailure.java0000644000175000017500000000032412732165123025254 0ustar eugeneeugenepackage test.retryAnalyzer; import org.testng.Assert; import org.testng.annotations.Test; public class PersistentFailure { @Test(retryAnalyzer = MyRetry.class) public void test() { Assert.fail(); } } testng-6.9.12/src/test/java/test/retryAnalyzer/ExitCodeTest.java0000644000175000017500000000135112732165123024151 0ustar eugeneeugenepackage test.retryAnalyzer; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; public class ExitCodeTest extends SimpleBaseTest { @Test public void exitsWithZeroOnSuccess() { TestNG tng = create(ImmediateSuccess.class); tng.run(); assertEquals(tng.getStatus(), 0); } @Test public void exitsWithNonzeroOnFailure() { TestNG tng = create(PersistentFailure.class); tng.run(); assertTrue(tng.getStatus() != 0); } @Test public void exitsWithZeroAfterSuccessfulRetry() { TestNG tng = create(EventualSuccess.class); tng.run(); assertEquals(tng.getStatus(), 0); } } testng-6.9.12/src/test/java/test/retryAnalyzer/InvocationCountTest.java0000644000175000017500000000706612732165123025600 0ustar eugeneeugenepackage test.retryAnalyzer; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; import java.util.concurrent.atomic.AtomicInteger; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; import org.testng.TestNG; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.google.common.collect.ConcurrentHashMultiset; import com.google.common.collect.Multiset; /** * retryAnalyzer parameter unit tests. * @author tocman@gmail.com (Jeremie Lenfant-Engelmann) * */ public final class InvocationCountTest implements IRetryAnalyzer { static final Multiset invocations = ConcurrentHashMultiset.create(); private static final AtomicInteger retriesRemaining = new AtomicInteger(100); private int r1 = 0; private int r2 = 0; private int r3 = 0; private int r7 = 0; private static int value = 42; @Test(retryAnalyzer = InvocationCountTest.class) public void testAnnotationWithNoRetries() { } @Test(retryAnalyzer = InvocationCountTest.class) public void testAnnotationWithOneRetry() { if (r1++ < 1) { fail(); } } @Test(retryAnalyzer = InvocationCountTest.class) public void testAnnotationWithSevenRetries() { if (r7++ < 7) { fail(); } } @Test(retryAnalyzer = ThreeRetries.class, successPercentage = 0) public void failAfterThreeRetries() { fail(); } @Test(dependsOnMethods = { "testAnnotationWithNoRetries", "testAnnotationWithOneRetry", "testAnnotationWithSevenRetries", "failAfterThreeRetries" }, alwaysRun = true) public void checkInvocationCounts() { assertEquals(invocations.count("testAnnotationWithNoRetries"), 0); assertEquals(invocations.count("testAnnotationWithOneRetry"), 1); assertEquals(invocations.count("testAnnotationWithSevenRetries"), 7); assertEquals(invocations.count("failAfterThreeRetries"), 4); } @DataProvider(name="dataProvider") private Object[][] dataProvider() { return new Object[][] { { 1, false }, { 0, true }, { 0, true }, { 1, false } }; } @DataProvider(name="dataProvider2") private Object[][] dataProvider2() { value = 42; return new Object[][] { { true }, { true } }; } @Test(retryAnalyzer = InvocationCountTest.class, dataProvider = "dataProvider") public void testAnnotationWithDataProvider(int paf, boolean test) { if (paf == 1 && test == false) { if (r2 >= 1) { r2--; fail(); } } } @Test(retryAnalyzer = InvocationCountTest.class, dataProvider = "dataProvider2") public void testAnnotationWithDataProviderAndRecreateParameters(boolean dummy) { if (r3 == 1) { this.value = 0; r3--; fail(); } else if (r3 == 0) { assertEquals(this.value, 42); } } @Test public void withFactory() { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { MyFactory.class}); FactoryTest.m_count = 0; tng.run(); assertEquals(FactoryTest.m_count, 4); } @Override public boolean retry(ITestResult result) { invocations.add(result.getName()); return retriesRemaining.getAndDecrement() >= 0; } public static class ThreeRetries implements IRetryAnalyzer { private final AtomicInteger remainingRetries = new AtomicInteger(3); @Override public boolean retry(ITestResult result) { invocations.add(result.getName()); return remainingRetries.getAndDecrement() > 0; } } } testng-6.9.12/src/test/java/test/retryAnalyzer/RetryAnalyzerTest.java0000644000175000017500000000211412732165123025256 0ustar eugeneeugenepackage test.retryAnalyzer; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import java.util.List; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class RetryAnalyzerTest extends SimpleBaseTest { @Test public void testInvocationCounts() { TestNG tng = create(InvocationCountTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); assertFalse(tng.hasFailure()); assertFalse(tng.hasSkip()); assertTrue(tla.getFailedTests().isEmpty()); List fsp = tla.getFailedButWithinSuccessPercentageTests(); assertEquals(fsp.size(), 1); assertEquals(fsp.get(0).getName(), "failAfterThreeRetries"); List skipped = tla.getSkippedTests(); assertEquals(skipped.size(), InvocationCountTest.invocations.size() - fsp.size()); } } testng-6.9.12/src/test/java/test/retryAnalyzer/EventualSuccess.java0000644000175000017500000000057112732165123024724 0ustar eugeneeugenepackage test.retryAnalyzer; import org.testng.Assert; import org.testng.annotations.Test; import java.util.concurrent.atomic.AtomicBoolean; public class EventualSuccess { private static final AtomicBoolean ranYet = new AtomicBoolean(false); @Test(retryAnalyzer = MyRetry.class) public void test() { if (!ranYet.getAndSet(true)) { Assert.fail(); } } } testng-6.9.12/src/test/java/test/retryAnalyzer/FactoryTest.java0000755000175000017500000000113712732165123024061 0ustar eugeneeugenepackage test.retryAnalyzer; import static org.testng.Assert.fail; import org.testng.ITest; import org.testng.annotations.Test; public class FactoryTest implements ITest { public static int m_count = 0; private String name; public FactoryTest(String name) { this.name = name; } @Override public String getTestName() { return name; } @Test(retryAnalyzer = MyRetry.class) public void someTest1() { System.out.println("Test Called : " + this.name); if (name.contains("5")) { m_count++; fail(); } } } testng-6.9.12/src/test/java/test/retryAnalyzer/ImmediateSuccess.java0000644000175000017500000000024612732165123025036 0ustar eugeneeugenepackage test.retryAnalyzer; import org.testng.annotations.Test; public class ImmediateSuccess { @Test(retryAnalyzer = MyRetry.class) public void test() { } } testng-6.9.12/src/test/java/test/retryAnalyzer/MyFactory.java0000755000175000017500000000057112732165123023530 0ustar eugeneeugenepackage test.retryAnalyzer; import org.testng.annotations.Factory; public class MyFactory { @Factory public Object[] createTests() { int num = 10; Object[] result = new Object[num]; for (int i = 0; i < num; i++) { FactoryTest obj = new FactoryTest("Test" + i); result[i] = obj; } return result; } } testng-6.9.12/src/test/java/test/retryAnalyzer/MyRetry.java0000755000175000017500000000046712732165123023232 0ustar eugeneeugenepackage test.retryAnalyzer; import org.testng.ITestResult; import org.testng.util.RetryAnalyzerCount; public class MyRetry extends RetryAnalyzerCount { public MyRetry(){ setCount(3); } @Override public boolean retryMethod(ITestResult arg0) { // TODO Auto-generated method stub return true; } } testng-6.9.12/src/test/java/test/BaseTest.java0000644000175000017500000003667212732165123020462 0ustar eugeneeugenepackage test; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import org.testng.Assert; import org.testng.IClassListener; import org.testng.IInvokedMethodListener; import org.testng.ISuite; import org.testng.ITestResult; import org.testng.ITestRunnerFactory; import org.testng.SuiteRunner; import org.testng.TestListenerAdapter; import org.testng.TestRunner; import org.testng.annotations.BeforeMethod; import org.testng.collections.Lists; import org.testng.internal.Configuration; import org.testng.internal.IConfiguration; import org.testng.reporters.JUnitXMLReporter; import org.testng.reporters.TestHTMLReporter; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlMethodSelector; import org.testng.xml.XmlPackage; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; /** * Base class for tests * * @author Cedric Beust, May 5, 2004 * */ public class BaseTest extends BaseDistributedTest { private static final String m_outputDirectory= "test-output-tests"; private XmlSuite m_suite= null; private ITestRunnerFactory m_testRunnerFactory; private IConfiguration m_configuration; private Integer m_verbose = null; public BaseTest() { m_testRunnerFactory= new InternalTestRunnerFactory(this); m_configuration = new Configuration(); } private IConfiguration getConfiguration() { return m_configuration; } protected void setDebug() { getTest().setVerbose(9); } protected void setParallel(XmlSuite.ParallelMode parallel) { getTest().setParallel(parallel); } protected void setVerbose(int n) { m_verbose = n; } protected void setTestTimeOut(long n) { getTest().setTimeOut(n); } protected void setSuiteTimeOut(long n) { m_suite.setTimeOut(Long.toString(n)); } protected void setJUnit(boolean f) { getTest().setJUnit(f); } protected void setThreadCount(int count) { getTest().getSuite().setThreadCount(count); } private Map m_tests= new HashMap<>(); private Map m_passedTests= new HashMap<>(); private Map m_failedTests= new HashMap<>(); private Map m_skippedTests= new HashMap<>(); private Map m_testConfigs= new HashMap<>(); private Map m_passedConfigs= new HashMap<>(); private Map m_failedConfigs= new HashMap<>(); private Map m_skippedConfigs= new HashMap<>(); private Map m_failedButWithinSuccessPercentageTests= new HashMap<>(); protected Map> getTests(Map map) { Map> result= map.get(getId()); if(null == result) { result= new HashMap<>(); map.put(getId(), result); } return result; } protected XmlTest getTest() { return m_tests.get(getId()); } protected void setTests(Map map, Map m) { map.put(getId(), m); } public Map> getFailedTests() { return getTests(m_failedTests); } public Map> getFailedButWithinSuccessPercentageTests() { return getTests(m_failedButWithinSuccessPercentageTests); } public Map> getPassedTests() { return getTests(m_passedTests); } public Map> getSkippedTests() { return getTests(m_skippedTests); } public Map> getFailedConfigs() { return getTests(m_failedConfigs); } public Map> getPassedConfigs() { return getTests(m_passedConfigs); } public Map> getSkippedConfigs() { return getTests(m_skippedConfigs); } public void setSkippedTests(Map m) { setTests(m_skippedTests, m); } public void setPassedTests(Map m) { setTests(m_passedTests, m); } public void setFailedTests(Map m) { setTests(m_failedTests, m); } public void setFailedButWithinSuccessPercentageTests(Map m) { setTests(m_failedButWithinSuccessPercentageTests, m); } public void setSkippedConfigs(Map m) { setTests(m_skippedConfigs, m); } public void setPassedConfigs(Map m) { setTests(m_passedConfigs, m); } public void setFailedConfigs(Map m) { setTests(m_failedConfigs, m); } protected void run() { assert null != getTest() : "Test wasn't set, maybe @Configuration methodSetUp() was never called"; setPassedTests(new HashMap()); setFailedTests(new HashMap()); setSkippedTests(new HashMap()); setPassedConfigs(new HashMap()); setFailedConfigs(new HashMap()); setSkippedConfigs(new HashMap()); setFailedButWithinSuccessPercentageTests(new HashMap()); m_suite.setVerbose(m_verbose != null ? m_verbose : 0); SuiteRunner suite = new SuiteRunner(m_configuration, m_suite, m_outputDirectory, m_testRunnerFactory); suite.run(); } protected void addMethodSelector(String className, int priority) { XmlMethodSelector methodSelector= new XmlMethodSelector(); methodSelector.setName(className); methodSelector.setPriority(priority); getTest().getMethodSelectors().add(methodSelector); } protected void addClasses(Class... classes) { for (Class clazz : classes) { addClass(clazz); } } protected XmlClass addClass(Class cls) { return addClass(cls.getName()); } protected XmlClass addClass(String className) { XmlClass result= new XmlClass(className); getTest().getXmlClasses().add(result); return result; } protected void setBeanShellExpression(String expression) { getTest().setBeanShellExpression(expression); } protected void addPackage(String pkgName, String[] included, String[] excluded) { XmlPackage pkg= new XmlPackage(); pkg.setName(pkgName); pkg.getInclude().addAll(Arrays.asList(included)); pkg.getExclude().addAll(Arrays.asList(excluded)); getTest().getSuite().getXmlPackages().add(pkg); } private XmlClass findClass(String className) { for(XmlClass cl : getTest().getXmlClasses()) { if(cl.getName().equals(className)) { return cl; } } XmlClass result= addClass(className); return result; } public void addIncludedMethod(String className, String m) { XmlClass xmlClass= findClass(className); xmlClass.getIncludedMethods().add(new XmlInclude(m)); getTest().getXmlClasses().add(xmlClass); } public void addExcludedMethod(String className, String m) { XmlClass xmlClass= findClass(className); xmlClass.getExcludedMethods().add(m); getTest().getXmlClasses().add(xmlClass); } public void addIncludedGroup(String g) { getTest().addIncludedGroup(g); } public void addExcludedGroup(String g) { getTest().addExcludedGroup(g); } public void addMetaGroup(String mg, List l) { getTest().getMetaGroups().put(mg, l); } public void addMetaGroup(String mg, String n) { List l= new ArrayList<>(); l.add(n); addMetaGroup(mg, l); } public void setParameter(String key, String value) { getTest().addParameter(key, value); } // @Configuration(beforeTestMethod = true, groups = { "init", "initTest"}) @BeforeMethod(groups= { "init", "initTest" }) public void methodSetUp() { m_suite= new XmlSuite(); m_suite.setName("Internal_suite"); XmlTest xmlTest= new XmlTest(m_suite); xmlTest.setName("Internal_test_failures_are_expected"); m_tests.put(getId(), xmlTest); } private void addTest(Map> tests, ITestResult t) { List l= tests.get(t.getMethod().getMethodName()); if(null == l) { l= new ArrayList<>(); tests.put(t.getMethod().getMethodName(), l); } l.add(t); } public void addPassedTest(ITestResult t) { addTest(getPassedTests(), t); } public void addFailedTest(ITestResult t) { addTest(getFailedTests(), t); } public void addFailedButWithinSuccessPercentageTest(ITestResult t) { addTest(getFailedButWithinSuccessPercentageTests(), t); } public void addSkippedTest(ITestResult t) { addTest(getSkippedTests(), t); } public void addPassedConfig(ITestResult t) { addTest(getPassedConfigs(), t); } public void addFailedConfig(ITestResult t) { addTest(getFailedConfigs(), t); } public void addSkippedConfig(ITestResult t) { addTest(getSkippedConfigs(), t); } private void ppp(String s) { System.out.println("[BaseTest " + getId() + "] " + s); } protected Long getId() { return 42L; // long result = Thread.currentThread().getId(); //// System.out.println("RETURNING ID " + result); // return result; } public XmlSuite getSuite() { return m_suite; } public void setSuite(XmlSuite suite) { m_suite = suite; } /** * Used for instanceCount testing, when we need to look inside the * TestResult to count the various SUCCESS/FAIL/FAIL_BUT_OK */ protected void verifyResults(Map> tests, int expected, String message) { if(tests.size() > 0) { Set keys= tests.keySet(); Object firstKey= keys.iterator().next(); List passedResult= tests.get(firstKey); int n= passedResult.size(); assert n == expected : "Expected " + expected + " " + message + " but found " + n; } else { assert expected == 0 : "Expected " + expected + " " + message + " but found " + tests.size(); } } protected void dumpResults(String name, Map> tests) { ppp("============= " + name); for(Map.Entry> entry : tests.entrySet()) { ppp("TEST:" + entry.getKey()); List l= entry.getValue(); for(ITestResult tr : l) { ppp(" " + tr); } } } protected static void verifyInstanceNames(String title, Map> actual, String[] expected) { List actualNames = Lists.newArrayList(); for (Map.Entry> es : actual.entrySet()) { for (ITestResult tr : es.getValue()) { Object instance = tr.getInstance(); actualNames.add(es.getKey() + "#" + (instance != null ? instance.toString() : "")); } } Assert.assertEqualsNoOrder(actualNames.toArray(), expected); } protected void verifyPassedTests(String... expectedPassed) { verifyTests("Passed", expectedPassed, getPassedTests()); } protected void verifyFailedTests(String... expectedFailed) { verifyTests("Failed", expectedFailed, getFailedTests()); } protected void verifySkippedTests(String... expectedSkipped) { verifyTests("Skipped", expectedSkipped, getSkippedTests()); } /** * * @param fileName The filename to parse * @param regexp The regular expression * @param resultLines An out parameter that will contain all the lines * that matched the regexp * @return A List containing the lines of all the matches * * Note that the size() of the returned valuewill always be equal to * result.size() at the end of this function. */ public static List grep(File fileName, String regexp, List resultLines) { List resultLineNumbers = new ArrayList<>(); BufferedReader fr = null; try { fr = new BufferedReader(new FileReader(fileName)); String line = fr.readLine(); int currentLine = 0; Pattern p = Pattern.compile(".*" + regexp + ".*"); while(null != line) { // ppp("COMPARING " + p + " TO @@@" + line + "@@@"); if(p.matcher(line).matches()) { resultLines.add(line); resultLineNumbers.add(currentLine); } line = fr.readLine(); currentLine++; } } catch(IOException e) { e.printStackTrace(); } finally { if(null != fr) { try { fr.close(); } catch(IOException ex) { ex.printStackTrace(); } } } return resultLineNumbers; } private static class InternalTestRunnerFactory implements ITestRunnerFactory { private final BaseTest m_baseTest; public InternalTestRunnerFactory(final BaseTest baseTest) { m_baseTest= baseTest; } /** * @see org.testng.ITestRunnerFactory#newTestRunner(org.testng.ISuite, org.testng.xml.XmlTest) */ @Override public TestRunner newTestRunner(ISuite suite, XmlTest test, Collection listeners, List classListeners) { TestRunner testRunner= new TestRunner(m_baseTest.getConfiguration(), suite, test, false, listeners, classListeners); testRunner.addListener(new TestHTMLReporter()); testRunner.addListener(new JUnitXMLReporter()); testRunner.addListener(new TestListener(m_baseTest)); if (listeners != null) { for (IInvokedMethodListener l : listeners) { testRunner.addListener(l); } } return testRunner; } } /** * Deletes all files and subdirectories under dir. * @return true if all deletions were successful. * If a deletion fails, the method stops attempting to delete and returns false. */ public static boolean deleteDir(File dir) { if (dir.isDirectory()) { String[] children = dir.list(); for (String element : children) { boolean success = deleteDir(new File(dir, element)); if (!success) { return false; } } } // The directory is now empty so delete it return dir.delete(); } protected void runTest(String cls, String[] passed, String[] failed, String[] skipped) { addClass(cls); run(); verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } // BaseTest //////////////////////////// class TestListener extends TestListenerAdapter { private static BaseTest m_test= null; public TestListener(BaseTest t1) { m_test= t1; } @Override public void onTestSuccess(ITestResult tr) { m_test.addPassedTest(tr); } @Override public void onTestFailure(ITestResult tr) { m_test.addFailedTest(tr); } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { m_test.addFailedButWithinSuccessPercentageTest(result); } @Override public void onTestSkipped(ITestResult tr) { m_test.addSkippedTest(tr); } @Override public void onConfigurationSuccess(ITestResult tr) { m_test.addPassedConfig(tr); } @Override public void onConfigurationFailure(ITestResult tr) { m_test.addFailedConfig(tr); } @Override public void onConfigurationSkip(ITestResult tr) { m_test.addSkippedConfig(tr); } } // TestListener testng-6.9.12/src/test/java/test/methodinterceptors/0000755000175000017500000000000012732165123022011 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/methodinterceptors/Issue392.java0000644000175000017500000000037512732165123024207 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; public class Issue392 { @AfterClass public void afterClass() {} @Test public void test1() {} @Test public void test2() {} } testng-6.9.12/src/test/java/test/methodinterceptors/RemoveAMethodInterceptor.java0000644000175000017500000000275012732165123027576 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import java.util.ArrayList; import java.util.List; /** * An interceptor that removes the method called "two". */ public class RemoveAMethodInterceptor implements IMethodInterceptor { @Override public List intercept(List methods, ITestContext context) { List result = new ArrayList<>(); for (IMethodInstance method : methods) { String name = method.getMethod().getMethodName(); if (!name.equals("two")) { result.add(method); } } log(this, methods, result); return result; } public static void log(IMethodInterceptor listener, List input, List output) { StringBuilder msg = new StringBuilder().append(listener.getClass().getName()) .append(" - Input:").append(getMethodNames(input)).append(" ").append(input.size()) .append(" methods.").append(" Output:").append(getMethodNames(output)).append(" ") .append(output.size()).append(" methods"); log(msg.toString()); } public static List getMethodNames(List methods) { List names = new ArrayList<>(); for (IMethodInstance m : methods) { names.add(m.getMethod().getMethodName()); } return names; } private static void log(String s) { // System.out.println("[MI2] " + s); } }testng-6.9.12/src/test/java/test/methodinterceptors/MethodInterceptorTest.java0000644000175000017500000000631612732165123027161 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.Parser; import org.testng.xml.XmlSuite; import org.xml.sax.SAXException; import test.SimpleBaseTest; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import javax.xml.parsers.ParserConfigurationException; public class MethodInterceptorTest extends SimpleBaseTest { private String XML = "" + "" + "" + "" + "" + " " + "" + "" + " " + " " + " " + " " + " " + "" + ""; @Test public void noMethodsShouldRun() { TestNG tng = create(); tng.setTestClasses(new Class[] { FooTest.class }); testNullInterceptor(tng); } private void testNullInterceptor(TestNG tng) { tng.setMethodInterceptor(new NullMethodInterceptor()); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 0); Assert.assertEquals(tla.getFailedTests().size(), 0); Assert.assertEquals(tla.getSkippedTests().size(), 0); } private void testFast(boolean useInterceptor) { TestNG tng = create(); tng.setTestClasses(new Class[] { FooTest.class }); if (useInterceptor) { tng.setMethodInterceptor(new FastTestsFirstInterceptor()); } TestListenerAdapter tla = new TestListenerAdapter(); // tng.setParallel("methods"); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 3); ITestResult first = tla.getPassedTests().get(0); String method = "zzzfast"; if (useInterceptor) { Assert.assertEquals(first.getMethod().getMethodName(), method); } else { Assert.assertNotSame(first.getMethod().getMethodName(), method); } } @Test public void fastShouldRunFirst() { testFast(true /* use interceptor */); } @Test public void fastShouldNotRunFirst() { testFast(false /* don't use interceptor */); } @Test public void nullMethodInterceptorWorksInTestngXml() throws IOException, ParserConfigurationException, SAXException { File f = File.createTempFile("testng-tests-", ""); f.deleteOnExit(); BufferedWriter bw = new BufferedWriter(new FileWriter(f)); bw.write(XML); bw.close(); try { List xmlSuites = new Parser(f.getAbsolutePath()).parseToList(); TestNG tng = create(); tng.setXmlSuites(xmlSuites); testNullInterceptor(tng); } catch(Exception ex) { ex.printStackTrace(); } } @Test(timeOut = 1000) public void shouldNotLockUpWithInterceptorThatRemovesMethods() { TestNG tng = create(LockUpInterceptorSampleTest.class); tng.setParallel(XmlSuite.ParallelMode.METHODS); tng.run(); } } testng-6.9.12/src/test/java/test/methodinterceptors/Issue521Test.java0000644000175000017500000000245612732165123025043 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.TestNG; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; import test.InvokedMethodNameListener; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; public class Issue521Test extends SimpleBaseTest { @Test(description = "test for https://github.com/cbeust/testng/issues/521") public void BeforeClass_method_should_be_fired_when_IMethodInterceptor_removes_test_methods() { TestNG tng = create(Issue521.class); tng.setMethodInterceptor(new IMethodInterceptor() { @Override public List intercept(List methods, ITestContext context) { List instances = new ArrayList<>(); for (IMethodInstance instance : methods) { if (!instance.getMethod().getMethodName().equals("test1")) { instances.add(instance); } } return instances; } }); InvokedMethodNameListener listener = new InvokedMethodNameListener(); tng.addListener(listener); tng.run(); assertThat(listener.getInvokedMethodNames()).containsExactly("beforeClass", "test2"); } } testng-6.9.12/src/test/java/test/methodinterceptors/Issue392Test.java0000644000175000017500000000245412732165123025047 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.TestNG; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; import test.InvokedMethodNameListener; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; public class Issue392Test extends SimpleBaseTest { @Test(description = "test for https://github.com/cbeust/testng/issues/392") public void AfterClass_method_should_be_fired_when_IMethodInterceptor_removes_test_methods() { TestNG tng = create(Issue392.class); tng.setMethodInterceptor(new IMethodInterceptor() { @Override public List intercept(List methods, ITestContext context) { List instances = new ArrayList<>(); for (IMethodInstance instance : methods) { if (!instance.getMethod().getMethodName().equals("test1")) { instances.add(instance); } } return instances; } }); InvokedMethodNameListener listener = new InvokedMethodNameListener(); tng.addListener(listener); tng.run(); assertThat(listener.getInvokedMethodNames()).containsExactly("test2", "afterClass"); } } testng-6.9.12/src/test/java/test/methodinterceptors/FastTestsFirstInterceptor.java0000644000175000017500000000160112732165123030021 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; public class FastTestsFirstInterceptor implements IMethodInterceptor { @Override public List intercept(List methods, ITestContext context) { List result = new ArrayList<>(); for (IMethodInstance m : methods) { Test test = m.getMethod().getMethod().getAnnotation(Test.class); Set groups = new HashSet<>(); for (String group : test.groups()) { groups.add(group); } if (groups.contains("fast")) { result.add(0, m); } else { result.add(m); } } return result; } } testng-6.9.12/src/test/java/test/methodinterceptors/NullMethodInterceptor.java0000644000175000017500000000062312732165123027147 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import java.util.ArrayList; import java.util.List; public class NullMethodInterceptor implements IMethodInterceptor { @Override public List intercept(List methods, ITestContext context) { return new ArrayList<>(); } } testng-6.9.12/src/test/java/test/methodinterceptors/FooTest.java0000644000175000017500000000032412732165123024236 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.annotations.Test; public class FooTest { @Test(groups = "fast") public void zzzfast() {} @Test public void slow() {} @Test public void a() {} } testng-6.9.12/src/test/java/test/methodinterceptors/LockUpInterceptorSampleTest.java0000644000175000017500000000075112732165123030275 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners({RemoveAMethodInterceptor.class}) public class LockUpInterceptorSampleTest { @Test public void one() { log("one"); } @Test public void two() { log("two"); } @Test public void three() { log("three"); } private static void log(String s) { // System.out.println("[MITest] " + s); } }testng-6.9.12/src/test/java/test/methodinterceptors/Issue521.java0000644000175000017500000000040012732165123024166 0ustar eugeneeugenepackage test.methodinterceptors; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class Issue521 { @BeforeClass public void beforeClass() {} @Test public void test1() {} @Test public void test2() {} } testng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/0000755000175000017500000000000012732165123026306 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/FooTest.java0000644000175000017500000000037112732165123030535 0ustar eugeneeugenepackage test.methodinterceptors.multipleinterceptors; import org.testng.annotations.Test; public class FooTest { @Test public void a() { } @Test public void b() { } @Test public void c() { } @Test public void d() { } } testng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/ThirdInterceptor.java0000644000175000017500000000027012732165123032441 0ustar eugeneeugenepackage test.methodinterceptors.multipleinterceptors; public class ThirdInterceptor extends MethodNameFilterInterceptor { public ThirdInterceptor() { super("c"); } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootroottestng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/MultipleInterceptorsTest.javatestng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/MultipleInterceptorsTest.ja0000644000175000017500000000237212732165123033663 0ustar eugeneeugenepackage test.methodinterceptors.multipleinterceptors; import java.util.Collections; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class MultipleInterceptorsTest extends SimpleBaseTest { @Test public void testMultipleInterceptors(){ TestNG tng = create(FooTest.class); tng.setMethodInterceptor(new FirstInterceptor()); tng.setMethodInterceptor(new SecondInterceptor()); tng.setMethodInterceptor(new ThirdInterceptor()); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); Assert.assertEquals(tla.getPassedTests().get(0).getName(), "d"); } @Test public void testMultipleInterceptorsWithPreserveOrder() { TestNG tng = create(); tng.setTestSuites(Collections.singletonList( getPathToResource("/methodinterceptors/multipleinterceptors/multiple-interceptors.xml"))); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().get(0).getMethod().getDescription(), "abc"); } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootroottestng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/MethodNameFilterInterceptor.javatestng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/MethodNameFilterInterceptor0000644000175000017500000000215712732165123033644 0ustar eugeneeugenepackage test.methodinterceptors.multipleinterceptors; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.ITestNGMethod; import java.util.ArrayList; import java.util.List; public abstract class MethodNameFilterInterceptor implements IMethodInterceptor { private final String methodName; protected MethodNameFilterInterceptor(String methodName) { this.methodName = methodName; } @Override public List intercept(List methods, ITestContext context) { List result = new ArrayList<>(); for (IMethodInstance methodInstance : methods) { ITestNGMethod method = methodInstance.getMethod(); String name = method.getMethodName(); if (!name.equals(methodName)) { result.add(methodInstance); String currentDescription = method.getDescription(); if (currentDescription == null) { method.setDescription(methodName); } else { method.setDescription(currentDescription + methodName); } } } return result; } } testng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/SecondInterceptor.java0000644000175000017500000000027212732165123032604 0ustar eugeneeugenepackage test.methodinterceptors.multipleinterceptors; public class SecondInterceptor extends MethodNameFilterInterceptor { public SecondInterceptor() { super("b"); } } testng-6.9.12/src/test/java/test/methodinterceptors/multipleinterceptors/FirstInterceptor.java0000644000175000017500000000027012732165123032456 0ustar eugeneeugenepackage test.methodinterceptors.multipleinterceptors; public class FirstInterceptor extends MethodNameFilterInterceptor { public FirstInterceptor() { super("a"); } } testng-6.9.12/src/test/java/test/skipex/0000755000175000017500000000000012732165123017372 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/skipex/SkipAndExpectedSampleTest.java0000644000175000017500000000037712732165123025261 0ustar eugeneeugenepackage test.skipex; import org.testng.SkipException; import org.testng.annotations.Test; public class SkipAndExpectedSampleTest { @Test(expectedExceptions = NullPointerException.class) public void a2() { throw new SkipException("test"); } } testng-6.9.12/src/test/java/test/skipex/ConfigurationSkippedExceptionTest.java0000644000175000017500000000062112732165123027102 0ustar eugeneeugenepackage test.skipex; import org.testng.SkipException; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * This class/interface */ public class ConfigurationSkippedExceptionTest { @BeforeMethod public void configurationLevelSkipException() { throw new SkipException("some skip message"); } @Test public void dummyTest() { } } testng-6.9.12/src/test/java/test/skipex/SkippedExceptionTest.java0000644000175000017500000000366612732165123024366 0ustar eugeneeugenepackage test.skipex; import org.testng.Assert; import org.testng.ITestNGListener; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import java.util.List; /** * This class/interface */ public class SkippedExceptionTest { @Test public void skippedExceptionInConfigurationMethods() { TestListenerAdapter listener= new TestListenerAdapter(); TestNG test= new TestNG(false); test.addListener((ITestNGListener)listener); test.setVerbose(0); test.setTestClasses(new Class[] {ConfigurationSkippedExceptionTest.class}); test.run(); List confSkips= listener.getConfigurationSkips(); List testSkips= listener.getSkippedTests(); Assert.assertEquals(testSkips.size(), 1); Assert.assertEquals(testSkips.get(0).getMethod().getMethodName(), "dummyTest"); Assert.assertEquals(confSkips.size(), 1); Assert.assertEquals(confSkips.get(0).getMethod().getMethodName(), "configurationLevelSkipException"); } @Test public void skippedExceptionInTestMethods() { TestListenerAdapter listener= new TestListenerAdapter(); TestNG test= new TestNG(false); test.addListener(listener); test.setTestClasses(new Class[] {TestSkippedExceptionTest.class}); test.run(); List skips= listener.getSkippedTests(); List failures= listener.getFailedTests(); List passed = listener.getPassedTests(); Assert.assertEquals(skips.size(), 1); Assert.assertEquals(failures.size(), 1); Assert.assertEquals(passed.size(), 1); Assert.assertEquals(skips.get(0).getMethod().getMethodName(), "genericSkipException"); Assert.assertEquals(failures.get(0).getMethod().getMethodName(), "timedSkipException"); Assert.assertEquals(passed.get(0).getMethod().getMethodName(), "genericExpectedSkipException"); } } testng-6.9.12/src/test/java/test/skipex/TestSkippedExceptionTest.java0000644000175000017500000000125012732165123025211 0ustar eugeneeugenepackage test.skipex; import org.testng.SkipException; import org.testng.TimeBombSkipException; import org.testng.annotations.Test; /** * This class/interface */ public class TestSkippedExceptionTest { @Test public void genericSkipException() { throw new SkipException("genericSkipException is skipped for now"); } @Test(expectedExceptions = SkipException.class) public void genericExpectedSkipException() { throw new SkipException("genericExpectedSkipException should not be skipped"); } @Test public void timedSkipException() { throw new TimeBombSkipException("timedSkipException is time bombed", "2007/04/10"); } } testng-6.9.12/src/test/java/test/skipex/SkipAndExpectedTest.java0000644000175000017500000000114212732165123024106 0ustar eugeneeugenepackage test.skipex; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class SkipAndExpectedTest extends SimpleBaseTest { @Test public void shouldSkip() { TestNG tng = create(SkipAndExpectedSampleTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 0); Assert.assertEquals(tla.getSkippedTests().size(), 1); Assert.assertEquals(tla.getFailedTests().size(), 0); } } testng-6.9.12/src/test/java/test/methodselectors/0000755000175000017500000000000012732165123021273 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/methodselectors/SampleTest.java0000644000175000017500000000067112732165123024223 0ustar eugeneeugenepackage test.methodselectors; import org.testng.annotations.Test; public class SampleTest { @Test(groups = { "test1" }) public void test1() { ppp("TEST1"); } @Test(groups = { "test2" }) public void test2() { ppp("TEST2"); } @Test(groups = { "test3" }) public void test3() { ppp("TEST3"); } private static void ppp(String s) { if (false) { System.out.println("[SampleTest] " + s); } } } testng-6.9.12/src/test/java/test/methodselectors/NoTest.java0000644000175000017500000000010012732165123023341 0ustar eugeneeugenepackage test.methodselectors; public @interface NoTest { } testng-6.9.12/src/test/java/test/methodselectors/NoTestSelector.java0000644000175000017500000000132012732165123025047 0ustar eugeneeugenepackage test.methodselectors; import org.testng.IMethodSelector; import org.testng.IMethodSelectorContext; import org.testng.ITestNGMethod; import java.util.List; public class NoTestSelector implements IMethodSelector { /** * */ private static final long serialVersionUID = -7751190578710846487L; @Override public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod) { ppp("NOTEST RETURNING FALSE FOR " + method); return false; } @Override public void setTestMethods(List testMethods) { } private static void ppp(String s) { // System.out.println("[NoTestSelector] " + s); } } testng-6.9.12/src/test/java/test/methodselectors/PriorityTest.java0000644000175000017500000000301612732165123024617 0ustar eugeneeugenepackage test.methodselectors; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import java.util.List; public class PriorityTest { private void runTest(int priority, String[] passedTests) { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { PrioritySampleTest.class }); tng.addMethodSelector("test.methodselectors.NoTestSelector", priority); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); List passed = tla.getPassedTests(); Assert.assertEquals(passedTests.length, passed.size()); if (passedTests.length == 1) { String passed0 = passed.get(0).getName(); Assert.assertEquals(passed0, passedTests[0]); } if (passedTests.length == 2) { String passed0 = passed.get(0).getName(); String passed1 = passed.get(1).getName(); Assert.assertTrue(passed0.equals(passedTests[0]) || passed0.equals(passedTests[1])); Assert.assertTrue(passed1.equals(passedTests[0]) || passed1.equals(passedTests[1])); } } // @Test public void negativePriority() { runTest(-5, new String[] {}); } @Test public void lessThanTenPriority() { runTest(5, new String[] { "alwaysRun" }); } // @Test public void greaterThanTenPriority() { runTest(15, new String[] { "alwaysRun", "neverRun" }); } } testng-6.9.12/src/test/java/test/methodselectors/AllTestsMethodSelector.java0000644000175000017500000000131512732165123026533 0ustar eugeneeugenepackage test.methodselectors; import org.testng.IMethodSelector; import org.testng.IMethodSelectorContext; import org.testng.ITestNGMethod; import java.util.List; public class AllTestsMethodSelector implements IMethodSelector { /** * */ private static final long serialVersionUID = 8059117082807260868L; @Override public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod) { context.setStopped(true); return true; } private static void ppp(String s) { System.out.println("[MyMethodSelector] " + s); } @Override public void setTestMethods(List testMethods) { // TODO Auto-generated method stub } } testng-6.9.12/src/test/java/test/methodselectors/MethodSelectorInSuiteTest.java0000644000175000017500000000442112732165123027221 0ustar eugeneeugenepackage test.methodselectors; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.xml.XmlClass; import org.testng.xml.XmlMethodSelector; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import testhelper.OutputDirectoryPatch; import java.util.Arrays; import java.util.List; public class MethodSelectorInSuiteTest extends SimpleBaseTest{ private TestListenerAdapter m_tla; @BeforeMethod public void setup() { m_tla = new TestListenerAdapter(); } @Test public void programmaticXmlSuite() { TestNG tng = create(); XmlSuite suite = new XmlSuite(); XmlMethodSelector methodSelector = new XmlMethodSelector(); methodSelector.setName("test.methodselectors.Test2MethodSelector"); methodSelector.setPriority(-1); List methodSelectors = Lists.newArrayList(); methodSelectors.add(methodSelector); suite.setMethodSelectors(methodSelectors); XmlTest test = new XmlTest(suite); XmlClass testClass = new XmlClass(test.methodselectors.SampleTest.class); test.setXmlClasses(Arrays.asList(testClass)); tng.setXmlSuites(Arrays.asList(suite)); tng.addListener(m_tla); tng.run(); validate(new String[] { "test2" }); } @Test public void xmlXmlSuite() { TestNG tng = create(); tng.setTestSuites(Arrays.asList(getPathToResource("methodselector-in-xml.xml"))); tng.addListener(m_tla); tng.run(); validate(new String[] { "test2" }); } @Test public void fileOnCommandLine() { String[] args = new String[] { "-d", OutputDirectoryPatch.getOutputDirectory(), getPathToResource("methodselector-in-xml.xml") }; TestNG.privateMain(args, m_tla); validate(new String[] { "test2" }); } private void validate(String[] expectPassed) { List passed = m_tla.getPassedTests(); Assert.assertEquals(passed.size(), expectPassed.length); // doing this index based is probably not the best for (int i = 0; i < expectPassed.length; i++) { Assert.assertEquals(passed.get(i).getName(), expectPassed[i]); } } } testng-6.9.12/src/test/java/test/methodselectors/CommandLineTest.java0000644000175000017500000001262712732165123025174 0ustar eugeneeugenepackage test.methodselectors; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import test.SimpleBaseTest; import testhelper.OutputDirectoryPatch; import java.util.ArrayList; import java.util.List; public class CommandLineTest extends SimpleBaseTest { private String[] ARG_WITHOUT_CLASSES = new String[]{ "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-methodselectors", "", "" }; private String[] ARG_WITH_GROUPS = new String[]{ "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-testclass", "test.methodselectors.SampleTest", "-methodselectors", "", "-groups", "" }; private String[] ARG_WITHOUT_GROUPS = new String[]{ "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-testclass", "test.methodselectors.SampleTest", "-methodselectors", "", }; private TestListenerAdapter tla; @BeforeMethod public void setup() { ppp("setup()"); tla = new TestListenerAdapter(); } @Test public void commandLineNegativePriorityAllGroups() { ppp("commandLineNegativePriorityAllGroups()"); ARG_WITHOUT_GROUPS[7] = "test.methodselectors.AllTestsMethodSelector:-1"; TestNG.privateMain(ARG_WITHOUT_GROUPS, tla); String[] passed = { "test1", "test2", "test3" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineNegativePriorityGroup2() { ppp("commandLineNegativePriorityGroup2()"); ARG_WITHOUT_GROUPS[7] = "test.methodselectors.Test2MethodSelector:-1"; TestNG.privateMain(ARG_WITHOUT_GROUPS, tla); String[] passed = { "test2" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineLessThanPriorityTest1Test() { ppp("commandLineLessThanPriorityTest1Test()"); ARG_WITH_GROUPS[7] = "test.methodselectors.Test2MethodSelector:5"; ARG_WITH_GROUPS[9] = "test1"; TestNG.privateMain(ARG_WITH_GROUPS, tla); String[] passed = { "test1", "test2" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineGreaterThanPriorityTest1Test2() { ppp("commandLineGreaterThanPriorityTest1Test2()"); ARG_WITH_GROUPS[7] = "test.methodselectors.Test2MethodSelector:15"; ARG_WITH_GROUPS[9] = "test1"; TestNG.privateMain(ARG_WITH_GROUPS, tla); String[] passed = { "test2" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineLessThanPriorityAllTests() { ppp("commandLineLessThanPriorityAllTests()"); ARG_WITH_GROUPS[7] = "test.methodselectors.AllTestsMethodSelector:5"; ARG_WITH_GROUPS[9] = "test1"; TestNG.privateMain(ARG_WITH_GROUPS, tla); String[] passed = { "test1", "test2", "test3" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineMultipleSelectors() { ppp("commandLineMultipleSelectors()"); ARG_WITH_GROUPS[7] = "test.methodselectors.NoTestSelector:7,test.methodselectors.Test2MethodSelector:5"; ARG_WITH_GROUPS[9] = "test1"; TestNG.privateMain(ARG_WITH_GROUPS, tla); String[] passed = { "test1", "test2" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineNoTest1Selector() { ppp("commandLineNoTest1Selector()"); ARG_WITHOUT_GROUPS[7] = "test.methodselectors.NoTest1MethodSelector:5"; TestNG.privateMain(ARG_WITHOUT_GROUPS, tla); String[] passed = { "test2", "test3" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } @Test public void commandLineTestWithXmlFile() { ppp("commandLineTestWithXmlFile()"); ARG_WITHOUT_CLASSES[5] = "test.methodselectors.NoTest1MethodSelector:5"; ARG_WITHOUT_CLASSES[6] = getPathToResource("testng-methodselectors.xml"); TestNG.privateMain(ARG_WITHOUT_CLASSES, tla); String[] passed = { "test2", "test3" }; String[] failed = { }; verifyTests("Passed", passed, tla.getPassedTests()); verifyTests("Failed", failed, tla.getFailedTests()); } private void verifyTests(String title, String[] expected, List found) { List resultMethods = new ArrayList<>(); for( ITestResult result : found ) { resultMethods.add( result.getName() ); } Assert.assertEquals(resultMethods.size(), expected.length, "wrong number of " + title + " tests"); for(String e : expected) { Assert.assertTrue(resultMethods.contains(e), "Expected to find method " + e + " in " + title + " but didn't find it."); } } public static void ppp(String s) { //System.out.println("[CommandLineTest] " + s); } } testng-6.9.12/src/test/java/test/methodselectors/Test2MethodSelector.java0000644000175000017500000000134612732165123026005 0ustar eugeneeugenepackage test.methodselectors; import org.testng.IMethodSelector; import org.testng.IMethodSelectorContext; import org.testng.ITestNGMethod; import java.util.List; public class Test2MethodSelector implements IMethodSelector { /** * */ private static final long serialVersionUID = 4166247968392649912L; @Override public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod) { for (String group : method.getGroups()) { if (group.equals("test2")) { context.setStopped(true); return true; } } return false; } @Override public void setTestMethods(List testMethods) { // TODO Auto-generated method stub } } testng-6.9.12/src/test/java/test/methodselectors/BeanShellTest.java0000644000175000017500000000112612732165123024633 0ustar eugeneeugenepackage test.methodselectors; import org.testng.annotations.Test; import test.BaseTest; public class BeanShellTest extends BaseTest { @Test public void onlyGroup1() { addClass("test.methodselectors.SampleTest"); setBeanShellExpression("groups.\n containsKey \t (\"test1\")"); run(); String[] passed = { "test1", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } public static void ppp(String s) { System.out.println("[MethodSelectorTest] " + s); } } testng-6.9.12/src/test/java/test/methodselectors/PrioritySampleTest.java0000644000175000017500000000053512732165123025764 0ustar eugeneeugenepackage test.methodselectors; import org.testng.annotations.Test; public class PrioritySampleTest { @Test public void alwaysRun() { ppp("ALWAYS"); } @Test @NoTest public void neverRun() { ppp("NEVER"); } private static void ppp(String s) { System.out.println("[PrioritySampleTest] " + s); } } testng-6.9.12/src/test/java/test/methodselectors/MethodSelectorTest.java0000644000175000017500000000430512732165123025721 0ustar eugeneeugenepackage test.methodselectors; import org.testng.annotations.Test; import test.BaseTest; public class MethodSelectorTest extends BaseTest { @Test public void negativePriorityAllGroups() { addClass("test.methodselectors.SampleTest"); addMethodSelector("test.methodselectors.AllTestsMethodSelector", -1); run(); String[] passed = { "test1", "test2", "test3", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void negativePriorityGroup2() { addClass("test.methodselectors.SampleTest"); addMethodSelector("test.methodselectors.Test2MethodSelector", -1); run(); String[] passed = { "test2", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void lessThanPriorityTest1Test() { addClass("test.methodselectors.SampleTest"); addIncludedGroup("test1"); addMethodSelector("test.methodselectors.Test2MethodSelector", 5); run(); String[] passed = { "test1", "test2", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void greaterThanPriorityTest1Test2() { addClass("test.methodselectors.SampleTest"); addIncludedGroup("test1"); addMethodSelector("test.methodselectors.Test2MethodSelector", 15); run(); String[] passed = { "test2", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void lessThanPriorityAllTests() { addClass("test.methodselectors.SampleTest"); addIncludedGroup("test1"); addMethodSelector("test.methodselectors.AllTestsMethodSelector", 5); run(); String[] passed = { "test1", "test2", "test3" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } public static void ppp(String s) { System.out.println("[MethodSelectorTest] " + s); } } testng-6.9.12/src/test/java/test/methodselectors/NoTest1MethodSelector.java0000644000175000017500000000165412732165123026303 0ustar eugeneeugenepackage test.methodselectors; import org.testng.IMethodSelector; import org.testng.IMethodSelectorContext; import org.testng.ITestNGMethod; import java.util.List; public class NoTest1MethodSelector implements IMethodSelector { /** * */ private static final long serialVersionUID = 6706869410370733524L; @Override public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod) { for (String group : method.getGroups()) { if (group.equals("test1")) { ppp( method.getMethodName() + " is group test1, don't include" ); context.setStopped(true); return false; } } ppp( method.getMethodName() + " is not in group test1" ); return true; } @Override public void setTestMethods(List testMethods) { } public static void ppp(String s) { //System.out.println("[NoTest1MethodSelector] " + s); } } testng-6.9.12/src/test/java/test/inject/0000755000175000017500000000000012732165123017343 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/inject/InjectTestResultTest.java0000644000175000017500000000070112732165123024317 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class InjectTestResultTest extends SimpleBaseTest { @Test public void verifyTestResultInjection() { TestNG tng = create(InjectBeforeAndAfterMethodsWithTestResultSampleTest.class); tng.run(); Assert.assertEquals(0, InjectBeforeAndAfterMethodsWithTestResultSampleTest.m_success); } } testng-6.9.12/src/test/java/test/inject/InjectDataProviderTest.java0000644000175000017500000000252712732165123024575 0ustar eugeneeugenepackage test.inject; import org.testng.ITestContext; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import test.dataprovider.MyIterator; import java.util.Iterator; /** * Test that injection works for data providers. * * @author Cedric Beust, Mar 3, 2010 * */ public class InjectDataProviderTest { @DataProvider public Object[][] dp1() { return new Object[][] { new Object[] { 1, "a" }, new Object[] { 2, "b" }, }; } @Test(dataProvider = "dp1", enabled = true) public void dpObject1(Integer n, ITestContext ctx, String a) { } @Test(dataProvider = "dp1", enabled = true) public void dpObject2(ITestContext ctx, Integer n, String a) { } @Test(dataProvider = "dp1", enabled = true) public void dpObject3(Integer n, String a, ITestContext ctx) { } @DataProvider public Iterator dp2() { return new MyIterator( new Object[][] { new Object[] { 1, "a" }, new Object[] { 2, "b" }, }); } @Test(dataProvider = "dp2", enabled = false) public void dpIterator1(Integer n, ITestContext ctx, String a) { } @Test(dataProvider = "dp2", enabled = false) public void dpIterator2(ITestContext ctx, Integer n, String a) { } @Test(dataProvider = "dp2", enabled = false) public void dpIterator3(Integer n, String a, ITestContext ctx) { } } testng-6.9.12/src/test/java/test/inject/InjectBeforeMethodTest.java0000644000175000017500000000177712732165123024562 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.reflect.Method; public class InjectBeforeMethodTest { private int m_beforeIndex = 0; private int m_afterIndex = 0; private static final Object[][] DATA = { new Object[] { "a" }, new Object[] { "b" }, }; @BeforeMethod public void before(Object[] parameters) { Assert.assertEquals(DATA[m_beforeIndex], parameters); m_beforeIndex++; } @BeforeMethod public void before2(Object[] parameters, Method m) { } @BeforeMethod public void before3(Method m, Object[] parameters) { } @DataProvider public Object[][] dp() { return DATA; } @AfterMethod public void after(Object[] parameters) { Assert.assertEquals(DATA[m_afterIndex], parameters); m_afterIndex++; } @Test(dataProvider = "dp") public void f(String a) { } } testng-6.9.12/src/test/java/test/inject/Sample.java0000644000175000017500000000064712732165123021436 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.annotations.Test; public class Sample { @Test public void f(ITestContext tc) { Assert.assertNotNull(tc); ITestNGMethod[] allMethods = tc.getAllTestMethods(); Assert.assertEquals(allMethods.length, 1); Assert.assertEquals(allMethods[0].getMethod().getName(),"f"); } } testng-6.9.12/src/test/java/test/inject/InjectAfterMethodWithTestResultTest.java0000644000175000017500000000067412732165123027307 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class InjectAfterMethodWithTestResultTest extends SimpleBaseTest { @Test public void verifyTestResultInjection() { TestNG tng = create(InjectAfterMethodWithTestResultSampleTest.class); tng.run(); Assert.assertEquals(0, InjectAfterMethodWithTestResultSampleTest.m_success); } } testng-6.9.12/src/test/java/test/inject/InjectTestContextTest.java0000644000175000017500000000167212732165123024475 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.ITestContext; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import org.testng.xml.XmlTest; import test.SimpleBaseTest; public class InjectTestContextTest extends SimpleBaseTest { @Test(enabled = false) public void verifyTestContextInjection(ITestContext tc, XmlTest xmlTest) { TestNG tng = create(); tng.setTestClasses(new Class[] { Sample.class }); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(xmlTest.getName(), "Injection"); Assert.assertEquals(tla.getPassedTests().size(), 1); Assert.assertEquals(tla.getPassedTests().get(0).getMethod().getMethodName(), "f"); } @Parameters("string") @Test(enabled = true) public void injectionAndParameters(String s, ITestContext ctx) { } } testng-6.9.12/src/test/java/test/inject/InjectAfterMethodWithTestResultSampleTest.java0000644000175000017500000000206212732165123030442 0ustar eugeneeugenepackage test.inject; import org.testng.ITestResult; import org.testng.SkipException; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.lang.reflect.Method; public class InjectAfterMethodWithTestResultSampleTest { static int m_success; @Test public void pass() {} @Test public void fail() { throw new RuntimeException(); } @Test public void skip() { throw new SkipException("Skipped"); } @BeforeClass public void init() { m_success = 3; } @BeforeMethod public void before(Method m, ITestResult r) { System.out.println("Before result: " + r); } @AfterMethod public void after(Method m, ITestResult r) { String name = m.getName(); if (("pass".equals(name) && r.getStatus() == ITestResult.SUCCESS) || ("fail".equals(name) && r.getStatus() == ITestResult.FAILURE) || ("skip".equals(name) && r.getStatus() == ITestResult.SKIP)) { m_success--; } } } testng-6.9.12/src/test/java/test/inject/InjectBeforeAndAfterMethodsWithTestResultSampleTest.java0000644000175000017500000000236212732165123032376 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.ITestResult; import org.testng.SkipException; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.lang.reflect.Method; public class InjectBeforeAndAfterMethodsWithTestResultSampleTest { static int m_success; private ITestResult m_testResult; @Test public void pass() { Assert.assertEquals(m_testResult.getAttribute("before"), 10); } @Test public void fail() { throw new RuntimeException(); } @Test public void skip() { throw new SkipException("Skipped"); } @BeforeClass public void init() { m_success = 3; } @BeforeMethod public void before(Method m, ITestResult r) { m_testResult = r; r.setAttribute("before", 10); } @AfterMethod public void after(Method m, ITestResult r) { String name = m.getName(); Assert.assertEquals(r, m_testResult); if (("pass".equals(name) && r.getStatus() == ITestResult.SUCCESS) || ("fail".equals(name) && r.getStatus() == ITestResult.FAILURE) || ("skip".equals(name) && r.getStatus() == ITestResult.SKIP)) { m_success--; } } } testng-6.9.12/src/test/java/test/inject/NoInjectionTest.java0000644000175000017500000000140412732165123023264 0ustar eugeneeugenepackage test.inject; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.NoInjection; import org.testng.annotations.Test; import java.lang.reflect.Method; /** * Test the @NoInjection annotation. * * @author cbeust */ public class NoInjectionTest { @DataProvider(name = "provider") public Object[][] provide() throws Exception { return new Object[][] { { CC.class.getMethod("f") } }; } @Test(dataProvider = "provider") public void withoutInjection(@NoInjection Method m) { Assert.assertEquals(m.getName(), "f"); } @Test(dataProvider = "provider") public void withInjection(Method m) { Assert.assertEquals(m.getName(), "withInjection"); } } class CC { public void f() { } } testng-6.9.12/src/test/java/test/groupinvocation/0000755000175000017500000000000012732165123021315 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/groupinvocation/DummyTest2.java0000644000175000017500000000075212732165123024201 0ustar eugeneeugenepackage test.groupinvocation; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; /** * This class/interface */ public class DummyTest2 { private boolean m_invoked= false; @Test(groups={"A"}) public void dummyTest() { m_invoked= true; } @AfterClass(alwaysRun=true) public void checkInvocations() { Assert.assertFalse(m_invoked, "@Test method invoked even if @BeforeGroups failed"); } } testng-6.9.12/src/test/java/test/groupinvocation/GroupConfiguration.java0000644000175000017500000000071012732165123026002 0ustar eugeneeugenepackage test.groupinvocation; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; /** * This class/interface */ public class GroupConfiguration { @BeforeGroups(groups={"a"}) public void beforeGroups() { DummyTest.recordInvocation("beforeGroups", hashCode()); } @AfterGroups(groups={"a"}) public void afterGroups() { DummyTest.recordInvocation("afterGroups", hashCode()); } } testng-6.9.12/src/test/java/test/groupinvocation/testng.xml0000644000175000017500000000156712732165123023354 0ustar eugeneeugene testng-6.9.12/src/test/java/test/groupinvocation/GroupSuiteSampleTest.java0000644000175000017500000000034112732165123026266 0ustar eugeneeugenepackage test.groupinvocation; import org.testng.annotations.Test; public class GroupSuiteSampleTest { @Test(groups = "a") public void a() {} @Test(groups = "b") public void b() {} @Test public void c() {} } testng-6.9.12/src/test/java/test/groupinvocation/DummyTest.java0000644000175000017500000000223312732165123024113 0ustar eugeneeugenepackage test.groupinvocation; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import java.util.HashMap; import java.util.Map; /** * This class/interface */ public class DummyTest { private static Map s_externalClassGroups= new HashMap<>(); @Test(groups={"a"}) public void testA() { } @Test(groups={"b"}) public void testB() { } @Test(groups={"a", "b"}) public void testAB() { } @AfterClass(alwaysRun=true) public void checkInvocations() { Integer hashCode1= s_externalClassGroups.get("beforeGroups"); Assert.assertNotNull(hashCode1, "External @BeforeGroups not invoked"); Integer hashCode2= s_externalClassGroups.get("afterGroups"); Assert.assertNotNull(hashCode2, "External @AfterGroups not invoked"); Assert.assertEquals(hashCode1, hashCode2, "External @BeforeGroups and @AfterGroups were not invoked on the" + " same class instance"); } /** * @param string * @param i */ public static void recordInvocation(String string, int i) { s_externalClassGroups.put(string, i); } } testng-6.9.12/src/test/java/test/groupinvocation/FailingBeforeGroupMethod.java0000644000175000017500000000046312732165123027035 0ustar eugeneeugenepackage test.groupinvocation; import org.testng.annotations.BeforeGroups; /** * This class/interface */ public class FailingBeforeGroupMethod { @BeforeGroups(groups={"A"}) public void beforeGroupA() { throw new RuntimeException("Failing @BeforeGroups beforeGroupA method"); } } testng-6.9.12/src/test/java/test/groupinvocation/GroupSuiteTest.java0000644000175000017500000000406512732165123025133 0ustar eugeneeugenepackage test.groupinvocation; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; /** * Test that tags can have groups. */ @Test public class GroupSuiteTest extends SimpleBaseTest { public void includeFromSuite0() { runWithSuite(g(), g(), g("a", "b", "c")); } public void includeFromSuite1() { runWithSuite(g("a"), g(), g("a")); } public void includeFromSuite2() { runWithSuite(g("a", "b"), g(), g("a", "b")); } public void excludeFromSuite1() { runWithSuite(g(), g("a"), g("b", "c")); } public void excludeFromSuite2() { runWithSuite(g(), g("a", "b"), g("c")); } @Test(description = "Include in both suite and test") public void includeTestAndSuite1() { runWithSuite(g("a"), g(), g("b"), g(), g("a", "b")); } @Test(description = "Include in suite, exclude in test") public void excludeTestAndSuite2() { runWithSuite(g(), g("a"), g(), g("a"), g("b", "c")); } private void runWithSuite(String[] suiteGroups, String[] excludedSuiteGroups, String[] methods) { runWithSuite(suiteGroups, excludedSuiteGroups, g(), g(), methods); } private void runWithSuite(String[] suiteGroups, String[] excludedSuiteGroups, String[] testGroups, String[] excludedTestGroups, String[] methods) { XmlSuite s = createXmlSuite("Groups"); s.setIncludedGroups(Arrays.asList(suiteGroups)); s.setExcludedGroups(Arrays.asList(excludedSuiteGroups)); XmlTest t = createXmlTest(s, "Groups-test", GroupSuiteSampleTest.class.getName()); t.setIncludedGroups(Arrays.asList(testGroups)); t.setExcludedGroups(Arrays.asList(excludedTestGroups)); TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.addListener(tla); tng.setXmlSuites(Arrays.asList(new XmlSuite[] { s })); tng.run(); verifyPassedTests(tla, methods); } private String[] g(String... groups) { return groups; } } testng-6.9.12/src/test/java/test/privatemethod/0000755000175000017500000000000012732165123020742 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/privatemethod/PrivateMethodTest.java0000644000175000017500000000076012732165123025223 0ustar eugeneeugenepackage test.privatemethod; import org.testng.Assert; import org.testng.annotations.Test; public class PrivateMethodTest { public PrivateMethodTest(String name, int value) { } private int privateMethod() { return 1; } public static class PrivateMethodInnerTest { @Test public void testPrivateMethod() { PrivateMethodTest pmt = new PrivateMethodTest("aname", 1); int returnValue = pmt.privateMethod(); Assert.assertEquals(returnValue, 1); } } } testng-6.9.12/src/test/java/test/Exclude.java0000644000175000017500000000207712732165123020331 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; public class Exclude { private boolean m_included1 = false; private boolean m_included2 = false; private boolean m_excluded1 = true; private boolean m_excluded2 = true; @Test(groups = { "group1"} ) public void included1() { ppp("INCLUDED1"); m_included1 = true; } @Test(groups = { "group1"} ) public void included2() { ppp("INCLUDED2"); m_included2 = true; } @Test(groups = { "group1"} ) public void excluded1() { ppp("EXCLUDED1"); m_excluded1 = false; } @Test(groups = { "group1"} ) public void excluded2() { ppp("EXCLUDED1"); m_excluded2 = false; } @Test(dependsOnGroups = { "group1" }, groups = {"group2"} ) public void verify() { ppp("VERIFY"); assert m_included1 && m_included2 && m_excluded1 && m_excluded2: "Should all be true: " + m_included1 + " " + m_included2 + " " + m_excluded1 + " " + m_excluded2; } static private void ppp(String s) { if (false) { System.out.println("[Exclude] " + s); } } } testng-6.9.12/src/test/java/test/dependent/0000755000175000017500000000000012732165123020035 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/dependent/xml/0000755000175000017500000000000012732165123020635 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/dependent/xml/GroupDependencyTest.java0000644000175000017500000000416112732165123025435 0ustar eugeneeugenepackage test.dependent.xml; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; public class GroupDependencyTest extends SimpleBaseTest { @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { new String[] { "a", "b", "c", "a1", "b1", "c1" } }, new Object[] { new String[] { "a", "c", "b", "a1", "c1", "b1" } }, new Object[] { new String[] { "b", "a", "c", "b1", "a1", "c1" } }, new Object[] { new String[] { "b", "c", "a", "b1", "c1", "a1" } }, new Object[] { new String[] { "c", "b", "a", "c1", "b1", "a1" } }, new Object[] { new String[] { "c", "a", "b", "c1", "a1", "b1" } }, }; } @Test(dataProvider = "dp") public void verifyGroupSingle(String[] a) { configureGroup(a, false /* single */); } @Test(dataProvider = "dp") public void verifyGroupMulti(String[] a) { configureGroup(a, true /* multi */); } private void configureGroup(String[] a, boolean multi) { XmlSuite suite = createXmlSuite("Dependencies"); XmlTest test = createXmlTest(suite, "DependencyTest", GroupDependencySampleTest.class.getName()); if (multi) { test.addXmlDependencyGroup(a[2], a[1] + " " + a[0]); } else { test.addXmlDependencyGroup(a[2], a[1]); test.addXmlDependencyGroup(a[1], a[0]); } TestNG tng = create(); tng.setXmlSuites(Arrays.asList(suite)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); List t = tla.getPassedTests(); String method2 = t.get(2).getMethod().getMethodName(); if (multi) { // When we have "a depends on groups b and c", the only certainty is that "a" // will be run last Assert.assertEquals(method2, a[5]); } else { assertTestResultsEqual(tla.getPassedTests(), Arrays.asList(a[3], a[4], a[5])); } } } testng-6.9.12/src/test/java/test/dependent/xml/GroupDependencySampleTest.java0000644000175000017500000000036412732165123026600 0ustar eugeneeugenepackage test.dependent.xml; import org.testng.annotations.Test; public class GroupDependencySampleTest { @Test(groups = "a") public void a1() {} @Test(groups = "b") public void b1() {} @Test(groups = "c") public void c1() {} } testng-6.9.12/src/test/java/test/dependent/BaseOrderMethodTest.java0000644000175000017500000000177212732165123024556 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; /** * This class * * @author Cedric Beust, Aug 20, 2004 * */ public class BaseOrderMethodTest { protected boolean[] m_group1 = { false, false }; protected boolean[] m_group2 = { false, false }; protected boolean[] m_group3 = { false }; @Test(groups = { "2.0" }, dependsOnGroups = { "1.0", "1.1" }) public void a_second0() { verifyGroup(2, m_group1); m_group2[0] = true; } @Test(groups = { "3" }, dependsOnGroups = { "2.0" }) public void third0() { verifyGroup(3, m_group2); m_group3[0] = true; } public static void ppp(String s) { System.out.println("[BaseOrderMethodTest] " + s); } protected void verifyGroup(int groupNumber, boolean[] group) { for (int i = 0; i < group.length; i++) { assert group[i] : "Error while running group " + groupNumber + ": " + " index " + i + " of previous group should have been run before."; } } } testng-6.9.12/src/test/java/test/dependent/MultiGroup1SampleTest.java0000644000175000017500000000041012732165123025065 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; @Test(groups = { "checkin" }) public class MultiGroup1SampleTest { @Test(groups = {"a"}) public void testA() { } public void test1() throws Exception { throw new Exception("fail"); } } testng-6.9.12/src/test/java/test/dependent/SD2.java0000644000175000017500000000115512732165123021272 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; public class SD2 { public static List m_log = new ArrayList<>(); @Test(groups = { "one" }) public void oneA() { m_log.add("oneA"); } @Test public void canBeRunAnytime() { m_log.add("canBeRunAnytime"); } @Test(dependsOnGroups = { "one" } ) public void secondA() { m_log.add("secondA"); } @Test(dependsOnMethods= { "secondA" }) public void thirdA() { m_log.add("thirdA"); } @Test(groups = { "one" }) public void oneB() { m_log.add("oneB"); } }testng-6.9.12/src/test/java/test/dependent/SampleDependent1.java0000644000175000017500000000057412732165123024037 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; /** * This class exercises dependent groups * * @author Cedric Beust, Aug 19, 2004 * */ public class SampleDependent1 { @Test(groups = { "fail" }) public void fail() { Assert.assertTrue(false); } @Test(dependsOnGroups = { "fail" }) public void shouldBeSkipped() { } } testng-6.9.12/src/test/java/test/dependent/ImplicitGroupInclusion4SampleTest.java0000644000175000017500000000156212732165123027445 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ImplicitGroupInclusion4SampleTest { private boolean m_m1, m_m2, m_m3, m_m4; @BeforeClass(groups = {"g2"}) public void init() { m_m1 = m_m2 = m_m3 = m_m4 = false; } @Test (groups = {"g1"}) public void m1() { m_m1 = true; } @Test (groups = {"g1"}, dependsOnMethods="m1") public void m2() { m_m2 = true; } @Test (groups = {"g2"}) public void m3() { m_m3 = true; } @Test (groups = {"g2"}, dependsOnMethods="m3") public void m4() { m_m4 = true; } @AfterClass(groups = {"g2"}) public void verify() { Assert.assertFalse(m_m1, "Shouldn't have invoked m1()"); Assert.assertFalse(m_m2); Assert.assertTrue(m_m3); Assert.assertTrue(m_m4); } }testng-6.9.12/src/test/java/test/dependent/SampleDependentMethods4.java0000644000175000017500000000061512732165123025362 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; /** * This class * * @author cbeust */ public class SampleDependentMethods4 { @Test public void step1() { } @Test(dependsOnMethods = { "step1" }) public void step2() { Assert.assertTrue(false, "Problem in step2"); } @Test(dependsOnMethods = { "step2" }) public void step3() { } } testng-6.9.12/src/test/java/test/dependent/DependentOnMethod1AlwaysRunSampleTest.java0000644000175000017500000000114112732165123030172 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; /** * a will fail but b should run anyway because of alwaysRun=true * * Created on Nov 18, 2005 * @author cbeust */ public class DependentOnMethod1AlwaysRunSampleTest { private boolean m_ok = false; @Test public void a() { throw new RuntimeException("Voluntary failure"); } @Test(dependsOnMethods = {"a"}, alwaysRun = true) public void b() { m_ok = true; } @Test(dependsOnMethods = {"b"}) public void verify() { Assert.assertTrue(m_ok, "method b() should have been invoked"); } } testng-6.9.12/src/test/java/test/dependent/GroupByInstancesTest.java0000644000175000017500000000230112732165123024773 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.collections.Lists; import test.SimpleBaseTest; import java.util.List; public class GroupByInstancesTest extends SimpleBaseTest { @Test public void dontGroupByInstances() { runTest(false); } @Test public void groupByInstances() { runTest(true); } private void runTest(boolean group) { TestNG tng = create(GroupByInstancesSampleTest.class); GroupByInstancesSampleTest.m_log = Lists.newArrayList(); tng.setGroupByInstances(group); tng.run(); List log = GroupByInstancesSampleTest.m_log; int i = 0; if (group) { Assert.assertTrue(log.get(i++).startsWith("signIn")); Assert.assertTrue(log.get(i++).startsWith("signOut")); Assert.assertTrue(log.get(i++).startsWith("signIn")); Assert.assertTrue(log.get(i++).startsWith("signOut")); } else { Assert.assertTrue(log.get(i++).startsWith("signIn")); Assert.assertTrue(log.get(i++).startsWith("signIn")); Assert.assertTrue(log.get(i++).startsWith("signOut")); Assert.assertTrue(log.get(i++).startsWith("signOut")); } } } testng-6.9.12/src/test/java/test/dependent/ImplicitGroupInclusion3SampleTest.java0000644000175000017500000000060612732165123027442 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; public class ImplicitGroupInclusion3SampleTest { @Test( groups = {"inc"} ) public void test1() {} @Test( groups = {"exc"} ) public void test2() { throw new RuntimeException("exclude me"); } @Test( groups = {"exc"}, dependsOnMethods={"test2"} ) public void test3() { throw new RuntimeException("exclude me"); } }testng-6.9.12/src/test/java/test/dependent/MultipleDependentSampleTest.java0000644000175000017500000000056312732165123026330 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; public class MultipleDependentSampleTest { @Test public void init() {} @Test(dependsOnMethods = "init") public void fail() { Assert.fail(); } @Test(dependsOnMethods = "fail") public void skip1() {} @Test(dependsOnMethods = "skip1") public void skip2() {} } testng-6.9.12/src/test/java/test/dependent/DependentOnGroup2AlwaysRunSampleTest.java0000644000175000017500000000126512732165123030056 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; /** * a will fail but b should run anyway because of alwaysRun=true * * Created on Nov 18, 2005 * @author cbeust */ public class DependentOnGroup2AlwaysRunSampleTest { private boolean m_ok = false; @Test(groups = { "group-a"}) public void a() { throw new RuntimeException("Voluntary failure"); } @Test(groups = { "group-a"}) public void a2() { } @Test(dependsOnGroups = {"group-a"}, alwaysRun = true) public void b() { m_ok = true; } @Test(dependsOnMethods = {"b"}) public void verify() { Assert.assertTrue(m_ok, "method b() should have been invoked"); } } testng-6.9.12/src/test/java/test/dependent/DifferentClassDependsOnGroupsTest2.java0000644000175000017500000000027312732165123027520 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; public class DifferentClassDependsOnGroupsTest2 { @Test(dependsOnGroups = { "mainGroup" }) public void test1() { } } testng-6.9.12/src/test/java/test/dependent/SampleDependentMethods6.java0000644000175000017500000000043312732165123025362 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; /** * This class * * @author cbeust */ public class SampleDependentMethods6 { @Test(dependsOnMethods = { "step2" }) public void step1() { } @Test(dependsOnMethods = { "step1" }) public void step2() { } } testng-6.9.12/src/test/java/test/dependent/DependencyFixTest.java0000644000175000017500000000111312732165123024261 0ustar eugeneeugenepackage test.dependent; import static org.testng.Assert.assertTrue; import org.testng.annotations.Test; public class DependencyFixTest { @Test(dependsOnMethods = "helloWorld", ignoreMissingDependencies = true) public void dependentOnNonExistingMethod() { assertTrue(true); } @Test(dependsOnMethods = "dependentOnNonExistingMethod") public void dependentOnExistingMethod() { assertTrue(true); } @Test(groups = "selfSufficient", dependsOnGroups = "nonExistingGroup", ignoreMissingDependencies = true) public void dependentOnNonExistingGroup() { assertTrue(true); } } testng-6.9.12/src/test/java/test/dependent/MultiGroup2SampleTest.java0000644000175000017500000000032712732165123025075 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; @Test(groups = {"integration"}, dependsOnGroups = {"checkin", "a"}) public class MultiGroup2SampleTest { public void test2() throws Exception { } } testng-6.9.12/src/test/java/test/dependent/MissingMethodSampleTest.java0000644000175000017500000000156412732165123025462 0ustar eugeneeugenepackage test.dependent; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.Parser; import java.io.ByteArrayInputStream; public class MissingMethodSampleTest { @Test(dependsOnMethods="missingMethod", ignoreMissingDependencies=true) public void explicitlyIgnoreMissingMethod() { } @Test(dependsOnMethods="missingMethod", alwaysRun=true) public void alwaysRunDespiteMissingMethod() {} public static void main(String[] args) throws Exception { TestNG tng = new TestNG(); String xml = "" + "" + ""; System.out.println(xml); ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes()); tng.setXmlSuites(new Parser(is).parseToList()); tng.run(); } } testng-6.9.12/src/test/java/test/dependent/ImplicitMethodInclusionSampleTest.java0000644000175000017500000000057012732165123027503 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; public class ImplicitMethodInclusionSampleTest { @Test(groups = {"linux"}) public void a() { // ppp("A"); } @Test(groups = {"linux", "windows"} , dependsOnMethods={"a"}) public void b() { // ppp("B"); } private void ppp(String string) { System.out.println("[Implicit] " + string); } } testng-6.9.12/src/test/java/test/dependent/InstanceSkipSampleTest.java0000644000175000017500000000214712732165123025301 0ustar eugeneeugenepackage test.dependent; import java.util.List; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; import org.testng.collections.Lists; /** * Verify that only instances that fail cause dependency failures. In other words, * when run, this test should show: * passed = [f#1 f#3 g#1 g#3], failed = [f#2], skipped = [g#2] * * @author Cedric Beust */ public class InstanceSkipSampleTest { private int m_n; public static List m_list = Lists.newArrayList(); @Factory(dataProvider = "dp") public InstanceSkipSampleTest(int n) { m_n = n; } @DataProvider public static Object[][] dp() { return new Object[][] { new Object[] { 1 }, new Object[] { 2 }, new Object[] { 3 }, }; } @Test public void f() { if (m_n == 2) throw new RuntimeException(); log("f"); } @Test(dependsOnMethods = "f") public void g() { log("g"); } private void log(String s) { m_list.add(s + "#" + m_n); } @Override public String toString() { return "" + m_n; } } testng-6.9.12/src/test/java/test/dependent/DepthDependencyTest.java0000644000175000017500000000052512732165123024605 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; public class DepthDependencyTest { @Test(groups = { "1"} ) public void f1() { throw new RuntimeException(); } @Test(groups = { "2"}, dependsOnGroups = {"1"} ) public void f2() { } @Test(groups = { "3"}, dependsOnGroups = {"2"} ) public void f3() { } } testng-6.9.12/src/test/java/test/dependent/ImplicitGroupInclusion2SampleTest.java0000644000175000017500000000136112732165123027440 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ImplicitGroupInclusion2SampleTest { private boolean m_m1, m_m2, m_m3; @BeforeClass(groups = {"g2"}) public void init() { m_m1 = m_m2 = m_m3 = false; } @Test (groups = {"g1"}) public void m1() { m_m1 = true; } @Test (groups = {"g1"}, dependsOnMethods="m1") public void m2() { m_m2 = true; } @Test (groups = {"g2"}) public void m3() { m_m3 = true; } @AfterClass(groups = {"g2"}) public void verify() { Assert.assertFalse(m_m1, "Shouldn't have invoked m1()"); Assert.assertFalse(m_m2); Assert.assertTrue(m_m3); } }testng-6.9.12/src/test/java/test/dependent/DependentWithDataProviderSampleTest.java0000644000175000017500000000217412732165123027755 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; import org.testng.collections.Lists; import java.util.List; public class DependentWithDataProviderSampleTest { public static List m_log = Lists.newArrayList(); private String param; @Factory( dataProvider = "prov" ) public DependentWithDataProviderSampleTest( String param ) { this.param = param; } @DataProvider( name = "prov" ) public static Object[][] dataProvider() { return new Object[][] { { "One" }, { "Two" }, { "Three" }, }; } private void log(String s) { m_log.add(s + "#" + param); } @BeforeClass public void prepare() { log("prepare"); } @Test public void test1() { log("test1"); } @Test( dependsOnMethods = "test1" ) public void test2() { log("test2"); } @AfterClass public void clean() { log("clean"); } @Override public String toString() { return "[" + param + "]"; } } testng-6.9.12/src/test/java/test/dependent/DependentAlwaysRunTest.java0000644000175000017500000000265312732165123025322 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import test.BaseTest; public class DependentAlwaysRunTest extends BaseTest { @Test public void verifyDependsOnMethodsAlwaysRun() { addClass("test.dependent.DependentOnMethod1AlwaysRunSampleTest"); run(); String[] passed = { "b", "verify" }; String[] failed = { "a" }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyDependsOnGroups1AlwaysRun() { addClass("test.dependent.DependentOnGroup1AlwaysRunSampleTest"); run(); String[] passed = { "b", "verify" }; String[] failed = { "a" }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyDependsOnGroups2AlwaysRun() { addClass("test.dependent.DependentOnGroup2AlwaysRunSampleTest"); run(); String[] passed = { "a2", "b", "verify" }; String[] failed = { "a" }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dependent/SampleDependentMethods5.java0000644000175000017500000000041112732165123025355 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; /** * This class * * @author cbeust */ public class SampleDependentMethods5 { @Test public void step1() { } @Test(dependsOnMethods = { "step1", "blablabla" }) public void step2() { } } testng-6.9.12/src/test/java/test/dependent/MultiGroupTest.java0000644000175000017500000000116512732165123023652 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import test.BaseTest; public class MultiGroupTest extends BaseTest { @Test public void verifyDependsOnMultiGroups() { addClass(MultiGroup1SampleTest.class.getName()); addClass(MultiGroup2SampleTest.class.getName()); run(); String[] passed = { "testA", }; String[] failed = { "test1" }; String[] skipped = { "test2" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dependent/DependsOnProtectedMethodTest.java0000644000175000017500000000122012732165123026425 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * This class/interface */ public class DependsOnProtectedMethodTest { private boolean m_before1 = false; private boolean m_before2 = false; @BeforeMethod(dependsOnMethods = { "before2" }) protected void before() { m_before1 = true; } @BeforeMethod protected void before2() { m_before2 = true; } @Test public void verifyBeforeInvocations() { Assert.assertTrue(m_before1 && m_before2, "Protected dependent @BeforeMethods should have been invoked"); } } testng-6.9.12/src/test/java/test/dependent/GroupByInstancesSampleTest.java0000644000175000017500000000206312732165123026142 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; import org.testng.collections.Lists; import java.util.List; public class GroupByInstancesSampleTest { private String m_country; public static List m_log = Lists.newArrayList(); private static void log(String method, String country) { // System.out.println("LOG:" + method + "#" + country + " " + Thread.currentThread().getId()); m_log.add(method + "#" + country); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { "usa" }, new Object[] { "uk" }, }; } @Factory(dataProvider = "dp") public GroupByInstancesSampleTest(String country) { m_country = country; } @Test public void signIn() { log("signIn", m_country); } @Test(dependsOnMethods = "signIn") public void signOut() { log("signOut", m_country); } @Override public String toString() { return "[GroupByInstancesSampleTest: " + m_country + "]"; } } testng-6.9.12/src/test/java/test/dependent/functionality1/0000755000175000017500000000000012732165123023006 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/dependent/functionality1/Config.java0000644000175000017500000000035312732165123025057 0ustar eugeneeugenepackage test.dependent.functionality1; import org.testng.annotations.BeforeSuite; public class Config { @BeforeSuite (groups = "other") public void beforeSuite(){ System.out.println("BeforeSuite group 'other'"); } } testng-6.9.12/src/test/java/test/dependent/functionality1/Test2.java0000644000175000017500000000050212732165123024647 0ustar eugeneeugenepackage test.dependent.functionality1; import org.testng.annotations.Test; @Test(groups = "tests.functional.upload", dependsOnGroups = "tests.functional.package") public class Test2 { public void test2_1() { System.out.println("Test 2_1"); } public void test2_2() { System.out.println("Test 2_2"); } } testng-6.9.12/src/test/java/test/dependent/functionality1/Test1.java0000644000175000017500000000043512732165123024653 0ustar eugeneeugenepackage test.dependent.functionality1; import org.testng.annotations.Test; @Test (groups = "tests.functional.package") public class Test1 { public void test1_1(){ System.out.println("Test 1_1"); } public void test1_2(){ System.out.println("Test 1_2"); } } testng-6.9.12/src/test/java/test/dependent/Test1.java0000644000175000017500000000006112732165123021675 0ustar eugeneeugenepackage test.dependent; public class Test1 { } testng-6.9.12/src/test/java/test/dependent/DifferentClassDependsOnGroupsTest1.java0000644000175000017500000000051712732165123027520 0ustar eugeneeugenepackage test.dependent; import static org.testng.Assert.assertTrue; import org.testng.annotations.Test; public class DifferentClassDependsOnGroupsTest1 { @Test(groups = { "mainGroup" }) public void test0() { assertTrue(1 == 0); // Force a failure } @Test(dependsOnGroups= {"mainGroup"}) public void test2() { } } testng-6.9.12/src/test/java/test/dependent/SampleDependentMethods.java0000644000175000017500000000312112732165123025271 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; /** * This class exercises dependent methods * * @author Cedric Beust, Aug 19, 2004 * */ public class SampleDependentMethods { private boolean m_oneA = false; private boolean m_oneB = false; private boolean m_secondA = false; private boolean m_thirdA = false; @Test public void oneA() { // ppp("oneA"); // assert false : "TEMPORARY FAILURE"; assert ! m_secondA : "secondA shouldn't have been run yet"; m_oneA = true; } @Test public void canBeRunAnytime() { } @Test(dependsOnMethods= { "oneA", "oneB" }) public void secondA() { // ppp("secondA"); assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert ! m_secondA : "secondA shouldn't have been run yet"; m_secondA = true; } @Test(dependsOnMethods= { "secondA" }) public void thirdA() { // ppp("thirdA"); assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert m_secondA : "secondA wasn't run"; assert ! m_thirdA : "thirdA shouldn't have been run yet"; m_thirdA = true; } @Test public void oneB() { // ppp("oneB"); assert ! m_secondA : "secondA shouldn't have been run yet"; m_oneB = true; } @AfterClass public void tearDown() { assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert m_secondA : "secondA wasn't run"; assert m_thirdA : "thirdA wasn't run"; } public static void ppp(String s) { System.out.println("[SampleDependentMethods] " + s); } }testng-6.9.12/src/test/java/test/dependent/DependentTest.java0000644000175000017500000000720212732165123023447 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Test; import test.BaseTest; import test.SimpleBaseTest; import java.util.List; public class DependentTest extends BaseTest { @Test public void simpleSkip() { addClass(SampleDependent1.class.getName()); run(); String[] passed = {}; String[] failed = { "fail" }; String[] skipped = { "shouldBeSkipped" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void dependentMethods() { addClass(SampleDependentMethods.class.getName()); run(); String[] passed = { "oneA", "oneB", "secondA", "thirdA", "canBeRunAnytime" }; String[] failed = {}; String[] skipped = {}; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void dependentMethodsWithSkip() { addClass(SampleDependentMethods4.class.getName()); run(); String[] passed = { "step1", }; String[] failed = { "step2", }; String[] skipped = { "step3" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test @ExpectedExceptions({ org.testng.TestNGException.class }) public void dependentMethodsWithNonExistentMethod() { addClass(SampleDependentMethods5.class.getName()); run(); String[] passed = { "step1", "step2" }; String[] failed = {}; String[] skipped = {}; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test(expectedExceptions = org.testng.TestNGException.class) public void dependentMethodsWithCycle() { addClass(SampleDependentMethods6.class.getName()); run(); } @Test(expectedExceptions = org.testng.TestNGException.class) public void dependentGroupsWithCycle() { addClass("test.dependent.SampleDependentMethods7"); run(); } @Test public void multipleSkips() { addClass(MultipleDependentSampleTest.class.getName()); run(); String[] passed = { "init", }; String[] failed = { "fail", }; String[] skipped = { "skip1", "skip2" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void instanceDependencies() { addClass(InstanceSkipSampleTest.class.getName()); run(); verifyInstanceNames("Passed", getPassedTests(), new String[] { "f#1", "f#3", "g#1", "g#3"}); verifyInstanceNames("Failed", getFailedTests(), new String[] { "f#2" }); verifyInstanceNames("Skipped", getSkippedTests(), new String[] { "g#" }); } @Test public void dependentWithDataProvider() { TestNG tng = SimpleBaseTest.create(DependentWithDataProviderSampleTest.class); tng.setGroupByInstances(true); List log = DependentWithDataProviderSampleTest.m_log; log.clear(); tng.run(); for (int i = 0; i < 12; i += 4) { String[] s = log.get(i).split("#"); String instance = s[1]; Assert.assertEquals(log.get(i), "prepare#" + instance); Assert.assertEquals(log.get(i + 1), "test1#" + instance); Assert.assertEquals(log.get(i + 2), "test2#" + instance); Assert.assertEquals(log.get(i + 3), "clean#" + instance); } } } // DependentTest testng-6.9.12/src/test/java/test/dependent/DepBugVerifyTest.java0000644000175000017500000000064512732165123024100 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; import java.util.List; public class DepBugVerifyTest { @Test public void verify() { List log = DepBugSampleTest.getLog(); String[] expected = new String[] { "setup", "send", "get", "destroy" }; for (int i = 0; i < log.size(); i++) { Assert.assertEquals(expected[i], log.get(i)); } } } testng-6.9.12/src/test/java/test/dependent/ImplicitGroupInclusionSampleTest.java0000644000175000017500000000046212732165123027357 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; public class ImplicitGroupInclusionSampleTest { @Test(groups = "z") public void z() { } @Test(groups = "a", dependsOnGroups = {"z"}) public void a() { } @Test(groups = "b", dependsOnGroups = {"a"}) public void b() { } } testng-6.9.12/src/test/java/test/dependent/ClassDependsOnGroups.java0000644000175000017500000000173312732165123024751 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import test.BaseTest; public class ClassDependsOnGroups extends BaseTest { @Test public void verifyDependsOnGroups() { addClass(test.dependent.DifferentClassDependsOnGroupsTest1.class.getName()); addClass(test.dependent.DifferentClassDependsOnGroupsTest2.class.getName()); run(); String[] failed = { "test0" }; String[] skipped = { "test1", "test2" }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyGroupsAcrossClasses() { addClass(test.dependent.C1.class.getName()); addClass(test.dependent.C2.class.getName()); run(); String[] failed = { "failingTest" }; String[] skipped = { "shouldBeSkipped" }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dependent/DependentOnGroup1AlwaysRunSampleTest.java0000644000175000017500000000117412732165123030054 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; /** * a will fail but b should run anyway because of alwaysRun=true * * Created on Nov 18, 2005 * @author cbeust */ public class DependentOnGroup1AlwaysRunSampleTest { private boolean m_ok = false; @Test(groups = { "group-a"}) public void a() { throw new RuntimeException("Voluntary failure"); } @Test(dependsOnGroups = {"group-a"}, alwaysRun = true) public void b() { m_ok = true; } @Test(dependsOnMethods = {"b"}) public void verify() { Assert.assertTrue(m_ok, "method b() should have been invoked"); } } testng-6.9.12/src/test/java/test/dependent/SampleDependentMethods2.java0000644000175000017500000000311012732165123025351 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; /** * This class exercises dependent methods * * @author Cedric Beust, Aug 19, 2004 * */ public class SampleDependentMethods2 { private boolean m_oneA = false; private boolean m_oneB = false; private boolean m_secondA = false; private boolean m_thirdA = false; @Test(groups = { "one" }) public void oneA() { // ppp("oneA"); assert ! m_secondA : "secondA shouldn't have been run yet"; m_oneA = true; } @Test public void canBeRunAnytime() { } @Test(dependsOnGroups = { "one" } ) public void secondA() { // ppp("secondA"); assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert ! m_secondA : "secondA shouldn't have been run yet"; m_secondA = true; } @Test(dependsOnMethods= { "secondA" }) public void thirdA() { // ppp("thirdA"); assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert m_secondA : "secondA wasn't run"; assert ! m_thirdA : "thirdA shouldn't have been run yet"; m_thirdA = true; } @Test(groups = { "one" }) public void oneB() { // ppp("oneB"); assert ! m_secondA : "secondA shouldn't have been run yet"; m_oneB = true; } @AfterClass public void tearDown() { assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert m_secondA : "secondA wasn't run"; assert m_thirdA : "thirdA wasn't run"; } public static void ppp(String s) { System.out.println("[SampleDependentMethods] " + s); } }testng-6.9.12/src/test/java/test/dependent/MissingMethodTest.java0000644000175000017500000000115312732165123024312 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import test.BaseTest; public class MissingMethodTest extends BaseTest { @Test public void verifyThatExceptionIsThrownIfMissingMethod() { addClass("test.dependent.MissingMethodSampleTest"); run(); String[] passed = { "explicitlyIgnoreMissingMethod", "alwaysRunDespiteMissingMethod" }; String[] failed = { }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dependent/MissingGroupSampleTest.java0000644000175000017500000000150412732165123025330 0ustar eugeneeugenepackage test.dependent; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.Parser; import java.io.ByteArrayInputStream; public class MissingGroupSampleTest { @Test(dependsOnGroups = {"missing-group"}) public void shouldBeSkipped() { } @Test(dependsOnGroups = {"missing-group"}, ignoreMissingDependencies=true) public void shouldNotBeSkipped() { } public static void main(String[] args) throws Exception { TestNG tng = new TestNG(); String xml = ""; System.out.println(xml); ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes()); tng.setXmlSuites(new Parser(is).parseToList()); tng.run(); } } testng-6.9.12/src/test/java/test/dependent/SampleDependentMethods3.java0000644000175000017500000000243012732165123025356 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.AfterClass; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * This class tests overloaded dependent methods * * @author Cedric Beust, Aug 19, 2004 * */ public class SampleDependentMethods3 { private boolean m_oneA = false; private boolean m_oneB = false; private boolean m_secondA = false; @Test public void one() { // ppp("oneA"); assert ! m_secondA : "secondA shouldn't have been run yet"; m_oneA = true; } @Parameters({ "foo" }) @Test public void one(String s) { // ppp("oneB"); assert ! m_secondA : "secondA shouldn't have been run yet"; assert "Cedric".equals(s) : "Expected parameter value Cedric but got " + s; m_oneB = true; } @Test(dependsOnMethods = { "one" } ) public void secondA() { // ppp("secondA"); assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert ! m_secondA : "secondA shouldn't have been run yet"; m_secondA = true; } @AfterClass public void tearDown() { assert m_oneA : "oneA wasn't run"; assert m_oneB : "oneB wasn't run"; assert m_secondA : "secondA wasn't run"; } public static void ppp(String s) { System.out.println("[SampleDependentMethods] " + s); } }testng-6.9.12/src/test/java/test/dependent/ClassWide2Test.java0000644000175000017500000000053012732165123023476 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.annotations.Test; public class ClassWide2Test { // @Test(dependsOnMethods = {"m1" }) @Test(dependsOnMethods = {"test.dependent.ClassWide1Test.m1" }) public void m2() { Assert.assertTrue(ClassWide1Test.m1WasRun()); } // @Test // public void m1() { // // } } testng-6.9.12/src/test/java/test/dependent/C1.java0000644000175000017500000000032212732165123021140 0ustar eugeneeugenepackage test.dependent; import static org.testng.Assert.fail; import org.testng.annotations.Test; @Test(groups="group1") public class C1 { public void failingTest() { fail("always fails"); } } testng-6.9.12/src/test/java/test/dependent/SampleDependentConfigurationMethods.java0000644000175000017500000000120512732165123030022 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class SampleDependentConfigurationMethods { private boolean m_create = false; private boolean m_first = false; @BeforeMethod public void createInstance() { m_create = true; } @BeforeMethod(dependsOnMethods = { "createInstance"}) public void firstInvocation() { assert m_create : "createInstance() was never called"; m_first = true; } @Test public void verifyDependents() { assert m_create : "createInstance() was never called"; assert m_first : "firstInvocation() was never called"; } } testng-6.9.12/src/test/java/test/dependent/ImplicitGroupInclusionTest.java0000644000175000017500000000452212732165123026216 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import test.BaseTest; public class ImplicitGroupInclusionTest extends BaseTest { @Test public void verifyImplicitGroupInclusion() { addClass("test.dependent.ImplicitGroupInclusionSampleTest"); addIncludedGroup("b"); run(); String[] passed = { "a", "b", "z" }; String[] failed = { }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyImplicitGroupInclusion2() { addClass("test.dependent.ImplicitGroupInclusion2SampleTest"); addIncludedGroup("g2"); run(); String[] passed = { "m3" }; String[] failed = { }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyImplicitGroupInclusion4() { addClass("test.dependent.ImplicitGroupInclusion4SampleTest"); addIncludedGroup("g2"); run(); String[] passed = { "m3", "m4" }; String[] failed = { }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyImplicitGroupInclusion3() { addClass("test.dependent.ImplicitGroupInclusion3SampleTest"); addIncludedGroup("inc"); addExcludedGroup("exc"); run(); String[] passed = { "test1" }; String[] failed = { }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } @Test public void verifyImplicitMethodInclusion() { addClass("test.dependent.ImplicitMethodInclusionSampleTest"); addIncludedGroup("windows"); run(); String[] passed = { "a", "b" }; String[] failed = { }; String[] skipped = { }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dependent/SampleDependentTest.java0000644000175000017500000000147312732165123024615 0ustar eugeneeugenepackage test.dependent; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class SampleDependentTest extends SimpleBaseTest { @Test public void test2() { TestNG tng = create(SD2.class); SD2.m_log.clear(); tng.run(); boolean oneA = false; boolean oneB = false; boolean secondA = false; for (String s : SD2.m_log) { if ("oneA".equals(s)) { oneA = true; } if ("oneB".equals(s)) { oneB = true; } if ("secondA".equals(s)) { Assert.assertTrue(oneA); Assert.assertTrue(oneB); secondA = true; } if ("thirdA".equals(s)) { Assert.assertTrue(oneA); Assert.assertTrue(oneB); Assert.assertTrue(secondA); } } } } testng-6.9.12/src/test/java/test/dependent/C2.java0000644000175000017500000000047712732165123021154 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; @Test(groups={"group2"}, dependsOnGroups={"group1"}) public class C2 { public void shouldBeSkipped() { // the expectation is that this test will be SKIPPED because // a test in group1 failed and we have a dependsOnGroups={"group1"} } } testng-6.9.12/src/test/java/test/dependent/OrderMethodTest.java0000644000175000017500000000121212732165123023750 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; /** * This class verifies that when methods have dependents, they are run * in the correct order. * * @author Cedric Beust, Aug 19, 2004 * */ public class OrderMethodTest extends BaseOrderMethodTest { @Test(groups = { "1.0" }) public void z_first0() { // ppp("1.0"); m_group1[0] = true; } @Test(groups = { "2.1" }, dependsOnGroups = { "1.0", "1.1" }) public void a_second1() { // ppp("2.1"); verifyGroup(2, m_group1); m_group2[1] = true; } @Test(groups = { "1.1" }) public void z_premiere1() { // ppp("1.1"); m_group1[1] = true; } } testng-6.9.12/src/test/java/test/dependent/ClassWide1Test.java0000644000175000017500000000053112732165123023476 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class ClassWide1Test { private static boolean m_ok = false; @BeforeTest public void init() { m_ok = false; } @Test public void m1() { m_ok = true; } public static boolean m1WasRun() { return m_ok; } } testng-6.9.12/src/test/java/test/dependent/MissingGroupTest.java0000644000175000017500000000111412732165123024163 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.Test; import test.BaseTest; public class MissingGroupTest extends BaseTest { @Test public void verifyThatExceptionIsThrownIfMissingGroup() { addClass("test.dependent.MissingGroupSampleTest"); run(); String[] passed = { "shouldNotBeSkipped" }; String[] failed = { }; String[] skipped = { "shouldBeSkipped" }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dependent/DepBugSampleTest.java0000644000175000017500000000151712732165123024054 0ustar eugeneeugenepackage test.dependent; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; @Test public class DepBugSampleTest { private static List m_log = new ArrayList<>(); private static void log(String s) { // ppp(s); m_log.add(s); } private static void ppp(String s) { System.out.println("[DepBugSampleTest] " + s); } public static List getLog() { return m_log; } @BeforeClass public void setup() throws Exception { log("setup"); } @AfterClass public void destroy() throws Exception { log("destroy"); } @Test(dependsOnMethods = "send") public void get() throws Exception { log("get"); } public void send() throws Exception { log("send"); } } testng-6.9.12/src/test/java/test/SimpleBaseTest.java0000644000175000017500000000701312732165123021617 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.collections.Lists; import org.testng.internal.Utils; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.io.File; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class SimpleBaseTest { // System property specifying where the resources (e.g. xml files) can be found private static final String TEST_RESOURCES_DIR = "test.resources.dir"; public static TestNG create() { TestNG result = new TestNG(); result.setUseDefaultListeners(false); result.setVerbose(0); return result; } public static TestNG create(Class... testClasses) { TestNG result = create(); result.setTestClasses(testClasses); return result; } protected TestNG create(XmlSuite... suites) { TestNG result = create(); result.setXmlSuites(Arrays.asList(suites)); return result; } protected TestNG createTests(String suiteName, Class... testClasses) { XmlSuite suite = createXmlSuite(suiteName); int i=0; for (Class testClass : testClasses) { createXmlTest(suite, testClass.getName() + i, testClass); i++; } return create(suite); } protected XmlSuite createXmlSuite(String name) { XmlSuite result = new XmlSuite(); result.setName(name); return result; } protected XmlTest createXmlTest(XmlSuite suite, String name, Class clazz, Class... classes) { XmlTest result = new XmlTest(suite); int index = 0; result.setName(name); XmlClass xc = new XmlClass(clazz.getName(), index++, true /* load classes */); result.getXmlClasses().add(xc); for (Class c : classes) { xc = new XmlClass(c.getName(), index++, true /* load classes */); result.getXmlClasses().add(xc); } return result; } protected XmlTest createXmlTest(XmlSuite suite, String name, String... classes) { XmlTest result = new XmlTest(suite); int index = 0; result.setName(name); for (String c : classes) { XmlClass xc = new XmlClass(c, index++, true /* load classes */); result.getXmlClasses().add(xc); } return result; } protected void addMethods(XmlClass cls, String... methods) { int index = 0; for (String m : methods) { XmlInclude include = new XmlInclude(m, index++); cls.getIncludedMethods().add(include); } } public static String getPathToResource(String fileName) { String result = System.getProperty(TEST_RESOURCES_DIR); if (result == null) { throw new IllegalArgumentException("System property " + TEST_RESOURCES_DIR + " was not defined."); } return result + File.separatorChar + fileName; } protected void verifyPassedTests(TestListenerAdapter tla, String... methodNames) { Iterator it = tla.getPassedTests().iterator(); Assert.assertEquals(tla.getPassedTests().size(), methodNames.length); int i = 0; while (it.hasNext()) { Assert.assertEquals(it.next().getName(), methodNames[i++]); } } /** * Compare a list of ITestResult with a list of String method names, */ public static void assertTestResultsEqual(List results, List methods) { List resultMethods = Lists.newArrayList(); for (ITestResult r : results) { resultMethods.add(r.getMethod().getMethodName()); } Assert.assertEquals(resultMethods, methods); } } testng-6.9.12/src/test/java/test/jason/0000755000175000017500000000000012732165123017201 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/jason/MainTest.java0000644000175000017500000000142612732165123021573 0ustar eugeneeugenepackage test.jason; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; public class MainTest extends SimpleBaseTest { @Test public void afterClassShouldRun() { XmlSuite s = createXmlSuite("S"); XmlTest t = createXmlTest(s, "T", Main.class.getName()); XmlClass c = t.getXmlClasses().get(0); c.getIncludedMethods().add(new XmlInclude("test1")); t.setPreserveOrder("true"); TestNG tng = create(); tng.setXmlSuites(Arrays.asList(new XmlSuite[] { s })); Main.m_passed = false; tng.run(); Assert.assertTrue(Main.m_passed); } }testng-6.9.12/src/test/java/test/jason/MainBase.java0000644000175000017500000000031712732165123021524 0ustar eugeneeugenepackage test.jason; import org.testng.annotations.Test; public class MainBase { @Test(description = "This test is never run but prevents AfterClass") public void checkReportsExist() { } } testng-6.9.12/src/test/java/test/jason/Main.java0000644000175000017500000000055612732165123020736 0ustar eugeneeugenepackage test.jason; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; public class Main extends MainBase { public static boolean m_passed = false; @AfterClass public void afterClass() { m_passed = true; } @Test(description = "This test is run") public void test1() throws InterruptedException { } } testng-6.9.12/src/test/java/test/timeout/0000755000175000017500000000000012732165123017555 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/timeout/TestTimeOutSampleTest.java0000644000175000017500000000045612732165123024655 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.Test; public class TestTimeOutSampleTest { @Test public void timeoutTest() { try { Thread.sleep(2_000); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); } } } testng-6.9.12/src/test/java/test/timeout/TimeOutTest.java0000644000175000017500000000327112732165123022651 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import java.util.Arrays; import java.util.Iterator; import test.BaseTest; public class TimeOutTest extends BaseTest { private final long m_id; public TimeOutTest() { m_id = System.currentTimeMillis(); } private void privateTimeOutTest(XmlSuite.ParallelMode parallel) { addClass(TimeOutSampleTest.class); if (parallel != null) { setParallel(parallel); } run(); verifyPassedTests("timeoutShouldPass"); verifyFailedTests("timeoutShouldFailByException", "timeoutShouldFailByTimeOut"); } @DataProvider(name = "parallelModes") public Iterator createData() { final Iterator parallelModes = Arrays.asList(XmlSuite.ParallelMode.values()).iterator(); return new Iterator() { @Override public boolean hasNext() { return parallelModes.hasNext(); } @Override public Object[] next() { return new Object[]{ parallelModes.next() }; } @Override public void remove() { throw new UnsupportedOperationException("remove"); } }; } @Test(dataProvider = "parallelModes") public void timeOutInParallel(XmlSuite.ParallelMode parallelMode) { privateTimeOutTest(parallelMode); } @Test public void timeOutInNonParallel() { privateTimeOutTest(null); } @Test public void verifyInvocationTimeOut() { addClass(InvocationTimeOutSampleTest.class); run(); verifyPassedTests("shouldPass"); verifyFailedTests("shouldFail"); } @Override public Long getId() { return m_id; } } testng-6.9.12/src/test/java/test/timeout/TimeOutWithParallelSample.java0000644000175000017500000000034312732165123025461 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.Test; public class TimeOutWithParallelSample { @Test(timeOut = 1_000) public void myTestMethod() throws InterruptedException { Thread.sleep(1_500); } } testng-6.9.12/src/test/java/test/timeout/TimeOutIntegrationTest.java0000644000175000017500000000145312732165123025055 0ustar eugeneeugenepackage test.timeout; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; public class TimeOutIntegrationTest { @Test(description = "https://github.com/cbeust/testng/issues/811") public void testTimeOutWhenParallelIsTest() { TestNG tng = new TestNG(); tng.setParallel(XmlSuite.ParallelMode.TESTS); tng.setTestClasses(new Class[]{TimeOutWithParallelSample.class}); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getFailedTests().size(), 1); Assert.assertEquals(tla.getSkippedTests().size(), 0); Assert.assertEquals(tla.getPassedTests().size(), 0); } } testng-6.9.12/src/test/java/test/timeout/TimeOutSample2Test.java0000644000175000017500000000044312732165123024073 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.Test; /** * Tests timeouts set from testng.xml * @author cbeust */ public class TimeOutSample2Test { @Test(timeOut = 1_500) public void timeoutShouldFailByTimeOut() throws InterruptedException { Thread.sleep(10_000); } } testng-6.9.12/src/test/java/test/timeout/issue575.xml0000644000175000017500000000037512732165123021675 0ustar eugeneeugene testng-6.9.12/src/test/java/test/timeout/InvocationTimeOutSampleTest.java0000644000175000017500000000103512732165123026041 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.Test; public class InvocationTimeOutSampleTest { @Test(invocationCount = 5, invocationTimeOut = 2_000) public void shouldPass() { try { Thread.sleep(250); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); } } @Test(invocationCount = 5, invocationTimeOut = 1_000) public void shouldFail() { try { Thread.sleep(250); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); } } } testng-6.9.12/src/test/java/test/timeout/TimeOutSampleTest.java0000644000175000017500000000106512732165123024012 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.Test; /** * This class tests timeouts * * @author cbeust */ public class TimeOutSampleTest { @Test(timeOut = 5_000 /* 5 seconds */) public void timeoutShouldPass() { } @Test(timeOut = 5_000 /* 5 seconds */) public void timeoutShouldFailByException() { throw new RuntimeException("EXCEPTION SHOULD MAKE THIS METHOD FAIL"); } @Test(timeOut = 1_000 /* 1 second */) public void timeoutShouldFailByTimeOut() throws InterruptedException { Thread.sleep(10_000 /* 10 seconds */); } } testng-6.9.12/src/test/java/test/timeout/TimeOutFromXmlTest.java0000644000175000017500000000463012732165123024156 0ustar eugeneeugenepackage test.timeout; import org.testng.annotations.Test; import org.testng.xml.SuiteXmlParser; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.BaseTest; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class TimeOutFromXmlTest extends BaseTest { private void timeOutTest(boolean onSuite) { addClass(TestTimeOutSampleTest.class); if (onSuite) { setSuiteTimeOut(1_000); } else { setTestTimeOut(1_000); } run(); verifyPassedTests(); verifyFailedTests("timeoutTest"); } @Test public void timeOutOnSuiteTag() { timeOutTest(true /* on suite */); } @Test public void timeOutOnTestTag() { timeOutTest(false /* on test */); } @Test public void noTimeOut() { addClass(TestTimeOutSampleTest.class); run(); verifyPassedTests("timeoutTest"); verifyFailedTests(); } @Test public void twoDifferentTests() { XmlSuite result = new XmlSuite(); result.setName("Suite"); createXmlTest(result, "WithoutTimeOut"); createXmlTest(result, "WithTimeOut").setTimeOut(1_000); setSuite(result); run(); verifyPassedTests("timeoutTest"); verifyFailedTests("timeoutTest"); } private XmlTest createXmlTest(XmlSuite suite, String name) { XmlTest result = new XmlTest(suite); result.setName(name); List classes = new ArrayList<>(); XmlClass cls = new XmlClass(TestTimeOutSampleTest.class); cls.setIncludedMethods( Collections.singletonList(new XmlInclude("timeoutTest"))); classes.add(cls); result.setXmlClasses(classes); return result; } @Test public void timeOutInParallelTestsFromXml() throws IOException { String file = "src/test/java/test/timeout/issue575.xml"; try (FileInputStream stream = new FileInputStream(file)) { SuiteXmlParser suiteParser = new SuiteXmlParser(); XmlSuite suite = suiteParser.parse(file, stream, true); setSuite(suite); run(); verifyPassedTests("timeoutShouldPass"); verifyFailedTests("timeoutShouldFailByException", "timeoutShouldFailByTimeOut"); } } } testng-6.9.12/src/test/java/test/ant/0000755000175000017500000000000012732165123016651 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/ant/MultipleThreadTest.java0000644000175000017500000000472512732165123023307 0ustar eugeneeugenepackage test.ant; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Tests that more than one thread is used for running tests * @author micheb10 2 Oct 2006 * */ public class MultipleThreadTest { public static Set _threads; @BeforeClass public void prepareHashSet() { _threads=Collections.synchronizedSet(new HashSet()); } @Test public void recordThread00() { _threads.add(Thread.currentThread()); } @Test public void recordThread01() { _threads.add(Thread.currentThread()); } @Test public void recordThread02() { _threads.add(Thread.currentThread()); } @Test public void recordThread03() { _threads.add(Thread.currentThread()); } @Test public void recordThread04() { _threads.add(Thread.currentThread()); } @Test public void recordThread05() { _threads.add(Thread.currentThread()); } @Test public void recordThread06() { _threads.add(Thread.currentThread()); } @Test public void recordThread07() { _threads.add(Thread.currentThread()); } @Test public void recordThread08() { _threads.add(Thread.currentThread()); } @Test public void recordThread09() { _threads.add(Thread.currentThread()); } @Test public void recordThread10() { _threads.add(Thread.currentThread()); } @Test public void recordThread11() { _threads.add(Thread.currentThread()); } @Test public void recordThread12() { _threads.add(Thread.currentThread()); } @Test public void recordThread13() { _threads.add(Thread.currentThread()); } @Test public void recordThread14() { _threads.add(Thread.currentThread()); } @Test public void recordThread15() { _threads.add(Thread.currentThread()); } @Test public void recordThread16() { _threads.add(Thread.currentThread()); } @Test public void recordThread17() { _threads.add(Thread.currentThread()); } @Test public void recordThread18() { _threads.add(Thread.currentThread()); } @Test public void recordThread19() { _threads.add(Thread.currentThread()); } @AfterClass public void confirmMultipleThreads() { Assert.assertTrue(_threads.size()>1,"More than one thread should have been used for running the tests - "+_threads.size()+" was used"); } } testng-6.9.12/src/test/java/test/ant/NoPackageTest.java0000644000175000017500000000061112732165123022202 0ustar eugeneeugenepackage test.ant; import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; /** * @author Filippo Diotalevi */ public class NoPackageTest { private boolean m_run = false; @Test(groups = {"nopackage"}) public void test() { m_run = true; } @AfterMethod(groups = {"nopackage"}) public void after() { assert m_run : "test method was not run"; } } testng-6.9.12/src/test/java/test/ant/TestCommandLineArgs.java0000644000175000017500000000174112732165123023362 0ustar eugeneeugenepackage test.ant; import static org.testng.AssertJUnit.assertEquals; import org.testng.annotations.Test; import java.io.File; /** * Tests some of the functionality in {@link TestNGCommandLineArgs}. * * @author jkuhnert */ public class TestCommandLineArgs { @Test public void testUnixPathResolution() { String path = "/wee/wom/flibble.txt"; String[] segments = path.split("[/\\\\]", -1); assertEquals(4, segments.length); assertEquals("wee", segments[1]); } @Test public void testDOSPathResolution() { String path = "c:\\\\com\\pants\\wibble.txt"; String[] segments = path.split("[/\\\\]", -1); assertEquals(5, segments.length); assertEquals("com", segments[2]); // because c: is actually \\ which will be split twice } @Test public void testPathResolution() { File file = new File("pom.xml"); assert file.exists(); String path = file.getAbsolutePath(); assert path.split("[/\\\\]", -1).length > 1; } } testng-6.9.12/src/test/java/test/ant/AntSystemPropertySet.java0000644000175000017500000000170012732165123023662 0ustar eugeneeugenepackage test.ant; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import org.testng.annotations.Test; /** * Test whether nested propertysets are passed passed from the ant task. Executed by the "run:antprop" target * in test/build.xml. * * @author
Todd Wells */ public class AntSystemPropertySet { @Test public void outputTestProperties() { assertNotNull(System.getProperty("syspropset1"), "syspropset1 not found"); assertEquals(System.getProperty("syspropset1"), "value 1", "Wrong value for syspropset1"); assertNotNull(System.getProperty("syspropset2"), "syspropset2 not found"); assertEquals(System.getProperty("syspropset2"), "value 2", "Wrong value for syspropset2"); assertNotNull(System.getProperty("sysprop1"), "sysprop1 not found"); assertEquals(System.getProperty("sysprop1"), "value 3", "Wrong value for sysprop1"); } } testng-6.9.12/src/test/java/test/ant/DontOverrideSuiteNameTest.java0000644000175000017500000000032412732165123024572 0ustar eugeneeugenepackage test.ant; import org.testng.annotations.Test; @Test public class DontOverrideSuiteNameTest { private boolean m_run = false; @Test(groups = {"nopackage"}) public void test() { m_run = true; } } testng-6.9.12/src/test/java/test/testng56/0000755000175000017500000000000012732165123017546 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng56/testng-56.xml0000644000175000017500000000040412732165123022022 0ustar eugeneeugene testng-6.9.12/src/test/java/test/testng56/ParallelTest.java0000644000175000017500000000204512732165123023006 0ustar eugeneeugenepackage test.testng56; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * This class/interface */ public class ParallelTest { @BeforeClass public void setup() { System.out.println(Thread.currentThread().getId() + ":setup"); } @AfterClass public void teardown() { System.out.println(Thread.currentThread().getId() + ":teardown"); } @Test public void test1() { System.out.println(Thread.currentThread().getId() + ":test1"); } @Test(dependsOnMethods = {"test1"}) public void test2() { System.out.println(Thread.currentThread().getId() + ":test2"); } @Test public void test3() { System.out.println(Thread.currentThread().getId() + ":test3"); } @Test(dependsOnMethods = {"test3"}) public void test4() { System.out.println(Thread.currentThread().getId() + ":test4"); } @Test public void test5() { System.out.println(Thread.currentThread().getId() + ":test5"); } } testng-6.9.12/src/test/java/test/DynamicGraphTest.java0000644000175000017500000000660612732165123022150 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.ITestNGMethod; import org.testng.annotations.Test; import org.testng.internal.DynamicGraph; import org.testng.internal.DynamicGraph.Status; import java.util.Comparator; import java.util.List; public class DynamicGraphTest { private static class Node { private final String name; private final int priority; private Node(String name) { this(name, 0); } private Node(String name, int priority) { this.name = name; this.priority = priority; } } private static void assertFreeNodesEquals(DynamicGraph graph, Node... expected) { List freeNodes = graph.getFreeNodes(); String[] actual = new String[freeNodes.size()]; for (int i=0; i {a1; a2;} b2 -> {a1; a2;} c1 -> {b1; b2;} x; y; } */ DynamicGraph dg = new DynamicGraph<>(); dg.setComparator(new Comparator() { @Override public int compare(Node o1, Node o2) { return o1.priority - o2.priority; } }); Node a1 = new Node("a1", 1); Node a2 = new Node("a2", 2); Node b1 = new Node("b1", 1); Node b2 = new Node("b2", 2); Node c1 = new Node("c1", 1); dg.addNode(a1); dg.addNode(a2); dg.addNode(b1); dg.addNode(b2); dg.addNode(c1); dg.addEdge(b1, a1, a2); dg.addEdge(b2, a1, a2); dg.addEdge(c1, b1, b2); Node x = new Node("x"); Node y = new Node("y"); dg.addNode(x); dg.addNode(y); List freeNodes = dg.getFreeNodes(); assertFreeNodesEquals(dg, y, x); dg.setStatus(freeNodes, Status.RUNNING); freeNodes = dg.getFreeNodes(); assertFreeNodesEquals(dg, a1); dg.setStatus(freeNodes, Status.RUNNING); freeNodes = dg.getFreeNodes(); assertFreeNodesEquals(dg, a2); dg.setStatus(freeNodes, Status.RUNNING); dg.setStatus(a1, Status.FINISHED); assertFreeNodesEquals(dg); dg.setStatus(a2, Status.FINISHED); assertFreeNodesEquals(dg, b1); dg.setStatus(b2, Status.RUNNING); dg.setStatus(b1, Status.FINISHED); assertFreeNodesEquals(dg); dg.setStatus(b2, Status.FINISHED); assertFreeNodesEquals(dg, c1); } @Test public void test2() { /* digraph test2 { a1; a2; b1 -> {a1; a2;} x; } */ DynamicGraph dg = new DynamicGraph<>(); Node a1 = new Node("a1", 1); Node a2 = new Node("a2", 2); Node b1 = new Node("b1", 1); dg.addNode(a1); dg.addNode(a2); dg.addNode(b1); dg.addEdge(b1, a1, a2); Node x = new Node("x"); dg.addNode(x); List freeNodes = dg.getFreeNodes(); assertFreeNodesEquals(dg, a1, a2, x); dg.setStatus(freeNodes, Status.RUNNING); dg.setStatus(a1, Status.FINISHED); assertFreeNodesEquals(dg); dg.setStatus(a2, Status.FINISHED); assertFreeNodesEquals(dg, b1); Node b2 = new Node("b2", 2); dg.setStatus(b2, Status.RUNNING); dg.setStatus(b1, Status.FINISHED); assertFreeNodesEquals(dg); } } testng-6.9.12/src/test/java/test/thread/0000755000175000017500000000000012732165123017336 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/thread/Test1Test.java0000644000175000017500000000052712732165123022045 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; public class Test1Test extends BaseSequentialSample { @Test public void f11() { ppp("f11"); addId("Test1Test.f11()", Thread.currentThread().getId()); } @Test public void f12() { ppp("f12"); addId("Test1Test.f12()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/TrueParallelTest.java0000644000175000017500000000320612732165123023436 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; /** * Attempt to make sure that we are truly running methods in parallel. The best I can think * of right now is to run the tests a few times in a row and verify the ordering is never * the same. */ public class TrueParallelTest extends SimpleBaseTest { @Test public void shouldRunInParallel() { boolean success = false; for (int i = 0, count = Runtime.getRuntime().availableProcessors() * 4; i < count; i++) { XmlSuite s = createXmlSuite("TrueParallel"); createXmlTest(s, "Test", TrueParallelSampleTest.class.getName()); TestNG tng = create(); s.setParallel(XmlSuite.ParallelMode.METHODS); tng.setXmlSuites(Arrays.asList(s)); BaseThreadTest.initThreadLog(); tng.run(); // A sequential result will look like "m1 m1 m3 m3 m2 m2 m4 m4 m5 m5". A properly // multithreaded result will have at least one non-consecutive different pair: // "m1 m1 m3 m2 m4 m4 m2 m3 m5 m5" List strings = TrueParallelSampleTest.getStrings(); boolean ii = isInterleaved(strings); success = success || ii; // System.out.println(strings + " -> " + ii); } Assert.assertTrue(success, "Couldn't find any interleaved test method run"); } private boolean isInterleaved(List strings) { for (int i = 0; i < strings.size(); i += 2) { if (! strings.get(i).equals(strings.get(i + 1))) { return true; } } return false; } } testng-6.9.12/src/test/java/test/thread/ParallelWithFactorySampleTest.java0000644000175000017500000000130212732165123026117 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class ParallelWithFactorySampleTest extends BaseSequentialSample { private int m_n; @DataProvider public static Object[][] dp() { return new Object[][] { new Object[] { 42 }, new Object[] { 43 } }; } @Factory(dataProvider = "dp") public ParallelWithFactorySampleTest(int n) { m_n = n; } protected int getN() { return m_n; } @Test public void f1() { addId("f1 " + getN(), Thread.currentThread().getId()); } @Test public void f2() { addId("f2", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/ThreadPoolSampleBugTest.java0000644000175000017500000000132712732165123024705 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; public class ThreadPoolSampleBugTest { private static final long TIMEOUT = 500; @Test(invocationCount = 1, threadPoolSize = 5) public void shouldPass1() throws InterruptedException { Thread.sleep(TIMEOUT); } @Test(invocationCount = 2, threadPoolSize = 5) public void shouldPass2() throws InterruptedException { Thread.sleep(TIMEOUT); } @Test(timeOut = 10, invocationCount = 1, threadPoolSize = 5) public void shouldFail1() throws InterruptedException { Thread.sleep(TIMEOUT); } @Test(timeOut = 10, invocationCount = 2, threadPoolSize = 5) public void shouldFail2() throws InterruptedException { Thread.sleep(TIMEOUT); } } testng-6.9.12/src/test/java/test/thread/ThreadTest.java0000644000175000017500000000120012732165123022241 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; import test.BaseTest; public class ThreadTest extends BaseTest { @Test(groups = "broken", description = "This can be fixed by using sets instead of lists in DynamicGraph, but more failures happen then") public void timeoutAndInvocationCountShouldFail() { addClass(ThreadPoolSampleBugTest.class.getName()); run(); String[] passed = { "shouldPass1", "shouldPass2" }; String[] failed = { "shouldFail1", "shouldFail2" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/thread/testng.xml0000644000175000017500000000072112732165123021364 0ustar eugeneeugene testng-6.9.12/src/test/java/test/thread/SingleThreadedSample2Test.java0000644000175000017500000000100512732165123025143 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(singleThreaded = true) public class SingleThreadedSample2Test extends BaseSequentialSample { @Test public void f1() { addId("SingleThreadedSample2Test.f1()", Thread.currentThread().getId()); } @Test public void f2() { addId("SingleThreadedSample2Test.f2()", Thread.currentThread().getId()); } @Test public void f3() { addId("SingleThreadedSample2Test.f3()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/B.java0000644000175000017500000000101412732165123020356 0ustar eugeneeugenepackage test.thread; import java.util.HashMap; import java.util.Map; import org.testng.annotations.Test; import org.testng.collections.Maps; public class B { public static Map m_threadIds = Maps.newHashMap(); public static void setUp() { m_threadIds = new HashMap<>(); } @Test public void f2() { Long id = Thread.currentThread().getId(); m_threadIds.put(id, id); } private static void ppp(String s) { System.out.println("[FactoryTest] " + s); } } testng-6.9.12/src/test/java/test/thread/ThreadPoolSizeTest.java0000644000175000017500000000045512732165123023741 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; public class ThreadPoolSizeTest extends ThreadPoolSizeBase { @Test(invocationCount = 5, threadPoolSize = 3) public void f1() { logThread(); } @Test(dependsOnMethods = {"f1"}) public void verify() { verifyThreads(3); } } testng-6.9.12/src/test/java/test/thread/ThreadPoolSizeWithTimeOutTest.java0000644000175000017500000000136512732165123026105 0ustar eugeneeugenepackage test.thread; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import junit.framework.Assert; public class ThreadPoolSizeWithTimeOutTest extends ThreadPoolSizeBase { @Test(invocationCount = 5, threadPoolSize = 3, timeOut = 1000) public void f1() { logThread(); } @Test(dependsOnMethods = {"f1"}) public void verify() { verifyThreads(3); } @Test public void threadPoolAndTimeOutShouldFail() { TestNG tng = create(ThreadPoolSizeSampleTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(0, tla.getPassedTests().size()); Assert.assertEquals(1, tla.getFailedTests().size()); } } testng-6.9.12/src/test/java/test/thread/SequentialSample3Test.java0000644000175000017500000000072612732165123024405 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(sequential = true) public class SequentialSample3Test extends BaseSequentialSample { public void f1() { addId("SequentialSample3Test.f1()", Thread.currentThread().getId()); } public void f2() { addId("SequentialSample3Test.f2()", Thread.currentThread().getId()); } public void f3() { addId("SequentialSample3Test.f3()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/ParallelTestTest.java0000644000175000017500000000640612732165123023443 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.BaseTest; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class ParallelTestTest extends BaseTest { @DataProvider private static Object[][] verifyParallelDp() { return new Object[][]{ // isCommandLine, parallelMode, expectedThreadCount {true, XmlSuite.ParallelMode.NONE, 1}, {false, XmlSuite.ParallelMode.NONE, 1}, {true, XmlSuite.ParallelMode.TESTS, 2}, {false, XmlSuite.ParallelMode.TESTS, 2}, {true, XmlSuite.ParallelMode.METHODS, 4}, {false, XmlSuite.ParallelMode.METHODS, 4}, {true, XmlSuite.ParallelMode.CLASSES, 2}, {false, XmlSuite.ParallelMode.CLASSES, 2}, {true, XmlSuite.ParallelMode.INSTANCES, 2}, {false, XmlSuite.ParallelMode.INSTANCES, 2} }; } @Test(dataProvider = "verifyParallelDp") public void verifyParallel(boolean isCommandLine, XmlSuite.ParallelMode parallelMode, int expectedThreadCount) { verifyExpected(isCommandLine, parallelMode, expectedThreadCount, Test1Test.class, Test2Test.class); } @DataProvider private static Object[][] verifyParallelWithFactoryDp() { return new Object[][]{ // isCommandLine, parallelMode, expectedThreadCount {true, XmlSuite.ParallelMode.NONE, 1}, {false, XmlSuite.ParallelMode.NONE, 1}, {true, XmlSuite.ParallelMode.INSTANCES, 2}, {false, XmlSuite.ParallelMode.INSTANCES, 2} }; } @Test(dataProvider = "verifyParallelWithFactoryDp") // TODO use "verifyParallelDp" public void verifyParallelWithFactory(boolean isCommandLine, XmlSuite.ParallelMode parallelMode, int expectedThreadCount) { verifyExpected(isCommandLine, parallelMode, expectedThreadCount, ParallelWithFactorySampleTest.class); } private void createTest(XmlSuite xmlSuite, Class clazz) { XmlTest result = new XmlTest(xmlSuite); List classes = result.getXmlClasses(); XmlClass xmlClass = new XmlClass(clazz); classes.add(xmlClass); } private void verifyExpected(boolean isCommandLine, XmlSuite.ParallelMode parallelMode, int expectedThreadCount, Class... classes) { XmlSuite xmlSuite = new XmlSuite(); xmlSuite.setName("ParallelTestTest"); xmlSuite.setParallel(parallelMode); for (Class clazz : classes) { createTest(xmlSuite, clazz); } TestNG tng = new TestNG(); tng.setVerbose(0); if (isCommandLine) { tng.setCommandLineSuite(xmlSuite); } else { tng.setXmlSuites(Arrays.asList(xmlSuite)); } Helper.reset(); tng.run(); List> maps = Lists.newArrayList(); for (Class clazz : classes) { maps.add(Helper.getMap(clazz.getName())); } Map mergedMap = new HashMap<>(); for (Map m : maps) { mergedMap.putAll(m); } Assert.assertEquals(mergedMap.size(), expectedThreadCount); } } testng-6.9.12/src/test/java/test/thread/Sample1.java0000644000175000017500000000027412732165123021506 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; public class Sample1 extends BaseThreadTest { @Test public void s1() { logThread(Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/TrueParallelSampleTest.java0000644000175000017500000000117612732165123024604 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; import java.util.Random; @Test public class TrueParallelSampleTest extends BaseThreadTest { static Random random = new Random(System.currentTimeMillis()); private void log(String s) { logString(s); try { Thread.sleep(random.nextInt(10)); } catch (InterruptedException ex) { Thread.yield(); } logString(s); logCurrentThread(); } public void m1() { log("m1"); } public void m2() { log("m2"); } public void m3() { log("m3"); } public void m4() { log("m4"); } public void m5() { log("m5"); } } testng-6.9.12/src/test/java/test/thread/Test2Test.java0000644000175000017500000000052712732165123022046 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; public class Test2Test extends BaseSequentialSample { @Test public void f21() { ppp("f21"); addId("Test2Test.f21()", Thread.currentThread().getId()); } @Test public void f22() { ppp("f22"); addId("Test2Test.f22()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/ParallelSuiteTest.java0000644000175000017500000001024612732165123023612 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; import java.util.Map; public class ParallelSuiteTest extends SimpleBaseTest { @Test public void suitesShouldRunInParallel1() { runTest(5, 2, 2, null, Arrays.asList( getPathToResource("suite-parallel-1.xml"), getPathToResource("suite-parallel-2.xml"))); } @Test public void suitesShouldRunInParallel2() { runTest(5, 3, 3, null, Arrays.asList( getPathToResource("suite-parallel-0.xml"))); } @Test(description = "Number of threads (2) is less than number of suites (3)") public void suitesShouldRunInParallel3() { final int SUITE_THREAD_POOL_SIZE = 2; TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.setSuiteThreadPoolSize(SUITE_THREAD_POOL_SIZE); tng.setTestSuites(Arrays.asList(getPathToResource("suite-parallel-0.xml"))); tng.addListener(tla); BaseThreadTest.initThreadLog(); tng.run(); //Shouldn't not deadlock Assert.assertEquals(BaseThreadTest.getThreadCount(), SUITE_THREAD_POOL_SIZE); } private void runTest(int suiteThreadPoolSize, int expectedThreadCount, int expectedSuiteCount, Boolean randomizeSuites, List paths) { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.setSuiteThreadPoolSize(suiteThreadPoolSize); tng.setTestSuites(paths); tng.addListener(tla); if (null != randomizeSuites) { tng.setRandomizeSuites(randomizeSuites); } BaseThreadTest.initThreadLog(); tng.run(); Assert.assertEquals(BaseThreadTest.getThreadCount(), expectedThreadCount, "Thread count expected:" + expectedThreadCount + " actual:" + BaseThreadTest.getThreadCount()); Assert.assertEquals(BaseThreadTest.getSuitesMap().keySet().size(), expectedSuiteCount); } @Test public void suitesShouldRunInParallel4() { runTest(10, 5, 5, null, Arrays.asList( getPathToResource("parallel-suites/suite-parallel-1.xml"), getPathToResource("parallel-suites/suite-parallel-2.xml"), getPathToResource("parallel-suites/suite-parallel-2-1.xml"), getPathToResource("parallel-suites/suite-parallel-2-2.xml"))); } @Test public void suitesShouldRunInParallel5() { runTest(5, 5, 7, null, Arrays.asList( getPathToResource("parallel-suites/suite-parallel-0.xml"))); } @Test(description = "Number of threads (2) is less than level of suites (3)") public void suitesShouldRunInParallel6() { runTest(2, 2, 7, null, Arrays.asList( getPathToResource("parallel-suites/suite-parallel-0.xml"))); } @Test(description = "If suiteThreadPoolSize and randomizeSuites are not specified" + " suites should run in order specified in XML") public void suitesShouldRunInOrder() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.setTestSuites(Arrays.asList(getPathToResource("suite-parallel-0.xml"))); tng.addListener(tla); BaseThreadTest.initThreadLog(); tng.run(); Map suitesMap = BaseThreadTest.getSuitesMap(); Assert.assertEquals(BaseThreadTest.getThreadCount(), 1); Assert.assertEquals(suitesMap.keySet().size(), 3); final String SUITE_NAME_PREFIX = "Suite Parallel "; if (suitesMap.get(SUITE_NAME_PREFIX + 1) > suitesMap.get(SUITE_NAME_PREFIX + 2)) { Assert.fail("Suite " + (SUITE_NAME_PREFIX + 1) + " should have run before " + (SUITE_NAME_PREFIX + 2)); } Assert.assertTrue(suitesMap.get(SUITE_NAME_PREFIX + 2) <= suitesMap.get(SUITE_NAME_PREFIX + 0)); } @Test(description = "Number of threads (1) is less than number of levels of suites (2)") public void suitesShouldRun1() { runTest(1, 1, 3, true, Arrays.asList( getPathToResource("suite-parallel-0.xml"))); // runTest(1, 1, 7, true, Arrays.asList( // getPathToResource("parallel-suites/suite-parallel-0.xml"))); // // runTest(2, 2, 7, true, Arrays.asList( // getPathToResource("parallel-suites/suite-parallel-0.xml"))); } } testng-6.9.12/src/test/java/test/thread/SequentialSampleTest.java0000644000175000017500000000072212732165123024316 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(sequential = true) public class SequentialSampleTest extends BaseSequentialSample { public void f1() { addId("SequentialSampleTest.f1()", Thread.currentThread().getId()); } public void f2() { addId("SequentialSampleTest.f2()", Thread.currentThread().getId()); } public void f3() { addId("SequentialSampleTest.f3()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/Sample2.java0000644000175000017500000000061212732165123021503 0ustar eugeneeugenepackage test.thread; import org.testng.ITestContext; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class Sample2 extends BaseThreadTest { @BeforeMethod public void before(ITestContext ctx) { logSuite(ctx.getSuite().getName(), System.currentTimeMillis()); } @Test public void s1() { logThread(Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/TestThreadCountTest.java0000644000175000017500000000163112732165123024122 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import org.testng.internal.thread.ThreadUtil; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Test for test level thread-count. * * @author Alex Popescu */ public class TestThreadCountTest { private Set m_threads= Collections.synchronizedSet(new HashSet()); @Test public void test1() { m_threads.add(ThreadUtil.currentThreadInfo()); } @Test public void test2() { m_threads.add(ThreadUtil.currentThreadInfo()); } @Test public void test3() { m_threads.add(ThreadUtil.currentThreadInfo()); } @AfterClass public void checkThreading() { Assert.assertEquals(m_threads.size(), 3, "Test should use 3 threads"); } } testng-6.9.12/src/test/java/test/thread/SequentialSample2Test.java0000644000175000017500000000072612732165123024404 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(sequential = true) public class SequentialSample2Test extends BaseSequentialSample { public void f1() { addId("SequentialSample2Test.f1()", Thread.currentThread().getId()); } public void f2() { addId("SequentialSample2Test.f2()", Thread.currentThread().getId()); } public void f3() { addId("SequentialSample2Test.f3()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/BaseThreadTest.java0000644000175000017500000000337112732165123023047 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import test.SimpleBaseTest; import java.util.List; import java.util.Map; import java.util.Set; public class BaseThreadTest extends SimpleBaseTest { static private Set m_threadIds; static private Map m_suitesMap; static private List m_strings; static void initThreadLog() { m_threadIds = Sets.newHashSet(); m_suitesMap = Maps.newHashMap(); m_strings = Lists.newArrayList(); } protected void logString(String s) { synchronized(m_strings) { log("BaseThreadTest", "Logging string:" + s); m_strings.add(s); } } public static List getStrings() { return m_strings; } protected void logCurrentThread() { logThread(Thread.currentThread().getId()); } protected void logThread(long threadId) { synchronized(m_threadIds) { log("BaseThreadTest", "Logging thread:" + threadId); m_threadIds.add(threadId); } } protected void logSuite(String suiteName, long time) { synchronized(m_suitesMap) { m_suitesMap.put(suiteName, time); } } static int getThreadCount() { synchronized(m_threadIds) { return m_threadIds.size(); } } static Map getSuitesMap() { return m_suitesMap; } protected void log(String cls, String s) { if (false) { System.out.println("[" + cls + "] thread:" + Thread.currentThread().getId() + " hash:" + hashCode() + " " + s); } } protected void verifyThreads(int expected) { Assert.assertEquals(getThreadCount(), expected, "Ran on " + getThreadCount() + " threads instead of " + expected); } } testng-6.9.12/src/test/java/test/thread/MultiThreadedDependentSampleTest.java0000644000175000017500000000417712732165123026576 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.collections.Lists; import java.util.List; public class MultiThreadedDependentSampleTest { public static List m_methods = Lists.newArrayList(); @BeforeClass public void bc() { // log("beforeClass"); } @AfterClass public void ac() { // log("afterClass"); } @BeforeMethod public void bm() { // log("beforeMethod"); } @AfterMethod public void am() { // log("afterMethod"); } @Test(groups = "1") public void a1() { logThread(); log("a1"); } @Test(groups = "1") public void a2() { logThread(); log("a2"); } @Test(groups = "1") public void a3() { logThread(); log("a3"); } @Test(groups = "2", dependsOnGroups = "1") public void b1() { logThread(); log("b1"); } @Test(groups = "2", dependsOnGroups = "1") public void b2() { logThread(); log("b2"); } @Test(groups = "2", dependsOnGroups = "1") public void b3() { logThread(); log("b3"); } @Test(groups = "2", dependsOnGroups = "1") public void b4() { logThread(); log("b4"); } @Test(groups = "2", dependsOnGroups = "1") public void b5() { logThread(); log("b5"); } @Test(dependsOnGroups = "2") public void c1() { logThread(); log("c1"); } @Test(dependsOnGroups = { "1" }) public void d() { logThread(); log("d"); } @Test public void x() { log("x"); } @Test public void y() { log("y"); } @Test public void z() { log("z"); } @Test public void t() { log("t"); } // @Test(groups = "mytest", dependsOnMethods = "g") // public void f() { // } // // // @AfterMethod // public void after() { // } private void logThread() { long id = Thread.currentThread().getId(); Helper.getMap(getClass().getName()).put(id, id); } private void log(String string) { synchronized(m_methods) { m_methods.add(string); } } } testng-6.9.12/src/test/java/test/thread/ThreadPoolSizeSampleTest.java0000644000175000017500000000034312732165123025077 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; public class ThreadPoolSizeSampleTest { @Test(threadPoolSize=2, timeOut=100) public void willPassBug() throws InterruptedException{ Thread.sleep(500); } } testng-6.9.12/src/test/java/test/thread/SingleThreadedSampleTest.java0000644000175000017500000000100112732165123025055 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(singleThreaded = true) public class SingleThreadedSampleTest extends BaseSequentialSample { @Test public void f1() { addId("SingleThreadedSampleTest.f1()", Thread.currentThread().getId()); } @Test public void f2() { addId("SingleThreadedSampleTest.f2()", Thread.currentThread().getId()); } @Test public void f3() { addId("SingleThreadedSampleTest.f3()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/Helper.java0000644000175000017500000000152212732165123021420 0ustar eugeneeugenepackage test.thread; import java.util.HashMap; import java.util.Map; public class Helper { private static Map> m_maps = new HashMap<>(); public static Map getMap(String className) { synchronized(m_maps) { Map result = m_maps.get(className); if (result == null) { // TODO a synchronizedMap will break MultiThreadedDependentSampleTest // a not synchronizedMap will __sometimes__ break ParallelITestTest //result = Collections.synchronizedMap(new HashMap()); result = new HashMap<>(); m_maps.put(className, result); } return result; } // System.out.println("Putting class:" + className + " result:" + result); } public static void reset() { m_maps = new HashMap<>(); } } testng-6.9.12/src/test/java/test/thread/SingleThreadedSample3Test.java0000644000175000017500000000107712732165123025155 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(singleThreaded = true) public class SingleThreadedSample3Test extends BaseSequentialSample { @Test public void f1() { addId("SingleThreadedSample3Test.f1()", Thread.currentThread().getId()); } @Test // (dependsOnMethods = "f1") public void f2() { addId("SingleThreadedSample3Test.f2()", Thread.currentThread().getId()); } @Test // (dependsOnMethods = "f2") public void f3() { addId("SingleThreadedSample3Test.f3()", Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/thread/DataProviderThreadPoolSizeTest.java0000644000175000017500000000204412732165123026242 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class DataProviderThreadPoolSizeTest extends SimpleBaseTest { @Test public void shouldUseDefaultDataProviderThreadCount() { TestNG tng = create(DataProviderThreadPoolSizeSampleTest.class); tng.setGroups("parallel"); tng.run(); Assert.assertEquals(DataProviderThreadPoolSizeSampleTest.getThreadCount(), 10); } @Test public void shouldNotUseThreadsIfNotUsingParallel() { TestNG tng = create(DataProviderThreadPoolSizeSampleTest.class); tng.setGroups("sequential"); tng.run(); Assert.assertEquals(DataProviderThreadPoolSizeSampleTest.getThreadCount(), 1); } @Test public void shouldUseSpecifiedDataProviderThreadCount() { TestNG tng = create(DataProviderThreadPoolSizeSampleTest.class); tng.setGroups("parallel"); tng.setDataProviderThreadCount(3); tng.run(); Assert.assertEquals(DataProviderThreadPoolSizeSampleTest.getThreadCount(), 3); } } testng-6.9.12/src/test/java/test/thread/SingleThreadForParallelMethodsTest.java0000644000175000017500000000124212732165123027061 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.BaseTest; public class SingleThreadForParallelMethodsTest extends BaseTest { @Test(description = "GITHUB #1066: Regression is in priority. It broke parallel mode") public void testPriorityDoesNotAffectSingleThreadOrder() { PriorityInSingleThreadTest.initThreadLog(); Helper.reset(); addClass(PriorityInSingleThreadTest.class); setParallel(XmlSuite.ParallelMode.METHODS); setThreadCount(10); run(); Assert.assertEquals(PriorityInSingleThreadTest.getThreadCount(), 1); } } testng-6.9.12/src/test/java/test/thread/PriorityInSingleThreadTest.java0000644000175000017500000000076412732165123025452 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Test; @Test(singleThreaded = true) public class PriorityInSingleThreadTest extends BaseThreadTest { @Test(priority = -10) public void f1() {logCurrentThread();} @Test(priority = -5) public void f2() {logCurrentThread();} @Test(priority = 0) public void f3() {logCurrentThread();} @Test(priority = 5) public void f4() {logCurrentThread();} @Test(priority = 10) public void f5() {logCurrentThread();} } testng-6.9.12/src/test/java/test/thread/SuiteThreadCountTest.java0000644000175000017500000000151312732165123024273 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import org.testng.internal.thread.ThreadUtil; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * Test for test level thread-count. * * @author Alex Popescu */ public class SuiteThreadCountTest { private Set m_threads= Collections.synchronizedSet(new HashSet()); @Test public void test1() { m_threads.add(ThreadUtil.currentThreadInfo()); } @Test public void test2() { m_threads.add(ThreadUtil.currentThreadInfo()); } @AfterClass public void checkThreading() { Assert.assertEquals(m_threads.size(), 2, "Test should use 2 threads (suite level)"); } } testng-6.9.12/src/test/java/test/thread/FactoryTest.java0000644000175000017500000000265712732165123022462 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; public class FactoryTest { @Test /** * In non-parallel mode, we should only have one thread id * for the two methods invoked on B. */ public void verifyFactoryNotParallel() { runTest(null, 1); } /** * In parallel mode "methods", we should have as many thread id's * as there are test methods on B (2). */ @Test public void verifyFactoryParallelMethods() { runTest(XmlSuite.ParallelMode.METHODS, 2); } @Test public void verifyFactoryParallelTests() { runTest(XmlSuite.ParallelMode.TESTS, 1); } private void runTest(XmlSuite.ParallelMode parallelMode, int expectedThreadIdCount) { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { FactorySampleTest.class}); if (parallelMode != null) { tng.setParallel(parallelMode); } TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); B.setUp(); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 2); Assert.assertEquals(B.m_threadIds.size(), expectedThreadIdCount); // ppp("# TESTS RUN " + tla.getPassedTests().size() // + " ID:" + B.m_threadIds.size()); } private void ppp(String string) { System.out.println("[FactoryTest] " + string); } } testng-6.9.12/src/test/java/test/thread/SequentialTest.java0000644000175000017500000000435612732165123023163 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.BaseTest; import java.util.HashMap; import java.util.Map; public class SequentialTest extends BaseTest { @Test public void verifySequential1() { verifySequential(1); } @Test public void verifySequential2() { verifySequential(2); } @Test public void verifySequential3() { verifySequential(3); } @Test public void verifySingleThreaded1() { verifySingleThreaded(1); } @Test public void verifySingleThreaded2() { verifySingleThreaded(2); } @Test public void verifySingleThreaded3() { verifySingleThreaded(3); } public void verifySequential(int threadCount) { runTest(threadCount, SequentialSampleTest.class.getName(), SequentialSample2Test.class.getName(), SequentialSample3Test.class.getName()); } public void verifySingleThreaded(int threadCount) { runTest(threadCount, SingleThreadedSampleTest.class.getName(), SingleThreadedSample2Test.class.getName(), SingleThreadedSample3Test.class.getName()); } private void runTest(int threadCount, String... classes) { Helper.reset(); for (String c : classes) { addClass(c); } setParallel(XmlSuite.ParallelMode.METHODS); setThreadCount(threadCount); run(); Map[] maps = new Map[] { Helper.getMap(classes[0]), Helper.getMap(classes[1]), Helper.getMap(classes[2]), }; for(Map m : maps) { Assert.assertEquals(m.size(), 1); } long[] ids = new long[] { maps[0].keySet().iterator().next(), maps[1].keySet().iterator().next(), maps[2].keySet().iterator().next(), }; Map verifyMap = new HashMap<>(); for (long id : ids) { verifyMap.put(id, id); } Assert.assertEquals(verifyMap.size(), threadCount); ppp("COUNT:" + threadCount + " THREAD ID'S:" + ids[0] + " " + ids[1] + " " + ids[2]); } private static void ppp(String s) { if (false) { System.out.println("[SequentialTest] " + s); } } } testng-6.9.12/src/test/java/test/thread/FactorySampleTest.java0000644000175000017500000000037312732165123023615 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.Factory; import org.testng.annotations.Test; @Test public class FactorySampleTest { @Factory public Object[] init() { return new Object[] { new B(), new B(), }; } } testng-6.9.12/src/test/java/test/thread/DataProviderThreadPoolSizeSampleTest.java0000644000175000017500000000361112732165123027405 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class DataProviderThreadPoolSizeSampleTest extends BaseThreadTest { @BeforeClass(alwaysRun = true) public void setUp() { log(getClass().getName(), "Init log ids"); initThreadLog(); } @DataProvider(parallel = true) public Object[][] parallelDataProvider() { return createArray(); } @DataProvider public Object[][] sequentialDataProvider() { return createArray(); } private Object[][] createArray() { int i = 0; return new Object[][] { new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, new Object[] { i++ }, }; } @Test(dataProvider = "sequentialDataProvider", groups = "sequential") public void fSequential(Integer p) { long n = Thread.currentThread().getId(); log(getClass().getName(), "Sequential"); logThread(n); } @Test(dataProvider = "parallelDataProvider", groups = "parallel") public void fParallel(Integer p) { long n = Thread.currentThread().getId(); log(getClass().getName(), "Parallel"); logThread(n); } // @Test(dependsOnMethods = {"f1"}) // public void verify() { // int expected = 3; // Assert.assertEquals(m_threadIds.size(), expected, // "Should have run on " + expected + " threads but ran on " + m_threadIds.size()); // } } testng-6.9.12/src/test/java/test/thread/BaseSequentialSample.java0000644000175000017500000000106112732165123024246 0ustar eugeneeugenepackage test.thread; import java.util.Map; public class BaseSequentialSample { protected void addId(String method, long id) { ppp(method + " ID:" + id); getMap().put(id, id); } Map getMap() { Map result = Helper.getMap(getClass().getName()); ppp("RETURNING MAP " + result + " THIS:" + this); return result; } protected void ppp(String s) { if (false) { System.out.println("[" + getClass().getName() + " " + Thread.currentThread().getId() + " " + "] " + s); } } } testng-6.9.12/src/test/java/test/thread/MultiThreadedDependentTest.java0000644000175000017500000000466512732165123025436 0ustar eugeneeugenepackage test.thread; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; import java.util.Map; /** * Test that classes with dependent methods are still run in different threads * and in the correct order. */ public class MultiThreadedDependentTest extends SimpleBaseTest { /** * Make sure that the topological order is preserved and that if * the TestNG runner is configured to run n threads, the dependent * methods are using these n threads. */ private void assertOrder(List methods) { List expectedMethods = Arrays.asList(new String[] { "a1", "a2", "a3", "b1", "b2", "b3", "b4", "b5", "c1", "d", "x", "y", "z", "t" }); int size = expectedMethods.size(); Assert.assertEquals(methods.size(), size); for (String em : expectedMethods) { Assert.assertTrue(methods.contains(em)); } Map map = Maps.newHashMap(); for (String m : methods) { map.put(m, Boolean.TRUE); if ("b1".equals(m) || "b2".equals(m) || "b3".equals(m) || "b4".equals(m) || "b5".equals(m)) { Assert.assertTrue(map.get("a1")); Assert.assertTrue(map.get("a2")); Assert.assertTrue(map.get("a3")); } if ("d".equals(m)) { Assert.assertTrue(map.get("a1")); Assert.assertTrue(map.get("a2")); } if ("c1".equals(m)) { Assert.assertTrue(map.get("b1")); Assert.assertTrue(map.get("b2")); } } Assert.assertEquals(map.size(), size); for (Boolean val : map.values()) { Assert.assertTrue(val); } } @Test public void test2Threads() { test(2); } @Test public void test3Threads() { test(3); } private void test(int threadCount) { Helper.reset(); MultiThreadedDependentSampleTest.m_methods = Lists.newArrayList(); TestNG tng = create(MultiThreadedDependentSampleTest.class); tng.setThreadCount(threadCount); tng.setParallel(XmlSuite.ParallelMode.METHODS); Map map = Helper.getMap(MultiThreadedDependentSampleTest.class.getName()); synchronized(map) { tng.run(); Assert.assertTrue(map.size() > 1, "Map size:" + map.size() + " expected more than 1"); assertOrder(MultiThreadedDependentSampleTest.m_methods); } } } testng-6.9.12/src/test/java/test/thread/ThreadPoolSizeBase.java0000644000175000017500000000056312732165123023674 0ustar eugeneeugenepackage test.thread; import org.testng.annotations.BeforeClass; public class ThreadPoolSizeBase extends BaseThreadTest { @BeforeClass public void setUp() { log(getClass().getName(), "Init log ids"); initThreadLog(); } protected void logThread() { long n = Thread.currentThread().getId(); log(getClass().getName(), ""); logThread(n); } } testng-6.9.12/src/test/java/test/classgroup/0000755000175000017500000000000012732165123020251 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/classgroup/Second.java0000644000175000017500000000037112732165123022330 0ustar eugeneeugenepackage test.classgroup; import org.testng.annotations.Test; @Test(dependsOnGroups = { "first" }) public class Second { @Test public void verify() { assert First.allRun() : "Methods for class First should have been invoked first."; } }testng-6.9.12/src/test/java/test/classgroup/First.java0000644000175000017500000000060012732165123022177 0ustar eugeneeugenepackage test.classgroup; import org.testng.annotations.Test; @Test(groups = { "first" }) public class First { private static boolean m_first1 = false; private static boolean m_first2 = false; @Test public void first1() { m_first1 = true; } @Test public void first2() { m_first2 = true; } static boolean allRun() { return m_first1 && m_first2; } }testng-6.9.12/src/test/java/test/dependsongroup/0000755000175000017500000000000012732165123021123 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/dependsongroup/TestFixture1.java0000644000175000017500000000026112732165123024334 0ustar eugeneeugenepackage test.dependsongroup; import org.testng.annotations.BeforeTest; public class TestFixture1 { @BeforeTest(groups={"test", "testgroup"}) public void setup() { } } testng-6.9.12/src/test/java/test/dependsongroup/ZeroSampleTest.java0000644000175000017500000000042012732165123024703 0ustar eugeneeugenepackage test.dependsongroup; import org.testng.annotations.Test; @Test(groups = { "zero" }) public class ZeroSampleTest { @Test public void zeroA() { // System.out.println("zeroA"); } @Test public void zeroB() { // System.out.println("zeroB"); } } testng-6.9.12/src/test/java/test/dependsongroup/SecondSampleTest.java0000644000175000017500000000047012732165123025204 0ustar eugeneeugenepackage test.dependsongroup; import org.testng.annotations.Test; @Test(groups = { "second" }, dependsOnGroups = { "zero" }) public class SecondSampleTest { @Test public void secondA() { // System.out.println("secondA"); } @Test public void secondB() { // System.out.println("secondB"); } }testng-6.9.12/src/test/java/test/dependsongroup/DependsOnGroupsTest.java0000644000175000017500000000156512732165123025714 0ustar eugeneeugenepackage test.dependsongroup; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class DependsOnGroupsTest extends SimpleBaseTest { @Test public void methodsShouldBeGroupedByClasses() { TestNG tng = create(new Class[] { ZeroSampleTest.class, FirstSampleTest.class, SecondSampleTest.class }); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); String[] expected = new String[] { "zeroA", "zeroB", "firstA", "firstB", "secondA", "secondB" }; for (int i = 0; i < expected.length; i++) { ITestResult testResult = tla.getPassedTests().get(i); Assert.assertEquals(testResult.getMethod().getMethodName(), expected[i]); } } } testng-6.9.12/src/test/java/test/dependsongroup/FirstSampleTest.java0000644000175000017500000000046412732165123025063 0ustar eugeneeugenepackage test.dependsongroup; import org.testng.annotations.Test; @Test(groups = { "first" }, dependsOnGroups = { "zero" }) public class FirstSampleTest { @Test public void firstA() { // System.out.println("firstA"); } @Test public void firstB() { // System.out.println("firstB"); } } testng-6.9.12/src/test/java/test/dependsongroup/suite.xml0000644000175000017500000000054112732165123022776 0ustar eugeneeugene testng-6.9.12/src/test/java/test/dependsongroup/TestFixture2.java0000644000175000017500000000044712732165123024343 0ustar eugeneeugenepackage test.dependsongroup; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class TestFixture2 { @BeforeTest(groups={"test"}, dependsOnGroups={"testgroup"}) public void setup() { } @Test(groups={"test"}) //@@ public void testMethod() { } } testng-6.9.12/src/test/java/test/v6/0000755000175000017500000000000012732165123016422 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/v6/C.java0000644000175000017500000000070712732165123017453 0ustar eugeneeugenepackage test.v6; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class C { @BeforeTest public void beforeTest() {} @AfterTest public void afterTest() {} @Test public void fc1() {} @BeforeSuite public void beforeSuite() {} @AfterSuite public void afterSuite() {} } testng-6.9.12/src/test/java/test/v6/B.java0000644000175000017500000000124312732165123017446 0ustar eugeneeugenepackage test.v6; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class B { @Test(dependsOnMethods = "fb1") public void fb2() { } @Test(groups = "1") public void fb1() {} @Test public void fb3() {} @BeforeMethod public void beforeMethod() {} @AfterMethod(groups = "1") public void afterMethod() {} @BeforeSuite public void beforeSuite() {} @BeforeClass public void beforeClass() {} @AfterClass public void afterClass() {} } testng-6.9.12/src/test/java/test/v6/A.java0000644000175000017500000000165512732165123017454 0ustar eugeneeugenepackage test.v6; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class A { @Test(dependsOnMethods = "fa1") public void fa2() { } @Test(groups = "1") public void fa1() {} @Test public void fa3() {} @BeforeGroups("1") public void beforeGroups() {} @AfterGroups("1") public void afterGroups() {} @BeforeMethod public void beforeMethod() {} @AfterMethod public void afterMethod() {} @BeforeSuite public void beforeSuite() {} @AfterSuite public void afterSuite() {} @BeforeClass public void beforeClass() {} @AfterClass public void afterClass() {} } testng-6.9.12/src/test/java/test/CountTest.java0000644000175000017500000000170712732165123020667 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import java.util.List; public class CountTest extends SimpleBaseTest { @Test(description = "Make sure that skipped methods are accurately counted") public void skippedMethodsShouldBeCounted() { TestNG tng = create(CountSampleTest.class); IReporter r = new IReporter() { @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { for (ISuite s : suites) { for (ISuiteResult sr : s.getResults().values()) { ITestContext ctx = sr.getTestContext(); Assert.assertEquals(2, ctx.getSkippedTests().size()); } } } }; tng.addListener(r); tng.run(); } } testng-6.9.12/src/test/java/test/testng109/0000755000175000017500000000000012732165123017625 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng109/SkippedTestWithExpectedExceptionTest.java0000644000175000017500000000071012732165123027762 0ustar eugeneeugenepackage test.testng109; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * This class/interface */ public class SkippedTestWithExpectedExceptionTest { @BeforeClass public void setup() { throw new RuntimeException("test-exception"); } @Test public void test1() { // empty } @Test(expectedExceptions={OutOfMemoryError.class}) public void test2() { // empty } } testng-6.9.12/src/test/java/test/attributes/0000755000175000017500000000000012732165123020255 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/attributes/AttributeTest.java0000644000175000017500000000166212732165123023730 0ustar eugeneeugenepackage test.attributes; import org.testng.ITestContext; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.Set; import junit.framework.Assert; public class AttributeTest { @BeforeClass public void bc(ITestContext ctx) { ctx.setAttribute("test", "1"); } @Test public void f1(ITestContext ctx) { Set names = ctx.getAttributeNames(); Assert.assertEquals(1, names.size()); Assert.assertTrue(names.contains("test")); Assert.assertEquals(ctx.getAttribute("test"), "1"); Object v = ctx.removeAttribute("test"); Assert.assertNotNull(v); ctx.setAttribute("test2", "2"); } @Test(dependsOnMethods = "f1") public void f2(ITestContext ctx) { Set names = ctx.getAttributeNames(); Assert.assertEquals(1, names.size()); Assert.assertTrue(names.contains("test2")); Assert.assertTrue(ctx.getAttribute("test2").equals("2")); } } testng-6.9.12/src/test/java/test/tmp/0000755000175000017500000000000012732165123016667 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/tmp/Tn.java0000644000175000017500000000073312732165123020116 0ustar eugeneeugenepackage test.tmp; import org.testng.Reporter; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class Tn { @Test (groups = {"g1"}) public void m1() { System.out.println("1"); } @Test (groups = {"g1"}, dependsOnMethods="m1") public void m2() { System.out.println("2"); } @Parameters(value = "param") @Test (groups = {"g2"}) public void m3(String param) { System.out.println("3"); Reporter.log("M3 WAS CALLED"); } } testng-6.9.12/src/test/java/test/tmp/TimeBombTest.java0000644000175000017500000000165412732165123022076 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Test; import java.lang.reflect.Method; import java.util.Calendar; public class TimeBombTest { @IgnoreUntil(time = "1022") @Test public void timeBomb() throws SecurityException, NoSuchMethodException { Method m = TimeBombTest.class.getMethod("timeBomb", new Class[0]); IgnoreUntil t = m.getAnnotation(IgnoreUntil.class); long now = Calendar.getInstance().getTimeInMillis(); long l = parseTime(t.time()); ppp("IGNORE:" + (now < l)); } private long parseTime(String string) { int hour = Integer.parseInt(string.substring(0, 2)); int minute = Integer.parseInt(string.substring(2)); Calendar result = Calendar.getInstance(); result.set(Calendar.HOUR_OF_DAY, hour); result.set(Calendar.MINUTE, minute); return result.getTimeInMillis(); } private void ppp(String string) { System.out.println("[TimeBombTest] " + string); } } testng-6.9.12/src/test/java/test/tmp/StaticInitializerTest.java0000644000175000017500000000045312732165123024027 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Test; @Test public class StaticInitializerTest { static { foo(); } public void testMe() { System.err.println("**** testMe ****"); } private static void foo() { throw new RuntimeException("FAILING"); } }testng-6.9.12/src/test/java/test/tmp/C.java0000644000175000017500000000100112732165123017704 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class C { @BeforeMethod public void cm() { // System.out.println("C.cm"); } @Test(dataProvider = "data") public void c(String s) { System.out.println("c(" + s + ")"); } @DataProvider(name = "data") static public Object[][] data() { return new Object[][] { new Object[] { "Foo" }, new Object[] { "Bar" }, }; } } testng-6.9.12/src/test/java/test/tmp/AnnotationTransformer.java0000644000175000017500000000237512732165123024076 0ustar eugeneeugenepackage test.tmp; import org.testng.IAnnotationTransformer; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class AnnotationTransformer implements IAnnotationTransformer, ITestListener { @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void onFinish(ITestContext context) { // TODO Auto-generated method stub } @Override public void onStart(ITestContext context) { // TODO Auto-generated method stub } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { // TODO Auto-generated method stub } @Override public void onTestFailure(ITestResult result) { // TODO Auto-generated method stub } @Override public void onTestSkipped(ITestResult result) { // TODO Auto-generated method stub } @Override public void onTestStart(ITestResult result) { // TODO Auto-generated method stub } @Override public void onTestSuccess(ITestResult result) { // TODO Auto-generated method stub } } testng-6.9.12/src/test/java/test/tmp/ConcreteTest.java0000644000175000017500000000065212732165123022137 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Configuration; import org.testng.annotations.Test; public class ConcreteTest extends Fixturable { @Configuration(beforeTest=true, afterGroups="fixture") public void beforeFixture() { ppp("BEFORE"); } @Test(groups = "fixture") public void test() { ppp("TEST"); } private static void ppp(String s) { System.out.println("[ConcreteTest] " + s); } } testng-6.9.12/src/test/java/test/tmp/AssertEqualsTest.java0000644000175000017500000000261412732165123023011 0ustar eugeneeugenepackage test.tmp; import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Random; import java.util.Set; public class AssertEqualsTest { private void log(String s) { System.out.println("[" + Thread.currentThread().getId() + "] " + s); } @Test(threadPoolSize = 3, invocationCount = 6) public void f1() { log("start"); try { int sleepTime = new Random().nextInt(500); Thread.sleep(sleepTime); } catch (Exception e) { log(" *** INTERRUPTED"); } log("end"); } @Test(threadPoolSize = 10, invocationCount = 10000) public void verifyMethodIsThreadSafe() { // foo(); } @Test(dependsOnMethods = "verifyMethodIsThreadSafe") public void verify() { // make sure that nothing was broken } public static void main(String[] args) { Set set1 = new LinkedHashSet(); Set set2 = new HashSet(); set1.add(5); set2.add(5); set1.add(6); set2.add(6); set1.add(1); set2.add(1); set1.add(9); set2.add(9); System.out.println("set1 is:" + set1.toString()); System.out.println("set2 is:" + set2.toString()); System.out.println("is set1 equals set2 :" + set1.equals(set2)); try { Assert.assertEquals(set1, set2, "set1 must equals with set2"); } catch (Exception ex) { ex.printStackTrace(); } } }testng-6.9.12/src/test/java/test/tmp/ParentTest.java0000644000175000017500000000073512732165123021630 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Configuration; import org.testng.annotations.Test; public class ParentTest { @Configuration(beforeTestMethod = true) public void btm1() { ppp("PARENT BEFORE TEST"); } @Configuration(afterTestMethod = true) public void atm1() { ppp("PARENT AFTER TEST"); } @Test public void t1() { ppp("TEST PARENT"); } private void ppp(String string) { System.out.println("[Parent] " + string); } } testng-6.9.12/src/test/java/test/tmp/TestCaseFactory.java0000644000175000017500000000054712732165123022603 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class TestCaseFactory { class MyTestClass { @Test public void testAll() { } } @Factory public Object[] createTestCases() { Object[] testCases = new Object[1]; testCases[0] = new MyTestClass() { }; return testCases; } }testng-6.9.12/src/test/java/test/tmp/Test0.java0000644000175000017500000000066412732165123020537 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Configuration; import org.testng.annotations.Test; public class Test0 { @Configuration(beforeTest = true) public void setup() { System.out.println("setup"); } @Test(groups = { "G0" }) public void test() { System.out.println("Test0.test"); } @Configuration(afterTest = true) public void tearDown() { System.out.println("tearDown"); } }testng-6.9.12/src/test/java/test/tmp/AFactory.java0000644000175000017500000000026112732165123021241 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Factory; public class AFactory { @Factory public Object[] create() { return new Object[] { new A(), new AA() }; } } testng-6.9.12/src/test/java/test/tmp/B.java0000644000175000017500000000050112732165123017707 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class B extends C { public static final String G = "group"; @BeforeMethod public void bm() { System.out.println("B.bm"); } @Test public void btest1() { System.out.println("B.btest1"); } } testng-6.9.12/src/test/java/test/tmp/BListener.java0000644000175000017500000000073012732165123021421 0ustar eugeneeugenepackage test.tmp; import org.testng.ITestResult; import org.testng.TestListenerAdapter; public class BListener extends TestListenerAdapter { public BListener() { System.out.println("BListener created"); } @Override public void onTestSuccess(ITestResult tr) { System.out.println("Success"); super.onTestSuccess(tr); } @Override public void onTestFailure(ITestResult tr) { System.out.println("Failure"); super.onTestFailure(tr); } } testng-6.9.12/src/test/java/test/tmp/ParamTest.java0000644000175000017500000000110712732165123021431 0ustar eugeneeugenepackage test.tmp; import org.testng.Reporter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ParamTest { @Test(dataProvider="dp") public void f(String s, int n) { // if ("Alois".equals(s)) assert false; Reporter.log("CALL " + n); ppp("TEST : " + s); } @DataProvider(name="dp") public Object[][] create() { return new Object[][] { new Object[] { "Cedric", 36}, new Object[] {"Alois", 35}, }; } private void ppp(String string) { System.err.println("[ParamTest] " + string); } } testng-6.9.12/src/test/java/test/tmp/p1/0000755000175000017500000000000012732165123017207 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/tmp/p1/ContainerTest.java0000644000175000017500000000054212732165123022635 0ustar eugeneeugenepackage test.tmp.p1; import static org.testng.AssertJUnit.assertNotNull; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public class ContainerTest { @BeforeSuite public void startup() { assertNotNull(null); } @AfterSuite public void shutdown() { assertNotNull(null); } } testng-6.9.12/src/test/java/test/tmp/ChildTest.java0000644000175000017500000000077012732165123021421 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Configuration; import org.testng.annotations.Test; public class ChildTest extends ParentTest { @Configuration(beforeTestMethod = true) public void btm2() { ppp("CHILD BEFORE TEST"); } @Configuration(afterTestMethod = true) public void atm2() { ppp("CHILD AFTER TEST"); } @Override @Test public void t1() { ppp("TEST CHILD"); } private void ppp(String string) { System.out.println("[Parent] " + string); } } testng-6.9.12/src/test/java/test/tmp/IgnoreUntil.java0000644000175000017500000000070012732165123021766 0ustar eugeneeugenepackage test.tmp; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({METHOD, TYPE, CONSTRUCTOR}) public @interface IgnoreUntil { /** * Format: hhmm */ public String time(); } testng-6.9.12/src/test/java/test/tmp/verify/0000755000175000017500000000000012732165123020173 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/tmp/verify/VerifyTest.java0000644000175000017500000000052112732165123023140 0ustar eugeneeugenepackage test.tmp.verify; import org.testng.annotations.Test; public class VerifyTest { @Test public void f2() { System.out.println("f2()"); } @Test public void f1() { System.out.println("f1()"); } @Verify public void verify() { // throw new RuntimeException(); // System.out.println("verify()"); } } testng-6.9.12/src/test/java/test/tmp/verify/Verify.java0000644000175000017500000000035512732165123022305 0ustar eugeneeugenepackage test.tmp.verify; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target(java.lang.annotation.ElementType.METHOD) public @interface Verify { } testng-6.9.12/src/test/java/test/tmp/verify/VerifyInterceptor.java0000644000175000017500000000502212732165123024520 0ustar eugeneeugenepackage test.tmp.verify; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.TestNGUtils; import org.testng.collections.Maps; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; public class VerifyInterceptor implements IMethodInterceptor { /** * @return the list of methods received in parameters with all methods * annotated with @Verify inserted after each of these test methods. * * This happens in two steps: * - Find all the methods annotated with @Verify in the classes that contain test methods * - Insert these verify methods after each method passed in parameter * These @Verify methods are stored in a map keyed by the class in order to avoid looking them * up more than once on the same class. */ @Override public List intercept(List methods, ITestContext context) { List result = new ArrayList<>(); Map, List> verifyMethods = Maps.newHashMap(); for (IMethodInstance mi : methods) { ITestNGMethod tm = mi.getMethod(); List verify = verifyMethods.get(tm.getRealClass()); if (verify == null) { verify = findVerifyMethods(tm.getRealClass(), tm); } result.add(mi); result.addAll(verify); } return result; } /** * @return all the @Verify methods found on @code{realClass} */ private List findVerifyMethods(Class realClass, final ITestNGMethod tm) { List result = new ArrayList<>(); for (final Method m : realClass.getDeclaredMethods()) { Annotation a = m.getAnnotation(Verify.class); if (a != null) { final ITestNGMethod vm = TestNGUtils.createITestNGMethod(tm, m); result.add(new IMethodInstance() { @Override public Object[] getInstances() { return tm.getInstances(); } @Override public ITestNGMethod getMethod() { return vm; } public int compareTo(IMethodInstance o) { if (getInstances()[0] == o.getInstances()[0]) { return 0; } else { return -1; } } @Override public Object getInstance() { return tm.getInstance(); } }); } } return result; } } testng-6.9.12/src/test/java/test/tmp/Tmp.java0000644000175000017500000000111112732165123020264 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Test; import java.util.Random; public class Tmp { @Test(invocationCount = 10, threadPoolSize = 5) public void f() { ppp("START " + Thread.currentThread().getId()); try { Random r = new Random(); Thread.sleep(Math.abs(r.nextInt() % 300)); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); handled.printStackTrace(); } ppp("END " + Thread.currentThread().getId()); } private void ppp(String string) { System.out.println("[Tmp] " + string); } } testng-6.9.12/src/test/java/test/tmp/TestA.java0000644000175000017500000000202212732165123020546 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class TestA { @BeforeClass public void insertA() { // Inserts an entity 'A'. This is an expensive operation. // After this, the entity 'A' is the first row on the table. } @Test public void testGetA() { // Checks that 'A' is the first row on the table, and loads it. } @Test(dependsOnMethods = "testGetA") public void testViewA_Details1() { // Loads the first row (assumed A) and checks some details } @Test(dependsOnMethods = "testGetA") public void testViewA_Details2() { // Loads the first row (assumed A) and checks some details } @Test(dependsOnMethods = "testGetA") public void testViewA_Details3() { // Loads the first row (assumed A) and checks some details } @Test(dependsOnMethods = "testGetA") public void testViewA_Details4() { // Loads the first row (assumed A) and checks some details } } testng-6.9.12/src/test/java/test/tmp/Fixturable.java0000644000175000017500000000043612732165123021642 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Configuration; public class Fixturable { @Configuration(beforeTest=true, groups="fixture") public void setupFixture() { ppp("SETUP"); } private static void ppp(String s) { System.out.println("[Fixturable] " + s); } } testng-6.9.12/src/test/java/test/tmp/RetryAnalyzer.java0000644000175000017500000000040112732165123022340 0ustar eugeneeugenepackage test.tmp; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; public class RetryAnalyzer implements IRetryAnalyzer { @Override public boolean retry(ITestResult result) { System.out.println("retry()"); return true; } } testng-6.9.12/src/test/java/test/tmp/p2/0000755000175000017500000000000012732165123017210 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/tmp/p2/ServiceTest.java0000644000175000017500000000035012732165123022311 0ustar eugeneeugenepackage test.tmp.p2; import static org.testng.AssertJUnit.assertNotNull; import org.testng.annotations.Test; public class ServiceTest { @Test(groups = {"group1"}) public void service() { assertNotNull(null); } }testng-6.9.12/src/test/java/test/tmp/A.java0000644000175000017500000000150112732165123017707 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Test; import org.testng.asserts.SoftAssert; @Test public class A { // private FlexibleAssert m_assert = new FlexibleAssert(); private SoftAssert m_assert = new SoftAssert(); // private LoggingAssert m_assert = new LoggingAssert(); public void test1() { m_assert.assertTrue(true, "test1()"); } public void test2() { m_assert.assertTrue(true, "test2()"); } // @AfterClass // public void ac() { // System.out.println("Tests run in this class:" + m_assert.getMessages()); // } public void multiple() { m_assert.assertTrue(true, "Success 1"); m_assert.assertTrue(true, "Success 2"); m_assert.assertTrue(false, "Failure 1"); m_assert.assertTrue(true, "Success 3"); m_assert.assertTrue(false, "Failure 2"); m_assert.assertAll(); } }testng-6.9.12/src/test/java/test/tmp/Test1.java0000644000175000017500000000031012732165123020524 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Test; @Test(dependsOnGroups = { "G0" }) public class Test1 { public void test() { System.out.println("Test1.test"); } }testng-6.9.12/src/test/java/test/tmp/Sub.java0000644000175000017500000000131012732165123020256 0ustar eugeneeugenepackage test.tmp; import org.testng.Assert; import org.testng.annotations.Configuration; import org.testng.annotations.Test; @Test(groups = {"sub"}) public class Sub extends Base { boolean m_beforeTest; boolean m_afterTest; @Configuration(beforeTestClass = true) public void subSetup() { System.out.println("sub before class"); } @Configuration(afterTestClass = true) public void subTeardown() { System.out.println("sub after class"); } public void subTest() { System.out.println ("sub test"); } @Configuration(afterSuite = true) public void verify() { Assert.assertTrue(m_beforeTest); Assert.assertTrue(m_afterTest); } } testng-6.9.12/src/test/java/test/tmp/Test_TestListenerAppender.java0000644000175000017500000000074012732165123024636 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class Test_TestListenerAppender { @DataProvider(name = "test1") public Object[][] createData1() { // throw new RuntimeException("Intentionally thrown exception"); return new Object[][] { { "Cedric", 36}, {"Anne", 37}, }; } @Test(dataProvider = "test1") public void verifyData1(String n1, Integer n2) { System.out.println(n1 + " " + n2); } } testng-6.9.12/src/test/java/test/tmp/BeforeGroupTest.java0000644000175000017500000000103212732165123022605 0ustar eugeneeugenepackage test.tmp; import org.testng.ITestContext; import org.testng.annotations.BeforeGroups; public class BeforeGroupTest { // Logger l = LoggerFactory.getLogger(this.getClass()); @BeforeGroups(groups = { "NewUser" }, value = { "NewUser" }) public void preNewUser(ITestContext itc) { System.out.println("BEFOREGROUPS perfroming pre groups init"); // m_inj = Guice.createInjector(new JUnitModule(), new RequestModule(), // new GenericModule(), new SecurityModule()); // itc.setAttribute("injector", m_inj); } }testng-6.9.12/src/test/java/test/tmp/TestB.java0000644000175000017500000000172012732165123020553 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class TestB { @BeforeClass public void insertB() { // Inserts an entity 'B'. This is an expensive operation. // After this, the entity 'B' is the first row on the table. } @Test public void testGetB() { // Checks that 'B' is the first row on the table, and loads it. } @Test(dependsOnMethods = "testGetB") public void testViewB_Details1() { // Loads the first row (assumed B) and checks some details } @Test(dependsOnMethods = "testGetB") public void testViewB_Details2() { // Loads the first row (assumed B) and checks some details } @Test(dependsOnMethods = "testGetB") public void testViewB_Details3() { // Loads the first row (assumed B) and checks some details } @Test(dependsOnMethods = "testGetB") public void testViewB_Details4() { } } testng-6.9.12/src/test/java/test/tmp/ExponentTest.java0000644000175000017500000000211612732165123022172 0ustar eugeneeugenepackage test.tmp; import static org.testng.Assert.assertEquals; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @Test(suiteName = "Exponent suite", testName = "Exponent test") public class ExponentTest { @DataProvider(name = "random") public Object[][] generateRandomExps() { // This array should be generated with random numbers return new Object[][] { new Object[] { 0.0, Math.exp(0) }, new Object[] { 1.0, Math.exp(1) }, new Object[] { 2.0, Math.exp(2) }, }; } @BeforeMethod public void setUp() { ppp("BEFORE METHOD"); } @Test(dataProvider = "random") public void testExponent(double exponent, double expected) { ppp("COMPARING " + myExpFunction(exponent) + " AND " + expected); assertEquals(myExpFunction(exponent), expected); } private static void ppp(String s) { System.out.println("[ExponentTest] " + s); } private double myExpFunction(double exponent) { return Math.exp(exponent); } } testng-6.9.12/src/test/java/test/tmp/RegisterCommandTest.java0000644000175000017500000000113012732165123023450 0ustar eugeneeugenepackage test.tmp; import org.testng.ITestContext; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @Test(groups = { "NewUser" }) public class RegisterCommandTest { // Logger l = LoggerFactory.getLogger(this.getClass()); @BeforeClass public void beforeClass(ITestContext itc) { System.out.println("BEFORECLASS getting injector from context"); // m_inj = (Injector) itc.getAttribute("injector"); // m_inj.injectMembers(this); } public void testExecute(ITestContext itc) throws Exception { System.out.println("TESTEXECUTE do somthing"); } } testng-6.9.12/src/test/java/test/tmp/TestNGBug.java0000644000175000017500000000103112732165123021327 0ustar eugeneeugenepackage test.tmp; import org.testng.Reporter; import org.testng.annotations.Test; public class TestNGBug { // @Configuration(beforeTestMethod = true) public void init() { ppp("Base.init()"); } @Test public void test1() { Reporter.log("Child.test1"); } @Test(enabled = false) public void test2() { Reporter.log("Child.test2"); } @Test(groups = "a") public void test3() { Reporter.log("Child.test3"); } private void ppp(String string) { System.out.println("[TestNGBug] " + string); } } testng-6.9.12/src/test/java/test/tmp/b/0000755000175000017500000000000012732165123017110 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/tmp/b/TmpB.java0000644000175000017500000000022412732165123020613 0ustar eugeneeugenepackage test.tmp.b; import org.testng.annotations.Test; public class TmpB { @Test public void tmpb1() { System.out.println("tmpb1"); } }testng-6.9.12/src/test/java/test/tmp/AA.java0000644000175000017500000000217312732165123020016 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; @Test(sequential = true) public class AA { private int m_n; public AA() {} public AA(int n) { m_n = n; } private void log(String s) { System.out.println(" [AA(" + m_n + ") thread:" + Thread.currentThread().getId() + "] " + s); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 42 }, }; } // @BeforeClass // public void bc() { // log("beforeClass"); // } // // @AfterClass // public void ac() { // log("afterClass"); // } @Factory public Object[] create() { return new Object[] { new A(), new AA() }; } @Test public void aatest1() { log("aatest1"); } @Test(dependsOnMethods = "aatest1") public void aatest2() { log("aatest2"); } // @Test(priority = 3) public void atest3() { } public String getTestName() { return "This is test A"; } // @Test(groups = "mytest", dependsOnMethods = "g") // public void f() { // } // // // @AfterMethod // public void after() { // } } testng-6.9.12/src/test/java/test/tmp/DataDrivenTest.java0000644000175000017500000000201312732165123022407 0ustar eugeneeugenepackage test.tmp; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Properties; public class DataDrivenTest { @DataProvider(name = "provider") public Object[][] createData() throws FileNotFoundException, IOException { Properties p = new Properties(); List vResult = new ArrayList<>(); p.load(new FileInputStream(new File("c:/t/data.properties"))); for (Enumeration e = p.keys(); e.hasMoreElements(); ) { vResult.add(e.nextElement()); } Object[][] result = new Object[vResult.size()][1]; for (int i = 0; i < result.length; i++) { result[i] = new Object[] { vResult.get(i) }; } return result; } @Test(dataProvider = "provider") public void foo(int n) { Assert.assertTrue(n > 0); } } testng-6.9.12/src/test/java/test/tmp/TestFixture.java0000644000175000017500000000117112732165123022020 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.Configuration; public class TestFixture { public static int globalCallSequence = 0; public static int printGlobalCallSequence(String methodName) { globalCallSequence++; System.err.println("*** " + methodName + ": globalCallSequence=" + globalCallSequence); return globalCallSequence; } public int fixtureBeforeTestCallSequence; @Configuration(beforeTest=true, groups="fixture") public void beforeTest() { fixtureBeforeTestCallSequence = printGlobalCallSequence("TestFixture.beforeTest"); } public int getSomeRandomValue() { return 20; } } testng-6.9.12/src/test/java/test/tmp/Base.java0000644000175000017500000000030312732165123020400 0ustar eugeneeugenepackage test.tmp; import org.testng.annotations.BeforeMethod; public class Base { @BeforeMethod public void bm() { System.out.println("Thread" + Thread.currentThread().getId()); } }testng-6.9.12/src/test/java/test/InvocationAndSuccessPercentageTest.java0000644000175000017500000000616412732165123025664 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; /** * This class tests invocationCount and successPercentage * * @author cbeust */ public class InvocationAndSuccessPercentageTest extends BaseTest { @Test public void invocationCount() { addClass("test.sample.InvocationCountTest"); addIncludedGroup("invocationOnly"); run(); String[] passed = { "tenTimesShouldSucceed", }; String[] failed = { }; verifyResults(getPassedTests(), 10, "passed tests"); // Map passedTests = getPassedTests(); // Set keys = passedTests.keySet(); // Object firstKey = keys.iterator().next(); // ITestResult passedResult = (ITestResult) passedTests.get(firstKey); // int n = passedResult.getPassedMethods().size(); // assert n == 10 : // "Expected 10 tests to have passed, but only found " + n; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } /** * Result expected: * 8 passed * 2 failed but within success percentage */ @Test public void successPercentageThatSucceeds() { addClass("test.sample.InvocationCountTest"); addIncludedGroup("successPercentageThatSucceedsOnly"); run(); String[] passed = { "successPercentageShouldSucceed", }; String[] failed = { }; String[] failedButWithinSuccessPercentage = { "successPercentageShouldSucceed", }; verifyTests("FailedButWithinSuccessPercentage", failedButWithinSuccessPercentage, getFailedButWithinSuccessPercentageTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); // Should have 8 passed, 2 failed but within success percentage verifyResults(getPassedTests(), 8, "passed tests"); verifyResults( getFailedButWithinSuccessPercentageTests(), 2, "failed_but_within_success_percentage_tests"); } /** * Result expected: * 8 passed * 1 failed but within success percentage * 1 failed */ @Test public void successPercentageThatFails() { addClass(test.sample.InvocationCountTest.class); addIncludedGroup("successPercentageThatFailsOnly"); run(); String[] passed = { "successPercentageShouldFail", }; String[] failed = { "successPercentageShouldFail", }; String[] failedButWithinSuccessPercentage = { "successPercentageShouldFail", }; verifyTests("FailedButWithinSuccessPercentage", failedButWithinSuccessPercentage, getFailedButWithinSuccessPercentageTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); // Should have 8 passed, 2 failed but within success percentage verifyResults(getPassedTests(), 8, "passed tests"); verifyResults(getFailedTests(), 1, "failed tests"); verifyResults( getFailedButWithinSuccessPercentageTests(), 1, "failed_but_within_success_percentage_tests"); } public static void ppp(String s) { System.out.println("[Invocation] " + s); } } testng-6.9.12/src/test/java/test/testng106/0000755000175000017500000000000012732165123017622 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng106/FailingSuiteFixture.java0000644000175000017500000000047112732165123024421 0ustar eugeneeugenepackage test.testng106; import org.testng.annotations.BeforeSuite; /** * TESTNG-106: failing @BeforeSuite doesn't skip all tests */ public class FailingSuiteFixture { static int s_invocations = 0; @BeforeSuite public void failingBeforeSuite() { throw new RuntimeException(); } } testng-6.9.12/src/test/java/test/testng106/Test2.java0000644000175000017500000000056012732165123021467 0ustar eugeneeugenepackage test.testng106; import org.testng.annotations.Test; /** * This class/interface */ public class Test2 { @Test public void method2() { System.out.println("method2"); FailingSuiteFixture.s_invocations++; } @Test public void method3() { System.out.println("method3"); FailingSuiteFixture.s_invocations++; } } testng-6.9.12/src/test/java/test/testng106/TestNG106.java0000644000175000017500000000152512732165123022063 0ustar eugeneeugenepackage test.testng106; import java.util.Arrays; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; public class TestNG106 extends SimpleBaseTest { @Test public void testFailingBeforeSuiteShouldSkipAllTests() throws Exception { TestNG tng = create(); XmlSuite s = createXmlSuite("TESTNG-106"); createXmlTest(s, "myTest1", FailingSuiteFixture.class.getName(), Test1.class.getName()); createXmlTest(s, "myTest2", Test1.class.getName()); createXmlTest(s, "myTest3", Test2.class.getName()); createXmlTest(s, "myTest-last", Test2.class.getName()); tng.setXmlSuites(Arrays.asList(s)); tng.run(); Assert.assertEquals(FailingSuiteFixture.s_invocations, 0, "@BeforeSuite has failed. All tests should be skipped."); } } testng-6.9.12/src/test/java/test/testng106/Test1.java0000644000175000017500000000036712732165123021473 0ustar eugeneeugenepackage test.testng106; import org.testng.annotations.Test; /** * This class/interface */ public class Test1 { @Test public void method1() { System.out.println("method1"); FailingSuiteFixture.s_invocations++; } } testng-6.9.12/src/test/java/test/asserttests/0000755000175000017500000000000012732165123020453 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/asserttests/AssertTest.java0000644000175000017500000000776212732165123023433 0ustar eugeneeugenepackage test.asserttests; import org.testng.Assert; import org.testng.Assert.ThrowingRunnable; import org.testng.annotations.Test; import org.testng.collections.Sets; import java.io.IOException; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import static org.testng.Assert.expectThrows; public class AssertTest { @Test public void noOrderSuccess() { String[] rto1 = { "boolean", "BigInteger", "List",}; String[] rto2 = { "List", "BigInteger", "boolean",}; Assert.assertEqualsNoOrder(rto1, rto2); } @Test(expectedExceptions = AssertionError.class) public void noOrderFailure() { String[] rto1 = { "a", "a", "b",}; String[] rto2 = { "a", "b", "b",}; Assert.assertEqualsNoOrder(rto1, rto2); } @Test public void intArray_Issue4() { int[] intArr00 = {1}; int[] intArr01 = {1}; Assert.assertEquals(intArr00, intArr01); } @Test(expectedExceptions = AssertionError.class) public void arraysFailures_1() { int[] intArr = {1, 2}; long[] longArr = {1, 2}; Assert.assertEquals(intArr, longArr); } @Test(expectedExceptions = AssertionError.class) public void arraysFailures_2() { int[] intArr = {1, 2}; Assert.assertEquals(intArr, (long) 1); } @Test(expectedExceptions = AssertionError.class) public void arraysFailures_3() { long[] longArr = {1}; Assert.assertEquals((long) 1, longArr); } @Test public void setsSuccess() { Set set1 = Sets.newHashSet(); Set set2 = Sets.newHashSet(); set1.add(1); set2.add(1); set1.add(3); set2.add(3); set1.add(2); set2.add(2); Assert.assertEquals(set1, set2); Assert.assertEquals(set2, set1); } @Test(expectedExceptions = AssertionError.class) public void expectThrowsRequiresAnExceptionToBeThrown() { expectThrows(Throwable.class, nonThrowingRunnable()); } @Test public void expectThrowsIncludesAnInformativeDefaultMessage() { try { expectThrows(Throwable.class, nonThrowingRunnable()); } catch (AssertionError ex) { assertEquals("Expected Throwable to be thrown, but nothing was thrown", ex.getMessage()); return; } fail(); } @Test public void expectThrowsReturnsTheSameObjectThrown() { NullPointerException npe = new NullPointerException(); Throwable throwable = expectThrows(Throwable.class, throwingRunnable(npe)); assertSame(npe, throwable); } @Test(expectedExceptions = AssertionError.class) public void expectThrowsDetectsTypeMismatchesViaExplicitTypeHint() { NullPointerException npe = new NullPointerException(); expectThrows(IOException.class, throwingRunnable(npe)); } @Test public void expectThrowsWrapsAndPropagatesUnexpectedExceptions() { NullPointerException npe = new NullPointerException("inner-message"); try { expectThrows(IOException.class, throwingRunnable(npe)); } catch (AssertionError ex) { assertSame(npe, ex.getCause()); assertEquals("inner-message", ex.getCause().getMessage()); return; } fail(); } @Test public void expectThrowsSuppliesACoherentErrorMessageUponTypeMismatch() { NullPointerException npe = new NullPointerException(); try { expectThrows(IOException.class, throwingRunnable(npe)); } catch (AssertionError error) { assertEquals("Expected IOException to be thrown, but NullPointerException was thrown", error.getMessage()); assertSame(npe, error.getCause()); return; } fail(); } private static ThrowingRunnable nonThrowingRunnable() { return new ThrowingRunnable() { public void run() throws Throwable { } }; } private static ThrowingRunnable throwingRunnable(final Throwable t) { return new ThrowingRunnable() { public void run() throws Throwable { throw t; } }; } @Test public void doubleNaNAssertion() { Assert.assertEquals(Double.NaN, Double.NaN, 0.0); } } testng-6.9.12/src/test/java/test/asserttests/ArrayEqualityAssertTest.java0000644000175000017500000002272112732165123026140 0ustar eugeneeugenepackage test.asserttests; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; /** * Tests different equality cases for nested collections * and arrays. */ public class ArrayEqualityAssertTest { @Test public void arrayAssertEquals() { assertEquals(new int[]{ 42 }, new int[] { 42 }, "arrays of primitives are compared by value in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayAssertNotEquals() { assertNotEquals(new int[]{ 42 }, new int[] { 42 }, "arrays of primitives are compared by value in assertNotEquals"); } @Test public void boxedArrayAssertEquals() { assertEquals(new Integer[]{ 42 }, new Integer[] { 42 }, "arrays of wrapped values are compared by value in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void boxedArrayAssertNotEquals() { assertNotEquals(new Integer[]{ 42 }, new Integer[] { 42 }, "arrays of wrapped values are compared by value in assertNotEquals"); } @Test public void mixedArraysAssertEquals() { assertEquals(new int[]{ 42 }, new Integer[] { 42 }, "arrays of wrapped values are compared by value in assertEquals"); assertEquals(new Integer[]{ 42 }, new int[] { 42 }, "arrays of wrapped values are compared by value in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void mixedArraysAssertNotEquals() { assertNotEquals(new int[]{ 42 }, new Integer[] { 42 }, "arrays of wrapped values are compared by value in assertNotEquals"); assertNotEquals(new Integer[]{ 42 }, new int[] { 42 }, "arrays of wrapped values are compared by value in assertNotEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayInsideListAssertEquals() { List list = Arrays.asList( new int[]{ 42 } ); List listCopy = Arrays.asList( new int[]{ 42 } ); assertEquals(list, listCopy, "arrays inside lists are compared by reference in assertEquals"); } @Test public void arrayInsideListAssertNotEquals() { List list = Arrays.asList( new int[]{ 42 } ); List listCopy = Arrays.asList( new int[]{ 42 } ); assertNotEquals(list, listCopy, "arrays inside lists are compared by reference in assertNotEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayInsideMapAssertEquals() { Map map = new HashMap<>(); map.put("array", new int[]{ 42 }); Map mapCopy = new HashMap<>(); mapCopy.put("array", new int[]{ 42 }); // arrays inside maps are compared by reference in assertEquals(Map,Map) assertEquals(map, mapCopy); } @Test(expectedExceptions = AssertionError.class) public void arrayInsideMapAssertEqualsWithMessage() { Map map = new HashMap<>(); map.put("array", new int[]{ 42 }); Map mapCopy = new HashMap<>(); mapCopy.put("array", new int[]{ 42 }); assertEquals(map, mapCopy, "arrays inside maps are compared by reference in assertEquals(Map,Map,String)"); } @Test public void arrayInsideMapAssertNotEquals() { Map map = new HashMap<>(); map.put("array", new int[]{ 42 }); Map mapCopy = new HashMap<>(); mapCopy.put("array", new int[]{ 42 }); assertNotEquals(map, mapCopy, "arrays inside maps are compared by reference in assertNotEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayInsideSetAssertEquals() { Set set = new HashSet<>(); set.add(new int[]{ 42 }); Set setCopy = new HashSet<>(); setCopy.add(new int[]{ 42 }); assertEquals(set, setCopy, "arrays inside sets are compared by reference in assertNotEquals"); } @Test public void arrayInsideSetAssertNotEquals() { Set set = new HashSet<>(); set.add(new int[]{ 42 }); Set setCopy = new HashSet<>(); setCopy.add(new int[]{ 42 }); assertNotEquals(set, setCopy, "arrays inside sets are compared by reference in assertNotEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayDeepInListsAssertEquals() { List> list = Collections.singletonList(Arrays.asList(new int[]{ 42 })); List> listCopy = Collections.singletonList(Arrays.asList(new int[]{ 42 })); assertEquals(list, listCopy, "arrays inside lists which are inside lists themselves are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayDeepInMapsAssertEquals() { Map> map = new HashMap<>(); Map innerMap = new HashMap<>(); innerMap.put("array", new int[]{ 42 }); map.put("map", innerMap); Map> mapCopy = new HashMap<>(); Map innerMapCopy = new HashMap<>(); innerMapCopy.put("array", new int[]{ 42 }); mapCopy.put("map", innerMapCopy); assertEquals(map, mapCopy, "arrays inside maps which are inside maps themselves are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayDeepInListAndMapAssertEquals() { List> list = new ArrayList<>(); Map innerMap = new HashMap<>(); innerMap.put("array", new int[]{ 42 }); list.add(innerMap); List> listCopy = new ArrayList<>(); Map innerMapCopy = new HashMap<>(); innerMapCopy.put("array", new int[]{ 42 }); list.add(innerMapCopy); assertEquals(list, listCopy, "arrays inside maps which are inside lists themselves are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayDeepInMapAndListAssertEquals() { Map> map = new HashMap<>(); map.put("list", Arrays.asList(new int[]{ 42 })); Map> mapCopy = new HashMap<>(); mapCopy.put("list", Arrays.asList(new int[]{ 42 })); assertEquals(map, mapCopy, "arrays inside maps which are inside lists themselves are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayInsideIterableAssertEquals() { Iterable iterable = Arrays.asList( new int[]{ 42 } ); Iterable iterableCopy = Arrays.asList( new int[]{ 42 } ); assertEquals(iterable, iterableCopy, "arrays inside Iterables are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayDeepInIterablesAssertEquals() { List> iterable = Collections.singletonList(Arrays.asList(new int[]{ 42 })); List> iterableCopy = Collections.singletonList(Arrays.asList(new int[]{ 42 })); assertEquals(iterable, iterableCopy, "arrays inside Iterables which are inside Iterables themselves are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayInsideArrayAssertEquals() { int[][] array = new int[][] { new int[]{ 42 } }; int[][] arrayCopy = new int[][] { new int[]{ 42 } }; assertEquals(array, arrayCopy, "arrays inside arrays are compared by reference in assertEquals"); } @Test(expectedExceptions = AssertionError.class) public void arrayDeepInArraysAssertEquals() { int[][][] array = new int[][][] { new int[][] { new int[]{ 42 } } }; int[][][] arrayCopy = new int[][][] { new int[][] { new int[]{ 42 } } }; assertEquals(array, arrayCopy, "arrays inside arrays which are inside arrays themselves are compared by reference in assertEquals"); } @SuppressWarnings("unchecked") @Test(expectedExceptions = AssertionError.class) public void arrayDeepInArrayAndListAssertEquals() { List[] array = new List[] { Arrays.asList(new int[]{ 42 }) }; List[] arrayCopy = new List[] { Arrays.asList(new int[]{ 42 }) }; assertEquals(array, arrayCopy, "arrays inside arrays which are inside arrays themselves are compared by reference in assertEquals"); } } testng-6.9.12/src/test/java/test/multiple/0000755000175000017500000000000012732165123017722 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/multiple/Test1.java0000644000175000017500000000073412732165123021571 0ustar eugeneeugenepackage test.multiple; import static org.testng.Assert.assertTrue; import org.testng.annotations.AfterTest; import org.testng.annotations.Test; public class Test1 { private static int m_count = 0; @Test public void f1() { // ppp("INVOKING f1 " + m_count); assertTrue(m_count < 1, "FAILING"); m_count++; } @AfterTest public void cleanUp() { m_count = 0; } private static void ppp(String s) { System.out.println("[Test1] " + s); } } testng-6.9.12/src/test/java/test/multiple/TestMultiple.java0000644000175000017500000000103312732165123023215 0ustar eugeneeugenepackage test.multiple; import org.testng.annotations.Test; import test.BaseTest; public class TestMultiple extends BaseTest { private static final String CLASS_NAME = "test.multiple.ThisFactory"; @Test(groups = { "current" }) public void multiple() { addClass(CLASS_NAME); run(); String[] passed = { "f1", }; String[] failed = { "f1","f1","f1","f1","f1", "f1","f1","f1","f1", }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/multiple/ThisFactory.java0000644000175000017500000000056312732165123023030 0ustar eugeneeugenepackage test.multiple; import org.testng.annotations.Factory; import java.util.ArrayList; import java.util.List; /** * This class * * @author cbeust */ public class ThisFactory { @Factory public Object[] create() { List result = new ArrayList(); for (int i = 0; i < 10; i++) { result.add(new Test1()); } return result.toArray(); } } testng-6.9.12/src/test/java/test/serviceloader/0000755000175000017500000000000012732165123020716 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/serviceloader/ServiceLoaderSampleTest.java0000644000175000017500000000034412732165123026313 0ustar eugeneeugenepackage test.serviceloader; import org.testng.annotations.Test; /** * Dummy class to test ServiceLoader * * @author Cedric Beust */ public class ServiceLoaderSampleTest { @Test public void f() {} } testng-6.9.12/src/test/java/test/serviceloader/MyConfigurationListener.java0000644000175000017500000000063712732165123026412 0ustar eugeneeugenepackage test.serviceloader; import org.testng.IConfigurationListener; import org.testng.ITestResult; public class MyConfigurationListener implements IConfigurationListener { @Override public void onConfigurationSuccess(ITestResult itr) { } @Override public void onConfigurationFailure(ITestResult itr) { } @Override public void onConfigurationSkip(ITestResult itr) { } } testng-6.9.12/src/test/java/test/serviceloader/TmpSuiteListener.java0000644000175000017500000000037612732165123025047 0ustar eugeneeugenepackage test.serviceloader; import org.testng.ISuite; import org.testng.ISuiteListener; public class TmpSuiteListener implements ISuiteListener { @Override public void onFinish(ISuite suite) {} @Override public void onStart(ISuite suite) {} } testng-6.9.12/src/test/java/test/serviceloader/ServiceLoaderTest.java0000644000175000017500000000352412732165123025154 0ustar eugeneeugenepackage test.serviceloader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import test.listeners.ListenerAssert; public class ServiceLoaderTest extends SimpleBaseTest { @Test public void serviceLoaderShouldWork() throws MalformedURLException { TestNG tng = create(ServiceLoaderSampleTest.class); URL url = getClass().getClassLoader().getResource("serviceloader.jar"); URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { url }); tng.setServiceLoaderClassLoader(ucl); tng.run(); ListenerAssert.assertListenerType(tng.getServiceLoaderListeners(), TmpSuiteListener.class); } @Test public void serviceLoaderWithNoClassLoader() { //Here ServiceLoader is expected to rely on the current context class loader to load the service loader file //Since serviceloader.jar doesn't seem to be visible to the current thread's contextual class loader //resorting to pushing in a class loader into the current thread that can load the resource URL url = getClass().getClassLoader().getResource("serviceloader.jar"); URLClassLoader ucl = URLClassLoader.newInstance(new URL[] { url }); Thread.currentThread().setContextClassLoader(ucl); TestNG tng = create(ServiceLoaderSampleTest.class); tng.run(); ListenerAssert.assertListenerType(tng.getServiceLoaderListeners(), TmpSuiteListener.class); } @Test(description = "GITHUB-491") public void serviceLoaderShouldWorkWithConfigurationListener() { TestNG tng = create(ServiceLoaderSampleTest.class); tng.run(); Assert.assertEquals(1, tng.getServiceLoaderListeners().size()); ListenerAssert.assertListenerType(tng.getServiceLoaderListeners(), MyConfigurationListener.class); } } testng-6.9.12/src/test/java/test/reflect/0000755000175000017500000000000012732165123017513 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/reflect/TestResultJustForTesting.java0000644000175000017500000000356312732165123025356 0ustar eugeneeugenepackage test.reflect; import org.testng.IClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import java.util.Set; /** * Created on 12/30/15. * * @author Nitin Verma */ public class TestResultJustForTesting implements ITestResult { @Override public int getStatus() { return 0; } @Override public void setStatus(int status) { } @Override public ITestNGMethod getMethod() { return null; } @Override public Object[] getParameters() { return new Object[0]; } @Override public void setParameters(Object[] parameters) { } @Override public IClass getTestClass() { return null; } @Override public Throwable getThrowable() { return null; } @Override public void setThrowable(Throwable throwable) { } @Override public long getStartMillis() { return 0; } @Override public long getEndMillis() { return 0; } @Override public void setEndMillis(long millis) { } @Override public String getName() { return null; } @Override public boolean isSuccess() { return false; } @Override public String getHost() { return null; } @Override public Object getInstance() { return null; } @Override public String getTestName() { return null; } @Override public String getInstanceName() { return null; } @Override public ITestContext getTestContext() { return null; } @Override public int compareTo(ITestResult o) { return 0; } @Override public Object getAttribute(String name) { return null; } @Override public void setAttribute(String name, Object value) { } @Override public Set getAttributeNames() { return null; } @Override public Object removeAttribute(String name) { return null; } } testng-6.9.12/src/test/java/test/reflect/TestContextJustForTesting.java0000644000175000017500000000505412732165123025521 0ustar eugeneeugenepackage test.reflect; import com.google.inject.Injector; import com.google.inject.Module; import org.testng.IClass; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.xml.XmlTest; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Set; /** * Created on 12/30/15. * * @author Nitin Verma */ public class TestContextJustForTesting implements ITestContext { @Override public String getName() { return null; } @Override public Date getStartDate() { return null; } @Override public Date getEndDate() { return null; } @Override public IResultMap getPassedTests() { return null; } @Override public IResultMap getSkippedTests() { return null; } @Override public IResultMap getFailedButWithinSuccessPercentageTests() { return null; } @Override public IResultMap getFailedTests() { return null; } @Override public String[] getIncludedGroups() { return new String[0]; } @Override public String[] getExcludedGroups() { return new String[0]; } @Override public String getOutputDirectory() { return null; } @Override public ISuite getSuite() { return null; } @Override public ITestNGMethod[] getAllTestMethods() { return new ITestNGMethod[0]; } @Override public String getHost() { return null; } @Override public Collection getExcludedMethods() { return null; } @Override public IResultMap getPassedConfigurations() { return null; } @Override public IResultMap getSkippedConfigurations() { return null; } @Override public IResultMap getFailedConfigurations() { return null; } @Override public XmlTest getCurrentXmlTest() { return null; } @Override public List getGuiceModules(Class cls) { return null; } @Override public Injector getInjector(List moduleInstances) { return null; } @Override public Injector getInjector(IClass iClass) { return null; } @Override public void addInjector(List moduleInstances, Injector injector) { } @Override public Object getAttribute(String name) { return null; } @Override public void setAttribute(String name, Object value) { } @Override public Set getAttributeNames() { return null; } @Override public Object removeAttribute(String name) { return null; } } testng-6.9.12/src/test/java/test/reflect/ReflectionRecipesTest.java0000644000175000017500000003260212732165123024626 0ustar eugeneeugenepackage test.reflect; import org.testng.Assert; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.TestRunner; import org.testng.annotations.DataProvider; import org.testng.annotations.NoInjection; import org.testng.annotations.Test; import org.testng.internal.reflect.InjectableParameter; import org.testng.internal.reflect.Parameter; import org.testng.internal.reflect.ReflectionRecipes; import org.testng.xml.XmlTest; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Connection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * @author Nitin Verma */ public class ReflectionRecipesTest { private static final Object[] A0 = new Object[]{343, true}; private static final Parameter[] S0 = getMethodParameters(T.class, "s0"); private static final Parameter[] S1 = getMethodParameters(T.class, "s1"); private static final Parameter[] S2 = getMethodParameters(T.class, "s2"); private static final Parameter[] S3 = getMethodParameters(T.class, "s3"); private static Parameter[] getMethodParameters(final Class clazz, final String methodName) { Method method = null; Parameter[] parameters = null; for (final Method m : clazz.getMethods()) { if (m.getName().equals(methodName)) { method = m; } } if (method != null) { parameters = ReflectionRecipes.getMethodParameters(method); } return parameters; } @DataProvider public Object[][] methodInputParameters() { return new Object[][]{S0, S1, S2, S3}; } @DataProvider public Object[][] methodInputParamArgsPair() { return new Object[][]{ new Object[]{S0, A0}, new Object[]{S1, A0}, new Object[]{S2, A0}, new Object[]{S3, A0}, }; } @DataProvider public Object[][] exactMatchDP() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { final Method[] methods = ExactMatchTest.class.getDeclaredMethods(); final List objects = new ArrayList<>(); System.out.println("exactMatchDP:"); for (int i = 0; i < methods.length; i++) { final Method method = methods[i]; final ExactMatchTest.Expectation annotation = method.getAnnotation(ExactMatchTest.Expectation.class); if (annotation != null) { final String provider = annotation.expectationProvider(); final int flag = annotation.flag(); Assert.assertNotNull(provider); final Method providerMethod = ExactMatchTest.class.getMethod(provider, int.class); final Object out = providerMethod.invoke(ExactMatchTest.class, flag); Assert.assertTrue(out instanceof Object[][]); System.out.println(method.getName() + ", " + out); objects.add(new Object[]{out, method}); } } return objects.toArray(new Object[objects.size()][]); } @DataProvider public Object[][] matchArrayEndingDP() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { final Method[] methods = MatchArrayEndingTest.class.getDeclaredMethods(); final List objects = new ArrayList<>(); System.out.println("matchArrayEndingDP:"); for (int i = 0; i < methods.length; i++) { final Method method = methods[i]; final MatchArrayEndingTest.Expectation annotation = method.getAnnotation(MatchArrayEndingTest.Expectation.class); if (annotation != null) { final String provider = annotation.expectationProvider(); final int flag = annotation.flag(); Assert.assertNotNull(provider); final Method providerMethod = MatchArrayEndingTest.class.getMethod(provider, int.class); final Object out = providerMethod.invoke(MatchArrayEndingTest.class, flag); Assert.assertTrue(out instanceof Object[][]); System.out.println(method.getName() + ", " + out); objects.add(new Object[]{out, method}); } } return objects.toArray(new Object[objects.size()][]); } @DataProvider public Object[][] testContexts() { return new Object[][]{ {TestRunner.class}, {ITestContext.class}, {TestContextJustForTesting.class} }; } @DataProvider public Object[][] notTestContexts() { return new Object[][]{ {Object.class}, {Class.class}, {Connection.class} }; } @Test(dataProvider = "matchArrayEndingDP") public void matchArrayEndingTest(final Object[][] expected, @NoInjection final Method method) { if (expected != null) { final Parameter[] methodParameters = ReflectionRecipes.getMethodParameters(method); Assert.assertNotNull(methodParameters); final Parameter[] filteredParameters = ReflectionRecipes.filter(methodParameters, InjectableParameter.Assistant.ALL_INJECTS); Assert.assertNotNull(filteredParameters); for (final Object[] expect : expected) { Assert.assertNotNull(expect); Assert.assertEquals(expect.length, 2); Assert.assertNotNull(expect[0]); Assert.assertTrue(expect[0] instanceof Object[]); Assert.assertNotNull(expect[1]); Assert.assertTrue(expect[1] instanceof Boolean); Assert.assertEquals( ReflectionRecipes.matchArrayEnding(filteredParameters, (Object[]) expect[0]), expect[1] ); } } } @Test(dataProvider = "exactMatchDP") public void exactMatchTest(final Object[][] expected, @NoInjection final Method method) { if (expected != null) { final Parameter[] methodParameters = ReflectionRecipes.getMethodParameters(method); Assert.assertNotNull(methodParameters); final Parameter[] filteredParameters = ReflectionRecipes.filter(methodParameters, InjectableParameter.Assistant.ALL_INJECTS); Assert.assertNotNull(filteredParameters); for (final Object[] expect : expected) { Assert.assertNotNull(expect); Assert.assertEquals(expect.length, 2); Assert.assertNotNull(expect[0]); Assert.assertTrue(expect[0] instanceof Object[]); Assert.assertNotNull(expect[1]); Assert.assertTrue(expect[1] instanceof Boolean); Assert.assertEquals( ReflectionRecipes.exactMatch(filteredParameters, (Object[]) expect[0]), expect[1] ); } } } @Test(dataProvider = "methodInputParameters") public void testFilters(final Parameter[] parameters) { System.out.println("In: " + Arrays.asList(parameters)); final Parameter[] parameters1 = ReflectionRecipes.filter(parameters, InjectableParameter.Assistant.ALL_INJECTS); System.out.println("Out: " + Arrays.asList(parameters1)); Assert.assertEquals(parameters1.length, 2); Assert.assertEquals(parameters1[0].getType(), int.class); Assert.assertEquals(parameters1[1].getType(), Boolean.class); } @Test(dataProvider = "methodInputParamArgsPair") public void testInject(final Parameter[] parameters, final Object[] args) { System.out.println("In: " + Arrays.asList(parameters)); System.out.println("args: " + Arrays.asList(args)); final Object[] injectedArgs = ReflectionRecipes.inject( parameters, InjectableParameter.Assistant.ALL_INJECTS, args, null, null, null ); System.out.println("injectedArgs: " + Arrays.asList(injectedArgs)); Assert.assertEquals(injectedArgs.length, parameters.length); } @Test(dataProvider = "testContexts") public void testIsOrImplementsInterface(final Class clazz) { Assert.assertTrue(ReflectionRecipes.isOrImplementsInterface(ITestContext.class, clazz)); } @Test(dataProvider = "notTestContexts") public void testNegativeCaseIsOrImplementsInterface(final Class clazz) { Assert.assertFalse(ReflectionRecipes.isOrImplementsInterface(ITestContext.class, clazz)); } private static interface T { public void s0(TestContextJustForTesting testContext, int i, Boolean b); public void s1(int i, ITestContext iTestContext, Boolean b); public void s2(int i, Boolean b, ITestContext iTestContext); public void s3(ITestContext iTestContext1, int i, Boolean b, ITestContext iTestContext2); } public static abstract class ExactMatchTest { public static Object[][] exactMatchData(final int flag) { switch (flag) { case 0: return new Object[][]{ new Object[]{new Object[]{}, true}, new Object[]{new Object[]{1}, false}, new Object[]{new Object[]{""}, false}, new Object[]{new Object[]{1, ""}, false}, }; case 1: return new Object[][]{ new Object[]{new Object[]{1}, true}, new Object[]{new Object[]{}, false}, new Object[]{new Object[]{""}, false}, new Object[]{new Object[]{1, ""}, false}, new Object[]{new Object[]{"", 1}, false}, }; default: return null; } } @Expectation(expectationProvider = "exactMatchData", flag = 0) public abstract void s0(); @Expectation(expectationProvider = "exactMatchData", flag = 0) public abstract void s0(final ITestContext a0); @Expectation(expectationProvider = "exactMatchData", flag = 0) public abstract void s0(final ITestContext a0, final ITestResult a1); @Expectation(expectationProvider = "exactMatchData", flag = 0) public abstract void s0(final ITestContext a0, final ITestResult a1, final XmlTest a2); @Expectation(expectationProvider = "exactMatchData", flag = 0) public abstract void s0(final ITestContext a0, final ITestResult a1, final XmlTest a2, final Method a3); @Expectation(expectationProvider = "exactMatchData", flag = 1) public abstract void s1(final int a0); @Expectation(expectationProvider = "exactMatchData", flag = 1) public abstract void s1(final ITestContext a0, final int a1); @Expectation(expectationProvider = "exactMatchData", flag = 1) public abstract void s1(final ITestContext a0, final Integer a1, final ITestResult a2); @Expectation(expectationProvider = "exactMatchData", flag = 1) public abstract void s1(final int a0, final ITestContext a1, final ITestResult a2, final XmlTest a3); @Expectation(expectationProvider = "exactMatchData", flag = 1) public abstract void s1(final ITestContext a0, final ITestResult a1, final int a2, final XmlTest a3, final Method a4); @Retention(RUNTIME) @Target({METHOD}) public static @interface Expectation { public String expectationProvider(); public int flag(); } } public static abstract class MatchArrayEndingTest { public static Object[][] matchArrayEndingData(final int flag) { switch (flag) { case 0: return new Object[][]{ new Object[]{new Object[]{10f, 2.1f}, true}, new Object[]{new Object[]{10}, false}, new Object[]{new Object[]{10d, ""}, false}, new Object[]{new Object[]{1, ""}, false}, }; case 1: return new Object[][]{ new Object[]{new Object[]{1, 10f, 2.1f}, true}, new Object[]{new Object[]{}, false}, new Object[]{new Object[]{""}, false}, new Object[]{new Object[]{10f, "", 2.1f}, false}, new Object[]{new Object[]{"", 10f, 2.1f}, false}, }; default: return null; } } @Expectation(expectationProvider = "matchArrayEndingData", flag = 0) public abstract void s0(final float... f); @Expectation(expectationProvider = "matchArrayEndingData", flag = 0) public abstract void s0(final float[] f, final ITestContext a0); @Expectation(expectationProvider = "matchArrayEndingData", flag = 0) public abstract void s0(final ITestContext a0, final float[] f, final ITestResult a1); @Expectation(expectationProvider = "matchArrayEndingData", flag = 0) public abstract void s0(final ITestContext a0, final ITestResult a1, final XmlTest a2, final float... f); @Expectation(expectationProvider = "matchArrayEndingData", flag = 0) public abstract void s0(final ITestContext a0, final ITestResult a1, final XmlTest a2, final float[] f, final Method a3); @Expectation(expectationProvider = "matchArrayEndingData", flag = 1) public abstract void s1(final int a0, final float... f); @Expectation(expectationProvider = "matchArrayEndingData", flag = 1) public abstract void s1(final ITestContext a0, final int a1, final float... f); @Expectation(expectationProvider = "matchArrayEndingData", flag = 1) public abstract void s1(final ITestContext a0, final Integer a1, final ITestResult a2, final float... f); @Expectation(expectationProvider = "matchArrayEndingData", flag = 1) public abstract void s1(final int a0, final ITestContext a1, final ITestResult a2, final float[] f, final XmlTest a3); @Expectation(expectationProvider = "matchArrayEndingData", flag = 1) public abstract void s1(final ITestContext a0, final ITestResult a1, final int a2, final XmlTest a3, final float[] f, final Method a4); @Retention(RUNTIME) @Target({METHOD}) public static @interface Expectation { public String expectationProvider(); public int flag(); } } } testng-6.9.12/src/test/java/test/reflect/XmlTestJustForTesting.java0000644000175000017500000000032412732165123024630 0ustar eugeneeugenepackage test.reflect; import org.testng.xml.XmlTest; /** * Created on 12/30/15. * * @author Nitin Verma */ public class XmlTestJustForTesting extends XmlTest { } testng-6.9.12/src/test/java/test/reflect/TestMethodMatcher.java0000644000175000017500000002154012732165123023744 0ustar eugeneeugenepackage test.reflect; import org.testng.Assert; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.annotations.DataProvider; import org.testng.annotations.NoInjection; import org.testng.annotations.Test; import org.testng.internal.reflect.DataProviderMethodMatcher; import org.testng.internal.reflect.MethodMatcher; import org.testng.internal.reflect.MethodMatcherContext; import org.testng.xml.XmlTest; import java.lang.reflect.Method; /** * Created on 12/24/15 * * @author Nitin Verma */ public class TestMethodMatcher { private static Method getMethod(final String methodName) { Method method = null; for (final Method m : TestMethodMatcher.class.getMethods()) { if (m.getName().equals(methodName)) { method = m; } } return method; } @DataProvider public Object[][] methodParamPairs() { return new Object[][]{ new Object[]{"goodTestIssue122", new Object[]{"3", new String[]{"three", "four"}}}, new Object[]{"badTestIssue122", new Object[]{"3", new String[]{"three", "four"}}}, new Object[]{"goodTestIssue122", new Object[]{"3", "three", "four"}}, new Object[]{"badTestIssue122", new Object[]{"3", "three", "four"}}, new Object[]{"mixedArgs", new Object[]{3, true, new String[]{"three"}, "four"}}, new Object[]{"mixedArgs", new Object[]{3, true, new String[]{"three"}, new String[]{"four"}}}, new Object[]{"potpourri0", new Object[]{ getMethod("mixedArgs"), new XmlTestJustForTesting(), 3, getMethod("badTestIssue122"), new TestContextJustForTesting(), true, new TestResultJustForTesting(), new String[]{"three"}, new String[]{"four"}} }, new Object[]{"potpourri1", new Object[]{ getMethod("mixedArgs"), new XmlTestJustForTesting(), 3, getMethod("badTestIssue122"), new TestContextJustForTesting(), true, new TestResultJustForTesting(), new String[]{"three"}, new String[]{"four"}} }, }; } @DataProvider public Object[][] methodParamFailingPairs() { return new Object[][]{ new Object[]{"goodTestIssue122", new Object[]{3, "three", "four"}}, new Object[]{"badTestIssue122", new Object[]{3, "three", "four"}}, new Object[]{"mixedArgs", new Object[]{3, true, "three", "four"}}, }; } @Test(dataProvider = "methodParamPairs") public void testMatcher(final String methodName, final Object[] params, final ITestContext iTestContext, final ITestResult iTestResult) { final Method method = getMethod(methodName); final MethodMatcher matcher = new DataProviderMethodMatcher( new MethodMatcherContext(method, params, iTestContext, iTestResult)); try { method.invoke(new TestMethodMatcher(), matcher.getConformingArguments()); } catch (final Throwable throwable) { System.out.println("methodParamPairs failure"); throwable.printStackTrace(); Assert.fail("methodParamPairs failure"); } } @Test(dataProvider = "methodParamFailingPairs") public void testNegativeCaseMatcher(final String methodName, final Object[] params, final ITestContext iTestContext, final ITestResult iTestResult) { final Method method = getMethod(methodName); final MethodMatcher matcher = new DataProviderMethodMatcher( new MethodMatcherContext(method, params, iTestContext, iTestResult)); Assert.assertFalse(matcher.conforms()); try { method.invoke(new TestMethodMatcher(), matcher.getConformingArguments()); Assert.fail(); } catch (final Throwable throwable) { throwable.printStackTrace(); //noop } } public void goodTestIssue122(String s, String[] strings) { for (String item : strings) { System.out.println("An item is \"" + item + "\""); } Assert.assertEquals(s, "3"); } public void badTestIssue122(String s, String... strings) { for (String item : strings) { System.out.println("An item is \"" + item + "\""); } Assert.assertEquals(s, "3"); } public void mixedArgs( final int i, final Boolean b, final String[] s1, final String... strings ) { for (String item : strings) { System.out.println("An item is \"" + item + "\""); } Assert.assertEquals(i, 3); Assert.assertNotNull(b); Assert.assertTrue(b); Assert.assertNotNull(s1); Assert.assertEquals(s1.length, 1); Assert.assertEquals(s1[0], "three"); Assert.assertNotNull(strings); Assert.assertEquals(strings.length, 1); Assert.assertEquals(strings[0], "four"); } public void potpourri0( @NoInjection final Method myMethod1, @NoInjection final XmlTest myXmlTest, final Method currentTestMethod, final int i, final Method myMethod2, final ITestContext iTestContext, @NoInjection final ITestContext myTestContext, final Boolean b, @NoInjection final ITestResult myTestResult, final ITestResult iTestResult, final String[] s1, final XmlTest xmlTest, final String... strings ) { System.out.println("MyMethod1 is \"" + myMethod1 + "\""); System.out.println("MyMethod2 is \"" + myMethod2 + "\""); System.out.println("CurrentTestMethod is \"" + currentTestMethod + "\""); System.out.println("MyITestContext is \"" + myTestContext + "\""); System.out.println("ITestContext is \"" + iTestContext + "\""); System.out.println("ITestResult is \"" + iTestResult + "\""); System.out.println("MyTestResult is \"" + myTestResult + "\""); System.out.println("XmlTest is \"" + xmlTest + "\""); System.out.println("MyXmlTest is \"" + myXmlTest + "\""); for (String item : strings) { System.out.println("An item is \"" + item + "\""); } Assert.assertNotNull(myTestContext); Assert.assertTrue(myTestContext instanceof TestContextJustForTesting); Assert.assertNotNull(myTestResult); Assert.assertTrue(myTestResult instanceof TestResultJustForTesting); Assert.assertNotNull(myXmlTest); Assert.assertTrue(myXmlTest instanceof XmlTestJustForTesting); Assert.assertNotNull(currentTestMethod); Assert.assertEquals("potpourri0", currentTestMethod.getName()); Assert.assertNotNull(myMethod1); Assert.assertEquals("mixedArgs", myMethod1.getName()); Assert.assertNotNull(myMethod2); Assert.assertEquals("badTestIssue122", myMethod2.getName()); Assert.assertEquals(i, 3); Assert.assertNotNull(b); Assert.assertTrue(b); Assert.assertNotNull(s1); Assert.assertEquals(s1.length, 1); Assert.assertEquals(s1[0], "three"); Assert.assertNotNull(strings); Assert.assertEquals(strings.length, 1); Assert.assertEquals(strings[0], "four"); } public void potpourri1( @NoInjection final Method myMethod1, @NoInjection final XmlTest myXmlTest, final Method currentTestMethod, final int i, final Method myMethod2, final ITestContext iTestContext, @NoInjection final ITestContext myTestContext, final Boolean b, @NoInjection final ITestResult myTestResult, final ITestResult iTestResult, final String[] s1, final XmlTest xmlTest, final String[] strings ) { System.out.println("MyMethod1 is \"" + myMethod1 + "\""); System.out.println("MyMethod2 is \"" + myMethod2 + "\""); System.out.println("CurrentTestMethod is \"" + currentTestMethod + "\""); System.out.println("MyITestContext is \"" + myTestContext + "\""); System.out.println("ITestContext is \"" + iTestContext + "\""); System.out.println("ITestResult is \"" + iTestResult + "\""); System.out.println("MyTestResult is \"" + myTestResult + "\""); System.out.println("XmlTest is \"" + xmlTest + "\""); System.out.println("MyXmlTest is \"" + myXmlTest + "\""); for (String item : strings) { System.out.println("An item is \"" + item + "\""); } Assert.assertNotNull(myTestContext); Assert.assertTrue(myTestContext instanceof TestContextJustForTesting); Assert.assertNotNull(myTestResult); Assert.assertTrue(myTestResult instanceof TestResultJustForTesting); Assert.assertNotNull(myXmlTest); Assert.assertTrue(myXmlTest instanceof XmlTestJustForTesting); Assert.assertNotNull(currentTestMethod); Assert.assertEquals("potpourri1", currentTestMethod.getName()); Assert.assertNotNull(myMethod1); Assert.assertEquals("mixedArgs", myMethod1.getName()); Assert.assertNotNull(myMethod2); Assert.assertEquals("badTestIssue122", myMethod2.getName()); Assert.assertEquals(i, 3); Assert.assertNotNull(b); Assert.assertTrue(b); Assert.assertNotNull(s1); Assert.assertEquals(s1.length, 1); Assert.assertEquals(s1[0], "three"); Assert.assertNotNull(strings); Assert.assertEquals(strings.length, 1); Assert.assertEquals(strings[0], "four"); } } testng-6.9.12/src/test/java/test/Test2.java0000644000175000017500000000424712732165123017742 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.annotations.Configuration; import org.testng.annotations.Test; /** * * @author Cedric Beust, May 5, 2004 * */ public class Test2 extends BaseTest { private boolean m_initializedCorrectly = false; @Configuration(beforeTestMethod = true) // @BeforeMethod public void correctSetup() { m_initializedCorrectly = true; } // Shouldn't be called @Configuration(beforeTestMethod = true, groups = "excludeThisGroup") // @BeforeMethod(groups = { "excludeThisGroup"} ) public void incorrectSetup() { throw new RuntimeException("Should never be run"); } @Test public void noGroups() { addClass("test.sample.Sample1"); run(); String[] passed = { "method1", "method2", "method3", "broken", "throwExpectedException1ShouldPass", "throwExpectedException2ShouldPass" }; String[] failed = { "throwExceptionShouldFail", "verifyLastNameShouldFail" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void setUpWithGroups() { run(); Assert.assertTrue(m_initializedCorrectly, "Should have run the correctSetup method"); } @Test public void partialGroupsClass() { addClass("test.sample.PartialGroupTest"); addIncludedGroup("classGroup"); run(); String[] passed = { "testMethodGroup", "testClassGroup" }; String[] failed = { "testMethodGroupShouldFail", "testClassGroupShouldFail" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); // ppp("@@@@@@@@@@@@@@@@@@ PASSED TESTS"); // for (Object o : getPassedTests().values()) { // ppp("@@@@@@@@@@ PASSED:" + o); // } } @Test public void partialGroupsMethod() { addClass("test.sample.PartialGroupTest"); addIncludedGroup("methodGroup"); run(); String[] passed = { "testMethodGroup", }; String[] failed = { "testMethodGroupShouldFail" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/sample/0000755000175000017500000000000012732165123017350 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/sample/InvocationCountTest.java0000644000175000017500000000357012732165123024202 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterSuite; import org.testng.annotations.Test; /** * This class is used to test invocationCountTest * * @author cbeust */ public class InvocationCountTest { // // Invocation test // private static int m_count = 0; @AfterSuite(groups = {"invocationOnly"}) public void afterSuite() { m_count = 0; m_count2 = 0; m_count3 = 0; } @Test(groups = { "invocationOnly"}, invocationCount = 10 ) public void tenTimesShouldSucceed() { m_count++; } // // Invocation + Success percentage test // This method will work the first 8 times and fail after that, but overall // the test should still pass because successPercentage = 80 // private static int m_count2 = 0; @Test(groups = { "successPercentageThatSucceedsOnly" }, invocationCount = 10, successPercentage = 80) public void successPercentageShouldSucceed() { if (m_count2 >= 8) { throw new RuntimeException("Called more than eight times : " + m_count2); } m_count2++; } // // Invocation + Success percentage test // This method will work the first 8 times and fail after that. One of // the failures will fall under the percentage tolerance but the next one // will not. // private static int m_count3 = 0; @Test(groups = { "successPercentageThatFailsOnly" }, invocationCount = 10, successPercentage = 90) public void successPercentageShouldFail() { if (m_count3>= 8) { throw new RuntimeException("Called more than eight times : " + m_count3); } m_count3++; } @AfterClass(groups = { "invocationOnly"}) public void verify() { assert 10 == m_count : "Method should have been invoked 10 times but was invoked " + m_count + " times"; } public static void ppp(String s) { System.out.println("[InvocationCount] " + s); } } testng-6.9.12/src/test/java/test/sample/README.txt0000644000175000017500000000023312732165123021044 0ustar eugeneeugeneThis directory contains "samples": TestNG tests that are not invoked directly but invoked programmatically by the real test classes in the main directory. testng-6.9.12/src/test/java/test/sample/JUnitSample1.java0000644000175000017500000000141012732165123022463 0ustar eugeneeugenepackage test.sample; import junit.framework.TestCase; /** * This class * * @author Cedric Beust, May 5, 2004 * */ public class JUnitSample1 extends TestCase { private String m_field = null; public static final String EXPECTED2 = "testSample1_2"; public static final String EXPECTED1 = "testSample1_1"; public JUnitSample1() { super(); } public JUnitSample1(String n) { super(n); } @Override public void setUp() { m_field = "foo"; } @Override public void tearDown() { m_field = null; } /** * * */ public void testSample1_1() { // ppp("Sample 1_1"); } public void testSample1_2() { // ppp("Sample 1_2"); } private static void ppp(String s) { System.out.println("[JUnitSample1] " + s); } } testng-6.9.12/src/test/java/test/sample/SetUpWithParameterTest.java0000644000175000017500000000052512732165123024612 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * This class fails in setUp and should result in 1 failure, 1 skip * * @author cbeust */ public class SetUpWithParameterTest { @BeforeClass public void setUp(String bogusParameter) { } @Test public void test() { } } testng-6.9.12/src/test/java/test/sample/JUnitSample2.java0000644000175000017500000000102412732165123022465 0ustar eugeneeugenepackage test.sample; import junit.framework.TestCase; /** * This class * * @author Cedric Beust, May 5, 2004 * */ public class JUnitSample2 extends TestCase { public static final String EXPECTED = "testSample2ThatSetUpWasRun"; private String m_field = null; public JUnitSample2() { super(); } public JUnitSample2(String n) { super(n); } @Override public void setUp() { m_field = "foo"; } public void testSample2ThatSetUpWasRun() { assert null != m_field : "setUp() wasn't run"; } } testng-6.9.12/src/test/java/test/sample/BaseAfterClassCalledAtEnd.java0000644000175000017500000000046712732165123025065 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.AfterClass; public class BaseAfterClassCalledAtEnd { protected boolean m_afterClass = false; @AfterClass(dependsOnGroups = { ".*" }) public void baseAfterClass() { assert m_afterClass : "This afterClass method should have been called last"; } } testng-6.9.12/src/test/java/test/sample/PartialGroupTest.java0000644000175000017500000000162412732165123023467 0ustar eugeneeugenepackage test.sample; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * This class tests groups that are partially defined at the class level * and then augmented at the method level. * * @author cbeust */ @Test(groups = { "classGroup" }) public class PartialGroupTest { public static boolean m_successMethod = false; public static boolean m_successClass = false; @BeforeClass public void init() { m_successMethod = false; m_successClass = false; } @Test(groups = { "methodGroup" }) public void testMethodGroup() { m_successMethod = true; } @Test public void testClassGroupShouldFail() { Assert.assertTrue(false); } @Test(groups = { "methodGroup" }) public void testMethodGroupShouldFail() { Assert.assertTrue(false); } @Test public void testClassGroup() { m_successClass = true; } } testng-6.9.12/src/test/java/test/sample/Sample1.java0000644000175000017500000000302112732165123021511 0ustar eugeneeugenepackage test.sample; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Test; /** * This class * * @author Cedric Beust, Apr 26, 2004 * */ public class Sample1 extends BaseSample1 { @AfterClass public static void tearDownClass1() { } @AfterClass public void tearDownClass2() { } @BeforeMethod public void beforeTest() { } @AfterMethod public void afterTest() { } @Test(groups = {"even"}) public void method2() { } @Test(groups = {"odd"}) public void method3() { } @Test(groups = {"odd"}, enabled = false) public void oddDisableMethod() { } @Test(groups = {"broken"}) public void broken() { } @Test(groups = {"fail"}) @ExpectedExceptions( {NumberFormatException.class, ArithmeticException.class}) public void throwExpectedException1ShouldPass() { throw new NumberFormatException(); } @Test(groups = {"fail"}) @ExpectedExceptions( {NumberFormatException.class, ArithmeticException.class}) public void throwExpectedException2ShouldPass() { throw new ArithmeticException(); } @Test(groups = {"fail", "bug"}) public void throwExceptionShouldFail() { throw new NumberFormatException(); } @Test(groups = {"assert"}) public void verifyLastNameShouldFail() { Assert.assertEquals("Beust", "", "Expected name Beust, found blah"); } private static void ppp(String s) { System.out.println("[Test1] " + s); } } testng-6.9.12/src/test/java/test/sample/BaseSampleInheritance.java0000644000175000017500000000224212732165123024401 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; /** * @author Cedric Beust, Apr 30, 2004 * */ public class BaseSampleInheritance { protected List m_configurations = new ArrayList<>(); protected void addConfiguration(String c) { m_configurations.add(c); } protected boolean m_invokedBaseMethod = false; @Test(groups = { "inheritedTestMethod" }) public void baseMethod() { m_invokedBaseMethod = true; } protected boolean m_invokedBaseConfiguration = false; @BeforeClass public void baseConfiguration() { m_invokedBaseConfiguration = true; } @BeforeClass(groups = { "configuration1" }, dependsOnGroups = { "configuration0" }) public void configuration1() { // System.out.println("CONFIGURATION 1"); addConfiguration("configuration1"); } @Test(dependsOnGroups = { "inheritedTestMethod" }) public void testBooleans() { assert m_invokedBaseMethod : "Didn't invoke test method in base class"; assert m_invokedBaseConfiguration : "Didn't invoke configuration method in base class"; } } testng-6.9.12/src/test/java/test/sample/Scope.java0000644000175000017500000000075412732165123021272 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.Test; /** * This class tests paramete scopes. * * @author cbeust */ public class Scope { @Test(groups = { "outer-group" }, parameters = { "parameter" }) public void outerDeprecated(String s) { assert "out".equals(s) : "Expected out got " + s; } @Test(groups = { "inner-group" }, parameters = { "parameter" }) public void innerDeprecated(String s) { assert "in".equals(s) : "Expected in got " + s; } } testng-6.9.12/src/test/java/test/sample/Basic2.java0000644000175000017500000000163112732165123021317 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterTest; import org.testng.annotations.Test; public class Basic2 { private boolean m_basic2WasRun = false; private static int m_afterClass = 0; @Test(dependsOnGroups = { "basic1" }) public void basic2() { m_basic2WasRun = true; assert Basic1.getCount() > 0 : "COUNT WAS NOT INCREMENTED"; } @AfterTest public void cleanUp() { m_basic2WasRun = false; m_afterClass = 0; } private void ppp(String s) { System.out.println("[Basic2 " + Thread.currentThread().getId() + " ] " + hashCode() + " " + s); } @AfterClass public void checkTestAtClassLevelWasRun() { m_afterClass++; assert m_basic2WasRun : "Class annotated with @Test didn't have its methods run."; assert 1 == m_afterClass : "After class should have been called exactly once, not " + m_afterClass; } }testng-6.9.12/src/test/java/test/sample/JUnitSample4.java0000644000175000017500000000131612732165123022473 0ustar eugeneeugenepackage test.sample; import junit.framework.Assert; import junit.framework.TestCase; import junit.framework.TestSuite; /** * * @author lukas */ public abstract class JUnitSample4 extends TestCase { private int i = 0; public JUnitSample4(String name, int i) { super(name); this.i = i; } public void testXY() { Assert.assertEquals(1, 1); } public static TestSuite suite() { TestSuite ts = new TestSuite("Sample Suite"); for (int i = 0; i < 3; i++) { ts.addTest(new T(i)); } return ts; } private static class T extends JUnitSample4 { public T(int i) { super("testXY", i); } } } testng-6.9.12/src/test/java/test/sample/JUnitSample3.java0000644000175000017500000000076612732165123022502 0ustar eugeneeugenepackage test.sample; import org.testng.Assert; import junit.framework.TestCase; /** * This class verifies that a new instance is used every time * * @author cbeust */ public class JUnitSample3 extends TestCase { private int m_count = 0; public void test1() { Assert.assertEquals( m_count, 0); m_count++; } public void test2() { Assert.assertEquals( m_count, 0); m_count++; } private static void ppp(String s) { System.out.println("[JUnitSample3] " + s); } } testng-6.9.12/src/test/java/test/sample/ConverterSample3.java0000644000175000017500000000362412732165123023414 0ustar eugeneeugenepackage test.sample; /* * Created on 12-Sep-2006 by micheb10 */ /** * Sample file for the Javadoc annotations to Java 5 annotations converter for a non-default package * @author micheb10 12-Sep-2006 * @testng.test */ public class ConverterSample3 { /** * This comment line should be preserved * @testng.before-suite alwaysRun = "true" */ public void beforeSuiteAlwaysRun() { // We are just checking appropriate annotations are added so we don't care about body } /** * @testng.test */ public void plainTest() { // Empty body } /** * @testng.test * @testng.expected-exceptions * value = "java.lang.NullPointerException java.lang.NumberFormatException" */ public void expectedExceptions() { // Empty body } /** * @testng.test groups = "groupA groupB" */ public void testGroups() { // Empty body } /** * @testng.after-method */ public void afterMethod() { // Empty body } /** * This key should be preserved * @author The author is a standard tag and should not be touched * @testng.test groups = "groupA" alwaysRun=true * dependsOnMethods = "expectedExceptions" timeOut="3000" * @version another standard tag should not be changed * @testng.expected-exceptions * value = "java.lang.NullPointerException java.lang.NumberFormatException" * @testng.parameters value="firstParameter secondParameter thirdParameter" */ public void testEverything() { // Lots and lots of stuff } /** * @testng.data-provider name="test1" */ public Object[][] dataProvider() { return null; } /** * @testng.factory */ public Object[] factory() { return null; } /** * @testng.test */ public class TestInnerClass { public void bareInnerMethod() { // Empty body } /** * @testng.test */ public void testInnerMethod() { // empty body } } } testng-6.9.12/src/test/java/test/sample/Sample2.java0000644000175000017500000000071012732165123021514 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.Test; /** * This class * * @author Cedric Beust, Apr 26, 2004 * */ public class Sample2 { @Test(groups = "g1") public void method1() { // System.out.println("@@@@@@@@@@@@@@@@@@@ METHOD1"); } @Test public void method2() { // System.out.println("@@@@@@@@@@@@@@@@@@@ METHOD2"); } @Test public void method3() { // System.out.println("@@@@@@@@@@@@@@@@@@@ METHOD3"); } } testng-6.9.12/src/test/java/test/sample/Basic1.java0000644000175000017500000000105712732165123021320 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class Basic1 { static private int m_count = 0; public static void incrementCount() { m_count++; } public static int getCount() { return m_count; } @BeforeMethod public void beforeTestMethod() { incrementCount(); } @Test(groups = { "basic1" } ) public void basic1() { assert getCount() > 0 : "COUNT WAS NOT INCREMENTED"; } static private void ppp(String s) { System.out.println("[Basic1] " + s); } }testng-6.9.12/src/test/java/test/sample/AllJUnitTests.java0000644000175000017500000000065112732165123022722 0ustar eugeneeugenepackage test.sample; import junit.framework.Test; import junit.framework.TestSuite; /** * Tests the suite() functionality of TestNG * * @author Cedric Beust, May 5, 2004 * */ public class AllJUnitTests { public static Test suite() { TestSuite suite= new TestSuite(); suite.addTest(new JUnitSample1(JUnitSample1.EXPECTED1)); suite.addTest(new JUnitSample2(JUnitSample2.EXPECTED)); return suite; } } testng-6.9.12/src/test/java/test/sample/BaseSample1.java0000644000175000017500000000030612732165123022307 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.Test; /** * @author Cedric Beust, Apr 30, 2004 * */ public class BaseSample1 { @Test(groups = { "odd" }) public void method1() { } } testng-6.9.12/src/test/java/test/sample/AfterClassCalledAtEnd.java0000644000175000017500000000310612732165123024263 0ustar eugeneeugenepackage test.sample; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * Check to see that AfterClass is called only at the end and that after methods * are called in reverse order of the before methods. */ public class AfterClassCalledAtEnd extends BaseAfterClassCalledAtEnd { boolean m_before1Class = false; boolean m_test1 = false; boolean m_test2 = false; boolean m_test3 = false; @BeforeClass(groups = { "before1Class" } ) public void before1Class() { m_before1Class = true; } @AfterClass(groups = { "someGroup" }) public void afterClass() { m_afterClass = true; assert m_test1 && m_test2 && m_test3 : "One of the test methods was not invoked: " + m_test1 + " " + m_test2 + " " + m_test3; } @Test(description = "Verify that beforeClass and afterClass are called correctly") public void test1() { m_test1 = true; assert m_before1Class : "beforeClass configuration must be called before method"; assert ! m_afterClass : "afterClass configuration must not be called before test method"; } @Test public void test2() { m_test2 = true; assert m_before1Class : "beforeClass configuration must be called before method"; assert ! m_afterClass : "afterClass configuration must not be called before test method"; } @Test public void test3() { m_test3 = true; assert m_before1Class : "beforeClass configuration must be called before method"; assert ! m_afterClass : "afterClass configuration must not be called before test method"; } }testng-6.9.12/src/test/java/test/sample/PartialGroupVerification.java0000644000175000017500000000053412732165123025171 0ustar eugeneeugene package test.sample; import org.testng.annotations.Test; /** * This class verifies the PartialGroupTest * * @author cbeust */ public class PartialGroupVerification { @Test public void verify() { assert PartialGroupTest.m_successMethod && PartialGroupTest.m_successClass : "test1 and test2 should have been invoked both"; } }testng-6.9.12/src/test/java/test/hook/0000755000175000017500000000000012732165123017027 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/hook/ConfigurableSuccessTest.java0000644000175000017500000000137212732165123024466 0ustar eugeneeugenepackage test.hook; import org.testng.IConfigurable; import org.testng.IConfigureCallBack; import org.testng.ITestResult; import org.testng.annotations.Test; import java.lang.reflect.Method; /** * Test harness for {@link IConfigurable} */ public class ConfigurableSuccessTest extends BaseConfigurable { @Override public void run(IConfigureCallBack callBack, ITestResult testResult) { m_hookCount++; Object[] parameters = callBack.getParameters(); if (parameters.length > 0) { m_methodName = ((Method) parameters[0]).getName(); } callBack.runConfigurationMethod(testResult); } @Test public void hookWasRun() { // Assert.assertEquals(m_hookCount, 2); // Assert.assertTrue(m_bc); // Assert.assertTrue(m_bm); } } testng-6.9.12/src/test/java/test/hook/ConfigurableSuccessWithListenerTest.java0000644000175000017500000000157412732165123027034 0ustar eugeneeugenepackage test.hook; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import java.lang.reflect.Method; @Listeners(ConfigurableListener.class) public class ConfigurableSuccessWithListenerTest { static boolean m_bm = false; static boolean m_bc = false; static boolean m_bt; static boolean m_bs; @BeforeSuite public void bs() { m_bs = true; } @BeforeMethod public void bt() { m_bt = true; } @BeforeMethod public void bm(Method m) { m_bm = true; } @BeforeClass public void bc() { m_bc = true; } @Test public void hookWasRun() { Assert.assertEquals(ConfigurableListener.m_hookCount, 2); Assert.assertTrue(m_bc); Assert.assertTrue(m_bm); } } testng-6.9.12/src/test/java/test/hook/ConfigurableFailureTest.java0000644000175000017500000000104312732165123024440 0ustar eugeneeugenepackage test.hook; import org.testng.Assert; import org.testng.IConfigurable; import org.testng.IConfigureCallBack; import org.testng.ITestResult; import org.testng.annotations.Test; /** * Test harness for {@link IConfigurable} */ public class ConfigurableFailureTest extends BaseConfigurable { @Override public void run(IConfigureCallBack callBack, ITestResult testResult) { m_hookCount++; // Not calling the callback } @Test public void hookWasNotRun() { Assert.assertFalse(m_bc); Assert.assertFalse(m_bm); } } testng-6.9.12/src/test/java/test/hook/HookSuccessTest.java0000644000175000017500000000237112732165123022766 0ustar eugeneeugenepackage test.hook; import org.testng.IHookCallBack; import org.testng.IHookable; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test harness for {@link IHookable} * * @author Cedric Beust * @since Aug 01, 2006 */ public class HookSuccessTest implements IHookable { static boolean m_hook = false; static boolean m_testWasRun = false; static String m_parameter = null; @Override public void run(IHookCallBack callBack, ITestResult testResult) { m_hook = true; Object[] parameters = callBack.getParameters(); if (parameters.length > 0) { m_parameter = parameters[0].toString(); } callBack.runTestMethod(testResult); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { "foo" } }; } @Test(dataProvider = "dp") public void verify(String name) { m_testWasRun = true; Reporter.log("output from hook test.verify"); } // @AfterMethod // public void tearDown() { // Assert.assertTrue(m_hook); // Assert.assertTrue(m_testWasRun); // } private void ppp(String string) { System.out.println("[HookTest] " + string); } } testng-6.9.12/src/test/java/test/hook/HookListener.java0000644000175000017500000000053612732165123022304 0ustar eugeneeugenepackage test.hook; import org.testng.IHookCallBack; import org.testng.IHookable; import org.testng.ITestResult; public class HookListener implements IHookable { public static boolean m_hook = false; @Override public void run(IHookCallBack callBack, ITestResult testResult) { m_hook = true; callBack.runTestMethod(testResult); } } testng-6.9.12/src/test/java/test/hook/BaseConfigurable.java0000644000175000017500000000137012732165123023066 0ustar eugeneeugenepackage test.hook; import org.testng.IConfigurable; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import java.lang.reflect.Method; abstract public class BaseConfigurable implements IConfigurable { static int m_hookCount = 0; static boolean m_bs = false; static boolean m_bt = false; static boolean m_bm = false; static boolean m_bc = false; static String m_methodName = null; @BeforeSuite public void bs() { m_bs = true; } @BeforeTest public void bt() { m_bt = true; } @BeforeMethod public void bm(Method m) { m_bm = true; } @BeforeClass public void bc() { m_bc = true; } } testng-6.9.12/src/test/java/test/hook/HookSuccess862Test.java0000644000175000017500000000236712732165123023233 0ustar eugeneeugenepackage test.hook; import org.testng.*; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import javax.inject.Named; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class HookSuccess862Test implements IHookable { @Override public void run(IHookCallBack callBack, ITestResult testResult) { Method method = testResult.getMethod().getConstructorOrMethod().getMethod(); for (int i = 0; i < callBack.getParameters().length; i++) { Annotation[] annotations = method.getParameterAnnotations()[i]; for (Annotation annotation : annotations) { if (annotation instanceof Named) { Named named = (Named) annotation; callBack.getParameters()[0] = callBack.getParameters()[0] + named.value(); } } } callBack.runTestMethod(testResult); } @DataProvider public Object[][] dp() { return new Object[][]{ new Object[]{"foo", "test"} }; } @Test(dataProvider = "dp") public void verify(@Named("bar") String bar, String test) { Assert.assertEquals(bar, "foobar"); Assert.assertEquals(test, "test"); } } testng-6.9.12/src/test/java/test/hook/ConfigurableListener.java0000644000175000017500000000111312732165123023774 0ustar eugeneeugenepackage test.hook; import org.testng.IConfigurable; import org.testng.IConfigureCallBack; import org.testng.ITestResult; import java.lang.reflect.Method; public class ConfigurableListener implements IConfigurable { static int m_hookCount = 0; static String m_methodName; @Override public void run(IConfigureCallBack callBack, ITestResult testResult) { m_hookCount++; Object[] parameters = callBack.getParameters(); if (parameters.length > 0) { m_methodName = ((Method) parameters[0]).getName(); } callBack.runConfigurationMethod(testResult); } } testng-6.9.12/src/test/java/test/hook/HookSuccessWithListenerTest.java0000644000175000017500000000043212732165123025324 0ustar eugeneeugenepackage test.hook; import org.testng.Assert; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(HookListener.class) public class HookSuccessWithListenerTest { @Test public void verify() { Assert.assertTrue(HookListener.m_hook); } } testng-6.9.12/src/test/java/test/hook/HookSuccess599Test.java0000644000175000017500000000206412732165123023234 0ustar eugeneeugenepackage test.hook; import org.testng.IHookCallBack; import org.testng.IHookable; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test harness for {@link IHookable} * * @author Cedric Beust * @since Aug 01, 2006 */ public class HookSuccess599Test implements IHookable { static boolean m_hook = false; static boolean m_testWasRun = false; static String m_parameter = null; @Override public void run(IHookCallBack callBack, ITestResult testResult) { m_hook = true; Object[] parameters = callBack.getParameters(); if (parameters.length > 0) { m_parameter = parameters[0].toString(); } callBack.runTestMethod(testResult); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { "foo" } }; } @Test(dataProvider = "dp", timeOut = 100) public void verify(String name) { m_testWasRun = true; Reporter.log("output from hook test.verify"); } } testng-6.9.12/src/test/java/test/hook/HookFailureTest.java0000644000175000017500000000133312732165123022742 0ustar eugeneeugenepackage test.hook; import org.testng.IHookCallBack; import org.testng.IHookable; import org.testng.ITestResult; import org.testng.annotations.Test; public class HookFailureTest implements IHookable { static boolean m_hook = false; static boolean m_testWasRun = false; @Override public void run(IHookCallBack callBack, ITestResult testResult) { m_hook = true; // Not invoking the callback: the method should not be run } @Test public void verify() { m_testWasRun = true; } // @AfterMethod // public void tearDown() { // Assert.assertTrue(m_hook); // Assert.assertFalse(m_testWasRun); // } private void ppp(String string) { System.out.println("[HookFailureTest] " + string); } } testng-6.9.12/src/test/java/test/hook/HookableTest.java0000644000175000017500000000775012732165123022267 0ustar eugeneeugenepackage test.hook; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import test.BaseTest; /** * Because IHookable and IConfigurable are global, it's safer to run them in a * sub-TestNG object, otherwise they will be run for your entire test suite... * * @author cbeust */ public class HookableTest extends BaseTest { @BeforeMethod public void bm() { HookSuccessTest.m_hook = false; HookSuccessTest.m_testWasRun = false; HookSuccessTest.m_parameter = null; HookSuccess599Test.m_hook = false; HookSuccess599Test.m_testWasRun = false; HookSuccess599Test.m_parameter = null; HookFailureTest.m_hook = false; HookFailureTest.m_testWasRun = false; HookListener.m_hook = false; BaseConfigurable.m_hookCount = 0; BaseConfigurable.m_bc = false; BaseConfigurable.m_bm = false; BaseConfigurable.m_bs = false; BaseConfigurable.m_bt = false; BaseConfigurable.m_methodName = null; ConfigurableListener.m_hookCount = 0; ConfigurableListener.m_methodName = null; ConfigurableSuccessWithListenerTest.m_bc = false; ConfigurableSuccessWithListenerTest.m_bm = false; } @Test public void hookSuccess() { addClass(HookSuccessTest.class); run(); verifyTests("Passed", new String[] { "verify" }, getPassedTests()); Assert.assertTrue(HookSuccessTest.m_hook); Assert.assertTrue(HookSuccessTest.m_testWasRun); Assert.assertEquals(HookSuccessTest.m_parameter, "foo"); } @Test(description = "https://github.com/cbeust/testng/issues/599") public void issue599() { addClass(HookSuccess599Test.class); run(); verifyTests("Passed", new String[] { "verify" }, getPassedTests()); Assert.assertTrue(HookSuccess599Test.m_hook); Assert.assertTrue(HookSuccess599Test.m_testWasRun); Assert.assertEquals(HookSuccess599Test.m_parameter, "foo"); } @Test(description = "https://github.com/cbeust/testng/pull/862") public void issue862() { addClass(HookSuccess862Test.class); run(); verifyTests("Passed", new String[] { "verify" }, getPassedTests()); } @Test public void hookSuccessWithListener() { addClass(HookSuccessWithListenerTest.class); run(); verifyTests("Passed", new String[] { "verify" }, getPassedTests()); Assert.assertTrue(HookListener.m_hook); } @Test public void hookFailure() { addClass(HookFailureTest.class); run(); // To investigate: TestNG still thinks the test passed since it can't know whether // the hook ended up invoking the test or not. // verifyTests("Passed", new String[] { }, getPassedTests()); Assert.assertTrue(HookFailureTest.m_hook); Assert.assertFalse(HookFailureTest.m_testWasRun); } @Test public void configurableSuccess() { addClass(ConfigurableSuccessTest.class); run(); Assert.assertEquals(BaseConfigurable.m_hookCount, 4); Assert.assertTrue(BaseConfigurable.m_bc); Assert.assertTrue(BaseConfigurable.m_bm); Assert.assertTrue(BaseConfigurable.m_bs); Assert.assertTrue(BaseConfigurable.m_bt); Assert.assertEquals(BaseConfigurable.m_methodName, "hookWasRun"); } @Test public void configurableSuccessWithListener() { addClass(ConfigurableSuccessWithListenerTest.class); run(); Assert.assertEquals(ConfigurableListener.m_hookCount, 4); Assert.assertTrue(ConfigurableSuccessWithListenerTest.m_bs); Assert.assertTrue(ConfigurableSuccessWithListenerTest.m_bt); Assert.assertTrue(ConfigurableSuccessWithListenerTest.m_bc); Assert.assertTrue(ConfigurableSuccessWithListenerTest.m_bm); Assert.assertEquals(ConfigurableListener.m_methodName, "hookWasRun"); } @Test public void configurableFailure() { addClass(ConfigurableFailureTest.class); run(); Assert.assertEquals(BaseConfigurable.m_hookCount, 4); Assert.assertFalse(BaseConfigurable.m_bc); Assert.assertFalse(BaseConfigurable.m_bm); Assert.assertFalse(BaseConfigurable.m_bs); Assert.assertFalse(BaseConfigurable.m_bt); } } testng-6.9.12/src/test/java/test/groupbug/0000755000175000017500000000000012732165123017721 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/groupbug/GroupBugTest.java0000644000175000017500000000126512732165123023162 0ustar eugeneeugenepackage test.groupbug; import org.testng.Assert; import org.testng.annotations.Test; import org.testng.collections.Lists; import test.BaseTest; import java.util.Arrays; import java.util.List; public class GroupBugTest extends BaseTest { static List passed = Lists.newArrayList(); @Test(groups = "broken", description = "Comment out dependsOnGroups in ITCaseOne will fix the ordering, that's the bug") public void shouldOrderByClass() { passed.clear(); addClass(ITCaseOne.class); addClass(ITCaseTwo.class); run(); List expected = Arrays.asList( "one1", "one2", "two1", "two2" ); Assert.assertEquals(passed, expected); } } testng-6.9.12/src/test/java/test/groupbug/ITCaseTwo.java0000644000175000017500000000133712732165123022372 0ustar eugeneeugenepackage test.groupbug; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ITCaseTwo { @BeforeClass public void beforeClass() { System.out.printf("RUN %s.beforeClass()\n", getClass()); } @AfterClass(alwaysRun = true) public void afterClass() { System.out.printf("RUN %s.afterClass()\n", getClass()); } @Test(groups = "std-two") public void two1() { GroupBugTest.passed.add("two1"); System.out.printf("RUN %s.two1()\n", getClass()); } @Test(groups = "logic-two", dependsOnGroups = "std-two") public void two2() { GroupBugTest.passed.add("two2"); System.out.printf("RUN %s.two2()\n", getClass()); } }testng-6.9.12/src/test/java/test/groupbug/ITCaseOne.java0000644000175000017500000000146312732165123022342 0ustar eugeneeugenepackage test.groupbug; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ITCaseOne { @BeforeClass public void beforeClass() { System.out.printf("RUN %s.beforeClass()\n", getClass()); } @AfterClass(alwaysRun = true) public void afterClass() { System.out.printf("RUN %s.afterClass()\n", getClass()); } @Test(groups = "std-one") public void one1() { GroupBugTest.passed.add("one1"); System.out.printf("RUN %s.one1()\n", getClass()); } /** * Commenting out dependsOnGroups fixes the ordering, that's the bug. */ @Test(groups = "logic-one", dependsOnGroups = "std-one") public void one2() { GroupBugTest.passed.add("one2"); System.out.printf("RUN %s.one2()\n", getClass()); } }testng-6.9.12/src/test/java/test/uniquesuite/0000755000175000017500000000000012732165123020447 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/uniquesuite/TestBefore2.java0000644000175000017500000000033312732165123023435 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.Assert; import org.testng.annotations.Test; public class TestBefore2 extends BaseBefore { @Test public void verify() { Assert.assertEquals(m_beforeCount, 1); } } testng-6.9.12/src/test/java/test/uniquesuite/TestAfter.java0000644000175000017500000000125712732165123023220 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.AfterTest; import org.testng.annotations.Test; import testhelper.OutputDirectoryPatch; public class TestAfter { @Test public void testAfter() { TestNG tng = new TestNG(); tng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); tng.setTestClasses(new Class[] { TestAfter1.class, TestAfter2.class }); tng.setVerbose(0); tng.run(); Assert.assertEquals(BaseAfter.m_afterCount, 1); } @AfterTest public void afterTest() { BaseAfter.m_afterCount = 0; BaseBefore.m_beforeCount = 0; BaseBefore.m_afterCount = 0; } } ///// testng-6.9.12/src/test/java/test/uniquesuite/TestAfter2.java0000644000175000017500000000022412732165123023273 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.annotations.Test; public class TestAfter2 extends BaseAfter { @Test public void verify() { } } testng-6.9.12/src/test/java/test/uniquesuite/BaseBefore.java0000644000175000017500000000067712732165123023321 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public class BaseBefore { public static int m_beforeCount = 0; public static int m_afterCount = 0; @BeforeSuite public void incrementBefore() { m_beforeCount++; } @AfterSuite public void incrementAfter() { m_afterCount++; } private static void ppp(String s) { System.out.println("[Base] " + s); } } testng-6.9.12/src/test/java/test/uniquesuite/BaseAfter.java0000644000175000017500000000063112732165123023146 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public class BaseAfter { public static int m_afterCount = 0; @BeforeSuite public void beforeSuite() { m_afterCount = 0; } @AfterSuite public void incrementAfter() { m_afterCount++; } private static void ppp(String s) { System.out.println("[BaseAfter] " + s); } } testng-6.9.12/src/test/java/test/uniquesuite/TestBefore1.java0000644000175000017500000000033312732165123023434 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.Assert; import org.testng.annotations.Test; public class TestBefore1 extends BaseBefore { @Test public void verify() { Assert.assertEquals(m_beforeCount, 1); } } testng-6.9.12/src/test/java/test/uniquesuite/TestAfter1.java0000644000175000017500000000022412732165123023272 0ustar eugeneeugenepackage test.uniquesuite; import org.testng.annotations.Test; public class TestAfter1 extends BaseAfter { @Test public void verify() { } } testng-6.9.12/src/test/java/test/name/0000755000175000017500000000000012732165123017007 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/name/TestOnClassSample.java0000644000175000017500000000020712732165123023215 0ustar eugeneeugenepackage test.name; import org.testng.annotations.Test; @Test public class TestOnClassSample { @Test public void test() {} } testng-6.9.12/src/test/java/test/name/NameSample.java0000644000175000017500000000031112732165123021667 0ustar eugeneeugenepackage test.name; import org.testng.Assert; import org.testng.annotations.Test; @Test(testName = "NAME") public class NameSample { @Test public void test() { Assert.assertTrue(true); } } testng-6.9.12/src/test/java/test/name/BlankNameSample.java0000644000175000017500000000042712732165123022647 0ustar eugeneeugenepackage test.name; import org.testng.Assert; import org.testng.ITest; import org.testng.annotations.Test; public class BlankNameSample implements ITest { @Test public void test() { Assert.assertTrue(true); } @Override public String getTestName() { return ""; } } testng-6.9.12/src/test/java/test/name/TestOnClassListener.java0000644000175000017500000000161012732165123023560 0ustar eugeneeugenepackage test.name; import org.testng.IInvokedMethod; import org.testng.IReporter; import org.testng.ISuite; import org.testng.xml.XmlSuite; import java.util.ArrayList; import java.util.List; public class TestOnClassListener implements IReporter { private final List names = new ArrayList<>(); private final List testNames = new ArrayList<>(); @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { for (ISuite suite : suites) { for (IInvokedMethod method : suite.getAllInvokedMethods()) { names.add(method.getTestResult().getName()); testNames.add(method.getTestResult().getTestName()); } } } public List getNames() { return names; } public List getTestNames() { return testNames; } } testng-6.9.12/src/test/java/test/name/NoNameSample.java0000644000175000017500000000026212732165123022171 0ustar eugeneeugenepackage test.name; import org.testng.Assert; import org.testng.annotations.Test; public class NoNameSample { @Test public void test() { Assert.assertTrue(true); } } testng-6.9.12/src/test/java/test/name/SimpleITestSample.java0000644000175000017500000000044512732165123023221 0ustar eugeneeugenepackage test.name; import org.testng.Assert; import org.testng.ITest; import org.testng.annotations.Test; public class SimpleITestSample implements ITest { @Test public void test() { Assert.assertTrue(true); } @Override public String getTestName() { return "NAME"; } } testng-6.9.12/src/test/java/test/name/NameTest.java0000644000175000017500000001542112732165123021375 0ustar eugeneeugenepackage test.name; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class NameTest extends SimpleBaseTest { @Test public void itestTest() { TestNG tng = create(SimpleITestSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), "NAME"); Assert.assertEquals(result.getTestName(), "NAME"); } @Test public void itestTestWithXml() { TestNG tng = createTests("suite", SimpleITestSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), "NAME"); Assert.assertEquals(result.getTestName(), "NAME"); } @Test public void testNameTest() { TestNG tng = create(NameSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), "NAME"); Assert.assertEquals(result.getTestName(), "NAME"); } @Test public void testNameTestWithXml() { TestNG tng = createTests("suite", NameSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), "NAME"); Assert.assertEquals(result.getTestName(), "NAME"); } @Test public void noNameTest() { TestNG tng = create(NoNameSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), "test"); Assert.assertEquals(result.getTestName(), null); } @Test public void noNameTestWithXml() { TestNG tng = createTests("suite", NoNameSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), "test"); Assert.assertEquals(result.getTestName(), null); } @Test public void complexITestTest() { TestNG tng = create(ITestSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 5); List testNames = new ArrayList<>(Arrays.asList("test1", "test2", "test3", "test4", "test5")); for (ITestResult testResult : adapter.getPassedTests()) { Assert.assertTrue(testNames.remove(testResult.getName()), "Duplicate test names " + getNames(adapter.getPassedTests())); } Assert.assertEquals(testNames, Collections.emptyList()); } private static List getNames(List results) { List names = new ArrayList<>(results.size()); for (ITestResult result : results) { names.add(result.getName()); } return names; } @Test(description = "GITHUB-922: ITestResult doesn't contain name if a class has @Test") public void testOnClassFromReporter() { TestNG tng = create(TestOnClassSample.class); TestOnClassListener listener = new TestOnClassListener(); tng.addListener(listener); tng.run(); Assert.assertEquals(listener.getNames().size(), 1); Assert.assertEquals(listener.getNames().get(0), "test"); // testName should be ignored if not specified Assert.assertEquals(listener.getTestNames().size(), 1); Assert.assertEquals(listener.getTestNames().get(0), null); } @Test public void blankNameTest() { TestNG tng = create(BlankNameSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), ""); Assert.assertEquals(result.getTestName(), ""); } @Test public void blankNameTestWithXml() { TestNG tng = createTests("suite", BlankNameSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); Assert.assertTrue(adapter.getFailedTests().isEmpty()); Assert.assertTrue(adapter.getSkippedTests().isEmpty()); Assert.assertEquals(adapter.getPassedTests().size(), 1); ITestResult result = adapter.getPassedTests().get(0); Assert.assertEquals(result.getMethod().getMethodName(), "test"); Assert.assertEquals(result.getName(), ""); Assert.assertEquals(result.getTestName(), ""); } } testng-6.9.12/src/test/java/test/name/ITestSample.java0000644000175000017500000000221512732165123022044 0ustar eugeneeugenepackage test.name; import org.testng.Assert; import org.testng.ITest; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; // From http://stackoverflow.com/q/33404335/4234729 public class ITestSample implements ITest { public ThreadLocal testName = new ThreadLocal<>(); @DataProvider(name = "dp", parallel = true) public Object[][] getTests() { return new Object[][]{new Object[]{"test1"}, new Object[]{"test2"}, new Object[]{"test3"}, new Object[]{"test4"}, new Object[]{"test5"}}; } @Test(dataProvider = "dp") public void run(String testName) { Assert.assertEquals(testName, this.testName.get()); } @BeforeMethod public void init(Object[] testArgs) { testName.set((String) testArgs[0]); } @AfterMethod public void tearDown(Object[] testArgs) { Assert.assertEquals((String) testArgs[0], this.testName.get()); } @Override public String getTestName() { return testName.get(); } } testng-6.9.12/src/test/java/test/JUnit4Test.java0000644000175000017500000000435612732165123020717 0ustar eugeneeugenepackage test; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import test.junit4.*; public class JUnit4Test extends BaseTest { @BeforeMethod(dependsOnGroups = {"initTest"}) public void initJUnitFlag() { getTest().setJUnit(true); } @DataProvider public static Object[][] dp() { return new Object[][]{ new Object[]{ new Class[]{JUnit4Sample2.class}, JUnit4Sample2.EXPECTED, JUnit4Sample2.FAILED, JUnit4Sample2.SKIPPED }, new Object[]{ new Class[]{JUnit4SampleSuite.class}, JUnit4SampleSuite.EXPECTED, JUnit4SampleSuite.FAILED, JUnit4SampleSuite.SKIPPED }, new Object[]{ new Class[]{JUnit4Child.class}, JUnit4Child.EXPECTED, new String[0], new String[0] }, new Object[]{ new Class[]{InheritedTest.class, JUnit4Sample1.class}, new String[]{"t1", "t1"}, new String[0], new String[0] }, new Object[]{ new Class[]{JUnit4ParameterizedTest.class}, JUnit4ParameterizedTest.EXPECTED, JUnit4ParameterizedTest.FAILED, JUnit4ParameterizedTest.SKIPPED }, new Object[]{ new Class[]{BeforeClassJUnit4Sample.class}, new String[0], new String[0], new String[]{"myTest"} }, new Object[]{ new Class[]{ClassRuleJUnit4Sample.class}, new String[0], new String[0], new String[]{"myTest"} } }; } @Test(dataProvider = "dp") public void testTests(Class[] classes, String[] expectedPassedTests, String[] expectedFailedTests, String[] expectedSkippedTests) { addClasses(classes); assert getTest().isJUnit(); run(); verifyPassedTests(expectedPassedTests); verifyFailedTests(expectedFailedTests); verifySkippedTests(expectedSkippedTests); } } testng-6.9.12/src/test/java/test/NestedStaticTest.java0000644000175000017500000000157212732165123022171 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.collections.Sets; import java.util.HashSet; import java.util.List; import java.util.Set; public class NestedStaticTest extends SimpleBaseTest { @Test public void nestedClassShouldBeIncluded() { TestNG tng = create(NestedStaticSampleTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Set expected = new HashSet() {{ add("nested"); add("f"); }}; Set actual = Sets.newHashSet(); List passedTests = tla.getPassedTests(); for (ITestResult t : passedTests) { actual.add(t.getMethod().getMethodName()); } Assert.assertEquals(actual, expected); } } testng-6.9.12/src/test/java/test/SampleInheritance.java0000644000175000017500000000276612732165123022340 0ustar eugeneeugenepackage test; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import test.sample.BaseSampleInheritance; public class SampleInheritance extends BaseSampleInheritance { // Test dependency of configuration methods @BeforeClass(groups= { "configuration0"}) public void configuration0() { addConfiguration("configuration0"); // System.out.println("CONFIGURATION 0"); } @BeforeClass(dependsOnGroups = { "configuration1"}) public void configuration2() { assert m_configurations.size() == 2 : "Expected size 2 found " + m_configurations.size(); assert "configuration0".equals(m_configurations.get(0)) : "Expected configuration0 to be run"; assert "configuration1".equals(m_configurations.get(1)) : "Expected configuration1 to be run"; addConfiguration("configuration2"); } @Test(dependsOnGroups = { "inheritedTestMethod"} ) public void inheritedMethodsWereCalledInOrder() { assert m_invokedBaseMethod : "Didn't invoke test method in base class"; assert m_invokedBaseConfiguration : "Didn't invoke configuration method in base class"; } @Test public void configurationsWereCalledInOrder() { assert m_configurations.size() == 3; assert "configuration0".equals(m_configurations.get(0)) : "Expected configuration0 to be run"; assert "configuration1".equals(m_configurations.get(1)) : "Expected configuration1 to be run"; assert "configuration2".equals(m_configurations.get(2)) : "Expected configuration1 to be run"; } } testng-6.9.12/src/test/java/test/verify/0000755000175000017500000000000012732165123017373 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/verify/Verify3SampleTest.java0000644000175000017500000000042112732165123023564 0ustar eugeneeugenepackage test.verify; import org.testng.annotations.BeforeClass; /** * Make sure that @Listeners annotations can come from superclasses */ public class Verify3SampleTest extends Verify3Base { @BeforeClass public void bc() { VerifyTestListener.m_count = 0; } } testng-6.9.12/src/test/java/test/verify/Verify3Base.java0000644000175000017500000000020212732165123022352 0ustar eugeneeugenepackage test.verify; import org.testng.annotations.Listeners; @Listeners(VerifyTestListener.class) public class Verify3Base { } testng-6.9.12/src/test/java/test/verify/VerifyTest.java0000644000175000017500000000211712732165123022343 0ustar eugeneeugenepackage test.verify; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class VerifyTest extends SimpleBaseTest { private void runTest(Class cls, int expected) { TestNG tng = create(cls); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), expected); } @Test public void verifyWithAnnotation() { runTest(VerifySampleTest.class, 4); } @Test public void verifyWithoutAnnotation() { runTest(VerifyNoListenersSampleTest.class, 3); } @Test public void verifyTestListener() { TestNG tng = create(Verify2SampleTest.class); VerifyTestListener.m_count = 0; tng.run(); Assert.assertEquals(VerifyTestListener.m_count, 1); } @Test public void verifyBaseClassTestListener() { TestNG tng = create(Verify3SampleTest.class); VerifyTestListener.m_count = 0; tng.run(); Assert.assertEquals(VerifyTestListener.m_count, 1); } } testng-6.9.12/src/test/java/test/verify/Verify.java0000644000175000017500000000047512732165123021510 0ustar eugeneeugenepackage test.verify; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({METHOD, TYPE}) public @interface Verify { } testng-6.9.12/src/test/java/test/verify/VerifyMethodInterceptor.java0000644000175000017500000000224612732165123025066 0ustar eugeneeugenepackage test.verify; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.collections.Lists; import java.util.List; public class VerifyMethodInterceptor implements IMethodInterceptor { @Override public List intercept(List methods, ITestContext context) { List result = Lists.newArrayList(); IMethodInstance verifier = null; // Doing a naive approach here: we run through the list of methods // twice, once to find the verifier and once more to actually create // the result. Obviously, this can be done with just one loop for (IMethodInstance m : methods) { if (m.getMethod().getMethod().getAnnotation(Verifier.class) != null) { verifier = m; break; } } // Create the result with each @Verify method followed by a call // to the @Verifier method for (IMethodInstance m : methods) { if (m != verifier) { result.add(m); } if (m.getMethod().getMethod().getAnnotation(Verify.class) != null) { result.add(verifier); } } return result; } }testng-6.9.12/src/test/java/test/verify/Verify2SampleTest.java0000644000175000017500000000201312732165123023562 0ustar eugeneeugenepackage test.verify; import org.testng.ITestNGListener; import org.testng.ITestNGListenerFactory; import org.testng.annotations.Listeners; import org.testng.annotations.Test; /** * Illustrate the implementation of a @Verify/@Verifier test. * * One method should be annotated with @Verifier and then each test method * annotated with @Verify will be followed with a call to the @Verifier * method. */ @Listeners(VerifyTestListener.class) public class Verify2SampleTest implements ITestNGListenerFactory { public Verify2SampleTest() {} @Verify @Test public void f1() { log("f1"); } @Verify @Test public void f2() { log("f2"); } @Verifier @Test public void verify() { log("Verifying"); } private void log(String string) { if (false) { System.out.println(hashCode() + " " + string); } } @Override public ITestNGListener createListener(Class listenerClass) { log("Creating a listener of type " + listenerClass); return null; } } testng-6.9.12/src/test/java/test/verify/Verifier.java0000644000175000017500000000047712732165123022021 0ustar eugeneeugenepackage test.verify; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({METHOD, TYPE}) public @interface Verifier { } testng-6.9.12/src/test/java/test/verify/VerifyNoListenersSampleTest.java0000644000175000017500000000073112732165123025673 0ustar eugeneeugenepackage test.verify; import org.testng.annotations.Test; /** * Same class as VerifySampleTest but without the @Listeners annotation. */ public class VerifyNoListenersSampleTest { @Verify @Test public void f1() { log("f1"); } @Verify @Test public void f2() { log("f2"); } @Verifier @Test public void verify() { log("Verifying"); } private void log(String string) { if (false) { System.out.println(string); } } } testng-6.9.12/src/test/java/test/verify/VerifyTestListener.java0000644000175000017500000000131212732165123024045 0ustar eugeneeugenepackage test.verify; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class VerifyTestListener implements ITestListener { public static int m_count = 0; @Override public void onFinish(ITestContext context) { } @Override public void onStart(ITestContext context) { m_count++; } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } @Override public void onTestFailure(ITestResult result) { } @Override public void onTestSkipped(ITestResult result) { } @Override public void onTestStart(ITestResult result) { } @Override public void onTestSuccess(ITestResult result) { } } testng-6.9.12/src/test/java/test/verify/VerifySampleTest.java0000644000175000017500000000126712732165123023512 0ustar eugeneeugenepackage test.verify; import org.testng.annotations.Listeners; import org.testng.annotations.Test; /** * Illustrate the implementation of a @Verify/@Verifier test. * * One method should be annotated with @Verifier and then each test method * annotated with @Verify will be followed with a call to the @Verifier * method. */ @Listeners(VerifyMethodInterceptor.class) public class VerifySampleTest { @Verify @Test public void f1() { log("f1"); } @Verify @Test public void f2() { log("f2"); } @Verifier @Test public void verify() { log("Verifying"); } private void log(String string) { if (false) { System.out.println(string); } } } testng-6.9.12/src/test/java/test/testng249/0000755000175000017500000000000012732165123017632 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng249/B.java0000644000175000017500000000021412732165123020653 0ustar eugeneeugenepackage test.testng249; import org.testng.annotations.Test; public class B extends Base { @Override @Test public void b() { } }testng-6.9.12/src/test/java/test/testng249/VerifyTest.java0000644000175000017500000000217412732165123022605 0ustar eugeneeugenepackage test.testng249; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; public class VerifyTest extends SimpleBaseTest { @Test public void verify() { XmlSuite suite = new XmlSuite(); suite.setName("Suite"); XmlTest test = new XmlTest(suite); test.setName("Test"); XmlClass c1 = new XmlClass(B.class); c1.setIncludedMethods(Arrays.asList(new XmlInclude[] { new XmlInclude("b")})); XmlClass c2 = new XmlClass(Base.class); c2.setIncludedMethods(Arrays.asList(new XmlInclude[] { new XmlInclude("b")})); test.setXmlClasses(Arrays.asList(new XmlClass[] { c1, c2 })); TestNG tng = new TestNG(); tng.setVerbose(0); tng.setXmlSuites(Arrays.asList(new XmlSuite[] { suite })); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 2); } } testng-6.9.12/src/test/java/test/testng249/Base.java0000644000175000017500000000016312732165123021347 0ustar eugeneeugenepackage test.testng249; import org.testng.annotations.Test; public class Base { @Test public void b() { } }testng-6.9.12/src/test/java/test/IndividualMethodsTest.java0000644000175000017500000000116312732165123023207 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * Test that if an individual method is specified on testng.xml, the @Configuration * method still runs. * * Created on Aug 1, 2005 * @author cbeust */ public class IndividualMethodsTest { private boolean m_setUpCalled = false; @BeforeMethod public void setUp() { m_setUpCalled = true; } @Test public void testMethod() { // this line causes the test to fail, showing that setUp() hadn't been run Assert.assertTrue(m_setUpCalled); } } testng-6.9.12/src/test/java/test/mannotation/0000755000175000017500000000000012732165123020416 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/mannotation/MTest2.java0000644000175000017500000000016212732165123022376 0ustar eugeneeugenepackage test.mannotation; import org.testng.annotations.Test; @Test(alwaysRun = false) public class MTest2 { } testng-6.9.12/src/test/java/test/mannotation/MBase.java0000644000175000017500000000032512732165123022250 0ustar eugeneeugenepackage test.mannotation; import org.testng.annotations.Test; @Test(groups = "base-class", dependsOnGroups="dog3", dependsOnMethods="dom3", enabled=true) public class MBase { public void baseTest() {} } testng-6.9.12/src/test/java/test/mannotation/MBaseCapture.java0000644000175000017500000000053512732165123023577 0ustar eugeneeugenepackage test.mannotation; import org.testng.annotations.Test; /** * Make sure that if a method is declared in the base class and a child class * adds a class-scoped group to it, that method receives it as well. * * @author cbeust * @date Mar 22, 2006 */ public class MBaseCapture { @Test public void shouldBelongToGroupChild() { } } testng-6.9.12/src/test/java/test/mannotation/MChildCaptureTest.java0000644000175000017500000000025212732165123024604 0ustar eugeneeugenepackage test.mannotation; import org.testng.annotations.Test; @Test(groups = "child") public class MChildCaptureTest extends MBaseCapture { public void f() { } } testng-6.9.12/src/test/java/test/mannotation/MTest1.java0000644000175000017500000000563312732165123022405 0ustar eugeneeugenepackage test.mannotation; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Configuration; import org.testng.annotations.DataProvider; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Factory; import org.testng.annotations.Parameters; import org.testng.annotations.Test; @Test(enabled = true, groups = {"group1", "group2"}, alwaysRun = true, parameters = {"param1", "param2"}, dependsOnGroups = {"dg1", "dg2"}, dependsOnMethods = {"dm1", "dm2"}, timeOut = 42, invocationCount = 43, successPercentage = 44, threadPoolSize = 3, dataProvider = "dp", description = "Class level description") public class MTest1 { @Test(enabled = true, groups = {"group5", "group6"}, alwaysRun = true, parameters = {"param5", "param6"}, dependsOnGroups = {"dg5", "dg6"}, dependsOnMethods = {"dm5", "dm6"}, timeOut = 242, invocationCount = 243, successPercentage = 62, dataProvider = "dp3", description = "Constructor description", expectedExceptions = NumberFormatException.class) public MTest1() {} @Test(enabled = true, groups = {"group3", "group4"}, alwaysRun = true, parameters = {"param3", "param4"}, dependsOnGroups = {"dg3", "dg4"}, dependsOnMethods = {"dm3", "dm4"}, timeOut = 142, invocationCount = 143, successPercentage = 61, dataProvider = "dp2", description = "Method description", expectedExceptions = NullPointerException.class) public void f() {} @Configuration(beforeSuite = true, beforeTestMethod = true, beforeTest = true, beforeTestClass = true, beforeGroups = { "b1", "b2"}) public void before() {} @Configuration(afterSuite = true, afterTestMethod = true, afterTest = true, afterTestClass = true, afterGroups = {"a1", "a2"}) public void after() {} @Configuration(parameters = {"oparam1", "oparam2"}, enabled = false, groups = {"ogroup1", "ogroup2"}, dependsOnGroups = {"odg1","odg2"}, dependsOnMethods = {"odm1", "odm2"}, alwaysRun = true, inheritGroups = false, description = "beforeSuite description") @DataProvider(name = "dp4") @ExpectedExceptions({MTest1.class, MTest2.class }) public void otherConfigurations() {} @Factory(parameters = {"pf1", "pf2"}) public void factory() {} @Parameters({"pp1", "pp2", "pp3"}) public void parameters() {} @BeforeSuite @BeforeTest @BeforeGroups @BeforeClass @BeforeMethod public void newBefore() {} @AfterSuite @AfterTest @AfterGroups @AfterClass @AfterMethod public void newAfter() {} } testng-6.9.12/src/test/java/test/mannotation/MTest3.java0000644000175000017500000000136512732165123022405 0ustar eugeneeugenepackage test.mannotation; import org.testng.annotations.Configuration; import org.testng.annotations.Test; @Test(groups = "child-class-test3", dependsOnGroups = "dog1", dependsOnMethods = "dom1") public class MTest3 extends MBase { @Test(groups = "method-test3") public void groups1() {} @Test public void groups2() {} @Test(dependsOnGroups = "dog2") public void dependsOnGroups1() {} @Test public void dependsOnGroups2() {} @Test(dependsOnMethods = "dom2") public void dependsOnMethods1() {} @Test public void dependsOnMethods2() {} @Test(enabled = false) public void enabled1() {} @Test public void enabled2() {} @Configuration(beforeSuite = true, groups = "method-test3") public void beforeSuite() { } } testng-6.9.12/src/test/java/test/mannotation/MAnnotationSampleTest.java0000644000175000017500000002745512732165123025527 0ustar eugeneeugenepackage test.mannotation; import org.testng.Assert; import org.testng.annotations.Configuration; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.IParametersAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Test; import org.testng.internal.IConfiguration; import org.testng.internal.annotations.IAfterSuite; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.annotations.IBeforeSuite; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @Test(enabled = true) public class MAnnotationSampleTest { private IConfiguration m_configuration = new org.testng.internal.Configuration(); private IAnnotationFinder m_finder; @Configuration(beforeTestClass = true, enabled = true) public void init() { m_finder = m_configuration.getAnnotationFinder(); } public void verifyTestClassLevel() { // // Tests on MTest1SampleTest // ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(MTest1.class, ITestAnnotation.class); Assert.assertTrue(test1.getEnabled()); Assert.assertEquals(test1.getGroups(), new String[] { "group1", "group2" }); Assert.assertTrue(test1.getAlwaysRun()); Assert.assertEquals(test1.getParameters(), new String[] { "param1", "param2" }); Assert.assertEqualsNoOrder(test1.getDependsOnGroups(), new String[] { "dg1", "dg2" }, "depends on groups"); Assert.assertEqualsNoOrder( test1.getDependsOnMethods(), new String[] { "dm1", "dm2" }); Assert.assertEquals(test1.getTimeOut(), 42); Assert.assertEquals(test1.getInvocationCount(), 43); Assert.assertEquals(test1.getSuccessPercentage(), 44); Assert.assertEquals(test1.getThreadPoolSize(), 3); Assert.assertEquals(test1.getDataProvider(), "dp"); Assert.assertEquals(test1.getDescription(), "Class level description"); // // Tests on MTest1SampleTest (test defaults) // ITestAnnotation test2 = (ITestAnnotation) m_finder.findAnnotation(MTest2.class, ITestAnnotation.class); // test default for enabled Assert.assertTrue(test2.getEnabled()); Assert.assertFalse(test2.getAlwaysRun()); Assert.assertEquals(test2.getTimeOut(), 0); Assert.assertEquals(test2.getInvocationCount(), 1); Assert.assertEquals(test2.getSuccessPercentage(), 100); Assert.assertEquals(test2.getDataProvider(), ""); } public void verifyTestMethodLevel() throws SecurityException, NoSuchMethodException { // // Tests on MTest1SampleTest // Method method = MTest1.class.getMethod("f", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertTrue(test1.getEnabled()); Assert.assertEqualsNoOrder(test1.getGroups(), new String[] { "group1", "group3", "group4", "group2" }); Assert.assertTrue(test1.getAlwaysRun()); Assert.assertEquals(test1.getParameters(), new String[] { "param3", "param4" }); Assert.assertEqualsNoOrder(test1.getDependsOnGroups(), new String[] { "dg1", "dg2", "dg3", "dg4" }); Assert.assertEqualsNoOrder(test1.getDependsOnMethods(), new String[] { "dm1", "dm2", "dm3", "dm4" }); Assert.assertEquals(test1.getTimeOut(), 142); Assert.assertEquals(test1.getInvocationCount(), 143); Assert.assertEquals(test1.getSuccessPercentage(), 61); Assert.assertEquals(test1.getDataProvider(), "dp2"); Assert.assertEquals(test1.getDescription(), "Method description"); Class[] exceptions = test1.getExpectedExceptions(); Assert.assertEquals(exceptions.length, 1); Assert.assertEquals(exceptions[0], NullPointerException.class); } public void verifyTestConstructorLevel() throws SecurityException, NoSuchMethodException { // // Tests on MTest1SampleTest // Constructor constructor = MTest1.class.getConstructor(new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(constructor, ITestAnnotation.class); Assert.assertNotNull(test1); Assert.assertTrue(test1.getEnabled()); Assert.assertEqualsNoOrder(test1.getGroups(), new String[] { "group5", "group1", "group6", "group2" }); Assert.assertTrue(test1.getAlwaysRun()); Assert.assertEquals(test1.getParameters(), new String[] { "param5", "param6" }); Assert.assertEqualsNoOrder(test1.getDependsOnGroups(), new String[] { "dg1", "dg2", "dg5", "dg6" }); Assert.assertEqualsNoOrder(test1.getDependsOnMethods(), new String[] { "dm1", "dm2", "dm5", "dm6" }); Assert.assertEquals(test1.getTimeOut(), 242); Assert.assertEquals(test1.getInvocationCount(), 243); Assert.assertEquals(test1.getSuccessPercentage(), 62); Assert.assertEquals(test1.getDataProvider(), "dp3"); Assert.assertEquals(test1.getDescription(), "Constructor description"); Class[] exceptions = test1.getExpectedExceptions(); Assert.assertEquals(exceptions.length, 1); Assert.assertEquals(exceptions[0], NumberFormatException.class); } public void verifyConfigurationBefore() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("before", new Class[0]); IConfigurationAnnotation configuration = (IConfigurationAnnotation) m_finder.findAnnotation(method, IConfigurationAnnotation.class); Assert.assertNotNull(configuration); Assert.assertTrue(configuration.getBeforeSuite()); Assert.assertTrue(configuration.getBeforeTestMethod()); Assert.assertTrue(configuration.getBeforeTest()); Assert.assertTrue(configuration.getBeforeTestClass()); Assert.assertFalse(configuration.getAfterSuite()); Assert.assertFalse(configuration.getAfterTestMethod()); Assert.assertFalse(configuration.getAfterTest()); Assert.assertFalse(configuration.getAfterTestClass()); Assert.assertEquals(0, configuration.getAfterGroups().length); String[] bg = configuration.getBeforeGroups(); Assert.assertEquals(bg.length, 2); Assert.assertEqualsNoOrder(bg, new String[] {"b1", "b2"}); // Default values Assert.assertTrue(configuration.getEnabled()); Assert.assertTrue(configuration.getInheritGroups()); Assert.assertFalse(configuration.getAlwaysRun()); } public void verifyConfigurationAfter() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("after", new Class[0]); IConfigurationAnnotation configuration = (IConfigurationAnnotation) m_finder.findAnnotation(method, IConfigurationAnnotation.class); Assert.assertNotNull(configuration); Assert.assertFalse(configuration.getBeforeSuite()); Assert.assertFalse(configuration.getBeforeTestMethod()); Assert.assertFalse(configuration.getBeforeTest()); Assert.assertFalse(configuration.getBeforeTestClass()); Assert.assertTrue(configuration.getAfterSuite()); Assert.assertTrue(configuration.getAfterTestMethod()); Assert.assertTrue(configuration.getAfterTest()); Assert.assertTrue(configuration.getAfterTestClass()); Assert.assertEquals(0, configuration.getBeforeGroups().length); String[] ag = configuration.getAfterGroups(); Assert.assertEquals(ag.length, 2); Assert.assertEqualsNoOrder(ag, new String[] {"a1", "a2"}); // Default values Assert.assertTrue(configuration.getEnabled()); Assert.assertTrue(configuration.getInheritGroups()); Assert.assertFalse(configuration.getAlwaysRun()); } public void verifyConfigurationOthers() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("otherConfigurations", new Class[0]); IConfigurationAnnotation configuration = (IConfigurationAnnotation) m_finder.findAnnotation(method, IConfigurationAnnotation.class); Assert.assertNotNull(configuration); Assert.assertFalse(configuration.getBeforeSuite()); Assert.assertFalse(configuration.getBeforeTestMethod()); Assert.assertFalse(configuration.getBeforeTest()); Assert.assertFalse(configuration.getBeforeTestClass()); Assert.assertFalse(configuration.getAfterSuite()); Assert.assertFalse(configuration.getAfterTestMethod()); Assert.assertFalse(configuration.getAfterTest()); Assert.assertFalse(configuration.getAfterTestClass()); Assert.assertFalse(configuration.getEnabled()); Assert.assertEquals(configuration.getParameters(), new String[] { "oparam1", "oparam2" }); Assert.assertEqualsNoOrder(configuration.getGroups(), new String[] { "group1", "ogroup1", "ogroup2", "group2" }, "groups"); Assert.assertEqualsNoOrder(configuration.getDependsOnGroups(), new String[] { "odg1", "odg2" }, "depends on groups"); Assert.assertEqualsNoOrder(configuration.getDependsOnMethods(), new String[] { "odm1", "odm2" }, "depends on methods"); Assert.assertFalse(configuration.getInheritGroups()); Assert.assertTrue(configuration.getAlwaysRun()); Assert.assertEquals(configuration.getDescription(), "beforeSuite description"); } public void verifyDataProvider() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("otherConfigurations", new Class[0]); IDataProviderAnnotation dataProvider = (IDataProviderAnnotation) m_finder.findAnnotation(method, IDataProviderAnnotation.class); Assert.assertNotNull(dataProvider); Assert.assertEquals(dataProvider.getName(), "dp4"); } public void verifyExpectedExceptions() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("otherConfigurations", new Class[0]); IExpectedExceptionsAnnotation exceptions= (IExpectedExceptionsAnnotation) m_finder.findAnnotation(method, IExpectedExceptionsAnnotation.class); Assert.assertNotNull(exceptions); Assert.assertEquals(exceptions.getValue(), new Class[] { MTest1.class, MTest2.class }); } public void verifyFactory() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("factory", new Class[0]); IFactoryAnnotation factory= (IFactoryAnnotation) m_finder.findAnnotation(method, IFactoryAnnotation.class); Assert.assertNotNull(factory); Assert.assertEquals(factory.getParameters(), new String[] { "pf1", "pf2" }); } public void verifyParameters() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("parameters", new Class[0]); IParametersAnnotation parameters = (IParametersAnnotation) m_finder.findAnnotation(method, IParametersAnnotation.class); Assert.assertNotNull(parameters); Assert.assertEquals(parameters.getValue(), new String[] { "pp1", "pp2", "pp3" }); } public void verifyNewConfigurationBefore() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("newBefore", new Class[0]); IConfigurationAnnotation configuration = (IConfigurationAnnotation) m_finder.findAnnotation(method, IBeforeSuite.class); Assert.assertNotNull(configuration); Assert.assertTrue(configuration.getBeforeSuite()); // Default values Assert.assertTrue(configuration.getEnabled()); Assert.assertTrue(configuration.getInheritGroups()); Assert.assertFalse(configuration.getAlwaysRun()); } public void verifyNewConfigurationAfter() throws SecurityException, NoSuchMethodException { Method method = MTest1.class.getMethod("newAfter", new Class[0]); IConfigurationAnnotation configuration = (IConfigurationAnnotation) m_finder.findAnnotation(method, IAfterSuite.class); Assert.assertNotNull(configuration); Assert.assertTrue(configuration.getAfterSuite()); // Default values Assert.assertTrue(configuration.getEnabled()); Assert.assertTrue(configuration.getInheritGroups()); Assert.assertFalse(configuration.getAlwaysRun()); } private static void ppp(String s) { System.out.println("[MAnnotationSampleTest] " + s); } } testng-6.9.12/src/test/java/test/mannotation/MAnnotation2SampleTest.java0000644000175000017500000001042112732165123025572 0ustar eugeneeugenepackage test.mannotation; import org.testng.Assert; import org.testng.annotations.Configuration; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Test; import org.testng.internal.IConfiguration; import org.testng.internal.annotations.IAnnotationFinder; import java.lang.reflect.Method; public class MAnnotation2SampleTest { private IConfiguration m_configuration = new org.testng.internal.Configuration(); private IAnnotationFinder m_finder; @Configuration(beforeTestClass = true, enabled = true, groups="current") public void init() { m_finder = m_configuration.getAnnotationFinder(); } @Test public void verifyTestGroupsInheritance() throws SecurityException, NoSuchMethodException { { Method method = MTest3.class.getMethod("groups1", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "method-test3", "child-class-test3", "base-class" }, test1.getGroups()); } { Method method = MTest3.class.getMethod("groups2", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "child-class-test3", "base-class" }, test1.getGroups()); } } @Test public void verifyTestDependsOnGroupsInheritance() throws SecurityException, NoSuchMethodException { { Method method = MTest3.class.getMethod("dependsOnGroups1", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "dog2", "dog1", "dog3" }, test1.getDependsOnGroups()); } { Method method = MTest3.class.getMethod("dependsOnGroups2", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "dog1", "dog3" }, test1.getDependsOnGroups()); } } @Test public void verifyTestDependsOnMethodsInheritance() throws SecurityException, NoSuchMethodException { { Method method = MTest3.class.getMethod("dependsOnMethods1", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "dom2", "dom3", "dom1" }, test1.getDependsOnMethods()); } { Method method = MTest3.class.getMethod("dependsOnMethods2", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "dom1", "dom3" }, test1.getDependsOnMethods()); } } @Test public void verifyConfigurationGroupsInheritance() throws SecurityException, NoSuchMethodException { Method method = MTest3.class.getMethod("beforeSuite", new Class[0]); IConfigurationAnnotation test1 = (IConfigurationAnnotation) m_finder.findAnnotation(method, IConfigurationAnnotation.class); Assert.assertEqualsNoOrder(new String[] { "method-test3", "child-class-test3", "base-class" }, test1.getGroups()); } @Test(groups="current") public void verifyTestEnabledInheritance() throws SecurityException, NoSuchMethodException { { Method method = MTest3.class.getMethod("enabled1", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertFalse(test1.getEnabled()); } { Method method = MTest3.class.getMethod("enabled2", new Class[0]); ITestAnnotation test1 = (ITestAnnotation) m_finder.findAnnotation(method, ITestAnnotation.class); Assert.assertTrue(test1.getEnabled()); } } // @Test(groups = "current") // public void verifyCapture() // throws SecurityException, NoSuchMethodException // { // { // Method method = MChildCaptureTest.class.getMethod("shouldBelongToGroupChild", new Class[0]); // ITest test1 = (ITest) m_finder.findAnnotation(method, ITest.class); // Assert.assertEqualsNoOrder(new String[] { "child" }, // test1.getGroups()); // } // } } testng-6.9.12/src/test/java/test/commandline/0000755000175000017500000000000012732165123020355 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/commandline/CommandLineOverridesXml.java0000644000175000017500000000270412732165123025755 0ustar eugeneeugenepackage test.commandline; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; public class CommandLineOverridesXml extends SimpleBaseTest { @Test(description = "Specifying -groups on the command line should override testng.xml") public void commandLineGroupsShouldOverrideXml() { runTest("go", null, Arrays.asList(new String[] { "f2" })); } @Test(description = "Specifying -excludegroups on the command line should override testng.xml") public void commandLineExcludedGroupsShouldOverrideXml() { runTest(null, "go", Arrays.asList(new String[] { "f1" })); } @Test public void shouldRunBothMethods() { runTest(null, null, Arrays.asList(new String[] { "f1", "f2" })); } private void runTest(String group, String excludedGroups, List methods) { XmlSuite s = createXmlSuite(getClass().getName()); XmlTest t = createXmlTest(s, "Test", OverrideSampleTest.class.getName()); TestNG tng = create(); if (group != null) tng.setGroups(group); if (excludedGroups != null) tng.setExcludedGroups(excludedGroups); tng.setXmlSuites(Arrays.asList(new XmlSuite[] { s })); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); assertTestResultsEqual(tla.getPassedTests(), methods); } } testng-6.9.12/src/test/java/test/commandline/OverrideSampleTest.java0000644000175000017500000000026112732165123025000 0ustar eugeneeugenepackage test.commandline; import org.testng.annotations.Test; public class OverrideSampleTest { @Test public void f1() {} @Test(groups = "go") public void f2() {} } testng-6.9.12/src/test/java/test/factory/0000755000175000017500000000000012732165123017536 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/factory/TestClassAnnotationTest.java0000644000175000017500000000155712732165123025211 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; /** * Make sure that @Factory methods are not counted as @Test in the * presence of a class-scoped @Test annotation. * * Created on Mar 30, 2006 * @author Cedric Beust */ @Test public class TestClassAnnotationTest { private int m_count; @Factory public Object[] createFixture() { ppp("FACTORY"); m_count++; return new Object[] { new Object[] { new Object() }}; } public void testOne() { ppp("TESTONE"); m_count++; } @AfterClass public void verify() { ppp("VERIFY"); Assert.assertEquals(m_count, 2); } private static void ppp(String s) { if (false) { System.err.println("[FactoryTest] " + s); } } } testng-6.9.12/src/test/java/test/factory/IteratorEmptyFactorySample.java0000644000175000017500000000106612732165123025706 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; import java.util.Collections; import java.util.Iterator; public class IteratorEmptyFactorySample { @DataProvider(name = "values") public static Iterator values() { return Collections.emptyIterator(); } @Factory(dataProvider = "values") public IteratorEmptyFactorySample(int value) { } @Test public void test() { Assert.fail(); } } testng-6.9.12/src/test/java/test/factory/FactoryAndTestMethodTest.java0000644000175000017500000000133512732165123025276 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; @Test(groups = { "x" }) public class FactoryAndTestMethodTest { @Factory(dataProvider = "data") public Object[] ohNo(String s) { return makeNullArgTests(s); } public static class NullArgsTest { public final String s; public NullArgsTest(String s) { this.s = s; } @Test public void test() { Assert.assertNotNull(s); } } private Object[] makeNullArgTests(String s) { return new Object[0]; } @DataProvider(name = "data") public Object[][] makeData() { return new Object[][] { { "foo" } }; } } testng-6.9.12/src/test/java/test/factory/FactoryInterleavingTest.java0000644000175000017500000000162312732165123025222 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.collections.Lists; import test.SimpleBaseTest; import java.util.List; public class FactoryInterleavingTest extends SimpleBaseTest { public static List LOG = Lists.newArrayList(); @Test public void methodsShouldBeInterleaved() { TestNG tng = create(FactoryInterleavingSampleFactory.class); tng.run(); Integer[] valid1 = { 10, 11, 12, 13, 20, 21, 22, 23, }; Integer[] valid2 = { 20, 21, 22, 23, 10, 11, 12, 13, }; Integer[] logArray = LOG.toArray(new Integer[LOG.size()]); if (! logArray.equals(valid1)) { Assert.assertEquals(logArray, valid1); } else if (! logArray.equals(valid2)) { System.err.println(logArray + " " + valid2); Assert.assertEquals(logArray, valid2); } } } testng-6.9.12/src/test/java/test/factory/FactoryOrderMainTest.java0000644000175000017500000000132212732165123024447 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.List; public class FactoryOrderMainTest extends SimpleBaseTest { @Test public void factoriesShouldBeInvokedInTheOrderOfCreation() { TestNG tng = create(FactoryOrderTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); List passed = tla.getPassedTests(); for (int i = 0; i < passed.size(); i++) { Assert.assertEquals(((FactoryOrderSampleTest) passed.get(i).getInstance()).getValue(), i); } } } testng-6.9.12/src/test/java/test/factory/FactoryWithInstanceInfoTest2.java0000644000175000017500000000142512732165123026071 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; import java.util.HashMap; import java.util.Map; /** * This class is created by FactoryWithInstanceInfoTest2 * * @author cbeust */ public class FactoryWithInstanceInfoTest2 { private static Map m_numbers = new HashMap<>(); private int m_number; public FactoryWithInstanceInfoTest2() { throw new RuntimeException("Shouldn't be invoked"); } public static Map getNumbers() { return m_numbers; } public FactoryWithInstanceInfoTest2(int n) { m_number = n; } @Test(groups = { "first" }) public void testInt() { Integer n = m_number; m_numbers.put(n, n); } private static void ppp(String s) { System.out.println("[FactoryTest2] " + s); } } testng-6.9.12/src/test/java/test/factory/FactoryInterleavingSampleFactory.java0000644000175000017500000000061212732165123027051 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; public class FactoryInterleavingSampleFactory { @Factory public Object[] factory() { return new Object[] { new FactoryInterleavingSampleA(1), new FactoryInterleavingSampleA(2) }; } @BeforeClass public void beforeB() { System.out.println("Before B"); } } testng-6.9.12/src/test/java/test/factory/FactoryWithInstanceInfoTest.java0000644000175000017500000000205412732165123026006 0ustar eugeneeugenepackage test.factory; import static org.testng.Assert.assertFalse; import org.testng.IInstanceInfo; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Factory; import org.testng.annotations.Parameters; import org.testng.internal.InstanceInfo; public class FactoryWithInstanceInfoTest { static boolean m_invoked = false; @Parameters({ "factory-param" }) @Factory public IInstanceInfo[] createObjectsWithInstanceInfo(String param) { assert "FactoryParam".equals(param) : "Incorrect param: " + param; assertFalse(m_invoked, "Should only be invoked once"); m_invoked = true; return new IInstanceInfo[] { new InstanceInfo(FactoryWithInstanceInfoTest2.class, new FactoryWithInstanceInfoTest2(42)), new InstanceInfo(FactoryWithInstanceInfoTest2.class, new FactoryWithInstanceInfoTest2(43)), }; } @BeforeSuite public void beforeSuite() { m_invoked = false; } private static void ppp(String s) { System.out.println("[FactoryWithInstanceInfoTest] " + s); } }testng-6.9.12/src/test/java/test/factory/FactoryOrderTest.java0000644000175000017500000000106212732165123023643 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; import java.util.ArrayList; import java.util.List; public class FactoryOrderTest { public FactoryOrderTest() { // System.out.println("inside testFactory constructor"); } @Factory public static Object[] testF() throws Exception { List result = new ArrayList(); // System.out.println("inside factory: "); int i = 0; while (i < 5) { result.add(new FactoryOrderSampleTest(i)); i++; } return result.toArray(); } }testng-6.9.12/src/test/java/test/factory/FactoryChild.java0000644000175000017500000000011212732165123022746 0ustar eugeneeugenepackage test.factory; public class FactoryChild extends FactoryBase { } testng-6.9.12/src/test/java/test/factory/FactoryDataProviderTest.java0000644000175000017500000000364112732165123025161 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.Iterator; public class FactoryDataProviderTest extends SimpleBaseTest { @Test(description = "Test @Factory(dataProvider) on a local static data provider") public void factoryWithLocalDataProvider() { runTest(FactoryDataProviderSampleTest.class, 41, 42); } @Test(description = "Test @Factory(dataProvider) on a data provider in another class") public void factoryWithStaticDataProvider() { runTest(FactoryDataProviderStaticSampleTest.class, 43, 44); } @Test(description = "Test @Factory(dataProvider) on a non static data provider with no arg ctor") public void factoryWithNonStaticDataProvider() { runTest(FactoryDataProviderWithNoArgCtorSampleErrorTest.class, 45, 46); } @Test(expectedExceptions = TestNGException.class, description = "Should fail because the data provider is not static") public void factoryWithNonStaticDataProviderShouldFail() { runTest(FactoryDataProviderStaticSampleErrorTest.class, 43, 44); } private void runTest(Class cls, int n1, int n2) { TestNG tng = create(cls); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 2); Iterator iterator = tla.getPassedTests().iterator(); BaseFactory t1 = (BaseFactory) iterator.next().getInstance(); BaseFactory t2 = (BaseFactory) iterator.next().getInstance(); // Assert.assertTrue(t1.getN() == n1 || t1.getN() == n2); // Assert.assertTrue(t2.getN() == n1 || t2.getN() == n2); // System.out.println("Results:" + t1.getN() + " " + t2.getN()); Assert.assertEquals(t1.getN(), n1); Assert.assertEquals(t2.getN(), n2); } } testng-6.9.12/src/test/java/test/factory/FactoryBase.java0000644000175000017500000000031412732165123022601 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; public class FactoryBase { @Factory public Object[] create() { return new Object[] { new FactoryBaseSampleTest() }; } } testng-6.9.12/src/test/java/test/factory/FactoryDataProviderSampleTest.java0000644000175000017500000000117512732165123026323 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class FactoryDataProviderSampleTest extends BaseFactory { @Factory(dataProvider = "dp") public FactoryDataProviderSampleTest(int n) { super(n); } @DataProvider static public Object[][] dp() { return new Object[][] { new Object[] { 41 }, new Object[] { 42 }, }; } @Override public String toString() { return "[FactoryDataProviderSampleTest " + getN() + "]"; } @Test public void f() { // System.out.println("Test:" + getN()); } } testng-6.9.12/src/test/java/test/factory/FactoryDataProviderWithNoArgCtorSampleErrorTest.java0000644000175000017500000000121212732165123031740 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; public class FactoryDataProviderWithNoArgCtorSampleErrorTest extends BaseFactory { public FactoryDataProviderWithNoArgCtorSampleErrorTest() { super(0); } @Factory(dataProvider = "dp") public FactoryDataProviderWithNoArgCtorSampleErrorTest(int n) { super(n); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 45 }, new Object[] { 46 }, }; } @Override public String toString() { return "[FactoryDataProviderWithNoArgCtorSampleErrorTest " + getN() + "]"; } } testng-6.9.12/src/test/java/test/factory/GitHub876Sample.java0000644000175000017500000000205112732165123023170 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class GitHub876Sample { @Factory public Object[] createInstances() { return new Object[]{ new GitHub876Sample(new DataTest("foo", true)), new GitHub876Sample(new DataTest("FOO", false)) }; } private final DataTest dataTest; public GitHub876Sample(DataTest dataTest) { this.dataTest = dataTest; } @Test public void test() { switch (dataTest.s) { case "FOO": Assert.assertFalse(dataTest.b); break; case "foo": Assert.assertTrue(dataTest.b); break; default: Assert.fail("Unknown value"); } } public static class DataTest { private final String s; private final boolean b; public DataTest(String s, boolean b) { this.s = s; this.b = b; } } } testng-6.9.12/src/test/java/test/factory/VerifyFactoryTest.java0000644000175000017500000000072112732165123024035 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; import java.util.Map; public class VerifyFactoryTest { @Test(dependsOnGroups = { "first" } ) public void mainCheck() { Map numbers = FactoryTest2.getNumbers(); assert null != numbers.get(42) : "Didn't find 42"; assert null != numbers.get(43) : "Didn't find 43"; assert 2 == numbers.size() : "Expected 2 numbers, found " + (numbers.size()); } } testng-6.9.12/src/test/java/test/factory/FactoryOrderSampleTest.java0000644000175000017500000000160712732165123025012 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FactoryOrderSampleTest { int value; public FactoryOrderSampleTest(int j) { value = j; log("classC constructor " + value); } private void log(String string) { // System.out.println("[FactoryOrderSampleTest] " + string); } @BeforeClass(groups = { "s1ds" }) public void setup() { log("classC.BeforeClass " + value); } @Test(groups = { "s1ds" }) public void methodC1() throws Exception { // Thread.sleep(1000); log("classC.methodC1 " + value); } @AfterClass(groups = { "s1ds" }) public void cleanup() { log("classC.AfterClass " + value); } @Override public String toString() { return "[FactoryOrderSampleTest " + value + "]"; } public int getValue() { return value; } }testng-6.9.12/src/test/java/test/factory/BaseFactory.java0000644000175000017500000000075012732165123022605 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; public class BaseFactory { private int m_n; public BaseFactory(int n) { m_n = n; } public int getN() { return m_n; } @Test public void f() { } /** * @@@ for some reason, the test results get added in the wrong order if * I don't define a toString() method. Need to investigate. */ @Override public String toString() { return "[" + getClass().getName() + " " + getN() + "]"; } } testng-6.9.12/src/test/java/test/factory/FactoryFailureSampleTest.java0000644000175000017500000000040212732165123025316 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class FactoryFailureSampleTest { @Factory public Object[] factory() { throw new NullPointerException(); } @Test public void f() { } } testng-6.9.12/src/test/java/test/factory/FactoryDataProviderStaticSampleTest.java0000644000175000017500000000042412732165123027467 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; public class FactoryDataProviderStaticSampleTest extends BaseFactory { @Factory(dataProvider = "dp", dataProviderClass = DPClass.class) public FactoryDataProviderStaticSampleTest(int n) { super(n); } } testng-6.9.12/src/test/java/test/factory/Sample2.java0000644000175000017500000000335212732165123021707 0ustar eugeneeugenepackage test.factory; import static org.testng.Assert.assertEquals; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; /** * Test that setUp methods are correctly interleaved even * when we use similar instances of a same test class. * * @author cbeust */ public class Sample2 { private static List m_methodList = new ArrayList<>(); @BeforeSuite public void init() { m_methodList = new ArrayList<>(); } @BeforeMethod public void setUp() { ppp("SET UP"); m_methodList.add("setUp"); } @AfterMethod public void tearDown() { ppp("TEAR DOWN"); m_methodList.add("tearDown"); } @AfterSuite public void afterSuite() { String[] expectedStrings = { "setUp", "testInputImages", "tearDown", "setUp", "testInputImages", "tearDown", "setUp", "testImages", "tearDown", "setUp", "testImages", "tearDown", }; List expected = new ArrayList<>(); for (String s : expectedStrings) { expected.add(s); } ppp("ORDER OF METHODS:"); for (String s : m_methodList) { ppp(" " + s); } assertEquals(m_methodList, expected); } @Test public void testInputImages() { m_methodList.add("testInputImages"); ppp("TESTINPUTIMAGES"); } @Test(dependsOnMethods={"testInputImages"}) public void testImages() { m_methodList.add("testImages"); } private static void ppp(String s) { if (false) { System.out.println("[Sample2] " + s); } } } testng-6.9.12/src/test/java/test/factory/classconf/0000755000175000017500000000000012732165123021511 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/factory/classconf/XClassOrderWithFactory.java0000644000175000017500000000154712732165123026740 0ustar eugeneeugenepackage test.factory.classconf; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; /** * This class/interface */ public class XClassOrderWithFactory { public static final String EXPECTED_LOG= "BTABTABTA"; public static final StringBuffer LOG= new StringBuffer(); @Factory public Object[] createInstances() throws Exception { return new Object[] { new XClassOrderTest(), new XClassOrderTest(), new XClassOrderTest() }; } public static class XClassOrderTest { @BeforeClass public void beforeClass() { LOG.append("B"); } public @Test void test() { LOG.append("T"); } public @AfterClass void afterClass() { LOG.append("A"); } } } testng-6.9.12/src/test/java/test/factory/classconf/XClassOrderWithFactoryTest.java0000644000175000017500000000123512732165123027572 0ustar eugeneeugenepackage test.factory.classconf; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; /** * This class/interface */ public class XClassOrderWithFactoryTest { @Test public void testBeforeAfterClassInvocationsWithFactory() { TestNG testng= new TestNG(); testng.setTestClasses(new Class[] {XClassOrderWithFactory.class}); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.setVerbose(0); testng.run(); Assert.assertEquals(XClassOrderWithFactory.LOG.toString(), XClassOrderWithFactory.EXPECTED_LOG); } } testng-6.9.12/src/test/java/test/factory/FactoryWithDataProvider.java0000644000175000017500000000126312732165123025153 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import java.util.ArrayList; import java.util.List; public class FactoryWithDataProvider { @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { new int[] { 3, 5 } }, new Object[] { new int [] { 7, 9 } }, }; } @Factory(dataProvider = "dp") public Object[] factory(int[] array) { List result = new ArrayList<>(); for (int n : array) { result.add(new OddTest(n)); } return result.toArray(); } private static void ppp(String s) { System.out.println("[FactoryWithDataProvider] " + s); } } testng-6.9.12/src/test/java/test/factory/DPClass.java0000644000175000017500000000035512732165123021675 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.DataProvider; public class DPClass { @DataProvider static public Object[][] dp() { return new Object[][] { new Object[] { 43 }, new Object[] { 44 }, }; } } testng-6.9.12/src/test/java/test/factory/FactoryTest2.java0000644000175000017500000000142612732165123022735 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; import java.util.HashMap; import java.util.Map; /** * This class * * @author cbeust */ public class FactoryTest2 { private static Map m_numbers = new HashMap<>(); private int m_number; public FactoryTest2() { throw new RuntimeException("Shouldn't be invoked"); } public static Map getNumbers() { return m_numbers; } public FactoryTest2(int n) { m_number = n; } @Test(groups = { "first" }) public void testInt() { Integer n = m_number; m_numbers.put(n, n); } @Override public String toString() { return "[FactoryTest2 " + m_number + "]"; } private static void ppp(String s) { System.out.println("[FactoryTest2] " + s); } } testng-6.9.12/src/test/java/test/factory/FactoryInterleavingSampleA.java0000644000175000017500000000126212732165123025624 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FactoryInterleavingSampleA { public int m_n; public FactoryInterleavingSampleA(int n) { m_n = n; } private void log(Integer s) { FactoryInterleavingTest.LOG.add(m_n * 10 + s); // System.out.println(" Instance " + m_n + " " + s); } @Override public String toString() { return "[A n:" + m_n + "]"; } @BeforeClass public void bc() { log(0); } @AfterClass public void ac() { log(3); } @Test public void f1() { log(1); } @Test public void f2() { log(2); } } testng-6.9.12/src/test/java/test/factory/BadFactoryMethodReturnTypeSample.java0000644000175000017500000000043612732165123026767 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; public class BadFactoryMethodReturnTypeSample { @Factory private Object createInstances() { return new Object[] { new BaseFactory(42), new BaseFactory(43) }; } } testng-6.9.12/src/test/java/test/factory/FactoryIntegrationTest.java0000644000175000017500000000335212732165123025057 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.annotations.Test; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; public class FactoryIntegrationTest extends SimpleBaseTest { @Test(description = "https://github.com/cbeust/testng/issues/876") public void testExceptionWithNonStaticFactoryMethod() { TestNG tng = create(GitHub876Sample.class); try { tng.run(); failBecauseExceptionWasNotThrown(TestNGException.class); } catch (TestNGException e) { assertThat(e).hasMessage("\nCan't invoke public java.lang.Object[] test.factory.GitHub876Sample.createInstances(): either make it static or add a no-args constructor to your class"); } } @Test public void testNonPublicFactoryMethodShouldWork() { TestNG tng = create(NonPublicFactoryMethodSample.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 2); } @Test public void testExceptionWithBadFactoryMethodReturnType() { TestNG tng = create(BadFactoryMethodReturnTypeSample.class); try { tng.run(); failBecauseExceptionWasNotThrown(TestNGException.class); } catch (TestNGException e) { assertThat(e).hasMessage("\ntest.factory.BadFactoryMethodReturnTypeSample.createInstances MUST return [ java.lang.Object[] or org.testng.IInstanceInfo[] ] but returns java.lang.Object"); } } } testng-6.9.12/src/test/java/test/factory/OddTest.java0000644000175000017500000000051612732165123021751 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.annotations.Test; public class OddTest { private int m_n; public OddTest(int n) { m_n = n; } @Test public void verify() { Assert.assertTrue(m_n % 2 != 0); } private static void ppp(String s) { System.out.println("[OddTest] " + s); } } testng-6.9.12/src/test/java/test/factory/NestedFactoryTest.java0000644000175000017500000000221012732165123024006 0ustar eugeneeugenepackage test.factory; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class NestedFactoryTest { private int m_capacity = 2; private float m_loadFactor = 0.4f; public class NestedFactory { @Factory public Object[] createInstances() { return new NestedFactoryTest[] { new NestedFactoryTest(1, 0.1f), new NestedFactoryTest(10, 0.5f), }; } } private static int m_instanceCount = 0; public NestedFactoryTest() { m_instanceCount++; } public NestedFactoryTest(int capacity, float loadFactor) { m_instanceCount++; this.m_capacity=capacity; this.m_loadFactor=loadFactor; } @Test public void verify() { // Should have three instances: the default one created by TestNG // and two created by the factory assertEquals(m_instanceCount, 3); assertTrue((m_capacity == 1 && m_loadFactor == 0.1f) || m_capacity == 10 && m_loadFactor == 0.5f); } private static void ppp(String s) { System.out.println("[NestedFactoryTest] " + s); } } testng-6.9.12/src/test/java/test/factory/DisabledFactoryTest.java0000644000175000017500000000113212732165123024275 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class DisabledFactoryTest extends SimpleBaseTest { @Test public void disabledFactoryShouldNotRun() { TestNG tng = create(DisabledFactorySampleTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 0); Assert.assertEquals(tla.getSkippedTests().size(), 0); Assert.assertEquals(tla.getFailedTests().size(), 0); } } testng-6.9.12/src/test/java/test/factory/NestedStaticFactoryTest.java0000644000175000017500000000227712732165123025173 0ustar eugeneeugenepackage test.factory; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class NestedStaticFactoryTest { private int m_capacity = 2; private float m_loadFactor = 0.4f; static public class NestedStaticFactory { @Factory public Object[] createInstances() { return new NestedStaticFactoryTest[] { new NestedStaticFactoryTest(1, 0.1f), new NestedStaticFactoryTest(10, 0.5f), }; } } private static int m_instanceCount = 0; public NestedStaticFactoryTest() { m_instanceCount++; } public NestedStaticFactoryTest(int capacity, float loadFactor) { m_instanceCount++; this.m_capacity=capacity; this.m_loadFactor=loadFactor; } @Test public void verify() { // Should have three instances: the default one created by TestNG // and two created by the factory assertEquals(m_instanceCount, 2); assertTrue((m_capacity == 1 && m_loadFactor == 0.1f) || m_capacity == 10 && m_loadFactor == 0.5f); } private static void ppp(String s) { System.out.println("[NestedStaticFactoryTest] " + s); } } testng-6.9.12/src/test/java/test/factory/FactoryWithDataProviderTest.java0000644000175000017500000000127412732165123026015 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; public class FactoryWithDataProviderTest { /** * Verify that a factory can receive a data provider */ @Test public void verifyDataProvider() { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { FactoryWithDataProvider.class }); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 4); } private static void ppp(String s) { System.out.println("[FactoryWithDataProviderTest] " + s); } } testng-6.9.12/src/test/java/test/factory/FactoryTest.java0000644000175000017500000000124312732165123022650 0ustar eugeneeugenepackage test.factory; import static org.testng.Assert.assertFalse; import org.testng.Assert; import org.testng.annotations.AfterSuite; import org.testng.annotations.Factory; import org.testng.annotations.Parameters; public class FactoryTest { static boolean m_invoked = false; @Parameters({ "factory-param" }) @Factory public Object[] createObjects(String param) { Assert.assertEquals(param, "FactoryParam"); assertFalse(m_invoked, "Should only be invoked once"); m_invoked = true; return new Object[] { new FactoryTest2(42), new FactoryTest2(43) }; } @AfterSuite public void afterSuite() { m_invoked = false; } }testng-6.9.12/src/test/java/test/factory/FactoryDataProviderStaticSampleErrorTest.java0000644000175000017500000000066012732165123030503 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; public class FactoryDataProviderStaticSampleErrorTest extends BaseFactory { @Factory(dataProvider = "dp") public FactoryDataProviderStaticSampleErrorTest(int n) { super(n); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 41 }, new Object[] { 42 }, }; } } testng-6.9.12/src/test/java/test/factory/EmptyFactoryDataProviderTest.java0000644000175000017500000000145712732165123026203 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.ITestNGListener; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; public class EmptyFactoryDataProviderTest { @Test public void test() { TestNG testng = new TestNG(false); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener((ITestNGListener) tla); // Used to check the warning message testng.setVerbose(2); testng.setTestClasses(new Class[]{ArrayEmptyFactorySample.class, IteratorEmptyFactorySample.class}); testng.run(); Assert.assertTrue(tla.getFailedTests().isEmpty()); Assert.assertTrue(tla.getSkippedTests().isEmpty()); Assert.assertTrue(tla.getPassedTests().isEmpty()); } } testng-6.9.12/src/test/java/test/factory/NonPublicFactoryMethodSample.java0000644000175000017500000000043412732165123026126 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; public class NonPublicFactoryMethodSample { @Factory private Object[] createInstances() { return new Object[] { new BaseFactory(42), new BaseFactory(43) }; } } testng-6.9.12/src/test/java/test/factory/FactoryBaseSampleTest.java0000644000175000017500000000020112732165123024576 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; public class FactoryBaseSampleTest { @Test public void f() {} } testng-6.9.12/src/test/java/test/factory/FactoryInSuperClassTest.java0000644000175000017500000000077212732165123025152 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class FactoryInSuperClassTest extends SimpleBaseTest { @Test public void factoryInSuperClassShouldWork() { TestNG tng = create(FactoryChild.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); } } testng-6.9.12/src/test/java/test/factory/FactoryInSeparateClass.java0000644000175000017500000000201212732165123024745 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.BeforeTest; import org.testng.annotations.Factory; import org.testng.annotations.Test; /** * this is like the FactoryTest, except it creates test instances in a separate * class from the test class */ public class FactoryInSeparateClass { static private boolean m_wasRun = false; static private int m_checkSum = 0; public static void addToSum(int i) { m_checkSum += i; } @BeforeTest public void beforeTest() { m_wasRun = false; m_checkSum = 0; } @Factory public Object[] createObjects() { return new Object[] { new MyTest(1), new MyTest(2), new MyTest(3), }; } @Test(groups = "testMethodOnFactoryClass", dependsOnGroups={"MyTest"}) public void checkSum() { m_wasRun = true; assert (m_checkSum == 6) : "Test instances made by factory did not invoke their test methods correctly. expected 6 but got " + m_checkSum; } public static boolean wasRun() { return m_wasRun; } } testng-6.9.12/src/test/java/test/factory/DisabledFactorySampleTest.java0000644000175000017500000000032312732165123025440 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; public class DisabledFactorySampleTest { @Factory(enabled = false) public Object[] factory() { return new Object[] { new MyTest() }; } } testng-6.9.12/src/test/java/test/factory/FactoryFailureTest.java0000644000175000017500000000066412732165123024166 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class FactoryFailureTest extends SimpleBaseTest { @Test public void factoryThrowingShouldNotRunTests() { TestNG tng = create(FactoryFailureSampleTest.class); try { tng.run(); Assert.fail(); } catch(Exception ex) { // success } } } testng-6.9.12/src/test/java/test/factory/MyTest.java0000644000175000017500000000140712732165123021630 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; public class MyTest { private int i; // in this test, our default constructor sets s to a value that will cause a failure // the valid test instances should come from the factory public MyTest() { i = 0; } public MyTest(int i) { this.i = i; } @Test(groups = "MyTest") public void testMethod() { FactoryInSeparateClass.addToSum(i); // assert i > 0 : "MyTest was not constructed with correct params"; assert (i != 0) : "My test was not created by the factory"; } @Test(dependsOnGroups = "testMethodOnFactoryClass") public void verifyThatTestMethodOnFactoryClassWasRun() { assert FactoryInSeparateClass.wasRun() : "Test method on factory class wasn't run"; } }testng-6.9.12/src/test/java/test/factory/Factory2Test.java0000644000175000017500000000070112732165123022730 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Factory; /** * Factory to test that setUp methods are correctly interleaved even * when we use similar instances of a same test class. * * @author cbeust */ public class Factory2Test { @Factory() public Object[] createObjects() { return new Object[] { new Sample2(), new Sample2() }; } private static void ppp(String s) { System.out.println("[FactoryTest] " + s); } }testng-6.9.12/src/test/java/test/factory/ArrayEmptyFactorySample.java0000644000175000017500000000074312732165123025174 0ustar eugeneeugenepackage test.factory; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class ArrayEmptyFactorySample { @DataProvider(name = "values") public static Object[][] values() { return new Object[][]{}; } @Factory(dataProvider = "values") public ArrayEmptyFactorySample(int value) { } @Test public void test() { Assert.fail(); } } testng-6.9.12/src/test/java/test/factory/VerifyFactoryWithInstanceInfoTest.java0000644000175000017500000000076112732165123027176 0ustar eugeneeugenepackage test.factory; import org.testng.annotations.Test; import java.util.Map; public class VerifyFactoryWithInstanceInfoTest { @Test(dependsOnGroups = { "first" } ) public void mainCheck() { Map numbers = FactoryWithInstanceInfoTest2.getNumbers(); assert null != numbers.get(42) : "Didn't find 42"; assert null != numbers.get(43) : "Didn't find 43"; assert 2 == numbers.size() : "Expected 2 numbers, found " + (numbers.size()); } } testng-6.9.12/src/test/java/test/interleavedorder/0000755000175000017500000000000012732165123021425 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/interleavedorder/BaseTestClass.java0000644000175000017500000000065512732165123024776 0ustar eugeneeugenepackage test.interleavedorder; import org.testng.annotations.Test; public class BaseTestClass { @Test public void testOne() { ppp("test1"); InterleavedInvocationTest.LOG.add("test1"); } @Test public void testTwo() { ppp("test2"); InterleavedInvocationTest.LOG.add("test2"); } private void ppp(String s) { if (false) { System.out.println(getClass().toString() + " " + s); } } } testng-6.9.12/src/test/java/test/interleavedorder/TestChild1.java0000644000175000017500000000111612732165123024233 0ustar eugeneeugenepackage test.interleavedorder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; public class TestChild1 extends BaseTestClass { @BeforeClass public void beforeTestChildOneClass() { ppp("beforeTestChild1Class"); InterleavedInvocationTest.LOG.add("beforeTestChild1Class"); } @AfterClass public void afterTestChildOneClass() { ppp("afterTestChild1Class"); InterleavedInvocationTest.LOG.add("afterTestChild1Class"); } private void ppp(String s) { if (false) { System.out.println("[TestChild1] " + s); } } } testng-6.9.12/src/test/java/test/interleavedorder/testng-order.xml0000644000175000017500000000044712732165123024571 0ustar eugeneeugene testng-6.9.12/src/test/java/test/interleavedorder/TestChild2.java0000644000175000017500000000111712732165123024235 0ustar eugeneeugenepackage test.interleavedorder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; public class TestChild2 extends BaseTestClass { @BeforeClass public void beforeTestChildTwoClass() { ppp("beforeTestChild2Class"); InterleavedInvocationTest.LOG.add("beforeTestChild2Class"); } @AfterClass public void afterTestChildTwoClass() { ppp("afterTestChild2Class"); InterleavedInvocationTest.LOG.add("afterTestChild2Class"); } private void ppp(String s) { if (false) { System.out.println("[TestChild2] " + s); } } } testng-6.9.12/src/test/java/test/interleavedorder/InterleavedInvocationTest.java0000644000175000017500000000322712732165123027430 0ustar eugeneeugenepackage test.interleavedorder; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import test.BaseTest; import testhelper.OutputDirectoryPatch; import java.util.ArrayList; import java.util.List; public class InterleavedInvocationTest extends BaseTest { public static List LOG = new ArrayList<>(); @BeforeTest public void beforeTest() { LOG = new ArrayList<>(); } private void verifyInvocation(int number, List log, int index) { Assert.assertEquals(log.get(index), "beforeTestChild" + number + "Class"); Assert.assertTrue(("test1".equals(log.get(index + 1)) && "test2".equals(LOG.get(index + 2))) || ("test2".equals(LOG.get(index + 1)) && "test1".equals(LOG.get(index + 2))), "test methods were not invoked correctly"); Assert.assertEquals(log.get(index + 3), "afterTestChild" + number + "Class"); } @Test public void invocationOrder() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = new TestNG(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(new Class[] { TestChild1.class, TestChild2.class }); testng.addListener(tla); testng.setVerbose(0); testng.run(); Assert.assertEquals(LOG.size(), 8, LOG.toString()); int number1 = "beforeTestChild1Class".equals(LOG.get(0)) ? 1 : 2; int number2 = number1 == 1 ? 2 : 1; verifyInvocation(number1, LOG, 0); verifyInvocation(number2, LOG, 4); } public static void ppp(String s) { System.out.println("[InterleavedTest] " + s); } } testng-6.9.12/src/test/java/test/assertion/0000755000175000017500000000000012732165123020076 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/assertion/SoftAssertTest.java0000644000175000017500000000266112732165123023703 0ustar eugeneeugenepackage test.assertion; import org.testng.Assert; import org.testng.annotations.Test; import org.testng.asserts.IAssert; import org.testng.asserts.SoftAssert; import java.util.ArrayList; import java.util.Collection; public class SoftAssertTest { @Test public void testOnSucceedAndFailureCalled() throws Exception { final Collection succeed = new ArrayList<>(); final Collection failures = new ArrayList<>(); final SoftAssert sa = new SoftAssert() { @Override public void onAssertSuccess(IAssert assertCommand) { succeed.add(assertCommand); } @Override public void onAssertFailure(IAssert assertCommand, AssertionError ex) { failures.add(assertCommand); } }; sa.assertTrue(true); sa.assertTrue(false); Assert.assertEquals(succeed.size(), 1, succeed.toString()); Assert.assertEquals(failures.size(), 1, failures.toString()); } @Test public void testAssertAllCount() throws Exception { String message = "My message"; SoftAssert sa = new SoftAssert(); sa.assertTrue(true); sa.assertTrue(false, message); try { sa.assertAll(); Assert.fail("Exception expected"); } catch (AssertionError e) { String[] lines = e.getMessage().split("\r?\n"); Assert.assertEquals(lines.length, 2); lines[1] = lines[1].replaceFirst(message, ""); Assert.assertFalse(lines[1].contains(message)); } } } testng-6.9.12/src/test/java/test/assertion/MyRawAssertion.java0000644000175000017500000000317012732165123023671 0ustar eugeneeugenepackage test.assertion; import org.testng.Assert; import org.testng.asserts.Assertion; import org.testng.asserts.IAssert; import java.util.ArrayList; import java.util.List; public class MyRawAssertion extends Assertion { private final List methods = new ArrayList<>(); @Override public void onAssertSuccess(IAssert assertCommand) { methods.add("onAssertSuccess"); super.onAssertSuccess(assertCommand); } @Override public void onAssertFailure(IAssert assertCommand) { methods.add("deprecated_onAssertFailure"); super.onAssertFailure(assertCommand); } @Override public void onAssertFailure(IAssert assertCommand, AssertionError ex) { methods.add("onAssertFailure"); super.onAssertFailure(assertCommand, ex); } @Override public void onBeforeAssert(IAssert assertCommand) { methods.add("onBeforeAssert"); super.onBeforeAssert(assertCommand); } @Override public void onAfterAssert(IAssert assertCommand) { methods.add("onAfterAssert"); super.onAfterAssert(assertCommand); } public List getMethods() { return methods; } public void myAssert(final String actual, final boolean expected, final String message) { doAssert(new IAssert() { @Override public String getMessage() { return message; } @Override public void doAssert() { Assert.assertNotNull(actual, message); Assert.assertTrue(expected, message); } @Override public Object getActual() { return actual; } @Override public Object getExpected() { return expected; } }); } } testng-6.9.12/src/test/java/test/assertion/AssertionTest.java0000644000175000017500000000263612732165123023557 0ustar eugeneeugenepackage test.assertion; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.asserts.LoggingAssert; import static org.assertj.core.api.Assertions.assertThat; public class AssertionTest { private LoggingAssert m_assert; private MyRawAssertion rawAssertion; @BeforeMethod public void bm() { m_assert = new LoggingAssert(); rawAssertion = new MyRawAssertion(); } @Test(expectedExceptions = AssertionError.class) public void test1() { m_assert.assertTrue(false, "new TestNG Assertion Failed"); } @Test public void test2() { rawAssertion.assertTrue(true); rawAssertion.myAssert("test", true, "Raw test"); assertThat(rawAssertion.getMethods()) .containsExactly("onBeforeAssert", "onAssertSuccess", "onAfterAssert", "onBeforeAssert", "onAssertSuccess", "onAfterAssert"); } @Test(expectedExceptions = AssertionError.class, expectedExceptionsMessageRegExp = "Raw test .*") public void test2_fails() { try { rawAssertion.assertTrue(true); rawAssertion.myAssert("test", false, "Raw test"); } catch (AssertionError error) { assertThat(rawAssertion.getMethods()) .containsExactly("onBeforeAssert", "onAssertSuccess", "onAfterAssert", "onBeforeAssert", "onAssertFailure", "deprecated_onAssertFailure", "onAfterAssert"); throw error; } } } testng-6.9.12/src/test/java/test/priority/0000755000175000017500000000000012732165123017750 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/priority/WithPrioritySampleTest.java0000644000175000017500000000031112732165123025265 0ustar eugeneeugenepackage test.priority; import org.testng.annotations.Test; public class WithPrioritySampleTest { @Test(priority = -2) public void first() {} @Test(priority = -1) public void second() {} } testng-6.9.12/src/test/java/test/priority/WithPrioritySample2Test.java0000644000175000017500000000031212732165123025350 0ustar eugeneeugenepackage test.priority; import org.testng.annotations.Test; public class WithPrioritySample2Test { @Test(priority = -2) public void first() {} @Test(priority = -3) public void second() {} } testng-6.9.12/src/test/java/test/priority/WithoutPrioritySampleTest.java0000644000175000017500000000025512732165123026024 0ustar eugeneeugenepackage test.priority; import org.testng.annotations.Test; public class WithoutPrioritySampleTest { @Test public void first() {} @Test public void second() {} } testng-6.9.12/src/test/java/test/priority/PriorityTest.java0000644000175000017500000000332612732165123023300 0ustar eugeneeugenepackage test.priority; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.InvokedMethodNameListener; import test.SimpleBaseTest; public class PriorityTest extends SimpleBaseTest { private void runTest(Class cls, boolean parallel, String... methods) { TestNG tng = create(cls); InvokedMethodNameListener listener = new InvokedMethodNameListener(); tng.addListener(listener); if (parallel) { tng.setParallel(XmlSuite.ParallelMode.METHODS); } tng.run(); Assert.assertEquals(listener.getInvokedMethodNames().toArray(), methods); } @Test(enabled = false, description = "Make sure priorities work in parallel mode") public void priorityInParallel1() { runTest(WithPrioritySampleTest.class, true /* parallel */, "first", "second"); } @Test(enabled = false, description = "Make sure priorities work in parallel mode") public void priorityInParallel2() { runTest(WithPrioritySample2Test.class, true /* parallel */, "second", "first"); } @Test(description = "Make sure priorities work in sequential mode") public void priorityInSequential1() { runTest(WithPrioritySampleTest.class, false /* sequential */, "first", "second"); } @Test(description = "Make sure priorities work in sequential mode") public void priorityInSequential2() { runTest(WithPrioritySample2Test.class, false /* sequential */, "second", "first"); } @Test(description = "GITHUB #793: Test suite with tests using dependency and priority has wrong behavior") public void priorityWithDependsOnMethods() { runTest(WithPriorityAndDependsMethodsSample.class, false /* sequential */, "first", "second", "third"); } } testng-6.9.12/src/test/java/test/priority/WithPriorityAndDependsMethodsSample.java0000644000175000017500000000040512732165123027703 0ustar eugeneeugenepackage test.priority; import org.testng.annotations.Test; public class WithPriorityAndDependsMethodsSample { @Test public void first() {} @Test(dependsOnMethods = {"first"}) public void second() {} @Test(priority = 1) public void third() {} } testng-6.9.12/src/test/java/test/StaticTest.java0000644000175000017500000000036012732165123021020 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; /** * This used to create a StackOverflowError. */ public class StaticTest { @Test public void test() { } @Test public static class InnerStaticClass extends StaticTest { } }testng-6.9.12/src/test/java/test/pkg2/0000755000175000017500000000000012732165123016732 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/pkg2/Test2.java0000644000175000017500000000027712732165123020604 0ustar eugeneeugenepackage test.pkg2; import test.pkg.PackageTest; public class Test2 { private Test2(float afloat) { PackageTest.NON_TEST_CONSTRUCTOR= true; } public void nonTestMethod() { } } testng-6.9.12/src/test/java/test/pkg2/Test1.java0000644000175000017500000000024312732165123020574 0ustar eugeneeugenepackage test.pkg2; import org.testng.annotations.Test; public class Test1 { @Test public void method11() { } @Test public void method12() { } } testng-6.9.12/src/test/java/test/pkg2/Test3.java0000644000175000017500000000017312732165123020600 0ustar eugeneeugenepackage test.pkg2; import org.testng.annotations.Test; public class Test3 { @Test public void method31() { } } testng-6.9.12/src/test/java/test/morten/0000755000175000017500000000000012732165123017373 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/morten/SampleTest.java0000644000175000017500000000152212732165123022317 0ustar eugeneeugenepackage test.morten; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class SampleTest { private int capacity = 10; private float loadFactor = 0.3f; public class SampleTestTestFactory { public SampleTestTestFactory() {} // CTR necessary ? @Factory public Object[] createInstances() { return new SampleTest[] { new SampleTest(1, 0.1f), new SampleTest(10, 0.5f), }; } } public SampleTest() { } public SampleTest(int capacity, float loadFactor) { System.out.println("CREATING TEST WITH " + capacity); this.capacity=capacity; this.loadFactor=loadFactor; } @Test public void testPut() { //FIXME: This test does nothing //HashMap hashTable = new HashMap(capacity, loadFactor); // ... } } testng-6.9.12/src/test/java/test/morten/SampleTestFactory.java0000644000175000017500000000044312732165123023650 0ustar eugeneeugenepackage test.morten; import org.testng.annotations.Factory; public class SampleTestFactory { public SampleTestFactory() {} // CTR necessary ? @Factory public Object[] createInstances() { return new SampleTest[] { new SampleTest(1, 0.1f), new SampleTest(10, 0.5f), }; } } testng-6.9.12/src/test/java/test/testng173/0000755000175000017500000000000012732165123017626 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng173/TestNG173Test.java0000644000175000017500000000327712732165123022741 0ustar eugeneeugenepackage test.testng173; import java.util.Arrays; import org.testng.Assert; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; public class TestNG173Test extends SimpleBaseTest { @Test public void orderShouldBePreservedInMethodsWithSameNameAndInDifferentClasses() { TestNG tng = create(); XmlSuite s = createXmlSuite("PreserveOrder"); XmlTest t = new XmlTest(s); t.getXmlClasses().add(new XmlClass("test.testng173.ClassA")); t.getXmlClasses().add(new XmlClass("test.testng173.ClassB")); t.setPreserveOrder("true"); tng.setXmlSuites(Arrays.asList(s)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); // bug //verifyPassedTests(tla, "test1", "test2", "testX", "test1", "test2"); // Proposed fix verifyPassedTests(tla, "test1", "test2", "testX", "test2", "test1"); } @Test public void orderShouldBePreservedInMethodsWithSameNameAndInDifferentClassesAndDifferentPackage() { TestNG tng = create(); XmlSuite s = createXmlSuite("PreserveOrder"); XmlTest t = new XmlTest(s); t.getXmlClasses().add(new XmlClass("test.testng173.ClassA")); t.getXmlClasses().add(new XmlClass("test.testng173.anotherpackage.ClassC")); t.setPreserveOrder("true"); tng.setXmlSuites(Arrays.asList(s)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); // bug //verifyPassedTests(tla, "test1", "test2", "testX", "test1", "test2"); verifyPassedTests(tla, "test1", "test2", "testX", "test2", "test1"); } } testng-6.9.12/src/test/java/test/testng173/ClassA.java0000644000175000017500000000030612732165123021636 0ustar eugeneeugenepackage test.testng173; import org.testng.annotations.Test; public class ClassA { @Test public void test1() { } @Test(dependsOnMethods = "test1") public void test2() { } } testng-6.9.12/src/test/java/test/testng173/anotherpackage/0000755000175000017500000000000012732165123022602 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng173/anotherpackage/ClassC.java0000644000175000017500000000043312732165123024615 0ustar eugeneeugenepackage test.testng173.anotherpackage; import org.testng.annotations.Test; public class ClassC { @Test public void testX() { } @Test(dependsOnMethods = "testX") public void test2() { } @Test(dependsOnMethods = "test2") public void test1() { } }testng-6.9.12/src/test/java/test/testng173/ClassB.java0000644000175000017500000000040112732165123021633 0ustar eugeneeugenepackage test.testng173; import org.testng.annotations.*; public class ClassB { @Test public void testX() { } @Test(dependsOnMethods = "testX") public void test2() { } @Test(dependsOnMethods = "test2") public void test1() { } }testng-6.9.12/src/test/java/test/conffailure/0000755000175000017500000000000012732165123020364 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/conffailure/ClassWithFailedBeforeTestClassVerification.java0000644000175000017500000000144712732165123031557 0ustar eugeneeugenepackage test.conffailure; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ClassWithFailedBeforeTestClassVerification { private static boolean m_success1 = false; private static boolean m_success2 = false; // Should be run even though ClassWithFailedBeforeTestClass failed in its configuration @BeforeClass public void setUpShouldPass() { m_success1 = true; } // Should be run even though ClassWithFailedBeforeTestClass failed in its configuration @AfterClass public void tearDown() { m_success2 = true; } // Adding this method or @Configuration will never be invoked @Test public void dummy() { } static public boolean success() { return m_success1 && m_success2; } } testng-6.9.12/src/test/java/test/conffailure/ClassWithFailedBeforeSuiteVerification.java0000644000175000017500000000114412732165123030735 0ustar eugeneeugenepackage test.conffailure; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; public class ClassWithFailedBeforeSuiteVerification { private static boolean m_success1 = true; private static boolean m_success2 = true; // Should not be run because beforeSuite failed on the other class @BeforeClass public void setUp() { m_success1 = false; } // Should not be run because beforeSuite failed on the other class @AfterClass public void tearDown() { m_success2 = false; } static public boolean success() { return m_success1 && m_success2; } } testng-6.9.12/src/test/java/test/conffailure/ClassWithFailedBeforeSuite.java0000644000175000017500000000033612732165123026374 0ustar eugeneeugenepackage test.conffailure; import org.testng.annotations.BeforeSuite; public class ClassWithFailedBeforeSuite { @BeforeSuite public void setUpShouldFail() { throw new RuntimeException("Failing in setUp"); } } testng-6.9.12/src/test/java/test/conffailure/ClassWithFailedBeforeTestClass.java0000644000175000017500000000055312732165123027211 0ustar eugeneeugenepackage test.conffailure; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ClassWithFailedBeforeTestClass { @BeforeClass public void setUpShouldFail() { throw new RuntimeException("Failing in setUp"); } // Adding this method or @Configuration will never be invoked @Test public void dummy() { } } testng-6.9.12/src/test/java/test/conffailure/ConfigurationFailure.java0000644000175000017500000000303612732165123025350 0ustar eugeneeugenepackage test.conffailure; import static org.testng.Assert.assertTrue; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import testhelper.OutputDirectoryPatch; /** * Test various cases where the @Configuration methods fail * * Created on Jul 20, 2005 * @author cbeust */ public class ConfigurationFailure { @Test public void beforeTestClassFails() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = new TestNG(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(new Class[] { ClassWithFailedBeforeTestClass.class, ClassWithFailedBeforeTestClassVerification.class }); testng.addListener(tla); testng.setVerbose(0); testng.run(); assertTrue(ClassWithFailedBeforeTestClassVerification.success(), "Not all the @Configuration methods of Run2 were run"); } @Test public void beforeTestSuiteFails() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = new TestNG(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(new Class[] { ClassWithFailedBeforeSuite.class, ClassWithFailedBeforeSuiteVerification.class }); testng.addListener(tla); testng.setVerbose(0); testng.run(); assertTrue(ClassWithFailedBeforeSuiteVerification.success(), "No @Configuration methods should have run"); } private static void ppp(String s) { System.out.println("[AlwaysRunTest] " + s); } } testng-6.9.12/src/test/java/test/reports/0000755000175000017500000000000012732165123017565 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/reports/ReporterLogTest.java0000644000175000017500000000277712732165123023551 0ustar eugeneeugenepackage test.reports; import org.testng.Assert; import org.testng.Reporter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.List; /** * Make sure that Reporter.log() in listeners don't get discarded. */ public class ReporterLogTest extends SimpleBaseTest { @Test public void shouldLogFromListenerOnSuccess() { TestNG tng = create(ReporterLogSuccessSampleTest.class); tng.run(); List output = Reporter.getOutput(); //System.out.println(output); Assert.assertTrue(contains(output, "Listener: onTestSuccess"), "Reporter should log from onTestSuccess listener"); } @Test public void shouldLogFromListenerOnSkip() { TestNG tng = create(ReporterLogSkippedSampleTest.class); tng.run(); List output = Reporter.getOutput(); //System.out.println(output); Assert.assertTrue(contains(output, "Listener: onTestSkipped"), "Reporter should log from onTestSkipped listener"); } @Test public void shouldLogFromListenerOnFailure() { TestNG tng = create(ReporterLogFailureSampleTest.class); tng.run(); List output = Reporter.getOutput(); //System.out.println(output); Assert.assertTrue(contains(output, "Listener: onTestFailure"), "Reporter should log from onTestFailure listener"); } private boolean contains(List output, String logMessage) { for (String s : output) { if (s.contains(logMessage)) { return true; } } return false; } } testng-6.9.12/src/test/java/test/reports/ReportTest.java0000644000175000017500000001017612732165123022550 0ustar eugeneeugenepackage test.reports; import org.testng.Assert; import org.testng.ITestListener; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.TestHelper; import java.io.File; import java.util.Arrays; import java.util.List; public class ReportTest { @Test public void verifyIndex() { File outputDir = TestHelper.createRandomDirectory(); String suiteName = "VerifyIndexSuite"; String testName = "TmpTest"; XmlSuite suite = TestHelper.createSuite(test.simple.SimpleTest.class, suiteName, testName); TestNG tng = TestHelper.createTestNG(suite, outputDir.getAbsolutePath()); File f = getHtmlReportFile(outputDir, suiteName, testName); tng.run(); Assert.assertTrue(f.exists()); } @Test public void directoryShouldBeSuiteName() { File outputDirectory = TestHelper.createRandomDirectory(); XmlSuite xmlSuite = new XmlSuite(); String suiteName = "ReportTestSuite1"; xmlSuite.setName(suiteName); XmlTest xmlTest = new XmlTest(xmlSuite); String testName = "Test1"; xmlTest.setName(testName); XmlTest xmlTest2 = new XmlTest(xmlSuite); String testName2 = "Test2"; xmlTest2.setName(testName2); TestNG testng = new TestNG(); testng.setVerbose(0); testng.setOutputDirectory(outputDirectory.getAbsolutePath()); testng.setXmlSuites(Arrays.asList(xmlSuite)); File f = getHtmlReportFile(outputDirectory, suiteName, testName); File f2 = getHtmlReportFile(outputDirectory, suiteName, testName2); testng.run(); Assert.assertTrue(f.exists(), "Expected to find file:" + f); Assert.assertTrue(f2.exists(), "Expected to find file:" + f2); } @Test public void oneDirectoryPerSuite() { File outputDirectory = TestHelper.createRandomDirectory(); String testName = "TmpTest"; String suiteNameA = "ReportSuiteA"; XmlSuite xmlSuiteA = TestHelper.createSuite(test.reports.A.class, suiteNameA, testName); String suiteNameB = "ReportSuiteB"; XmlSuite xmlSuiteB = TestHelper.createSuite(test.reports.B.class, suiteNameB, testName); TestNG testng = TestHelper.createTestNG(); testng.setOutputDirectory(outputDirectory.getAbsolutePath()); testng.setXmlSuites(Arrays.asList(xmlSuiteA, xmlSuiteB)); File f1 = getHtmlReportFile(outputDirectory, suiteNameA, testName); File f2 = getHtmlReportFile(outputDirectory, suiteNameB, testName); testng.run(); Assert.assertTrue(f1.exists()); Assert.assertTrue(f2.exists()); } private static File getHtmlReportFile(File outputDir, String suiteName, String testName) { File f = new File(outputDir.getAbsolutePath() + File.separatorChar + suiteName + File.separatorChar + testName + ".html"); if (f.exists()) { f.delete(); } return f; } @Test public void shouldHonorSuiteName() { TestNG testng = TestHelper.createTestNG(); testng.setTestClasses(new Class[] { A.class, B.class }); String outputDir = testng.getOutputDirectory(); String dirA = outputDir + File.separatorChar + "SuiteA-JDK5"; File fileA = new File(dirA); String dirB = outputDir + File.separatorChar + "SuiteB-JDK5"; File fileB = new File(dirB); Assert.assertFalse(fileA.exists()); Assert.assertFalse(fileB.exists()); testng.run(); Assert.assertTrue(fileA.exists(), fileA + " wasn't created"); Assert.assertTrue(fileB.exists(), fileB + " wasn't created"); } static boolean m_success = false; @Test public void reportLogShouldBeAvailableEvenWithTimeOut() { m_success = false; TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { ReporterSampleTest.class }); ITestListener listener = new TestListenerAdapter() { @Override public void onTestSuccess(ITestResult tr) { super.onTestSuccess(tr); List output = Reporter.getOutput(tr); m_success = output != null && output.size() > 0; } }; tng.addListener(listener); tng.run(); Assert.assertTrue(m_success); } } testng-6.9.12/src/test/java/test/reports/B.java0000644000175000017500000000020712732165123020610 0ustar eugeneeugenepackage test.reports; import org.testng.annotations.Test; @Test(suiteName = "SuiteB-JDK5") public class B { public void f() {} } testng-6.9.12/src/test/java/test/reports/ReporterLogSkippedSampleTest.java0000644000175000017500000000070712732165123026222 0ustar eugeneeugenepackage test.reports; import org.testng.Reporter; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(ReporterLogListener.class) public class ReporterLogSkippedSampleTest { @BeforeMethod public void beforeMethod() { throw new RuntimeException("Intentionally failed"); } @Test public void test_onSkip() { Reporter.log("Log from test_onSkip"); } } testng-6.9.12/src/test/java/test/reports/A.java0000644000175000017500000000024012732165123020604 0ustar eugeneeugenepackage test.reports; import org.testng.annotations.Test; @Test(suiteName = "SuiteA-JDK5", testName = "TestA-JDK5") public class A { public void f() {} } testng-6.9.12/src/test/java/test/reports/ReporterLogListener.java0000644000175000017500000000122712732165123024404 0ustar eugeneeugenepackage test.reports; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.TestListenerAdapter; /** * Listener that calls Reporter.log */ public class ReporterLogListener extends TestListenerAdapter { @Override public void onTestSuccess(ITestResult result) { Reporter.log("Listener: onTestSuccess"); super.onTestSuccess(result); } @Override public void onTestFailure(ITestResult result) { Reporter.log("Listener: onTestFailure"); super.onTestFailure(result); } @Override public void onTestSkipped(ITestResult result) { Reporter.log("Listener: onTestSkipped"); super.onTestSkipped(result); } } testng-6.9.12/src/test/java/test/reports/FailedSampleTest.java0000644000175000017500000000027512732165123023622 0ustar eugeneeugenepackage test.reports; import org.testng.annotations.Test; public class FailedSampleTest { @Test public void failed() { throw new RuntimeException("Failing intentionally"); } } testng-6.9.12/src/test/java/test/reports/EmailableReportDriver.java0000644000175000017500000000172612732165123024661 0ustar eugeneeugenepackage test.reports; import org.testng.Assert; import org.testng.Reporter; import org.testng.annotations.Test; /** * Generates multiple permutations of TestNG output to see how things look in EmailableReporter. * * @author Paul Mendelson * @since 5.3 * @version $Revision$ */ @Test public class EmailableReportDriver { public void doFailureSansLog() { Assert.fail("show failure in report"); } public void doFailureNested() { Assert.fail("show failure in report",new Exception("Real cuase")); } public void doFailureWithLog() { Reporter.log("Preparing to fail"); Assert.fail("show failure in report"); } @Test(expectedExceptions={NumberFormatException.class}) public void doExpectedExceptionSansLog() { Reporter.log("step 1"); Reporter.log("step 2"); Integer.parseInt("BAD TEXT"); } @Test(expectedExceptions={NumberFormatException.class}) public void doExpectedExceptionWithLog() { Integer.parseInt("BAD TEXT"); } } testng-6.9.12/src/test/java/test/reports/ReporterLogFailureSampleTest.java0000644000175000017500000000055112732165123026207 0ustar eugeneeugenepackage test.reports; import org.testng.Reporter; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(ReporterLogListener.class) public class ReporterLogFailureSampleTest { @Test public void test_onFailure() { Reporter.log("Log from test_onFailure"); throw new RuntimeException("Intentionally failed"); } } testng-6.9.12/src/test/java/test/reports/ReporterSampleTest.java0000644000175000017500000000126112732165123024234 0ustar eugeneeugenepackage test.reports; import org.testng.Reporter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Regression test: if a timeOut is provided, getReporter(testResult) returns * null. * * Created on Sep 21, 2006 * @author Cedric Beust */ public class ReporterSampleTest { @DataProvider(name = "dp") public Object[][] createParameters() { return new Object[][] { new Object[] { "param1"}, new Object[] {"param2"} }; } @Test(dataProvider = "dp", timeOut = 10000) public void report(String p) { Reporter.log("IN THE REPORTER: " + p); } } testng-6.9.12/src/test/java/test/reports/ReporterLogSuccessSampleTest.java0000644000175000017500000000046012732165123026227 0ustar eugeneeugenepackage test.reports; import org.testng.Reporter; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(ReporterLogListener.class) public class ReporterLogSuccessSampleTest { @Test public void test_onSuccess() { Reporter.log("Log from test_onSuccess"); } }testng-6.9.12/src/test/java/test/reports/ReporterTest.java0000644000175000017500000000111712732165123023072 0ustar eugeneeugenepackage test.reports; import org.testng.*; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import java.util.Set; @Listeners(ReporterTest.class) public class ReporterTest extends TestListenerAdapter { @Override public void onStart (ITestContext testContext) { Reporter.log ("foo"); } @Test public void testMethod() { Reporter.log ("bar"); // This line is required. Else the log that was triggered from onStart() would never be // persisted at all. Assert.assertTrue (Reporter.getOutput ().size () == 2); } } testng-6.9.12/src/test/java/test/reports/FailedReporterTest.java0000644000175000017500000000372112732165123024202 0ustar eugeneeugenepackage test.reports; import javax.xml.parsers.ParserConfigurationException; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.reporters.FailedReporter; import org.testng.xml.Parser; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import org.xml.sax.SAXException; import test.SimpleBaseTest; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.Collection; public class FailedReporterTest extends SimpleBaseTest { private static final String XML = "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "" + "" + ""; @Test public void failedFile() throws ParserConfigurationException, SAXException, IOException { TestNG tng = new TestNG(); tng.setVerbose(0); Collection suites = new Parser(new ByteArrayInputStream(XML.getBytes())).parse(); tng.setXmlSuites(Lists.newArrayList(suites)); TestListenerAdapter tla = new TestListenerAdapter(); File f = new File("/tmp"); tng.setOutputDirectory(f.getAbsolutePath()); tng.addListener(tla); tng.run(); Collection failedSuites = new Parser(new File(f, FailedReporter.TESTNG_FAILED_XML).getAbsolutePath()).parse(); XmlSuite failedSuite = failedSuites.iterator().next(); Assert.assertEquals("42", failedSuite.getParameter("n")); XmlTest test = failedSuite.getTests().get(0); Assert.assertEquals("43", test.getParameter("o")); XmlClass c = test.getClasses().get(0); Assert.assertEquals("44", c.getAllParameters().get("p")); } } testng-6.9.12/src/test/java/test/Test1.java0000644000175000017500000000706712732165123017744 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; public class Test1 extends BaseTest { /** * This constructor is package protected on purpose, to test that * TestNG can still instantiate the class. */ Test1() {} @Test(groups = { "current" }) public void includedGroups() { addClass("test.sample.Sample1"); assert 1 == getTest().getXmlClasses().size(); addIncludedGroup("odd"); run(); String[] passed = { "method1", "method3", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void groupsOfGroupsSimple() { addClass("test.sample.Sample1"); assert 1 == getTest().getXmlClasses().size(); // should match all methods belonging to group "odd" and "even" addIncludedGroup("evenodd"); List l = new ArrayList<>(); l.add("even"); l.add("odd"); addMetaGroup("evenodd", l); run(); String passed[] = { "method1", "method2", "method3", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void groupsOfGroupsWithIndirections() { addClass("test.sample.Sample1"); addIncludedGroup("all"); List l = new ArrayList<>(); l.add("methods"); l.add("broken"); addMetaGroup("all", l); l = new ArrayList<>(); l.add("odd"); l.add("even"); addMetaGroup("methods", l); addMetaGroup("broken", "broken"); run(); String[] passed = { "method1", "method2", "method3", "broken" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void groupsOfGroupsWithCycle() { addClass("test.sample.Sample1"); addIncludedGroup("all"); addMetaGroup("all", "all2"); addMetaGroup("all2", "methods"); addMetaGroup("methods", "all"); run(); String[] passed = { }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test // (groups = { "one" }) public void excludedGroups() { addClass("test.sample.Sample1"); addExcludedGroup("odd"); run(); String passed[] = { "method2", "broken", "throwExpectedException1ShouldPass", "throwExpectedException2ShouldPass" }; String[] failed = { "throwExceptionShouldFail", "verifyLastNameShouldFail" }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void regexp() { addClass("test.sample.Sample1"); // should matches all methods belonging to group "odd" addIncludedGroup("o.*"); run(); String passed[] = { "method1", "method3" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test(groups = { "currentold" }) public void logger() { Logger logger = Logger.getLogger(""); // System.out.println("# HANDLERS:" + logger.getHandlers().length); for (Handler handler : logger.getHandlers()) { handler.setLevel(Level.WARNING); handler.setFormatter(new org.testng.log.TextFormatter()); } logger.setLevel(Level.SEVERE); } static public void ppp(String s) { System.out.println("[Test1] " + s); } } // Test1 testng-6.9.12/src/test/java/test/preserveorder/0000755000175000017500000000000012732165123020756 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/preserveorder/C.java0000644000175000017500000000043412732165123022004 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; import test.BaseLogTest; public class C extends BaseLogTest { @Test public void c1() { log("C.c1"); } @Test public void c2() { log("C.c2"); } @Test public void c3() { log("C.c3"); } } testng-6.9.12/src/test/java/test/preserveorder/B.java0000644000175000017500000000043412732165123022003 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; import test.BaseLogTest; public class B extends BaseLogTest { @Test public void b1() { log("B.b1"); } @Test public void b2() { log("B.b2"); } @Test public void b3() { log("B.b3"); } } testng-6.9.12/src/test/java/test/preserveorder/TestClassFactory.java0000644000175000017500000000045612732165123025063 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Factory; public class TestClassFactory { @Factory public Object[] f() { final Object[] res = new Object[4]; for (int i = 1; i < 5; i++) { res[i-1] = new TestClass(i); } return res; } } testng-6.9.12/src/test/java/test/preserveorder/ChuckTest3.java0000755000175000017500000000105712732165123023607 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; public class ChuckTest3 { @Test(groups = {"functional"}, dependsOnMethods = {"c3TestTwo"}) public void c3TestThree() { // System.out.println("chucktest3: test three"); } @Test(groups = {"functional"}) public static void c3TestOne() { // System.out.println("chucktest3: test one"); } @Test(groups = {"functional"}, dependsOnMethods = {"c3TestOne"}) public static void c3TestTwo() { // System.out.println("chucktest3: test two"); } } testng-6.9.12/src/test/java/test/preserveorder/TestClass.java0000644000175000017500000000112012732165123023520 0ustar eugeneeugene/* * @(#) TestClass.java * Created: Aug 10, 2011 * By: Wolfgang & Monika Baltes * Copyright 2011 Wolfgang Baltes * WOLFGANG & MONIKA BALTES PROPRIETARY/CONFIDENTIAL. * Use is subject to license terms. */ package test.preserveorder; import org.testng.Assert; import org.testng.annotations.Test; /** * @author Wolfgang Baltes * */ public class TestClass { private final int val; public TestClass(final int val) { this.val = val; } @Test public void checkVal() { Assert.assertTrue(this.val != 0); } } testng-6.9.12/src/test/java/test/preserveorder/AAA.java0000644000175000017500000000044412732165123022205 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; import test.BaseLogTest; public class AAA extends BaseLogTest { @Test public void a1() { log("AAA.a1"); } @Test public void a2() { log("AAA.a2"); } @Test public void a3() { log("AAA.a3"); } } testng-6.9.12/src/test/java/test/preserveorder/SibTest.java0000755000175000017500000000037612732165123023207 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; @Test(singleThreaded = true) public class SibTest { @Test public void sib1() { } @Test(dependsOnMethods = "sib1") public void sib2() { // System.out.println("sib2"); } } testng-6.9.12/src/test/java/test/preserveorder/EdnTest.java0000755000175000017500000000030112732165123023164 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; @Test(singleThreaded = true) public class EdnTest { @Test public void edn1() { } @Test public void edn2() { } } testng-6.9.12/src/test/java/test/preserveorder/PreserveOrderTest.java0000644000175000017500000000750512732165123025257 0ustar eugeneeugenepackage test.preserveorder; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.BaseLogTest; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; public class PreserveOrderTest extends SimpleBaseTest { @Test public void preserveClassOrder() { String[][] tests = new String[][] { new String[] { "AAA", "B", "C" }, new String[] { "AAA", "C", "B" }, new String[] { "B", "AAA", "C" }, new String[] { "B", "C", "AAA" }, new String[] { "C", "B", "AAA" }, new String[] { "C", "AAA", "B" }, }; for (String[] t : tests) { TestNG tng = create(); // tng.setVerbose(2); XmlSuite s = createXmlSuite("Suite"); String[] fullTestNames = new String[t.length]; for (int i = 0; i < t.length; i++) { fullTestNames[i] = "test.preserveorder." + t[i]; } XmlTest xt = createXmlTest(s, "Test", fullTestNames); xt.setPreserveOrder("true"); // System.out.println(s.toXml()); tng.setXmlSuites(Arrays.asList(s)); tng.run(); // 3 methods per class, 3 classes, so the log should contain 9 calls List log = BaseLogTest.getLog(); Assert.assertEquals(log.size(), 9); // Every slice of 3 logs should belong to the same class in the same // order as in the specified string: AAA.a1, AAA.a2, AAA.a3, B.a1, etc... // Since we're only testing class ordering in this test, we only match // against the class name for (int i = 0; i < t.length; i++) { for (int j = 0; j < 3; j++) { Assert.assertTrue(log.get(j + (3 * i)).startsWith(t[i] + ".")); } } } } @Test public void preserveMethodOrder() { String[][] methods = new String[][] { new String[] { "a1", "a2", "a3" }, new String[] { "a1", "a3", "a2" }, new String[] { "a2", "a1", "a3" }, new String[] { "a2", "a3", "a1" }, new String[] { "a3", "a2", "a1" }, new String[] { "a3", "a1", "a2" }, }; for (String[] m : methods) { TestNG tng = create(); // tng.setVerbose(2); XmlSuite s = createXmlSuite("Suite"); String testName = "test.preserveorder.AAA"; XmlTest xt = createXmlTest(s, "Test", testName); addMethods(xt.getXmlClasses().get(0), m); xt.setPreserveOrder("true"); // System.out.println(s.toXml()); tng.setXmlSuites(Arrays.asList(s)); tng.run(); List log = BaseLogTest.getLog(); // System.out.println(log); for (int i = 0; i < log.size(); i++) { if (!log.get(i).endsWith(m[i])) { throw new AssertionError("Expected " + Arrays.asList(m) + " but got " + log); } } } } @Test public void orderShouldBePreservedWithDependencies() { TestNG tng = create(); XmlSuite s = createXmlSuite("PreserveOrder"); XmlTest t = new XmlTest(s); t.getXmlClasses().add(new XmlClass("test.preserveorder.ChuckTest4")); t.getXmlClasses().add(new XmlClass("test.preserveorder.ChuckTest3")); t.setPreserveOrder("true"); tng.setXmlSuites(Arrays.asList(s)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); verifyPassedTests(tla, "c4TestOne", "c4TestTwo", "c4TestThree", "c3TestOne", "c3TestTwo", "c3TestThree"); } @Test(description = "preserve-order on a factory doesn't cause an NPE") public void factoryPreserve() { TestNG tng = create(); XmlSuite s = createXmlSuite("FactoryPreserve"); XmlTest t = new XmlTest(s); t.getXmlClasses().add(new XmlClass(TestClassFactory.class.getName())); t.setPreserveOrder("true"); tng.setXmlSuites(Arrays.asList(s)); tng.run(); } } testng-6.9.12/src/test/java/test/preserveorder/ChuckTest4.java0000755000175000017500000000105712732165123023610 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; public class ChuckTest4 { @Test(groups = {"functional"}, dependsOnMethods = {"c4TestTwo"}) public void c4TestThree() { // System.out.println("chucktest4: test three"); } @Test(groups = {"functional"}) public static void c4TestOne() { // System.out.println("chucktest4: test one"); } @Test(groups = {"functional"}, dependsOnMethods = {"c4TestOne"}) public static void c4TestTwo() { // System.out.println("chucktest4: test two"); } } testng-6.9.12/src/test/java/test/preserveorder/PrgTest.java0000755000175000017500000000030512732165123023212 0ustar eugeneeugenepackage test.preserveorder; import org.testng.annotations.Test; @Test(singleThreaded=true) public class PrgTest { @Test public void prg1() { } @Test public void prg2() { } } testng-6.9.12/src/test/java/test/testng93/0000755000175000017500000000000012732165123017547 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng93/SingleTestTest.java0000644000175000017500000000102412732165123023330 0ustar eugeneeugenepackage test.testng93; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * This class/interface */ public class SingleTestTest { @BeforeMethod(groups={"group1"}) public void shouldRunBefore() { System.out.println("Runs before"); } @Test(groups={"group1"}) public void theFirstActualTest() { System.out.println("The first actual test"); } @Test public void theSecondActualTest() { System.out.println("The second actual test"); } } testng-6.9.12/src/test/java/test/testng93/testng-93.xml0000644000175000017500000000076212732165123022033 0ustar eugeneeugene testng-6.9.12/src/test/java/test/testng387/0000755000175000017500000000000012732165123017635 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng387/FailedDPTest.java0000644000175000017500000000217712732165123022757 0ustar eugeneeugenepackage test.testng387; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * test for http://jira.opensymphony.com/browse/TESTNG-387 * The invocation-numbers logic in failed.xml is wrong for dataprovider and parallel=true * * The test will throw exception when numbers are prime, so getFailedInvocationNumbers() should be a list of prime numbers. * * @author freynaud */ public class FailedDPTest { static final List primes = Arrays.asList(2, 3, 5, 7); /** * DP generating all number from 0 to 9. * */ @DataProvider(name = "DP", parallel = true) public Iterator getData() { List list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(new Integer[] { i }); } return list.iterator(); } /** * Throws an exception for a prime number. * @throws Exception */ @Test(dataProvider = "DP", groups = { "DPTest" }) public void isNotPrime(Integer i) throws Exception { if (primes.contains(i)){ throw new Exception(i+" is prime"); } } } testng-6.9.12/src/test/java/test/testng387/TestNG387.java0000644000175000017500000000156112732165123022111 0ustar eugeneeugenepackage test.testng387; import org.testng.*; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; import java.util.List; import static org.testng.Assert.assertEqualsNoOrder; public class TestNG387 extends SimpleBaseTest { @Test(invocationCount = 500) public void testInvocationCounterIsCorrectForMethodWithDataProvider() throws Exception { final TestNG tng = create(FailedDPTest.class); tng.setThreadCount(1); tng.setParallel(XmlSuite.ParallelMode.NONE); tng.setPreserveOrder(true); final TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); ITestNGMethod method = tla.getTestContexts().get(0).getAllTestMethods()[0]; List failed = method.getFailedInvocationNumbers(); assertEqualsNoOrder(failed.toArray(), FailedDPTest.primes.toArray()); } } testng-6.9.12/src/test/java/test/cyclic/0000755000175000017500000000000012732165123017335 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/cyclic/AbstractGenericTests.java0000644000175000017500000000034612732165123024266 0ustar eugeneeugenepackage test.cyclic; import org.testng.annotations.Test; public abstract class AbstractGenericTests extends BaseIntegrationTest { @Test(groups="integration") public final void testSomething() { //... } } testng-6.9.12/src/test/java/test/cyclic/BaseIntegrationTest.java0000644000175000017500000000050512732165123024116 0ustar eugeneeugenepackage test.cyclic; import org.testng.annotations.BeforeClass; public abstract class BaseIntegrationTest { @BeforeClass(groups="integration") protected void initIntegrationTesting() { //... } @BeforeClass(groups="integration") void executeBeforeClassDbOperations() { //... } } testng-6.9.12/src/test/java/test/cyclic/HibernateConcreteTests.java0000644000175000017500000000033412732165123024607 0ustar eugeneeugenepackage test.cyclic; import org.testng.annotations.Test; public class HibernateConcreteTests extends AbstractGenericTests { @Test(groups="integration") public void testSomethingElse() { //... } }testng-6.9.12/src/test/java/test/cyclic/SomeConcreteTests.java0000644000175000017500000000032712732165123023613 0ustar eugeneeugenepackage test.cyclic; import org.testng.annotations.Test; public class SomeConcreteTests extends AbstractGenericTests { @Test(groups="integration") public void testSomethingElse() { //... } }testng-6.9.12/src/test/java/test/invocationcount/0000755000175000017500000000000012732165123021311 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/invocationcount/DataProviderTrueFalseTest.java0000644000175000017500000000050612732165123027214 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class DataProviderTrueFalseTest extends DataProviderBase { @BeforeMethod(firstTimeOnly = true) public void beforeMethod() {} @AfterMethod(lastTimeOnly = false) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/FailedInvocationCount2.java0000644000175000017500000000115112732165123026463 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FailedInvocationCount2 { int m_count; int m_count2; @BeforeClass public void setUp() { m_count = 0; m_count2 = 0; } @Test(invocationCount = 10, skipFailedInvocations = true) public void shouldSkipFromAnnotation() { if (m_count++ > 3) { throw new RuntimeException(); } } @Test(invocationCount = 10, skipFailedInvocations = false) public void shouldNotSkipFromAnnotation() { if (m_count2++ > 3) { throw new RuntimeException(); } } } testng-6.9.12/src/test/java/test/invocationcount/DataProviderFalseTrueTest.java0000644000175000017500000000050712732165123027215 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class DataProviderFalseTrueTest extends DataProviderBase { @BeforeMethod(firstTimeOnly = false) public void beforeMethod() {} @AfterMethod(lastTimeOnly = true) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/FailedInvocationCount.java0000644000175000017500000000053512732165123026406 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class FailedInvocationCount { int m_count; @BeforeClass public void setUp() { m_count = 0; } @Test(invocationCount = 10) public void f() { if (m_count++ > 3) { throw new RuntimeException(); } } } testng-6.9.12/src/test/java/test/invocationcount/InvocationCountTrueTrueTest.java0000644000175000017500000000050512732165123027636 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class InvocationCountTrueTrueTest extends InvocationBase { @BeforeMethod(firstTimeOnly = true) public void beforeMethod() {} @AfterMethod(lastTimeOnly = true) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/DataProviderTrueTrueTest.java0000644000175000017500000000050512732165123027100 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class DataProviderTrueTrueTest extends DataProviderBase { @BeforeMethod(firstTimeOnly = true) public void beforeMethod() {} @AfterMethod(lastTimeOnly = true) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/InvocationCountFalseFalseTest.java0000644000175000017500000000051112732165123030061 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class InvocationCountFalseFalseTest extends InvocationBase { @BeforeMethod(firstTimeOnly = false) public void beforeMethod() {} @AfterMethod(lastTimeOnly = false) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/InvocationBase.java0000644000175000017500000000023112732165123025054 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.Test; public class InvocationBase { @Test(invocationCount = 3) public void f() { } } testng-6.9.12/src/test/java/test/invocationcount/FirstAndLastTimeTest.java0000644000175000017500000000675412732165123026205 0ustar eugeneeugenepackage test.invocationcount; import org.testng.TestNG; import org.testng.annotations.Test; import java.util.List; import test.InvokedMethodNameListener; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; /** * Test various combination of @BeforeMethod(firstTimeOnly = true/false) and * @AfterMethod(lastTimeOnly = true/false) with invocation counts and data * providers. * @author cbeust@google.com * */ public class FirstAndLastTimeTest extends SimpleBaseTest { @Test public void verifyDataProviderFalseFalse() { List invokedMethodNames = run(DataProviderFalseFalseTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "afterMethod", "beforeMethod", "f", "afterMethod", "beforeMethod", "f", "afterMethod", "beforeMethod", "f2", "afterMethod", "beforeMethod", "f2", "afterMethod", "beforeMethod", "f2", "afterMethod" ); } @Test public void verifyDataProviderTrueFalse() { List invokedMethodNames = run(DataProviderTrueFalseTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "afterMethod", "f", "afterMethod", "f", "afterMethod", "beforeMethod", "f2", "afterMethod", "f2", "afterMethod", "f2", "afterMethod" ); } @Test public void verifyDataProviderFalseTrue() { List invokedMethodNames = run(DataProviderFalseTrueTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "beforeMethod", "f", "beforeMethod", "f", "afterMethod", "beforeMethod", "f2", "beforeMethod", "f2", "beforeMethod", "f2", "afterMethod" ); } @Test public void verifyDataProviderTrueTrue() { List invokedMethodNames = run(DataProviderTrueTrueTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "f", "f", "afterMethod", "beforeMethod", "f2", "f2", "f2", "afterMethod" ); } @Test public void verifyInvocationCountFalseFalse() { List invokedMethodNames = run(InvocationCountFalseFalseTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "afterMethod", "beforeMethod", "f", "afterMethod", "beforeMethod", "f", "afterMethod" ); } @Test public void verifyInvocationCountTrueFalse() { List invokedMethodNames = run(InvocationCountTrueFalseTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "afterMethod", "f", "afterMethod", "f", "afterMethod" ); } @Test public void verifyInvocationCountFalseTrue() { List invokedMethodNames = run(InvocationCountFalseTrueTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "beforeMethod", "f", "beforeMethod", "f", "afterMethod" ); } @Test public void verifyInvocationCountTrueTrue() { List invokedMethodNames = run(InvocationCountTrueTrueTest.class); assertThat(invokedMethodNames).containsExactly( "beforeMethod", "f", "f", "f", "afterMethod" ); } private static List run(Class cls) { TestNG tng = create(cls); InvokedMethodNameListener listener = new InvokedMethodNameListener(); tng.addListener(listener); tng.run(); return listener.getInvokedMethodNames(); } } testng-6.9.12/src/test/java/test/invocationcount/DataProviderFalseFalseTest.java0000644000175000017500000000051012732165123027322 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class DataProviderFalseFalseTest extends DataProviderBase { @BeforeMethod(firstTimeOnly = false) public void beforeMethod() {} @AfterMethod(lastTimeOnly = false) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/DataProviderBase.java0000644000175000017500000000125112732165123025332 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.Arrays; import java.util.Iterator; public class DataProviderBase { @Test(dataProvider = "dp") public void f(Integer n) { } @DataProvider public Object[][] dp() { return new Integer[][] { new Integer[] { 0 }, new Integer[] { 1 }, new Integer[] { 2 } }; } @Test(dataProvider = "dp2") public void f2(Integer n) { } @DataProvider public Iterator dp2() { return Arrays.asList( new Object[] { 0 }, new Object[] { 1 }, new Object[] { 2 } ).iterator(); } } testng-6.9.12/src/test/java/test/invocationcount/InvocationCountTrueFalseTest.java0000644000175000017500000000050712732165123027753 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class InvocationCountTrueFalseTest extends InvocationBase { @BeforeMethod(firstTimeOnly = true) public void beforeMethod() {} @AfterMethod(lastTimeOnly = false) public void afterMethod() {} } testng-6.9.12/src/test/java/test/invocationcount/FailedInvocationCountTest.java0000644000175000017500000000257212732165123027251 0ustar eugeneeugenepackage test.invocationcount; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; public class FailedInvocationCountTest { private void runTest(boolean skip, int passed, int failed, int skipped) { TestNG testng = new TestNG(); testng.setVerbose(0); testng.setSkipFailedInvocationCounts(skip); testng.setTestClasses(new Class[] { FailedInvocationCount.class }); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.run(); Assert.assertEquals(tla.getPassedTests().size(), passed); Assert.assertEquals(tla.getFailedTests().size(), failed); Assert.assertEquals(tla.getSkippedTests().size(), skipped); } @Test public void verifyGloballyShouldStop() { runTest(true, 4, 1, 5); } @Test public void verifyGloballyShouldNotStop() { runTest(false, 4, 6, 0); } @Test public void verifyAttributeShouldStop() { TestNG testng = new TestNG(); testng.setVerbose(0); testng.setTestClasses(new Class[] { FailedInvocationCount2.class }); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.run(); Assert.assertEquals(tla.getPassedTests().size(), 8); Assert.assertEquals(tla.getFailedTests().size(), 7); Assert.assertEquals(tla.getSkippedTests().size(), 5); } } testng-6.9.12/src/test/java/test/invocationcount/InvocationCountFalseTrueTest.java0000644000175000017500000000050712732165123027753 0ustar eugeneeugenepackage test.invocationcount; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class InvocationCountFalseTrueTest extends InvocationBase { @BeforeMethod(firstTimeOnly = false) public void beforeMethod() {} @AfterMethod(lastTimeOnly = true) public void afterMethod() {} } testng-6.9.12/src/test/java/test/superclass/0000755000175000017500000000000012732165123020253 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/superclass/Base2.java0000644000175000017500000000073112732165123022053 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @Test public class Base2 { @BeforeClass public void bc() { ppp("BEFORE_CLASS"); } @BeforeMethod public void bm() { ppp("BEFORE_METHOD"); } public void tbase() { ppp("TEST IN BASE"); } private static void ppp(String s) { if (false) { System.out.println("[Base] " + s); } } } testng-6.9.12/src/test/java/test/superclass/Child1Test.java0000644000175000017500000000052512732165123023064 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.Test; @Test public class Child1Test extends Base1 { public void t1() { ppp("T1"); } public void t2() { ppp("T2"); } public void t3() { ppp("T3"); } private static void ppp(String s) { if (false) { System.out.println("[Child] " + s); } } } testng-6.9.12/src/test/java/test/superclass/ChildSampleTest3.java0000644000175000017500000000042512732165123024227 0ustar eugeneeugenepackage test.superclass; import org.testng.Assert; import org.testng.annotations.Test; public class ChildSampleTest3 extends BaseSampleTest3 { @Test public void pass() { Assert.assertTrue(true); } @Test public void fail() { Assert.assertTrue(false); } } testng-6.9.12/src/test/java/test/superclass/MainTest.java0000644000175000017500000000140012732165123022635 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.Test; import test.BaseTest; public class MainTest extends BaseTest { @Test public void baseMethodIsCalledWithMethodTest() { addClass("test.superclass.Child1Test"); run(); String[] passed = { "tbase", "t1", "t2", "t3" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void baseMethodIsCalledWithClassTest() { addClass("test.superclass.Child2Test"); run(); String[] passed = { "tbase", "t1", "t2", "t3" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/superclass/Test3.java0000644000175000017500000000106012732165123022115 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.Test; import test.BaseTest; public class Test3 extends BaseTest { @Test public void shouldExcludeBaseMethods() { addClass("test.superclass.ChildSampleTest3"); addExcludedMethod("test.superclass.ChildSampleTest3", "pass"); addExcludedMethod("test.superclass.ChildSampleTest3", "base"); run(); String[] passed = { }; String[] failed = { "fail" }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); } } testng-6.9.12/src/test/java/test/superclass/BaseSampleTest3.java0000644000175000017500000000022712732165123024056 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.Test; public class BaseSampleTest3 { @Test public void base() { assert true; } } testng-6.9.12/src/test/java/test/superclass/Base1.java0000644000175000017500000000073212732165123022053 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class Base1 { @BeforeClass public void bc() { ppp("BEFORE_CLASS"); } @BeforeMethod public void bm() { ppp("BEFORE_METHOD"); } @Test public void tbase() { ppp("TEST IN BASE"); } private static void ppp(String s) { if (false) { System.out.println("[Base] " + s); } } } testng-6.9.12/src/test/java/test/superclass/Child2Test.java0000644000175000017500000000052512732165123023065 0ustar eugeneeugenepackage test.superclass; import org.testng.annotations.Test; @Test public class Child2Test extends Base2 { public void t1() { ppp("T1"); } public void t2() { ppp("T2"); } public void t3() { ppp("T3"); } private static void ppp(String s) { if (false) { System.out.println("[Child] " + s); } } } testng-6.9.12/src/test/java/test/justin/0000755000175000017500000000000012732165123017403 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/justin/BaseTestCase.java0000644000175000017500000000200212732165123022546 0ustar eugeneeugenepackage test.justin; import org.testng.annotations.Test; /** * @author Justin Lee Date: Aug 15, 2004 */ @Test public abstract class BaseTestCase { protected static final String TEST_PASSWORD = "testPassword"; public BaseTestCase() { init(); } public BaseTestCase(String name) { this(); } private void init() { setSessionUser(null); } protected void commit() { } protected void tearDown() throws Exception { commit(); } protected Object createCustomer() throws Exception { return null; } protected Object createProject() throws Exception { return null; } protected Object createTimeEntry() throws Exception { return null; } protected Object createUser(String name) throws Exception { return null; } protected Object createUserGroup() throws Exception { return null; } protected void setSessionUser(Object user) { } } testng-6.9.12/src/test/java/test/justin/MonthTest.java0000644000175000017500000000075612732165123022203 0ustar eugeneeugenepackage test.justin; import org.testng.annotations.Test; import java.text.ParseException; /** * Created Jul 10, 2005 * * @author Justin Lee */ public class MonthTest extends BaseTestCase { public MonthTest() { } public MonthTest(String name) { super(name); } @Test(groups = {"bean-tests"}) public void july2005() throws ParseException { } @Test public void weekendDay() throws ParseException { } }testng-6.9.12/src/test/java/test/pholser/0000755000175000017500000000000012732165123017543 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/pholser/Saboteur.java0000644000175000017500000000155612732165123022201 0ustar eugeneeugenepackage test.pholser; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * @author Paul Holser * @version $Id: Saboteur.java,v 1.4 2006/06/22 13:45:01 cedric Exp $ */ public class Saboteur { @BeforeClass public void setUpFixture() { Captor.reset(); Captor.instance().capture( "Saboteur.setUpFixture" ); } @BeforeMethod public void setUp() { Captor.instance().capture( "Saboteur.setUp" ); } @AfterMethod public void tearDown() { Captor.instance().capture( "Saboteur.tearDown" ); } @AfterClass public void tearDownFixture() { Captor.instance().capture( "Saboteur.tearDownFixture" ); } @Test public void go() { } } testng-6.9.12/src/test/java/test/pholser/Captor.java0000644000175000017500000000151112732165123021634 0ustar eugeneeugenepackage test.pholser; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @author Paul Holser * @version $Id: Captor.java,v 1.3 2004/08/26 22:25:22 cedric Exp $ */ public class Captor { private static Captor instance = null; private List captives; public static Captor instance() { if (null == instance) { instance = new Captor(); } return instance; } public static void reset() { // System.out.println("@@PHOLSER RESETTING CAPTOR"); instance().captives = new ArrayList<>(); } public void capture( String aString ) { // System.out.println("@@PHOLSER CAPTURING " + aString); captives.add( aString ); } public List captives() { return Collections.unmodifiableList( captives ); } } testng-6.9.12/src/test/java/test/pholser/Demo.java0000644000175000017500000000317512732165123021300 0ustar eugeneeugenepackage test.pholser; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.Arrays; import java.util.List; /** * @author Paul Holser * @version $Id: Demo.java,v 1.5 2006/06/22 13:45:01 cedric Exp $ */ public class Demo { @BeforeClass public void setUpFixture() { Captor.reset(); Captor.instance().capture( "Demo.setUpFixture" ); } @BeforeMethod public void setUp() { Captor.instance().capture( "Demo.setUp" ); } @AfterMethod public void tearDown() { Captor.instance().capture( "Demo.tearDown" ); } @AfterClass public void tearDownFixture() { final List expected = Arrays.asList(new String[] { "Demo.setUpFixture", "Demo.setUp", "Demo.tearDown" }); final List actual = Captor.instance().captives(); verify(expected, actual); } @Test public void go() { final List expected = Arrays.asList(new String[] { "Demo.setUpFixture", "Demo.setUp" } ); final List actual = Captor.instance().captives(); verify(expected, actual); } private void verify(List expected, List actual) { if (! expected.equals(actual)) { throw new AssertionError("\nExpected:" + dumpList(expected) + "\n Got:" + dumpList(actual)); } } private String dumpList(List list) { StringBuffer result = new StringBuffer(); for (String l : list) { result.append(" " + l); } return result.toString(); } }testng-6.9.12/src/test/java/test/regression/0000755000175000017500000000000012732165123020247 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/regression/MyTestngTest2.java0000644000175000017500000000076012732165123023611 0ustar eugeneeugenepackage test.regression; import org.testng.ITestContext; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MyTestngTest2 extends MyTestngTest { @BeforeClass() public void beforeClass(ITestContext tc) throws Exception { } @BeforeMethod() public void beforeMethod(ITestContext tc) throws Exception { //throw new Exception("fail me"); } @Test() public void test(ITestContext tc) { } } testng-6.9.12/src/test/java/test/regression/BeforeTestFailingTest.java0000644000175000017500000000107212732165123025306 0ustar eugeneeugenepackage test.regression; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class BeforeTestFailingTest extends SimpleBaseTest { @Test public void beforeTestFailingShouldCauseSkips() { TestNG tng = create(MyTestngTest2.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getSkippedTests().size(), 1); Assert.assertEquals(tla.getPassedTests().size(), 0); } } testng-6.9.12/src/test/java/test/regression/groupsordering/0000755000175000017500000000000012732165123023320 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/regression/groupsordering/testng.xml0000644000175000017500000000103712732165123025347 0ustar eugeneeugene testng-6.9.12/src/test/java/test/regression/groupsordering/B.java0000644000175000017500000000033512732165123024345 0ustar eugeneeugenepackage test.regression.groupsordering; import org.testng.annotations.Test; public class B extends Base { @Test(groups= "a") public void testB() throws Exception { Base.s_childBWasRun= true; } } testng-6.9.12/src/test/java/test/regression/groupsordering/A.java0000644000175000017500000000033012732165123024337 0ustar eugeneeugenepackage test.regression.groupsordering; import org.testng.annotations.Test; public class A extends Base { @Test(groups= "a") public void testA() throws Exception { s_childAWasRun= true; } } testng-6.9.12/src/test/java/test/regression/groupsordering/Base.java0000644000175000017500000000163312732165123025040 0ustar eugeneeugenepackage test.regression.groupsordering; import org.testng.Assert; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; public abstract class Base { protected static boolean s_childAWasRun; protected static boolean s_childBWasRun; @BeforeGroups(value= "a", groups= "a") public void setUp() throws Exception { // System.out.println("class is " + getClass().getName() + " Before group "); Assert.assertFalse(s_childAWasRun || s_childBWasRun, "Static field was not reset: @AfterGroup method not invoked"); } @AfterGroups(value= "a", groups= "a") public void tearDown() { // System.out.println("class is " + getClass().getName() + " After group "); Assert.assertTrue(s_childAWasRun, "Child A was not run"); Assert.assertTrue(s_childBWasRun, "Child B was not run"); s_childAWasRun = false; s_childBWasRun = false; } } testng-6.9.12/src/test/java/test/regression/MyTestngTest.java0000644000175000017500000000060512732165123023525 0ustar eugeneeugenepackage test.regression; import org.testng.ITestContext; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; public class MyTestngTest { @BeforeSuite() public void beforeSuite(ITestContext tc) throws Exception { } @BeforeTest() public void beforeTest(ITestContext tc) throws Exception { throw new RuntimeException("barfing now"); } } testng-6.9.12/src/test/java/test/CountSampleTest.java0000644000175000017500000000200212732165123022016 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.SkipException; import org.testng.annotations.Test; /** * Use this test to show run/failed/skip result * differences between testng-5.12 and testng-5-14 * * @author CA Technologies */ public class CountSampleTest { @Test(groups = {"functional"}) public void testInvokedAndSkipped() throws SkipException { // System.out.println("Skipping this test after it is invoked."); throw new SkipException("This test is skipped after invocation"); } @Test(groups = {"functional"}) public static void testInvokedAndFailed() { // System.out.println("Failing this test after it is invoked."); Assert.fail("Failing this test on purpose"); } @Test(groups = {"functional"}, dependsOnMethods = {"testInvokedAndFailed"}) public static void testWillNotBeInvokedOnlySkipped() { // System.out.println("This test will be skipped, " + // "but not invoked because its dependsOnMethod fails."); } } testng-6.9.12/src/test/java/test/inheritance/0000755000175000017500000000000012732165123020360 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/inheritance/testng739/0000755000175000017500000000000012732165123022127 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/inheritance/testng739/B.java0000644000175000017500000000022412732165123023151 0ustar eugeneeugenepackage test.inheritance.testng739; import org.testng.annotations.Test; public class B extends BaseClass { @Test public void testB() { } } testng-6.9.12/src/test/java/test/inheritance/testng739/BaseClass.java0000644000175000017500000000023712732165123024634 0ustar eugeneeugenepackage test.inheritance.testng739; import org.testng.annotations.BeforeClass; public class BaseClass { @BeforeClass public void beforeBaseClass() {} } testng-6.9.12/src/test/java/test/inheritance/testng739/A.java0000644000175000017500000000043712732165123023156 0ustar eugeneeugenepackage test.inheritance.testng739; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class A extends BaseClass { @BeforeClass public void beforeClassA() { Assert.fail(); } @Test public void testA() { } } testng-6.9.12/src/test/java/test/inheritance/testng739/TestNG739.java0000644000175000017500000000153612732165123024406 0ustar eugeneeugenepackage test.inheritance.testng739; import org.testng.TestNG; import org.testng.annotations.Test; import test.InvokedMethodNameListener; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; public class TestNG739 extends SimpleBaseTest { @Test public void test_classes_should_be_skipped_when_a_before_class_fails() { TestNG tng = create(A.class, B.class); tng.setPreserveOrder(true); InvokedMethodNameListener listener = new InvokedMethodNameListener(); tng.setPreserveOrder(true); tng.addListener(listener); tng.run(); assertThat(listener.getSucceedMethodNames()).containsExactly("beforeBaseClass", "beforeBaseClass", "testB"); assertThat(listener.getFailedMethodNames()).containsExactly("beforeClassA"); assertThat(listener.getSkippedMethodNames()).containsExactly("testA"); } } testng-6.9.12/src/test/java/test/inheritance/VerifyTest.java0000644000175000017500000000126512732165123023333 0ustar eugeneeugenepackage test.inheritance; import org.testng.AssertJUnit; import org.testng.annotations.Test; import java.util.List; public class VerifyTest { @Test(dependsOnGroups = {"before"}) public void verify() { String[] expected = { "initApplication", "initDialog", "initDialog2", "test", "tearDownDialog2", "tearDownDialog", "tearDownApplication" }; int i = 0; List l = ZBase_0.getMethodList(); AssertJUnit.assertEquals(expected.length, l.size()); for (String s : l) { AssertJUnit.assertEquals(expected[i++], s); } } private static void ppp(String s) { System.out.println("[VerifyTest] " + s); } } testng-6.9.12/src/test/java/test/inheritance/testng234/0000755000175000017500000000000012732165123022115 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/inheritance/testng234/ParentTest.java0000644000175000017500000000033012732165123025045 0ustar eugeneeugenepackage test.inheritance.testng234; import org.testng.annotations.Test; public abstract class ParentTest { @Test public void executePolymorphicMethod() { } protected abstract void polymorphicMethod(); } testng-6.9.12/src/test/java/test/inheritance/testng234/ChildTest.java0000644000175000017500000000060412732165123024643 0ustar eugeneeugenepackage test.inheritance.testng234; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ChildTest extends ParentTest { @BeforeClass public void beforeClassMethod() { Assert.assertTrue(false, "This is so sad... I must skip all my tests ..."); } @Override @Test public void polymorphicMethod() { } } testng-6.9.12/src/test/java/test/inheritance/testng234/PolymorphicFailureTest.java0000644000175000017500000000135212732165123027436 0ustar eugeneeugenepackage test.inheritance.testng234; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.Arrays; public class PolymorphicFailureTest extends SimpleBaseTest { @Test public void superclassFailureShouldCauseFailure() { TestNG tng = create(ChildTest.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); assertTestResultsEqual(tla.getSkippedTests(), Arrays.asList( "polymorphicMethod", "executePolymorphicMethod") ); Assert.assertEquals(0, tla.getPassedTests().size()); Assert.assertEquals(0, tla.getFailedTests().size()); } } testng-6.9.12/src/test/java/test/inheritance/ClassScopeTest.java0000644000175000017500000000052312732165123024122 0ustar eugeneeugenepackage test.inheritance; import org.testng.Assert; import org.testng.annotations.Test; public class ClassScopeTest extends BaseClassScope { private boolean m_verify = false; public void setVerify() { m_verify = true; } @Test(dependsOnMethods = "setVerify") public void verify() { Assert.assertTrue(m_verify); } } testng-6.9.12/src/test/java/test/inheritance/DChild_2.java0000644000175000017500000000157612732165123022604 0ustar eugeneeugenepackage test.inheritance; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * Make sure that configuration inherited methods are invoked in the right * order. The funny naming is to make sure that the class names do not * play any role in the ordering of methods. * * Created on Sep 8, 2005 * @author cbeust */ public class DChild_2 extends Child_1 { @BeforeMethod public void initDialog2() { m_methodList.add("initDialog2"); ppp(" INIT 2"); } @AfterMethod public void tearDownDialog2() { m_methodList.add("tearDownDialog2"); ppp(" TEAR_DOWN 2"); } @Test(groups = {"before" }) public void test() { m_methodList.add("test"); ppp(" TEST"); } private static void ppp(String s) { if (m_verbose) { System.out.println("[D2] " + s); } } } testng-6.9.12/src/test/java/test/inheritance/testng471/0000755000175000017500000000000012732165123022120 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/inheritance/testng471/TestNG471.java0000644000175000017500000000301112732165123024356 0ustar eugeneeugenepackage test.inheritance.testng471; import org.testng.TestNG; import org.testng.annotations.Test; import test.InvokedMethodNameListener; import test.SimpleBaseTest; import static org.assertj.core.api.Assertions.assertThat; public class TestNG471 extends SimpleBaseTest { @Test public void test_classes_should_not_be_skipped_when_a_after_method_fails() { TestNG tng = create(Class1.class, Class2.class, Class3.class); tng.setPreserveOrder(true); tng.setVerbose(10); InvokedMethodNameListener listener = new InvokedMethodNameListener(); tng.setPreserveOrder(true); tng.addListener(listener); tng.run(); assertThat(listener.getFailedMethodNames()).containsExactly("afterMethodClass1"); assertThat(listener.getSkippedMethodNames()).containsExactly("test1_2"); assertThat(listener.getSucceedMethodNames()).containsExactly( "beforeSuperClass1", "beforeClass1", "beforeMethodClass1", "test1_1", // "afterMethodClass1" failed // "beforeMethodClass1", "test1_2" and "afterMethodClass1" skipped // "afterClass1" skipped "beforeSuperClass1", "beforeClass2", "beforeMethodClass2", "test2_1", "afterMethodClass2", "beforeMethodClass2", "test2_2", "afterMethodClass2", "afterClass2", "beforeSuperClass2", "beforeClass3", "beforeMethodClass3", "test3_1", "afterMethodClass3", "beforeMethodClass3", "test3_2", "afterMethodClass3", "afterClass3"); } } testng-6.9.12/src/test/java/test/inheritance/testng471/SuperClass2.java0000644000175000017500000000024612732165123025133 0ustar eugeneeugenepackage test.inheritance.testng471; import org.testng.annotations.BeforeClass; public class SuperClass2 { @BeforeClass public void beforeSuperClass2() { } } testng-6.9.12/src/test/java/test/inheritance/testng471/Class2.java0000644000175000017500000000062712732165123024117 0ustar eugeneeugenepackage test.inheritance.testng471; import org.testng.annotations.*; public class Class2 extends SuperClass1 { @BeforeClass public void beforeClass2() { } @AfterClass public void afterClass2() { } @BeforeMethod public void beforeMethodClass2() { } @AfterMethod public void afterMethodClass2() { } @Test public void test2_1() { } @Test public void test2_2() { } } testng-6.9.12/src/test/java/test/inheritance/testng471/Class1.java0000644000175000017500000000070312732165123024111 0ustar eugeneeugenepackage test.inheritance.testng471; import org.junit.Assert; import org.testng.annotations.*; public class Class1 extends SuperClass1 { @BeforeClass public void beforeClass1() { } @AfterClass public void afterClass1() { } @BeforeMethod public void beforeMethodClass1() { } @AfterMethod public void afterMethodClass1() { Assert.fail(); } @Test public void test1_1() { } @Test public void test1_2() { } } testng-6.9.12/src/test/java/test/inheritance/testng471/SuperClass1.java0000644000175000017500000000024612732165123025132 0ustar eugeneeugenepackage test.inheritance.testng471; import org.testng.annotations.BeforeClass; public class SuperClass1 { @BeforeClass public void beforeSuperClass1() { } } testng-6.9.12/src/test/java/test/inheritance/testng471/Class3.java0000644000175000017500000000110612732165123024111 0ustar eugeneeugenepackage test.inheritance.testng471; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class Class3 extends SuperClass2 { @BeforeClass public void beforeClass3() { } @AfterClass public void afterClass3() { } @BeforeMethod public void beforeMethodClass3() { } @AfterMethod public void afterMethodClass3() { } @Test public void test3_1() { } @Test public void test3_2() { } } testng-6.9.12/src/test/java/test/inheritance/BaseClassScope.java0000644000175000017500000000014612732165123024056 0ustar eugeneeugenepackage test.inheritance; import org.testng.annotations.Test; @Test public class BaseClassScope { } testng-6.9.12/src/test/java/test/inheritance/Child_1.java0000644000175000017500000000075412732165123022474 0ustar eugeneeugenepackage test.inheritance; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; public class Child_1 extends ZBase_0 { @BeforeMethod public void initDialog() { m_methodList.add("initDialog"); ppp(" INIT 1"); } @AfterMethod public void tearDownDialog() { m_methodList.add("tearDownDialog"); ppp(" TEAR_DOWN 1"); } private static void ppp(String s) { if (m_verbose) { System.out.println("[C1] " + s); } } } testng-6.9.12/src/test/java/test/inheritance/ZBase_0.java0000644000175000017500000000153412732165123022451 0ustar eugeneeugenepackage test.inheritance; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; import java.util.ArrayList; import java.util.List; public class ZBase_0 { protected static boolean m_verbose = false; protected static List m_methodList = new ArrayList<>(); @BeforeTest public void beforeTest() { m_methodList = new ArrayList<>(); } @BeforeMethod public void initApplication() { m_methodList.add("initApplication"); ppp("INIT 0"); } @AfterMethod public void tearDownApplication() { m_methodList.add("tearDownApplication"); ppp("TEAR DOWN 0"); } private static void ppp(String s) { if (m_verbose) { System.out.println("[Z0] " + s); } } public static List getMethodList() { return m_methodList; } } testng-6.9.12/src/test/java/test/simple/0000755000175000017500000000000012732165123017360 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/simple/SimpleTest.java0000644000175000017500000000032412732165123022313 0ustar eugeneeugenepackage test.simple; import org.testng.annotations.Test; public class SimpleTest { @Test public void f() { } private void ppp(String string) { System.out.println("[SimpleTest] " + string); } } testng-6.9.12/src/test/java/test/simple/IncludedExcludedTest.java0000644000175000017500000000477412732165123024304 0ustar eugeneeugenepackage test.simple; import org.testng.Assert; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ITestNGMethod; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import testhelper.OutputDirectoryPatch; import java.util.Collection; import java.util.List; public class IncludedExcludedTest { private TestNG m_tng; @BeforeMethod public void init() { m_tng = new TestNG(); m_tng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); m_tng.setVerbose(0); m_tng.setUseDefaultListeners(false); } @Test(description = "First test method") public void verifyIncludedExcludedCount1() { m_tng.setTestClasses(new Class[] {IncludedExcludedSampleTest.class}); m_tng.setGroups("a"); m_tng.addListener( new MyReporter(new String[] { "test3" }, new String[] { "test1", "test2"})); m_tng.run(); } @Test(description = "Second test method") public void verifyIncludedExcludedCount2() { m_tng.setTestClasses(new Class[] {IncludedExcludedSampleTest.class}); m_tng.addListener( new MyReporter( new String[] { "beforeSuite", "beforeTest", "beforeTestClass", "beforeTestMethod", "test1", "beforeTestMethod", "test3" }, new String[] { "test2"})); m_tng.run(); } } class MyReporter implements IReporter { private String[] m_included; private String[] m_excluded; public MyReporter(String[] included, String[] excluded) { m_included = included; m_excluded = excluded; } @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { Assert.assertEquals(suites.size(), 1); ISuite suite = suites.get(0); { Collection invoked = suite.getInvokedMethods(); Assert.assertEquals(invoked.size(), m_included.length); for (String s : m_included) { Assert.assertTrue(containsMethod(invoked, s)); } } { Collection excluded = suite.getExcludedMethods(); Assert.assertEquals(excluded.size(), m_excluded.length); for (String s : m_excluded) { Assert.assertTrue(containsMethod(excluded, s)); } } } private boolean containsMethod(Collection invoked, String string) { for (ITestNGMethod m : invoked) { if (m.getMethodName().equals(string)) { return true; } } return false; } } testng-6.9.12/src/test/java/test/simple/IncludedExcludedSampleTest.java0000644000175000017500000000172612732165123025440 0ustar eugeneeugenepackage test.simple; import org.testng.Reporter; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class IncludedExcludedSampleTest { @BeforeSuite public void beforeSuite() { Reporter.log("beforeSuite"); } @BeforeTest public void beforeTest() { Reporter.log("beforeTest"); } @BeforeClass public void beforeTestClass() { Reporter.log("beforeTestClass"); } @BeforeMethod public void beforeTestMethod() { Reporter.log("beforeTestMethod"); } @Test public void test1() { Reporter.log("Child.test1"); } @Test(enabled = false) public void test2() { Reporter.log("Child.test2"); } @Test(groups = "a") public void test3() { Reporter.log("Child.test3"); } private void ppp(String string) { System.out.println("[TestNGBug] " + string); } } testng-6.9.12/src/test/java/test/failedreporter/0000755000175000017500000000000012732165123021076 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/failedreporter/FailedReporterParametersTest.java0000644000175000017500000000605012732165123027535 0ustar eugeneeugenepackage test.failedreporter; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.BaseTest; public class FailedReporterParametersTest extends BaseTest { private File mTempDirectory; @BeforeMethod public void setUp() { File slashTmpDir = new File(System.getProperty("java.io.tmpdir")); mTempDirectory = new File(slashTmpDir, "testng-tmp-" + System.currentTimeMillis() % 1000); mTempDirectory.mkdirs(); mTempDirectory.deleteOnExit(); } @AfterMethod public void tearDown() { deleteDir(mTempDirectory); } @Test public void failedSuiteShouldHaveParameters() throws IOException { Map suiteParams = Maps.newHashMap(); Map testParams = Maps.newHashMap(); Map classParams = Maps.newHashMap(); Map methodParams = Maps.newHashMap(); suiteParams.put("suiteParam", "suiteParamValue"); //In testng-failed.xml, suite will have both origin suite parameters and children tests parameters. testParams.put("testParam", "testParamValue"); classParams.put("classParam", "classParamValue"); methodParams.put("methodParam", "methodParamValue"); TestNG tng = new TestNG(); XmlSuite suite = new XmlSuite(); suite.setParameters(suiteParams); tng.setXmlSuites(Lists.newArrayList(suite)); XmlTest test = new XmlTest(suite); XmlClass clazz = new XmlClass(); XmlInclude includeMethod = new XmlInclude("f2"); test.setParameters(testParams); test.setXmlClasses(Lists.newArrayList(clazz)); clazz.setParameters(classParams); clazz.setXmlTest(test); clazz.setIncludedMethods(Lists.newArrayList(includeMethod)); clazz.setClass(FailedReporterSampleTest.class); includeMethod.setParameters(methodParams); includeMethod.setXmlClass(clazz); tng.setVerbose(0); tng.setOutputDirectory(mTempDirectory.getAbsolutePath()); tng.run(); runAssertions(mTempDirectory, "", new String[] {"suiteParam", "testParam", "classParam", "methodParam"}); } public static void runAssertions(File outputDir, String expectedFormat, String[] expectedKeys) { File failed = new File(outputDir, "testng-failed.xml"); for (String expectedKey : expectedKeys) { List resultLines = Lists.newArrayList(); grep(failed, String.format(expectedFormat, expectedKey, expectedKey + "Value"), resultLines); int expectedSize = 1; if ("testParam".equals(expectedKey)) { expectedSize = 2; } Assert.assertEquals(resultLines.size(), expectedSize, "Mismatch param:" + expectedKey); } } } testng-6.9.12/src/test/java/test/failedreporter/FailedReporter2SampleTest.java0000644000175000017500000000067012732165123026737 0ustar eugeneeugenepackage test.failedreporter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class FailedReporter2SampleTest { @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 0 }, new Object[] { 1 }, new Object[] { 2 }, }; } @Test(dataProvider = "dp") public void f1(Integer ip) { if (ip == 1) { throw new RuntimeException(); } } } testng-6.9.12/src/test/java/test/failedreporter/FailedReporterScenariosTest.java0000644000175000017500000000636712732165123027373 0ustar eugeneeugenepackage test.failedreporter; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.reporters.FailedReporter; import test.BaseTest; import java.io.File; import java.util.UUID; import static test.failedreporter.FailedReporterLocalTestClass.WithFailure; import static test.failedreporter.FailedReporterLocalTestClass.WithoutFailure; public class FailedReporterScenariosTest extends BaseTest { private File tempDir = new File(System.getProperty("java.io.tmpdir")); @Test public void testFileCreationSkipWhenNoFailuresExist() { File fileLocation = runTests(RUN_TYPES.WITHOUT_FAILURES); try { Assert.assertFalse(getLocation(fileLocation).exists()); } finally { if (fileLocation.exists()) { deleteRecursive(fileLocation); } } } @Test public void testFileCreationInMixedMode() { File fileLocation = runTests(RUN_TYPES.MIXED_MODE); runAssertions(fileLocation); } @Test public void testFileCreationWhenFailuresExist() { File fileLocation = runTests(RUN_TYPES.WITH_FAILURES); runAssertions(fileLocation); } private void runAssertions(File fileLocation) { try { FailedReporterTest.runAssertions(fileLocation, new String[] {"testMethodWithFailure"}, ""); Assert.assertTrue(getLocation(fileLocation).exists()); } finally { if (fileLocation.exists()) { deleteRecursive(fileLocation); } } } private File getLocation(File fileLocation) { String name = fileLocation.getAbsolutePath() + File.separator + FailedReporter.TESTNG_FAILED_XML; return new File(name); } private File runTests(RUN_TYPES runType) { String suiteName = UUID.randomUUID().toString(); File fileLocation = new File(tempDir, suiteName); if (! fileLocation.exists()) { fileLocation.mkdirs(); } TestNG testNG = new TestNG(); Class[] classes = {}; switch (runType) { case WITH_FAILURES: classes = new Class[] {WithFailure.class}; break; case WITHOUT_FAILURES: classes = new Class[] {WithoutFailure.class}; break; case MIXED_MODE: classes = new Class[] {WithFailure.class, WithoutFailure.class}; } testNG.setTestClasses(classes); testNG.setOutputDirectory(fileLocation.getAbsolutePath()); try { testNG.run(); } catch (AssertionError e) { //catch all assertion failures. Our intent is not assertions of the test class. } return fileLocation; } private static void deleteRecursive(File path) { if (! path.exists()) { return; } if (path.isDirectory()) { File[] files = path.listFiles(); if (null != files) { for (File f : files) { deleteRecursive(f); } } } path.delete(); } enum RUN_TYPES { WITH_FAILURES, WITHOUT_FAILURES, MIXED_MODE } } testng-6.9.12/src/test/java/test/failedreporter/FailedReporterLocalTestClass.java0000644000175000017500000000117712732165123027457 0ustar eugeneeugenepackage test.failedreporter; import org.testng.Assert; import org.testng.annotations.Test; /** * A simple test class that is used by {@link FailedReporterScenariosTest} class to test out the presence/absence * of testng-failed.xml file when there are failures/no failures scenarios. */ public class FailedReporterLocalTestClass { public static class WithFailure { @Test public void testMethodWithFailure() { Assert.fail(); } } public static class WithoutFailure { @Test public void testMethodWithoutFailure() { Assert.assertTrue(true); } } } testng-6.9.12/src/test/java/test/failedreporter/FailedReporterSampleTest.java0000644000175000017500000000047612732165123026661 0ustar eugeneeugenepackage test.failedreporter; import org.testng.SkipException; import org.testng.annotations.Test; public class FailedReporterSampleTest { @Test public void f2() { throw new RuntimeException(); } @Test public void f1() { throw new SkipException("Skipped"); } @Test public void f3() { } } testng-6.9.12/src/test/java/test/failedreporter/FailedReporterTest.java0000644000175000017500000000364512732165123025520 0ustar eugeneeugenepackage test.failedreporter; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.collections.Lists; import test.BaseTest; import java.io.File; import java.io.IOException; import java.util.List; public class FailedReporterTest extends BaseTest { private File mTempDirectory; @BeforeMethod public void setUp() { File slashTmpDir = new File(System.getProperty("java.io.tmpdir")); mTempDirectory = new File(slashTmpDir, "testng-tmp-" + System.currentTimeMillis() % 1000); mTempDirectory.mkdirs(); mTempDirectory.deleteOnExit(); } @AfterMethod public void tearDown() { deleteDir(mTempDirectory); } @Test public void failedAndSkippedMethodsShouldBeIncluded() throws IOException { testFailedReporter(FailedReporterSampleTest.class, new String[] { "f1", "f2" }, ""); } @Test public void failedMethodWithDataProviderShouldHaveInvocationNumbers() throws IOException { testFailedReporter(FailedReporter2SampleTest.class, new String[] { "f1" }, ""); } private void testFailedReporter(Class cls, String[] expectedMethods, String expectedLine) { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { cls }); tng.setOutputDirectory(mTempDirectory.getAbsolutePath()); tng.run(); runAssertions(mTempDirectory,expectedMethods,expectedLine); } public static void runAssertions(File outputDir, String[] expectedMethods, String expectedLine) { File failed = new File(outputDir, "testng-failed.xml"); for (String s : expectedMethods) { List resultLines = Lists.newArrayList(); grep(failed, expectedLine.format(s), resultLines); Assert.assertEquals(1, resultLines.size()); } } } testng-6.9.12/src/test/java/test/CommandLineTest.java0000644000175000017500000000756612732165123021776 0ustar eugeneeugenepackage test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import org.testng.Assert; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.sample.JUnitSample1; import testhelper.OutputDirectoryPatch; import java.util.List; public class CommandLineTest { /** * Test -junit */ @Test(groups = { "current" } ) public void junitParsing() { String[] argv = { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-junit", "-testclass", "test.sample.JUnitSample1" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); List passed = tla.getPassedTests(); assertEquals(passed.size(), 2); String test1 = passed.get(0).getMethod().getMethodName(); String test2 = passed.get(1).getMethod().getMethodName(); assertTrue(JUnitSample1.EXPECTED1.equals(test1) && JUnitSample1.EXPECTED2.equals(test2) || JUnitSample1.EXPECTED1.equals(test2) && JUnitSample1.EXPECTED2.equals(test1)); } /** * Test the absence of -junit */ @Test(groups = { "current" } ) public void junitParsing2() { String[] argv = { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-testclass", "test.sample.JUnitSample1" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); List passed = tla.getPassedTests(); assertEquals(passed.size(), 0); } /** * Test the ability to override the default command line Suite name */ @Test(groups = { "current" } ) public void suiteNameOverride() { String suiteName="MySuiteName"; String[] argv = { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-junit", "-testclass", "test.sample.JUnitSample1", "-suitename", "\""+suiteName+"\"" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); List contexts = tla.getTestContexts(); assertTrue(contexts.size()>0); for (ITestContext context:contexts) { assertEquals(context.getSuite().getName(),suiteName); } } /** * Test the ability to override the default command line test name */ @Test(groups = { "current" } ) public void testNameOverride() { String testName="My Test Name"; String[] argv = { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-junit", "-testclass", "test.sample.JUnitSample1", "-testname", "\""+testName+"\"" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); List contexts = tla.getTestContexts(); assertTrue(contexts.size()>0); for (ITestContext context:contexts) { assertEquals(context.getName(),testName); } } @Test public void testUseDefaultListenersArgument() { TestNG.privateMain(new String[] { "-log", "0", "-usedefaultlisteners", "false", "-testclass", "test.sample.JUnitSample1" }, null); } @Test public void testMethodParameter() { String[] argv = { "-log", "0", "-d", OutputDirectoryPatch.getOutputDirectory(), "-methods", "test.sample.Sample2.method1,test.sample.Sample2.method3", }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); List passed = tla.getPassedTests(); Assert.assertEquals(passed.size(), 2); Assert.assertTrue((passed.get(0).getName().equals("method1") && passed.get(1).getName().equals("method3")) || (passed.get(1).getName().equals("method1") && passed.get(0).getName().equals("method3"))); } private static void ppp(String s) { System.out.println("[CommandLineTest] " + s); } } testng-6.9.12/src/test/java/test/SerializationTest.java0000644000175000017500000000151512732165123022411 0ustar eugeneeugenepackage test; import org.testng.ITestContext; import org.testng.annotations.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class SerializationTest { @Test(groups = "broken") public void iSuiteShouldBeSerializable(ITestContext context) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(context.getSuite()); oos.close(); } @Test(groups = { "broken", "maven-broken" }) public void testngMethodShouldBeSerializable(ITestContext context) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(context.getAllTestMethods()[0]); oos.close(); } } testng-6.9.12/src/test/java/test/failures/0000755000175000017500000000000012732165123017701 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/failures/Base0.java0000644000175000017500000000021512732165123021474 0ustar eugeneeugenepackage test.failures; import org.testng.annotations.Test; public class Base0 { @Test public void base1() { assert true; } } testng-6.9.12/src/test/java/test/failures/DependentTest.java0000644000175000017500000000037112732165123023313 0ustar eugeneeugenepackage test.failures; import org.testng.annotations.Test; public class DependentTest { @Test public void f1() { } @Test(dependsOnMethods = {"f1"}, dependsOnGroups = { "f" }) public void f2() { throw new RuntimeException(); } } testng-6.9.12/src/test/java/test/failures/FailuresTest.java0000644000175000017500000000336412732165123023164 0ustar eugeneeugenepackage test.failures; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.TestHelper; import java.util.HashMap; import java.util.Map; public class FailuresTest extends BaseFailuresTest { @Test public void shouldIncludeFailedMethodsFromBaseClass() { XmlSuite suite = TestHelper.createSuite("test.failures.Child", getSuiteName()); TestNG tng = TestHelper.createTestNG(suite); tng.run(); String[] expected = new String[] { "", "", "", }; verify(getOutputDir(), expected); } @Test(enabled = false) public void shouldIncludeDependentMethods() { XmlSuite suite = TestHelper.createSuite("test.failures.DependentTest", getSuiteName()); TestNG tng = TestHelper.createTestNG(suite); tng.run(); String[] expected = new String[] { "", "" }; verify(getOutputDir(), expected); } @Test(enabled = false) public void shouldIncludeParameters() { XmlSuite suite = TestHelper.createSuite("test.failures.Child", getSuiteName()); Map params = new HashMap<>(); params.put("first-name", "Cedric"); params.put("last-name", "Beust"); suite.setParameters(params); TestNG tng = TestHelper.createTestNG(suite); tng.run(); String[] expected = new String[] { "", }; verify(getOutputDir(), expected); } private String getOutputDir() { return System.getProperty("java.io.tmpdir"); } private static void ppp(String s) { System.out.println("[FailuresTest] " + s); } } testng-6.9.12/src/test/java/test/failures/Child.java0000644000175000017500000000036312732165123021571 0ustar eugeneeugenepackage test.failures; import org.testng.annotations.Test; public class Child extends Base1 { @Test public void pass() { assert true; } @Test public void fail() { throw new RuntimeException("VOLUNTARILY FAILED"); } } testng-6.9.12/src/test/java/test/failures/BaseFailuresTest.java0000644000175000017500000000447312732165123023761 0ustar eugeneeugenepackage test.failures; import org.testng.Assert; import org.testng.TestNG; import org.testng.reporters.FailedReporter; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.regex.Pattern; public class BaseFailuresTest { // protected TestNG run(Class[] classes, String outputDir) { // return run(new TestNG(), classes, outputDir); // } protected String getSuiteName() { return "TmpSuite"; } protected TestNG run(TestNG result, Class[] classes, String outputDir) { result.setVerbose(0); result.setOutputDirectory(outputDir); result.setTestClasses(classes); result.run(); return result; } /** * @param f * @param regexps * @return true if the file contains at least one occurrence of each regexp */ protected boolean containsRegularExpressions(File f, String[] strRegexps) { Pattern[] matchers = new Pattern[strRegexps.length]; boolean[] results = new boolean[strRegexps.length]; for (int i = 0; i < strRegexps.length; i++) { matchers[i] = Pattern.compile(".*" + strRegexps[i] + ".*"); results[i] = false; } try { FileReader fr = new FileReader(f); BufferedReader br = new BufferedReader(fr); String line = br.readLine(); while (line != null) { for (int i = 0; i < strRegexps.length; i++) { if (matchers[i].matcher(line).matches()) { results[i] = true; } } line = br.readLine(); } fr.close(); br.close(); } catch (FileNotFoundException e) { e.printStackTrace(); return false; } catch (IOException e) { e.printStackTrace(); return false; } for (int i = 0; i < results.length; i++) { boolean result = results[i]; if (! result) { throw new AssertionError("Couldn't find " + strRegexps[i]); } } return true; } protected void verify(String outputDir, String[] expected) { File f = new File(outputDir + File.separatorChar + getSuiteName() + File.separator + FailedReporter.TESTNG_FAILED_XML); boolean passed = containsRegularExpressions(f, expected); Assert.assertTrue(passed); File tmpDir = new File(outputDir); tmpDir.delete(); } } testng-6.9.12/src/test/java/test/failures/Base1.java0000644000175000017500000000040012732165123021471 0ustar eugeneeugenepackage test.failures; import org.testng.annotations.Test; public class Base1 extends Base0 { @Test public void base2() { assert true; } @Test public void failFromBase() { throw new RuntimeException("VOLUNTARILY FAILED"); } }testng-6.9.12/src/test/java/test/expectedexceptions/0000755000175000017500000000000012732165123021772 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/expectedexceptions/SampleExceptions.java0000644000175000017500000000176312732165123026127 0ustar eugeneeugenepackage test.expectedexceptions; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Test; /** * This class tests @ExpectedExceptions * * @author cbeust */ public class SampleExceptions { @Test @ExpectedExceptions({ NumberFormatException.class} ) public void shouldPass() { throw new NumberFormatException(); } @Test @ExpectedExceptions({ NumberFormatException.class} ) public void shouldFail1() { throw new RuntimeException(); } @Test @ExpectedExceptions({ NumberFormatException.class} ) public void shouldFail2() { } @Test @ExpectedExceptions(RuntimeException.class) public void shouldFail3() { } // @Test(expectedExceptions = NumberFormatException.class) // public void throwWrongException() { // throw new NullPointerException(); // } // @Test // @ExpectedExceptions({ FileNotFoundException.class, IOException.class }) // public void shouldPass2() throws Exception { // throw new FileNotFoundException(); // } } testng-6.9.12/src/test/java/test/expectedexceptions/ParametersExceptionTest.java0000644000175000017500000000135612732165123027464 0ustar eugeneeugenepackage test.expectedexceptions; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.SAXException; import java.io.IOException; import java.lang.reflect.Method; /** * This class/interface */ public class ParametersExceptionTest { @Test(dataProvider="A") public void testA(Exception err) { System.out.println("testA"); } @DataProvider(name="A") protected Object[][] dp() { return new Object[][] { {new IOException(), new SAXException() } }; } @AfterMethod protected void verify(Method method) { Assert.assertTrue(false, "forced failure"); } } testng-6.9.12/src/test/java/test/expectedexceptions/SampleExceptions2.java0000644000175000017500000000261312732165123026204 0ustar eugeneeugenepackage test.expectedexceptions; import org.testng.annotations.Test; /** * This class tests @ExpectedExceptions * * @author cbeust */ public class SampleExceptions2 { @Test(expectedExceptions = NumberFormatException.class ) public void shouldPass() { throw new NumberFormatException(); } @Test(expectedExceptions = NumberFormatException.class) public void shouldFail1() { throw new RuntimeException(); } @Test(expectedExceptions = NumberFormatException.class) public void shouldFail2() { } @Test(expectedExceptions = NumberFormatException.class, expectedExceptionsMessageRegExp = ".*bomb.*") public void shouldPass2() { throw new NumberFormatException("This should not bomb at all"); } @Test(expectedExceptions = NumberFormatException.class, expectedExceptionsMessageRegExp = ".*bombc.*") public void shouldFail3() { throw new NumberFormatException("This should bomb for good"); } @Test(expectedExceptions = NumberFormatException.class, expectedExceptionsMessageRegExp = ".*") public void shouldPass3() { throw new NumberFormatException(null); } @Test(expectedExceptions = NumberFormatException.class, expectedExceptionsMessageRegExp = "Multiline.*") public void shouldPass4() { throw new NumberFormatException("Multiline\nException"); } @Test(expectedExceptions = RuntimeException.class) public void shouldFail4() { } } testng-6.9.12/src/test/java/test/expectedexceptions/WrappedExpectedExceptionTest.java0000644000175000017500000000052312732165123030440 0ustar eugeneeugenepackage test.expectedexceptions; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Test; public class WrappedExpectedExceptionTest { @Test(timeOut = 1000L) @ExpectedExceptions({ IllegalStateException.class }) public void testTimeout() { throw new IllegalStateException("expected failure"); } } testng-6.9.12/src/test/java/test/expectedexceptions/ExpectedExceptionsTest.java0000644000175000017500000000131112732165123027274 0ustar eugeneeugenepackage test.expectedexceptions; import org.testng.annotations.Test; import test.BaseTest; public class ExpectedExceptionsTest extends BaseTest { @Test public void expectedExceptionsDeprecatedSyntax() { runTest("test.expectedexceptions.SampleExceptions", new String[] { "shouldPass" }, new String[] { "shouldFail1", "shouldFail2", "shouldFail3" }, new String[] {}); } @Test public void expectedExceptions() { runTest("test.expectedexceptions.SampleExceptions2", new String[] { "shouldPass", "shouldPass2", "shouldPass3", "shouldPass4" }, new String[] { "shouldFail1", "shouldFail2", "shouldFail3", "shouldFail4" }, new String[] {}); } } testng-6.9.12/src/test/java/test/BaseLogTest.java0000644000175000017500000000074212732165123021111 0ustar eugeneeugenepackage test; import org.testng.annotations.BeforeSuite; import org.testng.collections.Lists; import java.util.List; /** * Base class for tests that need to log methods as they get called. * * @author cbeust */ public class BaseLogTest { private static List m_log; @BeforeSuite public void bc() { m_log = Lists.newArrayList(); } public static void log(String s) { m_log.add(s); } public static List getLog() { return m_log; } } testng-6.9.12/src/test/java/test/annotationtransformer/0000755000175000017500000000000012732165123022524 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/annotationtransformer/MyTransformer.java0000644000175000017500000000201012732165123026170 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class MyTransformer implements IAnnotationTransformer { private final List methodNames = new ArrayList<>(); @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { annotation.setTimeOut(10000); if (testMethod != null) { switch (testMethod.getName()) { case "three": annotation.setInvocationCount(3); break; case "four": annotation.setInvocationCount(4); break; case "five": annotation.setInvocationCount(5); break; default: break; } methodNames.add(testMethod.getName()); } } public List getMethodNames() { return methodNames; } } testng-6.9.12/src/test/java/test/annotationtransformer/DataProviderTransformer.java0000644000175000017500000000170512732165123030201 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer2; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class DataProviderTransformer implements IAnnotationTransformer2 { @Override public void transform(IConfigurationAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void transform(IDataProviderAnnotation annotation, Method testMethod) { annotation.setName("dataProvider"); } @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void transform(IFactoryAnnotation annotation, Method testMethod) { } } testng-6.9.12/src/test/java/test/annotationtransformer/MySuiteListener2.java0000644000175000017500000000051412732165123026556 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.ISuite; import org.testng.ISuiteListener; public class MySuiteListener2 implements ISuiteListener { public static boolean triggered = false; @Override public void onStart(ISuite suite) { triggered = true; } @Override public void onFinish(ISuite suite) {} } testng-6.9.12/src/test/java/test/annotationtransformer/MyTimeOutTransformer.java0000644000175000017500000000071712732165123027513 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class MyTimeOutTransformer implements IAnnotationTransformer { @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { annotation.setTimeOut(5000); // 5 seconds } } testng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerInvocationCountTest.java0000644000175000017500000000160112732165123033625 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class AnnotationTransformerInvocationCountTest { public static class InvocationCountTransformer implements IAnnotationTransformer { private final int invocationCount; public InvocationCountTransformer(int invocationCount) { this.invocationCount = invocationCount; } @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { if ("concurrencyTest".equals(testMethod.getName())) { annotation.setInvocationCount(invocationCount); } } } @Test(invocationCount = 3) public void concurrencyTest() { } } testng-6.9.12/src/test/java/test/annotationtransformer/SimpleTest.java0000644000175000017500000000040712732165123025461 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.Assert; import org.testng.annotations.Test; public class SimpleTest { private int m_n; public SimpleTest(int n) { m_n = n; } @Test public void run() { Assert.assertEquals(m_n, 42); } } testng-6.9.12/src/test/java/test/annotationtransformer/MyListenerTransformer.java0000644000175000017500000000216612732165123027712 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer3; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.IListenersAnnotation; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class MyListenerTransformer implements IAnnotationTransformer3 { @Override public void transform(IListenersAnnotation annotation, Class testClass) { annotation.setValue(new Class[]{MySuiteListener2.class}); } @Override public void transform(IConfigurationAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {} @Override public void transform(IDataProviderAnnotation annotation, Method method) {} @Override public void transform(IFactoryAnnotation annotation, Method method) {} @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {} } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootroottestng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerClassInvocationSampleTest.javatestng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerClassInvocationSampleTes0000644000175000017500000000032312732165123033640 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.annotations.Test; @Test(invocationCount = 3) public class AnnotationTransformerClassInvocationSampleTest { public void f1() {} public void f2() {} } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootroottestng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerDataProviderSampleTest.javatestng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerDataProviderSampleTest.j0000644000175000017500000000067112732165123033547 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class AnnotationTransformerDataProviderSampleTest { @DataProvider public Object[][] dp() { return new Integer[][] { new Integer[] { 42 }, }; } @Test(dataProvider = "dataProvider") public void f(Integer n) { Assert.assertEquals(n, Integer.valueOf(42)); } } testng-6.9.12/src/test/java/test/annotationtransformer/MySuiteListener.java0000644000175000017500000000051312732165123026473 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.ISuite; import org.testng.ISuiteListener; public class MySuiteListener implements ISuiteListener { public static boolean triggered = false; @Override public void onStart(ISuite suite) { triggered = true; } @Override public void onFinish(ISuite suite) {} } testng-6.9.12/src/test/java/test/annotationtransformer/FactoryTransformer.java0000644000175000017500000000171012732165123027220 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer2; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class FactoryTransformer implements IAnnotationTransformer2 { @Override public void transform(IConfigurationAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void transform(IDataProviderAnnotation annotation, Method testMethod) { } @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void transform(IFactoryAnnotation annotation, Method testMethod) { annotation.setDataProvider("dataProvider"); } } testng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerClassSampleTest.java0000644000175000017500000000123212732165123032712 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.annotations.Listeners; import org.testng.annotations.Test; /** * This test will fail unless a time out transformer * is applied to it. * * @author cbeust * */ @Test(timeOut = 1000) @Listeners(MySuiteListener.class) public class AnnotationTransformerClassSampleTest { public void one() { try { Thread.sleep(2000); // ppp("FINISHED SLEEPING"); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); // ppp("WAS INTERRUPTED"); // ignore } } private void ppp(String string) { System.out.println("[Transformer] " + string); } } testng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerSampleTest.java0000644000175000017500000000141212732165123031724 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; public class AnnotationTransformerSampleTest { private int m_two = 0; private int m_five = 0; private int m_three = 0; private int m_four = 0; @Test(invocationCount = 2) public void two() { m_two++; } @Test(invocationCount = 5) public void four() { m_four++; } @Test(invocationCount = 5) public void three() { m_three++; } @Test public void five() { m_five++; } @Test(dependsOnMethods = {"two", "three", "four", "five"}) public void verify() { Assert.assertEquals(m_two, 2); Assert.assertEquals(m_three, 3); Assert.assertEquals(m_four, 4); Assert.assertEquals(m_five, 5); } } testng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerTest.java0000644000175000017500000001723512732165123030574 0ustar eugeneeugenepackage test.annotationtransformer; import org.assertj.core.api.iterable.Extractor; import org.testng.Assert; import org.testng.IAnnotationTransformer; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.Parser; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; import java.io.ByteArrayInputStream; import java.util.Arrays; import java.util.Collection; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; public class AnnotationTransformerTest extends SimpleBaseTest { private static final Extractor NAME_EXTRACTOR = new Extractor() { @Override public String extract(ITestResult input) { return input.getName(); } }; /** * Make sure that without a transformer in place, a class-level * annotation invocationCount is correctly used. */ @Test public void verifyAnnotationWithoutTransformer() { TestNG tng = create(AnnotationTransformerSampleTest.class); tng.setPreserveOrder(true); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); assertThat(tla.getPassedTests()).extracting(NAME_EXTRACTOR) .containsExactly( "five", "four", "four", "four", "four", "four", "three", "three", "three", "three", "three", "two", "two" ); assertThat(tla.getFailedTests()).extracting(NAME_EXTRACTOR) .containsExactly("verify"); } /** * Test a transformer on a method-level @Test */ @Test public void verifyAnnotationTransformerMethod() { TestNG tng = create(AnnotationTransformerSampleTest.class); tng.setPreserveOrder(true); MyTransformer transformer = new MyTransformer(); tng.setAnnotationTransformer(transformer); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); assertThat(transformer.getMethodNames()).contains("two", "three", "four", "five", "verify"); assertThat(tla.getPassedTests()).extracting(NAME_EXTRACTOR) .containsExactly( "five", "five", "five", "five", "five", "four", "four", "four", "four", "three", "three", "three", "two", "two", "verify" ); assertThat(tla.getFailedTests()).isEmpty(); } @Test public void verifyAnnotationTransformerHasOnlyOneNonNullArgument() { TestNG tng = create(AnnotationTransformerSampleTest.class); MyParamTransformer transformer = new MyParamTransformer(); tng.setAnnotationTransformer(transformer); tng.run(); assertThat(transformer.isSuccess()).isTrue(); } @Test public void verifyMyParamTransformerOnlyOneNonNull() { assertThat(MyParamTransformer.onlyOneNonNull(null, null, null)).isFalse(); assertThat(MyParamTransformer.onlyOneNonNull( MyParamTransformer.class, MyParamTransformer.class.getConstructors()[0], null)).isFalse(); assertThat(MyParamTransformer.onlyOneNonNull(MyParamTransformer.class, null, null)).isTrue(); } /** * Without an annotation transformer, we should have zero * passed tests and one failed test called "one". */ @Test public void verifyAnnotationTransformerClass2() { runTest(null, null, "one"); } /** * With an annotation transformer, we should have one passed * test called "one" and zero failed tests. */ @Test public void verifyAnnotationTransformerClass() { runTest(new MyTimeOutTransformer(), "one", null); } private void runTest(IAnnotationTransformer transformer, String passedName, String failedName) { MySuiteListener.triggered = false; MySuiteListener2.triggered = false; TestNG tng = new TestNG(); tng.setVerbose(0); if (transformer != null) { tng.setAnnotationTransformer(transformer); } tng.setTestClasses(new Class[] { AnnotationTransformerClassSampleTest.class}); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); List results = passedName != null ? tla.getPassedTests() : tla.getFailedTests(); String name = passedName != null ? passedName : failedName; Assert.assertEquals(results.size(), 1); Assert.assertEquals(name, results.get(0).getMethod().getMethodName()); Assert.assertTrue(MySuiteListener.triggered); Assert.assertFalse(MySuiteListener2.triggered); } @Test public void verifyListenerAnnotationTransformerClass() { MySuiteListener.triggered = false; MySuiteListener2.triggered = false; TestNG tng = new TestNG(); tng.setVerbose(0); tng.setAnnotationTransformer(new MyListenerTransformer()); tng.setTestClasses(new Class[]{AnnotationTransformerClassSampleTest.class}); tng.run(); Assert.assertFalse(MySuiteListener.triggered); Assert.assertTrue(MySuiteListener2.triggered); } @Test public void verifyConfigurationTransformer() { TestNG tng = new TestNG(); tng.setAnnotationTransformer(new ConfigurationTransformer()); tng.setVerbose(0); tng.setTestClasses(new Class[] { ConfigurationSampleTest.class}); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(ConfigurationSampleTest.getBefore(), "correct"); } @Test public void verifyDataProviderTransformer() { TestNG tng = create(); tng.setAnnotationTransformer(new DataProviderTransformer()); tng.setTestClasses(new Class[] { AnnotationTransformerDataProviderSampleTest.class}); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); } @Test public void verifyFactoryTransformer() { TestNG tng = create(); tng.setAnnotationTransformer(new FactoryTransformer()); tng.setTestClasses(new Class[] { AnnotationTransformerFactorySampleTest.class}); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); } @Test(description = "Test for issue #605") public void verifyInvocationCountTransformer() { TestNG tng = create(); tng.setTestClasses(new Class[] { AnnotationTransformerInvocationCountTest.class }); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 3); tng = create(); tng.setAnnotationTransformer(new AnnotationTransformerInvocationCountTest.InvocationCountTransformer(5)); tng.setTestClasses(new Class[]{AnnotationTransformerInvocationCountTest.class}); tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 5); } @Test public void annotationTransformerInXmlShouldBeRun() throws Exception { String xml = "" + " " + " " + " " + " " + " " + " " + " " + " " + "" ; ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes()); Collection suites = new Parser(is).parse(); TestNG tng = create(); tng.setXmlSuites(Arrays.asList(suites.toArray(new XmlSuite[0]))); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); } } testng-6.9.12/src/test/java/test/annotationtransformer/ConfigurationSampleTest.java0000644000175000017500000000131012732165123030173 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ConfigurationSampleTest { private static String m_before = "uninitialized"; @BeforeClass public void beforeClass() { m_before = "correct"; } @BeforeMethod(enabled = false) public void testingEnabledOnConfiguration() { m_before = "this method is not enabled, we should not be here"; } // will be disabled by the configuration transformer @BeforeMethod public void beforeMethod() { m_before = "incorrect"; } @Test public void f() {} public static String getBefore() { return m_before; } } testng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerInTestngXml.java0000644000175000017500000000107012732165123032057 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class AnnotationTransformerInTestngXml implements IAnnotationTransformer { @Test(enabled = false) public void shouldRunAfterTransformation() {} @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { annotation.setEnabled(true); } } testng-6.9.12/src/test/java/test/annotationtransformer/AnnotationTransformerFactorySampleTest.java0000644000175000017500000000065412732165123033263 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; public class AnnotationTransformerFactorySampleTest { @DataProvider public Object[][] dataProvider() { return new Integer[][] { new Integer[] { 42 }, }; } @Factory(dataProvider = "dp") public Object[] init(int n) { return new Object[] { new SimpleTest(n) }; } } testng-6.9.12/src/test/java/test/annotationtransformer/MyParamTransformer.java0000644000175000017500000000170112732165123027157 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class MyParamTransformer implements IAnnotationTransformer { private boolean success = true; @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { if (!onlyOneNonNull(testClass, testConstructor, testMethod)) { success = false; } } public static boolean onlyOneNonNull(Class testClass, Constructor testConstructor, Method testMethod) { return ((testClass != null && testConstructor == null && testMethod == null) || (testClass == null && testConstructor != null && testMethod == null) || (testClass == null && testConstructor == null && testMethod != null) ); } public boolean isSuccess() { return success; } } testng-6.9.12/src/test/java/test/annotationtransformer/ConfigurationTransformer.java0000644000175000017500000000176512732165123030432 0ustar eugeneeugenepackage test.annotationtransformer; import org.testng.IAnnotationTransformer2; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ConfigurationTransformer implements IAnnotationTransformer2 { @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void transform(IConfigurationAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { if (annotation.getBeforeTestMethod()) { annotation.setEnabled(false); } } @Override public void transform(IDataProviderAnnotation annotation, Method testMethod) { } @Override public void transform(IFactoryAnnotation annotation, Method testMethod) { } } testng-6.9.12/src/test/java/test/yaml/0000755000175000017500000000000012732165123017031 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/yaml/YamlTest.java0000644000175000017500000000203212732165123021433 0ustar eugeneeugenepackage test.yaml; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.xml.Parser; import org.testng.xml.XmlSuite; import org.xml.sax.SAXException; import test.SimpleBaseTest; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; import java.util.Collection; public class YamlTest extends SimpleBaseTest { @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { "a1" }, new Object[] { "a2" }, new Object[] { "a3" }, new Object[] { "a4" }, }; } @Test(dataProvider = "dp") public void compareFiles(String name) throws ParserConfigurationException, SAXException, IOException { Collection s1 = new Parser(getPathToResource("yaml" + File.separator + name + ".yaml")).parse(); Collection s2 = new Parser(getPathToResource("yaml" + File.separator + name + ".xml")).parse(); Assert.assertEquals(s1, s2); } } testng-6.9.12/src/test/java/test/abstractmethods/0000755000175000017500000000000012732165123021256 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/abstractmethods/CRUDTest2.java0000644000175000017500000000023612732165123023601 0ustar eugeneeugenepackage test.abstractmethods; public class CRUDTest2 extends CRUDTest { @Override public void create() { } @Override public void read() { } } testng-6.9.12/src/test/java/test/abstractmethods/AbstractTest.java0000644000175000017500000000105712732165123024527 0ustar eugeneeugenepackage test.abstractmethods; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class AbstractTest extends SimpleBaseTest { @Test(description = "Abstract methods defined in a superclass should be run") public void abstractShouldRun() { TestNG tng = create(CRUDTest2.class); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 2); } } testng-6.9.12/src/test/java/test/abstractmethods/CRUDTest.java0000644000175000017500000000032612732165123023517 0ustar eugeneeugenepackage test.abstractmethods; import org.testng.annotations.Test; abstract public class CRUDTest { @Test public abstract void create(); @Test(dependsOnMethods = "create") public abstract void read(); } testng-6.9.12/src/test/java/test/override/0000755000175000017500000000000012732165123017706 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/override/OverrideTest.java0000644000175000017500000000350212732165123023170 0ustar eugeneeugenepackage test.override; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.internal.Utils; import org.xml.sax.SAXException; import test.SimpleBaseTest; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; import java.util.Arrays; /** * Verify that command line switches override parameters in testng.xml. * * @author Cedric Beust */ public class OverrideTest extends SimpleBaseTest { private void runTest(String include, String exclude) { File f = Utils.createTempFile( "" + " " + " " + " " + " " + " " + "" ); TestNG tng = create(); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); if (include != null) tng.setGroups(include); if (exclude != null) tng.setExcludedGroups(exclude); tng.setTestSuites(Arrays.asList(f.getAbsolutePath())); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); } @Test(description = "Override -groups") public void overrideIncludeShouldWork() throws ParserConfigurationException, SAXException, IOException { runTest("goodGroup", null); } @Test(description = "Override -excludegroups") public void overrideExcludeShouldWork() throws ParserConfigurationException, SAXException, IOException { runTest(null, "badGroup"); } @Test(description = "Override -groups and -excludegroups") public void overrideIncludeAndExcludeShouldWork() throws ParserConfigurationException, SAXException, IOException { runTest("goodGroup", "badGroup"); } } testng-6.9.12/src/test/java/test/override/OverrideSampleTest.java0000644000175000017500000000041012732165123024325 0ustar eugeneeugenepackage test.override; import org.testng.annotations.Test; public class OverrideSampleTest { @Test(groups = "goodGroup") public void good() { } @Test(groups = "badGroup") public void bad() { throw new RuntimeException("Should not happen"); } } testng-6.9.12/src/test/java/test/converter/0000755000175000017500000000000012732165123020076 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/converter/ConverterSample1.java0000644000175000017500000000067512732165123024143 0ustar eugeneeugenepackage test.converter; import junit.framework.TestCase; public class ConverterSample1 extends TestCase { @Override protected void setUp() throws Exception { super.setUp(); } @Override protected void tearDown() throws Exception { super.tearDown(); } public final void testClassJunit() { } public final void testSetClassId() { } public final void testSetClassName() { } } testng-6.9.12/src/test/java/test/nested/0000755000175000017500000000000012732165123017351 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/nested/GarfTest.java0000644000175000017500000000055212732165123021735 0ustar eugeneeugenepackage test.nested; import org.testng.Assert; import org.testng.annotations.Test; import test.nested.foo.AccountTypeEnum; @Test(groups = { "unittest" }, enabled = true ) public class GarfTest { @Test() public void testGarf() { AccountTypeEnum foo = AccountTypeEnum.ClearingMember; Assert.assertEquals(foo,AccountTypeEnum.ClearingMember); } } testng-6.9.12/src/test/java/test/nested/foo/0000755000175000017500000000000012732165123020134 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/nested/foo/AccountTypeEnum.java0000644000175000017500000000017212732165123024062 0ustar eugeneeugenepackage test.nested.foo; public class AccountTypeEnum { public static final AccountTypeEnum ClearingMember = null; } testng-6.9.12/src/test/java/test/alwaysrun/0000755000175000017500000000000012732165123020114 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/alwaysrun/AlwaysRunAfter1.java0000644000175000017500000000110512732165123023744 0ustar eugeneeugenepackage test.alwaysrun; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class AlwaysRunAfter1 { private static boolean m_success = false; @BeforeClass public void setUpShouldFail() { throw new RuntimeException("Failing in setUp"); } @AfterClass(alwaysRun = true) public void tearDown() { m_success = true; } // Adding this method or @Configuration will never be invoked @Test public void dummy() { } static public boolean success() { return m_success; } } testng-6.9.12/src/test/java/test/alwaysrun/AlwaysRunTest.java0000644000175000017500000000315612732165123023551 0ustar eugeneeugenepackage test.alwaysrun; import static org.testng.Assert.assertTrue; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import testhelper.OutputDirectoryPatch; public class AlwaysRunTest extends SimpleBaseTest { @Test public void withAlwaysRunAfter() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = create(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(new Class[] { AlwaysRunAfter1.class }); testng.addListener(tla); testng.run(); assertTrue(AlwaysRunAfter1.success(), "afterTestMethod should have run"); } @Test public void withoutAlwaysRunAfter() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = create(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(new Class[] { AlwaysRunAfter2.class }); testng.addListener(tla); testng.run(); assertTrue(AlwaysRunAfter2.success(), "afterTestMethod should not have run"); } @Test public void withoutAlwaysRunBefore() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng = create(); testng.setOutputDirectory(OutputDirectoryPatch.getOutputDirectory()); testng.setTestClasses(new Class[] { AlwaysRunBefore1.class }); testng.setGroups("A"); testng.addListener(tla); testng.run(); assertTrue(AlwaysRunBefore1.success(), "before alwaysRun methods should have been run"); } private static void ppp(String s) { System.out.println("[AlwaysRunTest] " + s); } } testng-6.9.12/src/test/java/test/alwaysrun/AlwaysRunBefore1.java0000644000175000017500000000270612732165123024115 0ustar eugeneeugenepackage test.alwaysrun; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; /** * Tests alwaysRun on a before Configuration method. Invoke this test * by running group "A" * * @author cbeust * @date Mar 11, 2006 */ public class AlwaysRunBefore1 { private static boolean m_beforeSuiteSuccess = false; private static boolean m_beforeTestSuccess = false; private static boolean m_beforeTestClassSuccess = false; private static boolean m_beforeTestMethodSuccess = false; @BeforeSuite(alwaysRun = true) public void initSuite() { m_beforeSuiteSuccess = true; } @BeforeTest(alwaysRun = true) public void initTest() { m_beforeTestSuccess = true; } @BeforeClass(alwaysRun = true) public void initTestClass() { m_beforeTestClassSuccess = true; } @BeforeMethod(alwaysRun = true) public void initTestMethod() { m_beforeTestMethodSuccess = true; } @Test(groups = "A") public void foo() { Assert.assertTrue(m_beforeSuiteSuccess); Assert.assertTrue(m_beforeTestSuccess); Assert.assertTrue(m_beforeTestClassSuccess); Assert.assertTrue(m_beforeTestMethodSuccess); } public static boolean success() { return m_beforeSuiteSuccess && m_beforeTestSuccess && m_beforeTestClassSuccess && m_beforeTestMethodSuccess; } } testng-6.9.12/src/test/java/test/alwaysrun/AlwaysRunAfter2.java0000644000175000017500000000070112732165123023746 0ustar eugeneeugenepackage test.alwaysrun; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; public class AlwaysRunAfter2 { private static boolean m_success = true; @BeforeClass public void setUpShouldFail() { throw new RuntimeException("Failing in setUp"); } // Should not be run @AfterClass public void tearDown() { m_success = false; } static public boolean success() { return m_success; } } testng-6.9.12/src/test/java/test/InvokedMethodNameListener.java0000644000175000017500000000342612732165123024006 0ustar eugeneeugenepackage test; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import java.util.ArrayList; import java.util.Collections; import java.util.List; // TODO replace other test IInvokedMethodListener by this one public class InvokedMethodNameListener implements IInvokedMethodListener { private final List invokedMethodNames = new ArrayList<>(); private final List failedMethodNames = new ArrayList<>(); private final List skippedMethodNames = new ArrayList<>(); private final List succeedMethodNames = new ArrayList<>(); @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { invokedMethodNames.add(method.getTestMethod().getConstructorOrMethod().getName()); } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { switch (testResult.getStatus()) { case ITestResult.FAILURE: failedMethodNames.add(method.getTestMethod().getConstructorOrMethod().getName()); break; case ITestResult.SKIP: skippedMethodNames.add(method.getTestMethod().getConstructorOrMethod().getName()); break; case ITestResult.SUCCESS: succeedMethodNames.add(method.getTestMethod().getConstructorOrMethod().getName()); break; default: throw new AssertionError("Unexpected value: " + testResult.getStatus()); } } public List getInvokedMethodNames() { return Collections.unmodifiableList(invokedMethodNames); } public List getFailedMethodNames() { return failedMethodNames; } public List getSkippedMethodNames() { return skippedMethodNames; } public List getSucceedMethodNames() { return succeedMethodNames; } } testng-6.9.12/src/test/java/test/testng285/0000755000175000017500000000000012732165123017632 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/testng285/Derived.java0000644000175000017500000000037512732165123022064 0ustar eugeneeugenepackage test.testng285; import org.testng.annotations.Test; public class Derived extends BugBase { @Test public void f1() { log(Thread.currentThread().getId()); } @Test public void f2() { log(Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/testng285/BugBase.java0000644000175000017500000000070212732165123022004 0ustar eugeneeugenepackage test.testng285; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.HashSet; import java.util.Set; @Test(sequential = true) public class BugBase { static Set m_threadIds; @BeforeClass public void setup() { m_threadIds = new HashSet<>(); } void log(long threadId) { m_threadIds.add(threadId); } public void fbase() { log(Thread.currentThread().getId()); } } testng-6.9.12/src/test/java/test/testng285/TestNG285Test.java0000644000175000017500000000063412732165123022743 0ustar eugeneeugenepackage test.testng285; import org.testng.Assert; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.BaseTest; public class TestNG285Test extends BaseTest { @Test public void verifyBug() { addClass("test.testng285.Derived"); setParallel(XmlSuite.ParallelMode.METHODS); setThreadCount(5); run(); Assert.assertEquals(BugBase.m_threadIds.size(), 1); } } testng-6.9.12/src/test/java/test/multiplelisteners/0000755000175000017500000000000012732165123021653 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/multiplelisteners/TestMaker.java0000755000175000017500000000270012732165123024417 0ustar eugeneeugenepackage test.multiplelisteners; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.util.Arrays; import java.util.Collections; import java.util.List; public class TestMaker { @Test(description = "Make sure only one listener is created and not 2^3") public void run() { final TestNG tng = new TestNG(); tng.setUseDefaultListeners(false); tng.setListenerClasses(Arrays. asList(TestListenerAdapter.class, SimpleReporter.class)); final List suites = createSuites(); tng.setXmlSuites(suites); tng.setVerbose(0); tng.run(); // Reporter.log(tng.getSuiteListeners().size() + "", true); // for (final XmlSuite xmlSuite : suites) // { // Reporter.log(xmlSuite.getName() + ": " + xmlSuite.getListeners().size(), true); // } } private List createSuites() { final List ret = Lists.newArrayList(); for (int i = 0; i < 3; i++) { ret.add(createSuite(i)); } return ret; } private XmlSuite createSuite(final int nr) { final XmlSuite suite = new XmlSuite(); suite.setName("Suite_" + nr); new XmlTest(suite).setXmlClasses(Collections.singletonList(new XmlClass(Test1.class))); return suite; } } testng-6.9.12/src/test/java/test/multiplelisteners/Test1.java0000755000175000017500000000025712732165123023525 0ustar eugeneeugenepackage test.multiplelisteners; import org.testng.annotations.Test; @Test public class Test1 { public void test() { // Reporter.log("test1", true); } } testng-6.9.12/src/test/java/test/multiplelisteners/SimpleReporter.java0000755000175000017500000000177212732165123025504 0ustar eugeneeugenepackage test.multiplelisteners; import org.testng.IReporter; import org.testng.ISuite; import org.testng.SuiteRunner; import org.testng.TestListenerAdapter; import org.testng.internal.IConfiguration; import org.testng.xml.XmlSuite; import test.listeners.ListenerAssert; import java.lang.reflect.Field; import java.util.List; public class SimpleReporter implements IReporter { @Override public void generateReport(final List xmlSuites, final List suites, final String outputDirectory) { for (final ISuite iSuite : suites) { try { final Field field = SuiteRunner.class.getDeclaredField("m_configuration"); field.setAccessible(true); final IConfiguration conf = (IConfiguration) field.get(iSuite); ListenerAssert.assertListenerType(conf.getConfigurationListeners(), TestListenerAdapter.class); } catch (final Exception e) { throw new RuntimeException(e); } } } } testng-6.9.12/src/test/java/test/Misc.java0000644000175000017500000000127612732165123017633 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; /** * This class * * @author cbeust */ public class Misc extends BaseTest { @Test public void makeSureSetUpWithParameterWithNoParametersFails() { addClass("test.sample.SetUpWithParameterTest"); setVerbose(0); // setParallel(XmlSuite.PARALLEL_METHODS); run(); String[] passed = { }; // @Configuration failures are not reported in the ITestListener String[] failed = { }; String[] skipped = { "test", }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); verifyTests("Failed", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/parameters/0000755000175000017500000000000012732165123020232 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/parameters/InheritFromSuiteChild1.java0000644000175000017500000000127112732165123025363 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * Checks to see if the parameters from parent suite are passed onto the * child suite (referred by ) * @author nullin * */ public class InheritFromSuiteChild1 { @Test @Parameters({"parameter1", "parameter2", "parameter3", "parameter4"}) public void inheritedparameter(String p1, String p2, @Optional("foobar")String p3, String p4) { Assert.assertEquals(p1, "p1"); Assert.assertEquals(p2, "c1p2"); Assert.assertEquals(p3, "foobar"); Assert.assertEquals(p4, "c1p4"); } } testng-6.9.12/src/test/java/test/parameters/SampleTest.java0000644000175000017500000000023512732165123023156 0ustar eugeneeugenepackage test.parameters; import org.testng.annotations.Test; public class SampleTest { @Test public void foo() { //purposefully does nothing } } testng-6.9.12/src/test/java/test/parameters/ParameterSample.java0000644000175000017500000000273612732165123024167 0ustar eugeneeugenepackage test.parameters; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import org.testng.xml.Parser; import java.io.ByteArrayInputStream; /** * This class * * @author Cedric Beust, Jul 22, 2004 * */ public class ParameterSample { @Parameters({ "first-name" }) @BeforeMethod public void beforeTest(String firstName) { // System.out.println("[ParameterSample] Invoked beforeTestMethod with: " + firstName); assert "Cedric".equals(firstName) : "Expected Cedric, got " + firstName; } @Parameters({ "first-name" }) @Test(groups = { "singleString"}) public void testSingleString(String firstName) { // System.out.println("[ParameterSample] Invoked testString " + firstName); assert "Cedric".equals(firstName); } @Parameters({"this parameter doesn't exist"}) @Test public void testNonExistentParameter(@Optional String foo) { } public static void main(String[] args) throws Exception { TestNG tng = new TestNG(); String xml = ""; System.out.println(xml); ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes()); tng.setXmlSuites(new Parser(is).parseToList()); tng.run(); } } testng-6.9.12/src/test/java/test/parameters/OptionalParameterTest.java0000644000175000017500000000035512732165123025366 0ustar eugeneeugenepackage test.parameters; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; public class OptionalParameterTest { @Parameters("optional") public OptionalParameterTest(@Optional String optional) {} } testng-6.9.12/src/test/java/test/parameters/BeforeSampleTest.java0000644000175000017500000000133012732165123024276 0ustar eugeneeugenepackage test.parameters; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import junit.framework.Assert; public class BeforeSampleTest { @BeforeMethod @Parameters("parameter") public static void beforeMethod(String parameter) { Assert.assertEquals("parameter value", parameter); } @DataProvider(name = "dataProvider") public static Object[][] dataProvider() { return new Object[][]{{"abc", "def"}}; } @Test(dataProvider = "dataProvider") public static void testExample(String a, String b) { Assert.assertEquals("abc", a); Assert.assertEquals("def", b); } }testng-6.9.12/src/test/java/test/parameters/Shadow2SampleTest.java0000644000175000017500000000041412732165123024405 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class Shadow2SampleTest { @Parameters("a") @Test public void test2(String a) { Assert.assertEquals("Second", a); } } testng-6.9.12/src/test/java/test/parameters/ParamInheritanceTest.java0000644000175000017500000000417612732165123025157 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.Arrays; public class ParamInheritanceTest extends SimpleBaseTest { @Test(description = "When verbose is set to >1, TNG prints test results on CLI which are printed " + "using SuiteResultCounts.calculateResultCounts(). This method has been throwing NPE " + "because it's unable to find SuiteRunner in HashMap, because the list of parameters in " + "SuiteRunner changed" + " during execution. This test makes sure we dont run into any NPEs") public void noNPEInCountingResults() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.setTestSuites(Arrays.asList(getPathToResource("param-inheritance/parent-suite.xml"))); tng.setVerbose(2); tng.addListener(tla); OutputStream os = new ByteArrayOutputStream(); PrintStream out = System.out; PrintStream err = System.err; try { /* * Changing system print streams so that exception or results stmt is not logged * while running test (avoid confusing person running tests) */ System.setOut(new PrintStream(os)); System.setErr(new PrintStream(os)); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 1); } finally { try { os.close(); } catch (IOException e) { //no need to handle this } System.setOut(out); System.setErr(err); } } @Test(description = "Checks to make sure parameters are inherited and overridden properly") public void parameterInheritanceAndOverriding() { TestListenerAdapter tla = new TestListenerAdapter(); TestNG tng = create(); tng.setUseDefaultListeners(false); tng.setTestSuites(Arrays.asList(getPathToResource("parametertest/parent-suite.xml"))); tng.addListener(tla); tng.run(); Assert.assertEquals(tla.getPassedTests().size(), 3); } } testng-6.9.12/src/test/java/test/parameters/InheritFromSuiteChild2.java0000644000175000017500000000126312732165123025365 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * Checks to see if the parameters from parent suite are passed onto the * child suite (referred by ) * @author nullin * */ public class InheritFromSuiteChild2 { @Test @Parameters({"parameter1", "parameter2", "parameter3", "parameter4"}) public void inheritedparameter(String p1, String p2, String p3, @Optional("abc")String p4) { Assert.assertEquals(p1, "p1"); Assert.assertEquals(p2, "c2p2"); Assert.assertEquals(p3, "c2p3"); Assert.assertEquals(p4, "abc"); } } testng-6.9.12/src/test/java/test/parameters/Shadow1SampleTest.java0000644000175000017500000000041312732165123024403 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class Shadow1SampleTest { @Parameters("a") @Test public void test1(String a) { Assert.assertEquals("First", a); } } testng-6.9.12/src/test/java/test/parameters/ParameterTest.java0000644000175000017500000000177712732165123023671 0ustar eugeneeugenepackage test.parameters; import org.testng.annotations.Test; import test.BaseTest; /** * This class * * @author Cedric Beust, Jul 22, 2004 * */ public class ParameterTest extends BaseTest { public static void ppp(String s) { System.out.println("[ParameterTest] " + s); } @Test public void stringSingle() { addClass("test.parameters.ParameterSample"); setParameter("first-name", "Cedric"); run(); String[] passed = { "testSingleString", "testNonExistentParameter", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } @Test public void beforeMethodWithParameters() { addClass("test.parameters.BeforeSampleTest"); setParameter("parameter", "parameter value"); run(); String[] passed = { "testExample", }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/parameters/ShadowTest.java0000644000175000017500000000254112732165123023164 0ustar eugeneeugenepackage test.parameters; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; public class ShadowTest extends SimpleBaseTest { @Test public void parametersShouldNotBeShadowed() { XmlSuite s = createXmlSuite("s"); XmlTest t = createXmlTest(s, "t"); { XmlClass c1 = new XmlClass(Shadow1SampleTest.class.getName()); XmlInclude include1 = new XmlInclude("test1"); include1.setXmlClass(c1); c1.getLocalParameters().put("a", "First"); c1.getIncludedMethods().add(include1); t.getXmlClasses().add(c1); } { XmlClass c2 = new XmlClass(Shadow2SampleTest.class.getName()); XmlInclude include2 = new XmlInclude("test2"); include2.setXmlClass(c2); c2.getLocalParameters().put("a", "Second"); c2.getIncludedMethods().add(include2); t.getXmlClasses().add(c2); } TestNG tng = create(); tng.setXmlSuites(Arrays.asList(s)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); // System.out.println(s.toXml()); assertTestResultsEqual(tla.getPassedTests(), Arrays.asList("test1", "test2")); } } testng-6.9.12/src/test/java/test/parameters/ParameterOverrideTest.java0000644000175000017500000000464412732165123025365 0ustar eugeneeugenepackage test.parameters; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; public class ParameterOverrideTest extends SimpleBaseTest { enum S { FAIL, PASS_TEST, PASS_CLASS, PASS_INCLUDE, } @Test public void testOverrideSuite() { privateTestOverrideSuite(S.PASS_TEST); } @Test(expectedExceptions = AssertionError.class) public void testOverrideSuiteNegative() { privateTestOverrideSuite(S.FAIL); } @Test public void classOverrideSuite() { privateTestOverrideSuite(S.PASS_CLASS); } @Test(expectedExceptions = AssertionError.class) public void classOverrideSuiteNegative() { privateTestOverrideSuite(S.FAIL); } @Test public void includeOverrideClass() { privateTestOverrideSuite(S.PASS_INCLUDE); } @Test(expectedExceptions = AssertionError.class) public void includeOverrideClassNegative() { privateTestOverrideSuite(S.FAIL); } public void privateTestOverrideSuite(S status) { XmlSuite s = createXmlSuite("s"); s.getParameters().put("a", "Incorrect"); s.getParameters().put("InheritedFromSuite", "InheritedFromSuite"); XmlTest t = createXmlTest(s, "t"); t.getLocalParameters().put("InheritedFromTest", "InheritedFromTest"); if (status == S.PASS_TEST) { t.getLocalParameters().put("a", "Correct"); } { XmlClass c1 = new XmlClass(Override1Sample.class.getName()); c1.getLocalParameters().put("InheritedFromClass", "InheritedFromClass"); if (status == S.PASS_CLASS) { c1.getLocalParameters().put("a", "Correct"); } t.getXmlClasses().add(c1); for (String method : new String[] { "f", "g" }) { XmlInclude include1 = new XmlInclude(method); if (status == S.PASS_INCLUDE) { include1.getLocalParameters().put("a", "Correct"); } include1.setXmlClass(c1); c1.getIncludedMethods().add(include1); } } TestNG tng = create(); tng.setXmlSuites(Arrays.asList(s)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); // System.out.println(s.toXml()); // tng.setVerbose(10); tng.run(); assertTestResultsEqual(tla.getPassedTests(), Arrays.asList("f", "g")); } } testng-6.9.12/src/test/java/test/parameters/InheritFromSuiteChild3.java0000644000175000017500000000117412732165123025367 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * Checks to see if the parameters from parent suite are passed onto the * child suite (referred by ) * @author nullin * */ public class InheritFromSuiteChild3 { @Test @Parameters({"parameter1", "parameter2", "parameter3", "parameter4"}) public void inheritedparameter(String p1, String p2, String p3, String p4) { Assert.assertEquals(p1, "p1"); Assert.assertEquals(p2, "c3p2"); Assert.assertEquals(p3, "c2p3"); Assert.assertEquals(p4, "c3p4"); } } testng-6.9.12/src/test/java/test/parameters/Override1Sample.java0000644000175000017500000000115212732165123024076 0ustar eugeneeugenepackage test.parameters; import org.testng.Assert; import org.testng.annotations.Parameters; import org.testng.annotations.Test; @Test public class Override1Sample { @Parameters({"InheritedFromSuite", "InheritedFromTest", "InheritedFromClass"}) public void g(String suite, String test, String cls) { Assert.assertEquals(suite, "InheritedFromSuite"); Assert.assertEquals(test, "InheritedFromTest"); Assert.assertEquals(cls, "InheritedFromClass"); } public void h() { System.out.println("h()"); } @Parameters("a") public void f(String p) { Assert.assertEquals(p, "Correct"); } } testng-6.9.12/src/test/java/test/parameters/SuiteSampleTest.java0000644000175000017500000000052412732165123024171 0ustar eugeneeugenepackage test.parameters; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Parameters; public class SuiteSampleTest { @Parameters({"param"}) @BeforeSuite public void suiteParameter(String s) { ppp("PARAM:" + s); } private void ppp(String s) { System.out.println("[SuiteSampleTest] " + s); } } testng-6.9.12/src/test/java/test/methods/0000755000175000017500000000000012732165123017532 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/methods/SampleMethod1.java0000644000175000017500000000175512732165123023050 0ustar eugeneeugenepackage test.methods; import org.testng.annotations.Test; /** * This class is used to test invocation of methods * * @author cbeust */ public class SampleMethod1 { private static boolean m_ok1 = false; private static boolean m_ok2 = false; private static boolean m_ok3 = true; private static boolean m_ok4 = true; public static void reset() { m_ok1 = false; m_ok2 = false; m_ok3 = true; m_ok4 = true; } @Test(groups = { "sample1" }) public void shouldRun1() { m_ok1 = true; } @Test(groups = { "sample1" }) public void shouldRun2() { m_ok2 = true; } @Test public void shouldNotRun1() { m_ok3 = false; } @Test public void shouldNotRun2() { m_ok4 = false; } public static void verify() { assert m_ok1 && m_ok2 && m_ok3 && m_ok4 : "All booleans should be true: " + m_ok1 + " " + m_ok2 + " " + m_ok3 + " " + m_ok4; } static private void ppp(String s) { System.out.println("[SampleMethod1] " + s); } } testng-6.9.12/src/test/java/test/methods/VerifyMethod1.java0000644000175000017500000000061412732165123023064 0ustar eugeneeugenepackage test.methods; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; /** * This class verifies that the correct methods were run * * @author cbeust */ @Test(dependsOnGroups = { "sample1" }) public class VerifyMethod1 { @BeforeSuite public void init() { SampleMethod1.reset(); } @Test public void verify() { SampleMethod1.verify(); } } testng-6.9.12/src/test/java/test/mixed/0000755000175000017500000000000012732165123017175 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/mixed/JUnit3Test1.java0000644000175000017500000000041712732165123022077 0ustar eugeneeugenepackage test.mixed; import junit.framework.TestCase; /** * * @author lukas */ public class JUnit3Test1 extends TestCase { public JUnit3Test1(String name) { super(name); } public void testA() { } public void testB() { } } testng-6.9.12/src/test/java/test/mixed/MixedTest.java0000644000175000017500000000407412732165123021753 0ustar eugeneeugenepackage test.mixed; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.BaseTest; import testhelper.OutputDirectoryPatch; /** * * @author lukas */ public class MixedTest extends BaseTest { @Test public void mixedWithExcludedGroups() { String[] argv = { "-d", OutputDirectoryPatch.getOutputDirectory(), "-log", "0", "-mixed", "-groups", "unit", "-excludegroups", "ignore", "-testclass", "test.mixed.JUnit3Test1,test.mixed.JUnit4Test1,test.mixed.TestNGTest1,test.mixed.TestNGGroups" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); Assert.assertEquals(tla.getPassedTests().size(), 5); //2 from junit3test1, 2 from junit4test1, 0 from testngtest1 (no groups), 1 from testnggroups (1 is included, 1 is excluded) Assert.assertEquals(tla.getFailedTests().size(), 0); } @Test public void mixedClasses() { String[] argv = { "-d", OutputDirectoryPatch.getOutputDirectory(), "-log", "0", "-mixed", "-testclass", "test.mixed.JUnit3Test1,test.mixed.JUnit4Test1,test.mixed.TestNGTest1" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); Assert.assertEquals(tla.getPassedTests().size(), 6); Assert.assertEquals(tla.getFailedTests().size(), 0); } @Test public void mixedMethods() { String[] argv = { "-d", OutputDirectoryPatch.getOutputDirectory(), "-mixed", "-log", "0", "-methods", "test.mixed.JUnit3Test1.testB,test.mixed.JUnit4Test1.atest,test.mixed.TestNGTest1.tngCustomTest1" }; TestListenerAdapter tla = new TestListenerAdapter(); TestNG.privateMain(argv, tla); Assert.assertEquals(tla.getPassedTests().size(), 3); Assert.assertEquals(tla.getFailedTests().size(), 0); } } testng-6.9.12/src/test/java/test/mixed/TestNGTest1.java0000644000175000017500000000033012732165123022121 0ustar eugeneeugenepackage test.mixed; import org.testng.annotations.Test; /** * * @author lukas */ public class TestNGTest1 { @Test public void tngTest1() { } @Test public void tngCustomTest1() { } } testng-6.9.12/src/test/java/test/mixed/JUnit4Test1.java0000644000175000017500000000027612732165123022103 0ustar eugeneeugenepackage test.mixed; import org.junit.Test; /** * * @author lukas */ public class JUnit4Test1 { @Test public void atest() { } @Test public void bTest() { } } testng-6.9.12/src/test/java/test/mixed/TestNGGroups.java0000644000175000017500000000035612732165123022410 0ustar eugeneeugenepackage test.mixed; import org.testng.annotations.Test; @Test(groups = {"unit"}) public class TestNGGroups { @Test public void tngTest1() { } @Test(groups = {"ignore"}) public void tngShouldBeIgnored() { } } testng-6.9.12/src/test/java/test/ReturnValueSampleTest.java0000644000175000017500000000022112732165123023203 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; public class ReturnValueSampleTest { @Test public int shouldRun() { return 0; } } testng-6.9.12/src/test/java/test/nested2/0000755000175000017500000000000012732165123017433 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/nested2/TmpA.java0000644000175000017500000000100212732165123021130 0ustar eugeneeugenepackage test.nested2; import org.testng.annotations.Test; public class TmpA { public static class NestedAWithTest { @Test public void nestedA() {} } public static class NestedAWithoutTest { public NestedAWithoutTest() { throw new RuntimeException("TestNG should not instantiate me"); } public void nestedA() {} } @Test public static class DummyBase {} public static class NestedAWithInheritedTest extends DummyBase { public void nestedWithInheritedTest() {} } }testng-6.9.12/src/test/java/test/ReturnValueTest.java0000644000175000017500000000276512732165123022060 0ustar eugeneeugenepackage test; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.util.Arrays; public class ReturnValueTest extends SimpleBaseTest { private XmlSuite m_suite; private XmlTest m_test; @BeforeMethod public void before() { m_suite = createXmlSuite("suite"); m_test = createXmlTest(m_suite, "test", ReturnValueSampleTest.class.getName()); } @Test public void suiteReturnValueTestShouldBeRun() { m_suite.setAllowReturnValues(true); runTest(true); } @Test public void suiteReturnValueTestShouldNotBeRun() { runTest(false); } @Test public void testReturnValueTestShouldBeRun() { m_test.setAllowReturnValues(true); runTest(true); } private void runTest(boolean allowed) { TestNG tng = create(); tng.setXmlSuites(Arrays.asList(m_suite)); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); if (allowed) { Assert.assertEquals(tla.getFailedTests().size(), 0); Assert.assertEquals(tla.getSkippedTests().size(), 0); assertTestResultsEqual(tla.getPassedTests(), Arrays.asList("shouldRun")); } else { Assert.assertEquals(tla.getFailedTests().size(), 0); Assert.assertEquals(tla.getPassedTests().size(), 0); Assert.assertEquals(tla.getSkippedTests().size(), 0); } } } testng-6.9.12/src/test/java/test/bug90/0000755000175000017500000000000012732165123017015 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/bug90/Bug90Test.java0000644000175000017500000000152712732165123021413 0ustar eugeneeugenepackage test.bug90; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; public class Bug90Test extends SimpleBaseTest { @Test(description = "Fix for https://github.com/cbeust/testng/issues/90") public void afterClassShouldRun() { XmlSuite s = createXmlSuite("Bug90"); XmlTest t = createXmlTest(s, "Bug90 test", Sample.class.getName()); XmlClass c = t.getClasses().get(0); c.setIncludedMethods(Arrays.asList(new XmlInclude("test1"))); TestNG tng = create(); tng.setXmlSuites(Arrays.asList(s)); Sample.m_afterClassWasRun = false; tng.run(); Assert.assertTrue(Sample.m_afterClassWasRun); } } testng-6.9.12/src/test/java/test/bug90/Sample.java0000644000175000017500000000050512732165123021101 0ustar eugeneeugenepackage test.bug90; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; public class Sample { static boolean m_afterClassWasRun = false; @Test public void test1() { } @Test public void test2() { } @AfterClass public void afterClass() { m_afterClassWasRun = true; } } testng-6.9.12/src/test/java/test/guice/0000755000175000017500000000000012732165123017163 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/guice/GuiceBase.java0000644000175000017500000000020212732165123021647 0ustar eugeneeugenepackage test.guice; import org.testng.annotations.Guice; @Guice(modules = GuiceExampleModule.class) public class GuiceBase { } testng-6.9.12/src/test/java/test/guice/MyContextImpl.java0000644000175000017500000000031212732165123022576 0ustar eugeneeugenepackage test.guice; public class MyContextImpl implements MyContext { private final MySession mySession = new MySession(); @Override public MySession getSession() { return mySession; } } testng-6.9.12/src/test/java/test/guice/GuiceParentModule.java0000644000175000017500000000110212732165123023374 0ustar eugeneeugenepackage test.guice; import com.google.inject.AbstractModule; import com.google.inject.Inject; import com.google.inject.Singleton; import org.testng.ITestContext; public class GuiceParentModule extends AbstractModule { private final ITestContext context; public GuiceParentModule(ITestContext context) { this.context = context; } @Override protected void configure() { bind(MyService.class).toProvider(MyServiceProvider.class); bind(MyContext.class).to(MyContextImpl.class).in(Singleton.class); bind(ITestContext.class).toInstance(context); } } testng-6.9.12/src/test/java/test/guice/GuiceExampleModule.java0000644000175000017500000000047712732165123023554 0ustar eugeneeugenepackage test.guice; import com.google.inject.Binder; import com.google.inject.Module; import com.google.inject.Singleton; public class GuiceExampleModule implements Module { @Override public void configure(Binder binder) { binder.bind(ISingleton.class).to(ExampleSingleton.class).in(Singleton.class); } } testng-6.9.12/src/test/java/test/guice/GuiceParentModuleTest.java0000644000175000017500000000124712732165123024246 0ustar eugeneeugenepackage test.guice; import org.testng.Assert; import org.testng.ITestContext; import org.testng.annotations.Guice; import org.testng.annotations.Test; import com.google.inject.Inject; @Test @Guice(modules = GuiceTestModule.class) public class GuiceParentModuleTest { @Inject MySession mySession; @Inject MyService myService; @Inject ITestContext context; public void testService() { Assert.assertNotNull(myService); Assert.assertNotNull(mySession); myService.serve(mySession); Assert.assertNotNull(context); Assert.assertEquals(context.getName(), "Guice"); Assert.assertEquals(context.getSuite().getName(), "parent-module-suite"); } } testng-6.9.12/src/test/java/test/guice/ModuleFactory.java0000644000175000017500000000132412732165123022603 0ustar eugeneeugenepackage test.guice; import com.google.inject.Module; import org.testng.IModuleFactory; import org.testng.ITestContext; public class ModuleFactory implements IModuleFactory { @Override public Module createModule(ITestContext context, Class testClass) { String parameter = context.getCurrentXmlTest().getParameter("inject"); String expected = "guice"; if (! expected.equals(parameter)) { throw new RuntimeException("Excepted parameter to be " + expected + ", got " + parameter); } if (GuiceModuleFactoryTest.class == testClass) { return new GuiceExampleModule(); } else { throw new RuntimeException("Don't know how to create a module for class " + testClass); } } } testng-6.9.12/src/test/java/test/guice/Guice2Test.java0000644000175000017500000000061712732165123022010 0ustar eugeneeugenepackage test.guice; import com.google.inject.Inject; import org.testng.annotations.Guice; import org.testng.annotations.Test; import test.SimpleBaseTest; @Guice(modules = GuiceExampleModule.class) public class Guice2Test extends SimpleBaseTest { static ISingleton m_object; @Inject ISingleton m_singleton; @Test public void singletonShouldWork() { m_object = m_singleton; } } testng-6.9.12/src/test/java/test/guice/GuiceNoModuleTest.java0000644000175000017500000000025212732165123023364 0ustar eugeneeugenepackage test.guice; import org.testng.annotations.Guice; import org.testng.annotations.Test; @Guice public class GuiceNoModuleTest { @Test public void f() { } } testng-6.9.12/src/test/java/test/guice/GuiceModuleFactoryTest.java0000644000175000017500000000051412732165123024420 0ustar eugeneeugenepackage test.guice; import com.google.inject.Inject; import org.testng.annotations.Guice; import org.testng.annotations.Test; @Guice(moduleFactory = ModuleFactory.class) public class GuiceModuleFactoryTest { @Inject ISingleton m_singleton; @Test public void singletonShouldWork() { m_singleton.doSomething(); } } testng-6.9.12/src/test/java/test/guice/GuiceTest.java0000644000175000017500000000125312732165123021723 0ustar eugeneeugenepackage test.guice; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import junit.framework.Assert; public class GuiceTest extends SimpleBaseTest { @Test public void guiceTest() { TestNG tng = create(new Class[] { Guice1Test.class, Guice2Test.class}); Guice1Test.m_object = null; Guice2Test.m_object = null; tng.run(); Assert.assertNotNull(Guice1Test.m_object); Assert.assertNotNull(Guice2Test.m_object); Assert.assertEquals(Guice1Test.m_object, Guice2Test.m_object); } @Test public void guiceWithNoModules() { TestNG tng = create(new Class[] { GuiceNoModuleTest.class }); tng.run(); } } testng-6.9.12/src/test/java/test/guice/ISingleton.java0000644000175000017500000000011412732165123022075 0ustar eugeneeugenepackage test.guice; public interface ISingleton { void doSomething(); } testng-6.9.12/src/test/java/test/guice/MyServiceProvider.java0000644000175000017500000000042212732165123023445 0ustar eugeneeugenepackage test.guice; import com.google.inject.Provider; public class MyServiceProvider implements Provider { @Override public MyService get() { return new MyService() { @Override public void serve(MySession mySession) { } }; } } testng-6.9.12/src/test/java/test/guice/MyService.java0000644000175000017500000000013012732165123021726 0ustar eugeneeugenepackage test.guice; public interface MyService { void serve(MySession mySession); } testng-6.9.12/src/test/java/test/guice/MyContext.java0000644000175000017500000000011712732165123021757 0ustar eugeneeugenepackage test.guice; public interface MyContext { MySession getSession(); } testng-6.9.12/src/test/java/test/guice/MySession.java0000644000175000017500000000006112732165123021754 0ustar eugeneeugenepackage test.guice; public class MySession { } testng-6.9.12/src/test/java/test/guice/GuiceInheritanceTest.java0000644000175000017500000000041312732165123024072 0ustar eugeneeugenepackage test.guice; import com.google.inject.Inject; import org.testng.annotations.Test; public class GuiceInheritanceTest extends GuiceBase { @Inject ISingleton m_singleton; @Test public void singletonShouldWork() { m_singleton.doSomething(); } } testng-6.9.12/src/test/java/test/guice/Guice1Test.java0000644000175000017500000000065612732165123022012 0ustar eugeneeugenepackage test.guice; import com.google.inject.Inject; import org.testng.annotations.Guice; import org.testng.annotations.Test; import test.SimpleBaseTest; @Guice(modules = GuiceExampleModule.class) public class Guice1Test extends SimpleBaseTest { static ISingleton m_object; @Inject ISingleton m_singleton; @Test public void singletonShouldWork() { m_singleton.doSomething(); m_object = m_singleton; } } testng-6.9.12/src/test/java/test/guice/ExampleSingleton.java0000644000175000017500000000025212732165123023303 0ustar eugeneeugenepackage test.guice; public class ExampleSingleton implements ISingleton { @Override public void doSomething() { // System.out.println("Doing something"); } } testng-6.9.12/src/test/java/test/guice/GuiceTestModule.java0000644000175000017500000000060312732165123023067 0ustar eugeneeugenepackage test.guice; import com.google.inject.AbstractModule; import com.google.inject.Inject; public class GuiceTestModule extends AbstractModule { private final MyContext myContext; @Inject GuiceTestModule(MyContext myContext) { this.myContext = myContext; } @Override protected void configure() { bind(MySession.class).toInstance(myContext.getSession()); } } testng-6.9.12/src/test/java/test/dataprovider/0000755000175000017500000000000012732165123020553 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/dataprovider/ExplicitDataProviderNameTest.java0000644000175000017500000000123312732165123027144 0ustar eugeneeugenepackage test.dataprovider; import static org.testng.Assert.assertEquals; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class ExplicitDataProviderNameTest extends SimpleBaseTest { @Test(description = "TESTNG-576: Prefer DataProvider explicit name") public void should_prefer_dataProvider_explicit_name() { TestNG testng = create(ExplicitDataProviderNameSample.class); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.run(); assertEquals(tla.getPassedTests().size(), 1, "All tests should success"); } }testng-6.9.12/src/test/java/test/dataprovider/StaticDataProviderSampleTest.java0000644000175000017500000000231312732165123027153 0ustar eugeneeugenepackage test.dataprovider; import com.google.inject.AbstractModule; import com.google.inject.name.Names; import org.testng.Assert; import org.testng.annotations.Guice; import org.testng.annotations.Test; @Guice(modules = StaticDataProviderSampleTest.InjectionProviderModule.class) public class StaticDataProviderSampleTest { @Test(dataProvider = "static", dataProviderClass = StaticProvider.class) public void verifyStatic(String s) { Assert.assertEquals(s, "Cedric"); } @Test(dataProvider = "external", dataProviderClass = NonStaticProvider.class) public void verifyExternal(String s) { Assert.assertEquals(s, "Cedric"); } @Test(dataProvider = "injection", dataProviderClass = FieldInjectionProvider.class) public void verifyFieldInjection(String s) { Assert.assertEquals(s, "Cedric"); } @Test(dataProvider = "injection", dataProviderClass = ConstructorInjectionProvider.class) public void verifyConstructorInjection(String s) { Assert.assertEquals(s, "Cedric"); } public static class InjectionProviderModule extends AbstractModule { @Override protected void configure() { bind(String.class).annotatedWith(Names.named("test")).toInstance("Cedric"); } } } testng-6.9.12/src/test/java/test/dataprovider/InnexistentDataProvider.java0000644000175000017500000000040012732165123026225 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Test; /** * This class/interface */ public class InnexistentDataProvider { @Test(dataProvider="doesnotexist") public void testMethod(String s) { // doesn't matter } } testng-6.9.12/src/test/java/test/dataprovider/IndicesTest.java0000644000175000017500000000457012732165123023642 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.ITestNGListener; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.util.Arrays; import java.util.Collections; public class IndicesTest { @Test public void test() { TestNG testng = new TestNG(false); testng.setTestClasses(new Class[]{IndicesSample.class}); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener((ITestNGListener) tla); testng.setVerbose(0); try { testng.run(); } catch (RuntimeException e) { Assert.fail("Exceptions thrown during tests should always be caught!", e); } Assert.assertTrue(tla.getFailedTests().isEmpty(), "Should have 0 failure: bad data-provider iteration should be ignored"); Assert.assertEquals(tla.getPassedTests().size(), 2, "Should have 2 passed test"); } @Test public void test2() { TestNG testng = new TestNG(false); XmlSuite suite = new XmlSuite(); XmlTest test = new XmlTest(suite); XmlClass clazz = new XmlClass(IndicesSample.class); clazz.setXmlTest(test); test.getClasses().add(clazz); XmlInclude include = new XmlInclude("indicesShouldWork", Arrays.asList(0), 0); include.setXmlClass(clazz); clazz.getIncludedMethods().add(include); XmlInclude include2 = new XmlInclude("indicesShouldWorkWithIterator", Arrays.asList(0), 0); include2.setXmlClass(clazz); clazz.getIncludedMethods().add(include2); testng.setXmlSuites(Collections.singletonList(suite)); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener((ITestNGListener) tla); testng.setVerbose(0); try { testng.run(); } catch (RuntimeException e) { Assert.fail("Exceptions thrown during tests should always be caught!", e); } Assert.assertTrue(tla.getFailedTests().isEmpty(), "Should have 0 failure: bad data-provider iteration should be ignored"); Assert.assertEquals(tla.getPassedTests().size(), 4, "Should have 4 passed test"); } }testng-6.9.12/src/test/java/test/dataprovider/MyIterator.java0000644000175000017500000000116012732165123023513 0ustar eugeneeugenepackage test.dataprovider; import java.util.Iterator; public class MyIterator implements Iterator { private static int m_count = 0; private Object[][] m_data; public MyIterator(Object[][] data) { m_data = data; } @Override public boolean hasNext() { return m_count < m_data.length; } @Override public Object[] next() { ppp("RETURNING INDEX " + m_count); return m_data[m_count++]; } @Override public void remove() { } public static int getCount() { return m_count; } private static void ppp(String s) { System.out.println("[MyIterator] " + s); } } testng-6.9.12/src/test/java/test/dataprovider/EmptyDataProviderSample.java0000644000175000017500000000115512732165123026165 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.Collections; import java.util.Iterator; public class EmptyDataProviderSample { @DataProvider public Object[][] dp1() { return new Object[][]{}; } @Test(dataProvider = "dp1") public void test1() { Assert.fail(); } @DataProvider(indices = { 2 }) public Iterator dp2() { return Collections.emptyIterator(); } @Test(dataProvider = "dp2") public void test2() { Assert.fail(); } }testng-6.9.12/src/test/java/test/dataprovider/IndicesSample.java0000644000175000017500000000165412732165123024144 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.Arrays; import java.util.Iterator; public class IndicesSample { @DataProvider(indices = { 2 }) public Object[][] dp1() { return new Object[][] { new Object[] { 1 }, new Object[] { 2 }, new Object[] { 3 }, }; } @Test(dataProvider = "dp1") public void indicesShouldWork(int n) { if (n == 2) { throw new RuntimeException("This method should not have received a 2"); } } @DataProvider(indices = { 2 }) public Iterator dp2() { return Arrays.asList( new Object[] { 1 }, new Object[] { 2 }, new Object[] { 3 } ).iterator(); } @Test(dataProvider = "dp2") public void indicesShouldWorkWithIterator(int n) { if (n == 2) { throw new RuntimeException("This method should not have received a 2"); } } }testng-6.9.12/src/test/java/test/dataprovider/ParallelDataProviderTest.java0000644000175000017500000000220112732165123026312 0ustar eugeneeugenepackage test.dataprovider; import org.testng.ITestContext; import org.testng.TestNG; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import test.SimpleBaseTest; /** * Data providers were not working properly with parallel=true * @author cbeust */ public class ParallelDataProviderTest extends SimpleBaseTest { // protected static Logger logger = Logger // .getLogger(SampleMessageLoaderTest2.class); // // This method will provide data to any test method that declares that its // Data Provider // is named "test1" @DataProvider(name = "test1", parallel = true) public Object[][] createData1() { return new Object[][] { { "Cedric", 36}, { "Anne", 37}, { "A", 36}, { "B", 37} }; } // This test method declares that its data should be supplied by the Data // Provider // named "test1" @Test(dataProvider = "test1", threadPoolSize = 5) public void verifyData1(ITestContext testContext, String n1, Integer n2) { } @Test public void shouldNotThrowConcurrentModificationException() { TestNG tng = create(ParallelDataProvider2Test.class); tng.run(); } } testng-6.9.12/src/test/java/test/dataprovider/FailingDataProvider.java0000644000175000017500000000076412732165123025303 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * This class/interface */ public class FailingDataProvider { @DataProvider public Object[][] throwsExpectedException() { throw new RuntimeException("expected exception from @DP"); } @Test(dataProvider="throwsExpectedException") public void dpThrowingException() { Assert.fail("Method should never get invoked"); } } testng-6.9.12/src/test/java/test/dataprovider/FieldInjectionProvider.java0000644000175000017500000000056512732165123026025 0ustar eugeneeugenepackage test.dataprovider; import com.google.inject.Inject; import com.google.inject.name.Named; import org.testng.annotations.DataProvider; public class FieldInjectionProvider { @Inject @Named("test") private String value; @DataProvider(name = "injection") public Object[][] create() { return new Object[][] { new Object[] { value }, }; } } testng-6.9.12/src/test/java/test/dataprovider/TestInstanceTest.java0000644000175000017500000000162712732165123024670 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.annotations.TestInstance; import java.lang.reflect.Method; public class TestInstanceTest { private int m_n; private static int m_instanceCount = 0; public TestInstanceTest() {} public TestInstanceTest(int n) { this.m_n = n; } @DataProvider public Object[][] dp(Method m, @TestInstance Object instance) { TestInstanceTest o0 = (TestInstanceTest) instance; Assert.assertTrue(o0.m_n == 1 || o0.m_n == 2); m_instanceCount++; return new Object[][] { new Object[] {42}, new Object[] {43}, }; } @Test(dataProvider = "dp") public void f(int o) { } @Override public String toString() { return "[A n:" + m_n + "]"; } private static void ppp(String s) { System.out.println("[A] " + s); } }testng-6.9.12/src/test/java/test/dataprovider/IterableTest.java0000644000175000017500000000227012732165123024006 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import java.util.Iterator; public class IterableTest { private boolean m_ok1 = false; private boolean m_ok2 = false; public static final String FN2 = "Anne Marie"; public static final Integer LN2 = 37; public static final String FN1 = "Cedric"; public static final Integer LN1 = 36; public static final Object[][] DATA = new Object[][] { new Object[] { FN1, LN1 }, new Object[] { FN2, LN2 }, }; /** * @testng.data-provider name="test1" */ public Iterator createData() { return new MyIterator(DATA); } /** * @testng.test dataProvider="test1" */ public void verifyNames(String firstName, Integer age) { if (firstName.equals(FN1) && age.equals(LN1)) { m_ok1 = true; Assert.assertEquals(MyIterator.getCount(), 1); } if (firstName.equals(FN2) && age.equals(LN2)) { m_ok2 = true; Assert.assertEquals(MyIterator.getCount(), 2); } } /** * @testng.test dependsOnMethods = "verifyNames" */ public void verifyCount() { Assert.assertTrue(m_ok1 && m_ok2); } private static void ppp(String s) { System.out.println("[IterableTest] " + s); } } testng-6.9.12/src/test/java/test/dataprovider/FailingIterableDataProvider.java0000644000175000017500000000124512732165123026746 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.Iterator; public class FailingIterableDataProvider { @DataProvider(name = "dp") public Iterator createData() { return new Iterator() { int count=0; @Override public boolean hasNext() { return count<10; } @Override public Object[] next() { if (++count==6) { throw new RuntimeException(); } return new Object[] { count }; } @Override public void remove() {} }; } @Test(dataProvider="dp") public void happyTest(int count) { //pass } } testng-6.9.12/src/test/java/test/dataprovider/MethodTest.java0000644000175000017500000000301212732165123023472 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.reflect.Method; public class MethodTest { @DataProvider(name = "dp1") public Object[][] createData(Method m) { Assert.assertEquals("test1", m.getName()); Assert.assertEquals("test.dataprovider.MethodTest", m.getDeclaringClass().getName()); return new Object[][] { new Object[] { "Cedric" }, new Object[] { "Alois" }, }; } @Test(dataProvider = "dp1") public void test1(String s) { Assert.assertTrue("Cedric".equals(s) || "Alois".equals(s)); } private int m_test2 = 0; private int m_test3 = 0; @DataProvider(name = "dp2") public Object[][] createData2(Method m) { if ("test2".equals(m.getName())) { m_test2++; } else if ("test3".equals(m.getName())) { m_test3++; } else { throw new RuntimeException("Received method " + m + ", expected test2 or test3"); } Assert.assertEquals("test.dataprovider.MethodTest", m.getDeclaringClass().getName()); return new Object[][] { new Object[] { "Cedric" }, }; } @Test(dataProvider = "dp2") public void test2(String s) { Assert.assertTrue("Cedric".equals(s)); } @Test(dataProvider = "dp2") public void test3(String s) { Assert.assertTrue("Cedric".equals(s)); } @Test(dependsOnMethods = {"test2", "test3"}) public void multipleTestMethods() { Assert.assertEquals(1, m_test2); Assert.assertEquals(1, m_test3); } } testng-6.9.12/src/test/java/test/dataprovider/InheritedDataProviderTest.java0000644000175000017500000000036512732165123026502 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Test; //@Test(description = "class") public class InheritedDataProviderTest extends InheritedDataProviderBaseSampleTest { @Test(dataProvider = "dp") public void f(String a) { } } testng-6.9.12/src/test/java/test/dataprovider/BooleanTest.java0000644000175000017500000000143112732165123023634 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class BooleanTest { private boolean m_false = false; private boolean m_true = false; @Test(dataProvider = "allBooleans") public void doStuff(boolean t) { if (t) { m_true = true; } if (! t) { m_false = true; } } @Test(dependsOnMethods = {"doStuff"} ) public void verify() { Assert.assertTrue(m_true); Assert.assertTrue(m_false); } private void ppp(String string) { System.out.println("[BooleanTest] " + string); } @DataProvider(name = "allBooleans") public Object[][] createData() { return new Object[][] { new Object[] { true }, new Object[] { false }, }; } } testng-6.9.12/src/test/java/test/dataprovider/TestInstanceFactory.java0000644000175000017500000000036712732165123025360 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Factory; public class TestInstanceFactory { @Factory public Object[] init() { return new Object[] { new TestInstanceTest(1), new TestInstanceTest(2) }; } } testng-6.9.12/src/test/java/test/dataprovider/DataProviderWithError.java0000644000175000017500000000115712732165123025654 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * @author Vladislav.Rassokhin */ public class DataProviderWithError { @Test(dataProvider = "Data", invocationCount = 2) public void testShouldSkip() throws Exception { Assert.fail(); } @Test(dataProvider = "Data", invocationCount = 2, successPercentage = 10) public void testShouldSkipEvenIfSuccessPercentage() throws Exception { Assert.fail(); } @DataProvider(name = "Data") public static Object[][] Data() { throw new RuntimeException("Fail"); } } testng-6.9.12/src/test/java/test/dataprovider/ConstructorInjectionProvider.java0000644000175000017500000000072412732165123027324 0ustar eugeneeugenepackage test.dataprovider; import com.google.inject.Inject; import com.google.inject.name.Named; import org.testng.annotations.DataProvider; public class ConstructorInjectionProvider { private final String value; @Inject public ConstructorInjectionProvider(@Named("test") String value) { this.value = value; } @DataProvider(name = "injection") public Object[][] create() { return new Object[][] { new Object[] { value }, }; } } testng-6.9.12/src/test/java/test/dataprovider/UnnamedDataProviderTest.java0000644000175000017500000000137712732165123026162 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * This class/interface */ public class UnnamedDataProviderTest { private boolean m_false = false; private boolean m_true = false; @Test(dataProvider = "unnamedDataProvider") public void doStuff(boolean t) { if (t) { m_true = true; } if (! t) { m_false = true; } } @Test(dependsOnMethods = {"doStuff"} ) public void verify() { Assert.assertTrue(m_true); Assert.assertTrue(m_false); } @DataProvider public Object[][] unnamedDataProvider() { return new Object[][] { {Boolean.TRUE}, {Boolean.FALSE} }; } } testng-6.9.12/src/test/java/test/dataprovider/TestNG411Test.java0000644000175000017500000000125712732165123023655 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; public class TestNG411Test { @Test public void verify() { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { TestNG411SampleTest.class }); TestListenerAdapter al = new TestListenerAdapter(); tng.addListener(al); tng.run(); Assert.assertEquals(al.getPassedTests().size(), 1); Assert.assertEquals(al.getPassedTests().get(0).getMethod().getMethodName(), "checkMinTest_injection"); Assert.assertEquals(al.getFailedTests().size(), 2); } } testng-6.9.12/src/test/java/test/dataprovider/InheritedDataProviderBaseSampleTest.java0000644000175000017500000000033012732165123030427 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Test; //@Test(description = "parent") @Test (dataProviderClass=InheritedDataProviderSample1Test.class) public class InheritedDataProviderBaseSampleTest { } testng-6.9.12/src/test/java/test/dataprovider/EmptyDataProviderTest.java0000644000175000017500000000141312732165123025660 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.ITestNGListener; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; public class EmptyDataProviderTest { @Test public void test() { TestNG testng = new TestNG(false); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener((ITestNGListener) tla); // Used to check the warning message testng.setVerbose(2); testng.setTestClasses(new Class[]{EmptyDataProviderSample.class}); testng.run(); Assert.assertTrue(tla.getFailedTests().isEmpty()); Assert.assertTrue(tla.getSkippedTests().isEmpty()); Assert.assertTrue(tla.getPassedTests().isEmpty()); } } testng-6.9.12/src/test/java/test/dataprovider/DependentSampleTest.java0000644000175000017500000000105212732165123025324 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class DependentSampleTest { @DataProvider(name = "data") public Object[][] dp() { return new Object[][] { { "ok" }, { "not ok" }, }; } @Test(groups = { "a" }, dataProvider = "data") public void method1(String s) { if (!"ok".equals(s)) { throw new RuntimeException("error " + s); } } @Test(groups = { "b" }, dependsOnGroups = { "a" }) public void method2() throws InterruptedException { } } testng-6.9.12/src/test/java/test/dataprovider/Sample1Test.java0000644000175000017500000000167612732165123023572 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class Sample1Test { private boolean m_ok1 = false; private boolean m_ok2 = false; private static final String FN2 = "Anne Marie"; private static final Integer LN2 = 37; private static final String FN1 = "Cedric"; private static final Integer LN1 = 36; @DataProvider(name = "test1") public Object[][] createData() { return new Object[][] { new Object[] { FN1, LN1 }, new Object[] { FN2, LN2 }, }; } @Test(dataProvider = "test1") public void verifyNames(String firstName, Integer age) { if (firstName.equals(FN1) && age.equals(LN1)) { m_ok1 = true; } if (firstName.equals(FN2) && age.equals(LN2)) { m_ok2 = true; } } @Test(dependsOnMethods = {"verifyNames"}) public void verifyCount() { Assert.assertTrue(m_ok1 && m_ok2); } } testng-6.9.12/src/test/java/test/dataprovider/NonStaticProvider.java0000644000175000017500000000037112732165123025034 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; public class NonStaticProvider { @DataProvider(name = "external") public Object[][] create() { return new Object[][] { new Object[] { "Cedric" }, }; } } testng-6.9.12/src/test/java/test/dataprovider/FailingDataProviderTest.java0000644000175000017500000000227312732165123026140 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class FailingDataProviderTest extends SimpleBaseTest { private void shouldSkip(Class cls, String message, int expected) { TestNG testng = create(cls); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.run(); Assert.assertEquals(tla.getSkippedTests().size(), expected, message); } @Test(description = "TESTNG-142: Exceptions in DataProvider are not reported as failed test") public void failingDataProvider() { shouldSkip(FailingDataProvider.class, "Test method should be marked as skipped", 1); } @Test(description = "TESTNG-447: Abort when two data providers have the same name") public void duplicateDataProviders() { shouldSkip(DuplicateDataProviderSampleTest.class, "", 1); } @Test public void failingDataProviderAndInvocationCount() throws Exception { shouldSkip(DataProviderWithError.class, "Test should be skipped even if invocation counter and success percentage set", 4); } } testng-6.9.12/src/test/java/test/dataprovider/ParallelDataProvider2Test.java0000644000175000017500000000142712732165123026405 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.collections.Lists; import java.util.Iterator; import java.util.List; /** * @author Jacek Pulut * * Make sure this class can run without causing a ConcurrentModificationException. */ public class ParallelDataProvider2Test { @DataProvider(parallel = true) Iterator provide() { final List ret = Lists.newArrayList(); for (int i = 0; i < 1000; i++) { ret.add(new Integer[] { i }); } return ret.iterator(); } @Test(groups = "cme", dataProvider = "provide", invocationCount = 2, threadPoolSize = 2) public void checkCME(final Integer i) { // Reporter.log("" + i, true); } }testng-6.9.12/src/test/java/test/dataprovider/InheritanceBTest.java0000644000175000017500000000027212732165123024612 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Test; public class InheritanceBTest extends InheritanceATest { @Test(dataProvider = "dp") public void f(String s) { } } testng-6.9.12/src/test/java/test/dataprovider/ExplicitDataProviderNameSample.java0000644000175000017500000000066412732165123027455 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class ExplicitDataProviderNameSample { @Test(dataProvider="dp_name") public void should_find_exactly_one_data_provider(int i) {} @DataProvider(name="dp_name") Object[][] whatever_implicit_name() {return new Object[][] {{1}};} @DataProvider(name="whatever_explicit_name") Object[][] dp_name() {return null;} }testng-6.9.12/src/test/java/test/dataprovider/FailedDataProviderTest.java0000644000175000017500000000215612732165123025753 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import test.BaseTest; public class FailedDataProviderTest extends BaseTest { static int m_total = 0; @BeforeMethod public void init() { m_total = 0; } /** * Make sure that if a test method fails in the middle of a data provider, the rest * of the data set is still run. */ @Test public void allMethodsShouldBeInvoked() { TestNG tng = new TestNG(); tng.setTestClasses(new Class[] { FailedDataProviderSample.class }); tng.setVerbose(0); tng.run(); Assert.assertEquals(m_total, 6); } @Test public void failedDataProviderShouldCauseSkip() { addClass("test.dataprovider.DependentSampleTest"); run(); String[] passed = { "method1" }; String[] failed = { "method1" }; String[] skipped = { "method2" }; verifyTests("Failed", failed, getFailedTests()); verifyTests("Passed", passed, getPassedTests()); verifyTests("Skipped", skipped, getSkippedTests()); } } testng-6.9.12/src/test/java/test/dataprovider/FailingIterableDataProviderTest.java0000644000175000017500000000443512732165123027612 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.ITestNGListener; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.util.Arrays; import java.util.Collections; /** * TESTNG-291: * Exceptions thrown by Iterable DataProviders are not caught, no failed test reported */ public class FailingIterableDataProviderTest { @Test public void failingDataProvider() { TestNG testng= new TestNG(false); testng.setTestClasses(new Class[] {FailingIterableDataProvider.class}); TestListenerAdapter tla = new TestListenerAdapter(); testng.addListener(tla); testng.setVerbose(0); try { testng.run(); } catch (RuntimeException e) { Assert.fail("Exceptions thrown during tests should always be caught!", e); } Assert.assertEquals(tla.getFailedTests().size(), 1, "Should have 1 failure from a bad data-provider iteration"); Assert.assertEquals(tla.getPassedTests().size(), 5, "Should have 5 passed test from before the bad data-provider iteration"); } @Test public void failingDataProviderWithInvocationNumber() { XmlSuite suite = new XmlSuite(); XmlTest test = new XmlTest(suite); XmlClass clazz = new XmlClass(FailingIterableDataProvider.class); clazz.setXmlTest(test); test.getClasses().add(clazz); XmlInclude include = new XmlInclude("happyTest", Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), 0); include.setXmlClass(clazz); clazz.getIncludedMethods().add(include); TestListenerAdapter tla = new TestListenerAdapter(); TestNG testng= new TestNG(false); testng.setXmlSuites(Collections.singletonList(suite)); testng.addListener((ITestNGListener) tla); testng.setVerbose(0); try { testng.run(); } catch (RuntimeException e) { Assert.fail("Exceptions thrown during tests should always be caught!", e); } Assert.assertEquals(tla.getFailedTests().size(), 1, "Should have 1 failure from a bad data-provider iteration"); Assert.assertEquals(tla.getPassedTests().size(), 5, "Should have 5 passed test from before the bad data-provider iteration"); } }testng-6.9.12/src/test/java/test/dataprovider/ConfigurationAndDataProvidersTest.java0000644000175000017500000000342412732165123030203 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Make sure that all before methods except beforeTestMethod are invoked * before DataProvider. * * Created on Jan 19, 2006 * @author Cedric Beust */ public class ConfigurationAndDataProvidersTest { private boolean m_beforeSuite = false; private boolean m_beforeTest = false; private boolean m_beforeClass = false; private boolean m_beforeTestMethod = false; @DataProvider(name = "test1") public Object[][] createData() { Assert.assertTrue(m_beforeSuite, "beforeSuite should have been invoked"); Assert.assertTrue(m_beforeTest, "beforeTest should have been invoked"); Assert.assertTrue(m_beforeClass, "beforeClass should have been invoked"); Assert.assertFalse(m_beforeTestMethod, "beforeMethod should not have been invoked"); return new Object[][] { new Object[] { "Test" } }; } @Test(dataProvider = "test1") public void verifyNames(Object p) { // do nothing } @BeforeSuite public void setUpSuite () { m_beforeSuite = true; ppp("BEFORE SUITE"); } @BeforeTest public void setUpTest() { m_beforeTest = true; ppp("BEFORE TEST"); } @BeforeClass public void setUpClass() { m_beforeClass = true; ppp("BEFORE TEST CLASS"); } @BeforeMethod public void setUp() { m_beforeTestMethod = true; ppp("BEFORE TEST METHOD"); } private static void ppp(String s) { if (false) { System.out.println("[ConfigurationAndDataProvidersTest] " + s); } } } testng-6.9.12/src/test/java/test/dataprovider/ClassTest.java0000644000175000017500000000067612732165123023334 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Test; import test.BaseTest; public class ClassTest extends BaseTest { @Test(groups = { "current" }) public void includeMethodsOnly() { addClass(ClassSampleTest.class.getName()); run(); String[] passed = { "f", "g" }; String[] failed = { }; verifyTests("Passed", passed, getPassedTests()); verifyTests("Failed", failed, getFailedTests()); } } testng-6.9.12/src/test/java/test/dataprovider/CreateDataTest.java0000644000175000017500000000105612732165123024255 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class CreateDataTest { /** * @testng.data-provider name = "create-data" */ @DataProvider(name = "create-data") public Object[][] create() { return new Object[][] { new Object[] { new MyObject() } }; } /** * @testng.test data-provider = "create-data" */ @Test(dataProvider = "create-data") public void testMyTest(MyObject o) { // do something with o } } class MyObject {} testng-6.9.12/src/test/java/test/dataprovider/InheritanceATest.java0000644000175000017500000000033412732165123024610 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; public class InheritanceATest { @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { "a"} }; } } testng-6.9.12/src/test/java/test/dataprovider/StaticProvider.java0000644000175000017500000000037312732165123024363 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; public class StaticProvider { @DataProvider(name = "static") public static Object[][] create() { return new Object[][] { new Object[] { "Cedric" }, }; } } testng-6.9.12/src/test/java/test/dataprovider/DataProviderAsTest.java0000644000175000017500000000057012732165123025130 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test that if a class @Test is used, the @DataProvider * method won't be considered as a test. */ @Test public class DataProviderAsTest { public void f() { } @DataProvider public Object[][] dataProvider() { throw new RuntimeException(); } } testng-6.9.12/src/test/java/test/dataprovider/InstanceDataProviderTest.java0000644000175000017500000000043012732165123026324 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.Factory; public class InstanceDataProviderTest { @Factory public Object[] create() { return new Object[] { new InstanceDataProviderSampleTest(), new InstanceDataProviderSampleTest() }; } } testng-6.9.12/src/test/java/test/dataprovider/InheritedDataProviderSample1Test.java0000644000175000017500000000036012732165123027720 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; public class InheritedDataProviderSample1Test { @DataProvider static public Object[][] dp() { return new Object[][] { new Object[] { "a" } }; } } testng-6.9.12/src/test/java/test/dataprovider/FailedDataProviderSample.java0000644000175000017500000000075412732165123026257 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class FailedDataProviderSample { @DataProvider public Object[][] dp() { return new Integer[][] { new Integer[] { 1 }, new Integer[] { 2 }, new Integer[] { 3 }, }; } @Test(dataProvider = "dp") public void f(int n) { FailedDataProviderTest.m_total += n; if (n == 2) { throw new RuntimeException("Failed") ; } } } testng-6.9.12/src/test/java/test/dataprovider/InstanceDataProviderSampleTest.java0000644000175000017500000000142312732165123027471 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class InstanceDataProviderSampleTest { @DataProvider public Object[][] dp() { p("DATA PROVIDER"); return new Object[][] { new Object[] {hashCode()}, }; } @BeforeClass public void beforeTest() { p("BEFORE"); } @Test(dataProvider = "dp") public void f(Integer n) { p(" PARAM:" + n); Assert.assertEquals(n, Integer.valueOf(hashCode())); } @AfterClass public void afterTest() { p("AFTER"); } private void p(String s) { if (false) { System.out.println(hashCode() + " " + s); } } } testng-6.9.12/src/test/java/test/dataprovider/VarArgsDataProviderTest.java0000644000175000017500000000071212732165123026130 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class VarArgsDataProviderTest { private static final String[] S = new String[] { "a", "b", "c" }; @DataProvider public Object[][] data() { return new Object[][] { S }; } @Test(dataProvider = "data") public void testWithTwoEntriesInTestToolWindow(String... o) { Assert.assertEquals(o, S); } } testng-6.9.12/src/test/java/test/dataprovider/TestContextTest.java0000644000175000017500000000227012732165123024543 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; public class TestContextTest { @Test public void verifyTen() { verify("10", "verifyTen", 1, 0); } @Test public void verifyFive() { verify("5", "verifyFive", 1, 0); } @Test public void verifySix() { // Not including any group, so the two test methods should fail verify(null, null, 0, 2); } private void verify(String groupName, String passed, int passedCount, int failedCount) { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { TestContextSampleTest.class }); if (groupName != null) { tng.setGroups(groupName); } TestListenerAdapter al = new TestListenerAdapter(); tng.addListener(al); tng.run(); if (passedCount > 0) { Assert.assertEquals(al.getPassedTests().size(), passedCount); Assert.assertEquals(al.getPassedTests().get(0).getMethod().getMethodName(), passed); } if (failedCount > 0) { Assert.assertEquals(al.getFailedTests().size(), failedCount); } } } testng-6.9.12/src/test/java/test/dataprovider/TestNG411SampleTest.java0000644000175000017500000000313412732165123025013 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.ITestContext; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Used by {@link TestNG411Test}. Do not change number of methods or method names * @author nullin * */ public class TestNG411SampleTest { private static final String CHECK_MAX_DATA = "checkMaxData"; private static final String CHECK_MIN_DATA = "checkMinData"; @DataProvider(name = CHECK_MAX_DATA) public Object[][] dataProviderCheckMax() { return new Object[][] { { 1, 2, 3, 3 }, }; } @Test(description = "Number of parameters to this test don't match the " + "ones passed by data provider", dataProvider = CHECK_MAX_DATA) public void checkMaxTest(int nr1, int nr2, int expected) { Assert.fail("This code shouldnt be executed"); } @DataProvider(name = CHECK_MIN_DATA) public Object[][] dataProviderCheckMin() { return new Object[][] { { 1, 2, }, }; } @Test(description = "Number of parameters to this test don't match the " + "ones passed by data provider", dataProvider = CHECK_MIN_DATA) public void checkMinTest(int nr1, int nr2, int expected) { Assert.fail("This code shouldnt be executed"); } @Test(description = "Number of parameters to this test don't match the " + "ones passed by data provider. But an ojbect will be injected", dataProvider = CHECK_MIN_DATA) public void checkMinTest_injection(int nr1, int nr2, ITestContext ctx) { int result = Math.min(nr1, nr2); Assert.assertEquals(result, nr1); Assert.assertNotNull(ctx); } } testng-6.9.12/src/test/java/test/dataprovider/ClassSampleTest.java0000644000175000017500000000057312732165123024472 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @Test(dataProvider = "dp") public class ClassSampleTest { @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { "a" }, new Object[] { "b" }, }; } public void f(String a) { } public void g(String a) { } } testng-6.9.12/src/test/java/test/dataprovider/DuplicateDataProviderSampleTest.java0000644000175000017500000000063112732165123027637 0ustar eugeneeugenepackage test.dataprovider; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class DuplicateDataProviderSampleTest { @Test(dataProvider = "duplicate") public void f() { } @DataProvider(name = "duplicate") public Object[] dp1() { return new Object[0][]; } @DataProvider(name = "duplicate") public Object[] dp2() { return new Object[0][]; } } testng-6.9.12/src/test/java/test/dataprovider/TestContextSampleTest.java0000644000175000017500000000246612732165123025714 0ustar eugeneeugenepackage test.dataprovider; import org.testng.Assert; import org.testng.ITestContext; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Tests that when a DataProvider is declared with an ITestContext, * this parameter is correctly passed. * * Created on Dec 28, 2006 * @author Cedric Beust */ public class TestContextSampleTest { /** * @return As many parameters as the name of the included group */ @DataProvider(name = "testContext") public Object[][] createContext(ITestContext ctx) { // ppp("CONTEXT:" + ctx); String[] groups = ctx.getIncludedGroups(); int n = groups.length > 0 ? new Integer(groups[0]): 0; Object[] result = new Object[n]; for (int i = 0; i < n; i++) { result[i] = "foo"; } return new Object[][] { new Object[] { result }, }; } private static void ppp(String s) { System.out.println("[TestContextSampleTest] " + s); } @Test(dataProvider = "testContext", groups="10") public void verifyTen(Object[] objects) { Assert.assertEquals(objects.length, 10); } @Test(dataProvider = "testContext", groups="5") public void verifyFive(Object[] objects) { Assert.assertEquals(objects.length, 5); } } testng-6.9.12/src/test/java/test/access/0000755000175000017500000000000012732165123017330 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/access/BasePrivateAccessConfigurationMethods.java0000644000175000017500000000102512732165123027574 0ustar eugeneeugenepackage test.access; import org.testng.annotations.BeforeMethod; public class BasePrivateAccessConfigurationMethods { protected boolean m_baseProtected = false; protected boolean m_baseDefault = false; protected boolean m_basePrivate = true; @BeforeMethod void baseDefaultConfBeforeMethod() { m_baseDefault = true; } @BeforeMethod protected void baseProtectedConfBeforeMethod() { m_baseProtected = true; } @BeforeMethod private void basePrivateConfBeforeMethod() { m_basePrivate = false; } } testng-6.9.12/src/test/java/test/access/PrivateAccessConfigurationMethods.java0000644000175000017500000000271012732165123027003 0ustar eugeneeugenepackage test.access; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; /** * Test that private and protected @Configuration methods are run * * @author cbeust */ public class PrivateAccessConfigurationMethods extends BasePrivateAccessConfigurationMethods { private boolean m_private = false; private boolean m_default = false; private boolean m_protected = false; private boolean m_public = false; @BeforeMethod private void privateConfBeforeMethod() { m_private = true; } @BeforeMethod void defaultConfBeforeMethod() { m_default = true; } @BeforeMethod protected void protectedConfBeforeMethod() { m_protected = true; } @BeforeMethod public void publicConfBeforeMethod() { m_public = true; } @Test public void allAccessModifiersConfiguration() { Assert.assertTrue(m_private, "private @Configuration should have been run"); Assert.assertTrue(m_default, "default @Configuration should have been run"); Assert.assertTrue(m_protected, "protected @Configuration should have been run"); Assert.assertTrue(m_public, "public @Configuration should have been run"); Assert.assertTrue(m_baseProtected, "protected base @Configuration should have been run"); Assert.assertTrue(m_baseDefault, "default base @Configuration should have been run"); Assert.assertTrue(m_basePrivate, "private base @Configuration should not have been run"); } } testng-6.9.12/src/test/java/test/TestHelper.java0000644000175000017500000000412712732165123021015 0ustar eugeneeugenepackage test; import org.testng.TestNG; import org.testng.collections.Lists; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Random; public class TestHelper { public static XmlSuite createSuite(String cls, String suiteName) { return createSuite(cls, suiteName, "TmpTest"); } public static XmlSuite createSuite(Class cls, String suiteName, String testName) { return createSuite(cls.getName(), suiteName, testName); } private static XmlSuite createSuite(String cls, String suiteName, String testName) { XmlSuite result = new XmlSuite(); result.setName(suiteName); XmlTest test = new XmlTest(result); test.setName(testName); List classes = new ArrayList<>(); classes.add(new XmlClass(cls)); test.setXmlClasses(classes); return result; } public static TestNG createTestNG(String outputDir) { return createTestNG(null, outputDir); } public static TestNG createTestNG() { return createTestNG(null, null); } public static TestNG createTestNG(XmlSuite suite) { return createTestNG(suite, System.getProperty("java.io.tmpdir")); } public static TestNG createTestNG(XmlSuite suite, String outputDir) { TestNG result = new TestNG(); if (suite != null) { List suites = Lists.newArrayList(); suites.add(suite); result.setXmlSuites(suites); } if (outputDir == null) { outputDir = createRandomDirectory().getAbsolutePath(); } result.setOutputDirectory(outputDir); result.setVerbose(-1); return result; } public static File createRandomDirectory() { String dir = System.getProperty("java.io.tmpdir"); Random r = new Random(System.currentTimeMillis()); String name = "testng-tmp-" + r.nextInt(); File result = new File(dir + File.separatorChar + name); result.deleteOnExit(); result.mkdirs(); return result; } private static void ppp(String string) { System.out.println("[TestHelper] " + string); } } testng-6.9.12/src/test/java/test/NestedStaticSampleTest.java0000644000175000017500000000030512732165123023324 0ustar eugeneeugenepackage test; import org.testng.annotations.Test; public class NestedStaticSampleTest { @Test public void f() { } public class Nested { @Test public void nested() { } } } testng-6.9.12/src/test/java/test/listeners/0000755000175000017500000000000012732165123020077 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/listeners/OrderedListenerSampleTest.java0000644000175000017500000000103112732165123026031 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import test.SimpleBaseTest; @Listeners(SimpleListener.class) public class OrderedListenerSampleTest extends SimpleBaseTest { @BeforeMethod public void bm() { SimpleListener.m_list.add(1); } @Test public void f() { SimpleListener.m_list.add(2); } @AfterMethod public void am() { SimpleListener.m_list.add(4); } } testng-6.9.12/src/test/java/test/listeners/ResultContextTest.java0000644000175000017500000000067412732165123024434 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class ResultContextTest extends SimpleBaseTest { @Test public void testResultContext() { TestNG tng = create(ResultContextListenerSample.class); tng.run(); Assert.assertTrue(ResultContextListener.contextProvided, "Test context was not provided to the listener"); } } testng-6.9.12/src/test/java/test/listeners/ExecutionListener2SampleTest.java0000644000175000017500000000035512732165123026502 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(ExecutionListenerTest.ExecutionListener.class) public class ExecutionListener2SampleTest { @Test public void f() {} } testng-6.9.12/src/test/java/test/listeners/ResultListener.java0000644000175000017500000000256012732165123023731 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.internal.IResultListener2; public class ResultListener implements IResultListener2 { public static long m_end = 0; @Override public void onTestStart(ITestResult result) { // TODO Auto-generated method stub } @Override public void beforeConfiguration(ITestResult tr) { } @Override public void onTestSuccess(ITestResult result) { m_end = result.getEndMillis(); } @Override public void onTestFailure(ITestResult result) { // TODO Auto-generated method stub } @Override public void onTestSkipped(ITestResult result) { // TODO Auto-generated method stub } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { // TODO Auto-generated method stub } @Override public void onStart(ITestContext context) { // TODO Auto-generated method stub } @Override public void onFinish(ITestContext context) { // TODO Auto-generated method stub } @Override public void onConfigurationSuccess(ITestResult itr) { // TODO Auto-generated method stub } @Override public void onConfigurationFailure(ITestResult itr) { // TODO Auto-generated method stub } @Override public void onConfigurationSkip(ITestResult itr) { // TODO Auto-generated method stub } } testng-6.9.12/src/test/java/test/listeners/SuiteListenerSample2.java0000644000175000017500000000032112732165123024761 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(SuiteListener2.class) public class SuiteListenerSample2 { @Test public void foo(){} } testng-6.9.12/src/test/java/test/listeners/ConfigurationListenerSkipSampleTest.java0000644000175000017500000000054312732165123030112 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ConfigurationListenerSkipSampleTest { @BeforeMethod public void bmShouldFail() { throw new RuntimeException(); } @BeforeMethod(dependsOnMethods = "bmShouldFail") public void bm() { } @Test public void f() { } } testng-6.9.12/src/test/java/test/listeners/SuiteListener2.java0000644000175000017500000000327212732165123023627 0ustar eugeneeugenepackage test.listeners; import org.testng.*; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.List; public class SuiteListener2 implements IAnnotationTransformer, IInvokedMethodListener, ITestListener, ISuiteListener, IExecutionListener, IMethodInterceptor { public static int start = 0; public static int finish = 0; @Override public void onFinish(ISuite suite) { finish++; } @Override public void onStart(ISuite suite) { start++; } @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } @Override public void onExecutionStart() { } @Override public void onExecutionFinish() { } @Override public List intercept(List methods, ITestContext context) { return methods; } @Override public void onTestStart(ITestResult result) { } @Override public void onTestSuccess(ITestResult result) { } @Override public void onTestFailure(ITestResult result) { } @Override public void onTestSkipped(ITestResult result) { } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } @Override public void onStart(ITestContext context) { } @Override public void onFinish(ITestContext context) { } } testng-6.9.12/src/test/java/test/listeners/L2.java0000644000175000017500000000010212732165123021210 0ustar eugeneeugenepackage test.listeners; public class L2 extends BaseListener { } testng-6.9.12/src/test/java/test/listeners/AggregateSampleTest.java0000644000175000017500000000045512732165123024636 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(L2.class) public class AggregateSampleTest extends BaseAggregate { static int m_count = 0; static public void incrementCount() { m_count++; } @Test public void f() { } } testng-6.9.12/src/test/java/test/listeners/LSampleTest.java0000644000175000017500000000017512732165123023142 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Test; public class LSampleTest { @Test public void dummy() {} } testng-6.9.12/src/test/java/test/listeners/FailingSampleTest.java0000644000175000017500000000060712732165123024320 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.AfterMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(SimpleListener.class) public class FailingSampleTest { @AfterMethod public void am() { SimpleListener.m_list.add(6); } @Test public void a1() { SimpleListener.m_list.add(4); throw new RuntimeException(); } } testng-6.9.12/src/test/java/test/listeners/ExecutionListenerTest.java0000644000175000017500000000332612732165123025257 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.IExecutionListener; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; public class ExecutionListenerTest extends SimpleBaseTest { public static class ExecutionListener implements IExecutionListener { public static boolean m_start = false; public static boolean m_finish = false; @Override public void onExecutionStart() { m_start = true; } @Override public void onExecutionFinish() { m_finish = true; } } @Test public void executionListenerWithXml() { runTest(ExecutionListener1SampleTest.class, true /* add listener */, true /* should run */); } @Test public void executionListenerWithoutListener() { runTest(ExecutionListener1SampleTest.class, false /* don't add listener */, false /* should not run */); } @Test public void executionListenerAnnotation() { runTest(ExecutionListener2SampleTest.class, false /* don't add listener */, true /* should run */); } private void runTest(Class listenerClass, boolean addListener, boolean expected) { XmlSuite s = createXmlSuite("ExecutionListener"); XmlTest t = createXmlTest(s, "Test", listenerClass.getName()); if (addListener) { s.addListener(ExecutionListener.class.getName()); } TestNG tng = create(); tng.setXmlSuites(Arrays.asList(s)); ExecutionListener.m_start = false; ExecutionListener.m_finish = false; tng.run(); Assert.assertEquals(ExecutionListener.m_start, expected); Assert.assertEquals(ExecutionListener.m_finish, expected); } } testng-6.9.12/src/test/java/test/listeners/SuiteListener.java0000644000175000017500000000053112732165123023540 0ustar eugeneeugenepackage test.listeners; import org.testng.ISuite; import org.testng.ISuiteListener; public class SuiteListener implements ISuiteListener { public static int start = 0; public static int finish = 0; @Override public void onFinish(ISuite suite) { finish++; } @Override public void onStart(ISuite suite) { start++; } } testng-6.9.12/src/test/java/test/listeners/L1.java0000644000175000017500000000010212732165123021207 0ustar eugeneeugenepackage test.listeners; public class L1 extends BaseListener { } testng-6.9.12/src/test/java/test/listeners/AlterSuiteListenerTest.java0000644000175000017500000000464212732165123025377 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.IAlterSuiteListener; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.SimpleBaseTest; import java.util.Arrays; import java.util.List; public class AlterSuiteListenerTest extends SimpleBaseTest { public static final String ALTER_SUITE_LISTENER = "AlterSuiteListener"; @Test public void executionListenerWithXml() { XmlSuite suite = runTest(AlterSuiteListener1SampleTest.class, AlterSuiteNameListener.class.getName()); Assert.assertEquals(suite.getName(), AlterSuiteNameListener.class.getSimpleName()); } @Test public void executionListenerWithoutListener() { XmlSuite suite = runTest(AlterSuiteListener1SampleTest.class, null/*Donot add the listener*/); Assert.assertEquals(suite.getName(), ALTER_SUITE_LISTENER); } @Test public void executionListenerWithXml2() { XmlSuite suite = runTest(AlterSuiteListener1SampleTest.class, AlterXmlTestsInSuiteListener.class.getName()); Assert.assertEquals(suite.getTests().size(), 2); } private XmlSuite runTest(Class listenerClass, String listenerName) { XmlSuite s = createXmlSuite(ALTER_SUITE_LISTENER); createXmlTest(s, "Test", listenerClass.getName()); boolean addListener = (listenerName != null); if (addListener) { s.addListener(listenerName); } TestNG tng = create(); tng.setXmlSuites(Arrays.asList(s)); tng.run(); return s; } public static class AlterSuiteListener1SampleTest { @Test public void foo() { } } public static class AlterSuiteNameListener implements IAlterSuiteListener { @Override public void alter(List suites) { XmlSuite suite = suites.get(0); suite.setName(getClass().getSimpleName()); } } public static class AlterXmlTestsInSuiteListener implements IAlterSuiteListener { @Override public void alter(List suites) { XmlSuite suite = suites.get(0); List tests = suite.getTests(); XmlTest test = tests.get(0); XmlTest anotherTest = new XmlTest(suite); anotherTest.setName("foo"); anotherTest.setClasses(test.getClasses()); } } } testng-6.9.12/src/test/java/test/listeners/SetStatusListener.java0000644000175000017500000000164312732165123024413 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; /** * From https://github.com/rajsrivastav1919/TestNGTest */ public class SetStatusListener implements ITestListener { private ITestContext context; @Override public void onTestStart(ITestResult result) {} @Override public void onTestSuccess(ITestResult result) {} @Override public void onTestFailure(ITestResult result) { result.setStatus(ITestResult.SUCCESS); } @Override public void onTestSkipped(ITestResult result) {} @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) {} @Override public void onStart(ITestContext context) {} @Override public void onFinish(ITestContext context) { this.context = context; } public ITestContext getContext() { return context; } } testng-6.9.12/src/test/java/test/listeners/MyMethodInterceptor.java0000644000175000017500000000072312732165123024711 0ustar eugeneeugenepackage test.listeners; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import java.util.List; public class MyMethodInterceptor implements IMethodInterceptor { private int count = 0; @Override public List intercept(List methods, ITestContext context) { count++; return methods; } public int getCount() { return count; } } testng-6.9.12/src/test/java/test/listeners/EndMillisShouldNotBeZeroTest.java0000644000175000017500000000226612732165123026437 0ustar eugeneeugenepackage test.listeners; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import org.testng.annotations.BeforeClass; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import test.listeners.EndMillisShouldNotBeZeroTest.MyInvokedMethodListener; import junit.framework.Assert; @Listeners(MyInvokedMethodListener.class) public class EndMillisShouldNotBeZeroTest { private static long m_end; public static class MyInvokedMethodListener implements IInvokedMethodListener { @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { m_end = testResult.getEndMillis(); } } @BeforeClass public void bm() { m_end = 0; } @Test public void f1() { try { Thread.sleep(1); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); } } @Test(description = "Make sure that ITestResult#getEndMillis is properly set", dependsOnMethods = "f1") public void f2() { Assert.assertTrue(m_end > 0); } } testng-6.9.12/src/test/java/test/listeners/SimpleListener.java0000644000175000017500000000067012732165123023704 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import java.util.List; public class SimpleListener extends TestListenerAdapter { public static List m_list; @Override public void onTestSuccess(ITestResult tr) { m_list.add(3); super.onTestSuccess(tr); } @Override public void onTestFailure(ITestResult tr) { m_list.add(5); super.onTestSuccess(tr); } } testng-6.9.12/src/test/java/test/listeners/MyClassListener.java0000644000175000017500000000217212732165123024025 0ustar eugeneeugenepackage test.listeners; import org.testng.IClassListener; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestClass; import org.testng.ITestResult; import org.testng.internal.BaseTestMethod; import java.util.ArrayList; import java.util.List; public class MyClassListener implements IClassListener, IInvokedMethodListener { public static final List names = new ArrayList<>(); @Override public void onBeforeClass(ITestClass testClass) { names.add("BeforeClass=" + testClass.getRealClass().getSimpleName()); } @Override public void onAfterClass(ITestClass testClass) { names.add("AfterClass=" + testClass.getRealClass().getSimpleName()); } @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { BaseTestMethod m = (BaseTestMethod) method.getTestMethod(); names.add("BeforeMethod=" + m.getSimpleName()); } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { BaseTestMethod m = (BaseTestMethod) method.getTestMethod(); names.add("AfterMethod=" + m.getSimpleName()); } } testng-6.9.12/src/test/java/test/listeners/ClassListenerSample.java0000644000175000017500000000036112732165123024657 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(MyClassListener.class) public class ClassListenerSample { @Test public void test() {} @Test public void test2() {} } testng-6.9.12/src/test/java/test/listeners/ListenerTest.java0000644000175000017500000002036312732165123023373 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.ITestNGListener; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.testng.collections.Lists; import test.SimpleBaseTest; import java.util.Arrays; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; public class ListenerTest extends SimpleBaseTest { @BeforeMethod public void bm() { SimpleListener.m_list = Lists.newArrayList(); } @Test(description = "Ensure that if a listener is present, we get test(), onSuccess()," + " afterMethod()") public void listenerShouldBeCalledBeforeConfiguration() { TestNG tng = create(OrderedListenerSampleTest.class); tng.run(); Assert.assertEquals(SimpleListener.m_list, Arrays.asList(1, 2, 3, 4)); } @Test(description = "TESTNG-400: onTestFailure should be called before @AfterMethod") public void failureBeforeAfterMethod() { TestNG tng = create(FailingSampleTest.class); tng.run(); Assert.assertEquals(SimpleListener.m_list, Arrays.asList(4, 5, 6)); } @Test(description = "Inherited @Listeners annotations should aggregate") public void aggregateListeners() { TestNG tng = create(AggregateSampleTest.class); AggregateSampleTest.m_count = 0; tng.run(); Assert.assertEquals(AggregateSampleTest.m_count, 2); } @Test(description = "Should attach only one instance of the same @Listener class per test") public void shouldAttachOnlyOneInstanceOfTheSameListenerClassPerTest() { TestNG tng = create(Derived1.class, Derived2.class); BaseWithListener.m_count = 0; tng.run(); Assert.assertEquals(BaseWithListener.m_count, 2); } @Test(description = "@Listeners with an ISuiteListener") public void suiteListenersShouldWork() { TestNG tng = create(SuiteListenerSample.class); SuiteListener.start = 0; SuiteListener.finish = 0; tng.run(); Assert.assertEquals(SuiteListener.start, 1); Assert.assertEquals(SuiteListener.finish, 1); } @Test(description = "GITHUB-767: ISuiteListener called twice when @Listeners") public void suiteListenerInListernersAnnotationShouldBeRunOnce() { TestNG tng = createTests("Suite", SuiteListenerSample2.class); SuiteListener2.start = 0; SuiteListener2.finish = 0; tng.run(); Assert.assertEquals(SuiteListener2.start, 1); Assert.assertEquals(SuiteListener2.finish, 1); } @Test(description = "GITHUB-171") public void suiteListenersShouldBeOnlyRunOnceWithManyTests() { TestNG tng = createTests("suite", Derived1.class, Derived2.class); SuiteListener.start = 0; SuiteListener.finish = 0; tng.run(); Assert.assertEquals(SuiteListener.start, 1); Assert.assertEquals(SuiteListener.finish, 1); } @Test(description = "GITHUB-795") public void suiteListenersShouldBeOnlyRunOnceWithManyIdenticalTests() { TestNG tng = createTests("suite", Derived1.class, Derived1.class); SuiteListener.start = 0; SuiteListener.finish = 0; tng.run(); Assert.assertEquals(SuiteListener.start, 1); Assert.assertEquals(SuiteListener.finish, 1); } @Test(description = "GITHUB-169") public void invokedMethodListenersShouldBeOnlyRunOnceWithManyTests() { TestNG tng = createTests("suite", Derived1.class, Derived2.class); MyInvokedMethodListener.beforeInvocation.clear(); MyInvokedMethodListener.afterInvocation.clear(); tng.run(); assertThat(MyInvokedMethodListener.beforeInvocation).containsOnly( entry("t", 1), entry("s", 1) ); assertThat(MyInvokedMethodListener.afterInvocation).containsOnly( entry("t", 1), entry("s", 1) ); } @Test(description = "GITHUB-154: MethodInterceptor will be called twice") public void methodInterceptorShouldBeRunOnce() { TestNG tng = create(SuiteListenerSample.class); MyMethodInterceptor interceptor = new MyMethodInterceptor(); tng.addListener(interceptor); tng.run(); Assert.assertEquals(interceptor.getCount(), 1); } @Test(description = "GITHUB-356: Add listeners for @BeforeClass/@AfterClass") public void classListenerShouldWork() { MyClassListener.names.clear(); TestNG tng = create(Derived1.class, Derived2.class); MyClassListener listener = new MyClassListener(); tng.addListener((Object)listener); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); assertThat(adapter.getFailedTests()).isEmpty(); assertThat(adapter.getSkippedTests()).isEmpty(); assertThat(MyClassListener.names).containsExactly( "BeforeClass=Derived1", "BeforeMethod=Derived1.t", "AfterMethod=Derived1.t", "AfterClass=Derived1", "BeforeClass=Derived2", "BeforeMethod=Derived2.s", "AfterMethod=Derived2.s", "AfterClass=Derived2"); } @Test public void classListenerShouldWorkWithManyTestMethods() { MyClassListener.names.clear(); TestNG tng = create(Derived3.class); MyClassListener listener = new MyClassListener(); tng.addListener((Object)listener); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); assertThat(adapter.getFailedTests()).isEmpty(); assertThat(adapter.getSkippedTests()).isEmpty(); assertThat(MyClassListener.names).containsExactly( "BeforeClass=Derived3", "BeforeMethod=Derived3.r", "AfterMethod=Derived3.r", "BeforeMethod=Derived3.r1", "AfterMethod=Derived3.r1", "AfterClass=Derived3" ); } @Test(description = "GITHUB-356: Add listeners for @BeforeClass/@AfterClass") public void classListenerShouldWorkFromAnnotation() { MyClassListener.names.clear(); TestNG tng = create(ClassListenerSample.class); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener(adapter); tng.run(); assertThat(adapter.getFailedTests()).isEmpty(); assertThat(adapter.getSkippedTests()).isEmpty(); assertThat(MyClassListener.names).containsExactly( "BeforeClass=ClassListenerSample", "BeforeMethod=ClassListenerSample.test", "AfterMethod=ClassListenerSample.test", "BeforeMethod=ClassListenerSample.test2", "AfterMethod=ClassListenerSample.test2", "AfterClass=ClassListenerSample" ); } @Test public void classListenerShouldBeOnlyRunOnce() { MyClassListener.names.clear(); TestNG tng = create(Derived3.class); MyClassListener listener = new MyClassListener(); tng.addListener((ITestNGListener) listener); TestListenerAdapter adapter = new TestListenerAdapter(); tng.addListener((ITestNGListener) adapter); TestAndClassListener tacl = new TestAndClassListener(); tng.addListener((ITestNGListener) tacl); tng.run(); assertThat(adapter.getFailedTests()).isEmpty(); assertThat(adapter.getSkippedTests()).isEmpty(); assertThat(tacl.getBeforeClassCount()).isEqualTo(1); assertThat(tacl.getAfterClassCount()).isEqualTo(1); } @Test(description = "GITHUB-911: Should not call method listeners for skipped methods") public void methodListenersShouldNotBeCalledForSkippedMethods() { GitHub911Listener listener = new GitHub911Listener(); TestNG tng = create(GitHub911Sample.class); tng.addListener(listener); tng.run(); Assert.assertEquals(listener.onStart, 1); Assert.assertEquals(listener.onFinish, 1); Assert.assertEquals(listener.onTestStart, 0); Assert.assertEquals(listener.onTestSuccess, 0); Assert.assertEquals(listener.onTestFailure, 0); Assert.assertEquals(listener.onTestFailedButWithinSuccessPercentage, 0); Assert.assertEquals(listener.onTestSkipped, 2); } @Test(description = "GITHUB-895: Changing status of test by setStatus of ITestResult") public void setStatusShouldWorkInListener() { SetStatusListener listener = new SetStatusListener(); TestNG tng = create(SetStatusSample.class); tng.addListener(listener); tng.run(); Assert.assertEquals(listener.getContext().getFailedTests().size(), 0); Assert.assertEquals(listener.getContext().getFailedButWithinSuccessPercentageTests().size(), 0); Assert.assertEquals(listener.getContext().getSkippedTests().size(), 0); Assert.assertEquals(listener.getContext().getPassedTests().size(), 1); } } testng-6.9.12/src/test/java/test/listeners/GitHub911Sample.java0000644000175000017500000000053712732165123023526 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class GitHub911Sample { @BeforeSuite(alwaysRun = true) public void setUp() { Assert.fail(); } // TODO check before invocation @Test public void myTest1() {} @Test public void myTest2() {} } testng-6.9.12/src/test/java/test/listeners/BaseListener.java0000644000175000017500000000130112732165123023315 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class BaseListener implements ITestListener { @Override public void onTestStart(ITestResult result) { AggregateSampleTest.incrementCount(); } @Override public void onTestSuccess(ITestResult result) { } @Override public void onTestFailure(ITestResult result) { } @Override public void onTestSkipped(ITestResult result) { } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } @Override public void onStart(ITestContext context) { } @Override public void onFinish(ITestContext context) { } } testng-6.9.12/src/test/java/test/listeners/TestAndClassListener.java0000644000175000017500000000220112732165123024773 0ustar eugeneeugenepackage test.listeners; import org.testng.IClassListener; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class TestAndClassListener implements ITestListener, IClassListener { private int beforeClassCount = 0; private int afterClassCount = 0; @Override public void onBeforeClass(ITestClass testClass) { beforeClassCount++; } @Override public void onAfterClass(ITestClass testClass) { afterClassCount++; } @Override public void onTestStart(ITestResult result) { } @Override public void onTestSuccess(ITestResult result) { } @Override public void onTestFailure(ITestResult result) { } @Override public void onTestSkipped(ITestResult result) { } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } @Override public void onStart(ITestContext context) { } @Override public void onFinish(ITestContext context) { } public int getBeforeClassCount() { return beforeClassCount; } public int getAfterClassCount() { return afterClassCount; } } testng-6.9.12/src/test/java/test/listeners/SuiteAndInvokedMethodListenerTest.java0000644000175000017500000000261112732165123027505 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ISuite; import org.testng.ISuiteListener; import org.testng.ITestResult; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import test.listeners.SuiteAndInvokedMethodListenerTest.MyListener; /** * Make sure that if a listener implements both IInvokedMethodListener * and ISuiteListener, both listeners get invoked. * * @author Cedric Beust */ @Listeners(MyListener.class) public class SuiteAndInvokedMethodListenerTest { public static class MyListener implements IInvokedMethodListener, ISuiteListener { private static boolean m_before = false; private static boolean m_start = false; public MyListener() { } @Override public void beforeInvocation(IInvokedMethod method, ITestResult result) { m_before = true; } @Override public void afterInvocation(IInvokedMethod method, ITestResult result) { } @Override public void onStart(ISuite suite) { m_start = true; } @Override public void onFinish(ISuite suite) { } } @Test public void bothListenersShouldRun() { Assert.assertTrue(MyListener.m_before, "IInvokedMethodListener was not invoked"); Assert.assertTrue(MyListener.m_start, "ISuiteListener was not invoked"); } } testng-6.9.12/src/test/java/test/listeners/SuiteListenerSample.java0000644000175000017500000000031712732165123024704 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(SuiteListener.class) public class SuiteListenerSample { @Test public void foo(){} } testng-6.9.12/src/test/java/test/listeners/L3.java0000644000175000017500000000036712732165123021226 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestResult; import org.testng.TestListenerAdapter; public class L3 extends TestListenerAdapter { @Override public void onTestStart(ITestResult result) { BaseWithListener.incrementCount(); } } testng-6.9.12/src/test/java/test/listeners/ConfigurationListenerSucceedSampleTest.java0000644000175000017500000000036712732165123030563 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ConfigurationListenerSucceedSampleTest { @BeforeMethod public void bmShouldSucceed() {} @Test public void f() { } } testng-6.9.12/src/test/java/test/listeners/ConfigurationListenerFailSampleTest.java0000644000175000017500000000042612732165123030057 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class ConfigurationListenerFailSampleTest { @BeforeMethod public void bmShouldFail() { throw new RuntimeException(); } @Test public void f() { } } testng-6.9.12/src/test/java/test/listeners/ExecutionListener1SampleTest.java0000644000175000017500000000021312732165123026472 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Test; public class ExecutionListener1SampleTest { @Test public void f() {} } testng-6.9.12/src/test/java/test/listeners/GitHub911Listener.java0000644000175000017500000000176612732165123024077 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class GitHub911Listener implements ITestListener { int onTestStart = 0; int onTestSuccess = 0; int onTestFailure = 0; int onTestSkipped = 0; int onTestFailedButWithinSuccessPercentage = 0; int onStart = 0; int onFinish = 0; @Override public void onTestStart(ITestResult result) { onTestStart++; } @Override public void onTestSuccess(ITestResult result) { onTestSuccess++; } @Override public void onTestFailure(ITestResult result) { onTestFailure++; } @Override public void onTestSkipped(ITestResult result) { onTestSkipped++; } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { onTestFailedButWithinSuccessPercentage++; } @Override public void onStart(ITestContext context) { onStart++; } @Override public void onFinish(ITestContext context) { onFinish++; } } testng-6.9.12/src/test/java/test/listeners/SetStatusSample.java0000644000175000017500000000033012732165123024037 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.annotations.Test; public class SetStatusSample { @Test public void aFailingTest() { Assert.fail("Failing deliberately"); } } testng-6.9.12/src/test/java/test/listeners/ResultContextListenerSample.java0000644000175000017500000000033512732165123026436 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @Listeners(ResultContextListener.class) public class ResultContextListenerSample { @Test public void f() { } } testng-6.9.12/src/test/java/test/listeners/Derived1.java0000644000175000017500000000021212732165123022400 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Test; class Derived1 extends BaseWithListener { @Test public void t() { } } testng-6.9.12/src/test/java/test/listeners/Derived2.java0000644000175000017500000000021212732165123022401 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Test; class Derived2 extends BaseWithListener { @Test public void s() { } } testng-6.9.12/src/test/java/test/listeners/ListenerInXmlTest.java0000644000175000017500000000105612732165123024341 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.util.Arrays; public class ListenerInXmlTest extends SimpleBaseTest { @Test(description = "Make sure that listeners defined in testng.xml are invoked") public void listenerInXmlShouldBeInvoked() { TestNG tng = create(); tng.setTestSuites(Arrays.asList(getPathToResource("listener-in-xml.xml"))); LListener.invoked = false; tng.run(); Assert.assertTrue(LListener.invoked); } } testng-6.9.12/src/test/java/test/listeners/BaseWithListener.java0000644000175000017500000000040712732165123024157 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; @Listeners(value = {L3.class, SuiteListener.class, MyInvokedMethodListener.class}) class BaseWithListener { static int m_count = 0; public static void incrementCount() { m_count++; } } testng-6.9.12/src/test/java/test/listeners/LListener.java0000644000175000017500000000070112732165123022641 0ustar eugeneeugenepackage test.listeners; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; public class LListener implements IInvokedMethodListener { public static boolean invoked = false; @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { invoked = true; } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } } testng-6.9.12/src/test/java/test/listeners/MyInvokedMethodListener.java0000644000175000017500000000176512732165123025527 0ustar eugeneeugenepackage test.listeners; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.ITestResult; import java.util.HashMap; import java.util.Map; public class MyInvokedMethodListener implements IInvokedMethodListener { public static Map beforeInvocation = new HashMap<>(); public static Map afterInvocation = new HashMap<>(); @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { increments(beforeInvocation, method); } @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { increments(afterInvocation, method); } private static void increments(Map map, IInvokedMethod method) { String stringValue = method.getTestMethod().getMethodName(); Integer count = map.get(stringValue); if (count == null) { count = 0; } map.put(stringValue, count+1); } } testng-6.9.12/src/test/java/test/listeners/BaseAggregate.java0000644000175000017500000000017012732165123023421 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Listeners; @Listeners(L1.class) public class BaseAggregate { } testng-6.9.12/src/test/java/test/listeners/SuiteAndConfigurationListenerTest.java0000644000175000017500000000255012732165123027556 0ustar eugeneeugenepackage test.listeners; import java.util.concurrent.atomic.AtomicInteger; import org.testng.Assert; import org.testng.IConfigurationListener; import org.testng.ISuite; import org.testng.ISuiteListener; import org.testng.ITestResult; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import test.listeners.SuiteAndConfigurationListenerTest.MyListener; /** * Check that if a listener implements IConfigurationListener additionally to * ISuiteListener, ISuiteListener gets invoked exactly once. * * @author Mihails Volkovs */ @Listeners(MyListener.class) public class SuiteAndConfigurationListenerTest { public static class MyListener implements ISuiteListener, IConfigurationListener { private static volatile AtomicInteger started = new AtomicInteger(0); public MyListener() { } @Override public void onStart(ISuite suite) { started.incrementAndGet(); } @Override public void onFinish(ISuite suite) { } @Override public void onConfigurationSuccess(ITestResult itr) { } @Override public void onConfigurationFailure(ITestResult itr) { } @Override public void onConfigurationSkip(ITestResult itr) { } } @Test public void bothListenersShouldRun() { Assert.assertEquals(MyListener.started.get(), 1, "ISuiteListener was not invoked exactly once:"); } } testng-6.9.12/src/test/java/test/listeners/ResultContextListener.java0000644000175000017500000000133312732165123025273 0ustar eugeneeugenepackage test.listeners; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; public class ResultContextListener implements ITestListener { public static boolean contextProvided = false; public void onTestStart(ITestResult result) { ITestContext context = result.getTestContext(); if (context != null) { contextProvided = true; } } public void onTestSuccess(ITestResult result) { } public void onTestFailure(ITestResult result) { } public void onTestSkipped(ITestResult result) { } public void onTestFailedButWithinSuccessPercentage(ITestResult result) { } public void onStart(ITestContext context) { } public void onFinish(ITestContext context) { } } testng-6.9.12/src/test/java/test/listeners/Derived3.java0000644000175000017500000000025412732165123022410 0ustar eugeneeugenepackage test.listeners; import org.testng.annotations.Test; class Derived3 extends BaseWithListener { @Test public void r() { } @Test public void r1() { } } testng-6.9.12/src/test/java/test/listeners/ListenerAssert.java0000644000175000017500000000074612732165123023720 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.ITestNGListener; import java.util.List; public final class ListenerAssert { private ListenerAssert() {} public static void assertListenerType(List listeners, Class clazz) { for (ITestNGListener listener : listeners) { if (clazz.isInstance(listener)) { return; } } Assert.fail(); } } testng-6.9.12/src/test/java/test/listeners/ResultEndMillisTest.java0000644000175000017500000000067012732165123024664 0ustar eugeneeugenepackage test.listeners; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import test.sample.Sample1; import junit.framework.Assert; public class ResultEndMillisTest extends SimpleBaseTest { @Test public void endMillisShouldBeNonNull() { TestNG tng = create(Sample1.class); tng.addListener(new ResultListener()); tng.run(); Assert.assertTrue(ResultListener.m_end > 0); } } testng-6.9.12/src/test/java/test/listeners/ConfigurationListenerTest.java0000644000175000017500000000251212732165123026117 0ustar eugeneeugenepackage test.listeners; import org.testng.Assert; import org.testng.IConfigurationListener2; import org.testng.ITestResult; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class ConfigurationListenerTest extends SimpleBaseTest { static public class CL implements IConfigurationListener2 { private static int m_status = 0; @Override public void beforeConfiguration(ITestResult tr) { m_status += 1; } @Override public void onConfigurationSuccess(ITestResult itr) { m_status += 3; } @Override public void onConfigurationFailure(ITestResult itr) { m_status += 5; } @Override public void onConfigurationSkip(ITestResult itr) { m_status += 7; } } private void runTest(Class cls, int expected) { TestNG tng = create(cls); CL listener = new CL(); CL.m_status = 0; tng.addListener(listener); tng.run(); Assert.assertEquals(CL.m_status, expected); } @Test public void shouldSucceed() { runTest(ConfigurationListenerSucceedSampleTest.class, 1 + 3); } @Test public void shouldFail() { runTest(ConfigurationListenerFailSampleTest.class, 1 + 5); } @Test public void shouldSkip() { runTest(ConfigurationListenerSkipSampleTest.class, 1 + 5 + 7); // fail + skip } } testng-6.9.12/src/test/java/test/configuration/0000755000175000017500000000000012732165123020736 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/configuration/BaseGroupsASampleTest.java0000644000175000017500000000032512732165123025756 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.Test; public class BaseGroupsASampleTest extends Base { @Test(groups = "foo") public void a() { // System.out.println( "a" ); } }testng-6.9.12/src/test/java/test/configuration/MultipleBeforeGroupTest.java0000644000175000017500000000072612732165123026401 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; @Test( groups = "foo" ) public class MultipleBeforeGroupTest { private int m_count = 0; @BeforeGroups( "foo" ) public void beforeGroups() { m_count++; } @Test() public void test() { } @Test(dependsOnMethods = "test") public void verify() { Assert.assertEquals(1, m_count); } } testng-6.9.12/src/test/java/test/configuration/Base3.java0000644000175000017500000000117712732165123022544 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeGroups; public class Base3 { static private boolean m_before = false; /** * @return the m_before */ public static boolean getBefore() { return m_before; } @BeforeGroups("cg34-1") public void anotherBefore1() { log("anotherBefore1"); Assert.assertFalse(m_before); Assert.assertFalse(ConfigurationGroups3SampleTest.getF1()); m_before = true; } private void log(String string) { ppp(string); } private void ppp(String s) { if (false) { System.out.println("[Base3] " + s); } } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroupDataProviderSampleTest.java0000644000175000017500000000166112732165123031740 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; public class ConfigurationGroupDataProviderSampleTest { static List m_list = new ArrayList<>(); @BeforeGroups(groups={"twice"}, value={"twice"}) public void a(){ ppp("BEFORE()"); m_list.add(1); } @Test(groups={"twice"}, dataProvider="MyData") public void b(int a, int b) { m_list.add(2); ppp("B()" + a + "," + b); } @AfterGroups(groups={"twice"}, value={"twice"}) public void c(){ m_list.add(3); ppp("AFTER()"); } @DataProvider(name="MyData") public Object[][] input(){ return new Object[][]{ {1,1}, {2,2}, {3,3}}; } private void ppp(String string) { if (false) { System.out.println("[A] " + string); } } } testng-6.9.12/src/test/java/test/configuration/SingleConfigurationTest.java0000644000175000017500000000145712732165123026421 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; /** * Make sure that @BeforeTest is only called once if a factory is used * * @author Cedric Beust */ public class SingleConfigurationTest { private static int m_before; @Factory(dataProvider = "dp") public SingleConfigurationTest(int n) { } @DataProvider public static Object[][] dp() { return new Object[][] { new Object[] { 42 }, new Object[] { 43 }, }; } @BeforeTest public void bt() { m_before++; } @Test public void verify() { Assert.assertEquals(m_before, 1); } } testng-6.9.12/src/test/java/test/configuration/BeforeMethodTest.java0000644000175000017500000000131312732165123025002 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.lang.reflect.Method; public class BeforeMethodTest { private Method m_method; private ITestContext m_context; @BeforeMethod public void before(Method m, ITestContext ctx) { m_method = m; m_context = ctx; } @Test public void mainTest() { Assert.assertEquals(m_method.getName(), "mainTest"); ITestNGMethod[] methods = m_context.getAllTestMethods(); Assert.assertEquals(1, methods.length); Assert.assertEquals(methods[0].getMethod().getName(), "mainTest"); } } testng-6.9.12/src/test/java/test/configuration/BaseSuiteTest.java0000644000175000017500000000070612732165123024330 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.BeforeSuite; import java.util.ArrayList; import java.util.List; public class BaseSuiteTest { public static List m_order; @BeforeSuite public void beforeSuiteParent(){ m_order = new ArrayList<>(); m_order.add(1); } // @AfterSuite // public void afterSuiteParent(){ // m_order.add(5); // System.out.println("AFTER SUITE PARENT"); // } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroupIteratorDataProviderSampleTest.java0000644000175000017500000000212012732165123033441 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class ConfigurationGroupIteratorDataProviderSampleTest { static List m_list = new ArrayList<>(); @BeforeGroups(groups={"twice"}, value={"twice"}) public void a(){ ppp("BEFORE()"); m_list.add(1); } @Test(groups={"twice"}, dataProvider="MyData") public void b(int a, int b) { m_list.add(2); ppp("B()" + a + "," + b); } @AfterGroups(groups={"twice"}, value={"twice"}) public void c(){ m_list.add(3); ppp("AFTER()"); } @DataProvider(name="MyData") public Iterator input() { return Arrays.asList( new Object[]{1, 1}, new Object[]{2, 2}, new Object[]{3, 3} ).iterator(); } private void ppp(String string) { if (false) { System.out.println("[A] " + string); } } } testng-6.9.12/src/test/java/test/configuration/SuiteFactoryOnceSample1Test.java0000644000175000017500000000063112732165123027112 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class SuiteFactoryOnceSample1Test { public static int m_before = 0; public static int m_after = 0; @BeforeSuite public void bs() { m_before++; } @AfterSuite public void as() { m_after++; } @Test public void g1() { } }testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups5SampleTest.java0000644000175000017500000000273212732165123027703 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterGroups; import org.testng.annotations.Test; /** * afterGroups test with more than one group * * @author cbeust * @date Mar 7, 2006 */ public class ConfigurationGroups5SampleTest { private boolean m_after = false; private boolean m_run1 = false; private boolean m_run2 = false; private int m_afterCount = 0; @Test public void f() { log("f"); } @Test(groups = "cg5-1") public void run1() { log("run1"); if (m_afterCount == 0) { Assert.assertFalse(m_after); } m_run1 = true; } @Test(groups = "cg5-2") public void run2() { log("run2"); if (m_afterCount == 0) { Assert.assertFalse(m_after); } m_run2 = true; } @AfterGroups({ "cg5-1", "cg5-2"}) public void after() { log("after"); m_afterCount++; Assert.assertTrue(m_run1 || m_run2); if (m_afterCount == 0) { Assert.assertFalse(m_after); } m_after = true; } @Test(dependsOnGroups = { "cg5-1", "cg5-2" }) public void verify() { log("verify"); Assert.assertTrue(m_run1, "run1() wasn't run"); Assert.assertTrue(m_run2, "run2() wasn't run"); Assert.assertTrue(m_after, "after1() wasn't run"); Assert.assertEquals(2, m_afterCount); } private void log(String string) { ppp(string); } private void ppp(String s) { if (false) { System.out.println("[ConfigurationGroups5SampleTest] " + s); } } } testng-6.9.12/src/test/java/test/configuration/VerifySuiteTest.java0000644000175000017500000000043312732165123024717 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterSuite; import java.util.Arrays; public class VerifySuiteTest { @AfterSuite public void verify() { Assert.assertEquals(Arrays.asList(1, 2, 3), SuiteTest.m_order); } } testng-6.9.12/src/test/java/test/configuration/BeforeTestOrderingTest.java0000644000175000017500000000300012732165123026166 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.Reporter; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import test.TestHelper; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class BeforeTestOrderingTest { private static List m_testNames; @BeforeSuite public void init() { m_testNames = new ArrayList<>(); } static void addTest(String testName) { m_testNames.add(testName); } @Test public void verifyBeforeTestOrdering() { XmlSuite s = new XmlSuite(); Reporter.log("BEFORE"); XmlTest t1 = new XmlTest(s); XmlClass c1 = new XmlClass("test.configuration.BeforeTestOrdering1Test"); t1.getXmlClasses().add(c1); XmlTest t2 = new XmlTest(s); XmlClass c2 = new XmlClass("test.configuration.BeforeTestOrdering2Test"); t2.getXmlClasses().add(c2); TestNG tng = TestHelper.createTestNG(); TestListenerAdapter tl = new TestListenerAdapter(); tng.addListener(tl); tng.setXmlSuites(Arrays.asList(new XmlSuite[] { s })); tng.run(); List expected = Arrays.asList(new String[] { "bt1", "f1", "at1", "bt2", "f2", "at2", }); Assert.assertEquals(expected, m_testNames); } private static void ppp(String s) { System.out.println("[BeforeTestOrderingTest] " + s); } } testng-6.9.12/src/test/java/test/configuration/MethodCallOrderTest.java0000644000175000017500000000404012732165123025447 0ustar eugeneeugenepackage test.configuration; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class MethodCallOrderTest { public static boolean s_beforeSuite; public static boolean s_beforeTest; public static boolean s_beforeClass; public static boolean s_beforeMethod; @BeforeClass public void beforeClass() { assertTrue(s_beforeSuite); assertTrue(s_beforeTest); assertFalse(s_beforeClass); assertFalse(s_beforeMethod); s_beforeClass = true; } @AfterSuite public void cleanUp() { s_beforeSuite = false; s_beforeTest = false; s_beforeClass = false; s_beforeMethod = false; } @BeforeMethod public void beforeMethod() { assertTrue(s_beforeSuite); assertTrue(s_beforeTest); assertTrue(s_beforeClass); assertFalse(s_beforeMethod); s_beforeMethod = true; } @Test public void realTest() { assertTrue(s_beforeSuite); assertTrue(s_beforeTest); assertTrue(s_beforeClass); assertTrue(s_beforeMethod); } @AfterMethod public void afterMethod() { assertFalse(ExternalConfigurationClass.s_afterMethod, "afterTestMethod shouldn't have been run"); assertFalse(ExternalConfigurationClass.s_afterClass, "afterTestClass shouldn't have been run"); assertFalse(ExternalConfigurationClass.s_afterTest, "afterTest should haven't been run"); ExternalConfigurationClass.s_afterMethod = true; } @AfterClass public void afterClass() { assertTrue(ExternalConfigurationClass.s_afterMethod, "afterTestMethod should have been run"); assertFalse(ExternalConfigurationClass.s_afterClass, "afterTestClass shouldn't have been run"); assertFalse(ExternalConfigurationClass.s_afterTest, "afterTest should haven't been run"); ExternalConfigurationClass.s_afterClass = true; } } testng-6.9.12/src/test/java/test/configuration/ReflectMethodParametrizedConfigurationMethodTest.java0000644000175000017500000000265612732165123033440 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * This class/interface */ public class ReflectMethodParametrizedConfigurationMethodTest { private Map m_before= new HashMap<>(); private Map m_after= new HashMap<>(); @BeforeMethod public void beforeMethod(Method tobeInvokedTestMethod) { m_before.put(tobeInvokedTestMethod.getName(), tobeInvokedTestMethod.getName()); } @Test public void test1() {} @Test public void test2() {} @AfterMethod public void afterMethod(Method invokedTestMethod) { m_after.put(invokedTestMethod.getName(), invokedTestMethod.getName()); } @AfterClass public void assertBeforeAfterMethodsInvocations() { Assert.assertTrue(m_before.containsKey("test1"), "@Test method should have been passed to @BeforeMethod"); Assert.assertTrue(m_before.containsKey("test2"), "@Test method should have been passed to @BeforeMethod"); Assert.assertTrue(m_after.containsKey("test1"), "@Test method should have been passed to @AfterMethod"); Assert.assertTrue(m_before.containsKey("test2"), "@Test method should have been passed to @AfterMethod"); } } testng-6.9.12/src/test/java/test/configuration/BeforeTestOrdering2Test.java0000644000175000017500000000074412732165123026264 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class BeforeTestOrdering2Test extends BaseBeforeTestOrdering{ @BeforeTest public void bt2() { log("bt2"); } @AfterTest public void at2() { log("at2"); } @Test public void f2() { log("f2"); } private static void ppp(String s) { System.out.println("[BeforeTestOrdering2Test] " + s); } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups2SampleTest.java0000644000175000017500000000261612732165123027701 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; /** * beforeGroups test: make sure that the beforeGroups method is invoked * only once even if two test methods belong to the group * * @author cbeust * @date Mar 3, 2006 */ public class ConfigurationGroups2SampleTest { private boolean m_before = false; private boolean m_f1 = false; private boolean m_g1 = false; @BeforeGroups("cg2-1") public void before1() { Assert.assertFalse(m_before); Assert.assertFalse(m_f1); Assert.assertFalse(m_g1); m_before = true; log("before1"); } @Test(groups = "cg2-a") public void fa() { log("fa"); } @Test(groups = "cg2-1") public void f1() { Assert.assertTrue(m_before); m_f1 = true; log("f1"); } @Test(groups = "cg2-1") public void g1() { Assert.assertTrue(m_before); m_g1 = true; log("g1"); } private List m_list = new ArrayList<>(); @Test(dependsOnGroups = {"cg2-a", "cg2-1"}) public void verify() { Assert.assertTrue(m_before); Assert.assertTrue(m_f1); Assert.assertTrue(m_g1); } private void log(String s) { m_list.add(s); ppp(s); } private void ppp(String s) { if (false) { System.out.println("[ConfigurationGroups2SampleTest] " + s); } } } testng-6.9.12/src/test/java/test/configuration/BaseBeforeTestOrdering.java0000644000175000017500000000021712732165123026130 0ustar eugeneeugenepackage test.configuration; public class BaseBeforeTestOrdering { public void log(String s) { BeforeTestOrderingTest.addTest(s); } } testng-6.9.12/src/test/java/test/configuration/GroupsTest.java0000644000175000017500000000312012732165123023714 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.Arrays; import java.util.List; public class GroupsTest { private TestNG m_testNg; @BeforeMethod public void setUp() { m_testNg = new TestNG(); m_testNg.setVerbose(0); } @Test public void verifyDataProviderAfterGroups() { runTest(ConfigurationGroupDataProviderSampleTest.class, ConfigurationGroupDataProviderSampleTest.m_list, Arrays.asList(new Integer[] { 1, 2, 2, 2, 3 })); } @Test public void verifyIteratorDataProviderAfterGroups() { runTest(ConfigurationGroupIteratorDataProviderSampleTest.class, ConfigurationGroupIteratorDataProviderSampleTest.m_list, Arrays.asList(new Integer[] { 1, 2, 2, 2, 3 })); } @Test public void verifyParametersAfterGroups() { runTest(ConfigurationGroupInvocationCountSampleTest.class, ConfigurationGroupInvocationCountSampleTest.m_list, Arrays.asList(new Integer[] { 1, 2, 2, 2, 3 })); } @Test public void verifyBothAfterGroups() { runTest(ConfigurationGroupBothSampleTest.class, ConfigurationGroupBothSampleTest.m_list, Arrays.asList(new Integer[] { 1, 2, 2, 2, 2, 2, 2, 3 })); } private void runTest(Class cls, List list, List expected) { m_testNg.setTestClasses(new Class[] { cls }); m_testNg.run(); Assert.assertEquals(list, expected); } } testng-6.9.12/src/test/java/test/configuration/BeforeClassWithDisabledTest.java0000644000175000017500000000105212732165123027113 0ustar eugeneeugenepackage test.configuration; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import junit.framework.Assert; public class BeforeClassWithDisabledTest extends SimpleBaseTest { @Test public void afterClassShouldRunEvenWithDisabledMethods() { TestNG tng = create(new Class[] { ConfigurationDisabledSampleTest.class }); Assert.assertFalse(ConfigurationDisabledSampleTest.m_afterWasRun); tng.run(); Assert.assertTrue(ConfigurationDisabledSampleTest.m_afterWasRun); } } testng-6.9.12/src/test/java/test/configuration/BaseGroupsTest.java0000644000175000017500000000165112732165123024516 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; /** * Verify that a base class with a BeforeGroups method only gets invoked * once, no matter how many subclasses it has * * Created on Jan 23, 2007 * @author Cedric Beust */ public class BaseGroupsTest { @Test public void verifySingleInvocation() { TestNG tng = new TestNG(); tng.setVerbose(0); tng.setTestClasses(new Class[] { BaseGroupsASampleTest.class, BaseGroupsBSampleTest.class, }); TestListenerAdapter tla = new TestListenerAdapter(); tng.addListener(tla); tng.run(); Assert.assertEquals(Base.m_count, 1); } private static void ppp(String s) { System.out.println("[BaseGroupsTest] " + s); } } testng-6.9.12/src/test/java/test/configuration/BeforeClassThreadB.java0000644000175000017500000000060212732165123025221 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class BeforeClassThreadB { public static long WHEN; @BeforeClass(alwaysRun = true) public void setup() throws InterruptedException { WHEN = System.currentTimeMillis(); Thread.sleep(2000); } @Test public void execute() { } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroupInvocationCountSampleTest.java0000644000175000017500000000137312732165123032476 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; public class ConfigurationGroupInvocationCountSampleTest { static List m_list = new ArrayList<>(); @BeforeGroups(groups={"twice"}, value={"twice"}) public void a(){ ppp("BEFORE()"); m_list.add(1); } @Test(groups = {"twice"}, invocationCount = 3) public void b() { m_list.add(2); ppp("B()"); } @AfterGroups(groups={"twice"}, value={"twice"}) public void c(){ m_list.add(3); ppp("AFTER()"); } private void ppp(String string) { if (false) { System.out.println("[A] " + string); } } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroupBothSampleTest.java0000644000175000017500000000227412732165123030251 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ConfigurationGroupBothSampleTest { static List m_list = Collections.synchronizedList(new ArrayList()); private synchronized static void addToList(Integer n) { m_list.add(n); } @BeforeGroups(groups={"twice"}, value={"twice"}) public void a(){ ppp("BEFORE()"); addToList(1); } @Test(groups={"twice"}, dataProvider="MyData", invocationCount = 2, threadPoolSize=2) public void b(int a, int b) { addToList(2); ppp("B()" + a + "," + b); } @AfterGroups(groups={"twice"}, value={"twice"}) public void c(){ addToList(3); ppp("AFTER()"); } @DataProvider(name="MyData") public Object[][] input(){ return new Object[][]{ {1,1}, {2,2}, {3,3}}; } private void ppp(String string) { if (false) { System.out.println("[A] " + string + " on Thread:" + Thread.currentThread()); } } } testng-6.9.12/src/test/java/test/configuration/BeforeClassThreadTest.java0000644000175000017500000000111412732165123025756 0ustar eugeneeugenepackage test.configuration; import org.testng.TestNG; import org.testng.annotations.Test; import org.testng.xml.XmlSuite; import test.SimpleBaseTest; import junit.framework.Assert; public class BeforeClassThreadTest extends SimpleBaseTest{ @Test public void beforeClassMethodsShouldRunInParallel() { TestNG tng = create(new Class[] { BeforeClassThreadA.class, BeforeClassThreadB.class }); tng.setParallel(XmlSuite.ParallelMode.METHODS); tng.run(); Assert.assertTrue(Math.abs(BeforeClassThreadA.WHEN - BeforeClassThreadB.WHEN) < 1000); } } testng-6.9.12/src/test/java/test/configuration/BeforeTestOrdering1Test.java0000644000175000017500000000074512732165123026264 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class BeforeTestOrdering1Test extends BaseBeforeTestOrdering { @BeforeTest public void bt1() { log("bt1"); } @AfterTest public void at1() { log("at1"); } @Test public void f1() { log("f1"); } private static void ppp(String s) { System.out.println("[BeforeTestOrdering1Test] " + s); } } testng-6.9.12/src/test/java/test/configuration/SuiteTest.java0000644000175000017500000000100312732165123023524 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; public class SuiteTest extends BaseSuiteTest { @BeforeSuite(dependsOnMethods={"beforeSuiteParent"}) public void beforeSuiteChild(){ m_order.add(2); } // @AfterSuite(dependsOnMethods={"afterSuiteParent"}) // public void afterSuiteChild(){ // m_order.add(4); // System.out.println("AFTER SUITE CHILD"); // } @Test public void test1(){ m_order.add(3); } } testng-6.9.12/src/test/java/test/configuration/SuiteFactoryOnceTest.java0000644000175000017500000000107512732165123025672 0ustar eugeneeugenepackage test.configuration; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import junit.framework.Assert; public class SuiteFactoryOnceTest extends SimpleBaseTest { @Test public void suiteMethodsShouldOnlyRunOnce() { TestNG tng = create(SuiteFactoryOnceSample2Test.class); SuiteFactoryOnceSample1Test.m_before = 0; SuiteFactoryOnceSample1Test.m_after = 0; tng.run(); Assert.assertEquals(1, SuiteFactoryOnceSample1Test.m_before); Assert.assertEquals(1, SuiteFactoryOnceSample1Test.m_after); } } testng-6.9.12/src/test/java/test/configuration/ConfigurationInheritGroupsSampleTest.java0000644000175000017500000000073612732165123031143 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @Test(groups = { "group1" }) public class ConfigurationInheritGroupsSampleTest { private boolean m_ok = false; @BeforeMethod public void setUp() { m_ok = true; } public void test1() { Assert.assertTrue(m_ok); } private void ppp(String s) { System.out.println("[ConfigurationInheritGroupsSampleTest] " + s); } } testng-6.9.12/src/test/java/test/configuration/BeforeClassThreadA.java0000644000175000017500000000060212732165123025220 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class BeforeClassThreadA { public static long WHEN; @BeforeClass(alwaysRun = true) public void setup() throws InterruptedException { WHEN = System.currentTimeMillis(); Thread.sleep(2000); } @Test public void execute() { } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups6SampleTest.java0000644000175000017500000000244112732165123027701 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterGroups; import org.testng.annotations.Test; /** * afterGroups test when the group contains more than one method * * @author cbeust * @date Mar 7, 2006 */ public class ConfigurationGroups6SampleTest { private boolean m_after = false; private boolean m_run1 = false; private boolean m_run2 = false; @Test public void f() { log("f"); } @Test(groups = "cg6-1") public void run1() { log("run1"); Assert.assertFalse(m_after); m_run1 = true; } @Test(groups = "cg6-1") public void run2() { log("run2"); Assert.assertFalse(m_after); m_run2 = true; } @AfterGroups("cg6-1") public void after() { log("after"); Assert.assertTrue(m_run1); Assert.assertTrue(m_run2); Assert.assertFalse(m_after); m_after = true; } @Test(dependsOnGroups = { "cg6-1" }) public void verify() { log("verify"); Assert.assertTrue(m_run1, "run1() wasn't run"); Assert.assertTrue(m_run2, "run2() wasn't run"); Assert.assertTrue(m_after, "after1() wasn't run"); } private void log(String string) { ppp(string); } private void ppp(String s) { if (false) { System.out.println("[ConfigurationGroups4SampleTest] " + s); } } } testng-6.9.12/src/test/java/test/configuration/ConfigurationDisabledSampleTest.java0000644000175000017500000000075712732165123030053 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ConfigurationDisabledSampleTest { public static boolean m_afterWasRun; @BeforeClass(alwaysRun = true) public void before() { m_afterWasRun = false; } @AfterClass(alwaysRun = true) public void after() { m_afterWasRun = true; } @Test public void f1() {} @Test(enabled = false) public void f2() {} }testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups3SampleTest.java0000644000175000017500000000254412732165123027702 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; /** * beforeGroups test: make sure that if before methods are scattered on * more than one class, they are still taken into account * * @author cbeust * @date Mar 3, 2006 */ public class ConfigurationGroups3SampleTest extends Base3 { private boolean m_before = false; static private boolean m_f1 = false; @BeforeGroups("cg34-1") public void before1() { Assert.assertFalse(m_before); Assert.assertFalse(m_f1); m_before = true; log("before1"); } @Test(groups = "cg34-a") public void fa() { log("fa"); } @Test(groups = "cg34-1") public void f1() { Assert.assertTrue(m_before); Assert.assertTrue(Base3.getBefore()); m_f1 = true; log("f1"); } private List m_list = new ArrayList<>(); @Test(dependsOnGroups = {"cg34-a", "cg34-1"}) public void verify() { Assert.assertTrue(m_before); Assert.assertTrue(Base3.getBefore()); Assert.assertTrue(m_f1); } private void log(String s) { m_list.add(s); ppp(s); } private void ppp(String s) { if (false) { System.out.println("[ConfigurationGroups3SampleTest] " + s); } } public static boolean getF1() { return m_f1; } } testng-6.9.12/src/test/java/test/configuration/BaseGroupsBSampleTest.java0000644000175000017500000000032512732165123025757 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.Test; public class BaseGroupsBSampleTest extends Base { @Test(groups = "foo") public void b() { // System.out.println( "b" ); } }testng-6.9.12/src/test/java/test/configuration/SuiteFactoryOnceSample2Test.java0000644000175000017500000000040212732165123027107 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.Factory; public class SuiteFactoryOnceSample2Test { @Factory public Object[] factory() { return new Object[] { new SuiteFactoryOnceSample1Test(), new SuiteFactoryOnceSample1Test() }; } } testng-6.9.12/src/test/java/test/configuration/ConfigurationListenerSampleTest.java0000644000175000017500000000126012732165123030117 0ustar eugeneeugenepackage test.configuration; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.annotations.BeforeClass; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import test.configuration.ConfigurationListenerSampleTest.MyTLA; @Listeners(MyTLA.class) public class ConfigurationListenerSampleTest { static boolean m_passed = false; public static class MyTLA extends TestListenerAdapter { @Override public void onConfigurationFailure(ITestResult itr) { m_passed = true; } } @BeforeClass public void bm() { m_passed = false; throw new RuntimeException(); } @Test public void f1() { } }testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups7SampleTest.java0000644000175000017500000000150112732165123027676 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterGroups; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ConfigurationGroups7SampleTest { private List m_log = new ArrayList<>(); @BeforeGroups({"A"}) private void initA() { m_log.add("1"); } @Test(groups = {"A"}) public void testSomething() { m_log.add("2"); } @Test(groups = {"A"}) public void testSomethingMore() { m_log.add("2"); } @AfterGroups({"A"}) private void cleanUpA() { m_log.add("3"); } @Test(dependsOnGroups = "A") public void verify() { Assert.assertEquals(Arrays.asList(new String[] { "1", "2", "2", "3"}), m_log); } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups1SampleTest.java0000644000175000017500000000217312732165123027676 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; /** * Simple beforeGroups test: 1 before method and 2 test method * * @author cbeust * @date Mar 3, 2006 */ public class ConfigurationGroups1SampleTest { private boolean m_before = false; private boolean m_f1 = false; @BeforeGroups("cg1-1") public void before1() { Assert.assertFalse(m_before); Assert.assertFalse(m_f1); m_before = true; log("before1"); } @Test(groups = "cg1-a") public void fa() { log("fa"); } @Test(groups = "cg1-1") public void f1() { Assert.assertTrue(m_before); m_f1 = true; log("f1"); } private List m_list = new ArrayList<>(); @Test(dependsOnGroups = {"cg1-a", "cg1-1"}) public void verify() { Assert.assertTrue(m_before); Assert.assertTrue(m_f1); } private void log(String s) { m_list.add(s); ppp(s); } private void ppp(String s) { if (false) { System.out.println("[ConfigurationGroups1SampleTest] " + s); } } } testng-6.9.12/src/test/java/test/configuration/ConfigurationWithParameters.java0000644000175000017500000000073412732165123027274 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class ConfigurationWithParameters { private String m_param; @Parameters({ "param" }) @BeforeTest public void testInit(String param) { m_param = param; } @Parameters({ "param" }) @Test public void testMethod(String param) { Assert.assertEquals(m_param, param); } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups4SampleTest.java0000644000175000017500000000200212732165123027670 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterGroups; import org.testng.annotations.Test; /** * Simple afterGroups test * * @author cbeust * @date Mar 7, 2006 */ public class ConfigurationGroups4SampleTest { private boolean m_after = false; private boolean m_run = false; @Test public void f() { log("f"); } @Test(groups = "cg4-1") public void run() { log("run"); Assert.assertFalse(m_after); m_run = true; } @AfterGroups("cg4-1") public void after1() { log("after1"); Assert.assertTrue(m_run); Assert.assertFalse(m_after); m_after = true; } @Test(dependsOnGroups = "cg4-1") public void verify() { log("verify"); Assert.assertTrue(m_run, "run() wasn't run"); Assert.assertTrue(m_after, "after1() wasn't run"); } private void log(String string) { ppp(string); } private void ppp(String s) { if (false) { System.out.println("[ConfigurationGroups4SampleTest] " + s); } } } testng-6.9.12/src/test/java/test/configuration/ConfigurationGroups8SampleTest.java0000644000175000017500000000205512732165123027704 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Run with group "A" and "B" * Make sure that only methods and configurations belonging to that group * get invoked. * * @author cbeust * @date Mar 9, 2006 */ public class ConfigurationGroups8SampleTest { private List m_log = new ArrayList<>(); @Test public void dummy() { m_log.add("should not be invoked"); } @Test(groups = { "A" }) public void testSomething() { m_log.add("1"); } @Test(groups = { "A" }) public void testSomethingMore() { m_log.add("1"); } @AfterMethod private void cleanUpDummy() { m_log.add("should not be invoked"); } @AfterMethod(groups = "A") private void cleanUpA() { m_log.add("a"); } @Test(dependsOnGroups = "A", groups = "B") public void verify() { Assert.assertEquals(Arrays.asList(new String[] { "1", "a", "1", "a" }), m_log); } } testng-6.9.12/src/test/java/test/configuration/ExternalConfigurationClass.java0000644000175000017500000000272712732165123027111 0ustar eugeneeugenepackage test.configuration; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; public class ExternalConfigurationClass { public static boolean s_afterMethod; public static boolean s_afterClass; public static boolean s_afterTest; @BeforeSuite public void beforeSuite() { MethodCallOrderTest.s_beforeSuite = true; } @AfterSuite public void cleanUp() { s_afterMethod = false; s_afterClass = false; s_afterTest = false; } @BeforeTest public void beforeTest() { assertTrue(MethodCallOrderTest.s_beforeSuite); assertFalse(MethodCallOrderTest.s_beforeTest); assertFalse(MethodCallOrderTest.s_beforeClass); assertFalse(MethodCallOrderTest.s_beforeMethod); MethodCallOrderTest.s_beforeTest = true; } @AfterTest public void afterTest() { assertTrue(s_afterMethod, "afterTestMethod should have been run"); assertTrue(s_afterClass, "afterTestClass should have been run"); assertFalse(s_afterTest, "afterTest should haven't been run"); s_afterTest = true; } @AfterSuite public void afterSuite() { assertTrue(s_afterMethod, "afterTestMethod should have been run"); assertTrue(s_afterClass, "afterTestClass should have been run"); assertTrue(s_afterTest, "afterTest should have been run"); } } testng-6.9.12/src/test/java/test/configuration/Base.java0000644000175000017500000000072312732165123022455 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @Test(groups = {"base"}) public class Base { static int m_count; @BeforeTest public void init() { m_count = 0; } @BeforeGroups(groups = "foo") public void beforeGroups() { m_count++; } private static void ppp(String s) { System.out.println("[Base] " + s); } }testng-6.9.12/src/test/java/test/configuration/ConfigurationListenerTest.java0000644000175000017500000000073512732165123026763 0ustar eugeneeugenepackage test.configuration; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; public class ConfigurationListenerTest extends SimpleBaseTest { @Test public void listenerShouldBeCalled() { TestNG tng = create(ConfigurationListenerSampleTest.class); Assert.assertFalse(ConfigurationListenerSampleTest.m_passed); tng.run(); Assert.assertTrue(ConfigurationListenerSampleTest.m_passed); } } testng-6.9.12/src/test/java/test/configuration/ConfigurationTest.java0000644000175000017500000000771212732165123025257 0ustar eugeneeugenepackage test.configuration; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; /** * Test @Configuration * * @author cbeust */ public class ConfigurationTest { private boolean m_beforeSuite = false; private boolean m_afterSuite = false; private boolean m_beforeClass = false; private boolean m_afterClass = false; private boolean m_beforeMethod = false; private boolean m_afterMethod = false; @BeforeSuite public void beforeSuite() { ppp("@@@@ BEFORE_SUITE"); assert ! m_afterSuite : "afterSuite shouldn't have run"; assert ! m_beforeClass : "beforeClass shouldn't have run"; assert ! m_afterClass : "afterClass shouldn't have run"; assert ! m_beforeMethod: "beforeMethod shouldn't have run"; assert ! m_afterMethod: "afterMethod shouldn't have run"; m_beforeSuite = true; } @BeforeClass public void beforeClass() { ppp("@@@@ BEFORE_CLASS"); assert m_beforeSuite : "beforeSuite should have run"; assert ! m_afterSuite : "afterSuite shouldn't have run"; assert ! m_beforeClass : "beforeClass shouldn't have run"; assert ! m_afterClass : "afterClass shouldn't have run"; assert ! m_beforeMethod: "beforeMethod shouldn't have run"; assert ! m_afterMethod: "afterMethod shouldn't have run"; m_beforeClass = true; } @BeforeMethod public void beforeMethod() { ppp("@@@@ BEFORE_METHOD"); assert m_beforeSuite : "beforeSuite should have run"; assert m_beforeClass : "beforeClass have run"; assert ! m_afterSuite : "afterSuite shouldn't have run"; assert ! m_afterClass : "afterClass shouldn't have run"; assert ! m_beforeMethod: "beforeMethod shouldn't have run"; assert ! m_afterMethod: "afterMethod shouldn't have run"; m_beforeMethod = true; } @AfterMethod public void afterMethod() { ppp("@@@@ AFTER_METHOD"); assert m_beforeSuite : "beforeSuite should have run"; assert m_beforeClass : "beforeClass have run"; assert m_beforeMethod: "beforeMethod should have run"; assert ! m_afterSuite : "afterSuite shouldn't have run"; assert ! m_afterClass : "afterClass shouldn't have run"; assert ! m_afterMethod: "afterMethod shouldn't have run"; m_afterMethod = true; } @AfterClass public void afterClass() { ppp("@@@@ AFTER_CLASS"); assert m_beforeSuite : "beforeSuite should have run"; assert m_beforeClass : "beforeClass have run"; assert m_beforeMethod: "beforeMethod should have run"; assert m_afterMethod: "afterMethod should have run"; assert ! m_afterClass : "afterClass shouldn't have run"; assert ! m_afterSuite : "afterSuite shouldn't have run"; m_afterClass = true; } @AfterSuite public void afterSuite() { ppp("@@@@ AFTER_SUITE"); ppp(m_beforeSuite + " " + m_beforeClass + " " + m_beforeMethod + " " + m_afterMethod + " " + m_afterClass + " " + m_afterSuite); assert m_beforeSuite : "beforeSuite should have run"; assert m_beforeClass : "beforeClass have run"; assert m_beforeMethod: "beforeMethod should have run"; assert m_afterMethod: "afterMethod should have run"; assert m_afterClass : "afterClass should have run"; assert ! m_afterSuite : "afterSuite shouldn't have run"; m_afterSuite = true; } @Test public void verify() { ppp("@@@@ VERIFY"); assert m_beforeSuite : "beforeSuite should have run"; assert m_beforeClass : "beforeClass have run"; assert m_beforeMethod: "beforeMethod should have run"; assert ! m_afterSuite : "afterSuite shouldn't have run"; assert ! m_afterClass : "afterClass shouldn't have run"; assert ! m_afterMethod: "afterMethod shouldn't have run"; } private static void ppp(String s) { if (false) { System.out.println("[ConfigurationTest] " + s); } } } testng-6.9.12/src/test/java/test/jarpackages/0000755000175000017500000000000012732165123020342 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/jarpackages/testng.xml0000644000175000017500000000037012732165123022370 0ustar eugeneeugene testng-6.9.12/src/test/java/test/jarpackages/JarPackagesTest.java0000644000175000017500000000313712732165123024224 0ustar eugeneeugenepackage test.jarpackages; import org.testng.Assert; import org.testng.TestListenerAdapter; import org.testng.TestNG; import org.testng.annotations.Test; import test.SimpleBaseTest; import java.io.File; public class JarPackagesTest extends SimpleBaseTest { private TestListenerAdapter init(String jarFile) { TestNG tng = create(); File currentDir = new File("."); String path = currentDir.getAbsolutePath(); char s = File.separatorChar; path = path + s + "test" + s + "src" + s + "test" + s + "jarpackages" + s; String finalPath = path + jarFile; tng.setTestJar(finalPath); TestListenerAdapter result = new TestListenerAdapter(); tng.addListener(result); tng.run(); return result; } @Test public void jarWithTestngXml() { TestListenerAdapter tla = init("withtestngxml.jar"); Assert.assertEquals(tla.getPassedTests().size(), 2); String first = tla.getPassedTests().get(0).getName(); String second = tla.getPassedTests().get(1).getName(); boolean fThenG = "f".equals(first) && "g".equals(second); boolean gThenF = "g".equals(first) && "f".equals(second); Assert.assertTrue(fThenG || gThenF); } @Test public void jarWithoutTestngXml() { TestListenerAdapter tla = init("withouttestngxml.jar"); Assert.assertEquals(tla.getPassedTests().size(), 2); String first = tla.getPassedTests().get(0).getName(); String second = tla.getPassedTests().get(1).getName(); boolean fThenG = "f".equals(first) && "g".equals(second); boolean gThenF = "g".equals(first) && "f".equals(second); Assert.assertTrue(fThenG || gThenF); } } testng-6.9.12/src/test/java/test/jarpackages/tests/0000755000175000017500000000000012732165123021504 5ustar eugeneeugenetestng-6.9.12/src/test/java/test/jarpackages/tests/B.java0000644000175000017500000000016712732165123022534 0ustar eugeneeugenepackage test.jarpackages.tests; import org.testng.annotations.Test; public class B { @Test public void g() {} } testng-6.9.12/src/test/java/test/jarpackages/tests/A.java0000644000175000017500000000016712732165123022533 0ustar eugeneeugenepackage test.jarpackages.tests; import org.testng.annotations.Test; public class A { @Test public void f() {} } testng-6.9.12/src/test/java/testhelper/0000755000175000017500000000000012732165123017267 5ustar eugeneeugenetestng-6.9.12/src/test/java/testhelper/OutputDirectoryPatch.java0000644000175000017500000000301412732165123024275 0ustar eugeneeugenepackage testhelper; /** * OutputDirectoryPatch is a helper class to provide an output directory * for TestNG tests that explicitly create an instance of TestNG and do not know the * output directory specified for the test. * * @author cquezel * @since 4.8 */ public final class OutputDirectoryPatch { /** The default output directory name if none was specified. We should use something * different than "test-output" to make it clear that the output directory * has not been set. */ private static final String DEFAULT_OUTPUT_DIRECTORY = "test-output"; /** The name of the System property used to store the output directory. */ private static final String OUTPUT_DIRECTORY_PROPERTY_NAME = "testng.outputDir"; /** * Private constructor to disable instantiation. * * @since 4.8 */ private OutputDirectoryPatch() { // Hide constructor } /** * Returns the output directory as specified for the current test. * * @return the output directory as specified for the current test. * @since 4.8 */ public static String getOutputDirectory() { String tmp = System.getProperty(OUTPUT_DIRECTORY_PROPERTY_NAME); if (tmp != null) { return tmp; } // System.err.println("System property: " + OUTPUT_DIRECTORY_PROPERTY_NAME // + " has not been set. Using default path: " + DEFAULT_OUTPUT_DIRECTORY); // new Throwable("Stack is only to help locate the problem. No excpetion thrown.").printStackTrace(System.err); return DEFAULT_OUTPUT_DIRECTORY; } } testng-6.9.12/src/test/groovy/0000755000175000017500000000000012732165123015514 5ustar eugeneeugenetestng-6.9.12/src/test/groovy/test/0000755000175000017500000000000012732165123016473 5ustar eugeneeugenetestng-6.9.12/src/test/groovy/test/groovy/0000755000175000017500000000000012732165123020020 5ustar eugeneeugenetestng-6.9.12/src/test/groovy/test/groovy/EasyJUnitGroovySample.groovy0000644000175000017500000000051512732165123025513 0ustar eugeneeugenepackage test.groovy import org.junit.Test import static groovy.test.GroovyAssert.shouldFail // Sample from http://groovy-lang.org/testing.html#_junit_4 class EasyJUnitGroovySample { @Test void indexOutOfBoundsAccess() { def numbers = [1, 2, 3, 4] shouldFail { numbers.get(4) } } } testng-6.9.12/src/test/groovy/test/groovy/SpecialNameJUnitGroovySample.groovy0000644000175000017500000000053212732165123026772 0ustar eugeneeugenepackage test.groovy import org.junit.Test import static groovy.test.GroovyAssert.shouldFail // Sample from http://groovy-lang.org/testing.html#_junit_4 class SpecialNameJUnitGroovySample { @Test void "index Out Of Bounds Access"() { def numbers = [1, 2, 3, 4] shouldFail { numbers.get(4) } } } testng-6.9.12/src/test/groovy/test/groovy/SpockSample.groovy0000644000175000017500000000047612732165123023517 0ustar eugeneeugenepackage test.groovy import spock.lang.Specification class SpockSample extends Specification { def "adding an element leads to size increase"() { setup: "a new stack instance is created" def stack = new Stack() when: stack.push 42 then: stack.size() == 1 } }testng-6.9.12/src/test/groovy/test/groovy/GroovyTest.groovy0000644000175000017500000000252012732165123023413 0ustar eugeneeugenepackage test.groovy import org.testng.ITestNGListener import org.testng.TestListenerAdapter import org.testng.annotations.Test import test.SimpleBaseTest class GroovyTest extends SimpleBaseTest { @Test void easyGroovySampleShouldWork() { def tng = create(EasyJUnitGroovySample) tng.setJUnit(true) def adapter = new TestListenerAdapter() tng.addListener((ITestNGListener)adapter) tng.run() assert adapter.failedTests.isEmpty() assert adapter.skippedTests.isEmpty() assert adapter.passedTests.size() == 1 } @Test void specialNameGroovySampleShouldWork() { def tng = create(SpecialNameJUnitGroovySample) tng.setJUnit(true) def adapter = new TestListenerAdapter() tng.addListener((ITestNGListener)adapter) tng.run() assert adapter.failedTests.isEmpty() assert adapter.skippedTests.isEmpty() assert adapter.passedTests.size() == 1 } @Test void spockSampleShouldWork() { def tng = create(SpockSample) tng.setJUnit(true) def adapter = new TestListenerAdapter() tng.addListener((ITestNGListener)adapter) tng.run() assert adapter.failedTests.isEmpty() assert adapter.skippedTests.isEmpty() assert adapter.passedTests.size() == 1 } } testng-6.9.12/src/test/resources/0000755000175000017500000000000012735760204016205 5ustar eugeneeugenetestng-6.9.12/src/test/resources/xml/0000755000175000017500000000000012732165123017001 5ustar eugeneeugenetestng-6.9.12/src/test/resources/xml/goodWithDoctype.xml0000644000175000017500000000030112732165123022631 0ustar eugeneeugene testng-6.9.12/src/test/resources/xml/badWithoutDoctype.xml0000644000175000017500000000020512732165123023162 0ustar eugeneeugene testng-6.9.12/src/test/resources/xml/badWithDoctype.xml0000644000175000017500000000030112732165123022427 0ustar eugeneeugene testng-6.9.12/src/test/resources/xml/goodWithoutDoctype.xml0000644000175000017500000000020512732165123023364 0ustar eugeneeugene testng-6.9.12/src/test/resources/testnames/0000755000175000017500000000000012732165123020204 5ustar eugeneeugenetestng-6.9.12/src/test/resources/testnames/main-suite.xml0000644000175000017500000000124412732165123023002 0ustar eugeneeugene testng-6.9.12/src/test/resources/testnames/upstream-suite.xml0000644000175000017500000000032712732165123023717 0ustar eugeneeugene testng-6.9.12/src/test/resources/a.xml0000644000175000017500000000031612732165123017143 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng.xml0000644000175000017500000005612512732165123020240 0ustar eugeneeugene testng-6.9.12/src/test/resources/junit-suite.xml0000644000175000017500000000040512732165123021202 0ustar eugeneeugene testng-6.9.12/src/test/resources/create-serviceloader-jar.sh0000644000175000017500000000077212732165123023405 0ustar eugeneeugene# This script will update serviceloader.jar with the latest version of TmpSuiteListener.class, # which is used by test.serviceloader.ServiceLoaderTest. # Run this script after building TestNG and its tests with ant j=${PWD} rm -rf /tmp/sl mkdir /tmp/sl cd /tmp/sl jar xvf ${j}/serviceloader.jar echo "test.serviceloader.TmpSuiteListener" >META-INF/services/org.testng.ITestNGListener cp ${j}/../../../target/test-classes/test/serviceloader/TmpSuiteListener.class test/tmp jar cvf ${j}/serviceloader.jar . testng-6.9.12/src/test/resources/testng-all.xml0000644000175000017500000000507412732165123021003 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-single.xml0000644000175000017500000000067712732165123021520 0ustar eugeneeugene testng-6.9.12/src/test/resources/parent-module-suite.xml0000644000175000017500000000041212732165123022623 0ustar eugeneeugene testng-6.9.12/src/test/resources/methodselector-in-xml.xml0000644000175000017500000000056112732165123023150 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/0000755000175000017500000000000012732165123020506 5ustar eugeneeugenetestng-6.9.12/src/test/resources/sanitycheck/test-s-3.xml0000644000175000017500000000060012732165123022603 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test-s-2.xml0000644000175000017500000000057612732165123022616 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test-a.xml0000644000175000017500000000030212732165123022420 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test-b.xml0000644000175000017500000000030212732165123022421 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test-s-1.xml0000644000175000017500000000057612732165123022615 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test3.xml0000644000175000017500000000057512732165123022301 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test-s-a.xml0000644000175000017500000000031012732165123022657 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test2.xml0000644000175000017500000000057712732165123022302 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test-s-b.xml0000644000175000017500000000031012732165123022660 0ustar eugeneeugene testng-6.9.12/src/test/resources/sanitycheck/test1.xml0000644000175000017500000000112612732165123022270 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng_convert.xml0000644000175000017500000000056312732165123021773 0ustar eugeneeugene testng-6.9.12/src/test/resources/methodinterceptors/0000755000175000017500000000000012732165123022123 5ustar eugeneeugenetestng-6.9.12/src/test/resources/methodinterceptors/multipleinterceptors/0000755000175000017500000000000012732165123026420 5ustar eugeneeugenetestng-6.9.12/src/test/resources/methodinterceptors/multipleinterceptors/multiple-interceptors.xml0000644000175000017500000000113712732165123033516 0ustar eugeneeugene testng-6.9.12/src/test/resources/suite1-1.xml0000644000175000017500000000031512732165123020272 0ustar eugeneeugene testng-6.9.12/src/test/resources/param-inheritance/0000755000175000017500000000000012732165123021570 5ustar eugeneeugenetestng-6.9.12/src/test/resources/param-inheritance/child-suite.xml0000644000175000017500000000022112732165123024517 0ustar eugeneeugene testng-6.9.12/src/test/resources/param-inheritance/parent-suite.xml0000644000175000017500000000022712732165123024733 0ustar eugeneeugene testng-6.9.12/src/test/resources/suite-parallel-0.xml0000644000175000017500000000042412732165123022003 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-single.yaml0000644000175000017500000000044312732165123021651 0ustar eugeneeugenename: SingleSuite verbose: 2 tests: - name: Test1 excludedGroups: [ excludeThisGroup ] classes: - name: test.dependent.xml.GroupDependencyTest # includedMethods: [ a ] # - test.Test2 # - name: test.CommandLineTest # includedMethods: [ junitParsing ] testng-6.9.12/src/test/resources/testng.yaml0000644000175000017500000002475412732165123020405 0ustar eugeneeugenename: TestNG threadCount: 2 parameters: { short: 47, parameter: out, char: c, byte: 43, first-name: Cedric, int: 42, string: Cedric, factory-param: FactoryParam, boolean: true, long: 46, double: 44.0, float: 45.0 } tests: - name: Nopackage includedGroups: [ nopackage ] classes: - NoPackageTest - name: Regression1 excludedGroups: [ excludeThisGroup ] metaGroups: { evenodd: [ even, odd ] } classes: - test.parameters.ParameterSample - test.parameters.ParameterTest - test.Test1 - test.Test2 - test.CtorCalledOnce - test.expectedexceptions.ExpectedExceptionsTest - test.access.PrivateAccessConfigurationMethods - test.expectedexceptions.WrappedExpectedException - test.parameters.OptionalParameterTest - name: Regression2 excludedGroups: [ broken ] classes: - test.Test1 - test.MethodTest - test.sample.AfterClassCalledAtEnd - test.GraphTest - test.DynamicGraphTest - test.configuration.BaseGroupsTest - test.configuration.BeforeClassThreadTest - test.configuration.BeforeTestOrderingTest - test.configuration.ConfigurationTest - test.configuration.ExternalConfigurationClass - test.configuration.GroupsTest - test.configuration.MethodCallOrderTest - test.configuration.MultipleBeforeGroupTest - test.configuration.ReflectMethodParametrizedConfigurationMethodTest - test.configuration.SuiteFactoryOnceTest - test.configuration.SuiteTest - test.configuration.VerifySuiteTest - test.privatemethod.PrivateMethodTest$PrivateMethodInnerTest - test.multiple.TestMultiple - test.ClassConfigurations - test.alwaysrun.AlwaysRunTest - test.conffailure.ConfigurationFailure - test.superclass.MainTest - test.superclass.Test3 - test.failures.FailuresTest - test.mannotation.MAnnotationSampleTest - test.mannotation.MAnnotation2SampleTest - test.thread.ThreadPoolSizeTest - test.thread.SequentialTest - test.thread.ParallelTestTest - test.thread.FactoryTest - test.thread.DataProviderThreadPoolSizeTest - test.thread.MultiThreadedDependentTest - test.simple.IncludedExcludedTest - test.reports.ReportTest - test.annotationtransformer.AnnotationTransformerTest - test.jar.JarTest - test.xml.XmlVerifyTest - test.invokedmethodlistener.InvokedMethodListenerTest - test.testng249.VerifyTest - test.testng195.AfterMethodTest - test.regression.BeforeTestFailingTest - test.testng285.TestNG285Test - test.failedreporter.FailedReporterTest - test.attributes.AttributeTest - test.verify.VerifyTest - test.abstractconfmethod.C - test.issue78.NonPublicClassTest - test.listeners.ListenerTest - test.preserveorder.PreserveOrderTest - test.listeners.ResultEndMillisTest - name: Injection classes: - test.inject.InjectTestContextTest - test.inject.InjectBeforeMethodTest - test.inject.InjectTestResultTest - test.inject.InjectDataProviderTest - test.inject.NoInjectionTest - name: BeforeMethod classes: - test.configuration.BeforeMethodTest - name: Factory tests classes: - test.factory.classconf.XClassOrderWithFactoryTest - test.factory.FactoryInterleavingTest - name: Basic classes: - test.sample.Basic2 - test.sample.Basic1 - test.Misc - name: Exclusion excludedGroups: [ excludeThisGroup ] classes: - test.Test2 - name: Dependents parameters: { foo: Cedric } classes: - test.dependent.MissingGroupTest - test.dependent.MissingMethodTest - test.dependent.OrderMethodTest - test.dependent.DependentTest - test.dependent.SampleDependentMethods - test.dependent.SampleDependentMethods2 - test.dependent.SampleDependentMethods3 - test.dependent.SampleDependentConfigurationMethods - test.dependent.ClassDependsOnGroups - test.dependent.DependentAlwaysRunTest - test.dependent.MultiGroupTest - test.dependent.ImplicitGroupInclusionTest - test.dependent.ClassWide1Test - test.dependent.ClassWide2Test - test.dependent.DepBugSampleTest - test.dependent.DepBugVerifyTest - test.dependent.DependsOnProtectedMethodTest - test.dependsongroup.DependsOnGroupsTest - name: Inheritance classes: - test.SampleInheritance - test.inheritance.ClassScopeTest - name: Test outer scope includedGroups: [ outer-group ] classes: - test.sample.Scope - name: Test inner scope parameters: { parameter: in } includedGroups: [ inner-group ] classes: - test.sample.Scope - name: AfterClassCalledAtEnd classes: - test.sample.AfterClassCalledAtEnd - name: Triangle classes: - test.triangle.Child1 - test.triangle.Child2 - name: CheckTrianglePost parameters: { expected-calls: 2 } classes: - test.triangle.CheckCount - name: Test class groups 1 classes: - test.classgroup.Second - test.classgroup.First - name: Test class groups 2 classes: - test.classgroup.First - test.classgroup.Second - name: Factory classes: - test.factory.FactoryTest - test.factory.VerifyFactoryTest - test.factory.FactoryInSeparateClass - test.factory.Factory2Test - test.factory.FactoryWithInstanceInfoTest - test.factory.VerifyFactoryWithInstanceInfoTest - test.factory.TestClassAnnotationTest - test.factory.FactoryWithDataProviderTest - test.factory.FactoryOrderMainTest - test.factory.FactoryFailureTest - test.factory.FactoryInSuperClassTest - name: TimeOut classes: - test.timeout.TimeOutTest - test.timeout.TimeOutFromXmlTest - name: InvocationCount parameters: { count: 10 } classes: - test.InvocationAndSuccessPercentageTest - test.invocationcount.FailedInvocationCountTest - test.invocationcount.FirstAndLastTimeTest - name: Method1 classes: - name: test.methods.SampleMethod1 includedMethods: - shouldRun1 - shouldRun2 - test.methods.VerifyMethod1 - name: Method2 classes: - name: test.methods.SampleMethod1 excludedMethods: - shouldNotRun1 - shouldNotRun2 - test.methods.VerifyMethod1 - name: Method3 classes: - name: test.methods.SampleMethod1 excludedMethods: - .*Not.* - test.methods.VerifyMethod1 - name: Object factory classes: - test.objectfactory.CustomFactoryTest - test.objectfactory.CombinedTestAndObjectFactoryTest - name: Parameters for constructors classes: - test.ParameterConstructorTest - name: Excluded methods includedGroups: [ group1, group2 ] classes: - name: test.Exclude excludedMethods: - excluded1 - excluded2 - name: Parameters in init 1 parameters: { param: value1 } classes: - test.configuration.ConfigurationWithParameters - name: Parameters in init 2 parameters: { param: value2 } classes: - test.configuration.ConfigurationWithParameters - name: Individual method classes: - name: test.IndividualMethodsTest includedMethods: - testMethod - name: Method inheritance classes: - test.inheritance.DChild_2 - test.inheritance.VerifyTest - name: Method selectors classes: - test.methodselectors.MethodSelectorTest - test.methodselectors.BeanShellTest - test.methodselectors.CommandLineTest - name: Test order invocation classes: - test.interleavedorder.InterleavedInvocationTest - name: DataProvider classes: - test.dataprovider.Sample1Test - test.dataprovider.IterableTest - test.dataprovider.ConfigurationAndDataProvidersTest - test.dataprovider.BooleanTest - test.dataprovider.MethodTest - test.dataprovider.StaticDataProviderSampleTest - test.dataprovider.UnnamedDataProviderTest - test.dataprovider.TestContextTest - test.dataprovider.FailingDataProviderTest - test.dataprovider.DataProviderAsTest - test.dataprovider.TestInstanceFactory - test.dataprovider.FailedDataProviderTest - test.dataprovider.InstanceDataProviderTest - test.dataprovider.FailingIterableDataProviderTest - test.dataprovider.ClassTest - test.dataprovider.InheritedDataProviderTest - name: DP classes: - test.dataprovider.ParallelDataProviderTest - name: UniqueSuite classes: - test.uniquesuite.TestBefore1 - test.uniquesuite.TestBefore2 - test.uniquesuite.TestAfter - name: InheritGroups includedGroups: [ group1 ] classes: - test.configuration.ConfigurationInheritGroupsSampleTest - name: Nested includedGroups: [ unittest ] xmlPackages: - name: test.nested.* - name: Hookable classes: - test.hook.HookSuccessTest - test.hook.HookFailureTest - name: BeforeGroups-AfterGroups-1 classes: - test.configuration.ConfigurationGroups1SampleTest - test.configuration.ConfigurationGroups2SampleTest - test.configuration.ConfigurationGroups3SampleTest - test.configuration.ConfigurationGroups4SampleTest - test.configuration.ConfigurationGroups5SampleTest - test.configuration.ConfigurationGroups6SampleTest - test.configuration.ConfigurationGroups7SampleTest - name: BeforeGroups-AfterGroups-2 includedGroups: [ A, B ] classes: - test.configuration.ConfigurationGroups8SampleTest - name: JUnit classes: - test.JUnitTest1 - test.CommandLineTest - name: Ant-ClassFileResolution classes: - test.ant.TestCommandLineArgs - name: Class Run classes: - test.regression.groupsordering.A - test.regression.groupsordering.B - name: Groups Run includedGroups: [ a ] classes: - test.regression.groupsordering.A - test.regression.groupsordering.B - name: External group invocation includedGroups: [ a ] classes: - test.groupinvocation.GroupConfiguration - test.groupinvocation.DummyTest - name: SkipExceptions classes: - test.skipex.SkippedExceptionTest - name: MethodInterceptor classes: - test.methodinterceptors.MethodInterceptorTest - name: Asserts classes: - test.asserttests.AssertTest - name: ConfigFailurePolicy classes: - test.configurationfailurepolicy.FailurePolicyTest testng-6.9.12/src/test/resources/suite1.xml0000644000175000017500000000053512732165123020140 0ustar eugeneeugene testng-6.9.12/src/test/resources/META-INF/0000755000175000017500000000000012732165123017341 5ustar eugeneeugenetestng-6.9.12/src/test/resources/META-INF/services/0000755000175000017500000000000012732165123021164 5ustar eugeneeugenetestng-6.9.12/src/test/resources/META-INF/services/org.testng.ITestNGListener0000644000175000017500000000005212732165123026160 0ustar eugeneeugenetest.serviceloader.MyConfigurationListenertestng-6.9.12/src/test/resources/testng-single2.yaml0000644000175000017500000000204712732165123021735 0ustar eugeneeugenename: SingleSuite verbose: 2 parallel: false threadCount: 4 dataProviderThreadCount: 3 packages: - name: test.testng355.org.apache.tapestry5 include: [Foo, Foo2] exclude: [Bar] - name: test.testng355.org.apache.tapestry5.dom listeners: - test.invokedmethodlistener.MyListener parameters: { n: 42, p: 10, s: "a b c", t: "a,b" } methodSelectors: - className: org.testng.internal.XmlMethodSelector priority: 1 - expression: groups.containsKey("test1") language: beanshell tests: - name: Test3 includedGroups: [A, B] excludedGroups: [C, D] metaGroups: { a: [ b, d] } packages: [ com.example1, com.example2 ] parameters: { n: 43, z: foo } methodSelectors: - className: org.testng.internal.XmlMethodSelector priority: 1 - expression: groups.containsKey("test1") language: beanshell - name: Test1 classes: - name: test.tmp.A includedMethods: [test1, test2] excludedMethods: [test3] - test.tmp.B - name: Test2 classes: - test.tmp.B testng-6.9.12/src/test/resources/package.xml0000644000175000017500000000111612732165123020315 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-ant.xml0000644000175000017500000000041212732165123021004 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-configfailure.xml0000644000175000017500000000045212732165123023043 0ustar eugeneeugene testng-6.9.12/src/test/resources/listener-in-xml.xml0000644000175000017500000000053112732165123021751 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-methodselectors.xml0000644000175000017500000000034112732165123023427 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/0000755000175000017500000000000012732165123021307 5ustar eugeneeugenetestng-6.9.12/src/test/resources/parallel-suites/suite-parallel-2-2.xml0000644000175000017500000000035412732165123025254 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/suite-parallel-0.xml0000644000175000017500000000050512732165123025111 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/suite-parallel-2-2-1.xml0000644000175000017500000000023112732165123025404 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/suite-parallel-1.xml0000644000175000017500000000022112732165123025105 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/suite-parallel-3.xml0000644000175000017500000000022112732165123025107 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/suite-parallel-2-1.xml0000644000175000017500000000022512732165123025250 0ustar eugeneeugene testng-6.9.12/src/test/resources/parallel-suites/suite-parallel-2.xml0000644000175000017500000000043112732165123025111 0ustar eugeneeugene testng-6.9.12/src/test/resources/parametertest/0000755000175000017500000000000012732165123021061 5ustar eugeneeugenetestng-6.9.12/src/test/resources/parametertest/child2-suite.xml0000644000175000017500000000060112732165123024074 0ustar eugeneeugene testng-6.9.12/src/test/resources/parametertest/child3-suite.xml0000644000175000017500000000046112732165123024101 0ustar eugeneeugene testng-6.9.12/src/test/resources/parametertest/parent-suite.xml0000644000175000017500000000040512732165123024222 0ustar eugeneeugene testng-6.9.12/src/test/resources/parametertest/child1-suite.xml0000644000175000017500000000046112732165123024077 0ustar eugeneeugene testng-6.9.12/src/test/resources/suite-parallel-1.xml0000644000175000017500000000022112732165123021777 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-override.xml0000644000175000017500000000037412732165123022050 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-single2.xml0000644000175000017500000000106512732165123021572 0ustar eugeneeugene testng-6.9.12/src/test/resources/suite1-2.xml0000644000175000017500000000023312732165123020272 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-annconv.xml0000644000175000017500000000052712732165123021673 0ustar eugeneeugene testng-6.9.12/src/test/resources/testng-package.xml0000644000175000017500000000057512732165123021627 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/0000755000175000017500000000000012732165123017143 5ustar eugeneeugenetestng-6.9.12/src/test/resources/yaml/a1.xml0000644000175000017500000000310612732165123020166 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/a2.yaml0000644000175000017500000000215412732165123020333 0ustar eugeneeugenename: SingleSuite verbose: 2 parallel: false threadCount: 4 dataProviderThreadCount: 3 packages: - name: test.testng355.org.apache.tapestry5 include: [Foo, Foo2] exclude: [Bar] - name: test.testng355.org.apache.tapestry5.dom listeners: - test.invokedmethodlistener.MyListener parameters: { n: 42, p: 10, s: "a b c", t: "a,b" } tests: - name: Test3 preserveOrder: false includedGroups: [A, B] excludedGroups: [C, D] metaGroups: { a: [ b, d] } packages: [ com.example1, com.example2 ] parameters: { n: 43, z: foo } methodSelectors: - className: org.testng.internal.XmlMethodSelector priority: 1 - expression: groups.containsKey("test1") language: beanshell - name: Test1 preserveOrder: false classes: - name: test.tmp.A includedMethods: [test1, test2] excludedMethods: [test3] - test.tmp.B - name: Test2 preserveOrder: false classes: - test.tmp.B methodSelectors: - className: org.testng.internal.XmlMethodSelector priority: 1 - expression: groups.containsKey("test1") language: beanshell testng-6.9.12/src/test/resources/yaml/a4-a.yaml0000644000175000017500000000002712732165123020550 0ustar eugeneeugenename: a4-a verbose: 2 testng-6.9.12/src/test/resources/yaml/a3-b.xml0000644000175000017500000000060512732165123020410 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/a3-a.xml0000644000175000017500000000060512732165123020407 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/a4.xml0000644000175000017500000000033412732165123020171 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/a2.xml0000644000175000017500000000456412732165123020200 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/a4-b.yaml0000644000175000017500000000002712732165123020551 0ustar eugeneeugenename: a4-b verbose: 2 testng-6.9.12/src/test/resources/yaml/a1.yaml0000644000175000017500000000102212732165123020323 0ustar eugeneeugenename: SingleSuite verbose: 2 threadCount: 4 parameters: { n: 42 } dataProviderThreadCount: 3 parallel: false listeners: - test.methodinterceptors.FastTestsFirstInterceptor - test.invokedmethodlistener.MyListener packages: - name: test.testng355.org.apache.tapestry5 include: [Foo, Foo2] exclude: [Bar] - name: test.testng355.org.apache.tapestry5.dom tests: - name: Regression2 verbose: 2 parameters: { count: 10 } excludedGroups: [ broken ] classes: - test.listeners.ResultEndMillisTest testng-6.9.12/src/test/resources/yaml/a3-a.yaml0000644000175000017500000000013712732165123020551 0ustar eugeneeugenename: a3-a tests: - name: Test-a3-a classes: - test.listeners.ResultEndMillisTest testng-6.9.12/src/test/resources/yaml/a3.yaml0000644000175000017500000000007012732165123020327 0ustar eugeneeugenename: a3 verbose: 2 suiteFiles: [ a3-a.xml, a3-b.xml ] testng-6.9.12/src/test/resources/yaml/a3.xml0000644000175000017500000000032112732165123020164 0ustar eugeneeugene testng-6.9.12/src/test/resources/yaml/a3-b.yaml0000644000175000017500000000013712732165123020552 0ustar eugeneeugenename: a3-b tests: - name: Test-a3-b classes: - test.listeners.ResultEndMillisTest testng-6.9.12/src/test/resources/yaml/a4.yaml0000644000175000017500000000010312732165123020325 0ustar eugeneeugenename: SingleSuite verbose: 2 suiteFiles: [ a4-a.yaml, a4-b.yaml ] testng-6.9.12/src/test/resources/checksuitesinitialization/0000755000175000017500000000000012732165123023463 5ustar eugeneeugenetestng-6.9.12/src/test/resources/checksuitesinitialization/child-suite2.xml0000644000175000017500000000022312732165123026476 0ustar eugeneeugene testng-6.9.12/src/test/resources/checksuitesinitialization/parent-suite.xml0000644000175000017500000000031512732165123026624 0ustar eugeneeugene testng-6.9.12/src/test/resources/checksuitesinitialization/children/0000755000175000017500000000000012732165123025253 5ustar eugeneeugenetestng-6.9.12/src/test/resources/checksuitesinitialization/children/child-suite-3.xml0000644000175000017500000000037712732165123030356 0ustar eugeneeugene testng-6.9.12/src/test/resources/checksuitesinitialization/children/child-suite-4.xml0000644000175000017500000000022212732165123030344 0ustar eugeneeugene testng-6.9.12/src/test/resources/checksuitesinitialization/children/morechildren/0000755000175000017500000000000012732165123027726 5ustar eugeneeugenetestng-6.9.12/src/test/resources/checksuitesinitialization/children/morechildren/child-suite-5.xml0000644000175000017500000000022212732165123033020 0ustar eugeneeugene testng-6.9.12/src/test/resources/checksuitesinitialization/child-suite1.xml0000644000175000017500000000022312732165123026475 0ustar eugeneeugene testng-6.9.12/src/test/resources/hosts.properties0000644000175000017500000000006112732165123021454 0ustar eugeneeugenetestng.hosts=localhost:5150 testng.strategy=test testng-6.9.12/src/test/resources/suite-parallel-2.xml0000644000175000017500000000022112732165123022000 0ustar eugeneeugene testng-6.9.12/src/test/resources/b.xml0000644000175000017500000000031612732165123017144 0ustar eugeneeugene testng-6.9.12/src/main/0000755000175000017500000000000012732165123014134 5ustar eugeneeugenetestng-6.9.12/src/main/java/0000755000175000017500000000000012732165123015055 5ustar eugeneeugenetestng-6.9.12/src/main/java/testng-1.0.dtd.html0000644000175000017500000002154412732165123020323 0ustar eugeneeugene DTD for TestNG 1.0
<!--

Here is a quick overview of the main parts of this DTD.  For more information,
refer to the <a href="http://testng.org" >main web site</a>.

                                                      
A <b>suite</b> is made of <b>tests</b> and <b>parameters</b>.
                                                      

A <b>test</b> is made of three parts:                        

<ul>
<li> <b>parameters</b>, which override the suite parameters     
<li> <b>groups</b>, made of two parts                           

<li> <b>classes</b>, defining which classes are going to be part
  of this test run                                    
</ul>
                                                      
In turn, <b>groups</b> are made of two parts:                

<ul>
<li> Definitions, which allow you to group groups into   
  bigger groups                                       
<li> Runs, which defines the groups that the methods     
  must belong to in order to be run during this test  
</ul>
                                                      
Cedric Beust & Alexandru Popescu                      
@title DTD for TestNG                                    
@root suite

-->


<!-- A suite is the top-level element of a testng.xml file                  -->

<!ELEMENT suite (listeners|packages|test|parameter|method-selectors|suite-files)* >

<!-- Attributes: -->
<!--
@attr  name        The name of this suite (as it will appear in the reports)
@attr  junit       Whether to run in JUnit mode.
@attr  verbose     How verbose the output on the console will be.  
                This setting has no impact on the HTML reports.
@attr  parallel   Whether TestNG should use different threads
                to run your tests (might speed up the process)
@attr  configfailurepolicy  Whether to continue attempting Before/After
                Class/Methods after they've failed once or just skip remaining.
@attr  thread-count An integer giving the size of the thread pool to use
                if you set parallel.
@attr  annotations  If "javadoc", TestNG will look for
                JavaDoc annotations in your sources, otherwise it will
                use JDK5 annotations.
@attr  time-out     The time to wait in milliseconds before aborting the
                method (if parallel="methods" ) or the test (parallel="tests")
@attr  skipfailedinvocationCounts Whether to skip failed invocations.
@attr  data-provider-thread-count An integer giving the size of the thread pool to use
       for parallel data providers.
@attr  object-factory A class that implements IObjectFactory that will be used to
       instantiate the test objects.
-->
<!ATTLIST suite 
    name CDATA #REQUIRED
    junit (true | false) "false"
    verbose CDATA #IMPLIED
    parallel (false | methods | tests | classes) "false"
    configfailurepolicy (skip | continue) "skip"
    thread-count CDATA "5"
    annotations CDATA #IMPLIED
    time-out CDATA #IMPLIED
    skipfailedinvocationCounts (true | false) "false"
    data-provider-thread-count CDATA "10"
    object-factory CDATA #IMPLIED
>

<!-- A list of XML files that contain more suite descriptions -->
<!ELEMENT suite-files (suite-file)* >

<!ELEMENT suite-file ANY >
<!ATTLIST suite-file
    path CDATA #REQUIRED
>

<!--
Parameters can be defined at the <suite> or at the <test> level.
Parameters defined at the <test> level override parameters of the same name in <suite>

Parameters are used to link Java method parameters to their actual value, defined here.
-->
<!ELEMENT parameter ANY>
<!ATTLIST parameter
    name CDATA #REQUIRED
    value CDATA #REQUIRED >

<!--
Method selectors define user classes used to select which methods to run.
They need to implement <tt>org.testng.IMethodSelector</tt> 
-->
<!ELEMENT method-selectors (method-selector*) >

<!ELEMENT method-selector ((selector-class)*|script) >
<!ELEMENT selector-class ANY>
<!ATTLIST selector-class
    name CDATA #REQUIRED
  priority CDATA #IMPLIED
>
<!ELEMENT script ANY>
<!ATTLIST script
    language CDATA #REQUIRED
>

<!--
A test contains parameters and classes.  Additionally, you can define additional groups ("groups of groups")
-->

<!ELEMENT test (method-selectors?,parameter*,groups?,packages?,classes?) >

<!--
@attr  name         The name of this test (as it will appear in the reports)
@attr  junit        Whether to run in JUnit mode.
@attr  verbose      How verbose the output on the console will be.
                This setting has no impact on the HTML reports.
                Default value: suite level verbose.
@attr  parallel     Whether TestNG should use different threads
                to run your tests (might speed up the process)
@attr  thread-count An integer giving the size of the thread pool to be used if
                parallel mode is used. Overrides the suite level value.
@attr  annotations  If "javadoc", TestNG will look for
                JavaDoc annotations in your sources, otherwise it will
                use JDK5 annotations.
@attr  time-out     the time to wait in milliseconds before aborting
                the method (if parallel="methods" ) or the test (if parallel="tests" )
@attr  enabled      flag to enable/disable current test. Default value: true 
@attr  skipfailedinvocationCounts Whether to skip failed invocations.
-->
<!ATTLIST test
    name CDATA #REQUIRED 
    junit (true | false) "false"
    verbose  CDATA #IMPLIED
    parallel  CDATA #IMPLIED
    thread-count CDATA #IMPLIED
    annotations  CDATA #IMPLIED
    time-out CDATA #IMPLIED
    enabled CDATA #IMPLIED
    skipfailedinvocationCounts (true | false) "false"
>

<!--
Defines additional groups ("groups of groups") and also which groups to include in this test run
-->
<!ELEMENT groups (define*,run?) >

<!ELEMENT define (include*)>

<!ATTLIST define
    name CDATA #REQUIRED>

<!-- Defines which groups to include in the current group of groups         -->
<!ELEMENT include ANY>
<!ATTLIST include
    name CDATA #REQUIRED>

<!-- Defines which groups to exclude from the current group of groups       -->
<!ELEMENT exclude ANY>
<!ATTLIST exclude
    name CDATA #REQUIRED>

<!-- The subtag of groups used to define which groups should be run         -->
<!ELEMENT run (include?,exclude?)* >

<!-- The list of classes to include in this test                            -->
<!ELEMENT classes (class*) >
<!ELEMENT class (methods*) >
<!ATTLIST class
    name CDATA #REQUIRED >

<!-- The list of packages to include in this test                           -->
<!ELEMENT packages (package*) >

<!-- The package description. 
     If the package name ends with .* then subpackages are included too.
-->
<!ELEMENT package (include?,exclude?)*>
<!ATTLIST package
    name CDATA #REQUIRED >

<!-- The list of methods to include/exclude from this test                 -->
<!ELEMENT methods (include?,exclude?)* >

<!-- The list of listeners that will be passed to TestNG -->
<!ELEMENT listeners (listener*) >

<!ELEMENT listener ANY>
<!ATTLIST listener
    class-name CDATA #REQUIRED >
testng-6.9.12/src/main/java/com/0000755000175000017500000000000012732165123015633 5ustar eugeneeugenetestng-6.9.12/src/main/java/com/beust/0000755000175000017500000000000012732165123016755 5ustar eugeneeugenetestng-6.9.12/src/main/java/com/beust/testng/0000755000175000017500000000000012732165123020261 5ustar eugeneeugenetestng-6.9.12/src/main/java/com/beust/testng/TestNGAntTask.java0000755000175000017500000000042612732165123023563 0ustar eugeneeugenepackage com.beust.testng; /** * For backward compatibility. * * Created on Jun 18, 2005 * @author Cedric Beust * @deprecated Use org.testng.TestNGAntTask */ @Deprecated public class TestNGAntTask extends org.testng.TestNGAntTask { } testng-6.9.12/src/main/java/com/beust/testng/TestNG.java0000755000175000017500000000040112732165123022266 0ustar eugeneeugenepackage com.beust.testng; /** * For backward compatibility. * * Created on Jun 18, 2005 * @author Cedric Beust * @deprecated Use org.testng.TestNG */ @Deprecated public class TestNG extends org.testng.TestNG { }testng-6.9.12/src/main/java/org/0000755000175000017500000000000012732165123015644 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/0000755000175000017500000000000012732165123017150 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/xml/0000755000175000017500000000000012732165123017750 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/xml/XmlGroups.java0000644000175000017500000000331512732165123022555 0ustar eugeneeugenepackage org.testng.xml; import java.util.List; import org.testng.collections.Lists; import org.testng.reporters.XMLStringBuffer; import org.testng.xml.dom.Tag; import static org.testng.collections.CollectionUtils.hasElements; public class XmlGroups { private List m_defines = Lists.newArrayList(); private XmlRun m_run; private List m_dependencies = Lists.newArrayList(); public List getDefines() { return m_defines; } @Tag(name = "define") public void addDefine(XmlDefine define) { getDefines().add(define); } public void setDefines(List defines) { m_defines = defines; } public XmlRun getRun() { return m_run; } public void setRun(XmlRun run) { m_run = run; } public List getDependencies() { return m_dependencies; } // public void setDependencies(List dependencies) { // m_dependencies = dependencies; // } @Tag(name = "dependencies") public void setXmlDependencies(XmlDependencies dependencies) { m_dependencies.add(dependencies); } public String toXml(String indent) { XMLStringBuffer xsb = new XMLStringBuffer(indent); String indent2 = indent + " "; boolean hasGroups = hasElements(m_defines) || m_run != null || hasElements(m_dependencies); if (hasGroups) { xsb.push("groups"); } for (XmlDefine d : m_defines) { xsb.getStringBuffer().append(d.toXml(indent2)); } xsb.getStringBuffer().append(m_run.toXml(indent2)); for (XmlDependencies d : m_dependencies) { xsb.getStringBuffer().append(d.toXml(indent2)); } if (hasGroups) { xsb.pop("groups"); } return xsb.toXML(); } } testng-6.9.12/src/main/java/org/testng/xml/XmlRun.java0000644000175000017500000000232312732165123022040 0ustar eugeneeugenepackage org.testng.xml; import static org.testng.collections.CollectionUtils.hasElements; import org.testng.collections.Lists; import org.testng.reporters.XMLStringBuffer; import org.testng.xml.dom.OnElement; import java.util.List; public class XmlRun { public String toXml(String indent) { XMLStringBuffer xsb = new XMLStringBuffer(indent); boolean hasElements = hasElements(m_excludes) || hasElements(m_includes); if (hasElements) { xsb.push("run"); } for (String s : m_includes) { xsb.addEmptyElement("include", "name", s); } for (String s : m_excludes) { xsb.addEmptyElement("exclude", "name", s); } if (hasElements) { xsb.pop("run"); } return xsb.toXML(); } private List m_excludes = Lists.newArrayList(); public List getExcludes() { return m_excludes; } @OnElement(tag = "exclude", attributes = "name") public void onExclude(String name) { m_excludes.add(name); } private List m_includes = Lists.newArrayList(); public List getIncludes() { return m_includes; } @OnElement(tag = "include", attributes = "name") public void onInclude(String name) { m_includes.add(name); } } testng-6.9.12/src/main/java/org/testng/xml/XmlTest.java0000755000175000017500000006150012732165123022220 0ustar eugeneeugenepackage org.testng.xml; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.UUID; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.Utils; import org.testng.reporters.XMLStringBuffer; import org.testng.xml.dom.ParentSetter; import static org.testng.xml.XmlSuite.ParallelMode.skipDeprecatedValues; /** * This class describes the tag <test> in testng.xml. * * @author Cedric Beust * @author Alexandru Popescu */ public class XmlTest implements Serializable, Cloneable { private static final long serialVersionUID = 6533504325942417606L; public static final int DEFAULT_TIMEOUT_MS = Integer.MAX_VALUE; private XmlSuite m_suite; private String m_name; private Integer m_verbose = XmlSuite.DEFAULT_VERBOSE; private Boolean m_isJUnit = XmlSuite.DEFAULT_JUNIT; private int m_threadCount= -1; private List m_xmlClasses = Lists.newArrayList(); private List m_includedGroups = Lists.newArrayList(); private List m_excludedGroups = Lists.newArrayList(); private Map> m_metaGroups = Maps.newHashMap(); private Map m_parameters = Maps.newHashMap(); private XmlSuite.ParallelMode m_parallel; private List m_methodSelectors = Lists.newArrayList(); // test level packages private List m_xmlPackages = Lists.newArrayList(); private String m_timeOut; private Boolean m_skipFailedInvocationCounts = XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS; private Map> m_failedInvocationNumbers = null; // lazily initialized private String m_preserveOrder = XmlSuite.DEFAULT_PRESERVE_ORDER; private int m_index; private Boolean m_groupByInstances; private Boolean m_allowReturnValues = null; private Map m_xmlDependencyGroups = Maps.newHashMap(); /** * Constructs a XmlTest and adds it to suite's list of tests. * * @param suite the parent suite. * @param index the index of this test tag in testng.xml */ public XmlTest(XmlSuite suite, int index) { init(suite, index); } public XmlTest(XmlSuite suite) { init(suite, 0); } private void init(XmlSuite suite, int index) { m_suite = suite; m_suite.getTests().add(this); m_index = index; //no two tests in the same suite should have the same name. //so, make the default test name unique m_name = TestNG.DEFAULT_COMMAND_LINE_TEST_NAME + " " + UUID.randomUUID().toString(); } // For YAML public XmlTest() { } public void setXmlPackages(List packages) { m_xmlPackages = Lists.newArrayList(packages); } public List getXmlPackages() { return m_xmlPackages; } // For YAML public List getPackages() { return getXmlPackages(); } // For YAML public void setPackages(List p) { setXmlPackages(p); } public List getMethodSelectors() { return m_methodSelectors; } public void setMethodSelectors(List methodSelectors) { m_methodSelectors = Lists.newArrayList(methodSelectors); } /** * Returns the suite this test is part of. * @return the suite this test is part of. */ public XmlSuite getSuite() { return m_suite; } /** * @return the includedGroups. * Note: do not modify the returned value, use {@link #addIncludedGroup(String)}. */ public List getIncludedGroups() { List result; if (m_xmlGroups != null) { result = m_xmlGroups.getRun().getIncludes(); result.addAll(m_suite.getIncludedGroups()); } else { // deprecated result = Lists.newArrayList(m_includedGroups); result.addAll(m_suite.getIncludedGroups()); } return result; } /** * Sets the XML Classes. * @param classes The classes to set. * @deprecated use setXmlClasses */ @Deprecated public void setClassNames(List classes) { m_xmlClasses = classes; } /** * @return Returns the classes. */ public List getXmlClasses() { return m_xmlClasses; } // For YAML public List getClasses() { return getXmlClasses(); } // For YAML public void setClasses(List c) { setXmlClasses(c); } /** * Sets the XML Classes. * @param classes The classes to set. */ public void setXmlClasses(List classes) { m_xmlClasses = classes; } /** * @return Returns the name. */ public String getName() { return m_name; } /** * @param name The name to set. */ public void setName(String name) { m_name = name; } /** * @param v */ public void setVerbose(int v) { m_verbose = v; } public int getThreadCount() { return m_threadCount > 0 ? m_threadCount : getSuite().getThreadCount(); } public void setThreadCount(int threadCount) { m_threadCount = threadCount; } /** * @param g */ public void setIncludedGroups(List g) { m_includedGroups = g; } /** * @param g The excludedGrousps to set. */ public void setExcludedGroups(List g) { m_excludedGroups = g; } /** * @return Returns the excludedGroups. * Note: do not modify the returned value, use {@link #addExcludedGroup(String)}. */ public List getExcludedGroups() { List result = new ArrayList(m_excludedGroups); result.addAll(m_suite.getExcludedGroups()); return result; } public void addIncludedGroup(String g) { m_includedGroups.add(g); } public void addExcludedGroup(String g) { m_excludedGroups.add(g); } /** * @return Returns the verbose. */ public int getVerbose() { Integer result = m_verbose; if (null == result || XmlSuite.DEFAULT_VERBOSE.equals(m_verbose)) { result = m_suite.getVerbose(); } if (null != result) { return result; } else { return 1; } } public boolean getGroupByInstances() { Boolean result = m_groupByInstances; if (result == null || XmlSuite.DEFAULT_GROUP_BY_INSTANCES.equals(m_groupByInstances)) { result = m_suite.getGroupByInstances(); } if (result != null) { return result; } else { return XmlSuite.DEFAULT_GROUP_BY_INSTANCES; } } public void setGroupByInstances(boolean f) { m_groupByInstances = f; } /** * @return Returns the isJUnit. */ public boolean isJUnit() { Boolean result = m_isJUnit; if (null == result || XmlSuite.DEFAULT_JUNIT.equals(result)) { result = m_suite.isJUnit(); } return result; } /** * @param isJUnit The isJUnit to set. */ public void setJUnit(boolean isJUnit) { m_isJUnit = isJUnit; } // For YAML public void setJunit(boolean isJUnit) { setJUnit(isJUnit); } public void setSkipFailedInvocationCounts(boolean skip) { m_skipFailedInvocationCounts = skip; } /** * @return Returns the isJUnit. */ public boolean skipFailedInvocationCounts() { Boolean result = m_skipFailedInvocationCounts; if (null == result) { result = m_suite.skipFailedInvocationCounts(); } return result; } public void addMetaGroup(String name, List metaGroup) { m_metaGroups.put(name, metaGroup); } // For YAML public void setMetaGroups(Map> metaGroups) { m_metaGroups = metaGroups; } /** * @return Returns the metaGroups. */ public Map> getMetaGroups() { if (m_xmlGroups != null) { Map> result = Maps.newHashMap(); List defines = m_xmlGroups.getDefines(); for (XmlDefine xd : defines) { result.put(xd.getName(), xd.getIncludes()); } return result; } else { // deprecated return m_metaGroups; } } /** * @param parameters */ public void setParameters(Map parameters) { m_parameters = parameters; } public void addParameter(String key, String value) { m_parameters.put(key, value); } public String getParameter(String name) { String result = m_parameters.get(name); if (null == result) { result = m_suite.getParameter(name); } return result; } /** * @return the parameters defined in this test tag and the tags above it. */ public Map getAllParameters() { Map result = Maps.newHashMap(); result.putAll(getSuite().getParameters()); result.putAll(m_parameters); return result; } /** * @return the parameters defined in this tag, and only this test tag. To retrieve * the inherited parameters as well, call {@code getAllParameters()}. */ public Map getLocalParameters() { return m_parameters; } /** * @deprecated Use {@code getLocalParameters()} or {@code getAllParameters()} */ @Deprecated public Map getParameters() { return getAllParameters(); } /** * @deprecated Use {@code getLocalParameters()} instead * * @return the parameters defined on this tag only */ @Deprecated public Map getTestParameters() { return getLocalParameters(); } public void setParallel(XmlSuite.ParallelMode parallel) { m_parallel = skipDeprecatedValues(parallel); } public XmlSuite.ParallelMode getParallel() { XmlSuite.ParallelMode result; if (null != m_parallel || XmlSuite.DEFAULT_PARALLEL.equals(m_parallel)) { result = m_parallel; } else { result = m_suite.getParallel(); } return result; } public String getTimeOut() { String result = null; if (null != m_timeOut) { result = m_timeOut; } else { result = m_suite.getTimeOut(); } return result; } public long getTimeOut(long def) { long result = def; if (getTimeOut() != null) { result = Long.parseLong(getTimeOut()); } return result; } public void setTimeOut(long timeOut) { m_timeOut = Long.toString(timeOut); } private void setTimeOut(String timeOut) { m_timeOut = timeOut; } public void setExpression(String expression) { setBeanShellExpression(expression); } public void setBeanShellExpression(String expression) { List selectors = getMethodSelectors(); if (selectors.size() > 0) { selectors.get(0).setExpression(expression); } else if (expression != null) { XmlMethodSelector xms = new XmlMethodSelector(); xms.setExpression(expression); xms.setLanguage("BeanShell"); getMethodSelectors().add(xms); } } public String getExpression() { List selectors = getMethodSelectors(); if (selectors.size() > 0) { return selectors.get(0).getExpression(); } else { return null; } } public String toXml(String indent) { XMLStringBuffer xsb = new XMLStringBuffer(indent); Properties p = new Properties(); p.setProperty("name", getName()); if (m_isJUnit != null) { XmlUtils.setProperty(p, "junit", m_isJUnit.toString(), XmlSuite.DEFAULT_JUNIT.toString()); } if (m_parallel != null) { XmlUtils.setProperty(p, "parallel", m_parallel.toString(), XmlSuite.DEFAULT_PARALLEL.toString()); } if (m_verbose != null) { XmlUtils.setProperty(p, "verbose", m_verbose.toString(), XmlSuite.DEFAULT_VERBOSE.toString()); } if (null != m_timeOut) { p.setProperty("time-out", m_timeOut.toString()); } if (m_preserveOrder != null && ! XmlSuite.DEFAULT_PRESERVE_ORDER.equals(m_preserveOrder)) { p.setProperty("preserve-order", m_preserveOrder.toString()); } if (m_threadCount != -1) { p.setProperty("thread-count", Integer.toString(m_threadCount)); } if (m_groupByInstances != null) { XmlUtils.setProperty(p, "group-by-instances", String.valueOf(getGroupByInstances()), XmlSuite.DEFAULT_GROUP_BY_INSTANCES.toString()); } xsb.push("test", p); if (null != getMethodSelectors() && !getMethodSelectors().isEmpty()) { xsb.push("method-selectors"); for (XmlMethodSelector selector: getMethodSelectors()) { xsb.getStringBuffer().append(selector.toXml(indent + " ")); } xsb.pop("method-selectors"); } XmlUtils.dumpParameters(xsb, m_parameters); // groups if (!m_metaGroups.isEmpty() || !m_includedGroups.isEmpty() || !m_excludedGroups.isEmpty() || !m_xmlDependencyGroups.isEmpty()) { xsb.push("groups"); // define for (Map.Entry> entry: m_metaGroups.entrySet()) { String metaGroupName = entry.getKey(); List groupNames = entry.getValue(); Properties metaGroupProp= new Properties(); metaGroupProp.setProperty("name", metaGroupName); xsb.push("define", metaGroupProp); for (String groupName: groupNames) { Properties includeProps = new Properties(); includeProps.setProperty("name", groupName); xsb.addEmptyElement("include", includeProps); } xsb.pop("define"); } // run if (!m_includedGroups.isEmpty() || !m_excludedGroups.isEmpty()) { xsb.push("run"); for (String includeGroupName: m_includedGroups) { Properties includeProps = new Properties(); includeProps.setProperty("name", includeGroupName); xsb.addEmptyElement("include", includeProps); } for (String excludeGroupName: m_excludedGroups) { Properties excludeProps = new Properties(); excludeProps.setProperty("name", excludeGroupName); xsb.addEmptyElement("exclude", excludeProps); } xsb.pop("run"); } // group dependencies if (m_xmlDependencyGroups != null && ! m_xmlDependencyGroups.isEmpty()) { xsb.push("dependencies"); for (Map.Entry entry : m_xmlDependencyGroups.entrySet()) { xsb.addEmptyElement("group", "name", entry.getKey(), "depends-on", entry.getValue()); } xsb.pop("dependencies"); } xsb.pop("groups"); } if (null != m_xmlPackages && !m_xmlPackages.isEmpty()) { xsb.push("packages"); for (XmlPackage pack: m_xmlPackages) { xsb.getStringBuffer().append(pack.toXml(" ")); } xsb.pop("packages"); } // classes if (null != getXmlClasses() && !getXmlClasses().isEmpty()) { xsb.push("classes"); for (XmlClass cls : getXmlClasses()) { xsb.getStringBuffer().append(cls.toXml(indent + " ")); } xsb.pop("classes"); } xsb.pop("test"); return xsb.toXML(); } @Override public String toString() { // return toXml(""); StringBuilder result = new StringBuilder("[Test: \"") .append(m_name) .append("\"") .append(" verbose:") .append(m_verbose); result.append("[parameters:"); for (Map.Entry entry : m_parameters.entrySet()) { result.append(entry.getKey()).append("=>").append(entry.getValue()); } result.append("]"); result.append("[metagroups:"); for (Map.Entry> entry : m_metaGroups.entrySet()) { result.append(entry.getKey()).append("="); for (String n : entry.getValue()) { result.append(n).append(","); } } result.append("] "); result.append("[included: "); for (String g : m_includedGroups) { result.append(g).append(" "); } result.append("]"); result.append("[excluded: "); for (String g : m_excludedGroups) { result.append(g).append(" "); } result.append("] "); result.append(" classes:"); for (XmlClass cl : m_xmlClasses) { result.append(cl).append(" "); } result.append(" packages:"); for (XmlPackage p : m_xmlPackages) { result.append(p).append(" "); } result.append("] "); return result.toString(); } static void ppp(String s) { System.out.println("[XmlTest] " + s); } /** * Clone the source XmlTest by including: * - test attributes * - groups definitions * - parameters * * The <classes> sub element is ignored for the moment. * * @return a clone of the current XmlTest */ @Override public Object clone() { XmlTest result = new XmlTest(getSuite()); result.setName(getName()); result.setIncludedGroups(getIncludedGroups()); result.setExcludedGroups(getExcludedGroups()); result.setJUnit(isJUnit()); result.setParallel(getParallel()); result.setVerbose(getVerbose()); result.setParameters(getLocalParameters()); result.setXmlPackages(getXmlPackages()); result.setTimeOut(getTimeOut()); Map> metagroups = getMetaGroups(); for (Map.Entry> group: metagroups.entrySet()) { result.addMetaGroup(group.getKey(), group.getValue()); } return result; } /** * Convenience method to cache the ordering numbers for methods. */ public List getInvocationNumbers(String method) { if (m_failedInvocationNumbers == null) { m_failedInvocationNumbers = Maps.newHashMap(); for (XmlClass c : getXmlClasses()) { for (XmlInclude xi : c.getIncludedMethods()) { List invocationNumbers = xi.getInvocationNumbers(); if (invocationNumbers.size() > 0) { String methodName = c.getName() + "." + xi.getName(); m_failedInvocationNumbers.put(methodName, invocationNumbers); } } } } List result = m_failedInvocationNumbers.get(method); if (result == null) { // Don't use emptyList here since this list might end up receiving values if // the test run fails. return Lists.newArrayList(); } else { return result; } } public void setPreserveOrder(String preserveOrder) { m_preserveOrder = preserveOrder; } public String getPreserveOrder() { String result = m_preserveOrder; if (result == null || XmlSuite.DEFAULT_PRESERVE_ORDER.equals(m_preserveOrder)) { result = m_suite.getPreserveOrder(); } return result; } public void setSuite(XmlSuite result) { m_suite = result; } public Boolean getAllowReturnValues() { if (m_allowReturnValues != null) return m_allowReturnValues; else return getSuite().getAllowReturnValues(); } public void setAllowReturnValues(Boolean allowReturnValues) { m_allowReturnValues = allowReturnValues; } /** * Note that this attribute does not come from the XML file, it's calculated * internally and represents the order in which this test tag was found in its * <suite> tag. It's used to calculate the ordering of the tests * when preserve-test-order is true. */ public int getIndex() { return m_index; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((m_excludedGroups == null) ? 0 : m_excludedGroups.hashCode()); result = prime * result + ((m_failedInvocationNumbers == null) ? 0 : m_failedInvocationNumbers .hashCode()); result = prime * result + ((m_includedGroups == null) ? 0 : m_includedGroups.hashCode()); result = prime * result + ((m_isJUnit == null) ? 0 : m_isJUnit.hashCode()); result = prime * result + ((m_metaGroups == null) ? 0 : m_metaGroups.hashCode()); result = prime * result + ((m_methodSelectors == null) ? 0 : m_methodSelectors.hashCode()); result = prime * result + ((m_name == null) ? 0 : m_name.hashCode()); result = prime * result + ((m_parallel == null) ? 0 : m_parallel.hashCode()); result = prime * result + ((m_parameters == null) ? 0 : m_parameters.hashCode()); result = prime * result + ((m_preserveOrder == null) ? 0 : m_preserveOrder.hashCode()); result = prime * result + ((m_skipFailedInvocationCounts == null) ? 0 : m_skipFailedInvocationCounts.hashCode()); result = prime * result + m_threadCount; result = prime * result + ((m_timeOut == null) ? 0 : m_timeOut.hashCode()); result = prime * result + ((m_verbose == null) ? 0 : m_verbose.hashCode()); result = prime * result + ((m_xmlClasses == null) ? 0 : m_xmlClasses.hashCode()); result = prime * result + ((m_xmlPackages == null) ? 0 : m_xmlPackages.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) return XmlSuite.f(); if (getClass() != obj.getClass()) return XmlSuite.f(); XmlTest other = (XmlTest) obj; if (m_excludedGroups == null) { if (other.m_excludedGroups != null) return XmlSuite.f(); } else if (!m_excludedGroups.equals(other.m_excludedGroups)) return XmlSuite.f(); // if (m_expression == null) { // if (other.m_expression != null) // return XmlSuite.f(); // } else if (!m_expression.equals(other.m_expression)) // return XmlSuite.f(); if (m_failedInvocationNumbers == null) { if (other.m_failedInvocationNumbers != null) return XmlSuite.f(); } else if (!m_failedInvocationNumbers .equals(other.m_failedInvocationNumbers)) return XmlSuite.f(); if (m_includedGroups == null) { if (other.m_includedGroups != null) return XmlSuite.f(); } else if (!m_includedGroups.equals(other.m_includedGroups)) return XmlSuite.f(); if (m_isJUnit == null) { if (other.m_isJUnit != null && ! other.m_isJUnit.equals(XmlSuite.DEFAULT_JUNIT)) return XmlSuite.f(); } else if (!m_isJUnit.equals(other.m_isJUnit)) return XmlSuite.f(); if (m_metaGroups == null) { if (other.m_metaGroups != null) return XmlSuite.f(); } else if (!m_metaGroups.equals(other.m_metaGroups)) return XmlSuite.f(); if (m_methodSelectors == null) { if (other.m_methodSelectors != null) return XmlSuite.f(); } else if (!m_methodSelectors.equals(other.m_methodSelectors)) return XmlSuite.f(); if (m_name == null) { if (other.m_name != null) return XmlSuite.f(); } else if (!m_name.equals(other.m_name)) return XmlSuite.f(); if (m_parallel == null) { if (other.m_parallel != null) return XmlSuite.f(); } else if (!m_parallel.equals(other.m_parallel)) return XmlSuite.f(); if (m_parameters == null) { if (other.m_parameters != null) return XmlSuite.f(); } else if (!m_parameters.equals(other.m_parameters)) return XmlSuite.f(); if (m_preserveOrder == null) { if (other.m_preserveOrder != null) return XmlSuite.f(); } else if (!m_preserveOrder.equals(other.m_preserveOrder)) return XmlSuite.f(); if (m_skipFailedInvocationCounts == null) { if (other.m_skipFailedInvocationCounts != null) return XmlSuite.f(); } else if (!m_skipFailedInvocationCounts .equals(other.m_skipFailedInvocationCounts)) return XmlSuite.f(); if (m_threadCount != other.m_threadCount) return XmlSuite.f(); if (m_timeOut == null) { if (other.m_timeOut != null) return XmlSuite.f(); } else if (!m_timeOut.equals(other.m_timeOut)) return XmlSuite.f(); if (m_verbose == null) { if (other.m_verbose != null) return XmlSuite.f(); } else if (!m_verbose.equals(other.m_verbose)) return XmlSuite.f(); if (m_xmlClasses == null) { if (other.m_xmlClasses != null) return XmlSuite.f(); } else if (!m_xmlClasses.equals(other.m_xmlClasses)) return XmlSuite.f(); if (m_xmlPackages == null) { if (other.m_xmlPackages != null) return XmlSuite.f(); } else if (!m_xmlPackages.equals(other.m_xmlPackages)) return XmlSuite.f(); return true; } public void addXmlDependencyGroup(String group, String dependsOn) { if (! m_xmlDependencyGroups.containsKey(group)) { m_xmlDependencyGroups.put(group, dependsOn); } else { throw new TestNGException("Duplicate group dependency found for group \"" + group + "\"" + ", use a space-separated list of groups in the \"depends-on\" attribute"); } } public Map getXmlDependencyGroups() { if (m_xmlGroups != null) { Map result = Maps.newHashMap(); List deps = m_xmlGroups.getDependencies(); for (XmlDependencies d : deps) { result.putAll(d.getDependencies()); } return result; } else { // deprecated return m_xmlDependencyGroups; } } @ParentSetter public void setXmlSuite(XmlSuite suite) { m_suite = suite; } private XmlGroups m_xmlGroups; public void setGroups(XmlGroups xmlGroups) { m_xmlGroups = xmlGroups; } } testng-6.9.12/src/main/java/org/testng/xml/SuiteXmlParser.java0000644000175000017500000000131512732165123023542 0ustar eugeneeugenepackage org.testng.xml; import org.testng.TestNGException; import org.xml.sax.SAXException; import java.io.IOException; import java.io.InputStream; public class SuiteXmlParser extends XMLParser implements ISuiteParser { @Override public XmlSuite parse(String currentFile, InputStream inputStream, boolean loadClasses) { TestNGContentHandler contentHandler = new TestNGContentHandler(currentFile, loadClasses); try { parse(inputStream, contentHandler); return contentHandler.getSuite(); } catch (SAXException | IOException e) { throw new TestNGException(e); } } @Override public boolean accept(String fileName) { return fileName.endsWith(".xml"); } } testng-6.9.12/src/main/java/org/testng/xml/SuiteGenerator.java0000755000175000017500000000532012732165123023556 0ustar eugeneeugenepackage org.testng.xml; import java.io.File; import java.util.Collection; import java.util.Collections; import java.util.Map; /** * Factory to create custom suites. * @author Hani Suleiman * Date: Jul 25, 2005 * Time: 1:12:18 PM */ public class SuiteGenerator { private static final Collection EMPTY_CLASS_LIST= Collections.emptyList(); public static LaunchSuite createProxiedXmlSuite(final File xmlSuitePath) { return new LaunchSuite.ExistingSuite(xmlSuitePath); } public static LaunchSuite createSuite(String projectName, Collection packageNames, Map> classAndMethodNames, Collection groupNames, Map parameters, String annotationType, int logLevel) { LaunchSuite result; Collection classes = classAndMethodNames != null ? classAndMethodNames.keySet() : EMPTY_CLASS_LIST; if ((null != groupNames) && !groupNames.isEmpty()) { // // Create a suite from groups // result = new LaunchSuite.ClassListSuite(projectName, packageNames, classes, groupNames, parameters, annotationType, logLevel); } else if (packageNames != null && packageNames.size() > 0) { // // Create a suite from packages // result = new LaunchSuite.ClassListSuite(projectName, packageNames, classes, groupNames, parameters, annotationType, logLevel); } else { // // Default suite creation // result = new LaunchSuite.ClassesAndMethodsSuite(projectName, classAndMethodNames, parameters, annotationType, logLevel); } return result; } /** * @deprecated use {@link #createSuite(String, java.util.Collection, java.util.Map, * java.util.Collection, java.util.Map, String, int)} instead. */ @Deprecated public static LaunchSuite createCustomizedSuite(String projectName, Collection packageNames, Collection classNames, Collection methodNames, Collection groupNames, Map parameters, String annotationType, int logLevel) { if ((null != groupNames) && !groupNames.isEmpty()) { return new LaunchSuite.ClassListSuite(projectName, packageNames, classNames, groupNames, parameters, annotationType, logLevel); } else if ((classNames != null && classNames.size() > 1) || packageNames != null && packageNames.size() > 0) { return new LaunchSuite.ClassListSuite(projectName, packageNames, classNames, groupNames, parameters, annotationType, logLevel); } else { return new LaunchSuite.MethodsSuite(projectName, classNames.iterator().next(), methodNames, parameters, annotationType, logLevel); } } } testng-6.9.12/src/main/java/org/testng/xml/XmlMethodSelectors.java0000644000175000017500000000162512732165123024404 0ustar eugeneeugenepackage org.testng.xml; import static org.testng.collections.CollectionUtils.hasElements; import org.testng.collections.Lists; import org.testng.reporters.XMLStringBuffer; import java.util.List; public class XmlMethodSelectors { private List m_methodSelectors = Lists.newArrayList(); public XmlMethodSelectors() { } public List getMethodSelectors() { return m_methodSelectors; } public void setMethodSelector(XmlMethodSelector xms) { m_methodSelectors.add(xms); } public String toXml(String indent) { XMLStringBuffer xsb = new XMLStringBuffer(indent); if (hasElements(m_methodSelectors)) { xsb.push("method-selectors"); for (XmlMethodSelector selector : m_methodSelectors) { xsb.getStringBuffer().append(selector.toXml(indent + " ")); } xsb.pop("method-selectors"); } return xsb.toXML(); } } testng-6.9.12/src/main/java/org/testng/xml/XmlInclude.java0000644000175000017500000001026512732165123022663 0ustar eugeneeugenepackage org.testng.xml; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.reporters.XMLStringBuffer; import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.Properties; public class XmlInclude implements Serializable { private static final long serialVersionUID = 1L; private final String m_name; private final List m_invocationNumbers; private final int m_index; private String m_description; private final Map m_parameters = Maps.newHashMap(); private XmlClass m_xmlClass; public XmlInclude(String n) { this(n, 0); } public XmlInclude(String n, int index) { this(n, Lists.newArrayList(), index); } public XmlInclude(String n, List list, int index) { m_name = n; m_invocationNumbers = list; m_index = index; } public void setDescription(String description) { m_description = description; } public void setParameters(Map parameters) { m_parameters.clear(); m_parameters.putAll(parameters); } public String getDescription() { return m_description; } public String getName() { return m_name; } public List getInvocationNumbers() { return m_invocationNumbers; } public int getIndex() { return m_index; } public String toXml(String indent) { XMLStringBuffer xsb = new XMLStringBuffer(indent); Properties p = new Properties(); p.setProperty("name", getName()); List invocationNumbers = getInvocationNumbers(); if (invocationNumbers != null && invocationNumbers.size() > 0) { p.setProperty("invocation-numbers", XmlClass.listToString(invocationNumbers).toString()); } if (!m_parameters.isEmpty()){ xsb.push("include", p); XmlUtils.dumpParameters(xsb, m_parameters); xsb.pop("include"); } else { xsb.addEmptyElement("include", p); } return xsb.toXML(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + m_index; result = prime * result + ((m_invocationNumbers == null) ? 0 : m_invocationNumbers.hashCode()); result = prime * result + (m_parameters == null ? 0 : m_parameters.hashCode()); result = prime * result + ((m_name == null) ? 0 : m_name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return XmlSuite.f(); if (getClass() != obj.getClass()) return XmlSuite.f(); XmlInclude other = (XmlInclude) obj; // if (m_index != other.m_index) // return XmlSuite.f(); if (m_invocationNumbers == null) { if (other.m_invocationNumbers != null) return XmlSuite.f(); } else if (!m_invocationNumbers.equals(other.m_invocationNumbers)) return XmlSuite.f(); if (m_name == null) { if (other.m_name != null) return XmlSuite.f(); } else if (!m_name.equals(other.m_name)) return XmlSuite.f(); if (m_parameters == null) { if (other.m_parameters != null) { return XmlSuite.f(); } } else if (!m_parameters.equals(other.m_parameters)) { return XmlSuite.f(); } return true; } public void addParameter(String name, String value) { m_parameters.put(name, value); } /** * @deprecated Use {@code getLocalParameters()} or {@code getAllParameters()} */ @Deprecated public Map getParameters() { return getAllParameters(); } /** * @return the parameters defined in this test tag, and only this test tag. To retrieve * the inherited parameters as well, call {@code getAllParameters()}. */ public Map getLocalParameters() { return m_parameters; } /** * @return the parameters defined in this tag and the tags above it. */ public Map getAllParameters() { Map result = Maps.newHashMap(); if (m_xmlClass != null) { result.putAll(m_xmlClass.getAllParameters()); } result.putAll(m_parameters); return result; } public void setXmlClass(XmlClass xmlClass) { m_xmlClass = xmlClass; } } testng-6.9.12/src/main/java/org/testng/xml/XmlUtils.java0000644000175000017500000000160512732165123022376 0ustar eugeneeugenepackage org.testng.xml; import org.testng.reporters.XMLStringBuffer; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; public class XmlUtils { /** * Don't add this property if it's equal to its default value. */ public static void setProperty(Properties p, String name, String value, String def) { if (! def.equals(value) && value != null) { p.setProperty(name, value); } } public static void dumpParameters(XMLStringBuffer xsb, Map parameters) { // parameters if (!parameters.isEmpty()) { for(Map.Entry para: parameters.entrySet()) { Properties paramProps= new Properties(); paramProps.setProperty("name", para.getKey()); paramProps.setProperty("value", para.getValue()); xsb.addEmptyElement("parameter", paramProps); // BUGFIX: TESTNG-27 } } } } testng-6.9.12/src/main/java/org/testng/xml/IPostProcessor.java0000644000175000017500000000043512732165123023553 0ustar eugeneeugenepackage org.testng.xml; import java.util.Collection; /** * Used by Parser to perform changes on an XML suite after it's been parsed. * * @author Cedric Beust */ public interface IPostProcessor { Collection process(Collection suites); } testng-6.9.12/src/main/java/org/testng/xml/XMLParser.java0000644000175000017500000000704012732165123022431 0ustar eugeneeugenepackage org.testng.xml; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.testng.TestNGException; import org.testng.internal.ClassHelper; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; abstract public class XMLParser implements IFileParser { private final static SAXParser m_saxParser; static { SAXParserFactory spf = loadSAXParserFactory(); if (supportsValidation(spf)) { spf.setNamespaceAware(true); spf.setValidating(true); } SAXParser parser = null; try { parser = spf.newSAXParser(); } catch (ParserConfigurationException | SAXException e) { e.printStackTrace(); } m_saxParser = parser; } public void parse(InputStream is, DefaultHandler dh) throws SAXException, IOException { synchronized (m_saxParser) { m_saxParser.parse(is, dh); } } /** * Tries to load a SAXParserFactory by trying in order the following: * com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl (SUN JDK5) * org.apache.crimson.jaxp.SAXParserFactoryImpl (SUN JDK1.4) and * last SAXParserFactory.newInstance(). * * @return a SAXParserFactory implementation * @throws TestNGException thrown if no SAXParserFactory can be loaded */ private static SAXParserFactory loadSAXParserFactory() { SAXParserFactory spf = null; StringBuffer errorLog= new StringBuffer(); try { Class factoryClass= ClassHelper.forName("com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"); spf = (SAXParserFactory) factoryClass.newInstance(); } catch(Exception ex) { errorLog.append("JDK5 SAXParserFactory cannot be loaded: " + ex.getMessage()); } if(null == spf) { // If running with JDK 1.4 try { Class factoryClass = ClassHelper.forName("org.apache.crimson.jaxp.SAXParserFactoryImpl"); spf = (SAXParserFactory) factoryClass.newInstance(); } catch(Exception ex) { errorLog.append("\n").append("JDK1.4 SAXParserFactory cannot be loaded: " + ex.getMessage()); } } Throwable cause= null; if(null == spf) { try { spf= SAXParserFactory.newInstance(); } catch(FactoryConfigurationError fcerr) { cause= fcerr; } } if(null == spf) { throw new TestNGException("Cannot initialize a SAXParserFactory\n" + errorLog.toString(), cause); } return spf; } /** * Tests if the current SAXParserFactory supports DTD validation. */ private static boolean supportsValidation(SAXParserFactory spf) { try { spf.getFeature("http://xml.org/sax/features/validation"); return true; } catch(Exception ex) { return false; } } // private static void ppp(String s) { // System.out.println("[Parser] " + s); // } // /** // * // * @param argv ignored // * @throws FileNotFoundException if the // * @throws ParserConfigurationException // * @throws SAXException // * @throws IOException // * @since 1.0 // */ // public static void main(String[] argv) // throws FileNotFoundException, ParserConfigurationException, SAXException, IOException // { // XmlSuite l = // new Parser("c:/eclipse-workspace/testng/test/testng.xml").parse(); // // System.out.println(l); // } @Override } testng-6.9.12/src/main/java/org/testng/xml/XmlScript.java0000644000175000017500000000067212732165123022545 0ustar eugeneeugenepackage org.testng.xml; import org.testng.xml.dom.TagContent; public class XmlScript { private String m_language; private String m_script; public void setLanguage(String language) { m_language = language; } @TagContent(name = "script") public void setScript(String script) { m_script = script; } public String getScript() { return m_script; } public String getLanguage() { return m_language; } } testng-6.9.12/src/main/java/org/testng/xml/TestNGContentHandler.java0000755000175000017500000006167212732165123024627 0ustar eugeneeugenepackage org.testng.xml; import static org.testng.internal.Utils.isStringBlank; import org.testng.ITestObjectFactory; import org.testng.TestNGException; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.Utils; import org.testng.log4testng.Logger; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Stack; /** * Suite definition parser utility. * * @author Cedric Beust * @author Alexandru Popescu */ public class TestNGContentHandler extends DefaultHandler { private XmlSuite m_currentSuite = null; private XmlTest m_currentTest = null; private List m_currentDefines = null; private List m_currentRuns = null; private List m_currentClasses = null; private int m_currentTestIndex = 0; private int m_currentClassIndex = 0; private int m_currentIncludeIndex = 0; private List m_currentPackages = null; private XmlPackage m_currentPackage = null; private List m_suites = Lists.newArrayList(); private List m_currentIncludedGroups = null; private List m_currentExcludedGroups = null; private Map m_currentTestParameters = null; private Map m_currentSuiteParameters = null; private Map m_currentClassParameters = null; private Include m_currentInclude; private List m_currentMetaGroup = null; private String m_currentMetaGroupName; enum Location { SUITE, TEST, CLASS, INCLUDE, EXCLUDE } private Stack m_locations = new Stack<>(); private XmlClass m_currentClass = null; private ArrayList m_currentIncludedMethods = null; private List m_currentExcludedMethods = null; private ArrayList m_currentSelectors = null; private XmlMethodSelector m_currentSelector = null; private String m_currentLanguage = null; private String m_currentExpression = null; private List m_suiteFiles = Lists.newArrayList(); private boolean m_enabledTest; private List m_listeners; private String m_fileName; private boolean m_loadClasses; private boolean m_validate = false; private boolean m_hasWarn = false; public TestNGContentHandler(String fileName, boolean loadClasses) { m_fileName = fileName; m_loadClasses = loadClasses; } static private void ppp(String s) { System.out.println("[TestNGContentHandler] " + s); } /* * (non-Javadoc) * * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, * java.lang.String) */ @Override public InputSource resolveEntity(String systemId, String publicId) throws IOException, SAXException { InputSource result = null; if (Parser.DEPRECATED_TESTNG_DTD_URL.equals(publicId) || Parser.TESTNG_DTD_URL.equals(publicId)) { m_validate = true; InputStream is = getClass().getClassLoader().getResourceAsStream(Parser.TESTNG_DTD); if (null == is) { is = Thread.currentThread().getContextClassLoader().getResourceAsStream(Parser.TESTNG_DTD); if (null == is) { System.out.println("WARNING: couldn't find in classpath " + publicId + "\n" + "Fetching it from the Web site."); result = super.resolveEntity(systemId, publicId); } else { result = new InputSource(is); } } else { result = new InputSource(is); } } else { result = super.resolveEntity(systemId, publicId); } return result; } /** * Parse */ private void xmlSuiteFile(boolean start, Attributes attributes) { if (start) { String path = attributes.getValue("path"); pushLocation(Location.SUITE); m_suiteFiles.add(path); } else { m_currentSuite.setSuiteFiles(m_suiteFiles); popLocation(Location.SUITE); } } /** * Parse */ private void xmlSuite(boolean start, Attributes attributes) { if (start) { pushLocation(Location.SUITE); String name = attributes.getValue("name"); if (isStringBlank(name)) { throw new TestNGException("The tag must define the name attribute"); } m_currentSuite = new XmlSuite(); m_currentSuite.setFileName(m_fileName); m_currentSuite.setName(name); m_currentSuiteParameters = Maps.newHashMap(); String verbose = attributes.getValue("verbose"); if (null != verbose) { m_currentSuite.setVerbose(Integer.parseInt(verbose)); } String jUnit = attributes.getValue("junit"); if (null != jUnit) { m_currentSuite.setJUnit(Boolean.valueOf(jUnit)); } String parallel = attributes.getValue("parallel"); if (parallel != null) { XmlSuite.ParallelMode mode = XmlSuite.ParallelMode.getValidParallel(parallel); if (mode != null) { m_currentSuite.setParallel(mode); } else { Utils.log("Parser", 1, "[WARN] Unknown value of attribute 'parallel' at suite level: '" + parallel + "'."); } } String parentModule = attributes.getValue("parent-module"); if (parentModule != null) { m_currentSuite.setParentModule(parentModule); } String guiceStage = attributes.getValue("guice-stage"); if (guiceStage != null) { m_currentSuite.setGuiceStage(guiceStage); } XmlSuite.FailurePolicy configFailurePolicy = XmlSuite.FailurePolicy.getValidPolicy(attributes.getValue("configfailurepolicy")); if (null != configFailurePolicy) { m_currentSuite.setConfigFailurePolicy(configFailurePolicy); } String groupByInstances = attributes.getValue("group-by-instances"); if (groupByInstances!= null) { m_currentSuite.setGroupByInstances(Boolean.valueOf(groupByInstances)); } String skip = attributes.getValue("skipfailedinvocationcounts"); if (skip != null) { m_currentSuite.setSkipFailedInvocationCounts(Boolean.valueOf(skip)); } String threadCount = attributes.getValue("thread-count"); if (null != threadCount) { m_currentSuite.setThreadCount(Integer.parseInt(threadCount)); } String dataProviderThreadCount = attributes.getValue("data-provider-thread-count"); if (null != dataProviderThreadCount) { m_currentSuite.setDataProviderThreadCount(Integer.parseInt(dataProviderThreadCount)); } String timeOut = attributes.getValue("time-out"); if (null != timeOut) { m_currentSuite.setTimeOut(timeOut); } String objectFactory = attributes.getValue("object-factory"); if (null != objectFactory && m_loadClasses) { try { m_currentSuite.setObjectFactory((ITestObjectFactory)Class.forName(objectFactory).newInstance()); } catch(Exception e) { Utils.log("Parser", 1, "[ERROR] Unable to create custom object factory '" + objectFactory + "' :" + e); } } String preserveOrder = attributes.getValue("preserve-order"); if (preserveOrder != null) { m_currentSuite.setPreserveOrder(preserveOrder); } String allowReturnValues = attributes.getValue("allow-return-values"); if (allowReturnValues != null) { m_currentSuite.setAllowReturnValues(Boolean.valueOf(allowReturnValues)); } } else { m_currentSuite.setParameters(m_currentSuiteParameters); m_suites.add(m_currentSuite); m_currentSuiteParameters = null; popLocation(Location.SUITE); } } /** * Parse */ private void xmlDefine(boolean start, Attributes attributes) { if (start) { String name = attributes.getValue("name"); m_currentDefines = Lists.newArrayList(); m_currentMetaGroup = Lists.newArrayList(); m_currentMetaGroupName = name; } else { m_currentTest.addMetaGroup(m_currentMetaGroupName, m_currentMetaGroup); m_currentDefines = null; } } /** * Parse \n" + "\n"; public static void generateLog(ITestContext testContext, String host, String outputDirectory, Collection failedConfs, Collection skippedConfs, Collection passedTests, Collection failedTests, Collection skippedTests, Collection percentageTests) { try (PrintWriter writer = new PrintWriter(Utils.openWriter(outputDirectory, getOutputFile(testContext)))) { writer.append("\n\n") .append("TestNG: ").append(testContext.getName()).append("\n") .append(HtmlHelper.getCssString()) .append(HEAD) .append("\n") .append("\n"); Date startDate = testContext.getStartDate(); Date endDate = testContext.getEndDate(); long duration = (endDate.getTime() - startDate.getTime()) / 1000; int passed = testContext.getPassedTests().size() + testContext.getFailedButWithinSuccessPercentageTests().size(); int failed = testContext.getFailedTests().size(); int skipped = testContext.getSkippedTests().size(); String hostLine = Utils.isStringEmpty(host) ? "" : "Remote host:" + host + "\n"; writer .append("

").append(testContext.getName()).append("

") .append("\n") .append("\n") // .append("\n") // .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append(hostLine) .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("
Property file:").append(m_testRunner.getPropertyFileName()).append("
Tests passed/Failed/Skipped:").append(Integer.toString(passed)).append("/").append(Integer.toString(failed)).append("/").append(Integer.toString(skipped)).append("
Started on:").append(testContext.getStartDate().toString()).append("
Total time:").append(Long.toString(duration)).append(" seconds (").append(Long.toString(endDate.getTime() - startDate.getTime())) .append(" ms)
Included groups:").append(arrayToString(testContext.getIncludedGroups())).append("
Excluded groups:").append(arrayToString(testContext.getExcludedGroups())).append("

\n"); writer.append("(Hover the method name to see the test class name)

\n"); if (failedConfs.size() > 0) { generateTable(writer, "FAILED CONFIGURATIONS", failedConfs, "failed", CONFIGURATION_COMPARATOR); } if (skippedConfs.size() > 0) { generateTable(writer, "SKIPPED CONFIGURATIONS", skippedConfs, "skipped", CONFIGURATION_COMPARATOR); } if (failedTests.size() > 0) { generateTable(writer, "FAILED TESTS", failedTests, "failed", NAME_COMPARATOR); } if (percentageTests.size() > 0) { generateTable(writer, "FAILED TESTS BUT WITHIN SUCCESS PERCENTAGE", percentageTests, "percent", NAME_COMPARATOR); } if (passedTests.size() > 0) { generateTable(writer, "PASSED TESTS", passedTests, "passed", NAME_COMPARATOR); } if (skippedTests.size() > 0) { generateTable(writer, "SKIPPED TESTS", skippedTests, "skipped", NAME_COMPARATOR); } writer.append("\n"); } catch (IOException e) { if (TestRunner.getVerbose() > 1) { e.printStackTrace(); } else { ppp(e.getMessage()); } } } private static void ppp(String s) { System.out.println("[TestHTMLReporter] " + s); } private static class NameComparator implements Comparator, Serializable { private static final long serialVersionUID = 381775815838366907L; public int compare(ITestResult o1, ITestResult o2) { String c1 = o1.getMethod().getMethodName(); String c2 = o2.getMethod().getMethodName(); return c1.compareTo(c2); } } private static class ConfigurationComparator implements Comparator, Serializable { private static final long serialVersionUID = 5558550850685483455L; public int compare(ITestResult o1, ITestResult o2) { ITestNGMethod tm1= o1.getMethod(); ITestNGMethod tm2= o2.getMethod(); return annotationValue(tm2) - annotationValue(tm1); } private static int annotationValue(ITestNGMethod method) { if(method.isBeforeSuiteConfiguration()) { return 10; } if(method.isBeforeTestConfiguration()) { return 9; } if(method.isBeforeClassConfiguration()) { return 8; } if(method.isBeforeGroupsConfiguration()) { return 7; } if(method.isBeforeMethodConfiguration()) { return 6; } if(method.isAfterMethodConfiguration()) { return 5; } if(method.isAfterGroupsConfiguration()) { return 4; } if(method.isAfterClassConfiguration()) { return 3; } if(method.isAfterTestConfiguration()) { return 2; } if(method.isAfterSuiteConfiguration()) { return 1; } return 0; } } } testng-6.9.12/src/main/java/org/testng/reporters/XMLStringBuffer.java0000755000175000017500000002731012732165123025027 0ustar eugeneeugenepackage org.testng.reporters; import java.io.Writer; import java.util.Properties; import java.util.Stack; import java.util.regex.Pattern; import org.testng.internal.Nullable; /** * This class allows you to generate an XML text document by pushing * and popping tags from a stack maintained internally. * * @author Cedric Beust Jul 21, 2003 */ public class XMLStringBuffer { /** End of line, value of 'line.separator' system property or '\n' */ private static final String EOL = System.getProperty("line.separator", "\n"); /** Tab space indent for XML document */ private static final String DEFAULT_INDENT_INCREMENT = " "; /** The buffer to hold the xml document */ private IBuffer m_buffer; /** The stack of tags to make sure XML document is well formed. */ private final Stack m_tagStack = new Stack<>(); /** A string of space character representing the current indentation. */ private String m_currentIndent = ""; public XMLStringBuffer() { init(Buffer.create(), "", "1.0", "UTF-8"); } /** * @param start A string of spaces indicating the indentation at which * to start the generation. This constructor will not insert an ").append(EOL); } /** * Set the doctype for this document. * * @param docType The DOCTYPE string, without the "<!DOCTYPE " ">" */ public void setDocType(String docType) { m_buffer.append("" + EOL); } /** * Push a new tag. Its value is stored and will be compared against the parameter * passed to pop(). * * @param tagName The name of the tag. * @param schema The schema to use (can be null or an empty string). * @param attributes A Properties file representing the attributes (or null) */ public void push(String tagName, @Nullable String schema, @Nullable Properties attributes) { XMLUtils.xmlOpen(m_buffer, m_currentIndent, tagName + schema, attributes); m_tagStack.push(new Tag(m_currentIndent, tagName, attributes)); m_currentIndent += DEFAULT_INDENT_INCREMENT; } /** * Push a new tag. Its value is stored and will be compared against the parameter * passed to pop(). * * @param tagName The name of the tag. * @param schema The schema to use (can be null or an empty string). */ public void push(String tagName, @Nullable String schema) { push(tagName, schema, null); } /** * Push a new tag. Its value is stored and will be compared against the parameter * passed to pop(). * * @param tagName The name of the tag. * @param attributes A Properties file representing the attributes (or null) */ public void push(String tagName, @Nullable Properties attributes) { push(tagName, "", attributes); } public void push(String tagName, String... attributes) { push(tagName, createProperties(attributes)); } private Properties createProperties(String[] attributes) { Properties result = new Properties(); if (attributes == null) { return result; } if (attributes.length % 2 != 0) { throw new IllegalArgumentException("Arguments 'attributes' length must be even. Actual: " + attributes.length); } for (int i = 0; i < attributes.length; i += 2) { result.put(attributes[i], attributes[i + 1]); } return result; } /** * Push a new tag. Its value is stored and will be compared against the parameter * passed to pop(). * * @param tagName The name of the tag. */ public void push(String tagName) { push(tagName, ""); } /** * Pop the last pushed element without verifying it if matches the previously * pushed tag. */ public void pop() { pop(null); } /** * Pop the last pushed element and throws an AssertionError if it doesn't * match the corresponding tag that was pushed earlier. * * @param tagName The name of the tag this pop() is supposed to match. */ public void pop(String tagName) { m_currentIndent = m_currentIndent.substring(DEFAULT_INDENT_INCREMENT.length()); Tag t = m_tagStack.pop(); if (null != tagName) { if (!tagName.equals(t.tagName)) { // TODO Is it normal to throw an Error here? throw new AssertionError( "Popping the wrong tag: " + t.tagName + " but expected " + tagName); } } XMLUtils.xmlClose(m_buffer, m_currentIndent, t.tagName, XMLUtils.extractComment(tagName, t.properties)); } /** * Add a required element to the current tag. An opening and closing tag * will be generated even if value is null. * @param tagName The name of the tag * @param value The value for this tag */ public void addRequired(String tagName, @Nullable String value) { addRequired(tagName, value, (Properties) null); } /** * Add a required element to the current tag. An opening and closing tag * will be generated even if value is null. * @param tagName The name of the tag * @param value The value for this tag * @param attributes A Properties file containing the attributes (or null) */ public void addRequired(String tagName, @Nullable String value, @Nullable Properties attributes) { XMLUtils.xmlRequired(m_buffer, m_currentIndent, tagName, value, attributes); } public void addRequired(String tagName, @Nullable String value, String... attributes) { addRequired(tagName, value, createProperties(attributes)); } /** * Add an optional String element to the current tag. If value is null, nothing is * added. * @param tagName The name of the tag * @param value The value for this tag * @param attributes A Properties file containing the attributes (or null) */ public void addOptional(String tagName, @Nullable String value, @Nullable Properties attributes) { if (value != null) { XMLUtils.xmlOptional(m_buffer, m_currentIndent, tagName, value, attributes); } } public void addOptional(String tagName, @Nullable String value, String... attributes) { if (value != null) { XMLUtils.xmlOptional(m_buffer, m_currentIndent, tagName, value, createProperties(attributes)); } } /** * Add an optional String element to the current tag. If value is null, nothing is * added. * @param tagName The name of the tag * @param value The value for this tag */ public void addOptional(String tagName, @Nullable String value) { addOptional(tagName, value, (Properties) null); } /** * Add an optional Boolean element to the current tag. If value is null, nothing is * added. * @param tagName The name of the tag * @param value The value for this tag * @param attributes A Properties file containing the attributes (or null) */ public void addOptional(String tagName, @Nullable Boolean value, @Nullable Properties attributes) { if (null != value) { XMLUtils.xmlOptional(m_buffer, m_currentIndent, tagName, value.toString(), attributes); } } /** * Add an optional Boolean element to the current tag. If value is null, nothing is * added. * @param tagName The name of the tag * @param value The value for this tag */ public void addOptional(String tagName, @Nullable Boolean value) { addOptional(tagName, value, null); } /** * Add an empty element tag (e.g. ) * * @param tagName The name of the tag * */ public void addEmptyElement(String tagName) { addEmptyElement(tagName, (Properties) null); } /** * Add an empty element tag (e.g. ) * @param tagName The name of the tag * @param attributes A Properties file containing the attributes (or null) */ public void addEmptyElement(String tagName, @Nullable Properties attributes) { m_buffer.append(m_currentIndent).append("<").append(tagName); XMLUtils.appendAttributes(m_buffer, attributes); m_buffer.append("/>").append(EOL); } public void addEmptyElement(String tagName, String... attributes) { addEmptyElement(tagName, createProperties(attributes)); } public void addComment(String comment) { m_buffer.append(m_currentIndent).append("\n"); } public void addString(String s) { m_buffer.append(s); } private static void ppp(String s) { System.out.println("[XMLStringBuffer] " + s); } /** * Add a CDATA tag. */ public void addCDATA(String content) { if (content == null) { content = "null"; } if (content.contains("]]>")) { String[] subStrings = content.split("]]>"); m_buffer.append(m_currentIndent).append(""); for (int i = 1; i < subStrings.length - 1; i++) { m_buffer.append("").append(subStrings[i]).append("]]]]>"); } m_buffer.append("").append(subStrings[subStrings.length - 1]).append("]]>"); if (content.endsWith("]]>")) { m_buffer.append("").append("]]>"); } m_buffer.append(EOL); } else { m_buffer.append(m_currentIndent).append("" + EOL); } } /** * * @return The StringBuffer used to create the document. */ public IBuffer getStringBuffer() { return m_buffer; } private static final Pattern INVALID_XML_CHARS = Pattern.compile("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD\uD800\uDC00-\uDBFF\uDFFF]"); /** * @return The String representation of the XML for this XMLStringBuffer. */ public String toXML() { return INVALID_XML_CHARS.matcher(m_buffer.toString()).replaceAll(""); } public static void main(String[] argv) { IBuffer result = Buffer.create(); XMLStringBuffer sb = new XMLStringBuffer(result, ""); sb.push("family"); Properties p = new Properties(); p.setProperty("prop1", "value1"); p.setProperty("prop2", "value2"); sb.addRequired("cedric", "true", p); sb.addRequired("alois", "true"); sb.addOptional("anne-marie", (String) null); sb.pop(); System.out.println(result.toString()); assert ("" + EOL + "true" + EOL + "true" + EOL + "" + EOL) .equals(result.toString()); } public String getCurrentIndent() { return m_currentIndent; } public void toWriter(Writer fw) { m_buffer.toWriter(fw); } } //////////////////////// class Tag { public final String tagName; public final String indent; public final Properties properties; public Tag(String ind, String n, Properties p) { tagName = n; indent = ind; properties = p; } @Override public String toString() { return tagName; } } testng-6.9.12/src/main/java/org/testng/reporters/JqReporter.java0000644000175000017500000001647212732165123024147 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.IReporter; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.collections.ListMultiMap; import org.testng.collections.Maps; import org.testng.internal.Utils; import org.testng.xml.XmlSuite; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; public class JqReporter implements IReporter { private static final String C = "class"; private static final String D = "div"; private static final String S = "span"; private int m_testCount = 0; private String m_outputDirectory; private Map m_testMap = Maps.newHashMap(); @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { m_outputDirectory = "/Users/cedric/java/misc/jquery"; XMLStringBuffer xsb = new XMLStringBuffer(" "); xsb.push(D, "id", "suites"); generateSuites(xmlSuites, suites, xsb); xsb.pop(D); String all; try { all = Files.readFile(new File("/Users/cedric/java/misc/jquery/head")); Utils.writeFile(m_outputDirectory, "index2.html", all + xsb.toXML()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private XMLStringBuffer generateSuites(List xmlSuites, List suites, XMLStringBuffer main) { for (ISuite suite : suites) { if (suite.getResults().size() == 0) { continue; } XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); XMLStringBuffer header = new XMLStringBuffer(main.getCurrentIndent()); xsb.push(D, C, "suite-content"); Map results = suite.getResults(); XMLStringBuffer xs1 = new XMLStringBuffer(xsb.getCurrentIndent()); XMLStringBuffer xs2 = new XMLStringBuffer(xsb.getCurrentIndent()); XMLStringBuffer xs3 = new XMLStringBuffer(xsb.getCurrentIndent()); int failed = 0; int skipped = 0; int passed = 0; for (ISuiteResult result : results.values()) { ITestContext context = result.getTestContext(); failed += context.getFailedTests().size(); generateTests("failed", context.getFailedTests(), context, xs1); skipped += context.getSkippedTests().size(); generateTests("skipped", context.getSkippedTests(), context, xs2); passed += context.getPassedTests().size(); generateTests("passed", context.getPassedTests(), context, xs3); } xsb.addOptional(D, "Failed" + " tests", C, "result-banner " + "failed"); xsb.addString(xs1.toXML()); xsb.addOptional(D, "Skipped" + " tests", C, "result-banner " + "skipped"); xsb.addString(xs2.toXML()); xsb.addOptional(D, "Passed" + " tests", C, "result-banner " + "passed"); xsb.addString(xs3.toXML()); header.push(D, C, "suite"); header.push(D, C, "suite-header"); header.addOptional(S, suite.getName(), C, "suite-name"); header.push(D, C, "stats"); int total = failed + skipped + passed; String stats = String.format("%s, %d failed, %d skipped, %d passed", pluralize(total, "method"), failed, skipped, passed); header.push("ul"); // Method stats header.push("li"); header.addOptional(S, stats, C, "method-stats"); header.pop("li"); // Tests header.push("li"); header.addOptional(S, String.format("%s ", pluralize(results.values().size(), "test"), C, "test-stats")); header.pop("li"); // List of tests header.push("ul"); for (ISuiteResult tr : results.values()) { String testName = tr.getTestContext().getName(); header.push("li"); header.addOptional("a", testName, "href", "#" + m_testMap.get(testName)); header.pop("li"); } header.pop("ul"); header.pop("ul"); header.pop(D); header.pop(D); main.addString(header.toXML()); main.addString(xsb.toXML()); } return main; } private String capitalize(String s) { return Character.toUpperCase(s.charAt(0)) + s.substring(1); } private void generateTests(String tagClass, IResultMap tests, ITestContext context, XMLStringBuffer xsb) { if (tests.getAllMethods().isEmpty()) return; xsb.push(D, C, "test" + (tagClass != null ? " " + tagClass : "")); ListMultiMap, ITestResult> map = Maps.newListMultiMap(); for (ITestResult m : tests.getAllResults()) { map.put(m.getTestClass().getRealClass(), m); } String testName = "test-" + (m_testCount++); m_testMap.put(context.getName(), testName); xsb.push(D, C, "test-name"); xsb.push("a", "name", testName); xsb.addString(context.getName()); xsb.pop("a"); // Expand icon xsb.push("a", C, "expand", "href", "#"); xsb.addEmptyElement("img", "src", getStatusImage(tagClass)); xsb.pop("a"); xsb.pop(D); xsb.push(D, C, "test-content"); for (Class c : map.keySet()) { xsb.push(D, C, C); xsb.push(D, C, "class-header"); // Passed/failed icon xsb.addEmptyElement("img", "src", getImage(tagClass)); xsb.addOptional(S, c.getName(), C, "class-name"); xsb.pop(D); xsb.push(D, C, "class-content"); List l = map.get(c); for (ITestResult m : l) { generateMethod(tagClass, m, context, xsb); } xsb.pop(D); xsb.pop(D); } xsb.pop(D); xsb.pop(D); } private static String getStatusImage(String status) { return "up.png"; // if ("passed".equals(status)) return "down.png"; // else return "up.png"; } private static String getImage(String tagClass) { return tagClass + ".png"; } private void generateMethod(String tagClass, ITestResult tr, ITestContext context, XMLStringBuffer xsb) { long time = tr.getEndMillis() - tr.getStartMillis(); xsb.push(D, C, "method"); xsb.push(D, C, "method-content"); xsb.addOptional(S, tr.getMethod().getMethodName(), C, "method-name"); // Parameters? if (tr.getParameters().length > 0) { StringBuilder sb = new StringBuilder(); boolean first = true; for (Object p : tr.getParameters()) { if (!first) sb.append(", "); first = false; sb.append(Utils.toString(p)); } xsb.addOptional(S, "(" + sb.toString() + ")", C, "parameters"); } // Exception? if (tr.getThrowable() != null) { StringBuilder stackTrace = new StringBuilder(); for (StackTraceElement str : tr.getThrowable().getStackTrace()) { stackTrace.append(str.toString()).append("
"); } xsb.addOptional(D, stackTrace.toString() + "\n", C, "stack-trace"); } xsb.addOptional(S, " " + Long.toString(time) + " ms", C, "method-time"); xsb.pop(D); xsb.pop(D); } /** * Overridable by subclasses to create different directory names (e.g. with timestamps). * @param outputDirectory the output directory specified by the user */ protected String generateOutputDirectoryName(String outputDirectory) { return outputDirectory; } private String pluralize(int count, String singular) { return Integer.toString(count) + " " + (count > 1 ? (singular.endsWith("s") ? singular + "es" : singular + "s") : singular); } } testng-6.9.12/src/main/java/org/testng/reporters/EmailableReporter.java0000755000175000017500000004263612732165123025454 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.IInvokedMethod; import org.testng.IReporter; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.collections.Lists; import org.testng.internal.Utils; import org.testng.log4testng.Logger; import org.testng.xml.XmlSuite; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; /** * Reported designed to render self-contained HTML top down view of a testing * suite. * * @author Paul Mendelson * @since 5.2 * @version $Revision: 719 $ */ public class EmailableReporter implements IReporter { private static final Logger L = Logger.getLogger(EmailableReporter.class); // ~ Instance fields ------------------------------------------------------ private PrintWriter m_out; private int m_row; private Integer m_testIndex; private int m_methodIndex; // ~ Methods -------------------------------------------------------------- /** Creates summary of the run */ @Override public void generateReport(List xml, List suites, String outdir) { try { m_out = createWriter(outdir); } catch (IOException e) { L.error("output file", e); return; } startHtml(m_out); generateSuiteSummaryReport(suites); generateMethodSummaryReport(suites); generateMethodDetailReport(suites); endHtml(m_out); m_out.flush(); m_out.close(); } protected PrintWriter createWriter(String outdir) throws IOException { new File(outdir).mkdirs(); return new PrintWriter(new BufferedWriter(new FileWriter(new File(outdir, "emailable-report.html")))); } /** Creates a table showing the highlights of each test method with links to the method details */ protected void generateMethodSummaryReport(List suites) { m_methodIndex = 0; startResultSummaryTable("methodOverview"); int testIndex = 1; for (ISuite suite : suites) { if(suites.size()>1) { titleRow(suite.getName(), 5); } Map r = suite.getResults(); for (ISuiteResult r2 : r.values()) { ITestContext testContext = r2.getTestContext(); String testName = testContext.getName(); m_testIndex = testIndex; resultSummary(suite, testContext.getFailedConfigurations(), testName, "failed", " (configuration methods)"); resultSummary(suite, testContext.getFailedTests(), testName, "failed", ""); resultSummary(suite, testContext.getSkippedConfigurations(), testName, "skipped", " (configuration methods)"); resultSummary(suite, testContext.getSkippedTests(), testName, "skipped", ""); resultSummary(suite, testContext.getPassedTests(), testName, "passed", ""); testIndex++; } } m_out.println(""); } /** Creates a section showing known results for each method */ protected void generateMethodDetailReport(List suites) { m_methodIndex = 0; for (ISuite suite : suites) { Map r = suite.getResults(); for (ISuiteResult r2 : r.values()) { ITestContext testContext = r2.getTestContext(); if (r.values().size() > 0) { m_out.println("

" + testContext.getName() + "

"); } resultDetail(testContext.getFailedConfigurations()); resultDetail(testContext.getFailedTests()); resultDetail(testContext.getSkippedConfigurations()); resultDetail(testContext.getSkippedTests()); resultDetail(testContext.getPassedTests()); } } } /** * @param tests */ private void resultSummary(ISuite suite, IResultMap tests, String testname, String style, String details) { if (tests.getAllResults().size() > 0) { StringBuffer buff = new StringBuffer(); String lastClassName = ""; int mq = 0; int cq = 0; for (ITestNGMethod method : getMethodSet(tests, suite)) { m_row += 1; m_methodIndex += 1; ITestClass testClass = method.getTestClass(); String className = testClass.getName(); if (mq == 0) { String id = (m_testIndex == null ? null : "t" + Integer.toString(m_testIndex)); titleRow(testname + " — " + style + details, 5, id); m_testIndex = null; } if (!className.equalsIgnoreCase(lastClassName)) { if (mq > 0) { cq += 1; m_out.print("" + " 1) { m_out.print(" rowspan=\"" + mq + "\""); } m_out.println(">" + lastClassName + "" + buff); } mq = 0; buff.setLength(0); lastClassName = className; } Set resultSet = tests.getResults(method); long end = Long.MIN_VALUE; long start = Long.MAX_VALUE; for (ITestResult testResult : tests.getResults(method)) { if (testResult.getEndMillis() > end) { end = testResult.getEndMillis(); } if (testResult.getStartMillis() < start) { start = testResult.getStartMillis(); } } mq += 1; if (mq > 1) { buff.append(""); } String description = method.getDescription(); String testInstanceName = resultSet.toArray(new ITestResult[]{})[0].getTestName(); buff.append("" + qualifiedName(method) + " " + (description != null && description.length() > 0 ? "(\"" + description + "\")" : "") + "" + (null == testInstanceName ? "" : "
(" + testInstanceName + ")") + "" + "" + resultSet.size() + "" + "" + start + "" + "" + (end - start) + "" + ""); } if (mq > 0) { cq += 1; m_out.print("" + " 1) { m_out.print(" rowspan=\"" + mq + "\""); } m_out.println(">" + lastClassName + "" + buff); } } } /** Starts and defines columns result summary table */ private void startResultSummaryTable(String style) { tableStart(style, "summary"); m_out.println("Class" + "Method# of
ScenariosStartTime
(ms)"); m_row = 0; } private String qualifiedName(ITestNGMethod method) { StringBuilder addon = new StringBuilder(); String[] groups = method.getGroups(); int length = groups.length; if (length > 0 && !"basic".equalsIgnoreCase(groups[0])) { addon.append("("); for (int i = 0; i < length; i++) { if (i > 0) { addon.append(", "); } addon.append(groups[i]); } addon.append(")"); } return "" + method.getMethodName() + " " + addon; } private void resultDetail(IResultMap tests) { for (ITestResult result : tests.getAllResults()) { ITestNGMethod method = result.getMethod(); m_methodIndex++; String cname = method.getTestClass().getName(); m_out.println("

" + cname + ":" + method.getMethodName() + "

"); Set resultSet = tests.getResults(method); generateForResult(result, method, resultSet.size()); m_out.println("

back to summary

"); } } private void generateForResult(ITestResult ans, ITestNGMethod method, int resultSetSize) { Object[] parameters = ans.getParameters(); boolean hasParameters = parameters != null && parameters.length > 0; if (hasParameters) { tableStart("result", null); m_out.print(""); for (int x = 1; x <= parameters.length; x++) { m_out.print("Parameter #" + x + ""); } m_out.println(""); m_out.print(""); for (Object p : parameters) { m_out.println("" + Utils.escapeHtml(Utils.toString(p)) + ""); } m_out.println(""); } List msgs = Reporter.getOutput(ans); boolean hasReporterOutput = msgs.size() > 0; Throwable exception=ans.getThrowable(); boolean hasThrowable = exception!=null; if (hasReporterOutput||hasThrowable) { if (hasParameters) { m_out.print(" 1) { m_out.print(" colspan=\"" + parameters.length + "\""); } m_out.println(">"); } else { m_out.println("
"); } if (hasReporterOutput) { if(hasThrowable) { m_out.println("

Test Messages

"); } for (String line : msgs) { m_out.println(line + "
"); } } if(hasThrowable) { boolean wantsMinimalOutput = ans.getStatus()==ITestResult.SUCCESS; if(hasReporterOutput) { m_out.println("

" +(wantsMinimalOutput?"Expected Exception":"Failure") +"

"); } generateExceptionReport(exception,method); } if (hasParameters) { m_out.println(""); } else { m_out.println("
"); } } if (hasParameters) { m_out.println(""); } } protected void generateExceptionReport(Throwable exception,ITestNGMethod method) { m_out.print("
"); m_out.print(Utils.stackTrace(exception, true)[0]); m_out.println("
"); } /** * Since the methods will be sorted chronologically, we want to return * the ITestNGMethod from the invoked methods. */ private Collection getMethodSet(IResultMap tests, ISuite suite) { List r = Lists.newArrayList(); List invokedMethods = suite.getAllInvokedMethods(); for (IInvokedMethod im : invokedMethods) { if (tests.getAllMethods().contains(im.getTestMethod())) { r.add(im); } } Arrays.sort(r.toArray(new IInvokedMethod[r.size()]), new TestSorter()); List result = Lists.newArrayList(); // Add all the invoked methods for (IInvokedMethod m : r) { result.add(m.getTestMethod()); } // Add all the methods that weren't invoked (e.g. skipped) that we // haven't added yet for (ITestNGMethod m : tests.getAllMethods()) { if (!result.contains(m)) { result.add(m); } } return result; } public void generateSuiteSummaryReport(List suites) { tableStart("testOverview", null); m_out.print(""); tableColumnStart("Test"); tableColumnStart("Methods
Passed"); tableColumnStart("Scenarios
Passed"); tableColumnStart("# skipped"); tableColumnStart("# failed"); tableColumnStart("Total
Time"); tableColumnStart("Included
Groups"); tableColumnStart("Excluded
Groups"); m_out.println(""); NumberFormat formatter = new DecimalFormat("#,##0.0"); int qty_tests = 0; int qty_pass_m = 0; int qty_pass_s = 0; int qty_skip = 0; int qty_fail = 0; long time_start = Long.MAX_VALUE; long time_end = Long.MIN_VALUE; m_testIndex = 1; for (ISuite suite : suites) { if (suites.size() > 1) { titleRow(suite.getName(), 8); } Map tests = suite.getResults(); for (ISuiteResult r : tests.values()) { qty_tests += 1; ITestContext overview = r.getTestContext(); startSummaryRow(overview.getName()); int q = getMethodSet(overview.getPassedTests(), suite).size(); qty_pass_m += q; summaryCell(q,Integer.MAX_VALUE); q = overview.getPassedTests().size(); qty_pass_s += q; summaryCell(q,Integer.MAX_VALUE); q = getMethodSet(overview.getSkippedTests(), suite).size(); qty_skip += q; summaryCell(q,0); q = getMethodSet(overview.getFailedTests(), suite).size(); qty_fail += q; summaryCell(q,0); time_start = Math.min(overview.getStartDate().getTime(), time_start); time_end = Math.max(overview.getEndDate().getTime(), time_end); summaryCell(formatter.format( (overview.getEndDate().getTime() - overview.getStartDate().getTime()) / 1000.) + " seconds", true); summaryCell(overview.getIncludedGroups()); summaryCell(overview.getExcludedGroups()); m_out.println(""); m_testIndex++; } } if (qty_tests > 1) { m_out.println("Total"); summaryCell(qty_pass_m,Integer.MAX_VALUE); summaryCell(qty_pass_s,Integer.MAX_VALUE); summaryCell(qty_skip,0); summaryCell(qty_fail,0); summaryCell(formatter.format((time_end - time_start) / 1000.) + " seconds", true); m_out.println(" "); } m_out.println(""); } private void summaryCell(String[] val) { StringBuffer b = new StringBuffer(); for (String v : val) { b.append(v + " "); } summaryCell(b.toString(),true); } private void summaryCell(String v,boolean isgood) { m_out.print("" + v + ""); } private void startSummaryRow(String label) { m_row += 1; m_out.print("" + label + "" + ""); } private void summaryCell(int v,int maxexpected) { summaryCell(String.valueOf(v),v<=maxexpected); } private void tableStart(String cssclass, String id) { m_out.println(""); m_row = 0; } private void tableColumnStart(String label) { m_out.print(""); } private void titleRow(String label, int cq) { titleRow(label, cq, null); } private void titleRow(String label, int cq, String id) { m_out.print(""); m_row = 0; } /** Starts HTML stream */ protected void startHtml(PrintWriter out) { out.println(""); out.println(""); out.println(""); out.println("TestNG Report"); out.println(""); out.println(""); out.println(""); } /** Finishes HTML stream */ protected void endHtml(PrintWriter out) { out.println(""); } // ~ Inner Classes -------------------------------------------------------- /** Arranges methods by classname and method name */ private static final class TestSorter implements Comparator { // ~ Methods ------------------------------------------------------------- /** Arranges methods by classname and method name */ @Override public int compare(IInvokedMethod o1, IInvokedMethod o2) { // System.out.println("Comparing " + o1.getMethodName() + " " + o1.getDate() // + " and " + o2.getMethodName() + " " + o2.getDate()); return (int) (o1.getDate() - o2.getDate()); // int r = ((T) o1).getTestClass().getName().compareTo(((T) o2).getTestClass().getName()); // if (r == 0) { // r = ((T) o1).getMethodName().compareTo(((T) o2).getMethodName()); // } // return r; } } } testng-6.9.12/src/main/java/org/testng/reporters/util/0000755000175000017500000000000012732165123022152 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/reporters/util/StackTraceTools.java0000755000175000017500000000244012732165123026065 0ustar eugeneeugenepackage org.testng.reporters.util; import org.testng.ITestNGMethod; /** * Functionality to allow tools to analyse and subdivide stack traces. * * @author Paul Mendelson * @since 5.3 * @version $Revision: 173 $ */ public class StackTraceTools { /** Finds topmost position of the test method in the stack, or top of stack if method is not in it. */ public static int getTestRoot(StackTraceElement[] stack,ITestNGMethod method) { if(stack!=null) { String cname = method.getTestClass().getName(); for(int x=stack.length-1; x>=0; x--) { if(cname.equals(stack[x].getClassName()) && method.getMethodName().equals(stack[x].getMethodName())) { return x; } } return stack.length-1; } else { return -1; } } /** Finds topmost position of the test method in the stack, or top of stack if method is not in it. */ public static StackTraceElement[] getTestNGInstrastructure(StackTraceElement[] stack,ITestNGMethod method) { int slot=StackTraceTools.getTestRoot(stack, method); if(slot>=0) { StackTraceElement[] r=new StackTraceElement[stack.length-slot]; System.arraycopy(stack, slot, r, 0, r.length); return r; } else { return new StackTraceElement[0]; } } } testng-6.9.12/src/main/java/org/testng/reporters/JUnitReportReporter.java0000644000175000017500000002241612732165123026015 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.collections.ListMultiMap; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.Utils; import org.testng.xml.XmlSuite; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class JUnitReportReporter implements IReporter { @Override public void generateReport(List xmlSuites, List suites, String defaultOutputDirectory) { Map, Set> results = Maps.newHashMap(); Map, Set> failedConfigurations = Maps.newHashMap(); ListMultiMap befores = Maps.newListMultiMap(); ListMultiMap afters = Maps.newListMultiMap(); for (ISuite suite : suites) { Map suiteResults = suite.getResults(); for (ISuiteResult sr : suiteResults.values()) { ITestContext tc = sr.getTestContext(); addResults(tc.getPassedTests().getAllResults(), results); addResults(tc.getFailedTests().getAllResults(), results); addResults(tc.getSkippedTests().getAllResults(), results); addResults(tc.getFailedConfigurations().getAllResults(), failedConfigurations); for (ITestResult tr : tc.getPassedConfigurations().getAllResults()) { if (tr.getMethod().isBeforeMethodConfiguration()) { befores.put(tr.getInstance(), tr); } if (tr.getMethod().isAfterMethodConfiguration()) { afters.put(tr.getInstance(), tr); } } } } // A list of iterators for all the passed configuration, explanation below // ListMultiMap, ITestResult> beforeConfigurations = Maps.newListMultiMap(); // ListMultiMap, ITestResult> afterConfigurations = Maps.newListMultiMap(); // for (Map.Entry, Set> es : passedConfigurations.entrySet()) { // for (ITestResult tr : es.getValue()) { // ITestNGMethod method = tr.getMethod(); // if (method.isBeforeMethodConfiguration()) { // beforeConfigurations.put(method.getRealClass(), tr); // } // if (method.isAfterMethodConfiguration()) { // afterConfigurations.put(method.getRealClass(), tr); // } // } // } // Map> befores = Maps.newHashMap(); // for (Map.Entry, List> es : beforeConfigurations.getEntrySet()) { // List tr = es.getValue(); // for (ITestResult itr : es.getValue()) { // } // } // Map, Iterator> afters = Maps.newHashMap(); // for (Map.Entry, List> es : afterConfigurations.getEntrySet()) { // afters.put(es.getKey(), es.getValue().iterator()); // } for (Map.Entry, Set> entry : results.entrySet()) { Class cls = entry.getKey(); Properties p1 = new Properties(); p1.setProperty("name", cls.getName()); Date timeStamp = Calendar.getInstance().getTime(); p1.setProperty(XMLConstants.ATTR_TIMESTAMP, timeStamp.toGMTString()); List testCases = Lists.newArrayList(); int failures = 0; int errors = 0; int testCount = 0; float totalTime = 0; for (ITestResult tr: entry.getValue()) { TestTag testTag = new TestTag(); boolean isSuccess = tr.getStatus() == ITestResult.SUCCESS; if (! isSuccess) { if (tr.getThrowable() instanceof AssertionError) { failures++; } else { errors++; } } Properties p2 = new Properties(); p2.setProperty("classname", cls.getName()); p2.setProperty("name", getTestName(tr)); long time = tr.getEndMillis() - tr.getStartMillis(); time += getNextConfiguration(befores, tr); time += getNextConfiguration(afters, tr); p2.setProperty("time", "" + formatTime(time)); Throwable t = getThrowable(tr, failedConfigurations); if (! isSuccess && t != null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); testTag.message = t.getMessage(); testTag.type = t.getClass().getName(); testTag.stackTrace = sw.toString(); testTag.errorTag = tr.getThrowable() instanceof AssertionError ? "failure" : "error"; } totalTime += time; testCount++; testTag.properties = p2; testCases.add(testTag); } p1.setProperty("failures", "" + failures); p1.setProperty("errors", "" + errors); p1.setProperty("name", cls.getName()); p1.setProperty("tests", "" + testCount); p1.setProperty("time", "" + formatTime(totalTime)); try { p1.setProperty(XMLConstants.ATTR_HOSTNAME, InetAddress.getLocalHost().getHostName()); } catch (UnknownHostException e) { // ignore } // // Now that we have all the information we need, generate the file // XMLStringBuffer xsb = new XMLStringBuffer(); xsb.addComment("Generated by " + getClass().getName()); xsb.push("testsuite", p1); for (TestTag testTag : testCases) { if (testTag.stackTrace == null) { xsb.addEmptyElement("testcase", testTag.properties); } else { xsb.push("testcase", testTag.properties); Properties p = new Properties(); if (testTag.message != null) { p.setProperty("message", testTag.message); } p.setProperty("type", testTag.type); xsb.push(testTag.errorTag, p); xsb.addCDATA(testTag.stackTrace); xsb.pop(testTag.errorTag); xsb.pop("testcase"); } } xsb.pop("testsuite"); String outputDirectory = defaultOutputDirectory + File.separator + "junitreports"; Utils.writeUtf8File(outputDirectory, getFileName(cls), xsb.toXML()); } // System.out.println(xsb.toXML()); // System.out.println(""); } /** * Add the time of the configuration method to this test method. * * The only problem with this method is that the timing of a test method * might not be added to the time of the same configuration method that ran before * it but since they should all be equivalent, this should never be an issue. */ private long getNextConfiguration(ListMultiMap configurations, ITestResult tr) { long result = 0; List confResults = configurations.get(tr.getInstance()); Map seen = Maps.newHashMap(); if (confResults != null) { for (ITestResult r : confResults) { if (! seen.containsKey(r.getMethod())) { result += r.getEndMillis() - r.getStartMillis(); seen.put(r.getMethod(), r); } } confResults.removeAll(seen.values()); } return result; } protected String getFileName(Class cls) { return "TEST-" + cls.getName() + ".xml"; } protected String getTestName(ITestResult tr) { return tr.getMethod().getMethodName(); } private String formatTime(float time) { DecimalFormatSymbols symbols = new DecimalFormatSymbols(); // JUnitReports wants points here, regardless of the locale symbols.setDecimalSeparator('.'); DecimalFormat format = new DecimalFormat("#.###", symbols); format.setMinimumFractionDigits(3); return format.format(time / 1000.0f); } private Throwable getThrowable(ITestResult tr, Map, Set> failedConfigurations) { Throwable result = tr.getThrowable(); if (result == null && tr.getStatus() == ITestResult.SKIP) { // Attempt to grab the stack trace from the configuration failure for (Set failures : failedConfigurations.values()) { for (ITestResult failure : failures) { // Naive implementation for now, eventually, we need to try to find // out if it's this failure that caused the skip since (maybe by // seeing if the class of the configuration method is assignable to // the class of the test method, although that's not 100% fool proof if (failure.getThrowable() != null) { return failure.getThrowable(); } } } } return result; } static class TestTag { public Properties properties; public String message; public String type; public String stackTrace; public String errorTag; } private void addResults(Set allResults, Map, Set> out) { for (ITestResult tr : allResults) { Class cls = tr.getMethod().getTestClass().getRealClass(); Set l = out.get(cls); if (l == null) { l = Sets.newHashSet(); out.put(cls, l); } l.add(tr); } } } testng-6.9.12/src/main/java/org/testng/reporters/XMLUtils.java0000755000175000017500000001065412732165123023532 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.internal.Nullable; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Map.Entry; import java.util.Properties; /** * Static helpers for XML. * * @author Cedric Beust Jul 21, 2003 * */ public final class XMLUtils { /** Platform specific end of line */ private static final String EOL = System.getProperty("line.separator"); private XMLUtils() { // Hide constructor } /** * Generate tag. * An opening and closing tag will be generated even if value is null. * @param name name of the tag * @param content content for this tag (or null) * @param attributes tag attributes (or null) */ static public String xml(String indent, String name, @Nullable String content, @Nullable Properties attributes) { IBuffer result = Buffer.create(); xmlOpen(result, indent, name, attributes, true /* no newline */); if (content != null) { result.append(content); } xmlClose(result, "", name, XMLUtils.extractComment(name, attributes)); return result.toString(); } public static String extractComment(String tag, Properties properties) { if (properties == null || "span".equals(tag)) return null; String[] attributes = new String[] { "id", "name", "class" }; for (String a : attributes) { String comment = properties.getProperty(a); if (comment != null) { return " "; } } return null; } public static void xmlOptional(IBuffer result, String sp, String elementName, Boolean value, Properties attributes) { if (null != value) { xmlRequired(result, sp, elementName, value.toString(), attributes); } } public static void xmlOptional(IBuffer result, String sp, String elementName, @Nullable String value, Properties attributes) { if (null != value) { xmlRequired(result, sp, elementName, value, attributes); } } public static void xmlRequired(IBuffer result, String sp, String elementName, @Nullable String value, @Nullable Properties attributes) { result.append(xml(sp, elementName, value, attributes)); } public static void xmlOpen(IBuffer result, String indent, String tag, Properties attributes) { xmlOpen(result, indent, tag, attributes, false /* no newline */); } /** * Appends the attributes to result. The attributes are added on a single line * as: key1="value1" key2="value2" ... (a space is added before the first key) * * @param result * the buffer to append attributes to. * @param attributes * the attributes to append (may be null). */ public static void appendAttributes(IBuffer result, Properties attributes) { if (null != attributes) { for (Object element : attributes.entrySet()) { Entry entry = (Entry) element; String key = entry.getKey().toString(); String value = escape(entry.getValue().toString()); result.append(" ").append(key).append("=\"").append(value).append("\""); } } } public static void xmlOpen(IBuffer result, String indent, String tag, Properties attributes, boolean noNewLine) { result.append(indent).append("<").append(tag); appendAttributes(result, attributes); result.append(">"); if (!noNewLine) { result.append(EOL); } } public static void xmlClose(IBuffer result, String indent, String tag, String comment) { result.append(indent).append("") .append(comment != null ? comment : "") .append(EOL); } public static String escape(String input) { if (input == null) { return null; } StringBuilder result = new StringBuilder(); StringCharacterIterator iterator = new StringCharacterIterator(input); char character = iterator.current(); while (character != CharacterIterator.DONE) { if (character == '<') { result.append("<"); } else if (character == '>') { result.append(">"); } else if (character == '\"') { result.append("""); } else if (character == '\'') { result.append("'"); } else if (character == '&') { result.append("&"); } else { result.append(character); } character = iterator.next(); } return result.toString(); } } testng-6.9.12/src/main/java/org/testng/reporters/XMLReporter.java0000755000175000017500000002332712732165123024235 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.Reporter; import org.testng.internal.Utils; import org.testng.xml.XmlSuite; import java.io.File; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TimeZone; /** * The main entry for the XML generation operation * * @author Cosmin Marginean, Mar 16, 2007 */ public class XMLReporter implements IReporter { public static final String FILE_NAME = "testng-results.xml"; private final XMLReporterConfig config = new XMLReporterConfig(); private XMLStringBuffer rootBuffer; @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { if (Utils.isStringEmpty(config.getOutputDirectory())) { config.setOutputDirectory(outputDirectory); } // Calculate passed/failed/skipped int passed = 0; int failed = 0; int skipped = 0; for (ISuite s : suites) { Map suiteResults = s.getResults(); synchronized(suiteResults) { for (ISuiteResult sr : suiteResults.values()) { ITestContext testContext = sr.getTestContext(); passed += testContext.getPassedTests().size(); failed += testContext.getFailedTests().size(); skipped += testContext.getSkippedTests().size(); } } } rootBuffer = new XMLStringBuffer(); Properties p = new Properties(); p.put("passed", passed); p.put("failed", failed); p.put("skipped", skipped); p.put("total", passed + failed + skipped); rootBuffer.push(XMLReporterConfig.TAG_TESTNG_RESULTS, p); writeReporterOutput(rootBuffer); for (ISuite suite : suites) { writeSuite(suite.getXmlSuite(), suite); } rootBuffer.pop(); Utils.writeUtf8File(config.getOutputDirectory(), FILE_NAME, rootBuffer, null /* no prefix */); } private void writeReporterOutput(XMLStringBuffer xmlBuffer) { // TODO: Cosmin - maybe a element isn't indicated for each line xmlBuffer.push(XMLReporterConfig.TAG_REPORTER_OUTPUT); List output = Reporter.getOutput(); for (String line : output) { if (line != null) { xmlBuffer.push(XMLReporterConfig.TAG_LINE); xmlBuffer.addCDATA(line); xmlBuffer.pop(); } } xmlBuffer.pop(); } private void writeSuite(XmlSuite xmlSuite, ISuite suite) { switch (config.getFileFragmentationLevel()) { case XMLReporterConfig.FF_LEVEL_NONE: writeSuiteToBuffer(rootBuffer, suite); break; case XMLReporterConfig.FF_LEVEL_SUITE: case XMLReporterConfig.FF_LEVEL_SUITE_RESULT: File suiteFile = referenceSuite(rootBuffer, suite); writeSuiteToFile(suiteFile, suite); break; default: throw new AssertionError("Unexpected value: " + config.getFileFragmentationLevel()); } } private void writeSuiteToFile(File suiteFile, ISuite suite) { XMLStringBuffer xmlBuffer = new XMLStringBuffer(); writeSuiteToBuffer(xmlBuffer, suite); File parentDir = suiteFile.getParentFile(); suiteFile.getParentFile().mkdirs(); if (parentDir.exists() || suiteFile.getParentFile().exists()) { Utils.writeFile(parentDir.getAbsolutePath(), FILE_NAME, xmlBuffer.toXML()); } } private File referenceSuite(XMLStringBuffer xmlBuffer, ISuite suite) { String relativePath = suite.getName() + File.separatorChar + FILE_NAME; File suiteFile = new File(config.getOutputDirectory(), relativePath); Properties attrs = new Properties(); attrs.setProperty(XMLReporterConfig.ATTR_URL, relativePath); xmlBuffer.addEmptyElement(XMLReporterConfig.TAG_SUITE, attrs); return suiteFile; } private void writeSuiteToBuffer(XMLStringBuffer xmlBuffer, ISuite suite) { xmlBuffer.push(XMLReporterConfig.TAG_SUITE, getSuiteAttributes(suite)); writeSuiteGroups(xmlBuffer, suite); Map results = suite.getResults(); XMLSuiteResultWriter suiteResultWriter = new XMLSuiteResultWriter(config); for (Map.Entry result : results.entrySet()) { suiteResultWriter.writeSuiteResult(xmlBuffer, result.getValue()); } xmlBuffer.pop(); } private void writeSuiteGroups(XMLStringBuffer xmlBuffer, ISuite suite) { xmlBuffer.push(XMLReporterConfig.TAG_GROUPS); Map> methodsByGroups = suite.getMethodsByGroups(); for (Map.Entry> entry : methodsByGroups.entrySet()) { Properties groupAttrs = new Properties(); groupAttrs.setProperty(XMLReporterConfig.ATTR_NAME, entry.getKey()); xmlBuffer.push(XMLReporterConfig.TAG_GROUP, groupAttrs); Set groupMethods = getUniqueMethodSet(entry.getValue()); for (ITestNGMethod groupMethod : groupMethods) { Properties methodAttrs = new Properties(); methodAttrs.setProperty(XMLReporterConfig.ATTR_NAME, groupMethod.getMethodName()); methodAttrs.setProperty(XMLReporterConfig.ATTR_METHOD_SIG, groupMethod.toString()); methodAttrs.setProperty(XMLReporterConfig.ATTR_CLASS, groupMethod.getRealClass().getName()); xmlBuffer.addEmptyElement(XMLReporterConfig.TAG_METHOD, methodAttrs); } xmlBuffer.pop(); } xmlBuffer.pop(); } private Properties getSuiteAttributes(ISuite suite) { Properties props = new Properties(); props.setProperty(XMLReporterConfig.ATTR_NAME, suite.getName()); // Calculate the duration Map results = suite.getResults(); Date minStartDate = new Date(); Date maxEndDate = null; // TODO: We could probably optimize this in order not to traverse this twice synchronized(results) { for (Map.Entry result : results.entrySet()) { ITestContext testContext = result.getValue().getTestContext(); Date startDate = testContext.getStartDate(); Date endDate = testContext.getEndDate(); if (minStartDate.after(startDate)) { minStartDate = startDate; } if (maxEndDate == null || maxEndDate.before(endDate)) { maxEndDate = endDate != null ? endDate : startDate; } } } // The suite could be completely empty if (maxEndDate == null) { maxEndDate = minStartDate; } addDurationAttributes(config, props, minStartDate, maxEndDate); return props; } /** * Add started-at, finished-at and duration-ms attributes to the tag */ public static void addDurationAttributes(XMLReporterConfig config, Properties attributes, Date minStartDate, Date maxEndDate) { SimpleDateFormat format = new SimpleDateFormat(config.getTimestampFormat()); TimeZone utc = TimeZone.getTimeZone("UTC"); format.setTimeZone(utc); String startTime = format.format(minStartDate); String endTime = format.format(maxEndDate); long duration = maxEndDate.getTime() - minStartDate.getTime(); attributes.setProperty(XMLReporterConfig.ATTR_STARTED_AT, startTime); attributes.setProperty(XMLReporterConfig.ATTR_FINISHED_AT, endTime); attributes.setProperty(XMLReporterConfig.ATTR_DURATION_MS, Long.toString(duration)); } private Set getUniqueMethodSet(Collection methods) { Set result = new LinkedHashSet<>(); for (ITestNGMethod method : methods) { result.add(method); } return result; } // TODO: This is not the smartest way to implement the config public int getFileFragmentationLevel() { return config.getFileFragmentationLevel(); } public void setFileFragmentationLevel(int fileFragmentationLevel) { config.setFileFragmentationLevel(fileFragmentationLevel); } public int getStackTraceOutputMethod() { return config.getStackTraceOutputMethod(); } public void setStackTraceOutputMethod(int stackTraceOutputMethod) { config.setStackTraceOutputMethod(stackTraceOutputMethod); } public String getOutputDirectory() { return config.getOutputDirectory(); } public void setOutputDirectory(String outputDirectory) { config.setOutputDirectory(outputDirectory); } public boolean isGenerateGroupsAttribute() { return config.isGenerateGroupsAttribute(); } public void setGenerateGroupsAttribute(boolean generateGroupsAttribute) { config.setGenerateGroupsAttribute(generateGroupsAttribute); } public boolean isSplitClassAndPackageNames() { return config.isSplitClassAndPackageNames(); } public void setSplitClassAndPackageNames(boolean splitClassAndPackageNames) { config.setSplitClassAndPackageNames(splitClassAndPackageNames); } public String getTimestampFormat() { return config.getTimestampFormat(); } public void setTimestampFormat(String timestampFormat) { config.setTimestampFormat(timestampFormat); } public boolean isGenerateDependsOnMethods() { return config.isGenerateDependsOnMethods(); } public void setGenerateDependsOnMethods(boolean generateDependsOnMethods) { config.setGenerateDependsOnMethods(generateDependsOnMethods); } public void setGenerateDependsOnGroups(boolean generateDependsOnGroups) { config.setGenerateDependsOnGroups(generateDependsOnGroups); } public boolean isGenerateDependsOnGroups() { return config.isGenerateDependsOnGroups(); } public void setGenerateTestResultAttributes(boolean generateTestResultAttributes) { config.setGenerateTestResultAttributes(generateTestResultAttributes); } public boolean isGenerateTestResultAttributes() { return config.isGenerateTestResultAttributes(); } } testng-6.9.12/src/main/java/org/testng/reporters/HtmlHelper.java0000755000175000017500000000166412732165123024116 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.internal.Utils; import java.io.File; import java.io.IOException; public class HtmlHelper { private static final String CSS_FILE_NAME = "testng.css"; private static final String MY_CSS_FILE_NAME = "my-testng.css"; static public String getCssString() { return getCssString(".."); } static public String getCssString(String directory) { return "\n" + "\n"; } public static File generateStylesheet(String outputDirectory) throws IOException { File stylesheetFile = new File(outputDirectory, CSS_FILE_NAME); if (!stylesheetFile.exists()) { Utils.writeResourceToFile(stylesheetFile, CSS_FILE_NAME, TestHTMLReporter.class); } return stylesheetFile; } } testng-6.9.12/src/main/java/org/testng/reporters/jq/0000755000175000017500000000000012732165123021607 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/reporters/jq/IPanel.java0000644000175000017500000000022212732165123023616 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.reporters.XMLStringBuffer; public interface IPanel { void generate(XMLStringBuffer xsb); } testng-6.9.12/src/main/java/org/testng/reporters/jq/BaseMultiSuitePanel.java0000644000175000017500000000174712732165123026342 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.reporters.XMLStringBuffer; abstract public class BaseMultiSuitePanel extends BasePanel implements INavigatorPanel { abstract String getHeader(ISuite suite); abstract String getContent(ISuite suite, XMLStringBuffer xsb); public BaseMultiSuitePanel(Model model) { super(model); } @Override public void generate(XMLStringBuffer xsb) { for (ISuite s : getSuites()) { xsb.push(D, C, "panel", "panel-name", getPanelName(s)); xsb.push(D, C, "main-panel-header rounded-window-top"); xsb.addOptional(S, getHeader(s), C, "header-content"); xsb.pop(D); xsb.push(D, C, "main-panel-content rounded-window-bottom"); xsb.addString(getContent(s, xsb)); xsb.pop(D); xsb.pop(D); } } @Override public String getClassName() { return null; } @Override public String getPanelName(ISuite suite) { return getPrefix() + suiteToTag(suite); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/TimesPanel.java0000644000175000017500000000726112732165123024521 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.collections.Maps; import org.testng.reporters.XMLStringBuffer; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; public class TimesPanel extends BaseMultiSuitePanel { private Map m_totalTime = Maps.newHashMap(); public TimesPanel(Model model) { super(model); } @Override public String getPrefix() { return "times-"; } @Override public String getHeader(ISuite suite) { return "Times for " + suite.getName(); } private String js(ISuite suite) { String functionName = "tableData_" + suiteToTag(suite); StringBuilder result = new StringBuilder( "suiteTableInitFunctions.push('" + functionName + "');\n" + "function " + functionName + "() {\n" + "var data = new google.visualization.DataTable();\n" + "data.addColumn('number', 'Number');\n" + "data.addColumn('string', 'Method');\n" + "data.addColumn('string', 'Class');\n" + "data.addColumn('number', 'Time (ms)');\n"); List allTestResults = getModel().getAllTestResults(suite); result.append( "data.addRows(" + allTestResults.size() + ");\n"); Collections.sort(allTestResults, new Comparator() { @Override public int compare(ITestResult o1, ITestResult o2) { long t1 = o1.getEndMillis() - o1.getStartMillis(); long t2 = o2.getEndMillis() - o2.getStartMillis(); return (int) (t2 - t1); } }); int index = 0; for (ITestResult tr : allTestResults) { ITestNGMethod m = tr.getMethod(); long time = tr.getEndMillis() - tr.getStartMillis(); result .append("data.setCell(" + index + ", " + "0, " + index + ")\n") .append("data.setCell(" + index + ", " + "1, '" + m.getMethodName() + "')\n") .append("data.setCell(" + index + ", " + "2, '" + m.getTestClass().getName() + "')\n") .append("data.setCell(" + index + ", " + "3, " + time + ");\n"); Long total = m_totalTime.get(suite.getName()); if (total == null) { total = 0L; } m_totalTime.put(suite.getName(), total + time); index++; } result.append( "window.suiteTableData['" + suiteToTag(suite) + "']" + "= { tableData: data, tableDiv: 'times-div-" + suiteToTag(suite) + "'}\n" + "return data;\n" + "}\n"); return result.toString(); } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); xsb.push(D, C, "times-div"); xsb.push("script", "type", "text/javascript"); xsb.addString(js(suite)); xsb.pop("script"); Long time = m_totalTime.get(suite.getName()); if (time != null) { xsb.addRequired(S, String.format("Total running time: %s", prettyDuration(time)), C, "suite-total-time"); } xsb.push(D, "id", "times-div-" + suiteToTag(suite)); xsb.pop(D); xsb.pop(D); return xsb.toXML(); } private String prettyDuration(long totalTime) { String result; if (totalTime < 1000) { result = totalTime + " ms"; } else if (totalTime < 1000 * 60) { result = (totalTime / 1000) + " seconds"; } else if (totalTime < 1000 * 60 * 60) { result = (totalTime / 1000 / 60) + " minutes"; } else { result = (totalTime / 1000 / 60 / 60) + " hours"; } return result; } @Override public String getNavigatorLink(ISuite suite) { return "Times"; } } testng-6.9.12/src/main/java/org/testng/reporters/jq/GroupPanel.java0000644000175000017500000000250112732165123024524 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.reporters.XMLStringBuffer; import java.util.Collections; import java.util.List; public class GroupPanel extends BaseMultiSuitePanel { public GroupPanel(Model model) { super(model); } @Override public String getPrefix() { return "group-"; } @Override public String getHeader(ISuite suite) { return "Groups for " + suite.getName(); } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); List sortedGroups = getModel().getGroups(suite.getName()); Collections.sort(sortedGroups); for (String group : sortedGroups) { xsb.push(D, C, "test-group"); xsb.addRequired(S, group, C, "test-group-name"); xsb.addEmptyElement("br"); List sortedMethods = getModel().getMethodsInGroup(group); for (String method : sortedMethods) { xsb.push(D, C, "method-in-group"); xsb.addRequired(S, method, C, "method-in-group-name"); xsb.addEmptyElement("br"); xsb.pop(D); } xsb.pop(D); } return xsb.toXML(); } @Override public String getNavigatorLink(ISuite suite) { return pluralize(getModel().getGroups(suite.getName()).size(), "group"); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/ResultsByClass.java0000644000175000017500000000200012732165123025364 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ITestResult; import org.testng.collections.ListMultiMap; import org.testng.collections.Maps; import java.util.Collections; import java.util.Comparator; import java.util.List; public class ResultsByClass { public static final Comparator METHOD_NAME_COMPARATOR = new Comparator() { @Override public int compare(ITestResult arg0, ITestResult arg1) { return arg0.getMethod().getMethodName().compareTo( arg1.getMethod().getMethodName()); } }; private ListMultiMap, ITestResult> m_results = Maps.newListMultiMap(); public void addResult(Class c, ITestResult tr) { m_results.put(c, tr); } public List getResults(Class c) { List result = m_results.get(c); Collections.sort(result, METHOD_NAME_COMPARATOR); return result; } public List> getClasses() { // TODO do not use deprecated method return m_results.getKeys(); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/TestNgXmlPanel.java0000644000175000017500000000167712732165123025332 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.internal.Utils; import org.testng.reporters.XMLStringBuffer; public class TestNgXmlPanel extends BaseMultiSuitePanel { public TestNgXmlPanel(Model model) { super(model); } @Override public String getPrefix() { return "test-xml-"; } @Override public String getHeader(ISuite suite) { return suite.getXmlSuite().getFileName(); } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); xsb.push("pre"); xsb.addString(Utils.escapeHtml(suite.getXmlSuite().toXml())); xsb.pop("pre"); return xsb.toXML(); } @Override public String getNavigatorLink(ISuite suite) { String fqName = suite.getXmlSuite().getFileName(); if (fqName == null) fqName = "/[unset file name]"; return fqName.substring(fqName.lastIndexOf("/") + 1); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/ReporterPanel.java0000644000175000017500000000246212732165123025240 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.reporters.XMLStringBuffer; import java.util.List; /** * Display the reporter output for each test result. */ public class ReporterPanel extends BaseMultiSuitePanel { public ReporterPanel(Model model) { super(model); } @Override public String getPrefix() { return "reporter-"; } @Override public String getHeader(ISuite suite) { return "Reporter output for " + suite.getName(); } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); for (ITestResult tr : getModel().getAllTestResults(suite)) { List lines = Reporter.getOutput(tr); if (! lines.isEmpty()) { xsb.push(D, C, "reporter-method-div"); xsb.addRequired(S, Model.getTestResultName(tr), C, "reporter-method-name"); xsb.push(D, C, "reporter-method-output-div"); for (String output : lines) { xsb.addRequired(S, output, C, "reporter-method-output"); } xsb.pop(D); xsb.pop(D); } } return xsb.toXML(); } @Override public String getNavigatorLink(ISuite suite) { return "Reporter output"; } } testng-6.9.12/src/main/java/org/testng/reporters/jq/NavigatorPanel.java0000644000175000017500000001672312732165123025375 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.collections.Lists; import org.testng.reporters.XMLStringBuffer; import java.util.Collections; import java.util.List; import java.util.Map; public class NavigatorPanel extends BasePanel { private List m_panels; public NavigatorPanel(Model model, List panels) { super(model); m_panels = panels; } @Override public void generate(XMLStringBuffer main) { main.push(D, C, "navigator-root"); main.push(D, C, "navigator-suite-header"); main.addRequired(S, "All suites"); main.push("a", C, "collapse-all-link", "href", "#", "title", "Collapse/expand all the suites"); main.push("img", "src", "collapseall.gif", C, "collapse-all-icon"); main.pop("img"); main.pop("a"); main.pop(D); for (ISuite suite : getSuites()) { if (suite.getResults().size() == 0) { continue; } String suiteName = "suite-" + suiteToTag(suite); XMLStringBuffer header = new XMLStringBuffer(main.getCurrentIndent()); Map results = suite.getResults(); int failed = 0; int skipped = 0; int passed = 0; for (ISuiteResult result : results.values()) { ITestContext context = result.getTestContext(); failed += context.getFailedTests().size(); skipped += context.getSkippedTests().size(); passed += context.getPassedTests().size(); } // Suite name in big font header.push(D, C, "suite"); header.push(D, C, "rounded-window"); // Extra div so the highlighting logic will only highlight this line and not // the entire container header.push(D, C, "suite-header light-rounded-window-top"); header.push("a", "href", "#", "panel-name", suiteName, C, "navigator-link"); header.addOptional(S, suite.getName(), C, "suite-name border-" + getModel().getStatusForSuite(suite.getName())); header.pop("a"); header.pop(D); header.push(D, C, "navigator-suite-content"); generateInfo(header, suite); generateResult(header, failed, skipped, passed, suite, suiteName); header.pop("ul"); header.pop(D); // suite-section-content header.pop(D); // suite-header header.pop(D); // suite header.pop(D); // result-section header.pop(D); // navigator-suite-content main.addString(header.toXML()); } main.pop(D); } private void generateResult(XMLStringBuffer header, int failed, int skipped, int passed, ISuite suite, String suiteName) { // // Results // header.push(D, C, "result-section"); header.push(D, C, "suite-section-title"); header.addRequired(S, "Results"); header.pop(D); // Method stats int total = failed + skipped + passed; String stats = String.format("%s, %s %s %s", pluralize(total, "method"), maybe(failed, "failed", ", "), maybe(skipped, "skipped", ", "), maybe(passed, "passed", "")); header.push(D, C, "suite-section-content"); header.push("ul"); header.push("li"); header.addOptional(S, stats, C, "method-stats"); header.pop("li"); generateMethodList("Failed methods", new ResultsByStatus(suite, "failed", ITestResult.FAILURE), suiteName, header); generateMethodList("Skipped methods", new ResultsByStatus(suite, "skipped", ITestResult.SKIP), suiteName, header); generateMethodList("Passed methods", new ResultsByStatus(suite, "passed", ITestResult.SUCCESS), suiteName, header); } private void generateInfo(XMLStringBuffer header, ISuite suite) { // // Info // header.push(D, C, "suite-section-title"); header.addRequired(S, "Info"); header.pop(D); header.push(D, C, "suite-section-content"); header.push("ul"); // All the panels for (INavigatorPanel panel : m_panels) { addLinkTo(header, panel, suite); } header.pop("ul"); header.pop(D); // suite-section-content } private void addLinkTo(XMLStringBuffer header, INavigatorPanel panel, ISuite suite) { String text = panel.getNavigatorLink(suite); header.push("li"); header.push("a", "href", "#", "panel-name", panel.getPanelName(suite), C, "navigator-link "); String className = panel.getClassName(); if (className != null) { header.addOptional(S, text, C, className); } else { header.addOptional(S, text); } header.pop("a"); header.pop("li"); } private static String maybe(int count, String s, String sep) { return count > 0 ? count + " " + s + sep: ""; } private List getMethodsByStatus(ISuite suite, int status) { List result = Lists.newArrayList(); List testResults = getModel().getTestResults(suite); for (ITestResult tr : testResults) { if (tr.getStatus() == status) { result.add(tr); } } Collections.sort(result, ResultsByClass.METHOD_NAME_COMPARATOR); return result; } private static interface IResultProvider { List getResults(); String getType(); } private abstract static class BaseResultProvider implements IResultProvider { protected ISuite m_suite; protected String m_type; public BaseResultProvider(ISuite suite, String type) { m_suite = suite; m_type = type; } @Override public String getType() { return m_type; } } private class ResultsByStatus extends BaseResultProvider { private final int m_status; public ResultsByStatus(ISuite suite, String type, int status) { super(suite, type); m_status = status; } @Override public List getResults() { return getMethodsByStatus(m_suite, m_status); } } private void generateMethodList(String name, IResultProvider provider, String suiteName, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); String type = provider.getType(); String image = Model.getImage(type); xsb.push("li"); // The methods themselves xsb.addRequired(S, name, C, "method-list-title " + type); // The mark up to show the (hide)/(show) links xsb.push(S, C, "show-or-hide-methods " + type); xsb.addRequired("a", " (hide)", "href", "#", C, "hide-methods " + type + " " + suiteName, "panel-name", suiteName); xsb.addRequired("a", " (show)", "href", "#",C, "show-methods " + type + " " + suiteName, "panel-name", suiteName); xsb.pop(S); // List of methods xsb.push(D, C, "method-list-content " + type + " " + suiteName); int count = 0; List testResults = provider.getResults(); if (testResults != null) { Collections.sort(testResults, ResultsByClass.METHOD_NAME_COMPARATOR); for (ITestResult tr : testResults) { String testName = Model.getTestResultName(tr); xsb.push(S); xsb.addEmptyElement("img", "src", image, "width", "3%"); xsb.addRequired("a", testName, "href", "#", "hash-for-method", getModel().getTag(tr), "panel-name", suiteName, "title", tr.getTestClass().getName(), C, "method navigator-link"); xsb.pop(S); xsb.addEmptyElement("br"); count++; } } xsb.pop(D); xsb.pop("li"); if (count > 0) { main.addString(xsb.toXML()); } } } testng-6.9.12/src/main/java/org/testng/reporters/jq/INavigatorPanel.java0000644000175000017500000000045012732165123025474 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; /** * Panels that are accessible from the navigator. */ public interface INavigatorPanel extends IPanel { String getPanelName(ISuite suite); String getNavigatorLink(ISuite suite); String getClassName(); String getPrefix(); } testng-6.9.12/src/main/java/org/testng/reporters/jq/ChronologicalPanel.java0000644000175000017500000000637212732165123026225 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.IInvokedMethod; import org.testng.ISuite; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.reporters.XMLStringBuffer; import java.util.Collections; import java.util.Comparator; import java.util.List; public class ChronologicalPanel extends BaseMultiSuitePanel { public ChronologicalPanel(Model model) { super(model); } @Override public String getPrefix() { return "chronological-"; } @Override public String getHeader(ISuite suite) { return "Methods in chronological order"; } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); List invokedMethods = suite.getAllInvokedMethods(); Collections.sort(invokedMethods, new Comparator() { @Override public int compare(IInvokedMethod arg0, IInvokedMethod arg1) { return (int) (arg0.getTestResult().getStartMillis() - arg1.getTestResult().getStartMillis()); } }); String currentClass = ""; long start = 0; synchronized(invokedMethods) { for (IInvokedMethod im : invokedMethods) { ITestNGMethod m = im.getTestMethod(); // for (ITestResult tr : results) { // ITestNGMethod m = tr.getMethod(); String cls = "test-method"; if (m.isBeforeSuiteConfiguration()) { cls = "configuration-suite before"; } else if (m.isAfterSuiteConfiguration()) { cls = "configuration-suite after"; } else if (m.isBeforeTestConfiguration()) { cls = "configuration-test before"; } else if (m.isAfterTestConfiguration()) { cls = "configuration-test after"; } else if (m.isBeforeClassConfiguration()) { cls = "configuration-class before"; } else if (m.isAfterClassConfiguration()) { cls = "configuration-class after"; } else if (m.isBeforeMethodConfiguration()) { cls = "configuration-method before"; } else if (m.isAfterMethodConfiguration()) { cls = "configuration-method after"; } ITestResult tr = im.getTestResult(); String methodName = Model.getTestResultName(tr); if (!m.getTestClass().getName().equals(currentClass)) { if (!"".equals(currentClass)) { xsb.pop(D); } xsb.push(D, C, "chronological-class"); xsb.addRequired(D, m.getTestClass().getName(), C, "chronological-class-name"); currentClass = m.getTestClass().getName(); } xsb.push(D, C, cls); if (tr.getStatus() == ITestResult.FAILURE) { xsb.push("img", "src", Model.getImage("failed")); xsb.pop("img"); } // No need to check for skipped methods since by definition, they were never // invoked. xsb.addRequired(S, methodName, C, "method-name"); if (start == 0) { start = tr.getStartMillis(); } xsb.addRequired(S, Long.toString(tr.getStartMillis() - start) + " ms", C, "method-start"); xsb.pop(D); } } return xsb.toXML(); } @Override public String getNavigatorLink(ISuite suite) { return "Chronological view"; } } testng-6.9.12/src/main/java/org/testng/reporters/jq/IgnoredMethodsPanel.java0000644000175000017500000000262612732165123026353 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.ITestNGMethod; import org.testng.collections.Maps; import org.testng.collections.SetMultiMap; import org.testng.reporters.XMLStringBuffer; public class IgnoredMethodsPanel extends BaseMultiSuitePanel { public IgnoredMethodsPanel(Model model) { super(model); } @Override public String getPrefix() { return "ignored-methods-"; } @Override public String getHeader(ISuite suite) { return pluralize(suite.getExcludedMethods().size(), "ignored method"); } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); SetMultiMap, ITestNGMethod> map = Maps.newSetMultiMap(); for (ITestNGMethod method : suite.getExcludedMethods()) { map.put(method.getTestClass().getRealClass(), method); } for (Class c : map.keySet()) { xsb.push(D, C, "ignored-class-div"); xsb.addRequired(S, c.getName(), C, "ignored-class-name"); xsb.push(D, C, "ignored-methods-div"); for (ITestNGMethod m : map.get(c)) { xsb.addRequired(S, m.getMethodName(), C, "ignored-method-name"); xsb.addEmptyElement("br"); } xsb.pop(D); xsb.pop(D); } return xsb.toXML(); } @Override public String getNavigatorLink(ISuite suite) { return "Ignored methods"; } } testng-6.9.12/src/main/java/org/testng/reporters/jq/TestPanel.java0000644000175000017500000000222712732165123024354 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.reporters.XMLStringBuffer; import org.testng.xml.XmlTest; /** * Display the list of tags. */ public class TestPanel extends BaseMultiSuitePanel { public TestPanel(Model model) { super(model); } @Override public String getPrefix() { return "testlist-"; } @Override public String getHeader(ISuite suite) { return "Tests for " + suite.getName(); } @Override public String getContent(ISuite suite, XMLStringBuffer main) { XMLStringBuffer xsb = new XMLStringBuffer(main.getCurrentIndent()); xsb.push("ul"); for (XmlTest test : suite.getXmlSuite().getTests()) { xsb.push("li"); int count = test.getXmlClasses().size(); String name = test.getName() + " (" + pluralize(count, "class") + ")"; xsb.addRequired(S, name, C, "test-name"); xsb.pop("li"); } xsb.pop("ul"); return xsb.toXML(); } @Override public String getNavigatorLink(ISuite suite) { return pluralize(suite.getXmlSuite().getTests().size(), "test"); } @Override public String getClassName() { return "test-stats"; } } testng-6.9.12/src/main/java/org/testng/reporters/jq/Main.java0000644000175000017500000000542012732165123023337 0ustar eugeneeugenepackage org.testng.reporters.jq; import static org.testng.reporters.jq.BasePanel.C; import static org.testng.reporters.jq.BasePanel.D; import org.testng.IReporter; import org.testng.ISuite; import org.testng.internal.Utils; import org.testng.reporters.Files; import org.testng.reporters.XMLStringBuffer; import org.testng.xml.XmlSuite; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; public class Main implements IReporter { private static final String[] RESOURCES = new String[] { "jquery-1.7.1.min.js", "testng-reports.css", "testng-reports.js", "passed.png", "failed.png", "skipped.png", "navigator-bullet.png", "bullet_point.png", "collapseall.gif" }; private Model m_model; private String m_outputDirectory; @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { m_model = new Model(suites); m_outputDirectory = outputDirectory; XMLStringBuffer xsb = new XMLStringBuffer(" "); // Generate the top banner new BannerPanel(m_model).generate(xsb); // All the panels selectable from the navigator List panels = Arrays.asList( new TestNgXmlPanel(m_model), new TestPanel(m_model), new GroupPanel(m_model), new TimesPanel(m_model), new ReporterPanel(m_model), new IgnoredMethodsPanel(m_model), new ChronologicalPanel(m_model)); // Generate the navigator on the left hand side new NavigatorPanel(m_model, panels).generate(xsb); xsb.push(D, C, "wrapper"); xsb.push(D, "class", "main-panel-root"); // // Generate the main suite panel // new SuitePanel(m_model).generate(xsb); // Generate all the navigator panels for (INavigatorPanel panel : panels) { panel.generate(xsb); } xsb.pop(D); // main-panel-root xsb.pop(D); // wrapper xsb.addString(" \n"); xsb.addString("\n"); String all; try { try (InputStream header = getClass().getResourceAsStream("/header")) { if (header == null) { throw new RuntimeException("Couldn't find resource header"); } for (String fileName : RESOURCES) { try (InputStream is = getClass().getResourceAsStream("/" + fileName)) { if (is == null) { throw new AssertionError("Couldn't find resource: " + fileName); } Files.copyFile(is, new File(m_outputDirectory, fileName)); } } all = Files.readFile(header); Utils.writeUtf8File(m_outputDirectory, "index.html", xsb, all); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } testng-6.9.12/src/main/java/org/testng/reporters/jq/BannerPanel.java0000644000175000017500000000131012732165123024632 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.reporters.XMLStringBuffer; public class BannerPanel extends BasePanel { public BannerPanel(Model model) { super(model); } @Override public void generate(XMLStringBuffer xsb) { xsb.push(D, C, "top-banner-root"); xsb.addRequired(S, "Test results", C, "top-banner-title-font"); xsb.addEmptyElement("br"); int failedCount = getModel().getAllFailedResults().size(); String testResult = failedCount > 0 ? ", " + pluralize(failedCount, "failed test") : ""; String subTitle = pluralize(getModel().getSuites().size(), "suite") + testResult; xsb.addRequired(S, subTitle, C, "top-banner-font-1"); xsb.pop(D); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/BasePanel.java0000644000175000017500000000146212732165123024307 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import java.util.List; abstract public class BasePanel implements IPanel { public static final String C = "class"; public static final String D = "div"; public static final String S = "span"; private Model m_model; public BasePanel(Model model) { m_model = model; } protected Model getModel() { return m_model; } protected List getSuites() { return getModel().getSuites(); } protected static String pluralize(int count, String singular) { return Integer.toString(count) + " " + (count == 0 || count > 1 ? (singular.endsWith("s") ? singular + "es" : singular + "s") : singular); } protected static String suiteToTag(ISuite suite) { return suite.getName().replace(" ", "_"); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/SuitePanel.java0000644000175000017500000000634612732165123024534 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.ISuite; import org.testng.ITestResult; import org.testng.internal.Utils; import org.testng.reporters.XMLStringBuffer; import org.testng.util.Strings; import java.util.List; public class SuitePanel extends BasePanel { private static final String PASSED = "passed"; private static final String SKIPPED = "skipped"; private static final String FAILED = "failed"; public SuitePanel(Model model) { super(model); } @Override public void generate(XMLStringBuffer xsb) { for (ISuite suite : getSuites()) { generateSuitePanel(suite, xsb); } } private void generateSuitePanel(ISuite suite, XMLStringBuffer xsb) { String divName = suiteToTag(suite); xsb.push(D, C, "panel " + divName, "panel-name", "suite-" + divName); String[] statuses = new String[] { FAILED, SKIPPED, PASSED }; ResultsByClass[] results = new ResultsByClass[] { getModel().getFailedResultsByClass(suite), getModel().getSkippedResultsByClass(suite), getModel().getPassedResultsByClass(suite), }; for (int i = 0; i < results.length; i++) { ResultsByClass byClass = results[i]; for (Class c : byClass.getClasses()) { generateClassPanel(c, byClass.getResults(c), xsb, statuses[i], suite); } } xsb.pop(D); } private void generateClassPanel(Class c, List results, XMLStringBuffer xsb, String status, ISuite suite) { xsb.push(D, C, "suite-" + suiteToTag(suite) + "-class-" + status); xsb.push(D, C, "main-panel-header rounded-window-top"); // Passed/failed icon xsb.addEmptyElement("img", "src", Model.getImage(status)); xsb.addOptional(S, c.getName(), C, "class-name"); xsb.pop(D); xsb.push(D, C, "main-panel-content rounded-window-bottom"); for (ITestResult tr : results) { generateMethod(tr, xsb); } xsb.pop(D); xsb.pop(D); } private void generateMethod(ITestResult tr, XMLStringBuffer xsb) { xsb.push(D, C, "method"); xsb.push(D, C, "method-content"); xsb.push("a", "name", Model.getTestResultName(tr)); xsb.pop("a"); xsb.addOptional(S, tr.getMethod().getMethodName(), C, "method-name"); // Parameters? if (tr.getParameters().length > 0) { StringBuilder sb = new StringBuilder(); boolean first = true; for (Object p : tr.getParameters()) { if (!first) sb.append(", "); first = false; sb.append(Utils.toString(p)); } xsb.addOptional(S, "(" + sb.toString() + ")", C, "parameters"); } // Exception? if (tr.getStatus() != ITestResult.SUCCESS && tr.getThrowable() != null) { StringBuilder stackTrace = new StringBuilder(); stackTrace.append(Utils.stackTrace(tr.getThrowable(), true)[0]); xsb.addOptional(D, stackTrace.toString() + "\n", C, "stack-trace"); } // Description? String description = tr.getMethod().getDescription(); if (! Strings.isNullOrEmpty(description)) { xsb.push("em"); xsb.addString("(" + description + ")"); xsb.pop("em"); } // long time = tr.getEndMillis() - tr.getStartMillis(); // xsb.addOptional(S, " " + Long.toString(time) + " ms", C, "method-time"); xsb.pop(D); xsb.pop(D); } } testng-6.9.12/src/main/java/org/testng/reporters/jq/Model.java0000644000175000017500000001620012732165123023511 0ustar eugeneeugenepackage org.testng.reporters.jq; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.collections.ListMultiMap; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.SetMultiMap; import org.testng.internal.Utils; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; public class Model { private ListMultiMap m_model = Maps.newListMultiMap(); private List m_suites = null; private Map m_testTags = Maps.newHashMap(); private Map m_testResultMap = Maps.newHashMap(); private Map m_failedResultsByClass = Maps.newHashMap(); private Map m_skippedResultsByClass = Maps.newHashMap(); private Map m_passedResultsByClass = Maps.newHashMap(); private List m_allFailedResults = Lists.newArrayList(); // Each suite is mapped to failed.png, skipped.png or nothing (which means passed.png) private Map m_statusBySuiteName = Maps.newHashMap(); private SetMultiMap m_groupsBySuiteName = Maps.newSetMultiMap(); private SetMultiMap m_methodsByGroup = Maps.newSetMultiMap(); public Model(List suites) { m_suites = suites; init(); } public List getSuites() { return m_suites; } private void init() { int testCounter = 0; for (ISuite suite : m_suites) { List passed = Lists.newArrayList(); List failed = Lists.newArrayList(); List skipped = Lists.newArrayList(); Map suiteResults = suite.getResults(); synchronized(suiteResults) { for (ISuiteResult sr : suiteResults.values()) { ITestContext context = sr.getTestContext(); m_testTags.put(context.getName(), "test-" + testCounter++); failed.addAll(context.getFailedTests().getAllResults()); skipped.addAll(context.getSkippedTests().getAllResults()); passed.addAll(context.getPassedTests().getAllResults()); IResultMap[] map = new IResultMap[] { context.getFailedTests(), context.getSkippedTests(), context.getPassedTests() }; for (IResultMap m : map) { for (ITestResult tr : m.getAllResults()) { m_testResultMap.put(tr, getTestResultName(tr)); } } } } // Process them in the order passed, skipped and failed, so that the failed // icon overrides all the others and the skipped icon overrides passed. // Passed { ResultsByClass rbc = new ResultsByClass(); for (ITestResult tr : passed) { rbc.addResult(tr.getTestClass().getRealClass(), tr); updateGroups(suite, tr); } m_passedResultsByClass.put(suite, rbc); } // Skipped { ResultsByClass rbc = new ResultsByClass(); for (ITestResult tr : skipped) { m_statusBySuiteName.put(suite.getName(), "skipped"); rbc.addResult(tr.getTestClass().getRealClass(), tr); updateGroups(suite, tr); } m_skippedResultsByClass.put(suite, rbc); } // Failed { ResultsByClass rbc = new ResultsByClass(); for (ITestResult tr : failed) { m_statusBySuiteName.put(suite.getName(), "failed"); rbc.addResult(tr.getTestClass().getRealClass(), tr); m_allFailedResults.add(tr); updateGroups(suite, tr); } m_failedResultsByClass.put(suite, rbc); } m_model.putAll(suite, failed); m_model.putAll(suite, skipped); m_model.putAll(suite, passed); } } private void updateGroups(ISuite suite, ITestResult tr) { String[] groups = tr.getMethod().getGroups(); m_groupsBySuiteName.putAll(suite.getName(), Arrays.asList(groups)); for (String group : groups) { m_methodsByGroup.put(group, tr.getMethod().getMethodName()); } } public ResultsByClass getFailedResultsByClass(ISuite suite) { return m_failedResultsByClass.get(suite); } public ResultsByClass getSkippedResultsByClass(ISuite suite) { return m_skippedResultsByClass.get(suite); } public ResultsByClass getPassedResultsByClass(ISuite suite) { return m_passedResultsByClass.get(suite); } public String getTag(ITestResult tr) { return m_testResultMap.get(tr); } public List getTestResults(ISuite suite) { return nonnullList(m_model.get(suite)); } public static String getTestResultName(ITestResult tr) { StringBuilder result = new StringBuilder(tr.getMethod().getMethodName()); Object[] parameters = tr.getParameters(); if (parameters.length > 0) { result.append("("); StringBuilder p = new StringBuilder(); for (int i = 0; i < parameters.length; i++) { if (i > 0) p.append(", "); p.append(Utils.toString(parameters[i])); } if (p.length() > 100) { String s = p.toString().substring(0, 100); s = s + "..."; result.append(s); } else { result.append(p.toString()); } result.append(")"); } return result.toString(); } public List getAllFailedResults() { return m_allFailedResults; } public static String getImage(String tagClass) { return tagClass + ".png"; } public String getStatusForSuite(String suiteName) { String result = m_statusBySuiteName.get(suiteName); return result != null ? result : "passed"; } public Set nonnullSet(Set l) { return l != null ? l : Collections.emptySet(); } public List nonnullList(List l) { return l != null ? l : Collections.emptyList(); } public List getGroups(String name) { List result = Lists.newArrayList(nonnullSet(m_groupsBySuiteName.get(name))); Collections.sort(result); return result; } public List getMethodsInGroup(String groupName) { List result = Lists.newArrayList(nonnullSet(m_methodsByGroup.get(groupName))); Collections.sort(result); return result; } public List getAllTestResults(ISuite suite) { return getAllTestResults(suite, true /* tests only */); } public List getAllTestResults(ISuite suite, boolean testsOnly) { List result = Lists.newArrayList(); for (ISuiteResult sr : suite.getResults().values()) { result.addAll(sr.getTestContext().getPassedTests().getAllResults()); result.addAll(sr.getTestContext().getFailedTests().getAllResults()); result.addAll(sr.getTestContext().getSkippedTests().getAllResults()); if (! testsOnly) { result.addAll(sr.getTestContext().getPassedConfigurations().getAllResults()); result.addAll(sr.getTestContext().getFailedConfigurations().getAllResults()); result.addAll(sr.getTestContext().getSkippedConfigurations().getAllResults()); } } return result; } } testng-6.9.12/src/main/java/org/testng/reporters/XMLReporterConfig.java0000755000175000017500000001773612732165123025372 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.ITestResult; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; /** * @author Hani Suleiman Date: Mar 27, 2007 Time: 9:16:28 AM */ public class XMLReporterConfig { public static final String TAG_TEST = "test"; public static final String TAG_TEST_METHOD = "test-method"; public static final String TAG_EXCEPTION = "exception"; public static final String TAG_MESSAGE = "message"; public static final String TAG_SHORT_STACKTRACE = "short-stacktrace"; public static final String TAG_FULL_STACKTRACE = "full-stacktrace"; public static final String TAG_TESTNG_RESULTS = "testng-results"; public static final String TAG_SUITE = "suite"; public static final String TAG_GROUPS = "groups"; public static final String TAG_GROUP = "group"; public static final String TAG_CLASS = "class"; public static final String TAG_METHOD = "method"; public static final String TAG_PARAMS = "params"; public static final String TAG_PARAM = "param"; public static final String TAG_PARAM_VALUE = "value"; public static final String TAG_REPORTER_OUTPUT = "reporter-output"; public static final String TAG_LINE = "line"; public static final String TAG_ATTRIBUTES = "attributes"; public static final String TAG_ATTRIBUTE = "attribute"; public static final String ATTR_URL = "url"; public static final String ATTR_NAME = "name"; public static final String ATTR_STATUS = "status"; public static final String ATTR_DESC = "description"; public static final String ATTR_METHOD_SIG = "signature"; public static final String ATTR_GROUPS = "groups"; public static final String ATTR_CLASS = "class"; public static final String ATTR_TEST_INSTANCE_NAME = "test-instance-name"; public static final String ATTR_INDEX = "index"; public static final String ATTR_IS_NULL = "is-null"; public static final String ATTR_PACKAGE = "package"; public static final String ATTR_STARTED_AT = "started-at"; public static final String ATTR_FINISHED_AT = "finished-at"; public static final String ATTR_DURATION_MS = "duration-ms"; public static final String ATTR_IS_CONFIG = "is-config"; public static final String ATTR_DEPENDS_ON_METHODS = "depends-on-methods"; public static final String ATTR_DEPENDS_ON_GROUPS = "depends-on-groups"; public static final String ATTR_DATA_PROVIDER = "data-provider"; public static final String TEST_PASSED = "PASS"; public static final String TEST_FAILED = "FAIL"; public static final String TEST_SKIPPED = "SKIP"; private static Map STATUSES = new HashMap() {{ put(TEST_PASSED, ITestResult.SUCCESS); put(TEST_FAILED, ITestResult.FAILURE); put(TEST_SKIPPED, ITestResult.SKIP); }}; public static Integer getStatus(String status) { return STATUSES.get(status); } /** * Indicates that no file fragmentation should be performed. This value * indicates the XML generator to write all the results in one big file. Not * recommended for large test suites. */ public static final int FF_LEVEL_NONE = 1; /** * Will cause the XML generator to create separate files for each of the * suites. A separate directory will be generated for each suite having the * name of the suite and containing a suite.xml file that will be * referenced in the main file with an url attribute */ public static final int FF_LEVEL_SUITE = 2; /** * It behaves like FF_LEVEL_SUITE, except that it will also * create a file for each ISuiteResult */ public static final int FF_LEVEL_SUITE_RESULT = 3; /** * No stacktrace will be written in the output file */ public static final int STACKTRACE_NONE = 0; /** * Write only a short version of the stacktrace */ public static final int STACKTRACE_SHORT = 1; /** * Write only the full version of the stacktrace */ public static final int STACKTRACE_FULL = 2; /** * Write both types of stacktrace */ public static final int STACKTRACE_BOTH = 3; // note: We're hardcoding the 'Z' because Java doesn't support all the // intricacies of ISO-8601. static final String FMT_DEFAULT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; /** * Indicates the way that the file fragmentation should be performed. Set this * property to one of the FF_LEVEL_* values for the desired output structure */ private int fileFragmentationLevel = FF_LEVEL_NONE; /** * Stack trace output method for the failed tests using one of the * STACKTRACE_* constants. */ private int stackTraceOutputMethod = STACKTRACE_FULL; /** * The root output directory where the XMLs will be written. This will default * for now to the default TestNG output directory */ private String outputDirectory; /** * Indicates whether the groups attribute should be generated for * a test-method element. Defaults to false due to the fact that * this might be considered redundant because of the group generation in the * suite file. */ private boolean generateGroupsAttribute = false; /** * When true it will generate the <class< element with a * name and a package attribute. Otherwise, the * fully qualified name will be used for the name attribute. */ private boolean splitClassAndPackageNames = false; /** * Indicates whether the depends-on-methods attribute should be * generated for a test-method element */ private boolean generateDependsOnMethods = true; /** * Indicates whether the depends-on-groups attribute should be * generated for a test-method element */ private boolean generateDependsOnGroups = true; /** * Indicates whether {@link ITestResult} attributes should be generated for * each test-method element */ private boolean generateTestResultAttributes = false; /** * The output format for timestamps */ private String timestampFormat = FMT_DEFAULT; public int getFileFragmentationLevel() { return fileFragmentationLevel; } public void setFileFragmentationLevel(int fileFragmentationLevel) { this.fileFragmentationLevel = fileFragmentationLevel; } public int getStackTraceOutputMethod() { return stackTraceOutputMethod; } public void setStackTraceOutputMethod(int stackTraceOutputMethod) { this.stackTraceOutputMethod = stackTraceOutputMethod; } public String getOutputDirectory() { return outputDirectory; } public void setOutputDirectory(String outputDirectory) { this.outputDirectory = outputDirectory; } public boolean isGenerateGroupsAttribute() { return generateGroupsAttribute; } public void setGenerateGroupsAttribute(boolean generateGroupsAttribute) { this.generateGroupsAttribute = generateGroupsAttribute; } public boolean isSplitClassAndPackageNames() { return splitClassAndPackageNames; } public void setSplitClassAndPackageNames(boolean splitClassAndPackageNames) { this.splitClassAndPackageNames = splitClassAndPackageNames; } public String getTimestampFormat() { return timestampFormat; } public void setTimestampFormat(String timestampFormat) { this.timestampFormat = timestampFormat; } public boolean isGenerateDependsOnMethods() { return generateDependsOnMethods; } public void setGenerateDependsOnMethods(boolean generateDependsOnMethods) { this.generateDependsOnMethods = generateDependsOnMethods; } public boolean isGenerateDependsOnGroups() { return generateDependsOnGroups; } public void setGenerateDependsOnGroups(boolean generateDependsOnGroups) { this.generateDependsOnGroups = generateDependsOnGroups; } public void setGenerateTestResultAttributes(boolean generateTestResultAttributes) { this.generateTestResultAttributes = generateTestResultAttributes; } public boolean isGenerateTestResultAttributes() { return generateTestResultAttributes; } } testng-6.9.12/src/main/java/org/testng/reporters/FailedReporter.java0000755000175000017500000002222312732165123024753 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.MethodHelper; import org.testng.internal.Utils; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * This reporter is responsible for creating testng-failed.xml * * @author Cedric Beust * @author Alexandru Popescu */ public class FailedReporter extends TestListenerAdapter implements IReporter { public static final String TESTNG_FAILED_XML = "testng-failed.xml"; private XmlSuite m_xmlSuite; public FailedReporter() { } public FailedReporter(XmlSuite xmlSuite) { m_xmlSuite = xmlSuite; } @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { for (ISuite suite : suites) { generateFailureSuite(suite.getXmlSuite(), suite, outputDirectory); } } protected void generateFailureSuite(XmlSuite xmlSuite, ISuite suite, String outputDir) { XmlSuite failedSuite = xmlSuite.shallowCopy(); failedSuite.setName("Failed suite [" + xmlSuite.getName() + "]"); m_xmlSuite= failedSuite; Map xmlTests= Maps.newHashMap(); for(XmlTest xmlT: xmlSuite.getTests()) { xmlTests.put(xmlT.getName(), xmlT); } Map results = suite.getResults(); synchronized(results) { for(Map.Entry entry : results.entrySet()) { ISuiteResult suiteResult = entry.getValue(); ITestContext testContext = suiteResult.getTestContext(); generateXmlTest(suite, xmlTests.get(testContext.getName()), testContext, testContext.getFailedTests().getAllResults(), testContext.getSkippedTests().getAllResults()); } } if(null != failedSuite.getTests() && failedSuite.getTests().size() > 0) { Utils.writeUtf8File(outputDir, TESTNG_FAILED_XML, failedSuite.toXml()); Utils.writeUtf8File(suite.getOutputDirectory(), TESTNG_FAILED_XML, failedSuite.toXml()); } } /** * Do not rely on this method. The class is used as IReporter. * * @see org.testng.TestListenerAdapter#onFinish(org.testng.ITestContext) * @deprecated this class is used now as IReporter */ @Deprecated @Override public void onFinish(ITestContext context) { // Delete the previous file // File f = new File(context.getOutputDirectory(), getFileName(context)); // f.delete(); // Calculate the methods we need to rerun : failed tests and // their dependents // List failedTests = getFailedTests(); // List skippedTests = getSkippedTests(); } private void generateXmlTest(ISuite suite, XmlTest xmlTest, ITestContext context, Collection failedTests, Collection skippedTests) { // Note: we can have skipped tests and no failed tests // if a method depends on nonexistent groups if (skippedTests.size() > 0 || failedTests.size() > 0) { Set methodsToReRun = Sets.newHashSet(); // Get the transitive closure of all the failed methods and the methods // they depend on Collection[] allTests = new Collection[] { failedTests, skippedTests }; for (Collection tests : allTests) { for (ITestResult failedTest : tests) { ITestNGMethod current = failedTest.getMethod(); if (current.isTest()) { methodsToReRun.add(current); ITestNGMethod method = failedTest.getMethod(); // Don't count configuration methods if (method.isTest()) { List methodsDependedUpon = MethodHelper.getMethodsDependedUpon(method, context.getAllTestMethods()); for (ITestNGMethod m : methodsDependedUpon) { if (m.isTest()) { methodsToReRun.add(m); } } } } } } // // Now we have all the right methods. Go through the list of // all the methods that were run and only pick those that are // in the methodToReRun map. Since the methods are already // sorted, we don't need to sort them again. // List result = Lists.newArrayList(); for (ITestNGMethod m : context.getAllTestMethods()) { if (methodsToReRun.contains(m)) { result.add(m); } } methodsToReRun.clear(); Collection invoked= suite.getInvokedMethods(); for(ITestNGMethod tm: invoked) { if(!tm.isTest()) { methodsToReRun.add(tm); } } result.addAll(methodsToReRun); createXmlTest(context, result, xmlTest); } } /** * Generate testng-failed.xml */ private void createXmlTest(ITestContext context, List methods, XmlTest srcXmlTest) { XmlTest xmlTest = new XmlTest(m_xmlSuite); xmlTest.setName(context.getName() + "(failed)"); xmlTest.setBeanShellExpression(srcXmlTest.getExpression()); xmlTest.setIncludedGroups(srcXmlTest.getIncludedGroups()); xmlTest.setExcludedGroups(srcXmlTest.getExcludedGroups()); xmlTest.setParallel(srcXmlTest.getParallel()); xmlTest.setParameters(srcXmlTest.getLocalParameters()); xmlTest.setJUnit(srcXmlTest.isJUnit()); List xmlClasses = createXmlClasses(methods, srcXmlTest); xmlTest.setXmlClasses(xmlClasses); } /** * @param methods The methods we want to represent * @param srcXmlTest * @return A list of XmlClass objects (each representing a tag) based * on the parameter methods */ private List createXmlClasses(List methods, XmlTest srcXmlTest) { List result = Lists.newArrayList(); Map> methodsMap= Maps.newHashMap(); for (ITestNGMethod m : methods) { Object[] instances= m.getInstances(); Class clazz= instances == null || instances.length == 0 || instances[0] == null ? m.getRealClass() : instances[0].getClass(); Set methodList= methodsMap.get(clazz); if(null == methodList) { methodList= new HashSet<>(); methodsMap.put(clazz, methodList); } methodList.add(m); } // Ideally, we should preserve each parameter in each class but putting them // all in the same bag for now Map parameters = Maps.newHashMap(); for (XmlClass c : srcXmlTest.getClasses()) { parameters.putAll(c.getLocalParameters()); } int index = 0; for(Map.Entry> entry: methodsMap.entrySet()) { Class clazz= entry.getKey(); Set methodList= entry.getValue(); // @author Borojevic // Need to check all the methods, not just @Test ones. XmlClass xmlClass= new XmlClass(clazz.getName(), index++, false /* don't load classes */); List methodNames= Lists.newArrayList(methodList.size()); int ind = 0; for(ITestNGMethod m: methodList) { XmlInclude methodName = new XmlInclude(m.getMethod().getName(), m.getFailedInvocationNumbers(), ind++); methodName.setParameters(findMethodLocalParameters(srcXmlTest, m)); methodNames.add(methodName); } xmlClass.setIncludedMethods(methodNames); xmlClass.setParameters(parameters); result.add(xmlClass); } return result; } /** * Get local parameters of one include method from origin test xml. * @param srcXmlTest * @param method the method we want to find its parameters * @return local parameters belong to one test method. */ private static Map findMethodLocalParameters(XmlTest srcXmlTest, ITestNGMethod method) { Class clazz = method.getRealClass(); for (XmlClass c : srcXmlTest.getClasses()) { if (clazz == c.getSupportClass()) { for (XmlInclude xmlInclude : c.getIncludedMethods()) { if (xmlInclude.getName().equals(method.getMethodName())) { return xmlInclude.getLocalParameters(); } } } } return Collections.emptyMap(); } /** * TODO: we might want to make that more flexible in the future, but for * now, hardcode the file name */ private String getFileName(ITestContext context) { return TESTNG_FAILED_XML; } private static void ppp(String s) { System.out.println("[FailedReporter] " + s); } } testng-6.9.12/src/main/java/org/testng/reporters/ExitCodeListener.java0000755000175000017500000000065612732165123025264 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.TestNG; /** * A very simple ITestListener used by the TestNG runner to * find out the exit code. * * @author Alexandru Popescu */ public class ExitCodeListener extends TestNG.ExitCodeListener { public ExitCodeListener() { super(); } public ExitCodeListener(TestNG runner) { super(runner); } } testng-6.9.12/src/main/java/org/testng/reporters/IBuffer.java0000644000175000017500000000022712732165123023363 0ustar eugeneeugenepackage org.testng.reporters; import java.io.Writer; public interface IBuffer { IBuffer append(CharSequence string); void toWriter(Writer fw); } testng-6.9.12/src/main/java/org/testng/reporters/Files.java0000644000175000017500000000405012732165123023101 0ustar eugeneeugenepackage org.testng.reporters; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.nio.charset.StandardCharsets; public class Files { public static String readFile(File f) throws IOException { try (InputStream is = new FileInputStream(f)) { return readFile(is); } } public static String readFile(InputStream is) throws IOException { StringBuilder result = new StringBuilder(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = br.readLine(); while (line != null) { result.append(line + "\n"); line = br.readLine(); } return result.toString(); } public static void writeFile(String string, File f) throws IOException { f.getParentFile().mkdirs(); try (FileWriter fw = new FileWriter(f); BufferedWriter bw = new BufferedWriter(fw)) { bw.write(string); } } public static void copyFile(InputStream from, File to) throws IOException { if (! to.getParentFile().exists()) { to.getParentFile().mkdirs(); } try (OutputStream os = new FileOutputStream(to)) { byte[] buffer = new byte[65536]; int count = from.read(buffer); while (count > 0) { os.write(buffer, 0, count); count = from.read(buffer); } } } public static String streamToString(InputStream is) throws IOException { if (is != null) { Writer writer = new StringWriter(); char[] buffer = new char[1024]; try (Reader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { int n; while ((n = reader.read(buffer)) != -1) { writer.write(buffer, 0, n); } } return writer.toString(); } else { return ""; } } } testng-6.9.12/src/main/java/org/testng/reporters/EmailableReporter2.java0000644000175000017500000007360612732165123025534 0ustar eugeneeugenepackage org.testng.reporters; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.NumberFormat; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.collections.Lists; import org.testng.internal.Utils; import org.testng.log4testng.Logger; import org.testng.xml.XmlSuite; /** * Reporter that generates a single-page HTML report of the test results. *

* Based on an earlier implementation by Paul Mendelson. *

* * @author Abraham Lin */ public class EmailableReporter2 implements IReporter { private static final Logger LOG = Logger.getLogger(EmailableReporter.class); protected PrintWriter writer; protected List suiteResults = Lists.newArrayList(); // Reusable buffer private StringBuilder buffer = new StringBuilder(); @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { try { writer = createWriter(outputDirectory); } catch (IOException e) { LOG.error("Unable to create output file", e); return; } for (ISuite suite : suites) { suiteResults.add(new SuiteResult(suite)); } writeDocumentStart(); writeHead(); writeBody(); writeDocumentEnd(); writer.close(); } protected PrintWriter createWriter(String outdir) throws IOException { new File(outdir).mkdirs(); return new PrintWriter(new BufferedWriter(new FileWriter(new File( outdir, "emailable-report.html")))); } protected void writeDocumentStart() { writer.println(""); writer.print(""); } protected void writeHead() { writer.print(""); writer.print("TestNG Report"); writeStylesheet(); writer.print(""); } protected void writeStylesheet() { writer.print(""); } protected void writeBody() { writer.print(""); writeSuiteSummary(); writeScenarioSummary(); writeScenarioDetails(); writer.print(""); } protected void writeDocumentEnd() { writer.print(""); } protected void writeSuiteSummary() { NumberFormat integerFormat = NumberFormat.getIntegerInstance(); NumberFormat decimalFormat = NumberFormat.getNumberInstance(); int totalPassedTests = 0; int totalSkippedTests = 0; int totalFailedTests = 0; long totalDuration = 0; writer.print("
" + label + "" + label + "
"); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); int testIndex = 0; for (SuiteResult suiteResult : suiteResults) { writer.print(""); for (TestResult testResult : suiteResult.getTestResults()) { int passedTests = testResult.getPassedTestCount(); int skippedTests = testResult.getSkippedTestCount(); int failedTests = testResult.getFailedTestCount(); long duration = testResult.getDuration(); writer.print(""); buffer.setLength(0); writeTableData(buffer.append("") .append(Utils.escapeHtml(testResult.getTestName())) .append("").toString()); writeTableData(integerFormat.format(passedTests), "num"); writeTableData(integerFormat.format(skippedTests), (skippedTests > 0 ? "num attn" : "num")); writeTableData(integerFormat.format(failedTests), (failedTests > 0 ? "num attn" : "num")); writeTableData(decimalFormat.format(duration), "num"); writeTableData(testResult.getIncludedGroups()); writeTableData(testResult.getExcludedGroups()); writer.print(""); totalPassedTests += passedTests; totalSkippedTests += skippedTests; totalFailedTests += failedTests; totalDuration += duration; testIndex++; } } // Print totals if there was more than one test if (testIndex > 1) { writer.print(""); writer.print(""); writeTableHeader(integerFormat.format(totalPassedTests), "num"); writeTableHeader(integerFormat.format(totalSkippedTests), (totalSkippedTests > 0 ? "num attn" : "num")); writeTableHeader(integerFormat.format(totalFailedTests), (totalFailedTests > 0 ? "num attn" : "num")); writeTableHeader(decimalFormat.format(totalDuration), "num"); writer.print(""); writer.print(""); } writer.print("
Test# Passed# Skipped# FailedTime (ms)Included GroupsExcluded Groups
"); writer.print(Utils.escapeHtml(suiteResult.getSuiteName())); writer.print("
Total
"); } /** * Writes a summary of all the test scenarios. */ protected void writeScenarioSummary() { writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); writer.print(""); int testIndex = 0; int scenarioIndex = 0; for (SuiteResult suiteResult : suiteResults) { writer.print(""); for (TestResult testResult : suiteResult.getTestResults()) { writer.print(""); String testName = Utils.escapeHtml(testResult.getTestName()); scenarioIndex += writeScenarioSummary(testName + " — failed (configuration methods)", testResult.getFailedConfigurationResults(), "failed", scenarioIndex); scenarioIndex += writeScenarioSummary(testName + " — failed", testResult.getFailedTestResults(), "failed", scenarioIndex); scenarioIndex += writeScenarioSummary(testName + " — skipped (configuration methods)", testResult.getSkippedConfigurationResults(), "skipped", scenarioIndex); scenarioIndex += writeScenarioSummary(testName + " — skipped", testResult.getSkippedTestResults(), "skipped", scenarioIndex); scenarioIndex += writeScenarioSummary(testName + " — passed", testResult.getPassedTestResults(), "passed", scenarioIndex); writer.print(""); testIndex++; } } writer.print("
ClassMethodStartTime (ms)
"); writer.print(Utils.escapeHtml(suiteResult.getSuiteName())); writer.print("
"); } /** * Writes the scenario summary for the results of a given state for a single * test. */ private int writeScenarioSummary(String description, List classResults, String cssClassPrefix, int startingScenarioIndex) { int scenarioCount = 0; if (!classResults.isEmpty()) { writer.print(""); writer.print(description); writer.print(""); int scenarioIndex = startingScenarioIndex; int classIndex = 0; for (ClassResult classResult : classResults) { String cssClass = cssClassPrefix + ((classIndex % 2) == 0 ? "even" : "odd"); buffer.setLength(0); int scenariosPerClass = 0; int methodIndex = 0; for (MethodResult methodResult : classResult.getMethodResults()) { List results = methodResult.getResults(); int resultsCount = results.size(); assert resultsCount > 0; ITestResult firstResult = results.iterator().next(); String methodName = Utils.escapeHtml(firstResult .getMethod().getMethodName()); long start = firstResult.getStartMillis(); long duration = firstResult.getEndMillis() - start; // The first method per class shares a row with the class // header if (methodIndex > 0) { buffer.append(""); } // Write the timing information with the first scenario per // method buffer.append("").append(methodName) .append("").append("").append(start) .append("").append("") .append(duration).append(""); scenarioIndex++; // Write the remaining scenarios for the method for (int i = 1; i < resultsCount; i++) { buffer.append("").append("") .append(methodName).append(""); scenarioIndex++; } scenariosPerClass += resultsCount; methodIndex++; } // Write the test results for the class writer.print(""); writer.print(""); writer.print(Utils.escapeHtml(classResult.getClassName())); writer.print(""); writer.print(buffer); classIndex++; } scenarioCount = scenarioIndex - startingScenarioIndex; } return scenarioCount; } /** * Writes the details for all test scenarios. */ protected void writeScenarioDetails() { int scenarioIndex = 0; for (SuiteResult suiteResult : suiteResults) { for (TestResult testResult : suiteResult.getTestResults()) { writer.print("

"); writer.print(Utils.escapeHtml(testResult.getTestName())); writer.print("

"); scenarioIndex += writeScenarioDetails( testResult.getFailedConfigurationResults(), scenarioIndex); scenarioIndex += writeScenarioDetails( testResult.getFailedTestResults(), scenarioIndex); scenarioIndex += writeScenarioDetails( testResult.getSkippedConfigurationResults(), scenarioIndex); scenarioIndex += writeScenarioDetails( testResult.getSkippedTestResults(), scenarioIndex); scenarioIndex += writeScenarioDetails( testResult.getPassedTestResults(), scenarioIndex); } } } /** * Writes the scenario details for the results of a given state for a single * test. */ private int writeScenarioDetails(List classResults, int startingScenarioIndex) { int scenarioIndex = startingScenarioIndex; for (ClassResult classResult : classResults) { String className = classResult.getClassName(); for (MethodResult methodResult : classResult.getMethodResults()) { List results = methodResult.getResults(); assert !results.isEmpty(); String label = Utils .escapeHtml(className + "#" + results.iterator().next().getMethod() .getMethodName()); for (ITestResult result : results) { writeScenario(scenarioIndex, label, result); scenarioIndex++; } } } return scenarioIndex - startingScenarioIndex; } /** * Writes the details for an individual test scenario. */ private void writeScenario(int scenarioIndex, String label, ITestResult result) { writer.print("

"); writer.print(label); writer.print("

"); writer.print(""); // Write test parameters (if any) Object[] parameters = result.getParameters(); int parameterCount = (parameters == null ? 0 : parameters.length); if (parameterCount > 0) { writer.print(""); for (int i = 1; i <= parameterCount; i++) { writer.print(""); } writer.print(""); for (Object parameter : parameters) { writer.print(""); } writer.print(""); } // Write reporter messages (if any) List reporterMessages = Reporter.getOutput(result); if (!reporterMessages.isEmpty()) { writer.print(" 1) { writer.print(" colspan=\""); writer.print(parameterCount); writer.print("\""); } writer.print(">Messages"); writer.print(" 1) { writer.print(" colspan=\""); writer.print(parameterCount); writer.print("\""); } writer.print(">"); writeReporterMessages(reporterMessages); writer.print(""); } // Write exception (if any) Throwable throwable = result.getThrowable(); if (throwable != null) { writer.print(" 1) { writer.print(" colspan=\""); writer.print(parameterCount); writer.print("\""); } writer.print(">"); writer.print((result.getStatus() == ITestResult.SUCCESS ? "Expected Exception" : "Exception")); writer.print(""); writer.print(" 1) { writer.print(" colspan=\""); writer.print(parameterCount); writer.print("\""); } writer.print(">"); writeStackTrace(throwable); writer.print(""); } writer.print("
Parameter #"); writer.print(i); writer.print("
"); writer.print(Utils.escapeHtml(Utils.toString(parameter))); writer.print("
"); writer.print("

back to summary

"); } protected void writeReporterMessages(List reporterMessages) { writer.print("
"); Iterator iterator = reporterMessages.iterator(); assert iterator.hasNext(); writer.print(Utils.escapeHtml(iterator.next())); while (iterator.hasNext()) { writer.print("
"); writer.print(Utils.escapeHtml(iterator.next())); } writer.print("
"); } protected void writeStackTrace(Throwable throwable) { writer.print("
"); writer.print(Utils.stackTrace(throwable, true)[0]); writer.print("
"); } /** * Writes a TH element with the specified contents and CSS class names. * * @param html * the HTML contents * @param cssClasses * the space-delimited CSS classes or null if there are no * classes to apply */ protected void writeTableHeader(String html, String cssClasses) { writeTag("th", html, cssClasses); } /** * Writes a TD element with the specified contents. * * @param html * the HTML contents */ protected void writeTableData(String html) { writeTableData(html, null); } /** * Writes a TD element with the specified contents and CSS class names. * * @param html * the HTML contents * @param cssClasses * the space-delimited CSS classes or null if there are no * classes to apply */ protected void writeTableData(String html, String cssClasses) { writeTag("td", html, cssClasses); } /** * Writes an arbitrary HTML element with the specified contents and CSS * class names. * * @param tag * the tag name * @param html * the HTML contents * @param cssClasses * the space-delimited CSS classes or null if there are no * classes to apply */ protected void writeTag(String tag, String html, String cssClasses) { writer.print("<"); writer.print(tag); if (cssClasses != null) { writer.print(" class=\""); writer.print(cssClasses); writer.print("\""); } writer.print(">"); writer.print(html); writer.print(""); } /** * Groups {@link TestResult}s by suite. */ protected static class SuiteResult { private final String suiteName; private final List testResults = Lists.newArrayList(); public SuiteResult(ISuite suite) { suiteName = suite.getName(); for (ISuiteResult suiteResult : suite.getResults().values()) { testResults.add(new TestResult(suiteResult.getTestContext())); } } public String getSuiteName() { return suiteName; } /** * @return the test results (possibly empty) */ public List getTestResults() { return testResults; } } /** * Groups {@link ClassResult}s by test, type (configuration or test), and * status. */ protected static class TestResult { /** * Orders test results by class name and then by method name (in * lexicographic order). */ protected static final Comparator RESULT_COMPARATOR = new Comparator() { @Override public int compare(ITestResult o1, ITestResult o2) { int result = o1.getTestClass().getName() .compareTo(o2.getTestClass().getName()); if (result == 0) { result = o1.getMethod().getMethodName() .compareTo(o2.getMethod().getMethodName()); } return result; } }; private final String testName; private final List failedConfigurationResults; private final List failedTestResults; private final List skippedConfigurationResults; private final List skippedTestResults; private final List passedTestResults; private final int failedTestCount; private final int skippedTestCount; private final int passedTestCount; private final long duration; private final String includedGroups; private final String excludedGroups; public TestResult(ITestContext context) { testName = context.getName(); Set failedConfigurations = context .getFailedConfigurations().getAllResults(); Set failedTests = context.getFailedTests() .getAllResults(); Set skippedConfigurations = context .getSkippedConfigurations().getAllResults(); Set skippedTests = context.getSkippedTests() .getAllResults(); Set passedTests = context.getPassedTests() .getAllResults(); failedConfigurationResults = groupResults(failedConfigurations); failedTestResults = groupResults(failedTests); skippedConfigurationResults = groupResults(skippedConfigurations); skippedTestResults = groupResults(skippedTests); passedTestResults = groupResults(passedTests); failedTestCount = failedTests.size(); skippedTestCount = skippedTests.size(); passedTestCount = passedTests.size(); duration = context.getEndDate().getTime() - context.getStartDate().getTime(); includedGroups = formatGroups(context.getIncludedGroups()); excludedGroups = formatGroups(context.getExcludedGroups()); } /** * Groups test results by method and then by class. */ protected List groupResults(Set results) { List classResults = Lists.newArrayList(); if (!results.isEmpty()) { List resultsPerClass = Lists.newArrayList(); List resultsPerMethod = Lists.newArrayList(); List resultsList = Lists.newArrayList(results); Collections.sort(resultsList, RESULT_COMPARATOR); Iterator resultsIterator = resultsList.iterator(); assert resultsIterator.hasNext(); ITestResult result = resultsIterator.next(); resultsPerMethod.add(result); String previousClassName = result.getTestClass().getName(); String previousMethodName = result.getMethod().getMethodName(); while (resultsIterator.hasNext()) { result = resultsIterator.next(); String className = result.getTestClass().getName(); if (!previousClassName.equals(className)) { // Different class implies different method assert !resultsPerMethod.isEmpty(); resultsPerClass.add(new MethodResult(resultsPerMethod)); resultsPerMethod = Lists.newArrayList(); assert !resultsPerClass.isEmpty(); classResults.add(new ClassResult(previousClassName, resultsPerClass)); resultsPerClass = Lists.newArrayList(); previousClassName = className; previousMethodName = result.getMethod().getMethodName(); } else { String methodName = result.getMethod().getMethodName(); if (!previousMethodName.equals(methodName)) { assert !resultsPerMethod.isEmpty(); resultsPerClass.add(new MethodResult(resultsPerMethod)); resultsPerMethod = Lists.newArrayList(); previousMethodName = methodName; } } resultsPerMethod.add(result); } assert !resultsPerMethod.isEmpty(); resultsPerClass.add(new MethodResult(resultsPerMethod)); assert !resultsPerClass.isEmpty(); classResults.add(new ClassResult(previousClassName, resultsPerClass)); } return classResults; } public String getTestName() { return testName; } /** * @return the results for failed configurations (possibly empty) */ public List getFailedConfigurationResults() { return failedConfigurationResults; } /** * @return the results for failed tests (possibly empty) */ public List getFailedTestResults() { return failedTestResults; } /** * @return the results for skipped configurations (possibly empty) */ public List getSkippedConfigurationResults() { return skippedConfigurationResults; } /** * @return the results for skipped tests (possibly empty) */ public List getSkippedTestResults() { return skippedTestResults; } /** * @return the results for passed tests (possibly empty) */ public List getPassedTestResults() { return passedTestResults; } public int getFailedTestCount() { return failedTestCount; } public int getSkippedTestCount() { return skippedTestCount; } public int getPassedTestCount() { return passedTestCount; } public long getDuration() { return duration; } public String getIncludedGroups() { return includedGroups; } public String getExcludedGroups() { return excludedGroups; } /** * Formats an array of groups for display. */ protected String formatGroups(String[] groups) { if (groups.length == 0) { return ""; } StringBuilder builder = new StringBuilder(); builder.append(groups[0]); for (int i = 1; i < groups.length; i++) { builder.append(", ").append(groups[i]); } return builder.toString(); } } /** * Groups {@link MethodResult}s by class. */ protected static class ClassResult { private final String className; private final List methodResults; /** * @param className * the class name * @param methodResults * the non-null, non-empty {@link MethodResult} list */ public ClassResult(String className, List methodResults) { this.className = className; this.methodResults = methodResults; } public String getClassName() { return className; } /** * @return the non-null, non-empty {@link MethodResult} list */ public List getMethodResults() { return methodResults; } } /** * Groups test results by method. */ protected static class MethodResult { private final List results; /** * @param results * the non-null, non-empty result list */ public MethodResult(List results) { this.results = results; } /** * @return the non-null, non-empty result list */ public List getResults() { return results; } } } testng-6.9.12/src/main/java/org/testng/reporters/FileStringBuffer.java0000644000175000017500000001115712732165123025245 0ustar eugeneeugenepackage org.testng.reporters; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.util.Random; /** * A string buffer that flushes its content to a temporary file whenever the internal * string buffer becomes larger than MAX. If the buffer never reaches that size, no file * is ever created and everything happens in memory, so the overhead compared to * StringBuffer/StringBuilder is minimal. * * Note: calling toString() will force the entire string to be loaded in memory, use * toWriter() if you need to avoid this. * * This class is not multi thread safe. * * @author Cedric Beust * * @since Nov 9, 2012 */ public class FileStringBuffer implements IBuffer { private static int MAX = 100000; private static final boolean VERBOSE = System.getProperty("fileStringBuffer") != null; private File m_file; private StringBuilder m_sb = new StringBuilder(); private final int m_maxCharacters; public FileStringBuffer() { this(MAX); } public FileStringBuffer(int maxCharacters) { m_maxCharacters = maxCharacters; } @Override public FileStringBuffer append(CharSequence s) { if (s == null) { throw new IllegalArgumentException("CharSequence (Argument 0 of FileStringBuffer#append) should not be null"); } // m_sb.append(s); if (m_sb.length() > m_maxCharacters) { flushToFile(); } if (s.length() < MAX) { // Small string, add it to our internal buffer m_sb.append(s); } else { // Big string, add it to the temporary file directly flushToFile(); try (FileWriter writer = new FileWriter(m_file, true /* append */)) { copy(new StringReader(s.toString()), writer); } catch (IOException e) { e.printStackTrace(); } } return this; } @Override public void toWriter(Writer fw) { if (fw == null) { throw new IllegalArgumentException("Writer (Argument 0 of FileStringBuffer#toWriter) should not be null"); } try { BufferedWriter bw = new BufferedWriter(fw); if (m_file == null) { bw.write(m_sb.toString()); bw.close(); } else { flushToFile(); try (FileReader reader = new FileReader(m_file)) { copy(reader, bw); } } } catch(IOException ex) { ex.printStackTrace(); } } private static void copy(Reader input, Writer output) throws IOException { char[] buf = new char[MAX]; while (true) { int length = input.read(buf); if (length < 0) break; output.write(buf, 0, length); } } private void flushToFile() { if (m_sb.length() == 0) return; if (m_file == null) { try { m_file = File.createTempFile("testng", "fileStringBuffer"); m_file.deleteOnExit(); p("Created temp file " + m_file); } catch (IOException e) { e.printStackTrace(); } } p("Size " + m_sb.length() + ", flushing to " + m_file); try (FileWriter fw = new FileWriter(m_file, true /* append */)) { fw.append(m_sb); } catch (IOException e) { e.printStackTrace(); } m_sb = new StringBuilder(); } private static void p(String s) { if (VERBOSE) { System.out.println("[FileStringBuffer] " + s); } } @Override public String toString() { String result = null; if (m_file != null) { flushToFile(); try { result = Files.readFile(m_file); } catch (IOException e) { e.printStackTrace(); } } else { result = m_sb.toString(); } return result; } public static void main(String[] args) throws IOException { String s = "abcdefghijklmnopqrstuvwxyz"; FileStringBuffer fsb = new FileStringBuffer(10); StringBuilder control = new StringBuilder(); Random r = new Random(); for (int i = 0; i < 1000; i++) { int start = Math.abs(r.nextInt() % 26); int length = Math.abs(r.nextInt() % (26 - start)); String fragment = s.substring(start, start + length); p("... Appending " + fragment); fsb.append(fragment); control.append(fragment); } File expected = new File("/tmp/expected"); expected.delete(); try (FileWriter expectedWriter = new FileWriter(expected)) { expectedWriter.append(control); } File actual = new File("/tmp/actual"); actual.delete(); try (FileWriter actualWriter = new FileWriter(actual)) { fsb.toWriter(actualWriter); } // Assert.assertEquals(fsb.toString(), control.toString()); } } testng-6.9.12/src/main/java/org/testng/reporters/XMLConstants.java0000755000175000017500000000340012732165123024375 0ustar eugeneeugenepackage org.testng.reporters; /** * interface groups the XML constants * tries to emulate what's in org.apache.tools.ant.taskdefs.optional.junit.XMLConstants * to be compatible with junitreport */ public interface XMLConstants { /** the testsuites element for the aggregate document */ String TESTSUITES = "testsuites"; /** the testsuite element */ String TESTSUITE = "testsuite"; /** the testcase element */ String TESTCASE = "testcase"; /** the error element */ String ERROR = "error"; /** the failure element */ String FAILURE = "failure"; /** the system-err element */ String SYSTEM_ERR = "system-err"; /** the system-out element */ String SYSTEM_OUT = "system-out"; /** package attribute for the aggregate document */ String ATTR_PACKAGE = "package"; /** name attribute for property, testcase and testsuite elements */ String ATTR_NAME = "name"; /** time attribute for testcase and testsuite elements */ String ATTR_TIME = "time"; /** errors attribute for testsuite elements */ String ATTR_ERRORS = "errors"; /** failures attribute for testsuite elements */ String ATTR_FAILURES = "failures"; /** tests attribute for testsuite elements */ String ATTR_TESTS = "tests"; /** type attribute for failure and error elements */ String ATTR_TYPE = "type"; /** message attribute for failure elements */ String ATTR_MESSAGE = "message"; /** the properties element */ String PROPERTIES = "properties"; /** the property element */ String PROPERTY = "property"; /** value attribute for property elements */ String ATTR_VALUE = "value"; /** classname attribute for testcase elements */ String ATTR_CLASSNAME = "classname"; String ATTR_HOSTNAME = "hostname"; String ATTR_TIMESTAMP = "timestamp"; }testng-6.9.12/src/main/java/org/testng/reporters/SuiteHTMLReporter.java0000755000175000017500000006567312732165123025365 0ustar eugeneeugenepackage org.testng.reporters; import static org.testng.internal.Utils.isStringNotEmpty; import org.testng.IInvokedMethod; import org.testng.IReporter; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.Reporter; import org.testng.collections.Maps; import org.testng.internal.Utils; import org.testng.xml.XmlSuite; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; /** * This class implements an HTML reporter for suites. * * @author cbeust * @author Alexandru Popescu */ public class SuiteHTMLReporter implements IReporter { public static final String METHODS_CHRONOLOGICAL = "methods.html"; public static final String METHODS_ALPHABETICAL = "methods-alphabetical.html"; public static final String GROUPS = "groups.html"; public static final String CLASSES = "classes.html"; public static final String REPORTER_OUTPUT = "reporter-output.html"; public static final String METHODS_NOT_RUN = "methods-not-run.html"; public static final String TESTNG_XML = "testng.xml.html"; private Map m_classes = Maps.newHashMap(); private String m_outputDirectory; @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { m_outputDirectory = generateOutputDirectoryName(outputDirectory + File.separator + "old"); try { HtmlHelper.generateStylesheet(outputDirectory); } catch (IOException e) { // TODO Propagate the exception properly. e.printStackTrace(); } for (ISuite suite : suites) { // // Generate the various reports // XmlSuite xmlSuite = suite.getXmlSuite(); if (xmlSuite.getTests().size() == 0) { continue; } generateTableOfContents(xmlSuite, suite); generateSuites(xmlSuite, suite); generateIndex(xmlSuite, suite); generateMain(xmlSuite, suite); generateMethodsAndGroups(xmlSuite, suite); generateMethodsChronologically(xmlSuite, suite, METHODS_CHRONOLOGICAL, false); generateMethodsChronologically(xmlSuite, suite, METHODS_ALPHABETICAL, true); generateClasses(xmlSuite, suite); generateReporterOutput(xmlSuite, suite); generateExcludedMethodsReport(xmlSuite, suite); generateXmlFile(xmlSuite, suite); } generateIndex(suites); } /** * Overridable by subclasses to create different directory names (e.g. with timestamps). * @param outputDirectory the output directory specified by the user */ protected String generateOutputDirectoryName(String outputDirectory) { return outputDirectory; } private void generateXmlFile(XmlSuite xmlSuite, ISuite suite) { String content = xmlSuite.toXml().replaceAll("<", "<").replaceAll(">", ">") .replaceAll(" ", " ").replaceAll("\n", "
"); StringBuffer sb = new StringBuffer(""); sb.append("").append("testng.xml for ") .append(xmlSuite.getName()).append("") .append(content) .append(""); Utils.writeFile(getOutputDirectory(xmlSuite), TESTNG_XML, sb.toString()); } /** * Generate the main index.html file that lists all the suites * and their result */ private void generateIndex(List suites) { StringBuffer sb = new StringBuffer(); String title = "Test results"; sb.append("\n" + title + "") .append(HtmlHelper.getCssString(".")) .append("\n") .append("

").append(title).append("

\n") .append("") .append("\n"); int totalFailedTests = 0; int totalPassedTests = 0; int totalSkippedTests = 0; StringBuffer suiteBuf= new StringBuffer(); for (ISuite suite : suites) { if (suite.getResults().size() == 0) { continue; } String name = suite.getName(); int failedTests= 0; int passedTests= 0; int skippedTests= 0; Map results = suite.getResults(); for (ISuiteResult result : results.values()) { ITestContext context = result.getTestContext(); failedTests += context.getFailedTests().size(); totalFailedTests += context.getFailedTests().size(); passedTests += context.getPassedTests().size(); totalPassedTests += context.getPassedTests().size(); skippedTests += context.getSkippedTests().size(); totalSkippedTests += context.getSkippedTests().size(); } String cls = failedTests > 0 ? "invocation-failed" : (passedTests > 0 ? "invocation-passed" : "invocation-failed"); suiteBuf.append("") .append("\n"); suiteBuf.append("") .append("") .append("") .append("") .append(""); } String cls= totalFailedTests > 0 ? "invocation-failed" : (totalPassedTests > 0 ? "invocation-passed" : "invocation-failed"); sb.append("") .append("") .append("") .append("") .append("") .append("") .append("\n"); sb.append(suiteBuf); sb.append("
SuitePassedFailedSkippedtestng.xml
") .append(name).append("" + passedTests + "" + failedTests + "" + skippedTests + "Link").append("
Total").append(totalPassedTests).append("").append(totalFailedTests).append("").append(totalSkippedTests).append(" 
").append("\n"); Utils.writeFile(m_outputDirectory, "index.html", sb.toString()); } private void generateExcludedMethodsReport(XmlSuite xmlSuite, ISuite suite) { Collection excluded = suite.getExcludedMethods(); StringBuffer sb2 = new StringBuffer("

Methods that were not run

\n"); for (ITestNGMethod method : excluded) { Method m = method.getMethod(); if (m != null) { sb2.append("\n"); } } sb2.append("
") .append(m.getDeclaringClass().getName() + "." + m.getName()); String description = method.getDescription(); if(isStringNotEmpty(description)) { sb2.append("
").append(SP2).append("").append(description).append(""); } sb2.append("
"); Utils.writeFile(getOutputDirectory(xmlSuite), METHODS_NOT_RUN, sb2.toString()); } private void generateReporterOutput(XmlSuite xmlSuite, ISuite suite) { StringBuffer sb = new StringBuffer(); // // Reporter output // sb.append("

Reporter output

") .append(""); List output = Reporter.getOutput(); for (String line : output) { sb.append("\n"); } sb.append("
").append(line).append("
"); Utils.writeFile(getOutputDirectory(xmlSuite), REPORTER_OUTPUT, sb.toString()); } private void generateClasses(XmlSuite xmlSuite, ISuite suite) { StringBuffer sb = new StringBuffer(); sb.append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("") ; for (ITestClass tc : m_classes.values()) { sb.append(generateClass(tc)); } sb.append("
Class nameMethod nameGroups
\n"); Utils.writeFile(getOutputDirectory(xmlSuite), CLASSES, sb.toString()); } private final static String SP = " "; private final static String SP2 = SP + SP + SP + SP; private final static String SP3 = SP2 + SP2; private final static String SP4 = SP3 + SP3; private String generateClass(ITestClass cls) { StringBuffer sb = new StringBuffer(); sb.append("\n") .append("").append(cls.getRealClass().getName()).append("\n") .append(" ") .append(" ") .append("\n") ; String[] tags = new String[] { "@Test", "@BeforeClass", "@BeforeMethod", "@AfterMethod", "@AfterClass" }; ITestNGMethod[][] methods = new ITestNGMethod[][] { cls.getTestMethods(), cls.getBeforeClassMethods(), cls.getBeforeTestMethods(), cls.getAfterTestMethods(), cls.getAfterClassMethods() }; for (int i = 0; i < tags.length; i++) { sb.append("\n") .append("").append(tags[i]).append("\n") .append("\n") .append(dumpMethods(methods[i])) ; } // sb.append("
") // .append("

").append(cls.getRealClass().getName()).append("

\n"); // // sb.append("
").append(SP3).append("Test methods\n") // .append(dumpMethods(cls.getTestMethods())).append("
\n") // .append("
").append(SP3).append("@BeforeClass\n") // .append(dumpMethods(cls.getBeforeClassMethods())).append("
\n") // .append("
").append(SP3).append("@BeforeMethod\n") // .append(dumpMethods(cls.getBeforeTestMethods())).append("
\n") // .append("
").append(SP3).append("@AfterMethod\n") // .append(dumpMethods(cls.getAfterTestMethods())).append("
\n") // .append("
").append(SP3).append("@AfterClass\n") // .append(dumpMethods(cls.getAfterClassMethods())).append("
\n") // ; String result = sb.toString(); return result; } private String dumpMethods(ITestNGMethod[] testMethods) { StringBuffer sb = new StringBuffer(); if(null == testMethods || testMethods.length == 0) { return ""; } for (ITestNGMethod m : testMethods) { sb.append("\n"); sb.append(" \n") .append("").append(m.getMethodName()).append("\n") ; String[] groups = m.getGroups(); if (groups != null && groups.length > 0) { sb.append(""); for (String g : groups) { sb.append(g).append(" "); } sb.append("\n"); } else { sb.append(" "); } sb.append("\n"); } // StringBuffer sb = new StringBuffer("
"); //""); // for (ITestNGMethod tm : testMethods) { // sb // .append(SP4).append(tm.getMethodName()).append("()\n") // .append(dumpGroups(tm.getGroups())) // .append("
"); // ; // } String result = sb.toString(); return result; } private String dumpGroups(String[] groups) { StringBuffer sb = new StringBuffer(); if (null != groups && groups.length > 0) { sb.append(SP4).append("["); for (String g : groups) { sb.append(g).append(" "); } sb.append("]
\n"); } String result = sb.toString(); return result; } /** * Generate information about the methods that were run */ public static final String AFTER= "<<"; public static final String BEFORE = ">>"; private void generateMethodsChronologically(XmlSuite xmlSuite, ISuite suite, String outputFileName, boolean alphabetical) { try (BufferedWriter bw = Utils.openWriter(getOutputDirectory(xmlSuite), outputFileName)) { bw.append("

Methods run, sorted chronologically

"); bw.append("

" + BEFORE + " means before, " + AFTER + " means after

"); long startDate = -1; bw.append("
").append(suite.getName()).append("

"); bw.append("(Hover the method name to see the test class name)

\n"); Collection invokedMethods = suite.getAllInvokedMethods(); if (alphabetical) { @SuppressWarnings({"unchecked"}) Comparator alphabeticalComparator = new Comparator(){ @Override public int compare(Object o1, Object o2) { IInvokedMethod m1 = (IInvokedMethod) o1; IInvokedMethod m2 = (IInvokedMethod) o2; return m1.getTestMethod().getMethodName().compareTo(m2.getTestMethod().getMethodName()); } }; Collections.sort((List) invokedMethods, alphabeticalComparator); } SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); boolean addedHeader = false; synchronized(invokedMethods) { for (IInvokedMethod iim : invokedMethods) { ITestNGMethod tm = iim.getTestMethod(); if (!addedHeader) { bw.append("

\n") .append("") .append("") .append("") .append("") .append("") .append("") .append("") .append("") .append("") .append("") .append("") .append("\n"); addedHeader = true; } String methodName = tm.toString(); boolean bc = tm.isBeforeClassConfiguration(); boolean ac = tm.isAfterClassConfiguration(); boolean bt = tm.isBeforeTestConfiguration(); boolean at = tm.isAfterTestConfiguration(); boolean bs = tm.isBeforeSuiteConfiguration(); boolean as = tm.isAfterSuiteConfiguration(); boolean bg = tm.isBeforeGroupsConfiguration(); boolean ag = tm.isAfterGroupsConfiguration(); boolean setUp = tm.isBeforeMethodConfiguration(); boolean tearDown = tm.isAfterMethodConfiguration(); boolean isClassConfiguration = bc || ac; boolean isGroupsConfiguration = bg || ag; boolean isTestConfiguration = bt || at; boolean isSuiteConfiguration = bs || as; boolean isSetupOrTearDown = setUp || tearDown; String configurationClassMethod = isClassConfiguration ? (bc ? BEFORE : AFTER) + methodName : SP; String configurationTestMethod = isTestConfiguration ? (bt ? BEFORE : AFTER) + methodName : SP; String configurationGroupsMethod = isGroupsConfiguration ? (bg ? BEFORE : AFTER) + methodName : SP; String configurationSuiteMethod = isSuiteConfiguration ? (bs ? BEFORE : AFTER) + methodName : SP; String setUpOrTearDownMethod = isSetupOrTearDown ? (setUp ? BEFORE : AFTER) + methodName : SP; String testMethod = tm.isTest() ? methodName : SP; StringBuffer instances = new StringBuffer(); for (long o : tm.getInstanceHashCodes()) { instances.append(o).append(" "); } if (startDate == -1) { startDate = iim.getDate(); } String date = format.format(iim.getDate()); bw.append("") .append(" ") .append(" ") .append(td(configurationSuiteMethod)) .append(td(configurationTestMethod)) .append(td(configurationClassMethod)) .append(td(configurationGroupsMethod)) .append(td(setUpOrTearDownMethod)) .append(td(testMethod)) .append(" ") .append(" ") .append("\n") ; } } bw.append("
TimeDelta (ms)Suite
configuration
Test
configuration
Class
configuration
Groups
configuration
Method
configuration
Test
method
ThreadInstances
").append(date).append("").append(Long.toString(iim.getDate() - startDate)).append("").append(tm.getId()).append("").append(instances).append("
\n"); } catch (IOException e) { Utils.log("[SuiteHTMLReporter]", 1, "Error writing to " + outputFileName + ": " + e.getMessage()); } } /** * Generate a HTML color based on the class of the method */ private String createColor(ITestNGMethod tm) { // real class can be null if this client is remote (not serializable) long color = tm.getRealClass() != null ? tm.getRealClass().hashCode() & 0xffffff: 0xffffff; long[] rgb = { ((color & 0xff0000) >> 16) & 0xff, ((color & 0x00ff00) >> 8) & 0xff, color & 0xff }; // Not too dark for (int i = 0; i < rgb.length; i++) { if (rgb[i] < 0x60) { rgb[i] += 0x60; } } long adjustedColor = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; String result = Long.toHexString(adjustedColor); return result; } private String td(String s) { StringBuffer result = new StringBuffer(); String prefix = ""; if (s.startsWith(BEFORE)) { prefix = BEFORE; } else if (s.startsWith(AFTER)) { prefix = AFTER; } if (! s.equals(SP)) { result.append(""); int open = s.lastIndexOf("("); int start = s.substring(0, open).lastIndexOf("."); // int end = s.lastIndexOf(")"); if (start >= 0) { result.append(prefix + s.substring(start + 1, open)); } else { result.append(prefix + s); } result.append(" \n"); } else { result.append("").append(SP).append(""); } return result.toString(); } private void ppp(String s) { System.out.println("[SuiteHTMLReporter] " + s); } /** * Generate information about methods and groups */ private void generateMethodsAndGroups(XmlSuite xmlSuite, ISuite suite) { StringBuffer sb = new StringBuffer(); Map> groups = suite.getMethodsByGroups(); sb.append("

Groups used for this test run

"); if (groups.size() > 0) { sb.append("\n") .append("") .append(""); String[] groupNames = groups.keySet().toArray(new String[groups.size()]); Arrays.sort(groupNames); for (String group : groupNames) { Collection methods = groups.get(group); sb.append(""); StringBuffer methodNames = new StringBuffer(); Map uniqueMethods = Maps.newHashMap(); for (ITestNGMethod tm : methods) { uniqueMethods.put(tm, tm); } for (ITestNGMethod tm : uniqueMethods.values()) { methodNames.append(tm.toString()).append("
"); } sb.append("
\n"); } sb.append("
Group nameMethods
").append(group).append("" + methodNames.toString() + "
\n"); } Utils.writeFile(getOutputDirectory(xmlSuite), GROUPS, sb.toString()); } private void generateIndex(XmlSuite xmlSuite, ISuite sr) { StringBuffer index = new StringBuffer() .append("Results for " + sr.getName() + "\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") ; Utils.writeFile(getOutputDirectory(xmlSuite), "index.html", index.toString()); } private String makeTitle(ISuite suite) { return "Results for
" + suite.getName() + ""; } private void generateMain(XmlSuite xmlSuite, ISuite sr) { StringBuffer index = new StringBuffer() .append("Results for " + sr.getName() + "\n") .append("Select a result on the left-hand pane.") .append("\n") ; Utils.writeFile(getOutputDirectory(xmlSuite), "main.html", index.toString()); } /** * */ private void generateTableOfContents(XmlSuite xmlSuite, ISuite suite) { StringBuffer tableOfContents = new StringBuffer(); // // Generate methods and groups hyperlinks // Map suiteResults = suite.getResults(); int groupCount = suite.getMethodsByGroups().size(); int methodCount = 0; synchronized(suiteResults) { for (ISuiteResult sr : suiteResults.values()) { ITestNGMethod[] methods = sr.getTestContext().getAllTestMethods(); methodCount += Utils.calculateInvokedMethodCount(methods); // Collect testClasses for (ITestNGMethod tm : methods) { ITestClass tc = tm.getTestClass(); m_classes.put(tc.getRealClass().getName(), tc); } } } String name = "Results for " + suite.getName(); tableOfContents .append("\n") .append("\n") .append("" + name + "\n") .append(HtmlHelper.getCssString()) .append("\n") ; tableOfContents .append("\n") .append("

" + makeTitle(suite) + "

\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("\n") .append("") .append("
") .append(suiteResults.size()).append(" ").append(pluralize(suiteResults.size(), "test")) .append("") .append("") .append(m_classes.size() + " " + pluralize(m_classes.size(), "class")) .append("") .append("" + methodCount + " " + pluralize(methodCount, "method") + ":
\n") .append("  ").append("chronological
\n") .append("  ").append("alphabetical
\n") .append("  not run (" + suite.getExcludedMethods().size() + ")") .append("
").append(groupCount + pluralize(groupCount, " group") + "reporter outputtestng.xml
"); // // Generate results for individual tests // // Order the results so we can show the failures first, then the skip and // finally the successes Map redResults = Maps.newHashMap(); Map yellowResults = Maps.newHashMap(); Map greenResults = Maps.newHashMap(); synchronized(suiteResults) { for (Map.Entry entry : suiteResults.entrySet()) { String suiteName = entry.getKey(); ISuiteResult sr = entry.getValue(); ITestContext tc = sr.getTestContext(); int failed = tc.getFailedTests().size(); int skipped = tc.getSkippedTests().size(); int passed = tc.getPassedTests().size(); if (failed > 0) { redResults.put(suiteName, sr); } else if (skipped > 0) { yellowResults.put(suiteName, sr); } else if (passed > 0) { greenResults.put(suiteName, sr); } else { redResults.put(suiteName, sr); } } } ISuiteResult[][] results = new ISuiteResult[][] { sortResults(redResults.values()), sortResults(yellowResults.values()), sortResults(greenResults.values()) }; String[] colors = {"failed", "skipped", "passed"}; for (int i = 0; i < colors.length; i++) { ISuiteResult[] r = results[i]; for (ISuiteResult sr: r) { String suiteName = sr.getTestContext().getName(); generateSuiteResult(suiteName, sr, colors[i], tableOfContents, m_outputDirectory); } } tableOfContents.append(""); Utils.writeFile(getOutputDirectory(xmlSuite), "toc.html", tableOfContents.toString()); } private String pluralize(int count, String singular) { return count > 1 ? (singular.endsWith("s") ? singular + "es" : singular + "s") : singular; } private String getOutputDirectory(XmlSuite xmlSuite) { File fileResult = new File(m_outputDirectory + File.separatorChar + xmlSuite.getName()).getAbsoluteFile(); if (! fileResult.exists()) { fileResult.mkdirs(); if (! fileResult.exists()) { Utils.log("Reports", 2, "Problem creating output directory " + fileResult.getAbsolutePath()); } } return fileResult.getAbsolutePath(); } private ISuiteResult[] sortResults(Collection r) { ISuiteResult[] result = r.toArray(new ISuiteResult[r.size()]); Arrays.sort(result); return result; } private void generateSuiteResult(String suiteName, ISuiteResult sr, String cssClass, StringBuffer tableOfContents, String outputDirectory) { ITestContext tc = sr.getTestContext(); int passed = tc.getPassedTests().size(); int failed = tc.getFailedTests().size(); int skipped = tc.getSkippedTests().size(); String baseFile = tc.getName(); tableOfContents .append("\n\n") .append("

\n") ; tableOfContents.append("

\n") .append("") .append("") .append("") .append("
") .append(suiteName).append(" (").append(passed).append("/").append(failed).append("/").append(skipped).append(")") .append("\n") .append(" Results\n") // .append(" Output\n") // .append("  Property file
\n") .append("
\n") .append("
\n"); } /** * Writes a property file for each suite result. * * @param xmlSuite * @param suite */ private void generateSuites(XmlSuite xmlSuite, ISuite suite) { Map suiteResults = suite.getResults(); for (ISuiteResult sr : suiteResults.values()) { ITestContext testContext = sr.getTestContext(); StringBuffer sb = new StringBuffer(); for (ISuiteResult suiteResult : suiteResults.values()) { sb.append(suiteResult.toString()); } Utils.writeFile(getOutputDirectory(xmlSuite), testContext.getName() + ".properties", sb.toString()); } } } testng-6.9.12/src/main/java/org/testng/reporters/JUnitXMLReporter.java0000755000175000017500000002240312732165123025201 0ustar eugeneeugenepackage org.testng.reporters; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.IResultListener2; import org.testng.internal.Utils; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; /** * A JUnit XML report generator (replacing the original JUnitXMLReporter that was * based on XML APIs). * * @author Alex Popescu */ public class JUnitXMLReporter implements IResultListener2 { private static final Pattern ENTITY= Pattern.compile("&[a-zA-Z]+;.*"); private static final Pattern LESS= Pattern.compile("<"); private static final Pattern GREATER= Pattern.compile(">"); private static final Pattern SINGLE_QUOTE = Pattern.compile("'"); private static final Pattern QUOTE = Pattern.compile("\""); private static final Map ATTR_ESCAPES= Maps.newHashMap(); static { ATTR_ESCAPES.put("<", LESS); ATTR_ESCAPES.put(">", GREATER); ATTR_ESCAPES.put("'", SINGLE_QUOTE); ATTR_ESCAPES.put(""", QUOTE); } /** * keep lists of all the results */ private int m_numPassed= 0; private int m_numFailed= 0; private int m_numSkipped= 0; private int m_numFailedButIgnored= 0; private List m_allTests = Collections.synchronizedList(Lists.newArrayList()); private List m_configIssues = Collections.synchronizedList(Lists.newArrayList()); private Map m_fileNameMap = Maps.newHashMap(); private int m_fileNameIncrementer = 0; @Override public void onTestStart(ITestResult result) { } @Override public void beforeConfiguration(ITestResult tr) { } /** * Invoked each time a test succeeds. */ @Override public void onTestSuccess(ITestResult tr) { m_allTests.add(tr); m_numPassed++; } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult tr) { m_allTests.add(tr); m_numFailedButIgnored++; } /** * Invoked each time a test fails. */ @Override public void onTestFailure(ITestResult tr) { m_allTests.add(tr); m_numFailed++; } /** * Invoked each time a test is skipped. */ @Override public void onTestSkipped(ITestResult tr) { m_allTests.add(tr); m_numSkipped++; } /** * Invoked after the test class is instantiated and before * any configuration method is called. * */ @Override public void onStart(ITestContext context) { } /** * Invoked after all the tests have run and all their * Configuration methods have been called. * */ @Override public void onFinish(ITestContext context) { generateReport(context); resetAll(); } /** * @see org.testng.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult) */ @Override public void onConfigurationFailure(ITestResult itr) { m_configIssues.add(itr); } /** * @see org.testng.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult) */ @Override public void onConfigurationSkip(ITestResult itr) { m_configIssues.add(itr); } /** * @see org.testng.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult) */ @Override public void onConfigurationSuccess(ITestResult itr) { } /** * generate the XML report given what we know from all the test results */ protected void generateReport(ITestContext context) { XMLStringBuffer document= new XMLStringBuffer(); document.addComment("Generated by " + getClass().getName()); Properties attrs= new Properties(); attrs.setProperty(XMLConstants.ATTR_ERRORS, "0"); attrs.setProperty(XMLConstants.ATTR_FAILURES, "" + m_numFailed); try { attrs.setProperty(XMLConstants.ATTR_HOSTNAME, InetAddress.getLocalHost().getHostName()); } catch (UnknownHostException e) { // ignore } Set packages = getPackages(context); if (packages.size() > 0) { attrs.setProperty(XMLConstants.ATTR_NAME, context.getCurrentXmlTest().getName()); // attrs.setProperty(XMLConstants.ATTR_PACKAGE, packages.iterator().next()); } attrs.setProperty(XMLConstants.ATTR_TESTS, "" + m_allTests.size()); attrs.setProperty(XMLConstants.ATTR_TIME, "" + ((context.getEndDate().getTime() - context.getStartDate().getTime()) / 1000.0)); Date timeStamp = Calendar.getInstance().getTime(); attrs.setProperty(XMLConstants.ATTR_TIMESTAMP, timeStamp.toGMTString()); document.push(XMLConstants.TESTSUITE, attrs); // document.addEmptyElement(XMLConstants.PROPERTIES); createElementFromTestResults(document, m_configIssues); createElementFromTestResults(document, m_allTests); document.pop(); Utils.writeUtf8File(context.getOutputDirectory(),generateFileName(context) + ".xml", document.toXML()); } private void createElementFromTestResults(XMLStringBuffer document, List results) { synchronized(results) { for(ITestResult tr : results) { createElement(document, tr); } } } private Set getPackages(ITestContext context) { Set result = Sets.newHashSet(); for (ITestNGMethod m : context.getAllTestMethods()) { Package pkg = m.getMethod().getDeclaringClass().getPackage(); if (pkg != null) { result.add(pkg.getName()); } } return result; } private void createElement(XMLStringBuffer doc, ITestResult tr) { Properties attrs= new Properties(); long elapsedTimeMillis= tr.getEndMillis() - tr.getStartMillis(); String name= tr.getMethod().isTest() ? tr.getName() : Utils.detailedMethodName(tr.getMethod(), false); attrs.setProperty(XMLConstants.ATTR_NAME, name); attrs.setProperty(XMLConstants.ATTR_CLASSNAME, tr.getTestClass().getRealClass().getName()); attrs.setProperty(XMLConstants.ATTR_TIME, "" + (((double) elapsedTimeMillis) / 1000)); if((ITestResult.FAILURE == tr.getStatus()) || (ITestResult.SKIP == tr.getStatus())) { doc.push(XMLConstants.TESTCASE, attrs); if(ITestResult.FAILURE == tr.getStatus()) { createFailureElement(doc, tr); } else if(ITestResult.SKIP == tr.getStatus()) { createSkipElement(doc, tr); } doc.pop(); } else { doc.addEmptyElement(XMLConstants.TESTCASE, attrs); } } private void createFailureElement(XMLStringBuffer doc, ITestResult tr) { Properties attrs= new Properties(); Throwable t= tr.getThrowable(); if(t != null) { attrs.setProperty(XMLConstants.ATTR_TYPE, t.getClass().getName()); String message= t.getMessage(); if((message != null) && (message.length() > 0)) { attrs.setProperty(XMLConstants.ATTR_MESSAGE, encodeAttr(message)); // ENCODE } doc.push(XMLConstants.FAILURE, attrs); doc.addCDATA(Utils.stackTrace(t, false)[0]); doc.pop(); } else { doc.addEmptyElement(XMLConstants.FAILURE); // THIS IS AN ERROR } } private void createSkipElement(XMLStringBuffer doc, ITestResult tr) { doc.addEmptyElement("skipped"); } private String encodeAttr(String attr) { String result= replaceAmpersand(attr, ENTITY); for(Map.Entry e: ATTR_ESCAPES.entrySet()) { result= e.getValue().matcher(result).replaceAll(e.getKey()); } return result; } private String replaceAmpersand(String str, Pattern pattern) { int start = 0; int idx = str.indexOf('&', start); if(idx == -1) { return str; } StringBuffer result= new StringBuffer(); while(idx != -1) { result.append(str.substring(start, idx)); if(pattern.matcher(str.substring(idx)).matches()) { // do nothing it is an entity; result.append("&"); } else { result.append("&"); } start= idx + 1; idx= str.indexOf('&', start); } result.append(str.substring(start)); return result.toString(); } /** * Reset all member variables for next test. * */ private void resetAll() { m_allTests = Collections.synchronizedList(Lists.newArrayList()); m_configIssues = Collections.synchronizedList(Lists.newArrayList()); m_numFailed = 0; m_numFailedButIgnored = 0; m_numPassed = 0; m_numSkipped = 0; } /** * @author Borojevic Created this method to guarantee unique file names for * reports.
* Also, this will guarantee that the old reports are overwritten * when tests are run again. * @param context * test context * @return unique name for the file associated with this test context. * */ private String generateFileName(ITestContext context) { String fileName = null; String keyToSearch = context.getSuite().getName() + context.getName(); if (m_fileNameMap.get(keyToSearch) == null) { fileName = context.getName(); } else { fileName = context.getName() + m_fileNameIncrementer++; } m_fileNameMap.put(keyToSearch, fileName); return fileName; } } testng-6.9.12/src/main/java/org/testng/reporters/TextReporter.java0000644000175000017500000001262612732165123024516 0ustar eugeneeugenepackage org.testng.reporters; import static org.testng.internal.Utils.isStringNotBlank; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.testng.internal.Utils; import java.util.List; /** * A simple reporter that collects the results and prints them on standard out. * * @author Cedric Beust * @author Alexandru Popescu */ public class TextReporter extends TestListenerAdapter { private int m_verbose = 0; private String m_testName = null; public TextReporter(String testName, int verbose) { m_testName = testName; m_verbose = verbose; } @Override public void onFinish(ITestContext context) { if (m_verbose >= 2) { logResults(); } } private ITestNGMethod[] resultsToMethods(List results) { ITestNGMethod[] result = new ITestNGMethod[results.size()]; int i = 0; for (ITestResult tr : results) { result[i++] = tr.getMethod(); } return result; } private void logResults() { // // Log Text // for(Object o : getConfigurationFailures()) { ITestResult tr = (ITestResult) o; Throwable ex = tr.getThrowable(); String stackTrace= ""; if (ex != null) { if (m_verbose >= 2) { stackTrace= Utils.stackTrace(ex, false)[0]; } } logResult("FAILED CONFIGURATION", Utils.detailedMethodName(tr.getMethod(), false), tr.getMethod().getDescription(), stackTrace, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes() ); } for(Object o : getConfigurationSkips()) { ITestResult tr = (ITestResult) o; logResult("SKIPPED CONFIGURATION", Utils.detailedMethodName(tr.getMethod(), false), tr.getMethod().getDescription(), null, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes() ); } for(Object o : getPassedTests()) { ITestResult tr = (ITestResult) o; logResult("PASSED", tr, null); } for(Object o : getFailedTests()) { ITestResult tr = (ITestResult) o; Throwable ex = tr.getThrowable(); String stackTrace= ""; if (ex != null) { if (m_verbose >= 2) { stackTrace= Utils.stackTrace(ex, false)[0]; } } logResult("FAILED", tr, stackTrace); } for(Object o : getSkippedTests()) { ITestResult tr = (ITestResult) o; Throwable throwable = tr.getThrowable(); logResult("SKIPPED", tr, throwable != null ? Utils.stackTrace(throwable, false)[0] : null); } ITestNGMethod[] ft = resultsToMethods(getFailedTests()); StringBuffer logBuf= new StringBuffer("\n===============================================\n"); logBuf.append(" ").append(m_testName).append("\n"); logBuf.append(" Tests run: ").append(Utils.calculateInvokedMethodCount(getAllTestMethods())) .append(", Failures: ").append(Utils.calculateInvokedMethodCount(ft)) .append(", Skips: ").append(Utils.calculateInvokedMethodCount(resultsToMethods(getSkippedTests()))); int confFailures= getConfigurationFailures().size(); int confSkips= getConfigurationSkips().size(); if(confFailures > 0 || confSkips > 0) { logBuf.append("\n").append(" Configuration Failures: ").append(confFailures) .append(", Skips: ").append(confSkips); } logBuf.append("\n===============================================\n"); logResult("", logBuf.toString()); } private String getName() { return m_testName; } private void logResult(String status, ITestResult tr, String stackTrace) { logResult(status, tr.getName(), tr.getMethod().getDescription(), stackTrace, tr.getParameters(), tr.getMethod().getMethod().getParameterTypes()); } private void logResult(String status, String message) { StringBuffer buf= new StringBuffer(); if(isStringNotBlank(status)) { buf.append(status).append(": "); } buf.append(message); System.out.println(buf); } private void logResult(String status, String name, String description, String stackTrace, Object[] params, Class[] paramTypes) { StringBuffer msg= new StringBuffer(name); if(null != params && params.length > 0) { msg.append("("); // The error might be a data provider parameter mismatch, so make // a special case here if (params.length != paramTypes.length) { msg.append(name + ": Wrong number of arguments were passed by " + "the Data Provider: found " + params.length + " but " + "expected " + paramTypes.length + ")"); } else { for(int i= 0; i < params.length; i++) { if(i > 0) { msg.append(", "); } msg.append(Utils.toString(params[i], paramTypes[i])); } msg.append(")"); } } if (! Utils.isStringEmpty(description)) { msg.append("\n"); for (int i = 0; i < status.length() + 2; i++) { msg.append(" "); } msg.append(description); } if ( ! Utils.isStringEmpty(stackTrace)) { msg.append("\n").append(stackTrace); } logResult(status, msg.toString()); } public void ppp(String s) { System.out.println("[TextReporter " + getName() + "] " + s); } } testng-6.9.12/src/main/java/org/testng/IInvokedMethodListener.java0000755000175000017500000000061412732165123024376 0ustar eugeneeugenepackage org.testng; /** * A listener that gets invoked before and after a method is invoked by TestNG. * This listener will only be invoked for configuration and test methods. */ public interface IInvokedMethodListener extends ITestNGListener { void beforeInvocation(IInvokedMethod method, ITestResult testResult); void afterInvocation(IInvokedMethod method, ITestResult testResult); } testng-6.9.12/src/main/java/org/testng/IMethodInterceptor.java0000755000175000017500000000236512732165123023574 0ustar eugeneeugenepackage org.testng; import java.util.List; /** * This class is used to alter the list of test methods that TestNG is about to run. * *

* * An instance of this class will be invoked right before TestNG starts invoking test methods. * Only methods that have no dependents and that don't depend on any other test methods will * be passed in parameter. Implementers of this interface need to return a list of {@link IMethodInstance} * that represents the list of test methods they want run. TestNG will run these methods in the * same order found in the returned value. * *

* * Typically, the returned list will be just the methods passed in parameter but sorted * differently, but it can actually have any size (it can be empty, it can be of the * same size as the original list or it can contain more methods). * *

* * The {@link ITestContext} is passed in the intercept method so that implementers can set user values * (using {@link ITestContext#setAttribute(String, Object)}), which they can then look up * later while generating the reports. * * @author cbeust */ public interface IMethodInterceptor extends ITestNGListener { List intercept(List methods, ITestContext context); } testng-6.9.12/src/main/java/org/testng/log4testng/0000755000175000017500000000000012732165123021242 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/log4testng/Logger.java0000755000175000017500000006171412732165123023340 0ustar eugeneeugenepackage org.testng.log4testng; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.testng.Assert; import org.testng.collections.Maps; /** * TestNG support logging via a custom logging framework similar to * Log4j. To control logging, add a * resource named "log4testng.properties" to your classpath. The logging levels are * TRACE, DEBUG, INFO, WARN, ERROR and FATAL. * The Logging framework has the following characteristics: * *

    *
  • All logging is done using System.out (for levels < ERROR) or System.err. There * is no way to specify Appenders.
  • *
  • There is no way to control logging programmatically.
  • *
  • The log4testng.properties resource is searched in the classpath on the first * call to the logging API. If it is not present, logging defaults to the WARN * level.
  • *
* * The property file contains lines in the following format: * *

 * # log4testng will log its own behavior (generally used for debugging this package only).
 * log4testng.debug=true
 *
 * # Specifies the root Loggers logging level. Will log DEBUG level and above
 * log4testng.rootLogger=DEBUG
 *
 * # The org.testng.reporters.EmailableReporter Logger will log TRACE level and above
 * log4testng.logger.org.testng.reporters.EmailableReporter=TRACE
 *
 * # All Logger in packages below org.testng will log WARN level and above
 * log4testng.logger.org.testng=WARN
 * 
* * In your source files you will typically instantiate and use loggers this ways: *

 * import org.testng.log4testng.Logger;
 *
 * class ThisClass {
 *     private static final Logger LOGGER = Logger.getLogger(ThisClass.class);
 *
 *     ...
 *     LOGGER.debug("entering myMethod()");
 *     ...
 *     LOGGER.warn("unknown file: " + filename);
 *     ...
 *     LOGGER.error("Unexpected error", exception);
 * 
*/ public class Logger { // Attribute an hierarchical integer value to all levels. private static int i= 0; private static final int TRACE= i++; private static final int DEBUG= i++; private static final int INFO= i++; private static final int WARN= i++; private static final int ERROR= i++; private static final int FATAL= i++; private static final int LEVEL_COUNT= i; /** Standard prefix of all property names in log4testng.properties. */ private static final String PREFIX= "log4testng."; /** Standard prefix of all logger names in log4testng.properties. */ private static final String LOGGER_PREFIX= PREFIX + "logger."; /** Root logger name in log4testng.properties. */ private static final String ROOT_LOGGER= PREFIX + "rootLogger"; /** Debug property name in log4testng.properties. */ private static final String DEBUG_PROPERTY= PREFIX + "debug"; /** The standard error stream (this is allways System.err except for unit tests) */ private static PrintStream err= System.err; /** The standard output stream (this is allways System.out except for unit tests) */ private static PrintStream out= System.out; /** An ordered list of level names. */ private static final String[] levelNames= new String[LEVEL_COUNT]; static { levelNames[TRACE]= "TRACE"; levelNames[DEBUG]= "DEBUG"; levelNames[INFO] = "INFO"; levelNames[WARN] = "WARN"; levelNames[ERROR] = "ERROR"; levelNames[FATAL] = "FATAL"; } /** A map from level name to level integer index (TRACE->0, DEBUG->1 ...) */ private static final Map levelMap= Maps.newHashMap(); static { for(i= 0; i < LEVEL_COUNT; ++i) { levelMap.put(levelNames[i], i); } } /** true if the Logging system has been initialized. */ private static boolean initialized; /** Map from Logger names to level index (as specified in log4testng.properties) */ private static final Map loggerLevels = Maps.newHashMap(); /** Map of all known loggers. */ private static final Map loggers = Maps.newHashMap(); /** The logging level of the root logger (defaults to warn). */ private static int rootLoggerLevel= WARN; /** Should log4testng log what it is doing (defaults to false). */ private static boolean debug= false; /** The logger's level */ private final int level; /** The logger's name. */ private final Class klass; private final String m_className; /** * Retrieve a logger named according to the value of the pClass.getName() * parameter. If the named logger already exists, then the existing instance * will be returned. Otherwise, a new instance is created. By default, loggers * do not have a set level but inherit it from their nearest ancestor with * a set level. * * @param pClass The class' logger to retrieve. * @return a logger named according to the value of the pClass.getName(). */ public static synchronized Logger getLogger(Class pClass) { initialize(); Logger logger= loggers.get(pClass); if(logger != null) { return logger; } int level= getLevel(pClass); logger= new Logger(pClass, level); loggers.put(pClass, logger); return logger; } /** * Check whether this logger is enabled for the TRACE Level. * @return true if this logger is enabled for level TRACE, false otherwise. */ public boolean isTraceEnabled() { return isLevelEnabled(TRACE); } /** * Log a message object with the TRACE level. This method first checks if this * logger is TRACE enabled. If this logger is TRACE enabled, then it converts * the message object (passed as parameter) to a string by invoking toString(). * WARNING Note that passing a Throwable to this method will print the name of * the Throwable but no stack trace. To print a stack trace use the * trace(Object, Throwable) form instead. * @param message the message object to log. */ public void trace(Object message) { log(TRACE, message, null); } /** * Log a message object with the TRACE level including the stack trace of the * Throwable t passed as parameter. * See Logger.trace(Object) form for more detailed information. * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void trace(Object message, Throwable t) { log(TRACE, message, t); } /** * Check whether this logger is enabled for the DEBUG Level. * @return true if this logger is enabled for level DEBUG, false otherwise. */ public boolean isDebugEnabled() { return isLevelEnabled(DEBUG); } /** * Log a message object with the DEBUG level. * See Logger.trace(Object) form for more detailed information. * @param message the message object to log. */ public void debug(Object message) { log(DEBUG, message, null); } /** * Log a message object with the DEBUG level including the stack trace of the * Throwable t passed as parameter. * See Logger.trace(Object, Throwable) form for more detailed information. * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void debug(Object message, Throwable t) { log(DEBUG, message, t); } /** * Check whether this logger is enabled for the INFO Level. * @return true if this logger is enabled for level INFO, false otherwise. */ public boolean isInfoEnabled() { return isLevelEnabled(INFO); } /** * Log a message object with the INFO level. * See Logger.trace(Object) form for more detailed information. * @param message the message object to log. */ public void info(Object message) { log(INFO, message, null); } /** * Log a message object with the WARN level including the stack trace of the * Throwable t passed as parameter. * See Logger.trace(Object, Throwable) form for more detailed information. * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void info(Object message, Throwable t) { log(INFO, message, t); } /** * Log a message object with the WARN level. * See Logger.trace(Object) form for more detailed information. * @param message the message object to log. */ public void warn(Object message) { log(WARN, message, null); } /** * Log a message object with the ERROR level including the stack trace of the * Throwable t passed as parameter. * See Logger.trace(Object, Throwable) form for more detailed information. * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void warn(Object message, Throwable t) { log(WARN, message, t); } /** * Log a message object with the ERROR level. * See Logger.trace(Object) form for more detailed information. * @param message the message object to log. */ public void error(Object message) { log(ERROR, message, null); } /** * Log a message object with the DEBUG level including the stack trace of the * Throwable t passed as parameter. * See Logger.trace(Object, Throwable) form for more detailed information. * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void error(Object message, Throwable t) { log(ERROR, message, t); } /** * Log a message object with the FATAL level. * See Logger.trace(Object) form for more detailed information. * @param message the message object to log. */ public void fatal(Object message) { log(FATAL, message, null); } /** * Log a message object with the FATAL level including the stack trace of the * Throwable t passed as parameter. * See Logger.trace(Object, Throwable) form for more detailed information. * @param message the message object to log. * @param t the exception to log, including its stack trace. */ public void fatal(Object message, Throwable t) { log(FATAL, message, t); } private Logger(Class pClass, int pLevel) { level= pLevel; klass= pClass; m_className= pClass.getName().substring(pClass.getName().lastIndexOf('.') + 1); } private static synchronized void initialize() { if(initialized) { return; } // We flag as initialized right away because if anything goes wrong // We still consider it initialized. TODO Is this OK? initialized= true; InputStream is= Thread.currentThread().getContextClassLoader().getResourceAsStream("log4testng.properties"); if(is == null) { return; } Properties properties= new Properties(); try { properties.load(is); } catch(IOException e) { throw new RuntimeException(e); } checkProperties(properties); } private static void checkProperties(Properties pProperties) { { // See if we want to debug log4testng String debugStr= pProperties.getProperty(DEBUG_PROPERTY); if(debugStr != null) { if(debugStr.equalsIgnoreCase("true")) { debug= true; } else if(debugStr.equalsIgnoreCase("false")) { debug= false; } else { throw new IllegalArgumentException("Unknown " + DEBUG_PROPERTY + " value " + debugStr); } } loglog4testng("log4testng.debug set to " + debug); } { // Set the value of the root logger (if any). String rootLevelStr= pProperties.getProperty(ROOT_LOGGER); if(rootLevelStr != null) { Integer ilevel= levelMap.get(rootLevelStr.toUpperCase()); if(ilevel == null) { throw new IllegalArgumentException("Unknown level for log4testng.rootLogger " + rootLevelStr + " in log4testng.properties"); } rootLoggerLevel= ilevel; loglog4testng("Root level logger set to " + rootLevelStr + " level."); } } Iterator it= pProperties.entrySet().iterator(); while(it.hasNext()) { Map.Entry entry= (Entry) it.next(); String logger= (String) entry.getKey(); String level= (String) entry.getValue(); if(!logger.startsWith(PREFIX)) { throw new IllegalArgumentException("Illegal property value: " + logger); } if(logger.equals(DEBUG_PROPERTY)) { // Already handled } else if(logger.equals(ROOT_LOGGER)) { // Already handled } else { if(!logger.startsWith(LOGGER_PREFIX)) { throw new IllegalArgumentException("Illegal property value: " + logger); } Integer ilevel= levelMap.get(level.toUpperCase()); if(ilevel == null) { throw new IllegalArgumentException("Unknown level " + level + " for logger " + logger + " in log4testng.properties"); } loggerLevels.put(logger.substring(LOGGER_PREFIX.length()), ilevel); loglog4testng("logger " + logger + " set to " + ilevel + " level."); } } } /** * Returns the level associated to the current class. The level is obtain by searching * for a logger in the "testng-logging.properties" resource. For example, if class is * "org.testng.TestNG" the the following loggers are searched in this order: *
    *
  1. "org.testng.TestNG"
  2. *
  3. "org.testng"
  4. *
  5. "org"
  6. *
  7. The root level
  8. *
* * @param pClass the class name used for logger name. * @return the level associated to the current class. */ private static int getLevel(Class pClass) { String name= pClass.getName(); loglog4testng("Getting level for logger " + name); while(true) { Integer level= loggerLevels.get(name); if(level != null) { loglog4testng("Found level " + level + " for logger " + name); return level; } int dot= name.lastIndexOf('.'); if(dot == -1) { loglog4testng("Found level " + rootLoggerLevel + " for root logger"); // Logger name not found. Defaults to root logger level. return rootLoggerLevel; } name= name.substring(0, dot); } } private boolean isLevelEnabled(int pLevel) { return level <= pLevel; } private void log(int pLevel, Object pMessage, Throwable pT) { if(isLevelEnabled(pLevel)) { PrintStream ps= (pLevel >= ERROR) ? err : out; if(null != pT) { synchronized(ps) { ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage); pT.printStackTrace(ps); } } else { ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage); } } } /** * Logs the message to System.out of debug is on. * @param pmessage the message to log to the console */ private static void loglog4testng(String pmessage) { if(debug) { out.println("[log4testng] [debug] " + pmessage); } } /** * This method is for debugging purpose only. * * @param pProperties a properties bundle initialised as log4testng * property file would be. * @param pOut the standard output stream to be used for logging. * @param pErr the standard error stream to be used for logging. */ private static synchronized void testInitialize(Properties pProperties, PrintStream pOut, PrintStream pErr) { initialized= true; loggers.clear(); rootLoggerLevel= WARN; debug= false; out= pOut; err= pErr; checkProperties(pProperties); } /** * Makes sure the default debug value is false. */ private static void testDebugDefault() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.rootLogger", "WARN"); testInitialize(props, out2, err2); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); } /** * Makes sure the debug value can be turned on and actualls logs something. */ private static void testDebugOn() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.debug", "true"); props.put("log4testng.rootLogger", "WARN"); testInitialize(props, out2, err2); Assert.assertTrue(out1.toString().startsWith("[log4testng][debug]")); Assert.assertEquals(err1.toString(), ""); } /** * Makes sure the debug value can be turned off and logs nothing. */ private static void testDebugOff() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.debug", "false"); props.put("log4testng.rootLogger", "WARN"); testInitialize(props, out2, err2); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); } /** * Makes sure an illegal debug value throws an exception. */ private static void testDebugError() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.debug", "unknown"); props.put("log4testng.rootLogger", "WARN"); try { testInitialize(props, out2, err2); throw new RuntimeException("failure"); } catch(IllegalArgumentException pEx) { // Normal case Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); } } /** * Tests that the root logger's default level is WARN and that loggers do not * log bellow this level and do log in the correct stream for levels equal to * and above WARN. */ private static void testRootLoggerDefault() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); testInitialize(props, out2, err2); Logger strLogger= Logger.getLogger(String.class); strLogger.trace("trace should not appear"); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); strLogger.debug("debug should not appear"); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); strLogger.info("info should not appear"); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); strLogger.warn("warn should appear"); int outlength= out1.toString().length(); Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [WARN] warn should appear")); Assert.assertEquals(err1.toString(), ""); strLogger.error("error should appear"); Assert.assertEquals(out1.toString().length(), outlength); Assert.assertTrue(err1.toString().startsWith("[java.lang.String] [ERROR] error should appear")); strLogger.fatal("fatal should appear"); Assert.assertEquals(out1.toString().length(), outlength); Assert.assertTrue(err1.toString().contains("[java.lang.String] [FATAL] fatal should appear")); } /** * Test setting the root logger level */ private static void testRootLoggerSet() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.rootLogger", "DEBUG"); testInitialize(props, out2, err2); Logger strLogger= Logger.getLogger(String.class); strLogger.trace("trace should appear"); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); strLogger.debug("debug should appear"); Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear")); Assert.assertEquals(err1.toString(), ""); } /** * Test setting the root logger to an illegal level value throws an exception. */ private static void testRootLoggerSetError() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.rootLogger", "unknown"); try { testInitialize(props, out2, err2); throw new RuntimeException("failure"); } catch(IllegalArgumentException pEx) { // Normal case Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); } } /** * Test setting a user logger level */ private static void testUserLoggerSet() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.logger.java.lang.String", "DEBUG"); testInitialize(props, out2, err2); Logger strLogger= Logger.getLogger(String.class); strLogger.trace("trace should not appear"); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); strLogger.debug("debug should appear"); int outLength= out1.toString().length(); Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear")); Assert.assertEquals(err1.toString(), ""); Logger classLogger= Logger.getLogger(Class.class); classLogger.debug("debug should not appear"); Assert.assertEquals(out1.toString().length(), outLength); Assert.assertEquals(err1.toString(), ""); classLogger.warn("warn should appear"); Assert.assertTrue(out1.toString().contains("[java.lang.Class] [WARN] warn should appear")); Assert.assertEquals(err1.toString(), ""); } /** * Test setting a user logger to an illegal level value throws an exception */ private static void testUserLoggerSetError() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.logger.java.lang.String", "unknown"); try { testInitialize(props, out2, err2); throw new RuntimeException("failure"); } catch(IllegalArgumentException pEx) { // Normal case Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); } } /** * Tests setting a partial logger name (a hierarchy scope) */ private static void testUserLoggerSetHierarchy() { Properties props= new Properties(); ByteArrayOutputStream out1= new ByteArrayOutputStream(); ByteArrayOutputStream err1= new ByteArrayOutputStream(); PrintStream out2= new PrintStream(out1); PrintStream err2= new PrintStream(err1); props.put("log4testng.logger.java.lang", "DEBUG"); testInitialize(props, out2, err2); Logger strLogger= Logger.getLogger(String.class); strLogger.trace("trace should not appear"); Assert.assertEquals(out1.toString(), ""); Assert.assertEquals(err1.toString(), ""); strLogger.debug("debug should appear"); Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear")); Assert.assertEquals(err1.toString(), ""); } /** * Run all tests. (very crusty ...) * @param pArgs not used */ public static void main(String[] pArgs) { testDebugDefault(); testDebugOn(); testDebugOff(); testDebugError(); testRootLoggerDefault(); testRootLoggerSet(); testRootLoggerSetError(); testUserLoggerSet(); testUserLoggerSetError(); testUserLoggerSetHierarchy(); } } testng-6.9.12/src/main/java/org/testng/Converter.java0000644000175000017500000000561212732165123021766 0ustar eugeneeugenepackage org.testng; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.ParameterException; import org.testng.collections.Sets; import org.testng.internal.Yaml; import org.testng.xml.Parser; import org.testng.xml.XmlSuite; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Set; /** * Convert XML files to YAML and vice versa. * * @author cbeust */ public class Converter { @Parameter(description = "file1 [file2 file3...]", required = true) private List m_files; @Parameter(names = "-d", description = "The directory where the file(s) will be created") private String m_outputDirectory = "."; public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { Converter c = new Converter(); c.run(args); } private void findAllSuites(Collection suites, Set result) { for (XmlSuite s : suites) { result.add(s); for (XmlSuite xs : s.getChildSuites()) { findAllSuites(Arrays.asList(xs), result); } } } private void run(String[] args) throws ParserConfigurationException, SAXException, IOException { JCommander jc = new JCommander(this); try { jc.parse(args); File f = new File(m_outputDirectory); if (! f.exists()) f.mkdir(); for (String file : m_files) { Set allSuites = Sets.newHashSet(); Parser parser = new Parser(file); parser.setLoadClasses(false); // we might not have these classes on the classpath findAllSuites(parser.parse(), allSuites); for (XmlSuite suite : allSuites) { String fileName = suite.getFileName(); int ind = fileName.lastIndexOf("."); String bn = fileName.substring(0, ind); int ind2 = bn.lastIndexOf(File.separatorChar); String baseName = bn.substring(ind2 + 1); if (file.endsWith(".xml")) { File newFile = new File(m_outputDirectory, baseName + ".yaml"); writeFile(newFile, Yaml.toYaml(suite).toString()); } else if (file.endsWith(".yaml")) { File newFile = new File(m_outputDirectory, baseName + ".xml"); writeFile(newFile, suite.toXml()); } else { throw new TestNGException("Unknown file type:" + file); } } } } catch(ParameterException ex) { System.out.println("Error: " + ex.getMessage()); jc.usage(); } } private void writeFile(File newFile, String content) throws IOException { try (FileWriter bw = new FileWriter(newFile)) { bw.write(content); } System.out.println("Wrote " + newFile); } } testng-6.9.12/src/main/java/org/testng/IModuleFactory.java0000644000175000017500000000111412732165123022676 0ustar eugeneeugenepackage org.testng; import com.google.inject.Module; /** * This interface is used by the moduleFactory attribute of the @Guice * annotation. It allows users to use different Guice modules based on the test * class waiting to be injected. * * @author Cedric Beust */ public interface IModuleFactory { /** * @param context The current test context * @param testClass The test class * * @return The Guice module that should be used to get an instance of this * test class. */ Module createModule(ITestContext context, Class testClass); } testng-6.9.12/src/main/java/org/testng/IObjectFactory2.java0000644000175000017500000000052412732165123022745 0ustar eugeneeugenepackage org.testng; /** * Factory used to create all test instances. This object factory only receives the class * in parameter. * * @see org.testng.IObjectFactory * * @author Cedric Beust * * @since 5.14.6 */ public interface IObjectFactory2 extends ITestObjectFactory { Object newInstance(Class cls); } testng-6.9.12/src/main/java/org/testng/IClass.java0000755000175000017500000000312112732165123021171 0ustar eugeneeugenepackage org.testng; import org.testng.xml.XmlClass; import org.testng.xml.XmlTest; import java.io.Serializable; /** * IClass represents a test class and a collection of its instances. * * @author Cedric Beust */ public interface IClass extends Serializable { /** * @return this test class name. This is the name of the * corresponding Java class. */ String getName(); /** * @return the <test> tag this class was found in. */ XmlTest getXmlTest(); /** * @return the *lt;class> tag this class was found in. */ XmlClass getXmlClass(); /** * If this class implements org.testng.ITest, returns its test name, otherwise returns null. */ String getTestName(); /** * @return the Java class corresponding to this IClass. */ Class getRealClass(); /** * Returns all the instances the methods will be invoked upon. * This will typically be an array of one object in the absence * of a @Factory annotation. * * @param create flag if a new set of instances must be returned * (if set to false) * @return All the instances the methods will be invoked upon. */ Object[] getInstances(boolean create); /** * @deprecated Not used * * @return The number of instances used in this class. This method * is needed for serialization since we don't know ahead of time if the * instances of the test classes will be serializable. */ @Deprecated int getInstanceCount(); long[] getInstanceHashCodes(); void addInstance(Object instance); } testng-6.9.12/src/main/java/org/testng/ITestResult.java0000755000175000017500000000443412732165123022252 0ustar eugeneeugenepackage org.testng; /** * This class describes the result of a test. * * @author Cedric Beust, May 2, 2004 * @since May 2, 2004 * @version $Revision: 721 $, $Date: 2009-05-23 09:55:46 -0700 (Sat, 23 May 2009) $ * */ public interface ITestResult extends IAttributes, Comparable { // // Test status // public static final int SUCCESS = 1; public static final int FAILURE = 2; public static final int SKIP = 3; public static final int SUCCESS_PERCENTAGE_FAILURE = 4; public static final int STARTED= 16; /** * @return The status of this result, using one of the constants * above. */ public int getStatus(); public void setStatus(int status); /** * @return The test method this result represents. */ public ITestNGMethod getMethod(); /** * @return The parameters this method was invoked with. */ public Object[] getParameters(); public void setParameters(Object[] parameters); /** * @return The test class used this object is a result for. */ public IClass getTestClass(); /** * @return The throwable that was thrown while running the * method, or null if no exception was thrown. */ public Throwable getThrowable(); public void setThrowable(Throwable throwable); /** * @return the start date for this test, in milliseconds. */ public long getStartMillis(); /** * @return the end date for this test, in milliseconds. */ public long getEndMillis(); public void setEndMillis(long millis); /** * @return The name of this TestResult, typically identical to the name * of the method. */ public String getName(); /** * @return true if if this test run is a SUCCESS */ public boolean isSuccess(); /** * @return The host where this suite was run, or null if it was run locally. The * returned string has the form: host:port */ public String getHost(); /** * The instance on which this method was run. */ public Object getInstance(); /** * If this result's related instance implements ITest or use @Test(testName=...), returns its test name, otherwise returns null. */ public String getTestName(); public String getInstanceName(); /** * @return the {@link ITestContext} for this test result. */ public ITestContext getTestContext(); } testng-6.9.12/src/main/java/org/testng/TestNGAntTask.java0000755000175000017500000010354112732165123022454 0ustar eugeneeugenepackage org.testng; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Target; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Execute; import org.apache.tools.ant.taskdefs.ExecuteWatchdog; import org.apache.tools.ant.taskdefs.LogOutputStream; import org.apache.tools.ant.taskdefs.PumpStreamHandler; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.CommandlineJava; import org.apache.tools.ant.types.Environment; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.ResourceCollection; import org.apache.tools.ant.types.resources.FileResource; import org.apache.tools.ant.types.selectors.FilenameSelector; import org.testng.collections.Lists; import org.testng.internal.Utils; import org.testng.reporters.VerboseReporter; import static java.lang.Boolean.TRUE; import static org.testng.internal.Utils.isStringNotBlank; /** * TestNG settings: *
    *
  • classfileset (inner)
  • *
  • classfilesetref (attribute)
  • *
  • xmlfileset (inner)
  • *
  • xmlfilesetref (attribute)
  • *
  • enableAssert (attribute)
  • *
  • excludedGroups (attribute)
  • *
  • groups (attribute)
  • *
  • junit (attribute)
  • *
  • listener (attribute)
  • *
  • outputdir (attribute)
  • *
  • parallel (attribute)
  • *
  • reporter (attribute)
  • *
  • sourcedir (attribute)
  • *
  • sourcedirref (attribute)
  • *
  • suitename (attribute)
  • *
  • suiterunnerclass (attribute)
  • *
  • target (attribute)
  • *
  • testjar (attribute)
  • *
  • testname (attribute)
  • *
  • threadcount (attribute)
  • *
  • dataproviderthreadcount (attribute)
  • *
  • verbose (attribute)
  • *
  • testrunfactory (attribute)
  • *
  • configFailurepolicy (attribute)
  • *
  • randomizeSuites (attribute)
  • *
  • methodselectors (attribute)
  • *
* * Ant settings: *
    *
  • classpath (inner)
  • *
  • classpathref (attribute)
  • *
  • jvm (attribute)
  • *
  • workingDir (attribute)
  • *
  • env (inner)
  • *
  • sysproperty (inner)
  • *
  • propertyset (inner)
  • *
  • jvmarg (inner)
  • *
  • timeout (attribute)
  • *
  • haltonfailure (attribute)
  • *
  • onHaltTarget (attribute)
  • *
  • failureProperty (attribute)
  • *
  • haltonFSP (attribute)
  • *
  • FSPproperty (attribute)
  • *
  • haltonskipped (attribute)
  • *
  • skippedProperty (attribute)
  • *
  • testRunnerFactory (attribute)
  • *
* * Debug information: *
    *
  • dumpCommand (boolean)
  • *
  • dumpEnv (boolean)
  • *
  • dumpSys (boolean)
  • *
* * @author Alexandru Popescu * @author Cedric Beust * @author Lukas Jungmann */ public class TestNGAntTask extends Task { protected CommandlineJava m_javaCommand; protected List m_xmlFilesets= Lists.newArrayList(); protected List m_classFilesets= Lists.newArrayList(); protected File m_outputDir; protected File m_testjar; protected File m_workingDir; private Integer m_timeout; private List m_listeners= Lists.newArrayList(); private List m_methodselectors= Lists.newArrayList(); private String m_objectFactory; protected String m_testRunnerFactory; private boolean m_delegateCommandSystemProperties = false; protected Environment m_environment= new Environment(); /** The suite runner name (defaults to TestNG.class.getName(). */ protected String m_mainClass = TestNG.class.getName(); /** True if the temporary file created by the Ant Task for command line parameters * to TestNG should be preserved after execution. */ protected boolean m_dump; private boolean m_dumpEnv; private boolean m_dumpSys; protected boolean m_assertEnabled= true; protected boolean m_haltOnFailure; protected String m_onHaltTarget; protected String m_failurePropertyName; protected boolean m_haltOnSkipped; protected String m_skippedPropertyName; protected boolean m_haltOnFSP; protected String m_fspPropertyName; protected String m_includedGroups; protected String m_excludedGroups; protected String m_parallelMode; protected String m_threadCount; protected String m_dataproviderthreadCount; protected String m_configFailurePolicy; protected Boolean m_randomizeSuites; public String m_useDefaultListeners; private String m_suiteName="Ant suite"; private String m_testName="Ant test"; private Boolean m_skipFailedInvocationCounts; private String m_methods; private Mode mode = Mode.testng; public enum Mode { //lower-case to better look in build scripts testng, junit, mixed } /** * The list of report listeners added via <reporter> sub-element of the Ant task */ private List reporterConfigs = Lists.newArrayList(); private String m_testNames = ""; public void setParallel(String parallel) { m_parallelMode= parallel; } public void setThreadCount(String threadCount) { m_threadCount= threadCount; } public void setDataProviderThreadCount(String dataproviderthreadCount) { m_dataproviderthreadCount = dataproviderthreadCount; } public void setUseDefaultListeners(String f) { m_useDefaultListeners= f; } // Ant task settings public void setHaltonfailure(boolean value) { m_haltOnFailure= value; } public void setOnHaltTarget(String targetName) { m_onHaltTarget= targetName; } public void setFailureProperty(String propertyName) { m_failurePropertyName= propertyName; } public void setHaltonskipped(boolean value) { m_haltOnSkipped= value; } public void setSkippedProperty(String propertyName) { m_skippedPropertyName= propertyName; } public void setHaltonFSP(boolean value) { m_haltOnFSP= value; } public void setFSPProperty(String propertyName) { m_fspPropertyName= propertyName; } public void setDelegateCommandSystemProperties(boolean value){ m_delegateCommandSystemProperties = value; } /** * Sets the flag to log the command line. When verbose is set to true * the command line parameters are stored in a temporary file stored * in the user's default temporary file directory. The file created is * prefixed with "testng". */ public void setDumpCommand(boolean verbose) { m_dump = verbose; } /** * Sets the flag to write on System.out the Ant * Environment properties. * * @param verbose true for printing */ public void setDumpEnv(boolean verbose) { m_dumpEnv= verbose; } /** * Sets te flag to write on System.out the system properties. * @param verbose true for dumping the info */ public void setDumpSys(boolean verbose) { m_dumpSys= verbose; } public void setEnableAssert(boolean flag) { m_assertEnabled= flag; } /** * The directory to invoke the VM in. * @param workingDir the directory to invoke the JVM from. */ public void setWorkingDir(File workingDir) { m_workingDir= workingDir; } /** * Sets a particular JVM to be used. Default is 'java' and is solved * by Runtime.exec(). * * @param jvm the new jvm */ public void setJvm(String jvm) { getJavaCommand().setVm(jvm); } /** * Set the timeout value (in milliseconds). * *

If the tests are running for more than this value, the tests * will be canceled. * *

* @param value the maximum time (in milliseconds) allowed before declaring the test as 'timed-out' */ public void setTimeout(Integer value) { m_timeout= value; } public Commandline.Argument createJvmarg() { return getJavaCommand().createVmArgument(); } public void addSysproperty(Environment.Variable sysp) { getJavaCommand().addSysproperty(sysp); } /** * Adds an environment variable; used when forking. */ public void addEnv(Environment.Variable var) { m_environment.addVariable(var); } /** * Adds path to classpath used for tests. * * @return reference to the classpath in the embedded java command line */ public Path createClasspath() { return getJavaCommand().createClasspath(getProject()).createPath(); } /** * Adds a path to the bootclasspath. * @return reference to the bootclasspath in the embedded java command line */ public Path createBootclasspath() { return getJavaCommand().createBootclasspath(getProject()).createPath(); } /** * Set the classpath to be used when running the Java class * * @param s an Ant Path object containing the classpath. */ public void setClasspath(Path s) { createClasspath().append(s); } /** * Classpath to use, by reference. * * @param r a reference to an existing classpath */ public void setClasspathRef(Reference r) { createClasspath().setRefid(r); } public void addXmlfileset(FileSet fs) { m_xmlFilesets.add(fs); } public void setXmlfilesetRef(Reference ref) { m_xmlFilesets.add(createResourceCollection(ref)); } public void addClassfileset(FileSet fs) { m_classFilesets.add(appendClassSelector(fs)); } public void setClassfilesetRef(Reference ref) { m_classFilesets.add(createResourceCollection(ref)); } public void setTestNames(String testNames) { m_testNames = testNames; } /** * Sets the suite runner class to invoke * @param s the name of the suite runner class */ public void setSuiteRunnerClass(String s) { m_mainClass= s; } /** * Sets the suite name * @param s the name of the suite */ public void setSuiteName(String s) { m_suiteName= s; } /** * Sets the test name * @param s the name of the test */ public void setTestName(String s) { m_testName= s; } // TestNG settings public void setJUnit(boolean value) { mode = value ? Mode.junit : Mode.testng; } // TestNG settings public void setMode(Mode mode) { this.mode = mode; } /** * Sets the test output directory * @param dir the name of directory */ public void setOutputDir(File dir) { m_outputDir= dir; } /** * Sets the test jar * @param s the name of test jar */ public void setTestJar(File s) { m_testjar= s; } public void setGroups(String groups) { m_includedGroups= groups; } public void setExcludedGroups(String groups) { m_excludedGroups= groups; } private Integer m_verbose= null; private Integer m_suiteThreadPoolSize; private String m_xmlPathInJar; public void setVerbose(Integer verbose) { m_verbose= verbose; } public void setReporter(String listener) { m_listeners.add(listener); } public void setObjectFactory(String className) { m_objectFactory = className; } public void setTestRunnerFactory(String testRunnerFactory) { m_testRunnerFactory = testRunnerFactory; } public void setSuiteThreadPoolSize(Integer n) { m_suiteThreadPoolSize = n; } /** * @deprecated Use "listeners" */ @Deprecated public void setListener(String listener) { m_listeners.add(listener); } public void setListeners(String listeners) { StringTokenizer st= new StringTokenizer(listeners, " ,"); while(st.hasMoreTokens()) { m_listeners.add(st.nextToken()); } } public void setMethodSelectors(String methodSelectors) { StringTokenizer st= new StringTokenizer(methodSelectors, " ,"); while(st.hasMoreTokens()) { m_methodselectors.add(st.nextToken()); } } public void setConfigFailurePolicy(String failurePolicy) { m_configFailurePolicy = failurePolicy; } public void setRandomizeSuites(Boolean randomizeSuites) { m_randomizeSuites = randomizeSuites; } public void setMethods(String methods) { m_methods = methods; } /** * Launches TestNG in a new JVM. * * {@inheritDoc} */ @Override public void execute() throws BuildException { validateOptions(); CommandlineJava cmd = getJavaCommand(); cmd.setClassname(m_mainClass); if(m_assertEnabled) { cmd.createVmArgument().setValue("-ea"); } if (m_delegateCommandSystemProperties) { delegateCommandSystemProperties(); } List argv = createArguments(); String fileName= ""; FileWriter fw= null; BufferedWriter bw= null; try { File f= File.createTempFile("testng", ""); fileName= f.getAbsolutePath(); // If the user asked to see the command, preserve the file if(!m_dump) { f.deleteOnExit(); } fw= new FileWriter(f); bw= new BufferedWriter(fw); for(String arg : argv) { bw.write(arg); bw.newLine(); } bw.flush(); } catch(IOException e) { e.printStackTrace(); } finally { try { if(bw != null) { bw.close(); } if(fw != null) { fw.close(); } } catch(IOException e) { e.printStackTrace(); } } printDebugInfo(fileName); createClasspath().setLocation(findJar()); cmd.createArgument().setValue("@" + fileName); ExecuteWatchdog watchdog= createWatchdog(); boolean wasKilled= false; int exitValue= executeAsForked(cmd, watchdog); if(null != watchdog) { wasKilled= watchdog.killedProcess(); } actOnResult(exitValue, wasKilled); } private List createArguments() { List argv= Lists.newArrayList(); addBooleanIfTrue(argv, CommandLineArgs.JUNIT, mode == Mode.junit); addBooleanIfTrue(argv, CommandLineArgs.MIXED, mode == Mode.mixed); addBooleanIfTrue(argv, CommandLineArgs.SKIP_FAILED_INVOCATION_COUNTS, m_skipFailedInvocationCounts); addIntegerIfNotNull(argv, CommandLineArgs.LOG, m_verbose); addDefaultListeners(argv); addOutputDir(argv); addFileIfFile(argv, CommandLineArgs.TEST_JAR, m_testjar); addStringIfNotBlank(argv, CommandLineArgs.GROUPS, m_includedGroups); addStringIfNotBlank(argv, CommandLineArgs.EXCLUDED_GROUPS, m_excludedGroups); addFilesOfRCollection(argv, CommandLineArgs.TEST_CLASS, m_classFilesets); addListOfStringIfNotEmpty(argv, CommandLineArgs.LISTENER, m_listeners); addListOfStringIfNotEmpty(argv, CommandLineArgs.METHOD_SELECTORS, m_methodselectors); addStringIfNotNull(argv, CommandLineArgs.OBJECT_FACTORY, m_objectFactory); addStringIfNotNull(argv, CommandLineArgs.TEST_RUNNER_FACTORY, m_testRunnerFactory); addStringIfNotNull(argv, CommandLineArgs.PARALLEL, m_parallelMode); addStringIfNotNull(argv, CommandLineArgs.CONFIG_FAILURE_POLICY, m_configFailurePolicy); addBooleanIfTrue(argv, CommandLineArgs.RANDOMIZE_SUITES, m_randomizeSuites); addStringIfNotNull(argv, CommandLineArgs.THREAD_COUNT, m_threadCount); addStringIfNotNull(argv, CommandLineArgs.DATA_PROVIDER_THREAD_COUNT, m_dataproviderthreadCount); addStringIfNotBlank(argv, CommandLineArgs.SUITE_NAME, m_suiteName); addStringIfNotBlank(argv, CommandLineArgs.TEST_NAME, m_testName); addStringIfNotBlank(argv, CommandLineArgs.TEST_NAMES, m_testNames); addStringIfNotBlank(argv, CommandLineArgs.METHODS, m_methods); addReporterConfigs(argv); addIntegerIfNotNull(argv, CommandLineArgs.SUITE_THREAD_POOL_SIZE, m_suiteThreadPoolSize); addStringIfNotNull(argv, CommandLineArgs.XML_PATH_IN_JAR, m_xmlPathInJar); addXmlFiles(argv); return argv; } private void addDefaultListeners(List argv) { if (m_useDefaultListeners != null) { String useDefaultListeners = "false"; if ("yes".equalsIgnoreCase(m_useDefaultListeners) || "true".equalsIgnoreCase(m_useDefaultListeners)) { useDefaultListeners = "true"; } argv.add(CommandLineArgs.USE_DEFAULT_LISTENERS); argv.add(useDefaultListeners); } } private void addOutputDir(List argv) { if (null != m_outputDir) { if (!m_outputDir.exists()) { m_outputDir.mkdirs(); } if (m_outputDir.isDirectory()) { argv.add(CommandLineArgs.OUTPUT_DIRECTORY); argv.add(m_outputDir.getAbsolutePath()); } else { throw new BuildException("Output directory is not a directory: " + m_outputDir); } } } private void addReporterConfigs(List argv) { for (ReporterConfig reporterConfig : reporterConfigs) { argv.add(CommandLineArgs.REPORTER); argv.add(reporterConfig.serialize()); } } private void addFilesOfRCollection(List argv, String name, List resources) { addArgumentsIfNotEmpty(argv, name, getFiles(resources), ","); } private void addListOfStringIfNotEmpty(List argv, String name, List arguments) { addArgumentsIfNotEmpty(argv, name, arguments, ";"); } private void addArgumentsIfNotEmpty(List argv, String name, List arguments, String separator) { if (arguments != null && !arguments.isEmpty()) { argv.add(name); String value= Utils.join(arguments, separator); argv.add(value); } } private void addFileIfFile(List argv, String name, File file) { if ((null != file) && file.isFile()) { argv.add(name); argv.add(file.getAbsolutePath()); } } private void addBooleanIfTrue(List argv, String name, Boolean value) { if (TRUE.equals(value)) { argv.add(name); } } private void addIntegerIfNotNull(List argv, String name, Integer value) { if (value != null) { argv.add(name); argv.add(value.toString()); } } private void addStringIfNotNull(List argv, String name, String value) { if (value != null) { argv.add(name); argv.add(value); } } private void addStringIfNotBlank(List argv, String name, String value) { if (isStringNotBlank(value)) { argv.add(name); argv.add(value); } } private void addXmlFiles(List argv) { for (String file : getSuiteFileNames()) { argv.add(file); } } /** * @return the list of the XML file names. This method can be overridden by subclasses. */ protected List getSuiteFileNames() { List result = Lists.newArrayList(); for(String file : getFiles(m_xmlFilesets)) { result.add(file); } return result; } private void delegateCommandSystemProperties() { // Iterate over command-line args and pass them through as sysproperty // exclude any built-in properties that start with "ant." for (Object propKey : getProject().getUserProperties().keySet()) { String propName = (String) propKey; String propVal = getProject().getUserProperty(propName); if (propName.startsWith("ant.")) { log("Excluding ant property: " + propName + ": " + propVal, Project.MSG_DEBUG); } else { log("Including user property: " + propName + ": " + propVal, Project.MSG_DEBUG); Environment.Variable var = new Environment.Variable(); var.setKey(propName); var.setValue(propVal); addSysproperty(var); } } } private void printDebugInfo(String fileName) { if(m_dumpSys) { System.out.println("* SYSTEM PROPERTIES *"); Properties props= System.getProperties(); Enumeration en= props.propertyNames(); while(en.hasMoreElements()) { String key= (String) en.nextElement(); System.out.println(key + ": " + props.getProperty(key)); } System.out.println(""); } if(m_dumpEnv) { String[] vars= m_environment.getVariables(); if(null != vars && vars.length > 0) { System.out.println("* ENVIRONMENT *"); for(String v: vars) { System.out.println(v); } System.out.println(""); } } if(m_dump) { dumpCommand(fileName); } } private void ppp(String string) { System.out.println("[TestNGAntTask] " + string); } protected void actOnResult(int exitValue, boolean wasKilled) { if(exitValue == -1) { executeHaltTarget(exitValue); throw new BuildException("an error occured when running TestNG tests"); } if((exitValue & TestNG.HAS_NO_TEST) == TestNG.HAS_NO_TEST) { if(m_haltOnFailure) { executeHaltTarget(exitValue); throw new BuildException("No tests were run"); } else { if(null != m_failurePropertyName) { getProject().setNewProperty(m_failurePropertyName, "true"); } log("TestNG haven't found any tests to be run", Project.MSG_DEBUG); } } boolean failed= ((exitValue & TestNG.HAS_FAILURE) == TestNG.HAS_FAILURE) || wasKilled; if(failed) { final String msg= wasKilled ? "The tests timed out and were killed." : "The tests failed."; if(m_haltOnFailure) { executeHaltTarget(exitValue); throw new BuildException(msg); } else { if(null != m_failurePropertyName) { getProject().setNewProperty(m_failurePropertyName, "true"); } log(msg, Project.MSG_INFO); } } if((exitValue & TestNG.HAS_SKIPPED) == TestNG.HAS_SKIPPED) { if(m_haltOnSkipped) { executeHaltTarget(exitValue); throw new BuildException("There are TestNG SKIPPED tests"); } else { if(null != m_skippedPropertyName) { getProject().setNewProperty(m_skippedPropertyName, "true"); } log("There are TestNG SKIPPED tests", Project.MSG_DEBUG); } } if((exitValue & TestNG.HAS_FSP) == TestNG.HAS_FSP) { if(m_haltOnFSP) { executeHaltTarget(exitValue); throw new BuildException("There are TestNG FAILED WITHIN SUCCESS PERCENTAGE tests"); } else { if(null != m_fspPropertyName) { getProject().setNewProperty(m_fspPropertyName, "true"); } log("There are TestNG FAILED WITHIN SUCCESS PERCENTAGE tests", Project.MSG_DEBUG); } } } /** Executes the target, if any, that user designates executing before failing the test */ private void executeHaltTarget(int exitValue) { if(m_onHaltTarget != null) { if(m_outputDir != null) { getProject().setProperty("testng.outputdir", m_outputDir.getAbsolutePath()); } getProject().setProperty("testng.returncode", String.valueOf(exitValue)); Target t= (Target) getProject().getTargets().get(m_onHaltTarget); if(t != null) { t.execute(); } } } /** * Executes the command line as a new process. * * @param cmd the command to execute * @param watchdog * @return the exit status of the subprocess or INVALID. */ protected int executeAsForked(CommandlineJava cmd, ExecuteWatchdog watchdog) { Execute execute= new Execute(new TestNGLogSH(this, Project.MSG_INFO, Project.MSG_WARN, (m_verbose == null || m_verbose < 5)), watchdog); execute.setCommandline(cmd.getCommandline()); execute.setAntRun(getProject()); if(m_workingDir != null) { if(m_workingDir.exists() && m_workingDir.isDirectory()) { execute.setWorkingDirectory(m_workingDir); } else { log("Ignoring invalid working directory : " + m_workingDir, Project.MSG_WARN); } } String[] environment= m_environment.getVariables(); if(null != environment) { for(String envEntry : environment) { log("Setting environment variable: " + envEntry, Project.MSG_VERBOSE); } } execute.setEnvironment(environment); log(cmd.describeCommand(), Project.MSG_VERBOSE); int retVal; try { retVal= execute.execute(); } catch(IOException e) { throw new BuildException("Process fork failed.", e, getLocation()); } return retVal; } /** * Creates or returns the already created CommandlineJava. */ protected CommandlineJava getJavaCommand() { if(null == m_javaCommand) { m_javaCommand = new CommandlineJava(); } return m_javaCommand; } /** * @return null if there is no timeout value, otherwise the * watchdog instance. * * @throws BuildException under unspecified circumstances * @since Ant 1.2 */ protected ExecuteWatchdog createWatchdog() /*throws BuildException*/ { if(m_timeout == null) { return null; } return new ExecuteWatchdog(m_timeout.longValue()); } protected void validateOptions() throws BuildException { int suiteCount = getSuiteFileNames().size(); if (suiteCount == 0 && m_classFilesets.size() == 0 && Utils.isStringEmpty(m_methods) && ((null == m_testjar) || !m_testjar.isFile())) { throw new BuildException("No suites, classes, methods or jar file was specified."); } if((null != m_includedGroups) && (m_classFilesets.size() == 0 && suiteCount == 0)) { throw new BuildException("No class filesets or xml file sets specified while using groups"); } if(m_onHaltTarget != null) { if(!getProject().getTargets().containsKey(m_onHaltTarget)) { throw new BuildException("Target " + m_onHaltTarget + " not found in this project"); } } } private ResourceCollection createResourceCollection(Reference ref) { Object o = ref.getReferencedObject(); if (!(o instanceof ResourceCollection)) { throw new BuildException("Only File based ResourceCollections are supported."); } ResourceCollection rc = (ResourceCollection) o; if (!rc.isFilesystemOnly()) { throw new BuildException("Only ResourceCollections from local file system are supported."); } return rc; } private FileSet appendClassSelector(FileSet fs) { FilenameSelector selector= new FilenameSelector(); selector.setName("**/*.class"); selector.setProject(getProject()); fs.appendSelector(selector); return fs; } private File findJar() { Class thisClass= getClass(); String resource= thisClass.getName().replace('.', '/') + ".class"; URL url= thisClass.getClassLoader().getResource(resource); if(null != url) { String u= url.toString(); if(u.startsWith("jar:file:")) { int pling= u.indexOf("!"); String jarName= u.substring(4, pling); return new File(fromURI(jarName)); } else if(u.startsWith("file:")) { int tail= u.indexOf(resource); String dirName= u.substring(0, tail); return new File(fromURI(dirName)); } } return null; } private String fromURI(String uri) { URL url= null; try { url= new URL(uri); } catch(MalformedURLException murle) { } if((null == url) || !("file".equals(url.getProtocol()))) { throw new IllegalArgumentException("Can only handle valid file: URIs"); } StringBuffer buf= new StringBuffer(url.getHost()); if(buf.length() > 0) { buf.insert(0, File.separatorChar).insert(0, File.separatorChar); } String file= url.getFile(); int queryPos= file.indexOf('?'); buf.append((queryPos < 0) ? file : file.substring(0, queryPos)); uri= buf.toString().replace('/', File.separatorChar); if((File.pathSeparatorChar == ';') && uri.startsWith("\\") && (uri.length() > 2) && Character.isLetter(uri.charAt(1)) && (uri.lastIndexOf(':') > -1)) { uri= uri.substring(1); } StringBuffer sb= new StringBuffer(); CharacterIterator iter= new StringCharacterIterator(uri); for(char c= iter.first(); c != CharacterIterator.DONE; c= iter.next()) { if(c == '%') { char c1= iter.next(); if(c1 != CharacterIterator.DONE) { int i1= Character.digit(c1, 16); char c2= iter.next(); if(c2 != CharacterIterator.DONE) { int i2= Character.digit(c2, 16); sb.append((char) ((i1 << 4) + i2)); } } } else { sb.append(c); } } return sb.toString(); } /** * Returns the list of files corresponding to the resource collection * * @param resources * @return the list of files corresponding to the resource collection * @throws BuildException */ private List getFiles(List resources) throws BuildException { List files= Lists.newArrayList(); for (ResourceCollection rc : resources) { for (Iterator i = rc.iterator(); i.hasNext();) { Object o = i.next(); if (o instanceof FileResource) { FileResource fr = ((FileResource) o); if (fr.isDirectory()) { throw new BuildException("Directory based FileResources are not supported."); } if (!fr.isExists()) { log("'" + fr.toLongString() + "' does not exist", Project.MSG_VERBOSE); } files.add(fr.getFile().getAbsolutePath()); } else { log("Unsupported Resource type: " + o.toString(), Project.MSG_VERBOSE); } } } return files; } /** * Returns the list of files corresponding to the fileset * * @param filesets * @return the list of files corresponding to the fileset * @throws BuildException */ private List fileset(FileSet fileset) throws BuildException { List files= Lists.newArrayList(); DirectoryScanner ds= fileset.getDirectoryScanner(getProject()); for(String file : ds.getIncludedFiles()) { files.add(ds.getBasedir() + File.separator + file); } return files; } /** * Adds double quotes to the command line argument if it contains spaces. * @param pCommandLineArg the command line argument * @return pCommandLineArg in double quotes if it contains space. * */ private static String doubleQuote(String pCommandLineArg) { if(pCommandLineArg.indexOf(" ") != -1 && !(pCommandLineArg.startsWith("\"") && pCommandLineArg.endsWith("\""))) { return "\"" + pCommandLineArg + '\"'; } return pCommandLineArg; } /** * Creates a string representation of the path. */ private String createPathString(Path path, String sep) { if(path == null) { return null; } final StringBuffer buf= new StringBuffer(); for(int i= 0; i < path.list().length; i++) { File file= getProject().resolveFile(path.list()[i]); if(!file.exists()) { log("Classpath entry not found: " + file, Project.MSG_WARN); } buf.append(file.getAbsolutePath()).append(sep); } if(path.list().length > 0) { // cut the last ; buf.deleteCharAt(buf.length() - 1); } return buf.toString(); } private void dumpCommand(String fileName) { ppp("TESTNG PASSED @" + fileName + " WHICH CONTAINS:"); readAndPrintFile(fileName); } private void readAndPrintFile(String fileName) { File file = new File(fileName); BufferedReader br = null; try { br = new BufferedReader(new FileReader(file)); String line = br.readLine(); while (line != null) { System.out.println(" " + line); line = br.readLine(); } } catch(IOException ex) { ex.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } public void addConfiguredReporter(ReporterConfig reporterConfig) { reporterConfigs.add(reporterConfig); } public void setSkipFailedInvocationCounts(boolean skip) { m_skipFailedInvocationCounts = skip; } public void setXmlPathInJar(String path) { m_xmlPathInJar = path; } /** * Add the referenced property set as system properties for the TestNG JVM. * * @param sysPropertySet A PropertySet of system properties. */ public void addConfiguredPropertySet(PropertySet sysPropertySet) { Properties properties = sysPropertySet.getProperties(); log(properties.keySet().size() + " properties found in nested propertyset", Project.MSG_VERBOSE); for (Object propKeyObj : properties.keySet()) { String propKey = (String) propKeyObj; Environment.Variable sysProp = new Environment.Variable(); sysProp.setKey(propKey); if (properties.get(propKey) instanceof String) { String propVal = (String) properties.get(propKey); sysProp.setValue(propVal); getJavaCommand().addSysproperty(sysProp); log("Added system property " + propKey + " with value " + propVal, Project.MSG_VERBOSE); } else { log("Ignoring non-String property " + propKey, Project.MSG_WARN); } } } @Override protected void handleOutput(String output) { if (output.startsWith(VerboseReporter.LISTENER_PREFIX)) { //send everything from VerboseReporter to verbose level unless log level is > 4 log(output, m_verbose < 5 ? Project.MSG_VERBOSE : Project.MSG_INFO); } else { super.handleOutput(output); } } private static class TestNGLogOS extends LogOutputStream { private Task task; private boolean verbose; public TestNGLogOS(Task task, int level, boolean verbose) { super(task, level); this.task = task; this.verbose = verbose; } @Override protected void processLine(String line, int level) { if (line.startsWith(VerboseReporter.LISTENER_PREFIX)) { task.log(line, verbose ? Project.MSG_VERBOSE : Project.MSG_INFO); } else { super.processLine(line, level); } } } protected static class TestNGLogSH extends PumpStreamHandler { public TestNGLogSH(Task task, int outlevel, int errlevel, boolean verbose) { super(new TestNGLogOS(task, outlevel, verbose), new LogOutputStream(task, errlevel)); } } } testng-6.9.12/src/main/java/org/testng/IExecutionListener.java0000644000175000017500000000057112732165123023600 0ustar eugeneeugenepackage org.testng; /** * A listener used to monitor when a TestNG run starts and ends. * * @author Cedric Beust */ public interface IExecutionListener extends ITestNGListener { /** * Invoked before the TestNG run starts. */ void onExecutionStart(); /** * Invoked once all the suites have been run. */ void onExecutionFinish(); } testng-6.9.12/src/main/java/org/testng/IInvokedMethod.java0000755000175000017500000000121012732165123022661 0ustar eugeneeugenepackage org.testng; /** * An interface representing a method that has been invoked by TestNG. * * This interface is internal. */ public interface IInvokedMethod { /** * @return true if this method is a test method */ public abstract boolean isTestMethod(); /** * @return true if this method is a configuration method (@BeforeXXX or @AfterXXX) */ public abstract boolean isConfigurationMethod(); /** * @return the test method */ public abstract ITestNGMethod getTestMethod(); public ITestResult getTestResult(); /** * @return the date when this method was run */ public abstract long getDate(); }testng-6.9.12/src/main/java/org/testng/FileAssert.java0000755000175000017500000002267112732165123022067 0ustar eugeneeugenepackage org.testng; import java.io.File; import java.io.IOException; /** * Assertion tool for File centric assertions. * Conceptually this is an extension of {@link Assert} * Presents assertion methods with a more natural parameter order. * The order is always actualValue, expectedValue [, message]. * * @author Paul Mendelon * @since 5.6 * @version $Revision: 650 $, $Date: 2009-01-05 03:51:54 -0800 (Mon, 05 Jan 2009) $ */ public class FileAssert { /** * Protect constructor since it is a static only class */ private FileAssert() { // hide constructor } /** * Asserts that a {@code tstvalue} is a proper directory. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertDirectory(File tstvalue, String message) { boolean condition=false; try { condition=tstvalue.isDirectory(); } catch(SecurityException e) { failSecurity(e,tstvalue,fileType(tstvalue),"Directory", message); } if(!condition) { failFile(tstvalue,fileType(tstvalue),"Directory", message); } } static public void assertDirectory(File tstvalue) { assertDirectory(tstvalue, null); } /** * Asserts that a {@code tstvalue} is a proper file. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertFile(File tstvalue, String message) { boolean condition=false; try { condition=tstvalue.isFile(); } catch(SecurityException e) { failSecurity(e,tstvalue,fileType(tstvalue),"File", message); } if(!condition) { failFile(tstvalue,fileType(tstvalue),"File", message); } } /** * @see #assertFile(File, String) */ static public void assertFile(File tstvalue) { assertFile(tstvalue, null); } /** * Asserts that a {@code tstvalue} is a file of exactly {@code expected} characters * or a directory of exactly {@code expected} entries. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertLength(File tstvalue, long expected, String message) { long actual=-1L; try { actual=tstvalue.isDirectory()?tstvalue.list().length:tstvalue.length(); } catch(SecurityException e) { failSecurity(e,tstvalue,String.valueOf(actual),String.valueOf(expected), message); } if(actual!=expected) { failFile(tstvalue,String.valueOf(actual),String.valueOf(expected), message); } } /** * @see #assertLength(File, long, String) */ static public void assertLength(File tstvalue, long expected) { assertLength(tstvalue, expected, null); } /** * Asserts that a {@code tstvalue} is a file of at least {@code expected} characters * or a directory of at least {@code expected} entries. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertMinLength(File tstvalue, long expected, String message) { long actual=-1L; try { actual=tstvalue.isDirectory()?tstvalue.list().length:tstvalue.length(); } catch(SecurityException e) { failSecurity(e,tstvalue,String.valueOf(actual),"at least "+String.valueOf(expected), message); } if(actualexpected) { failFile(tstvalue,String.valueOf(actual),"at most "+String.valueOf(expected), message); } } /** * @see #assertMaxLength(File, long, String) */ static public void assertMaxLength(File tstvalue, long expected) { assertMaxLength(tstvalue, expected, null); } /** * Asserts that a {@code tstvalue} is readable. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertReadable(File tstvalue, String message) { boolean condition=false; try { condition=tstvalue.canRead(); } catch(SecurityException e) { failSecurity(e,tstvalue,fileAccess(tstvalue),"Read Access", message); } if(!condition) { failFile(tstvalue,fileAccess(tstvalue),"Read Access", message); } } /** * @see #assertReadable(File, String) */ static public void assertReadable(File tstvalue) { assertReadable(tstvalue, null); } /** * Asserts that a {@code tstvalue} is writeable. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertWriteable(File tstvalue, String message) { boolean condition=false; try { condition=tstvalue.canWrite(); } catch(SecurityException e) { failSecurity(e,tstvalue,fileAccess(tstvalue),"Write Access", message); } if(!condition) { failFile(tstvalue,fileAccess(tstvalue),"Write Access", message); } } /** * @see #assertWriteable(File, String) */ static public void assertWriteable(File tstvalue) { assertReadable(tstvalue, null); } /** * Asserts that a {@code tstvalue} is readable and writeable. If it isn't, * an AssertionError, with the given message, is thrown. * @param tstvalue the file to evaluate * @param message the assertion error message */ static public void assertReadWrite(File tstvalue, String message) { boolean condition=false; try { condition=tstvalue.canRead() && tstvalue.canWrite(); } catch(SecurityException e) { failSecurity(e,tstvalue,fileAccess(tstvalue),"Read/Write Access", message); } if(!condition) { failFile(tstvalue,fileAccess(tstvalue),"Read/Write Access", message); } } /** * @see #assertReadWrite(File, String) */ static public void assertReadWrite(File tstvalue) { assertReadWrite(tstvalue, null); } /** * Fails a test with the given message and wrapping the original exception. * * @param message the assertion error message * @param realCause the original exception */ static public void fail(String message, Throwable realCause) { AssertionError ae = new AssertionError(message); ae.initCause(realCause); throw ae; } /** * Fails a test with the given message. * @param message the assertion error message */ static public void fail(String message) { throw new AssertionError(message); } /** * Fails a test with no message. */ static public void fail() { fail(null); } /** * Formats failure for file assertions */ private static void failFile(File path, String actual, String expected, String message) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + "expected <" + expected +"> but was <" + toString(path) + ">" +(expected!=null?"<" + expected +">":"")); } /** * @param tstvalue * @param string * @param string2 * @param message */ private static void failSecurity(Exception e, File path, String actual, String expected, String message) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + "expected <" + expected +"> but was <" + toString(path) + ">" +"<" + (e!=null && e.getMessage()!=null && e.getMessage().length()>0 ?e.getMessage() :"not authorized by JVM") + ">"); } /** * String representation of what sort of file {@code path} is. */ private static String fileType(File path) { try { if(!path.exists()) { return "Non existant"; } else if (path.isDirectory()) { return "Directory"; } else if (path.isFile()) { return "File"; } else { return "Special File"; } } catch (SecurityException e) { return "Unauthorized"; } } /** * String representation of what sort of file {@code path} is. */ private static String fileAccess(File path) { try { if(!path.exists()) { return "Non existant"; } else if (path.canWrite() && path.canRead()) { return "Read/Write Access"; } else if (path.canRead()) { return "Read only Access"; } else if (path.canWrite()) { return "Write only Access"; } else { return "No Access"; } } catch (SecurityException e) { return "Unauthorized"; } } private static String toString(File path) { try { return path.getCanonicalPath(); } catch(IOException e) { return path.getAbsolutePath(); } } } testng-6.9.12/src/main/java/org/testng/IAnnotationTransformer2.java0000755000175000017500000000315712732165123024554 0ustar eugeneeugenepackage org.testng; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IFactoryAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * Use this interface instead of IAnnotationTransformer if you want to modify any TestNG * annotation besides @Test. */ public interface IAnnotationTransformer2 extends IAnnotationTransformer { /** * Transform an IConfiguration annotation. * * Note that only one of the three parameters testClass, * testConstructor and testMethod will be non-null. * * @param annotation The annotation that was read from your * test class. * @param testClass If the annotation was found on a class, this * parameter represents this class (null otherwise). * @param testConstructor If the annotation was found on a constructor, * this parameter represents this constructor (null otherwise). * @param testMethod If the annotation was found on a method, * this parameter represents this method (null otherwise). */ public void transform(IConfigurationAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod); /** * Transform an IDataProvider annotation. * * @param method The method annotated with the IDataProvider annotation. */ public void transform(IDataProviderAnnotation annotation, Method method); /** * Transform an IFactory annotation. * * @param method The method annotated with the IFactory annotation. */ public void transform(IFactoryAnnotation annotation, Method method); } testng-6.9.12/src/main/java/org/testng/ITestListener.java0000755000175000017500000000365612732165123022566 0ustar eugeneeugenepackage org.testng; /** * A listener for test running. * * @author Cedric Beust * @author Alexandru Popescu * @author Hani Suleiman */ public interface ITestListener extends ITestNGListener { /** * Invoked each time before a test will be invoked. * The ITestResult is only partially filled with the references to * class, method, start millis and status. * * @param result the partially filled ITestResult * @see ITestResult#STARTED */ void onTestStart(ITestResult result); /** * Invoked each time a test succeeds. * * @param result ITestResult containing information about the run test * @see ITestResult#SUCCESS */ public void onTestSuccess(ITestResult result); /** * Invoked each time a test fails. * * @param result ITestResult containing information about the run test * @see ITestResult#FAILURE */ public void onTestFailure(ITestResult result); /** * Invoked each time a test is skipped. * * @param result ITestResult containing information about the run test * @see ITestResult#SKIP */ public void onTestSkipped(ITestResult result); /** * Invoked each time a method fails but has been annotated with * successPercentage and this failure still keeps it within the * success percentage requested. * * @param result ITestResult containing information about the run test * @see ITestResult#SUCCESS_PERCENTAGE_FAILURE */ public void onTestFailedButWithinSuccessPercentage(ITestResult result); /** * Invoked after the test class is instantiated and before * any configuration method is called. */ public void onStart(ITestContext context); /** * Invoked after all the tests have run and all their * Configuration methods have been called. */ public void onFinish(ITestContext context); } testng-6.9.12/src/main/java/org/testng/IReporter.java0000755000175000017500000000111712732165123021731 0ustar eugeneeugenepackage org.testng; import org.testng.xml.XmlSuite; import java.util.List; /** * This interface can be implemented by clients to generate a report. Its method * generateReport() will be invoked after all the suite have run and the parameters * give all the test results that happened during that run. * * @author cbeust * Feb 17, 2006 */ public interface IReporter extends ITestNGListener { /** * Generate a report for the given suites into the specified output directory. */ void generateReport(List xmlSuites, List suites, String outputDirectory); } testng-6.9.12/src/main/java/org/testng/PreserveOrderMethodInterceptor.java0000644000175000017500000000160712732165123026166 0ustar eugeneeugenepackage org.testng; import org.testng.internal.MethodInstance; import java.util.Collections; import java.util.List; /** * A method interceptor that preserves the order in which test classes were found in * the <test> tag. * * @author cbeust * */ class PreserveOrderMethodInterceptor implements IMethodInterceptor { private void p(List methods, String s) { System.out.println("[PreserveOrderMethodInterceptor] " + s); for (IMethodInstance mi : methods) { System.out.println(" " + mi.getMethod().getMethodName() + " index:" + mi.getMethod().getTestClass().getXmlClass().getIndex()); } } @Override public List intercept(List methods, ITestContext context) { // p(methods, "Before"); Collections.sort(methods, MethodInstance.SORT_BY_INDEX); // p(methods, "After"); return methods; } } testng-6.9.12/src/main/java/org/testng/util/0000755000175000017500000000000012732165123020125 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/util/RetryAnalyzerCount.java0000755000175000017500000000245312732165123024623 0ustar eugeneeugenepackage org.testng.util; import java.util.concurrent.atomic.AtomicInteger; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; /** * An implementation of IRetryAnalyzer that allows you to specify * the maximum number of times you want your test to be retried. * * @author tocman@gmail.com (Jeremie Lenfant-Engelmann) */ public abstract class RetryAnalyzerCount implements IRetryAnalyzer { // Default retry once. AtomicInteger count = new AtomicInteger(1); /** * Set the max number of time the method needs to be retried. */ protected void setCount(int count) { this.count.set(count); } /** * Return the current counter value */ protected int getCount(){ return this.count.get(); } /** * Retries the test if count is not 0. * @param result The result of the test. */ @Override public boolean retry(ITestResult result) { if (count.getAndDecrement() > 0) { return retryMethod(result); } return false; } /** * The method implemented by the class that test if the test * must be retried or not. * @param result The result of the test. * @return true if the test must be retried, false otherwise. */ public abstract boolean retryMethod(ITestResult result); } testng-6.9.12/src/main/java/org/testng/util/Strings.java0000644000175000017500000000201512732165123022417 0ustar eugeneeugenepackage org.testng.util; import org.testng.collections.Lists; import org.testng.collections.Maps; import java.util.List; import java.util.Map; public class Strings { public static boolean isNullOrEmpty(String string) { return string == null || string.length() == 0; // string.isEmpty() in Java 6 } private static List ESCAPE_HTML_LIST = Lists.newArrayList( "&", "&", "<", "<", ">", ">" ); private static final Map ESCAPE_HTML_MAP = Maps.newLinkedHashMap(); static { for (int i = 0; i < ESCAPE_HTML_LIST.size(); i += 2) { ESCAPE_HTML_MAP.put(ESCAPE_HTML_LIST.get(i), ESCAPE_HTML_LIST.get(i + 1)); } } public static String escapeHtml(String text) { String result = text; for (Map.Entry entry : ESCAPE_HTML_MAP.entrySet()) { result = result.replace(entry.getKey(), entry.getValue()); } return result; } public static void main(String[] args) { System.out.println(escapeHtml("10 < 20 && 30 > 20")); } } testng-6.9.12/src/main/java/org/testng/ITestNGMethod.java0000755000175000017500000001627512732165123022447 0ustar eugeneeugenepackage org.testng; import org.testng.internal.ConstructorOrMethod; import org.testng.xml.XmlTest; import java.io.Serializable; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; /** * Describes a TestNG annotated method and the instance on which it will be invoked. * * This interface is not meant to be implemented by users. * * @author Cedric Beust, May 3, 2004 */ public interface ITestNGMethod extends Comparable, Serializable, Cloneable { /** * @return The real class on which this method was declared * (can be different from getMethod().getDeclaringClass() if * the test method was defined in a superclass). */ Class getRealClass(); ITestClass getTestClass(); /** * Sets the test class having this method. This is not necessarily the declaring class. * * @param cls The test class having this method. */ void setTestClass(ITestClass cls); /** * @return the corresponding Java test method. * @deprecated This method is deprecated and can now return null. Use * getConstructorOrMethod() instead. */ @Deprecated Method getMethod(); /** * Returns the method name. This is needed for serialization because * methods are not Serializable. * @return the method name. */ String getMethodName(); /** * @return All the instances the methods will be invoked upon. * This will typically be an array of one object in the absence * of an @Factory annotation. * * @deprecated Use getInstance(). */ @Deprecated Object[] getInstances(); Object getInstance(); /** * Needed for serialization. */ long[] getInstanceHashCodes(); /** * @return The groups this method belongs to, possibly added to the groups * declared on the class. */ String[] getGroups(); /** * @return The groups this method depends on, possibly added to the groups * declared on the class. */ String[] getGroupsDependedUpon(); /** * If a group was not found. */ String getMissingGroup(); public void setMissingGroup(String group); /** * Before and After groups */ public String[] getBeforeGroups(); public String[] getAfterGroups(); /** * @return The methods this method depends on, possibly added to the methods * declared on the class. */ String[] getMethodsDependedUpon(); void addMethodDependedUpon(String methodName); /** * @return true if this method was annotated with @Test */ boolean isTest(); /** * @return true if this method was annotated with @Configuration * and beforeTestMethod = true */ boolean isBeforeMethodConfiguration(); /** * @return true if this method was annotated with @Configuration * and beforeTestMethod = false */ boolean isAfterMethodConfiguration(); /** * @return true if this method was annotated with @Configuration * and beforeClassMethod = true */ boolean isBeforeClassConfiguration(); /** * @return true if this method was annotated with @Configuration * and beforeClassMethod = false */ boolean isAfterClassConfiguration(); /** * @return true if this method was annotated with @Configuration * and beforeSuite = true */ boolean isBeforeSuiteConfiguration(); /** * @return true if this method was annotated with @Configuration * and afterSuite = true */ boolean isAfterSuiteConfiguration(); /** * @return true if this method is a @BeforeTest (@Configuration beforeTest=true) */ boolean isBeforeTestConfiguration(); /** * @return true if this method is an @AfterTest (@Configuration afterTest=true) */ boolean isAfterTestConfiguration(); boolean isBeforeGroupsConfiguration(); boolean isAfterGroupsConfiguration(); /** * @return The timeout in milliseconds. */ long getTimeOut(); void setTimeOut(long timeOut); /** * @return the number of times this method needs to be invoked. */ int getInvocationCount(); void setInvocationCount(int count); /** * @return the total number of thimes this method needs to be invoked, including possible * clones of this method - this is relevant when threadPoolSize is bigger than 1 * where each clone of this method is only invoked once individually, i.e. * {@link org.testng.ITestNGMethod#getInvocationCount()} would always return 1. */ int getTotalInvocationCount(); /** * @return the success percentage for this method (between 0 and 100). */ int getSuccessPercentage(); /** * @return The id of the thread this method was run in. */ String getId(); void setId(String id); long getDate(); void setDate(long date); /** * Returns if this ITestNGMethod can be invoked from within IClass. */ boolean canRunFromClass(IClass testClass); /** * @return true if this method is alwaysRun=true */ boolean isAlwaysRun(); /** * @return the number of threads to be used when invoking the method on parallel */ int getThreadPoolSize(); void setThreadPoolSize(int threadPoolSize); boolean getEnabled(); public String getDescription(); void setDescription(String description); public void incrementCurrentInvocationCount(); public int getCurrentInvocationCount(); public void setParameterInvocationCount(int n); public int getParameterInvocationCount(); void setMoreInvocationChecker(Callable moreInvocationChecker); boolean hasMoreInvocation(); public ITestNGMethod clone(); public IRetryAnalyzer getRetryAnalyzer(); public void setRetryAnalyzer(IRetryAnalyzer retryAnalyzer); public boolean skipFailedInvocations(); public void setSkipFailedInvocations(boolean skip); /** * The time under which all invocationCount methods need to complete by. */ public long getInvocationTimeOut(); public boolean ignoreMissingDependencies(); public void setIgnoreMissingDependencies(boolean ignore); /** * Which invocation numbers of this method should be used (only applicable * if it uses a data provider). If this value is an empty list, use all the values * returned from the data provider. These values are read from the XML file in * the tag. */ public List getInvocationNumbers(); public void setInvocationNumbers(List numbers); /** * The list of invocation numbers that failed, which is only applicable for * methods that have a data provider. */ public void addFailedInvocationNumber(int number); public List getFailedInvocationNumbers(); /** * The scheduling priority. Lower priorities get scheduled first. */ public int getPriority(); public void setPriority(int priority); /** * @return the XmlTest this method belongs to. */ public XmlTest getXmlTest(); ConstructorOrMethod getConstructorOrMethod(); /** * @return the parameters found in the include tag, if any * @param test */ Map findMethodParameters(XmlTest test); } testng-6.9.12/src/main/java/org/testng/IMethodSelector.java0000755000175000017500000000235412732165123023054 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; import java.util.List; /** * This interface is used to augment or replace TestNG's algorithm to * decide whether a test method should be included in a test run. * * Created on Sep 26, 2005 * @author cbeust */ public interface IMethodSelector extends Serializable { /** * @param context The selector context. The implementation of this method * can invoke setHalted(true) to indicate that no other Method Selector * should be invoked by TestNG after this one. Additionally, this * implementation can manipulate the Map object returned by * getUserData(). * @param method The test method * @param isTestMethod true if this is a @Test method, false if it's a * configuration method * @return true if this method should be included in the test run, false * otherwise */ public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod method, boolean isTestMethod); /** * Invoked when all the test methods are known so that the method selector * can perform additional work, such as adding the transitive closure of * all the groups being included and depended upon. */ public void setTestMethods(List testMethods); } testng-6.9.12/src/main/java/org/testng/ISuiteResult.java0000755000175000017500000000065212732165123022422 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; /** * This class represents the result of a suite run. * * @author Cedric Beust, Aug 6, 2004 * */ public interface ISuiteResult extends Serializable { /** * @return The name of the property file for these tests. */ public String getPropertyFileName(); /** * @return The testing context for these tests. */ public ITestContext getTestContext(); } testng-6.9.12/src/main/java/org/testng/ITestNGListenerFactory.java0000644000175000017500000000072712732165123024334 0ustar eugeneeugenepackage org.testng; /** * A factory used to create instances of ITestNGListener. Users can implement this interface * in any of their test classes but there can be only one such instance. */ public interface ITestNGListenerFactory { /** * Create and return an instance of the listener class passed in parameter. Return null * if you want to use the default factory. */ ITestNGListener createListener(Class listenerClass); } testng-6.9.12/src/main/java/org/testng/SuiteResult.java0000755000175000017500000000310512732165123022305 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Objects; import org.testng.xml.XmlSuite; /** * This class logs the result of an entire Test Suite (defined by a * property file). * * @author Cedric Beust, May 10, 2004 * */ class SuiteResult implements ISuiteResult, Comparable { /* generated */ private static final long serialVersionUID = 6778513869858860756L; //FIXME: Is m_propertyFileName needed? private String m_propertyFileName = null; private XmlSuite m_suite = null; private ITestContext m_testContext = null; protected SuiteResult(XmlSuite suite, ITestContext tr) { m_suite = suite; m_testContext = tr; } /** * @return Returns the propertyFileName. */ @Override public String getPropertyFileName() { return m_propertyFileName; } /** * @return Returns the singleTestRunner. */ @Override public ITestContext getTestContext() { return m_testContext; } /** * @return Returns the suite. */ public XmlSuite getSuite() { return m_suite; } @Override public int compareTo(Object o) { int result = 0; try { SuiteResult other = (SuiteResult) o; String n1 = getTestContext().getName(); String n2 = other.getTestContext().getName(); result = n1.compareTo(n2); } catch(Exception ex) { ex.printStackTrace(); } return result; } /** * Returns the test context name. * {@inheritDoc} */ @Override public String toString() { return Objects.toStringHelper(getClass()) .add("context", getTestContext().getName()) .toString(); } } testng-6.9.12/src/main/java/org/testng/ISuiteListener.java0000755000175000017500000000062612732165123022732 0ustar eugeneeugenepackage org.testng; /** * Listener for test suites. * * @author Cedric Beust, Aug 6, 2004 * */ public interface ISuiteListener extends ITestNGListener { /** * This method is invoked before the SuiteRunner starts. */ public void onStart(ISuite suite); /** * This method is invoked after the SuiteRunner has run all * the test suites. */ public void onFinish(ISuite suite); } testng-6.9.12/src/main/java/org/testng/IAnnotationTransformer.java0000755000175000017500000000221312732165123024462 0ustar eugeneeugenepackage org.testng; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public interface IAnnotationTransformer extends ITestNGListener { /** * This method will be invoked by TestNG to give you a chance * to modify a TestNG annotation read from your test classes. * You can change the values you need by calling any of the * setters on the ITest interface. * * Note that only one of the three parameters testClass, * testConstructor and testMethod will be non-null. * * @param annotation The annotation that was read from your * test class. * @param testClass If the annotation was found on a class, this * parameter represents this class (null otherwise). * @param testConstructor If the annotation was found on a constructor, * this parameter represents this constructor (null otherwise). * @param testMethod If the annotation was found on a method, * this parameter represents this method (null otherwise). */ public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod); } testng-6.9.12/src/main/java/org/testng/TestNGUtils.java0000755000175000017500000000064212732165123022205 0ustar eugeneeugenepackage org.testng; import org.testng.internal.ClonedMethod; import java.lang.reflect.Method; public class TestNGUtils { /** * Create an ITestNGMethod for @code{method} based on @code{existingMethod}, which needs * to belong to the same class. */ public static ITestNGMethod createITestNGMethod(ITestNGMethod existingMethod, Method method) { return new ClonedMethod(existingMethod, method); } } testng-6.9.12/src/main/java/org/testng/TestListenerAdapter.java0000755000175000017500000001263612732165123023754 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Lists; import org.testng.collections.Objects; import org.testng.internal.IResultListener2; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * A simple ITestListener adapter that stores all the tests * that were run. You can retrieve these results with the * following methods: * getPassedTests() * getFailedTests() * getSkippedTests() * * If you extend this class in order to override any of these * methods, remember to call their super equivalent if you want * this list of tests to be maintained. * * @author Cedric Beust, Aug 6, 2004 * @author Alexandru Popescu */ public class TestListenerAdapter implements IResultListener2 { private List m_allTestMethods = Collections.synchronizedList(Lists.newArrayList()); private List m_passedTests = Collections.synchronizedList(Lists.newArrayList()); private List m_failedTests = Collections.synchronizedList(Lists.newArrayList()); private List m_skippedTests = Collections.synchronizedList(Lists.newArrayList()); private List m_failedButWSPerTests = Collections.synchronizedList(Lists.newArrayList()); private List m_testContexts= Collections.synchronizedList(new ArrayList()); private List m_failedConfs= Collections.synchronizedList(Lists.newArrayList()); private List m_skippedConfs= Collections.synchronizedList(Lists.newArrayList()); private List m_passedConfs= Collections.synchronizedList(Lists.newArrayList()); @Override public void onTestSuccess(ITestResult tr) { m_allTestMethods.add(tr.getMethod()); m_passedTests.add(tr); } @Override public void onTestFailure(ITestResult tr) { m_allTestMethods.add(tr.getMethod()); m_failedTests.add(tr); } @Override public void onTestSkipped(ITestResult tr) { m_allTestMethods.add(tr.getMethod()); m_skippedTests.add(tr); } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult tr) { m_allTestMethods.add(tr.getMethod()); m_failedButWSPerTests.add(tr); } protected ITestNGMethod[] getAllTestMethods() { return m_allTestMethods.toArray(new ITestNGMethod[m_allTestMethods.size()]); } @Override public void onStart(ITestContext testContext) { m_testContexts.add(testContext); } @Override public void onFinish(ITestContext testContext) { } /** * @return Returns the failedButWithinSuccessPercentageTests. */ public List getFailedButWithinSuccessPercentageTests() { return m_failedButWSPerTests; } /** * @return Returns the failedTests. */ public List getFailedTests() { return m_failedTests; } /** * @return Returns the passedTests. */ public List getPassedTests() { return m_passedTests; } /** * @return Returns the skippedTests. */ public List getSkippedTests() { return m_skippedTests; } private static void ppp(String s) { System.out.println("[TestListenerAdapter] " + s); } /** * @param allTestMethods The allTestMethods to set. */ public void setAllTestMethods(List allTestMethods) { m_allTestMethods = allTestMethods; } /** * @param failedButWithinSuccessPercentageTests The failedButWithinSuccessPercentageTests to set. */ public void setFailedButWithinSuccessPercentageTests( List failedButWithinSuccessPercentageTests) { m_failedButWSPerTests = failedButWithinSuccessPercentageTests; } /** * @param failedTests The failedTests to set. */ public void setFailedTests(List failedTests) { m_failedTests = failedTests; } /** * @param passedTests The passedTests to set. */ public void setPassedTests(List passedTests) { m_passedTests = passedTests; } /** * @param skippedTests The skippedTests to set. */ public void setSkippedTests(List skippedTests) { m_skippedTests = skippedTests; } @Override public void onTestStart(ITestResult result) { } public List getTestContexts() { return m_testContexts; } public List getConfigurationFailures() { return m_failedConfs; } /** * @see org.testng.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult) */ @Override public void onConfigurationFailure(ITestResult itr) { m_failedConfs.add(itr); } public List getConfigurationSkips() { return m_skippedConfs; } @Override public void beforeConfiguration(ITestResult tr) { } /** * @see org.testng.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult) */ @Override public void onConfigurationSkip(ITestResult itr) { m_skippedConfs.add(itr); } /** * @see org.testng.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult) */ @Override public void onConfigurationSuccess(ITestResult itr) { m_passedConfs.add(itr); } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("passed", getPassedTests().size()) .add("failed", getFailedTests().size()) .add("skipped", getSkippedTests().size()) .toString(); } } testng-6.9.12/src/main/java/org/testng/TestNGException.java0000755000175000017500000000104412732165123023040 0ustar eugeneeugenepackage org.testng; /** * The base class for all exceptions thrown by TestNG. * * @author Cedric Beust */ public class TestNGException extends RuntimeException { /* generated */ private static final long serialVersionUID = -422675971506425913L; public TestNGException(Throwable t) { super(t); } /** * @param string */ public TestNGException(String string) { super("\n" + string); } public TestNGException(String string, Throwable t) { super("\n" + string, t); } } testng-6.9.12/src/main/java/org/testng/InstanceOrderingMethodInterceptor.java0000644000175000017500000000253712732165123026640 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Lists; import org.testng.collections.Maps; import java.util.List; import java.util.Map; /** * A method interceptor that sorts its methods per instances (i.e. per class). * * */ class InstanceOrderingMethodInterceptor implements IMethodInterceptor { @Override public List intercept(List methods, ITestContext context) { return groupMethodsByInstance(methods); } /** * The default method interceptor which sorts methods by instances (i.e. by class). */ private List groupMethodsByInstance(List methods) { List instanceList = Lists.newArrayList(); Map> map = Maps.newHashMap(); for (IMethodInstance mi : methods) { Object[] methodInstances = mi.getInstances(); for (Object instance : methodInstances) { if (!instanceList.contains(instance)) { instanceList.add(instance); } List l = map.get(instance); if (l == null) { l = Lists.newArrayList(); map.put(instance, l); } l.add(mi); } } List result = Lists.newArrayList(); for (Object instance : instanceList) { result.addAll(map.get(instance)); } return result; } } testng-6.9.12/src/main/java/org/testng/IAttributes.java0000755000175000017500000000125212732165123022255 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; import java.util.Set; /** * A trait that is used by all interfaces that lets the user add or remove their * own attributes. */ public interface IAttributes extends Serializable { /** * @param name The name of the attribute to return */ public Object getAttribute(String name); /** * Set a custom attribute. */ public void setAttribute(String name, Object value); /** * @return all the attributes names. */ public Set getAttributeNames(); /** * Remove the attribute * * @return the attribute value if found, null otherwise */ public Object removeAttribute(String name); } testng-6.9.12/src/main/java/org/testng/AssertJUnit.java0000755000175000017500000002527112732165123022240 0ustar eugeneeugenepackage org.testng; import org.testng.internal.junit.ArrayAsserts; /** * A set of assert methods. Messages are only displayed when an assert fails. * Renamed from junit.framework.Assert. */ public class AssertJUnit extends ArrayAsserts { /** * Protect constructor since it is a static only class */ protected AssertJUnit() { } /** * Asserts that a condition is true. If it isn't it throws * an AssertionFailedError with the given message. */ static public void assertTrue(String message, boolean condition) { if(!condition) { fail(message); } } /** * Asserts that a condition is true. If it isn't it throws * an AssertionFailedError. */ static public void assertTrue(boolean condition) { assertTrue(null, condition); } /** * Asserts that a condition is false. If it isn't it throws * an AssertionFailedError with the given message. */ static public void assertFalse(String message, boolean condition) { assertTrue(message, !condition); } /** * Asserts that a condition is false. If it isn't it throws * an AssertionFailedError. */ static public void assertFalse(boolean condition) { assertFalse(null, condition); } /** * Fails a test with the given message. */ static public void fail(String message) { if (null == message) { message = ""; } throw new AssertionError(message); } /** * Fails a test with no message. */ static public void fail() { fail(null); } /** * Asserts that two objects are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, Object expected, Object actual) { if((expected == null) && (actual == null)) { return; } if((expected != null) && expected.equals(actual)) { return; } failNotEquals(message, expected, actual); } /** * Asserts that two objects are equal. If they are not * an AssertionFailedError is thrown. */ static public void assertEquals(Object expected, Object actual) { assertEquals(null, expected, actual); } /** * Asserts that two Strings are equal. */ static public void assertEquals(String message, String expected, String actual) { if((expected == null) && (actual == null)) { return; } if((expected != null) && expected.equals(actual)) { return; } throw new AssertionError(format(message, expected, actual)); } /** * Asserts that two Strings are equal. */ static public void assertEquals(String expected, String actual) { assertEquals(null, expected, actual); } /** * Asserts that two doubles are equal concerning a delta. If they are not * an AssertionFailedError is thrown with the given message. If the expected * value is infinity then the delta value is ignored. */ static public void assertEquals(String message, double expected, double actual, double delta) { // handle infinity specially since subtracting to infinite values gives NaN and the // the following test fails if(Double.isInfinite(expected)) { if(!(expected == actual)) { failNotEquals(message, expected, actual); } } else if(!(Math.abs(expected - actual) <= delta)) { // Because comparison with NaN always returns false failNotEquals(message, expected, actual); } } /** * Asserts that two doubles are equal concerning a delta. If the expected * value is infinity then the delta value is ignored. */ static public void assertEquals(double expected, double actual, double delta) { assertEquals(null, expected, actual, delta); } /** * Asserts that two floats are equal concerning a delta. If they are not * an AssertionFailedError is thrown with the given message. If the expected * value is infinity then the delta value is ignored. */ static public void assertEquals(String message, float expected, float actual, float delta) { // handle infinity specially since subtracting to infinite values gives NaN and the // the following test fails if(Float.isInfinite(expected)) { if(!(expected == actual)) { failNotEquals(message, expected, actual); } } else if(!(Math.abs(expected - actual) <= delta)) { failNotEquals(message, expected, actual); } } /** * Asserts that two floats are equal concerning a delta. If the expected * value is infinity then the delta value is ignored. */ static public void assertEquals(float expected, float actual, float delta) { assertEquals(null, expected, actual, delta); } /** * Asserts that two longs are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, long expected, long actual) { assertEquals(message, Long.valueOf(expected), Long.valueOf(actual)); } /** * Asserts that two longs are equal. */ static public void assertEquals(long expected, long actual) { assertEquals(null, expected, actual); } /** * Asserts that two booleans are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, boolean expected, boolean actual) { assertEquals(message, Boolean.valueOf(expected), Boolean.valueOf(actual)); } /** * Asserts that two booleans are equal. */ static public void assertEquals(boolean expected, boolean actual) { assertEquals(null, expected, actual); } /** * Asserts that two bytes are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, byte expected, byte actual) { assertEquals(message, Byte.valueOf(expected), Byte.valueOf(actual)); } /** * Asserts that two bytes are equal. */ static public void assertEquals(byte expected, byte actual) { assertEquals(null, expected, actual); } /** * Asserts that two chars are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, char expected, char actual) { assertEquals(message, Character.valueOf(expected), Character.valueOf(actual)); } /** * Asserts that two chars are equal. */ static public void assertEquals(char expected, char actual) { assertEquals(null, expected, actual); } /** * Asserts that two shorts are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, short expected, short actual) { assertEquals(message, Short.valueOf(expected), Short.valueOf(actual)); } /** * Asserts that two shorts are equal. */ static public void assertEquals(short expected, short actual) { assertEquals(null, expected, actual); } /** * Asserts that two ints are equal. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, int expected, int actual) { assertEquals(message, Integer.valueOf(expected), Integer.valueOf(actual)); } /** * Asserts that two ints are equal. */ static public void assertEquals(int expected, int actual) { assertEquals(null, expected, actual); } /** * Asserts that an object isn't null. */ static public void assertNotNull(Object object) { assertNotNull(null, object); } /** * Asserts that an object isn't null. If it is * an AssertionFailedError is thrown with the given message. */ static public void assertNotNull(String message, Object object) { assertTrue(message, object != null); } /** * Asserts that an object is null. */ static public void assertNull(Object object) { assertNull(null, object); } /** * Asserts that an object is null. If it is not * an AssertionFailedError is thrown with the given message. */ static public void assertNull(String message, Object object) { assertTrue(message, object == null); } /** * Asserts that two objects refer to the same object. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertSame(String message, Object expected, Object actual) { if(expected == actual) { return; } failNotSame(message, expected, actual); } /** * Asserts that two objects refer to the same object. If they are not * the same an AssertionFailedError is thrown. */ static public void assertSame(Object expected, Object actual) { assertSame(null, expected, actual); } /** * Asserts that two objects refer to the same object. If they are not * an AssertionFailedError is thrown with the given message. */ static public void assertNotSame(String message, Object expected, Object actual) { if(expected == actual) { failSame(message); } } /** * Asserts that two objects refer to the same object. If they are not * the same an AssertionFailedError is thrown. */ static public void assertNotSame(Object expected, Object actual) { assertNotSame(null, expected, actual); } static public void assertEquals(final byte[] expected, final byte[] actual) { assertEquals("", expected, actual); } static public void assertEquals(final String message, final byte[] expected, final byte[] actual) { if(expected == actual) { return; } if(null == expected) { fail("expected a null array, but not null found. " + message); } if(null == actual) { fail("expected not null array, but null found. " + message); } assertEquals("arrays don't have the same size. " + message, expected.length, actual.length); for(int i= 0; i < expected.length; i++) { if(expected[i] != actual[i]) { fail("arrays differ firstly at element [" + i +"]; " + format(message, expected[i], actual[i])); } } } static private void failSame(String message) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + "expected not same"); } static private void failNotSame(String message, Object expected, Object actual) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + "expected same:<" + expected + "> was not:<" + actual + ">"); } static private void failNotEquals(String message, Object expected, Object actual) { fail(format(message, expected, actual)); } static String format(String message, Object expected, Object actual) { String formatted = ""; if(message != null) { formatted = message + " "; } return formatted + "expected:<" + expected + "> but was:<" + actual + ">"; } } testng-6.9.12/src/main/java/org/testng/IObjectFactory.java0000755000175000017500000000070512732165123022667 0ustar eugeneeugenepackage org.testng; import java.lang.reflect.Constructor; /** * Factory used to create all test instances. This factory is passed the constructor * along with the parameters that TestNG calculated based on the environment * (@Parameters, etc...). * * @see IObjectFactory2 * * @author Hani Suleiman * @since 5.6 */ public interface IObjectFactory extends ITestObjectFactory { Object newInstance(Constructor constructor, Object... params); } testng-6.9.12/src/main/java/org/testng/TestClass.java0000755000175000017500000002112012732165123021717 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Lists; import org.testng.collections.Objects; import org.testng.internal.ConfigurationMethod; import org.testng.internal.NoOpTestClass; import org.testng.internal.RunInfo; import org.testng.internal.TestNGMethod; import org.testng.internal.Utils; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlClass; import org.testng.xml.XmlTest; import java.lang.reflect.Method; import java.util.List; /** * This class represents a test class: * - The test methods * - The configuration methods (test and method) * - The class file * * @author Cedric Beust * @author Alexandru Popescu */ class TestClass extends NoOpTestClass implements ITestClass { /* generated */ private static final long serialVersionUID = -8077917128278361294L; transient private IAnnotationFinder m_annotationFinder = null; // The Strategy used to locate test methods (TestNG, JUnit, etc...) transient private ITestMethodFinder m_testMethodFinder = null; private IClass m_iClass = null; private RunInfo m_runInfo = null; private String m_testName; private XmlTest m_xmlTest; private XmlClass m_xmlClass; protected TestClass(IClass cls, ITestMethodFinder testMethodFinder, IAnnotationFinder annotationFinder, RunInfo runInfo, XmlTest xmlTest, XmlClass xmlClass) { init(cls, testMethodFinder, annotationFinder, runInfo, xmlTest, xmlClass); } @Override public String getTestName() { return m_testName; } @Override public XmlTest getXmlTest() { return m_xmlTest; } @Override public XmlClass getXmlClass() { return m_xmlClass; } public IAnnotationFinder getAnnotationFinder() { return m_annotationFinder; } private void init(IClass cls, ITestMethodFinder testMethodFinder, IAnnotationFinder annotationFinder, RunInfo runInfo, XmlTest xmlTest, XmlClass xmlClass) { log(3, "Creating TestClass for " + cls); m_iClass = cls; m_testClass = cls.getRealClass(); m_xmlTest = xmlTest; m_xmlClass = xmlClass; m_runInfo = runInfo; m_testMethodFinder = testMethodFinder; m_annotationFinder = annotationFinder; initTestClassesAndInstances(); initMethods(); } private void initTestClassesAndInstances() { // // TestClasses and instances // Object[] instances = getInstances(false); for (Object instance : instances) { if (instance instanceof ITest) { m_testName = ((ITest) instance).getTestName(); break; } } if (m_testName == null) { m_testName = m_iClass.getTestName(); } } @Override public Object[] getInstances(boolean create) { return m_iClass.getInstances(create); } @Override public long[] getInstanceHashCodes() { return m_iClass.getInstanceHashCodes(); } @Deprecated @Override public int getInstanceCount() { return m_iClass.getInstanceCount(); } @Override public void addInstance(Object instance) { m_iClass.addInstance(instance); } private void initMethods() { ITestNGMethod[] methods = m_testMethodFinder.getTestMethods(m_testClass, m_xmlTest); m_testMethods = createTestMethods(methods); for (Object instance : m_iClass.getInstances(false)) { m_beforeSuiteMethods = ConfigurationMethod .createSuiteConfigurationMethods(m_testMethodFinder.getBeforeSuiteMethods(m_testClass), m_annotationFinder, true, instance); m_afterSuiteMethods = ConfigurationMethod .createSuiteConfigurationMethods(m_testMethodFinder.getAfterSuiteMethods(m_testClass), m_annotationFinder, false, instance); m_beforeTestConfMethods = ConfigurationMethod .createTestConfigurationMethods(m_testMethodFinder.getBeforeTestConfigurationMethods(m_testClass), m_annotationFinder, true, instance); m_afterTestConfMethods = ConfigurationMethod .createTestConfigurationMethods(m_testMethodFinder.getAfterTestConfigurationMethods(m_testClass), m_annotationFinder, false, instance); m_beforeClassMethods = ConfigurationMethod .createClassConfigurationMethods(m_testMethodFinder.getBeforeClassMethods(m_testClass), m_annotationFinder, true, instance); m_afterClassMethods = ConfigurationMethod .createClassConfigurationMethods(m_testMethodFinder.getAfterClassMethods(m_testClass), m_annotationFinder, false, instance); m_beforeGroupsMethods = ConfigurationMethod .createBeforeConfigurationMethods(m_testMethodFinder.getBeforeGroupsConfigurationMethods(m_testClass), m_annotationFinder, true, instance); m_afterGroupsMethods = ConfigurationMethod .createAfterConfigurationMethods(m_testMethodFinder.getAfterGroupsConfigurationMethods(m_testClass), m_annotationFinder, false, instance); m_beforeTestMethods = ConfigurationMethod .createTestMethodConfigurationMethods(m_testMethodFinder.getBeforeTestMethods(m_testClass), m_annotationFinder, true, instance); m_afterTestMethods = ConfigurationMethod .createTestMethodConfigurationMethods(m_testMethodFinder.getAfterTestMethods(m_testClass), m_annotationFinder, false, instance); } } /** * Create the test methods that belong to this class (rejects * all those that belong to a different class). */ private ITestNGMethod[] createTestMethods(ITestNGMethod[] methods) { List vResult = Lists.newArrayList(); for (ITestNGMethod tm : methods) { Method m = tm.getMethod(); if (m.getDeclaringClass().isAssignableFrom(m_testClass)) { for (Object o : m_iClass.getInstances(false)) { log(4, "Adding method " + tm + " on TestClass " + m_testClass); vResult.add(new TestNGMethod(/* tm.getRealClass(), */ m, m_annotationFinder, m_xmlTest, o)); } } else { log(4, "Rejecting method " + tm + " for TestClass " + m_testClass); } } ITestNGMethod[] result = vResult.toArray(new ITestNGMethod[vResult.size()]); return result; } private RunInfo getRunInfo() { return m_runInfo; } public ITestMethodFinder getTestMethodFinder() { return m_testMethodFinder; } private void log(int level, String s) { Utils.log("TestClass", level, s); } private static void ppp(String s) { System.out.println("[TestClass] " + s); } protected void dump() { System.out.println("===== Test class\n" + m_testClass.getName()); for (ITestNGMethod m : m_beforeClassMethods) { System.out.println(" @BeforeClass " + m); } for (ITestNGMethod m : m_beforeTestMethods) { System.out.println(" @BeforeMethod " + m); } for (ITestNGMethod m : m_testMethods) { System.out.println(" @Test " + m); } for (ITestNGMethod m : m_afterTestMethods) { System.out.println(" @AfterMethod " + m); } for (ITestNGMethod m : m_afterClassMethods) { System.out.println(" @AfterClass " + m); } System.out.println("======"); } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("name", m_testClass) .toString(); } public IClass getIClass() { return m_iClass; } }testng-6.9.12/src/main/java/org/testng/IAnnotationTransformer3.java0000644000175000017500000000033512732165123024545 0ustar eugeneeugenepackage org.testng; import org.testng.annotations.IListenersAnnotation; public interface IAnnotationTransformer3 extends IAnnotationTransformer2 { void transform(IListenersAnnotation annotation, Class testClass); } testng-6.9.12/src/main/java/org/testng/ITestRunnerFactory.java0000644000175000017500000000055712732165123023574 0ustar eugeneeugenepackage org.testng; import org.testng.xml.XmlTest; import java.util.Collection; import java.util.List; /** * A factory for TestRunners to be used by SuiteRunners. */ public interface ITestRunnerFactory { TestRunner newTestRunner(final ISuite suite, final XmlTest test, Collection listeners, List classListeners); } testng-6.9.12/src/main/java/org/testng/IInstanceInfo.java0000755000175000017500000000122312732165123022505 0ustar eugeneeugenepackage org.testng; /** * This class defines a pair of instance/class. A method with @Factory * can return an array of these objects instead of Object[] so that * instances can be dynamic proxies or mock objects and still provide * enough information to TestNG to figure out what classes the * annotations should be looked up in. * * @author Cedric Beust */ public interface IInstanceInfo { /** * @return The instance on which the tests will be invoked. */ T getInstance(); /** * @return The class on which the TestNG annotations should be looked for. */ Class getInstanceClass(); } testng-6.9.12/src/main/java/org/testng/IConfigureCallBack.java0000644000175000017500000000127012732165123023422 0ustar eugeneeugenepackage org.testng; /** * A parameter of this type will be passed to the run() method of a IConfigurable. * Invoking runConfigurationMethod() on that parameter will cause the test method currently * being diverted to be invoked. * * This interface is not meant to be implemented by clients, only by TestNG. * * @see org.testng.IConfigurable * * @author cbeust * Sep 07, 2010 */ public interface IConfigureCallBack { /** * Invoke the test method currently being hijacked. */ public void runConfigurationMethod(ITestResult testResult); /** * @return the parameters that will be used to invoke the configuration method. */ public Object[] getParameters(); } testng-6.9.12/src/main/java/org/testng/Assert.java0000644000175000017500000010007712732165123021261 0ustar eugeneeugenepackage org.testng; import static org.testng.internal.EclipseInterface.ASSERT_LEFT; import static org.testng.internal.EclipseInterface.ASSERT_LEFT2; import static org.testng.internal.EclipseInterface.ASSERT_MIDDLE; import static org.testng.internal.EclipseInterface.ASSERT_RIGHT; import org.testng.collections.Lists; import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Assertion tool class. Presents assertion methods with a more natural parameter order. * The order is always actualValue, expectedValue [, message]. * * @author Alexandru Popescu */ public class Assert { /** * Protect constructor since it is a static only class */ protected Assert() { // hide constructor } /** * Asserts that a condition is true. If it isn't, * an AssertionError, with the given message, is thrown. * @param condition the condition to evaluate * @param message the assertion error message */ static public void assertTrue(boolean condition, String message) { if(!condition) { failNotEquals(condition, Boolean.TRUE, message); } } /** * Asserts that a condition is true. If it isn't, * an AssertionError is thrown. * @param condition the condition to evaluate */ static public void assertTrue(boolean condition) { assertTrue(condition, null); } /** * Asserts that a condition is false. If it isn't, * an AssertionError, with the given message, is thrown. * @param condition the condition to evaluate * @param message the assertion error message */ static public void assertFalse(boolean condition, String message) { if(condition) { failNotEquals(condition, Boolean.FALSE, message); // TESTNG-81 } } /** * Asserts that a condition is false. If it isn't, * an AssertionError is thrown. * @param condition the condition to evaluate */ static public void assertFalse(boolean condition) { assertFalse(condition, null); } /** * Fails a test with the given message and wrapping the original exception. * * @param message the assertion error message * @param realCause the original exception */ static public void fail(String message, Throwable realCause) { AssertionError ae = new AssertionError(message); ae.initCause(realCause); throw ae; } /** * Fails a test with the given message. * @param message the assertion error message */ static public void fail(String message) { throw new AssertionError(message); } /** * Fails a test with no message. */ static public void fail() { fail(null); } /** * Asserts that two objects are equal. If they are not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(Object actual, Object expected, String message) { if (expected != null && expected.getClass().isArray()) { assertArrayEquals(actual, expected, message); return; } assertEqualsImpl(actual, expected, message); } /** * Differs from {@link #assertEquals(Object, Object, String)} by not taking arrays into * special consideration hence comparing them by reference. Intended to be called directly * to test equality of collections content. */ private static void assertEqualsImpl(Object actual, Object expected, String message) { if((expected == null) && (actual == null)) { return; } if(expected == null ^ actual == null) { failNotEquals(actual, expected, message); } if (expected.equals(actual) && actual.equals(expected)) { return; } failNotEquals(actual, expected, message); } private static void assertArrayEquals(Object actual, Object expected, String message) { if (expected == actual) { return; } if (null == expected) { fail("expected a null array, but not null found. " + message); } if (null == actual) { fail("expected not null array, but null found. " + message); } //is called only when expected is an array if (actual.getClass().isArray()) { int expectedLength = Array.getLength(expected); if (expectedLength == Array.getLength(actual)) { for (int i = 0 ; i < expectedLength ; i++) { Object _actual = Array.get(actual, i); Object _expected = Array.get(expected, i); try { assertEquals(_actual, _expected); } catch (AssertionError ae) { failNotEquals(actual, expected, message == null ? "" : message + " (values at index " + i + " are not the same)"); } } //array values matched return; } else { failNotEquals(Array.getLength(actual), expectedLength, message == null ? "" : message + " (Array lengths are not the same)"); } } failNotEquals(actual, expected, message); } /** * Asserts that two objects are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(Object actual, Object expected) { assertEquals(actual, expected, null); } /** * Asserts that two Strings are equal. If they are not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(String actual, String expected, String message) { assertEquals((Object) actual, (Object) expected, message); } /** * Asserts that two Strings are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(String actual, String expected) { assertEquals(actual, expected, null); } /** * Asserts that two doubles are equal concerning a delta. If they are not, * an AssertionError, with the given message, is thrown. If the expected * value is infinity then the delta value is ignored. * @param actual the actual value * @param expected the expected value * @param delta the absolute tolerable difference between the actual and expected values * @param message the assertion error message */ static public void assertEquals(double actual, double expected, double delta, String message) { // handle infinity specially since subtracting to infinite values gives NaN and the // the following test fails if(Double.isInfinite(expected)) { if(!(expected == actual)) { failNotEquals(actual, expected, message); } } else if (Double.isNaN(expected)) { if (!Double.isNaN(actual)) { failNotEquals(actual, expected, message); } } else if(!(Math.abs(expected - actual) <= delta)) { failNotEquals(actual, expected, message); } } /** * Asserts that two doubles are equal concerning a delta. If they are not, * an AssertionError is thrown. If the expected value is infinity then the * delta value is ignored. * @param actual the actual value * @param expected the expected value * @param delta the absolute tolerable difference between the actual and expected values */ static public void assertEquals(double actual, double expected, double delta) { assertEquals(actual, expected, delta, null); } /** * Asserts that two floats are equal concerning a delta. If they are not, * an AssertionError, with the given message, is thrown. If the expected * value is infinity then the delta value is ignored. * @param actual the actual value * @param expected the expected value * @param delta the absolute tolerable difference between the actual and expected values * @param message the assertion error message */ static public void assertEquals(float actual, float expected, float delta, String message) { // handle infinity specially since subtracting to infinite values gives NaN and the // the following test fails if(Float.isInfinite(expected)) { if(!(expected == actual)) { failNotEquals(actual, expected, message); } } else if(!(Math.abs(expected - actual) <= delta)) { failNotEquals(actual, expected, message); } } /** * Asserts that two floats are equal concerning a delta. If they are not, * an AssertionError is thrown. If the expected * value is infinity then the delta value is ignored. * @param actual the actual value * @param expected the expected value * @param delta the absolute tolerable difference between the actual and expected values */ static public void assertEquals(float actual, float expected, float delta) { assertEquals(actual, expected, delta, null); } /** * Asserts that two longs are equal. If they are not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(long actual, long expected, String message) { assertEquals(Long.valueOf(actual), Long.valueOf(expected), message); } /** * Asserts that two longs are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(long actual, long expected) { assertEquals(actual, expected, null); } /** * Asserts that two booleans are equal. If they are not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(boolean actual, boolean expected, String message) { assertEquals( Boolean.valueOf(actual), Boolean.valueOf(expected), message); } /** * Asserts that two booleans are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(boolean actual, boolean expected) { assertEquals(actual, expected, null); } /** * Asserts that two bytes are equal. If they are not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(byte actual, byte expected, String message) { assertEquals(Byte.valueOf(actual), Byte.valueOf(expected), message); } /** * Asserts that two bytes are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(byte actual, byte expected) { assertEquals(actual, expected, null); } /** * Asserts that two chars are equal. If they are not, * an AssertionFailedError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(char actual, char expected, String message) { assertEquals(Character.valueOf(actual), Character.valueOf(expected), message); } /** * Asserts that two chars are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(char actual, char expected) { assertEquals(actual, expected, null); } /** * Asserts that two shorts are equal. If they are not, * an AssertionFailedError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(short actual, short expected, String message) { assertEquals(Short.valueOf(actual), Short.valueOf(expected), message); } /** * Asserts that two shorts are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(short actual, short expected) { assertEquals(actual, expected, null); } /** * Asserts that two ints are equal. If they are not, * an AssertionFailedError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(int actual, int expected, String message) { assertEquals(Integer.valueOf(actual), Integer.valueOf(expected), message); } /** * Asserts that two ints are equal. If they are not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(int actual, int expected) { assertEquals(actual, expected, null); } /** * Asserts that an object isn't null. If it is, * an AssertionError is thrown. * @param object the assertion object */ static public void assertNotNull(Object object) { assertNotNull(object, null); } /** * Asserts that an object isn't null. If it is, * an AssertionFailedError, with the given message, is thrown. * @param object the assertion object * @param message the assertion error message */ static public void assertNotNull(Object object, String message) { if (object == null) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + "expected object to not be null"); } assertTrue(object != null, message); } /** * Asserts that an object is null. If it is not, * an AssertionError, with the given message, is thrown. * @param object the assertion object */ static public void assertNull(Object object) { assertNull(object, null); } /** * Asserts that an object is null. If it is not, * an AssertionFailedError, with the given message, is thrown. * @param object the assertion object * @param message the assertion error message */ static public void assertNull(Object object, String message) { if (object != null) { failNotSame(object, null, message); } } /** * Asserts that two objects refer to the same object. If they do not, * an AssertionFailedError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertSame(Object actual, Object expected, String message) { if(expected == actual) { return; } failNotSame(actual, expected, message); } /** * Asserts that two objects refer to the same object. If they do not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertSame(Object actual, Object expected) { assertSame(actual, expected, null); } /** * Asserts that two objects do not refer to the same objects. If they do, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertNotSame(Object actual, Object expected, String message) { if(expected == actual) { failSame(actual, expected, message); } } /** * Asserts that two objects do not refer to the same object. If they do, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertNotSame(Object actual, Object expected) { assertNotSame(actual, expected, null); } static private void failSame(Object actual, Object expected, String message) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + ASSERT_LEFT2 + expected + ASSERT_MIDDLE + actual + ASSERT_RIGHT); } static private void failNotSame(Object actual, Object expected, String message) { String formatted = ""; if(message != null) { formatted = message + " "; } fail(formatted + ASSERT_LEFT + expected + ASSERT_MIDDLE + actual + ASSERT_RIGHT); } static private void failNotEquals(Object actual , Object expected, String message ) { fail(format(actual, expected, message)); } static String format(Object actual, Object expected, String message) { String formatted = ""; if (null != message) { formatted = message + " "; } return formatted + ASSERT_LEFT + expected + ASSERT_MIDDLE + actual + ASSERT_RIGHT; } /** * Asserts that two collections contain the same elements in the same order. If they do not, * an AssertionError is thrown. * * @param actual the actual value * @param expected the expected value */ static public void assertEquals(Collection actual, Collection expected) { assertEquals(actual, expected, null); } /** * Asserts that two collections contain the same elements in the same order. If they do not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(Collection actual, Collection expected, String message) { if(actual == expected) { return; } if (actual == null || expected == null) { if (message != null) { fail(message); } else { fail("Collections not equal: expected: " + expected + " and actual: " + actual); } } assertEquals(actual.size(), expected.size(), (message == null ? "" : message + ": ") + "lists don't have the same size"); Iterator actIt = actual.iterator(); Iterator expIt = expected.iterator(); int i = -1; while(actIt.hasNext() && expIt.hasNext()) { i++; Object e = expIt.next(); Object a = actIt.next(); String explanation = "Lists differ at element [" + i + "]: " + e + " != " + a; String errorMessage = message == null ? explanation : message + ": " + explanation; assertEqualsImpl(a, e, errorMessage); } } /** Asserts that two iterators return the same elements in the same order. If they do not, * an AssertionError is thrown. * Please note that this assert iterates over the elements and modifies the state of the iterators. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(Iterator actual, Iterator expected) { assertEquals(actual, expected, null); } /** Asserts that two iterators return the same elements in the same order. If they do not, * an AssertionError, with the given message, is thrown. * Please note that this assert iterates over the elements and modifies the state of the iterators. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(Iterator actual, Iterator expected, String message) { if(actual == expected) { return; } if(actual == null || expected == null) { if(message != null) { fail(message); } else { fail("Iterators not equal: expected: " + expected + " and actual: " + actual); } } int i = -1; while(actual.hasNext() && expected.hasNext()) { i++; Object e = expected.next(); Object a = actual.next(); String explanation = "Iterators differ at element [" + i + "]: " + e + " != " + a; String errorMessage = message == null ? explanation : message + ": " + explanation; assertEqualsImpl(a, e, errorMessage); } if(actual.hasNext()) { String explanation = "Actual iterator returned more elements than the expected iterator."; String errorMessage = message == null ? explanation : message + ": " + explanation; fail(errorMessage); } else if(expected.hasNext()) { String explanation = "Expected iterator returned more elements than the actual iterator."; String errorMessage = message == null ? explanation : message + ": " + explanation; fail(errorMessage); } } /** Asserts that two iterables return iterators with the same elements in the same order. If they do not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEquals(Iterable actual, Iterable expected) { assertEquals(actual, expected, null); } /** Asserts that two iterables return iterators with the same elements in the same order. If they do not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(Iterable actual, Iterable expected, String message) { if(actual == expected) { return; } if(actual == null || expected == null) { if(message != null) { fail(message); } else { fail("Iterables not equal: expected: " + expected + " and actual: " + actual); } } Iterator actIt = actual.iterator(); Iterator expIt = expected.iterator(); assertEquals(actIt, expIt, message); } /** * Asserts that two arrays contain the same elements in the same order. If they do not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEquals(Object[] actual, Object[] expected, String message) { if(actual == expected) { return; } if ((actual == null && expected != null) || (actual != null && expected == null)) { if (message != null) { fail(message); } else { fail("Arrays not equal: " + Arrays.toString(expected) + " and " + Arrays.toString(actual)); } } assertEquals(Arrays.asList(actual), Arrays.asList(expected), message); } /** * Asserts that two arrays contain the same elements in no particular order. If they do not, * an AssertionError, with the given message, is thrown. * @param actual the actual value * @param expected the expected value * @param message the assertion error message */ static public void assertEqualsNoOrder(Object[] actual, Object[] expected, String message) { if(actual == expected) { return; } if ((actual == null && expected != null) || (actual != null && expected == null)) { failAssertNoEqual( "Arrays not equal: " + Arrays.toString(expected) + " and " + Arrays.toString(actual), message); } if (actual.length != expected.length) { failAssertNoEqual( "Arrays do not have the same size:" + actual.length + " != " + expected.length, message); } List actualCollection = Lists.newArrayList(); for (Object a : actual) { actualCollection.add(a); } for (Object o : expected) { actualCollection.remove(o); } if (actualCollection.size() != 0) { failAssertNoEqual( "Arrays not equal: " + Arrays.toString(expected) + " and " + Arrays.toString(actual), message); } } private static void failAssertNoEqual(String defaultMessage, String message) { if (message != null) { fail(message); } else { fail(defaultMessage); } } /** * Asserts that two arrays contain the same elements in the same order. If they do not, * an AssertionError is thrown. * * @param actual the actual value * @param expected the expected value */ static public void assertEquals(Object[] actual, Object[] expected) { assertEquals(actual, expected, null); } /** * Asserts that two arrays contain the same elements in no particular order. If they do not, * an AssertionError is thrown. * @param actual the actual value * @param expected the expected value */ static public void assertEqualsNoOrder(Object[] actual, Object[] expected) { assertEqualsNoOrder(actual, expected, null); } /** * Asserts that two sets are equal. */ static public void assertEquals(Set actual, Set expected) { assertEquals(actual, expected, null); } /** * Assert set equals */ static public void assertEquals(Set actual, Set expected, String message) { if (actual == expected) { return; } if (actual == null || expected == null) { // Keep the back compatible if (message == null) { fail("Sets not equal: expected: " + expected + " and actual: " + actual); } else { failNotEquals(actual, expected, message); } } if (!actual.equals(expected)) { if (message == null) { fail("Sets differ: expected " + expected + " but got " + actual); } else { failNotEquals(actual, expected, message); } } } /** * Asserts that two maps are equal. */ static public void assertEquals(Map actual, Map expected) { if (actual == expected) { return; } if (actual == null || expected == null) { fail("Maps not equal: expected: " + expected + " and actual: " + actual); } if (actual.size() != expected.size()) { fail("Maps do not have the same size:" + actual.size() + " != " + expected.size()); } Set entrySet = actual.entrySet(); for (Object anEntrySet : entrySet) { Map.Entry entry = (Map.Entry) anEntrySet; Object key = entry.getKey(); Object value = entry.getValue(); Object expectedValue = expected.get(key); assertEqualsImpl(value, expectedValue, "Maps do not match for key:" + key + " actual:" + value + " expected:" + expectedValue); } } ///// // assertNotEquals // public static void assertNotEquals(Object actual1, Object actual2, String message) { boolean fail = false; try { Assert.assertEquals(actual1, actual2); fail = true; } catch (AssertionError e) { } if (fail) { Assert.fail(message); } } public static void assertNotEquals(Object actual1, Object actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(String actual1, String actual2, String message) { assertNotEquals((Object) actual1, (Object) actual2, message); } static void assertNotEquals(String actual1, String actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(long actual1, long actual2, String message) { assertNotEquals(Long.valueOf(actual1), Long.valueOf(actual2), message); } static void assertNotEquals(long actual1, long actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(boolean actual1, boolean actual2, String message) { assertNotEquals(Boolean.valueOf(actual1), Boolean.valueOf(actual2), message); } static void assertNotEquals(boolean actual1, boolean actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(byte actual1, byte actual2, String message) { assertNotEquals(Byte.valueOf(actual1), Byte.valueOf(actual2), message); } static void assertNotEquals(byte actual1, byte actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(char actual1, char actual2, String message) { assertNotEquals(Character.valueOf(actual1), Character.valueOf(actual2), message); } static void assertNotEquals(char actual1, char actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(short actual1, short actual2, String message) { assertNotEquals(Short.valueOf(actual1), Short.valueOf(actual2), message); } static void assertNotEquals(short actual1, short actual2) { assertNotEquals(actual1, actual2, null); } static void assertNotEquals(int actual1, int actual2, String message) { assertNotEquals(Integer.valueOf(actual1), Integer.valueOf(actual2), message); } static void assertNotEquals(int actual1, int actual2) { assertNotEquals(actual1, actual2, null); } static public void assertNotEquals(float actual1, float actual2, float delta, String message) { boolean fail = false; try { Assert.assertEquals(actual1, actual2, delta, message); fail = true; } catch (AssertionError e) { } if (fail) { Assert.fail(message); } } static public void assertNotEquals(float actual1, float actual2, float delta) { assertNotEquals(actual1, actual2, delta, null); } static public void assertNotEquals(double actual1, double actual2, double delta, String message) { boolean fail = false; try { Assert.assertEquals(actual1, actual2, delta, message); fail = true; } catch (AssertionError e) { } if (fail) { Assert.fail(message); } } static public void assertNotEquals(double actual1, double actual2, double delta) { assertNotEquals(actual1, actual2, delta, null); } /** * This interface facilitates the use of {@link #expectThrows} from Java 8. It allows * method references to both void and non-void methods to be passed directly into * expectThrows without wrapping, even if they declare checked exceptions. *

* This interface is not meant to be implemented directly. */ public interface ThrowingRunnable { void run() throws Throwable; } /** * Asserts that {@code runnable} throws an exception when invoked. If it does not, an * {@link AssertionError} is thrown. * * @param runnable A function that is expected to throw an exception when invoked * @since 6.9.5 */ public static void assertThrows(ThrowingRunnable runnable) { assertThrows(Throwable.class, runnable); } /** * Asserts that {@code runnable} throws an exception of type {@code throwableClass} when * executed. If it does not throw an exception, an {@link AssertionError} is thrown. If it * throws the wrong type of exception, an {@code AssertionError} is thrown describing the * mismatch; the exception that was actually thrown can be obtained by calling {@link * AssertionError#getCause}. * * @param throwableClass the expected type of the exception * @param runnable A function that is expected to throw an exception when invoked * @since 6.9.5 */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public static void assertThrows(Class throwableClass, ThrowingRunnable runnable) { expectThrows(throwableClass, runnable); } /** * Asserts that {@code runnable} throws an exception of type {@code throwableClass} when * executed and returns the exception. If {@code runnable} does not throw an exception, an * {@link AssertionError} is thrown. If it throws the wrong type of exception, an {@code * AssertionError} is thrown describing the mismatch; the exception that was actually thrown can * be obtained by calling {@link AssertionError#getCause}. * * @param throwableClass the expected type of the exception * @param runnable A function that is expected to throw an exception when invoked * @return The exception thrown by {@code runnable} * @since 6.9.5 */ public static T expectThrows(Class throwableClass, ThrowingRunnable runnable) { try { runnable.run(); } catch (Throwable t) { if (throwableClass.isInstance(t)) { return throwableClass.cast(t); } else { String mismatchMessage = String.format("Expected %s to be thrown, but %s was thrown", throwableClass.getSimpleName(), t.getClass().getSimpleName()); throw new AssertionError(mismatchMessage, t); } } String message = String.format("Expected %s to be thrown, but nothing was thrown", throwableClass.getSimpleName()); throw new AssertionError(message); } } testng-6.9.12/src/main/java/org/testng/ITestContext.java0000644000175000017500000000566612732165123022425 0ustar eugeneeugenepackage org.testng; import com.google.inject.Injector; import com.google.inject.Module; import org.testng.internal.ClassImpl; import org.testng.xml.XmlTest; import java.util.Collection; import java.util.Date; import java.util.List; /** * This class defines a test context which contains all the information * for a given test run. An instance of this context is passed to the * test listeners so they can query information about their * environment. * * @author Cedric Beust, Aug 6, 2004 */ public interface ITestContext extends IAttributes { /** * The name of this test. */ public String getName(); /** * When this test started running. */ public Date getStartDate(); /** * When this test stopped running. */ public Date getEndDate(); /** * @return A list of all the tests that run successfully. */ public IResultMap getPassedTests(); /** * @return A list of all the tests that were skipped */ public IResultMap getSkippedTests(); /** * @return A list of all the tests that failed but are being ignored because * annotated with a successPercentage. */ public IResultMap getFailedButWithinSuccessPercentageTests(); /** * @return A map of all the tests that passed, indexed by * their ITextMethor. * * @see org.testng.ITestNGMethod */ public IResultMap getFailedTests(); /** * @return All the groups that are included for this test run. */ public String[] getIncludedGroups(); /** * @return All the groups that are excluded for this test run. */ public String[] getExcludedGroups(); /** * @return Where the reports will be generated. */ public String getOutputDirectory(); /** * @return The Suite object that was passed to the runner * at start-up. */ public ISuite getSuite(); /** * @return All the test methods that were run. */ public ITestNGMethod[] getAllTestMethods(); /** * @return The host where this test was run, or null if it was run locally. The * returned string has the form: host:port */ public String getHost(); /** * @return All the methods that were not included in this test run. */ public Collection getExcludedMethods(); /** * Retrieves information about the successful configuration method invocations. */ public IResultMap getPassedConfigurations(); /** * Retrieves information about the skipped configuration method invocations. */ public IResultMap getSkippedConfigurations(); /** * Retrieves information about the failed configuration method invocations. */ public IResultMap getFailedConfigurations(); /** * @return the current XmlTest. */ public XmlTest getCurrentXmlTest(); public List getGuiceModules(Class cls); public Injector getInjector(List moduleInstances); Injector getInjector(IClass iClass); public void addInjector(List moduleInstances, Injector injector); } testng-6.9.12/src/main/java/org/testng/asserts/0000755000175000017500000000000012732165123020634 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/asserts/IAssert.java0000644000175000017500000000021312732165123023045 0ustar eugeneeugenepackage org.testng.asserts; public interface IAssert { String getMessage(); void doAssert(); T getActual(); T getExpected(); } testng-6.9.12/src/main/java/org/testng/asserts/SoftAssert.java0000644000175000017500000000226312732165123023577 0ustar eugeneeugenepackage org.testng.asserts; import java.util.Map; import org.testng.collections.Maps; /** * When an assertion fails, don't throw an exception but record the failure. * Calling {@code assertAll()} will cause an exception to be thrown if at * least one assertion failed. */ public class SoftAssert extends Assertion { // LinkedHashMap to preserve the order private final Map> m_errors = Maps.newLinkedHashMap(); @Override protected void doAssert(IAssert a) { onBeforeAssert(a); try { a.doAssert(); onAssertSuccess(a); } catch (AssertionError ex) { onAssertFailure(a, ex); m_errors.put(ex, a); } finally { onAfterAssert(a); } } public void assertAll() { if (!m_errors.isEmpty()) { StringBuilder sb = new StringBuilder("The following asserts failed:"); boolean first = true; for (Map.Entry> ae : m_errors.entrySet()) { if (first) { first = false; } else { sb.append(","); } sb.append("\n\t"); sb.append(ae.getKey().getMessage()); } throw new AssertionError(sb.toString()); } } } testng-6.9.12/src/main/java/org/testng/asserts/Assertion.java0000644000175000017500000005020012732165123023443 0ustar eugeneeugenepackage org.testng.asserts; import java.util.Collection; import java.util.Map; import java.util.Set; /** * An assert class with various hooks allowing its behavior to be modified * by subclasses. */ public class Assertion implements IAssertLifecycle { protected void doAssert(IAssert assertCommand) { onBeforeAssert(assertCommand); try { executeAssert(assertCommand); onAssertSuccess(assertCommand); } catch(AssertionError ex) { onAssertFailure(assertCommand, ex); throw ex; } finally { onAfterAssert(assertCommand); } } /** * Run the assert command in parameter. Meant to be overridden by subclasses. */ @Override public void executeAssert(IAssert assertCommand) { assertCommand.doAssert(); } /** * Invoked when an assert succeeds. Meant to be overridden by subclasses. */ @Override public void onAssertSuccess(IAssert assertCommand) { } /** * Invoked when an assert fails. Meant to be overridden by subclasses. * * @deprecated use onAssertFailure(IAssert assertCommand, AssertionError ex) instead of. */ @Deprecated @Override public void onAssertFailure(IAssert assertCommand) { } @Override public void onAssertFailure(IAssert assertCommand, AssertionError ex) { onAssertFailure(assertCommand); } /** * Invoked before an assert is run. Meant to be overridden by subclasses. */ @Override public void onBeforeAssert(IAssert assertCommand) { } /** * Invoked after an assert is run. Meant to be overridden by subclasses. */ @Override public void onAfterAssert(IAssert assertCommand) { } abstract private static class SimpleAssert implements IAssert { private final T actual; private final T expected; private final String m_message; public SimpleAssert(String message) { this(null, null, message); } public SimpleAssert(T actual, T expected) { this(actual, expected, null); } public SimpleAssert(T actual, T expected, String message) { this.actual = actual; this.expected = expected; m_message = message; } @Override public String getMessage() { return m_message; } @Override public T getActual() { return actual; } @Override public T getExpected() { return expected; } @Override abstract public void doAssert(); } public void assertTrue(final boolean condition, final String message) { doAssert(new SimpleAssert(condition, Boolean.TRUE, message) { @Override public void doAssert() { org.testng.Assert.assertTrue(condition, message); } }); } public void assertTrue(final boolean condition) { doAssert(new SimpleAssert(condition, Boolean.TRUE) { @Override public void doAssert() { org.testng.Assert.assertTrue(condition); } }); } public void assertFalse(final boolean condition, final String message) { doAssert(new SimpleAssert(condition, Boolean.FALSE, message) { @Override public void doAssert() { org.testng.Assert.assertFalse(condition, message); } }); } public void assertFalse(final boolean condition) { doAssert(new SimpleAssert(condition, Boolean.FALSE) { @Override public void doAssert() { org.testng.Assert.assertFalse(condition); } }); } public void fail(final String message, final Throwable realCause) { doAssert(new SimpleAssert(message) { @Override public void doAssert() { org.testng.Assert.fail(message, realCause); } }); } public void fail(final String message) { doAssert(new SimpleAssert(message) { @Override public void doAssert() { org.testng.Assert.fail(message); } }); } public void fail() { doAssert(new SimpleAssert(null) { @Override public void doAssert() { org.testng.Assert.fail(); } }); } public void assertEquals(final T actual, final T expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final T actual, final T expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final String actual, final String expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final String actual, final String expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final double actual, final double expected, final double delta, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, delta, message); } }); } public void assertEquals(final double actual, final double expected, final double delta) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, delta); } }); } public void assertEquals(final float actual, final float expected, final float delta, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, delta, message); } }); } public void assertEquals(final float actual, final float expected, final float delta) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, delta); } }); } public void assertEquals(final long actual, final long expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final long actual, final long expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final boolean actual, final boolean expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final boolean actual, final boolean expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final byte actual, final byte expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final byte actual, final byte expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final char actual, final char expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final char actual, final char expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final short actual, final short expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final short actual, final short expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final int actual, final int expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final int actual, final int expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertNotNull(final Object object) { doAssert(new SimpleAssert(object, null) { @Override public void doAssert() { org.testng.Assert.assertNotNull(object); } }); } public void assertNotNull(final Object object, final String message) { doAssert(new SimpleAssert(object, null, message) { @Override public void doAssert() { org.testng.Assert.assertNotNull(object, message); } }); } public void assertNull(final Object object) { doAssert(new SimpleAssert(object, null) { @Override public void doAssert() { org.testng.Assert.assertNull(object); } }); } public void assertNull(final Object object, final String message) { doAssert(new SimpleAssert(object, null, message) { @Override public void doAssert() { org.testng.Assert.assertNull(object, message); } }); } public void assertSame(final Object actual, final Object expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertSame(actual, expected, message); } }); } public void assertSame(final Object actual, final Object expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertSame(actual, expected); } }); } public void assertNotSame(final Object actual, final Object expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotSame(actual, expected, message); } }); } public void assertNotSame(final Object actual, final Object expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotSame(actual, expected); } }); } public void assertEquals(final Collection actual, final Collection expected) { doAssert(new SimpleAssert>(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final Collection actual, final Collection expected, final String message) { doAssert(new SimpleAssert>(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final Object[] actual, final Object[] expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEqualsNoOrder(final Object[] actual, final Object[] expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEqualsNoOrder(actual, expected, message); } }); } public void assertEquals(final Object[] actual, final Object[] expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEqualsNoOrder(final Object[] actual, final Object[] expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEqualsNoOrder(actual, expected); } }); } public void assertEquals(final byte[] actual, final byte[] expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final byte[] actual, final byte[] expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final Set actual, final Set expected) { doAssert(new SimpleAssert>(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertEquals(final Set actual, final Set expected, final String message) { doAssert(new SimpleAssert>(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected, message); } }); } public void assertEquals(final Map actual, final Map expected) { doAssert(new SimpleAssert>(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertEquals(actual, expected); } }); } public void assertNotEquals(final Object actual, final Object expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final Object actual, final Object expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final String actual, final String expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final String actual, final String expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final long actual, final long expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final long actual, final long expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final boolean actual, final boolean expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final boolean actual, final boolean expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final byte actual, final byte expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final byte actual, final byte expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final char actual, final char expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final char actual, final char expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final short actual, final short expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final short actual, final short expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final int actual, final int expected, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, message); } }); } public void assertNotEquals(final int actual, final int expected) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected); } }); } public void assertNotEquals(final float actual, final float expected, final float delta, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, delta, message); } }); } public void assertNotEquals(final float actual, final float expected, final float delta) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, delta); } }); } public void assertNotEquals(final double actual, final double expected, final double delta, final String message) { doAssert(new SimpleAssert(actual, expected, message) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, delta, message); } }); } public void assertNotEquals(final double actual, final double expected, final double delta) { doAssert(new SimpleAssert(actual, expected) { @Override public void doAssert() { org.testng.Assert.assertNotEquals(actual, expected, delta); } }); } } testng-6.9.12/src/main/java/org/testng/asserts/LoggingAssert.java0000644000175000017500000000066512732165123024256 0ustar eugeneeugenepackage org.testng.asserts; import org.testng.collections.Lists; import java.util.List; /** * Log the messages of all the assertions that get run. */ public class LoggingAssert extends Assertion { private List m_messages = Lists.newArrayList(); @Override public void onBeforeAssert(IAssert a) { m_messages.add("Test:" + a.getMessage()); } public List getMessages() { return m_messages; } } testng-6.9.12/src/main/java/org/testng/asserts/IAssertLifecycle.java0000644000175000017500000000151312732165123024671 0ustar eugeneeugenepackage org.testng.asserts; /** * Life cycle methods for the assertion class. */ public interface IAssertLifecycle { /** * Run the assert command in parameter. */ void executeAssert(IAssert assertCommand); /** * Invoked when an assert succeeds. */ void onAssertSuccess(IAssert assertCommand); /** * Invoked when an assert fails. * * @deprecated use onAssertFailure(IAssert assertCommand, AssertionError ex) instead of. */ void onAssertFailure(IAssert assertCommand); /** * Invoked when an assert fails. * */ void onAssertFailure(IAssert assertCommand, AssertionError ex); /** * Invoked before an assert is run. */ void onBeforeAssert(IAssert assertCommand); /** * Invoked after an assert is run. */ void onAfterAssert(IAssert assertCommand); } testng-6.9.12/src/main/java/org/testng/ITestClassFinder.java0000755000175000017500000000121412732165123023162 0ustar eugeneeugenepackage org.testng; /** * This class is used by TestNG to locate the test classes. * * @author Cedric Beust */ public interface ITestClassFinder { /** * @return An array of all the classes that contain test * methods. This method usually returns an array of one * class, which is the class on which TestNG is running, * except in the following cases. * - TestNG: the class contains an @Factory method * - JUnit: the class contains a suite() method */ public IClass[] findTestClasses(); /** * Return the IClass for a given class */ public IClass getIClass(Class cls); } testng-6.9.12/src/main/java/org/testng/internal/0000755000175000017500000000000012732165123020764 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/annotations/0000755000175000017500000000000012732165123023321 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/annotations/ObjectFactoryAnnotation.java0000755000175000017500000000041712732165123030762 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IObjectFactoryAnnotation; /** * The internal representation of @ObjectFactory * @author Hani */ public class ObjectFactoryAnnotation extends BaseAnnotation implements IObjectFactoryAnnotation {} testng-6.9.12/src/main/java/org/testng/internal/annotations/BaseBeforeAfter.java0000755000175000017500000000271412732165123027152 0ustar eugeneeugenepackage org.testng.internal.annotations; public class BaseBeforeAfter extends TestOrConfiguration implements IBaseBeforeAfter { private String[] m_parameters = {}; private boolean m_alwaysRun = false; private boolean m_inheritGroups = true; private String[] m_beforeGroups = {}; private String[] m_afterGroups = {}; private String m_description; /** * @return the description */ @Override public String getDescription() { return m_description; } /** * @param description the description to set */ @Override public void setDescription(String description) { m_description = description; } public void setAlwaysRun(boolean alwaysRun) { m_alwaysRun = alwaysRun; } public void setInheritGroups(boolean inheritGroups) { m_inheritGroups = inheritGroups; } @Override public void setParameters(String[] parameters) { m_parameters = parameters; } @Override public String[] getParameters() { return m_parameters; } @Override public boolean getAlwaysRun() { return m_alwaysRun; } @Override public boolean getInheritGroups() { return m_inheritGroups; } public String[] getAfterGroups() { return m_afterGroups; } public void setAfterGroups(String[] afterGroups) { m_afterGroups = afterGroups; } public String[] getBeforeGroups() { return m_beforeGroups; } public void setBeforeGroups(String[] beforeGroups) { m_beforeGroups = beforeGroups; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAfterSuite.java0000755000175000017500000000014512732165123026353 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IAfterSuite extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/FactoryAnnotation.java0000755000175000017500000000224312732165123027632 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IFactoryAnnotation; /** * An implementation of IFactory * * Created on Dec 20, 2005 * @author Cedric Beust */ public class FactoryAnnotation extends BaseAnnotation implements IFactoryAnnotation { private String[] m_parameters = {}; private String m_dataProvider = null; private Class m_dataProviderClass; private boolean m_enabled = true; @Override public String getDataProvider() { return m_dataProvider; } @Override public void setDataProvider(String dataProvider) { m_dataProvider = dataProvider; } @Override public String[] getParameters() { return m_parameters; } public void setParameters(String[] parameters) { m_parameters = parameters; } public void setDataProviderClass(Class dataProviderClass) { m_dataProviderClass = dataProviderClass; } @Override public Class getDataProviderClass() { return m_dataProviderClass; } @Override public boolean getEnabled() { return m_enabled; } @Override public void setEnabled(boolean enabled) { m_enabled = enabled; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/TestAnnotation.java0000755000175000017500000001133712732165123027146 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.IRetryAnalyzer; import org.testng.annotations.ITestAnnotation; /** * An implementation of ITest * * Created on Dec 20, 2005 * @author Cedric Beust */ public class TestAnnotation extends TestOrConfiguration implements ITestAnnotation { private long m_invocationTimeOut = 0; private int m_invocationCount = 1; private int m_threadPoolSize = 0; private int m_successPercentage = 100; private String m_dataProvider = ""; private boolean m_alwaysRun = false; private Class[] m_expectedExceptions = {}; private String m_expectedExceptionsMessageRegExp = ".*"; private String m_suiteName = ""; private String m_testName = ""; private boolean m_singleThreaded = false; private boolean m_sequential = false; private Class m_dataProviderClass = null; private IRetryAnalyzer m_retryAnalyzer = null; private boolean m_skipFailedInvocations = false; private boolean m_ignoreMissingDependencies = false; /** * @return the expectedExceptions */ @Override public Class[] getExpectedExceptions() { return m_expectedExceptions; } /** * @param expectedExceptions the expectedExceptions to set */ @Override public void setExpectedExceptions(Class[] expectedExceptions) { m_expectedExceptions = expectedExceptions; } @Override public String getExpectedExceptionsMessageRegExp() { return m_expectedExceptionsMessageRegExp; } @Override public void setExpectedExceptionsMessageRegExp( String expectedExceptionsMessageRegExp) { m_expectedExceptionsMessageRegExp = expectedExceptionsMessageRegExp; } @Override public void setAlwaysRun(boolean alwaysRun) { m_alwaysRun = alwaysRun; } @Override public void setDataProvider(String dataProvider) { m_dataProvider = dataProvider; } @Override public Class getDataProviderClass() { return m_dataProviderClass; } @Override public void setDataProviderClass(Class dataProviderClass) { m_dataProviderClass = dataProviderClass; } @Override public void setInvocationCount(int invocationCount) { m_invocationCount = invocationCount; } @Override public void setSuccessPercentage(int successPercentage) { m_successPercentage = successPercentage; } @Override public int getInvocationCount() { return m_invocationCount; } @Override public long invocationTimeOut() { return m_invocationTimeOut; } @Override public void setInvocationTimeOut(long timeOut) { m_invocationTimeOut = timeOut; } @Override public int getSuccessPercentage() { return m_successPercentage; } @Override public String getDataProvider() { return m_dataProvider; } @Override public boolean getAlwaysRun() { return m_alwaysRun; } @Override public int getThreadPoolSize() { return m_threadPoolSize; } @Override public void setThreadPoolSize(int threadPoolSize) { m_threadPoolSize = threadPoolSize; } @Override public String getSuiteName() { return m_suiteName; } @Override public void setSuiteName(String xmlSuite) { m_suiteName = xmlSuite; } @Override public String getTestName() { return m_testName; } @Override public void setTestName(String xmlTest) { m_testName = xmlTest; } @Override public boolean getSingleThreaded() { return m_singleThreaded; } @Override public void setSingleThreaded(boolean singleThreaded) { m_singleThreaded = singleThreaded; } @Override public boolean getSequential() { return m_sequential; } @Override public void setSequential(boolean sequential) { m_sequential = sequential; } @Override public IRetryAnalyzer getRetryAnalyzer() { return m_retryAnalyzer; } @Override public void setRetryAnalyzer(Class c) { m_retryAnalyzer = null; if (c != null && IRetryAnalyzer.class.isAssignableFrom(c)) { try { m_retryAnalyzer = (IRetryAnalyzer) c.newInstance(); } catch (InstantiationException | IllegalAccessException e) { // The class will never be called. } } } @Override public void setSkipFailedInvocations(boolean skip) { m_skipFailedInvocations = skip; } @Override public boolean skipFailedInvocations() { return m_skipFailedInvocations; } @Override public void setIgnoreMissingDependencies(boolean ignore) { m_ignoreMissingDependencies = ignore; } @Override public boolean ignoreMissingDependencies() { return m_ignoreMissingDependencies; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/Converter.java0000755000175000017500000000404412732165123026140 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.collections.Lists; import org.testng.internal.ClassHelper; import org.testng.internal.Utils; import java.util.List; import java.util.StringTokenizer; /** * Convert a string values into primitive types. * * Created on Dec 20, 2005 * @author cbeust */ public class Converter { public static boolean getBoolean(String tagValue, boolean def) { boolean result = def; if (tagValue != null) { result = Boolean.valueOf(tagValue); } return result; } public static int getInt(String tagValue, int def) { int result = def; if (tagValue != null) { result = Integer.parseInt(tagValue); } return result; } public static String getString(String tagValue, String def) { String result = def; if (tagValue != null) { result = tagValue; } return result; } public static long getLong(String tagValue, long def) { long result = def; if (tagValue != null) { result = Long.parseLong(tagValue); } return result; } public static String[] getStringArray(String tagValue, String[] def) { String[] result = def; if (tagValue != null) { result = Utils.stringToArray(tagValue); } return result; } public static Class[] getClassArray(String tagValue, Class[] def) { Class[] result = def; List vResult = Lists.newArrayList(); if (tagValue != null) { StringTokenizer st = new StringTokenizer(tagValue, " ,"); while (st.hasMoreElements()) { String className = (String) st.nextElement(); try { Class cls = Class.forName(className); vResult.add(cls); } catch (ClassNotFoundException e) { e.printStackTrace(); } } result = (Class[]) vResult.toArray(new Class[vResult.size()]); } return result; } public static Class getClass(String namedParameter) { Class result = null; if (namedParameter != null) { result = ClassHelper.forName(namedParameter); } return result; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/AfterSuiteAnnotation.java0000755000175000017500000000015112732165123030272 0ustar eugeneeugenepackage org.testng.internal.annotations; public class AfterSuiteAnnotation extends BaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/JDK15AnnotationFinder.java0000755000175000017500000002307112732165123030133 0ustar eugeneeugenepackage org.testng.internal.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.testng.IAnnotationTransformer; import org.testng.IAnnotationTransformer2; import org.testng.IAnnotationTransformer3; import org.testng.ITestNGMethod; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Configuration; import org.testng.annotations.DataProvider; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Factory; import org.testng.annotations.IAnnotation; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.IListenersAnnotation; import org.testng.annotations.IObjectFactoryAnnotation; import org.testng.annotations.IParametersAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Listeners; import org.testng.annotations.ObjectFactory; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import org.testng.annotations.TestInstance; import org.testng.internal.collections.Pair; /** * This class implements IAnnotationFinder with JDK5 annotations * * Created on Dec 20, 2005 * @author Cedric Beust */ public class JDK15AnnotationFinder implements IAnnotationFinder { private JDK15TagFactory m_tagFactory = new JDK15TagFactory(); private Map, Class> m_annotationMap = new ConcurrentHashMap<>(); private Map, IAnnotation> m_annotations = new ConcurrentHashMap<>(); private IAnnotationTransformer m_transformer = null; @SuppressWarnings({"deprecation"}) public JDK15AnnotationFinder(IAnnotationTransformer transformer) { m_transformer = transformer; m_annotationMap.put(IListenersAnnotation.class, Listeners.class); m_annotationMap.put(IConfigurationAnnotation.class, Configuration.class); m_annotationMap.put(IDataProviderAnnotation.class, DataProvider.class); m_annotationMap.put(IExpectedExceptionsAnnotation.class, ExpectedExceptions.class); m_annotationMap.put(IFactoryAnnotation.class, Factory.class); m_annotationMap.put(IObjectFactoryAnnotation.class, ObjectFactory.class); m_annotationMap.put(IParametersAnnotation.class, Parameters.class); m_annotationMap.put(ITestAnnotation.class, Test.class); // internal m_annotationMap.put(IBeforeSuite.class, BeforeSuite.class); m_annotationMap.put(IAfterSuite.class, AfterSuite.class); m_annotationMap.put(IBeforeTest.class, BeforeTest.class); m_annotationMap.put(IAfterTest.class, AfterTest.class); m_annotationMap.put(IBeforeClass.class, BeforeClass.class); m_annotationMap.put(IAfterClass.class, AfterClass.class); m_annotationMap.put(IBeforeGroups.class, BeforeGroups.class); m_annotationMap.put(IAfterGroups.class, AfterGroups.class); m_annotationMap.put(IBeforeMethod.class, BeforeMethod.class); m_annotationMap.put(IAfterMethod.class, AfterMethod.class); } private A findAnnotationInSuperClasses(Class cls, Class a) { // Hack for @Listeners: we don't look in superclasses for this annotation // because inheritance of this annotation causes aggregation instead of // overriding if (a.equals(org.testng.annotations.Listeners.class)) { return cls.getAnnotation(a); } else { while (cls != null) { A result = cls.getAnnotation(a); if (result != null) { return result; } else { cls = cls.getSuperclass(); } } } return null; } @Override public A findAnnotation(Method m, Class annotationClass) { final Class a = m_annotationMap.get(annotationClass); if (a == null) { throw new IllegalArgumentException("Java @Annotation class for '" + annotationClass + "' not found."); } Annotation annotation = m.getAnnotation(a); return findAnnotation(m.getDeclaringClass(), annotation, annotationClass, null, null, m, new Pair<>(annotation, m)); } @Override public A findAnnotation(ITestNGMethod tm, Class annotationClass) { final Class a = m_annotationMap.get(annotationClass); if (a == null) { throw new IllegalArgumentException("Java @Annotation class for '" + annotationClass + "' not found."); } Method m = tm.getMethod(); Class testClass; if (tm.getInstance() == null) { testClass = m.getDeclaringClass(); } else { testClass = tm.getInstance().getClass(); } Annotation annotation = m.getAnnotation(a); if (annotation == null) { annotation = testClass.getAnnotation(a); } return findAnnotation(testClass, annotation, annotationClass, null, null, m, new Pair<>(annotation, m)); } private void transform(IAnnotation a, Class testClass, Constructor testConstructor, Method testMethod) { // // Transform @Test // if (a instanceof ITestAnnotation) { m_transformer.transform((ITestAnnotation) a, testClass, testConstructor, testMethod); } else if (m_transformer instanceof IAnnotationTransformer2) { IAnnotationTransformer2 transformer2 = (IAnnotationTransformer2) m_transformer; // // Transform a configuration annotation // if (a instanceof IConfigurationAnnotation) { IConfigurationAnnotation configuration = (IConfigurationAnnotation) a; transformer2.transform(configuration,testClass, testConstructor, testMethod); } // // Transform @DataProvider // else if (a instanceof IDataProviderAnnotation) { transformer2.transform((IDataProviderAnnotation) a, testMethod); } // // Transform @Factory // else if (a instanceof IFactoryAnnotation) { transformer2.transform((IFactoryAnnotation) a, testMethod); } else if (m_transformer instanceof IAnnotationTransformer3) { IAnnotationTransformer3 transformer = (IAnnotationTransformer3) m_transformer; // // Transform @Listeners // if (a instanceof IListenersAnnotation) { transformer.transform((IListenersAnnotation)a, testClass); } } // End IAnnotationTransformer3 } // End IAnnotationTransformer2 } @Override public A findAnnotation(Class cls, Class annotationClass) { final Class a = m_annotationMap.get(annotationClass); if (a == null) { throw new IllegalArgumentException("Java @Annotation class for '" + annotationClass + "' not found."); } Annotation annotation = findAnnotationInSuperClasses(cls, a); return findAnnotation(cls, annotation, annotationClass, cls, null, null, new Pair<>(annotation, annotationClass)); } @Override public A findAnnotation(Constructor cons, Class annotationClass) { final Class a = m_annotationMap.get(annotationClass); if (a == null) { throw new IllegalArgumentException("Java @Annotation class for '" + annotationClass + "' not found."); } Annotation annotation = cons.getAnnotation(a); return findAnnotation(cons.getDeclaringClass(), annotation, annotationClass, null, cons, null, new Pair<>(annotation, cons)); } private A findAnnotation(Class cls, Annotation a, Class annotationClass, Class testClass, Constructor testConstructor, Method testMethod, Pair p) { if (a == null) { return null; } IAnnotation result = m_annotations.get(p); if (result == null) { result = m_tagFactory.createTag(cls, testMethod, a, annotationClass, m_transformer); m_annotations.put(p, result); transform(result, testClass, testConstructor, testMethod); } //noinspection unchecked return (A) result; } @Override public boolean hasTestInstance(Method method, int i) { final Annotation[][] annotations = method.getParameterAnnotations(); if (annotations.length > 0 && annotations[i].length > 0) { final Annotation[] pa = annotations[i]; for (Annotation a : pa) { if (a instanceof TestInstance) { return true; } } } return false; } @Override public String[] findOptionalValues(Method method) { return optionalValues(method.getParameterAnnotations()); } @Override public String[] findOptionalValues(Constructor method) { return optionalValues(method.getParameterAnnotations()); } private String[] optionalValues(Annotation[][] annotations) { String[] result = new String[annotations.length]; for (int i = 0; i < annotations.length; i++) { for (Annotation a : annotations[i]) { if (a instanceof Optional) { result[i] = ((Optional)a).value(); break; } } } return result; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/JDK15TagFactory.java0000755000175000017500000004522212732165123026736 0ustar eugeneeugenepackage org.testng.internal.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.HashSet; import java.util.List; import java.util.Set; import com.google.common.primitives.Ints; import org.testng.IAnnotationTransformer; import org.testng.TestNGException; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Configuration; import org.testng.annotations.DataProvider; import org.testng.annotations.ExpectedExceptions; import org.testng.annotations.Factory; import org.testng.annotations.IAnnotation; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.IListenersAnnotation; import org.testng.annotations.IObjectFactoryAnnotation; import org.testng.annotations.IParametersAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.Listeners; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import org.testng.collections.Lists; import org.testng.internal.Utils; /** * This class creates implementations of IAnnotations based on the JDK5 * annotation that was found on the Java element. * * Created on Dec 20, 2005 * @author Cedric Beust */ public class JDK15TagFactory { public A createTag(Class cls, Method method, Annotation a, Class annotationClass, IAnnotationTransformer transformer) { IAnnotation result = null; if (a != null) { if (annotationClass == IConfigurationAnnotation.class) { result = createConfigurationTag(cls, a); } else if (annotationClass == IDataProviderAnnotation.class) { result = createDataProviderTag(method, a); } else if (annotationClass == IExpectedExceptionsAnnotation.class) { result = createExpectedExceptionsTag(a); } else if (annotationClass == IFactoryAnnotation.class) { result = createFactoryTag(cls, a); } else if (annotationClass == IParametersAnnotation.class) { result = createParametersTag(a); } else if (annotationClass == IObjectFactoryAnnotation.class) { result = createObjectFactoryTag(a); } else if (annotationClass == ITestAnnotation.class) { result = createTestTag(cls, a, transformer); } else if (annotationClass == IListenersAnnotation.class) { result = createListenersTag(cls, a, transformer); } else if (annotationClass == IBeforeSuite.class || annotationClass == IAfterSuite.class || annotationClass == IBeforeTest.class || annotationClass == IAfterTest.class || annotationClass == IBeforeGroups.class || annotationClass == IAfterGroups.class || annotationClass == IBeforeClass.class || annotationClass == IAfterClass.class || annotationClass == IBeforeMethod.class || annotationClass == IAfterMethod.class) { result = maybeCreateNewConfigurationTag(cls, a, annotationClass); } else { throw new TestNGException("Unknown annotation requested:" + annotationClass); } } //noinspection unchecked return (A) result; } private IAnnotation maybeCreateNewConfigurationTag(Class cls, Annotation a, Class annotationClass) { IAnnotation result = null; if (annotationClass == IBeforeSuite.class) { BeforeSuite bs = (BeforeSuite) a; result = createConfigurationTag(cls, a, true, false, false, false, new String[0], new String[0], false, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IAfterSuite.class) { AfterSuite bs = (AfterSuite) a; result = createConfigurationTag(cls, a, false, true, false, false, new String[0], new String[0], false, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IBeforeTest.class) { BeforeTest bs = (BeforeTest) a; result = createConfigurationTag(cls, a, false, false, true, false, new String[0], new String[0], false, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IAfterTest.class) { AfterTest bs = (AfterTest) a; result = createConfigurationTag(cls, a, false, false, false, true, new String[0], new String[0], false, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IBeforeGroups.class) { BeforeGroups bs = (BeforeGroups) a; final String[] groups= bs.value().length > 0 ? bs.value() : bs.groups(); result = createConfigurationTag(cls, a, false, false, false, false, groups, new String[0], false, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IAfterGroups.class) { AfterGroups bs = (AfterGroups) a; final String[] groups= bs.value().length > 0 ? bs.value() : bs.groups(); result = createConfigurationTag(cls, a, false, false, false, false, new String[0], groups, false, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IBeforeClass.class) { BeforeClass bs = (BeforeClass) a; result = createConfigurationTag(cls, a, false, false, false, false, new String[0], new String[0], true, false, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IAfterClass.class) { AfterClass bs = (AfterClass) a; result = createConfigurationTag(cls, a, false, false, false, false, new String[0], new String[0], false, true, false, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, false, bs.timeOut()); } else if (annotationClass == IBeforeMethod.class) { BeforeMethod bs = (BeforeMethod) a; result = createConfigurationTag(cls, a, false, false, false, false, new String[0], new String[0], false, false, true, false, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, bs.firstTimeOnly(), false, bs.timeOut()); } else if (annotationClass == IAfterMethod.class) { AfterMethod bs = (AfterMethod) a; result = createConfigurationTag(cls, a, false, false, false, false, new String[0], new String[0], false, false, false, true, bs.alwaysRun(), bs.dependsOnGroups(), bs.dependsOnMethods(), bs.description(), bs.enabled(), bs.groups(), bs.inheritGroups(), null, false, bs.lastTimeOnly(), bs.timeOut()); } return result; } @SuppressWarnings({"deprecation"}) private ConfigurationAnnotation createConfigurationTag(Class cls, Annotation a) { ConfigurationAnnotation result = new ConfigurationAnnotation(); Configuration c = (Configuration) a; result.setBeforeTestClass(c.beforeTestClass()); result.setAfterTestClass(c.afterTestClass()); result.setBeforeTestMethod(c.beforeTestMethod()); result.setAfterTestMethod(c.afterTestMethod()); result.setBeforeTest(c.beforeTest()); result.setAfterTest(c.afterTest()); result.setBeforeSuite(c.beforeSuite()); result.setAfterSuite(c.afterSuite()); result.setBeforeGroups(c.beforeGroups()); result.setAfterGroups(c.afterGroups()); result.setParameters(c.parameters()); result.setEnabled(c.enabled()); result.setGroups(join(c.groups(), findInheritedStringArray(cls, Test.class, "groups"))); result.setDependsOnGroups(c.dependsOnGroups()); result.setDependsOnMethods(c.dependsOnMethods()); result.setAlwaysRun(c.alwaysRun()); result.setInheritGroups(c.inheritGroups()); result.setDescription(c.description()); return result; } private IAnnotation createConfigurationTag(Class cls, Annotation a, boolean beforeSuite, boolean afterSuite, boolean beforeTest, boolean afterTest, String[] beforeGroups, String[] afterGroups, boolean beforeClass, boolean afterClass, boolean beforeMethod, boolean afterMethod, boolean alwaysRun, String[] dependsOnGroups, String[] dependsOnMethods, String description, boolean enabled, String[] groups, boolean inheritGroups, String[] parameters, boolean firstTimeOnly, boolean lastTimeOnly, long timeOut) { ConfigurationAnnotation result = new ConfigurationAnnotation(); result.setFakeConfiguration(true); result.setBeforeSuite(beforeSuite); result.setAfterSuite(afterSuite); result.setBeforeTest(beforeTest); result.setAfterTest(afterTest); result.setBeforeTestClass(beforeClass); result.setAfterTestClass(afterClass); result.setBeforeGroups(beforeGroups); result.setAfterGroups(afterGroups); result.setBeforeTestMethod(beforeMethod); result.setAfterTestMethod(afterMethod); result.setAlwaysRun(alwaysRun); result.setDependsOnGroups(dependsOnGroups); result.setDependsOnMethods(dependsOnMethods); result.setDescription(description); result.setEnabled(enabled); result.setGroups(groups); result.setInheritGroups(inheritGroups); result.setParameters(parameters); result.setFirstTimeOnly(firstTimeOnly); result.setLastTimeOnly(lastTimeOnly); result.setTimeOut(timeOut); return result; } private IAnnotation createDataProviderTag(Method method, Annotation a) { DataProviderAnnotation result = new DataProviderAnnotation(); DataProvider c = (DataProvider) a; if (c.name().isEmpty()) { result.setName(method.getName()); } else { result.setName(c.name()); } result.setParallel(c.parallel()); result.setIndices(Ints.asList(c.indices())); return result; } @SuppressWarnings({"deprecation"}) private IAnnotation createExpectedExceptionsTag(Annotation a) { ExpectedExceptionsAnnotation result = new ExpectedExceptionsAnnotation (); ExpectedExceptions c = (ExpectedExceptions ) a; result.setValue(c.value()); return result; } @SuppressWarnings({"deprecation"}) private IAnnotation createFactoryTag(Class cls, Annotation a) { FactoryAnnotation result = new FactoryAnnotation(); Factory c = (Factory) a; result.setParameters(c.parameters()); result.setDataProvider(c.dataProvider()); result.setDataProviderClass( findInherited(c.dataProviderClass(), cls, Factory.class, "dataProviderClass", DEFAULT_CLASS)); result.setEnabled(c.enabled()); return result; } private IAnnotation createObjectFactoryTag(Annotation a) { return new ObjectFactoryAnnotation(); } private IAnnotation createParametersTag(Annotation a) { ParametersAnnotation result = new ParametersAnnotation(); Parameters c = (Parameters) a; result.setValue(c.value()); return result; } @SuppressWarnings({"deprecation"}) private IAnnotation createListenersTag(Class cls, Annotation a, IAnnotationTransformer transformer) { ListenersAnnotation result = new ListenersAnnotation(); Listeners l = (Listeners) a; result.setValue(l.value()); return result; } @SuppressWarnings({"deprecation"}) private IAnnotation createTestTag(Class cls, Annotation a, IAnnotationTransformer transformer) { TestAnnotation result = new TestAnnotation(); Test test = (Test) a; result.setEnabled(test.enabled()); result.setGroups(join(test.groups(), findInheritedStringArray(cls, Test.class, "groups"))); result.setParameters(test.parameters()); result.setDependsOnGroups(join(test.dependsOnGroups(), findInheritedStringArray(cls, Test.class, "dependsOnGroups"))); result.setDependsOnMethods(join(test.dependsOnMethods(), findInheritedStringArray(cls, Test.class, "dependsOnMethods"))); result.setTimeOut(test.timeOut()); result.setInvocationTimeOut(test.invocationTimeOut()); result.setInvocationCount(test.invocationCount()); result.setThreadPoolSize(test.threadPoolSize()); result.setSuccessPercentage(test.successPercentage()); result.setDataProvider(test.dataProvider()); // result.setDataProviderClass(test.dataProviderClass() != Object.class ? // test.dataProviderClass() : null); result.setDataProviderClass( findInherited(test.dataProviderClass(), cls, Test.class, "dataProviderClass", DEFAULT_CLASS)); result.setAlwaysRun(test.alwaysRun()); result.setDescription( findInherited(test.description(), cls, Test.class, "description", DEFAULT_STRING)); result.setExpectedExceptions(test.expectedExceptions()); result.setExpectedExceptionsMessageRegExp(test.expectedExceptionsMessageRegExp()); result.setSuiteName(test.suiteName()); result.setTestName(test.testName()); result.setSequential(test.sequential()); result.setSingleThreaded(test.singleThreaded()); result.setRetryAnalyzer(test.retryAnalyzer()); result.setSkipFailedInvocations(test.skipFailedInvocations()); result.setIgnoreMissingDependencies(test.ignoreMissingDependencies()); result.setPriority(test.priority()); return result; } private String[] join(String[] strings, String[] strings2) { List result = Lists.newArrayList(strings); Set seen = new HashSet<>(Lists.newArrayList(strings)); for (String s : strings2) { if (! seen.contains(s)) { result.add(s); } } return result.toArray(new String[result.size()]); } /** * This interface is used to calculate the default value for various * annotation return types. This is used when looking for an annotation in a * hierarchy. We can't use null as a default since annotation don't allow * nulls, so each type has a different way of defining its own default. */ static interface Default { boolean isDefault(T t); } private static final Default> DEFAULT_CLASS = new Default>() { @Override public boolean isDefault(Class c) { return c == Object.class; } }; private static final Default DEFAULT_STRING = new Default() { @Override public boolean isDefault(String s) { return Utils.isStringEmpty(s); } }; /** * Find the value of an annotation, starting with the annotation found on the * method, then the class and then parent classes until we either find a * non-default value or we reach the top of the hierarchy (Object). */ private T findInherited(T methodValue, Class cls, Class annotationClass, String methodName, Default def) { // Look on the method first and return right away if the annotation is there if (!def.isDefault(methodValue)) { return methodValue; } // Not found, look on the class and then up the hierarchy while (cls != null && cls != Object.class) { Annotation annotation = cls.getAnnotation(annotationClass); if (annotation != null) { T result = (T) invokeMethod(annotation, methodName); if (!def.isDefault(result)) { return result; } } cls = cls.getSuperclass(); } return null; } /** * Find the value of a String[] annotation. The difference with the * findInherited method above is that TestNG aggregates String[] values across * hierarchies. For example, of the method annotation has { "a", "b" } and the * class has { "c" }, the returned value will be { "a", "b", "c" }. */ private String[] findInheritedStringArray(Class cls, Class annotationClass, String methodName) { if (null == cls) { return new String[0]; } List result = Lists.newArrayList(); while (cls != null && cls != Object.class) { Annotation annotation = cls.getAnnotation(annotationClass); if (annotation != null) { String[] g = (String[]) invokeMethod(annotation, methodName); for (String s : g) { result.add(s); } } cls = cls.getSuperclass(); } return result.toArray(new String[result.size()]); } private Object invokeMethod(Annotation test, String methodName) { Object result = null; try { // Note: we should cache methods already looked up Method m = test.getClass().getMethod(methodName, new Class[0]); result = m.invoke(test, new Object[0]); } catch (Exception e) { e.printStackTrace(); } return result; } private void ppp(String string) { System.out.println("[JDK15TagFactory] " + string); } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAnnotationFinder.java0000755000175000017500000000353212732165123027545 0ustar eugeneeugenepackage org.testng.internal.annotations; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import org.testng.ITestNGMethod; import org.testng.annotations.IAnnotation; /** * This interface defines how annotations are found on classes, methods * and constructors. It will be implemented by both JDK 1.4 and JDK 5 * annotation finders. * * @author Cedric Beust */ public interface IAnnotationFinder { /** * @param cls * @param annotationClass * @return The annotation on the class or null if none found. */ public A findAnnotation(Class cls, Class annotationClass); /** * @param m * @param annotationClass * @return The annotation on the method. * If not found, return the annotation on the declaring class. * If not found, return null. */ public A findAnnotation(Method m, Class annotationClass); A findAnnotation(ITestNGMethod m, Class annotationClass); /** * @param cons * @param annotationClass * @return The annotation on the method. * If not found, return the annotation on the declaring class. * If not found, return null. */ public A findAnnotation(Constructor cons, Class annotationClass); /** * @return true if the ith parameter of the given method has the annotation @TestInstance. */ public boolean hasTestInstance(Method method, int i); /** * @return the @Optional values of this method's parameters (null * if the parameter isn't optional) */ public String[] findOptionalValues(Method method); /** * @return the @Optional values of this method's parameters (null * if the parameter isn't optional) */ public String[] findOptionalValues(Constructor ctor); } testng-6.9.12/src/main/java/org/testng/internal/annotations/IBaseBeforeAfter.java0000755000175000017500000000424112732165123027260 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.ITestOrConfiguration; /** * Base interface for IBeforeSuite, IAfterSuite, etc... * * @author cbeust * @since Jun 22, 2006 */ public interface IBaseBeforeAfter extends ITestOrConfiguration { /** * Whether methods on this class/method are enabled. */ public boolean getEnabled(); /** * The list of groups this class/method belongs to. */ public String[] getGroups(); /** * The list of groups this method depends on. Every method * member of one of these groups is guaranteed to have been * invoked before this method. Furthermore, if any of these * methods was not a SUCCESS, this test method will not be * run and will be flagged as a SKIP. */ public String[] getDependsOnGroups(); /** * The list of methods this method depends on. There is no guarantee * on the order on which the methods depended upon will be run, but you * are guaranteed that all these methods will be run before the test method * that contains this annotation is run. Furthermore, if any of these * methods was not a SUCCESS, this test method will not be * run and will be flagged as a SKIP. * * If some of these methods have been overloaded, all the overloaded * versions will be run. */ public String[] getDependsOnMethods(); /** * For before methods (beforeSuite, beforeTest, beforeTestClass and * beforeTestMethod, but not beforeGroups): * If set to true, this configuration method will be run * regardless of what groups it belongs to. *
* For after methods (afterSuite, afterClass, ...): * If set to true, this configuration method will be run * even if one or more methods invoked previously failed or * was skipped. */ public boolean getAlwaysRun(); /** * If true, this @Configuration method will belong to groups specified in the * @Test annotation on the class (if any). */ public boolean getInheritGroups(); /** * The description for this method. The string used will appear in the * HTML report and also on standard output if verbose >= 2. */ public String getDescription(); } testng-6.9.12/src/main/java/org/testng/internal/annotations/DefaultAnnotationTransformer.java0000755000175000017500000000065712732165123032041 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.IAnnotationTransformer; import org.testng.annotations.ITestAnnotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class DefaultAnnotationTransformer implements IAnnotationTransformer { @Override public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) { } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IBeforeTest.java0000755000175000017500000000014512732165123026342 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IBeforeTest extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/ParametersAnnotation.java0000755000175000017500000000076512732165123030335 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IParametersAnnotation; /** * An implementation of IParameters * * Created on Dec 20, 2005 * @author
Cedric Beust */ public class ParametersAnnotation extends BaseAnnotation implements IParametersAnnotation { private String[] m_value = {}; @Override public String[] getValue() { return m_value; } public void setValue(String[] value) { m_value = value; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/ListenersAnnotation.java0000644000175000017500000000070012732165123030164 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.ITestNGListener; import org.testng.annotations.IAnnotation; public class ListenersAnnotation implements IListeners, IAnnotation { private Class[] m_value; @Override public Class[] getValue() { return m_value; } @Override public void setValue(Class[] value) { m_value = value; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAnnotationTransformer.java0000755000175000017500000000025012732165123030632 0ustar eugeneeugenepackage org.testng.internal.annotations; /** * For backward compatibility. */ public interface IAnnotationTransformer extends org.testng.IAnnotationTransformer { } testng-6.9.12/src/main/java/org/testng/internal/annotations/IBeforeSuite.java0000755000175000017500000000014612732165123026515 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IBeforeSuite extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/DataProviderAnnotation.java0000755000175000017500000000163112732165123030607 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IDataProviderAnnotation; import java.util.List; /** * An implementation of IDataProvider. * * Created on Dec 20, 2005 * @author Cedric Beust */ public class DataProviderAnnotation extends BaseAnnotation implements IDataProviderAnnotation { private String m_name; private boolean m_parallel; private List m_indices; @Override public boolean isParallel() { return m_parallel; } @Override public void setParallel(boolean parallel) { m_parallel = parallel; } @Override public String getName() { return m_name; } @Override public void setName(String name) { m_name = name; } @Override public List getIndices() { return m_indices; } @Override public void setIndices(List indices) { m_indices = indices; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAfterTest.java0000755000175000017500000000014412732165123026200 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IAfterTest extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAfterClass.java0000755000175000017500000000014512732165123026327 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IAfterClass extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/AnnotationHelper.java0000755000175000017500000003154612732165123027452 0ustar eugeneeugenepackage org.testng.internal.annotations; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.testng.ITestNGMethod; import org.testng.annotations.IAnnotation; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.IParametersAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Maps; import org.testng.internal.TestNGMethod; import org.testng.internal.Utils; import org.testng.internal.reflect.ReflectionHelper; import org.testng.xml.XmlTest; /** * Helper methods to find @Test and @Configuration tags. They minimize * the amount of casting we need to do. * * Created on Dec 20, 2005 * @author cbeust */ public class AnnotationHelper { public static ITestAnnotation findTest(IAnnotationFinder finder, Class cls) { return finder.findAnnotation(cls, ITestAnnotation.class); } public static ITestAnnotation findTest(IAnnotationFinder finder, Method m) { return finder.findAnnotation(m, ITestAnnotation.class); } public static ITestAnnotation findTest(IAnnotationFinder finder, ITestNGMethod m) { return finder.findAnnotation(m, ITestAnnotation.class); } public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Method m) { return finder.findAnnotation(m, IFactoryAnnotation.class); } public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Constructor c) { return finder.findAnnotation(c, IFactoryAnnotation.class); } public static ITestAnnotation findTest(IAnnotationFinder finder, Constructor ctor) { return finder.findAnnotation(ctor, ITestAnnotation.class); } public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Constructor ctor) { IConfigurationAnnotation result = finder.findAnnotation(ctor, IConfigurationAnnotation.class); if (result == null) { IConfigurationAnnotation bs = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeSuite.class); IConfigurationAnnotation as = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterSuite.class); IConfigurationAnnotation bt = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeTest.class); IConfigurationAnnotation at = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterTest.class); IConfigurationAnnotation bg = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeGroups.class); IConfigurationAnnotation ag = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterGroups.class); IConfigurationAnnotation bc = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeClass.class); IConfigurationAnnotation ac = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterClass.class); IConfigurationAnnotation bm = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeMethod.class); IConfigurationAnnotation am = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterMethod.class); if (bs != null || as != null || bt != null || at != null || bg != null || ag != null || bc != null || ac != null || bm != null || am != null) { result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am); } } return result; } public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Method m) { IConfigurationAnnotation result = finder.findAnnotation(m, IConfigurationAnnotation.class); if (result == null) { IConfigurationAnnotation bs = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeSuite.class); IConfigurationAnnotation as = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterSuite.class); IConfigurationAnnotation bt = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeTest.class); IConfigurationAnnotation at = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterTest.class); IConfigurationAnnotation bg = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeGroups.class); IConfigurationAnnotation ag = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterGroups.class); IConfigurationAnnotation bc = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeClass.class); IConfigurationAnnotation ac = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterClass.class); IConfigurationAnnotation bm = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeMethod.class); IConfigurationAnnotation am = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterMethod.class); if (bs != null || as != null || bt != null || at != null || bg != null || ag != null || bc != null || ac != null || bm != null || am != null) { result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am); } } return result; } private static IConfigurationAnnotation createConfiguration(IConfigurationAnnotation bs, IConfigurationAnnotation as, IConfigurationAnnotation bt, IConfigurationAnnotation at, IConfigurationAnnotation bg, IConfigurationAnnotation ag, IConfigurationAnnotation bc, IConfigurationAnnotation ac, IConfigurationAnnotation bm, IConfigurationAnnotation am) { ConfigurationAnnotation result = new ConfigurationAnnotation(); if (bs != null) { result.setBeforeSuite(true); finishInitialize(result, bs); } if (as != null) { result.setAfterSuite(true); finishInitialize(result, as); } if (bt != null) { result.setBeforeTest(true); finishInitialize(result, bt); } if (at != null) { result.setAfterTest(true); finishInitialize(result, at); } if (bg != null) { result.setBeforeGroups(bg.getBeforeGroups()); finishInitialize(result, bg); } if (ag != null) { result.setAfterGroups(ag.getAfterGroups()); finishInitialize(result, ag); } if (bc != null) { result.setBeforeTestClass(true); finishInitialize(result, bc); } if (ac != null) { result.setAfterTestClass(true); finishInitialize(result, ac); } if (bm != null) { result.setBeforeTestMethod(true); finishInitialize(result, bm); } if (am != null) { result.setAfterTestMethod(true); finishInitialize(result, am); } return result; } @SuppressWarnings({"deprecation"}) private static void finishInitialize(ConfigurationAnnotation result, IConfigurationAnnotation bs) { result.setFakeConfiguration(true); result.setAlwaysRun(bs.getAlwaysRun()); result.setDependsOnGroups(bs.getDependsOnGroups()); result.setDependsOnMethods(bs.getDependsOnMethods()); result.setDescription(bs.getDescription()); result.setEnabled(bs.getEnabled()); result.setGroups(bs.getGroups()); result.setInheritGroups(bs.getInheritGroups()); result.setParameters(bs.getParameters()); result.setTimeOut(bs.getTimeOut()); } private static final Class[] ALL_ANNOTATIONS = new Class[] { ITestAnnotation.class, IConfigurationAnnotation.class, IBeforeClass.class, IAfterClass.class, IBeforeMethod.class, IAfterMethod.class, IDataProviderAnnotation.class, IExpectedExceptionsAnnotation.class, IFactoryAnnotation.class, IParametersAnnotation.class, IBeforeSuite.class, IAfterSuite.class, IBeforeTest.class, IAfterTest.class, IBeforeGroups.class, IAfterGroups.class }; public static final Class[] CONFIGURATION_CLASSES = new Class[] { IConfigurationAnnotation.class, IBeforeSuite.class, IAfterSuite.class, IBeforeTest.class, IAfterTest.class, IBeforeGroups.class, IAfterGroups.class, IBeforeClass.class, IAfterClass.class, IBeforeMethod.class, IAfterMethod.class }; public static Class[] getAllAnnotations() { return ALL_ANNOTATIONS; } /** * Delegation method for creating the list of ITestMethods to be * analysed. */ public static ITestNGMethod[] findMethodsWithAnnotation(Class rootClass, Class annotationClass, IAnnotationFinder annotationFinder, XmlTest xmlTest) { // Keep a map of the methods we saw so that we ignore a method in a superclass if it's // already been seen in a child class Map vResult = Maps.newHashMap(); try { vResult = Maps.newHashMap(); // Class[] classes = rootClass.getTestClasses(); Class cls = rootClass; // // If the annotation is on the class or superclass, it applies to all public methods // except methods marked with @Configuration // // // Otherwise walk through all the methods and keep those // that have the annotation // // for (Class cls : classes) { while (null != cls) { boolean hasClassAnnotation = isAnnotationPresent(annotationFinder, cls, annotationClass); Method[] methods = ReflectionHelper.getLocalMethods(cls); for (Method m : methods) { boolean hasMethodAnnotation = isAnnotationPresent(annotationFinder, m, annotationClass); boolean hasTestNGAnnotation = isAnnotationPresent(annotationFinder, m, IFactoryAnnotation.class) || isAnnotationPresent(annotationFinder, m, ITestAnnotation.class) || isAnnotationPresent(annotationFinder, m, CONFIGURATION_CLASSES); boolean isPublic = Modifier.isPublic(m.getModifiers()); boolean isSynthetic = m.isSynthetic(); if ((isPublic && hasClassAnnotation && !isSynthetic && (! hasTestNGAnnotation)) || hasMethodAnnotation) { // Small hack to allow users to specify @Configuration classes even though // a class-level @Test annotation is present. In this case, don't count // that method as a @Test if (isAnnotationPresent(annotationFinder, m, IConfigurationAnnotation.class) && isAnnotationPresent(annotationFinder, cls, ITestAnnotation.class)) { Utils.log("", 3, "Method " + m + " has a configuration annotation" + " and a class-level @Test. This method will only be kept as a" + " configuration method."); continue; } // Skip the method if it has a return type if (m.getReturnType() != void.class && ! xmlTest.getAllowReturnValues()) { Utils.log("", 2, "Method " + m + " has a @Test annotation" + " but also a return value:" + " ignoring it. Use to fix this"); continue; } String key = createMethodKey(m); if (null == vResult.get(key)) { ITestNGMethod tm = new TestNGMethod(/* m.getDeclaringClass(), */ m, annotationFinder, xmlTest, null); /* @@@ */ vResult.put(key,tm); } } } // for // Now explore the superclass cls = cls.getSuperclass(); } // while } catch (SecurityException e) { e.printStackTrace(); } ITestNGMethod[] result = vResult.values().toArray(new ITestNGMethod[vResult.size()]); // for (Method m : result) { // ppp(" METHOD FOUND: " + m); // } return result; } public static Annotation findAnnotationSuperClasses(Class annotationClass, Class c) { while (c != null) { Annotation result = c.getAnnotation(annotationClass); if (result != null) return result; else c = c.getSuperclass(); } return null; } private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, Class[] annotationClasses) { for (Class a : annotationClasses) { if (annotationFinder.findAnnotation(m, a) != null) { return true; } } return false; } private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, Class annotationClass) { return annotationFinder.findAnnotation(m, annotationClass) != null; } private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Class cls, Class annotationClass) { return annotationFinder.findAnnotation(cls, annotationClass) != null; } /** * @return A hashcode representing the name of this method and its parameters, * but without its class */ private static String createMethodKey(Method m) { StringBuffer result = new StringBuffer(m.getName()); for (Class paramClass : m.getParameterTypes()) { result.append(' ').append(paramClass.toString()); } return result.toString(); } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAfterTests.java0000755000175000017500000000014512732165123026364 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IAfterTests extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/IListeners.java0000644000175000017500000000023512732165123026245 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IListenersAnnotation; public interface IListeners extends IListenersAnnotation { } testng-6.9.12/src/main/java/org/testng/internal/annotations/IBeforeMethod.java0000755000175000017500000000014612732165123026644 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IBeforeMethod extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/IDataProvidable.java0000644000175000017500000000061212732165123027155 0ustar eugeneeugenepackage org.testng.internal.annotations; /** * A trait shared by all the annotations that have dataProvider/dataProviderClass attributes. * * @author Cedric Beust */ public interface IDataProvidable { public String getDataProvider(); public void setDataProvider(String v); public Class getDataProviderClass(); public void setDataProviderClass(Class v); } testng-6.9.12/src/main/java/org/testng/internal/annotations/IBeforeGroups.java0000755000175000017500000000014712732165123026704 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IBeforeGroups extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/ExpectedExceptionsAnnotation.java0000755000175000017500000000101712732165123032024 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IExpectedExceptionsAnnotation; /** * An implementation of IExpectedExceptions * * Created on Dec 20, 2005 * @author Cedric Beust */ public class ExpectedExceptionsAnnotation extends BaseAnnotation implements IExpectedExceptionsAnnotation { private Class[] m_value = {}; @Override public Class[] getValue() { return m_value; } public void setValue(Class[] value) { m_value = value; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAfterGroups.java0000755000175000017500000000014612732165123026542 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IAfterGroups extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/ConfigurationAnnotation.java0000755000175000017500000000750712732165123031042 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.IConfigurationAnnotation; /** * An implementation of IConfiguration * * Created on Dec 16, 2005 * @author cbeust */ public class ConfigurationAnnotation extends TestOrConfiguration implements IConfigurationAnnotation, IBeforeSuite, IAfterSuite, IBeforeTest, IAfterTest, IBeforeGroups, IAfterGroups, IBeforeClass, IAfterClass, IBeforeMethod, IAfterMethod { private boolean m_beforeTestClass = false; private boolean m_afterTestClass = false; private boolean m_beforeTestMethod = false; private boolean m_afterTestMethod = false; private boolean m_beforeTest = false; private boolean m_afterTest = false; private boolean m_beforeSuite = false; private boolean m_afterSuite = false; private String[] m_parameters = {}; private boolean m_alwaysRun = false; private boolean m_inheritGroups = true; private String[] m_beforeGroups = {}; private String[] m_afterGroups = {}; private boolean m_isFakeConfiguration; private boolean m_firstTimeOnly = false; private boolean m_lastTimeOnly = false; public ConfigurationAnnotation() { } public void setAfterSuite(boolean afterSuite) { m_afterSuite = afterSuite; } public void setAfterTest(boolean afterTest) { m_afterTest = afterTest; } public void setAfterTestClass(boolean afterTestClass) { m_afterTestClass = afterTestClass; } public void setAfterTestMethod(boolean afterTestMethod) { m_afterTestMethod = afterTestMethod; } public void setAlwaysRun(boolean alwaysRun) { m_alwaysRun = alwaysRun; } public void setBeforeSuite(boolean beforeSuite) { m_beforeSuite = beforeSuite; } public void setBeforeTest(boolean beforeTest) { m_beforeTest = beforeTest; } public void setBeforeTestClass(boolean beforeTestClass) { m_beforeTestClass = beforeTestClass; } public void setBeforeTestMethod(boolean beforeTestMethod) { m_beforeTestMethod = beforeTestMethod; } public void setInheritGroups(boolean inheritGroups) { m_inheritGroups = inheritGroups; } @Override public void setParameters(String[] parameters) { m_parameters = parameters; } @Override public boolean getBeforeTestClass() { return m_beforeTestClass; } @Override public boolean getAfterTestClass() { return m_afterTestClass; } @Override public boolean getBeforeTestMethod() { return m_beforeTestMethod; } @Override public boolean getAfterTestMethod() { return m_afterTestMethod; } @Override public boolean getBeforeSuite() { return m_beforeSuite; } @Override public boolean getAfterSuite() { return m_afterSuite; } @Override public boolean getBeforeTest() { return m_beforeTest; } @Override public boolean getAfterTest() { return m_afterTest; } @Override public String[] getParameters() { return m_parameters; } @Override public boolean getAlwaysRun() { return m_alwaysRun; } @Override public boolean getInheritGroups() { return m_inheritGroups; } @Override public String[] getAfterGroups() { return m_afterGroups; } public void setAfterGroups(String[] afterGroups) { m_afterGroups = afterGroups; } @Override public String[] getBeforeGroups() { return m_beforeGroups; } public void setBeforeGroups(String[] beforeGroups) { m_beforeGroups = beforeGroups; } public void setFakeConfiguration(boolean b) { m_isFakeConfiguration = b; } @Override public boolean isFakeConfiguration() { return m_isFakeConfiguration; } public void setFirstTimeOnly(boolean f) { m_firstTimeOnly = f; } public boolean isFirstTimeOnly() { return m_firstTimeOnly; } public void setLastTimeOnly(boolean f) { m_lastTimeOnly = f; } public boolean isLastTimeOnly() { return m_lastTimeOnly; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/ITest.java0000755000175000017500000000021612732165123025216 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.ITestAnnotation; public interface ITest extends ITestAnnotation { } testng-6.9.12/src/main/java/org/testng/internal/annotations/IAfterMethod.java0000755000175000017500000000014612732165123026503 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IAfterMethod extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/BaseAnnotation.java0000755000175000017500000000123212732165123027072 0ustar eugeneeugenepackage org.testng.internal.annotations; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class BaseAnnotation { private Class m_testClass; private Method m_method; private Constructor m_constructor; public Constructor getConstructor() { return m_constructor; } public void setConstructor(Constructor constructor) { m_constructor = constructor; } public Method getMethod() { return m_method; } public void setMethod(Method method) { m_method = method; } public Class getTestClass() { return m_testClass; } public void setTestClass(Class testClass) { m_testClass = testClass; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/BeforeSuiteAnnotation.java0000755000175000017500000000015212732165123030434 0ustar eugeneeugenepackage org.testng.internal.annotations; public class BeforeSuiteAnnotation extends BaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/annotations/TestOrConfiguration.java0000755000175000017500000000345312732165123030144 0ustar eugeneeugenepackage org.testng.internal.annotations; import org.testng.annotations.ITestOrConfiguration; public class TestOrConfiguration extends BaseAnnotation implements ITestOrConfiguration { private String[] m_parameters = {}; private String[] m_groups = {}; private boolean m_enabled = true; private String[] m_dependsOnGroups = {}; private String[] m_dependsOnMethods = {}; private String m_description = ""; private int m_priority; private long m_timeOut = 0; @Override public String[] getGroups() { return m_groups; } @Override public boolean getEnabled() { return m_enabled; } @Override public void setDependsOnGroups(String[] dependsOnGroups) { m_dependsOnGroups = dependsOnGroups; } @Override public void setDependsOnMethods(String[] dependsOnMethods) { m_dependsOnMethods = dependsOnMethods; } @Override public void setGroups(String[] groups) { m_groups = groups; } @Override public String getDescription() { return m_description; } @Override public void setEnabled(boolean enabled) { m_enabled = enabled; } @Override public String[] getDependsOnGroups() { return m_dependsOnGroups; } @Override public String[] getDependsOnMethods() { return m_dependsOnMethods; } @Override public String[] getParameters() { return m_parameters; } public void setParameters(String[] parameters) { m_parameters = parameters; } @Override public void setDescription(String description) { m_description = description; } public int getPriority() { return m_priority; } public void setPriority(int priority) { m_priority = priority; } @Override public void setTimeOut(long timeOut) { m_timeOut = timeOut; } @Override public long getTimeOut() { return m_timeOut; } } testng-6.9.12/src/main/java/org/testng/internal/annotations/IBeforeClass.java0000755000175000017500000000014612732165123026471 0ustar eugeneeugenepackage org.testng.internal.annotations; public interface IBeforeClass extends IBaseBeforeAfter { } testng-6.9.12/src/main/java/org/testng/internal/TestMethodWithDataProviderMethodWorker.java0000755000175000017500000001120212732165123031402 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.collections.Lists; import org.testng.xml.XmlSuite; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; public class TestMethodWithDataProviderMethodWorker implements Callable> { private ITestNGMethod m_testMethod; private Object[] m_parameterValues; private Object m_instance; private XmlSuite m_xmlSuite; private Map m_parameters; private ITestClass m_testClass; private ITestNGMethod[] m_beforeMethods; private ITestNGMethod[] m_afterMethods; private ConfigurationGroupMethods m_groupMethods; private Invoker m_invoker; private ExpectedExceptionsHolder m_expectedExceptionHolder; private ITestContext m_testContext; private int m_parameterIndex; private boolean m_skipFailedInvocationCounts; private int m_invocationCount; private ITestResultNotifier m_notifier; private List m_testResults = Lists.newArrayList(); private int m_failureCount; public TestMethodWithDataProviderMethodWorker(Invoker invoker, ITestNGMethod testMethod, int parameterIndex, Object[] parameterValues, Object instance, XmlSuite suite, Map parameters, ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, ConfigurationGroupMethods groupMethods, ExpectedExceptionsHolder expectedExceptionHolder, ITestContext testContext, boolean skipFailedInvocationCounts, int invocationCount, int failureCount, ITestResultNotifier notifier) { m_invoker = invoker; m_testMethod = testMethod; m_parameterIndex = parameterIndex; m_parameterValues = parameterValues; m_instance = instance; m_xmlSuite = suite; m_parameters = parameters; m_testClass = testClass; m_beforeMethods = beforeMethods; m_afterMethods = afterMethods; m_groupMethods = groupMethods; m_expectedExceptionHolder = expectedExceptionHolder; m_skipFailedInvocationCounts = skipFailedInvocationCounts; m_testContext = testContext; m_invocationCount = invocationCount; m_failureCount = failureCount; m_notifier = notifier; } public long getMaxTimeOut() { return 500; } @Override public List call() { List tmpResults = Lists.newArrayList(); long start = System.currentTimeMillis(); final Invoker.FailureContext failure = new Invoker.FailureContext(); failure.count = m_failureCount; try { tmpResults.add(m_invoker.invokeTestMethod(m_instance, m_testMethod, m_parameterValues, m_parameterIndex, m_xmlSuite, m_parameters, m_testClass, m_beforeMethods, m_afterMethods, m_groupMethods, failure)); } finally { m_failureCount = failure.count; if (failure.instances.isEmpty()) { m_testResults.addAll(tmpResults); } else { for (Object instance : failure.instances) { List retryResults = Lists.newArrayList(); m_failureCount = m_invoker.retryFailed( instance, m_testMethod, m_xmlSuite, m_testClass, m_beforeMethods, m_afterMethods, m_groupMethods, retryResults, m_failureCount, m_expectedExceptionHolder, m_testContext, m_parameters, m_parameterIndex); m_testResults.addAll(retryResults); } } // // If we have a failure, skip all the // other invocationCounts // // If not specified globally, use the attribute // on the annotation // if (! m_skipFailedInvocationCounts) { m_skipFailedInvocationCounts = m_testMethod.skipFailedInvocations(); } if (m_failureCount > 0 && m_skipFailedInvocationCounts) { while (m_invocationCount-- > 0) { ITestResult r = new TestResult(m_testMethod.getTestClass(), m_instance, m_testMethod, null, start, System.currentTimeMillis(), m_testContext); r.setStatus(TestResult.SKIP); m_testResults.add(r); m_invoker.runTestListeners(r); m_notifier.addSkippedTest(m_testMethod, r); } } } m_parameterIndex++; return m_testResults; } public List getTestResults() { return m_testResults; } public int getInvocationCount() { return m_invocationCount; } public int getFailureCount() { return m_failureCount; } } testng-6.9.12/src/main/java/org/testng/internal/junit/0000755000175000017500000000000012732165123022115 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/junit/InexactComparisonCriteria.java0000644000175000017500000000104712732165123030073 0ustar eugeneeugenepackage org.testng.internal.junit; import org.testng.AssertJUnit; public class InexactComparisonCriteria extends ComparisonCriteria { public double fDelta; public InexactComparisonCriteria(double delta) { fDelta= delta; } @Override protected void assertElementsEqual(Object expected, Object actual) { if (expected instanceof Double) AssertJUnit.assertEquals((Double)expected, (Double)actual, fDelta); else AssertJUnit.assertEquals((Float)expected, (Float)actual, fDelta); } }testng-6.9.12/src/main/java/org/testng/internal/junit/ExactComparisonCriteria.java0000644000175000017500000000043112732165123027540 0ustar eugeneeugenepackage org.testng.internal.junit; import org.testng.AssertJUnit; public class ExactComparisonCriteria extends ComparisonCriteria { @Override protected void assertElementsEqual(Object expected, Object actual) { AssertJUnit.assertEquals(expected, actual); } } testng-6.9.12/src/main/java/org/testng/internal/junit/ArrayAsserts.java0000644000175000017500000002251412732165123025407 0ustar eugeneeugenepackage org.testng.internal.junit; public class ArrayAsserts { /** * Asserts that two object arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. If * expecteds and actuals are null, * they are considered equal. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * Object array or array of arrays (multi-dimensional array) with * expected values. * @param actuals * Object array or array of arrays (multi-dimensional array) with * actual values */ public static void assertArrayEquals(String message, Object[] expecteds, Object[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two object arrays are equal. If they are not, an * {@link AssertionError} is thrown. If expected and * actual are null, they are considered * equal. * * @param expecteds * Object array or array of arrays (multi-dimensional array) with * expected values * @param actuals * Object array or array of arrays (multi-dimensional array) with * actual values */ public static void assertArrayEquals(Object[] expecteds, Object[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two byte arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * byte array with expected values. * @param actuals * byte array with actual values */ public static void assertArrayEquals(String message, byte[] expecteds, byte[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two byte arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * byte array with expected values. * @param actuals * byte array with actual values */ public static void assertArrayEquals(byte[] expecteds, byte[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two char arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * char array with expected values. * @param actuals * char array with actual values */ public static void assertArrayEquals(String message, char[] expecteds, char[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two char arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * char array with expected values. * @param actuals * char array with actual values */ public static void assertArrayEquals(char[] expecteds, char[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two short arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * short array with expected values. * @param actuals * short array with actual values */ public static void assertArrayEquals(String message, short[] expecteds, short[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two short arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * short array with expected values. * @param actuals * short array with actual values */ public static void assertArrayEquals(short[] expecteds, short[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two int arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * int array with expected values. * @param actuals * int array with actual values */ public static void assertArrayEquals(String message, int[] expecteds, int[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two int arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * int array with expected values. * @param actuals * int array with actual values */ public static void assertArrayEquals(int[] expecteds, int[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two long arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * long array with expected values. * @param actuals * long array with actual values */ public static void assertArrayEquals(String message, long[] expecteds, long[] actuals) throws ArrayComparisonFailure { internalArrayEquals(message, expecteds, actuals); } /** * Asserts that two long arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * long array with expected values. * @param actuals * long array with actual values */ public static void assertArrayEquals(long[] expecteds, long[] actuals) { assertArrayEquals(null, expecteds, actuals); } /** * Asserts that two double arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * double array with expected values. * @param actuals * double array with actual values */ public static void assertArrayEquals(String message, double[] expecteds, double[] actuals, double delta) throws ArrayComparisonFailure { new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals); } /** * Asserts that two double arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * double array with expected values. * @param actuals * double array with actual values */ public static void assertArrayEquals(double[] expecteds, double[] actuals, double delta) { assertArrayEquals(null, expecteds, actuals, delta); } /** * Asserts that two float arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * float array with expected values. * @param actuals * float array with actual values */ public static void assertArrayEquals(String message, float[] expecteds, float[] actuals, float delta) throws ArrayComparisonFailure { new InexactComparisonCriteria(delta).arrayEquals(message, expecteds, actuals); } /** * Asserts that two float arrays are equal. If they are not, an * {@link AssertionError} is thrown. * * @param expecteds * float array with expected values. * @param actuals * float array with actual values */ public static void assertArrayEquals(float[] expecteds, float[] actuals, float delta) { assertArrayEquals(null, expecteds, actuals, delta); } /** * Asserts that two object arrays are equal. If they are not, an * {@link AssertionError} is thrown with the given message. If * expecteds and actuals are null, * they are considered equal. * * @param message * the identifying message for the {@link AssertionError} (null * okay) * @param expecteds * Object array or array of arrays (multi-dimensional array) with * expected values. * @param actuals * Object array or array of arrays (multi-dimensional array) with * actual values */ private static void internalArrayEquals(String message, Object expecteds, Object actuals) throws ArrayComparisonFailure { new ExactComparisonCriteria().arrayEquals(message, expecteds, actuals); } } testng-6.9.12/src/main/java/org/testng/internal/junit/ComparisonCriteria.java0000644000175000017500000000554612732165123026567 0ustar eugeneeugenepackage org.testng.internal.junit; import org.testng.AssertJUnit; import java.lang.reflect.Array; /** * Defines criteria for finding two items "equal enough". Concrete subclasses * may demand exact equality, or, for example, equality within a given delta. */ public abstract class ComparisonCriteria { /** * Asserts that two arrays are equal, according to the criteria defined by * the concrete subclass. If they are not, an {@link AssertionError} is * thrown with the given message. If expecteds and * actuals are null, they are considered equal. * * @param message * the identifying message for the {@link AssertionError} ( * null okay) * @param expecteds * Object array or array of arrays (multi-dimensional array) with * expected values. * @param actuals * Object array or array of arrays (multi-dimensional array) with * actual values */ public void arrayEquals(String message, Object expecteds, Object actuals) throws ArrayComparisonFailure { if (expecteds == actuals) return; String header= message == null ? "" : message + ": "; int expectedsLength= assertArraysAreSameLength(expecteds, actuals, header); for (int i= 0; i < expectedsLength; i++) { Object expected= Array.get(expecteds, i); Object actual= Array.get(actuals, i); if (isArray(expected) && isArray(actual)) { try { arrayEquals(message, expected, actual); } catch (ArrayComparisonFailure e) { e.addDimension(i); throw e; } } else try { assertElementsEqual(expected, actual); } catch (AssertionError e) { throw new ArrayComparisonFailure(header, e, i); } } } private boolean isArray(Object expected) { return expected != null && expected.getClass().isArray(); } private int assertArraysAreSameLength(Object expecteds, Object actuals, String header) { if (expecteds == null) AssertJUnit.fail(header + "expected array was null"); if (actuals == null) AssertJUnit.fail(header + "actual array was null"); int actualsLength= Array.getLength(actuals); int expectedsLength= Array.getLength(expecteds); if (actualsLength != expectedsLength) AssertJUnit.fail(header + "array lengths differed, expected.length=" + expectedsLength + " actual.length=" + actualsLength); return expectedsLength; } protected abstract void assertElementsEqual(Object expected, Object actual); } testng-6.9.12/src/main/java/org/testng/internal/junit/ArrayComparisonFailure.java0000644000175000017500000000303412732165123027401 0ustar eugeneeugenepackage org.testng.internal.junit; import java.util.ArrayList; import java.util.List; /** * Thrown when two array elements differ */ public class ArrayComparisonFailure extends AssertionError { private static final long serialVersionUID= 1L; private List fIndices= new ArrayList<>(); private final String fMessage; private final AssertionError fCause; /** * Construct a new ArrayComparisonFailure with an error text and the array's * dimension that was not equal * @param cause the exception that caused the array's content to fail the assertion test * @param index the array position of the objects that are not equal. */ public ArrayComparisonFailure(String message, AssertionError cause, int index) { fMessage= message; fCause= cause; addDimension(index); } public void addDimension(int index) { fIndices.add(0, index); } @Override public String getMessage() { StringBuilder builder= new StringBuilder(); if (fMessage != null) builder.append(fMessage); builder.append("arrays first differed at element "); for (int each : fIndices) { builder.append("["); builder.append(each); builder.append("]"); } builder.append("; "); builder.append(fCause.getMessage()); return builder.toString(); } /** * {@inheritDoc} */ @Override public String toString() { return getMessage(); } } testng-6.9.12/src/main/java/org/testng/internal/ConfigurationMethod.java0000755000175000017500000003442412732165123025611 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; import org.testng.ITestNGMethod; import org.testng.annotations.IAnnotation; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.ConfigurationAnnotation; import org.testng.internal.annotations.IAfterClass; import org.testng.internal.annotations.IAfterGroups; import org.testng.internal.annotations.IAfterMethod; import org.testng.internal.annotations.IAfterSuite; import org.testng.internal.annotations.IAfterTest; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.annotations.IBeforeClass; import org.testng.internal.annotations.IBeforeGroups; import org.testng.internal.annotations.IBeforeMethod; import org.testng.internal.annotations.IBeforeSuite; import org.testng.internal.annotations.IBeforeTest; public class ConfigurationMethod extends BaseTestMethod { /** * */ private static final long serialVersionUID = -6537771498553619645L; private final boolean m_isBeforeSuiteConfiguration; private final boolean m_isAfterSuiteConfiguration; private final boolean m_isBeforeTestConfiguration; private final boolean m_isAfterTestConfiguration; private final boolean m_isBeforeClassConfiguration; private final boolean m_isAfterClassConfiguration; private final boolean m_isBeforeMethodConfiguration; private final boolean m_isAfterMethodConfiguration; private boolean m_inheritGroupsFromTestClass = false; private ConfigurationMethod(ConstructorOrMethod com, IAnnotationFinder annotationFinder, boolean isBeforeSuite, boolean isAfterSuite, boolean isBeforeTest, boolean isAfterTest, boolean isBeforeClass, boolean isAfterClass, boolean isBeforeMethod, boolean isAfterMethod, String[] beforeGroups, String[] afterGroups, boolean initialize, Object instance) { super(com.getName(), com, annotationFinder, instance); if(initialize) { init(); } m_isBeforeSuiteConfiguration = isBeforeSuite; m_isAfterSuiteConfiguration = isAfterSuite; m_isBeforeTestConfiguration = isBeforeTest; m_isAfterTestConfiguration = isAfterTest; m_isBeforeClassConfiguration = isBeforeClass; m_isAfterClassConfiguration = isAfterClass; m_isBeforeMethodConfiguration = isBeforeMethod; m_isAfterMethodConfiguration = isAfterMethod; m_beforeGroups = beforeGroups; m_afterGroups = afterGroups; } /** * @deprecated use #ConfigurationMethod(ConstructorOrMethod,...) instead. */ @Deprecated public ConfigurationMethod(Method method, IAnnotationFinder annotationFinder, boolean isBeforeSuite, boolean isAfterSuite, boolean isBeforeTest, boolean isAfterTest, boolean isBeforeClass, boolean isAfterClass, boolean isBeforeMethod, boolean isAfterMethod, String[] beforeGroups, String[] afterGroups, Object instance) { this(new ConstructorOrMethod(method), annotationFinder, isBeforeSuite, isAfterSuite, isBeforeTest, isAfterTest, isBeforeClass, isAfterClass, isBeforeMethod, isAfterMethod, beforeGroups, afterGroups, instance); } public ConfigurationMethod(ConstructorOrMethod com, IAnnotationFinder annotationFinder, boolean isBeforeSuite, boolean isAfterSuite, boolean isBeforeTest, boolean isAfterTest, boolean isBeforeClass, boolean isAfterClass, boolean isBeforeMethod, boolean isAfterMethod, String[] beforeGroups, String[] afterGroups, Object instance) { this(com, annotationFinder, isBeforeSuite, isAfterSuite, isBeforeTest, isAfterTest, isBeforeClass, isAfterClass, isBeforeMethod, isAfterMethod, beforeGroups, afterGroups, true, instance); } private static ITestNGMethod[] createMethods(ITestNGMethod[] methods, IAnnotationFinder finder, boolean isBeforeSuite, boolean isAfterSuite, boolean isBeforeTest, boolean isAfterTest, boolean isBeforeClass, boolean isAfterClass, boolean isBeforeMethod, boolean isAfterMethod, String[] beforeGroups, String[] afterGroups, Object instance) { List result = Lists.newArrayList(); for (ITestNGMethod method : methods) { result.add(new ConfigurationMethod(method.getConstructorOrMethod(), finder, isBeforeSuite, isAfterSuite, isBeforeTest, isAfterTest, isBeforeClass, isAfterClass, isBeforeMethod, isAfterMethod, new String[0], new String[0], instance)); } return result.toArray(new ITestNGMethod[result.size()]); } public static ITestNGMethod[] createSuiteConfigurationMethods(ITestNGMethod[] methods, IAnnotationFinder annotationFinder, boolean isBefore, Object instance) { return createMethods(methods, annotationFinder, isBefore, !isBefore, false, false, false, false, false, false, new String[0], new String[0], instance); } public static ITestNGMethod[] createTestConfigurationMethods(ITestNGMethod[] methods, IAnnotationFinder annotationFinder, boolean isBefore, Object instance) { return createMethods(methods, annotationFinder, false, false, isBefore, !isBefore, false, false, false, false, new String[0], new String[0], instance); } public static ITestNGMethod[] createClassConfigurationMethods(ITestNGMethod[] methods, IAnnotationFinder annotationFinder, boolean isBefore, Object instance) { return createMethods(methods, annotationFinder, false, false, false, false, isBefore, !isBefore, false, false, new String[0], new String[0], instance); } public static ITestNGMethod[] createBeforeConfigurationMethods(ITestNGMethod[] methods, IAnnotationFinder annotationFinder, boolean isBefore, Object instance) { ITestNGMethod[] result = new ITestNGMethod[methods.length]; for(int i = 0; i < methods.length; i++) { result[i] = new ConfigurationMethod(methods[i].getConstructorOrMethod(), annotationFinder, false, false, false, false, false, false, false, false, isBefore ? methods[i].getBeforeGroups() : new String[0], new String[0], instance); } return result; } public static ITestNGMethod[] createAfterConfigurationMethods(ITestNGMethod[] methods, IAnnotationFinder annotationFinder, boolean isBefore, Object instance) { ITestNGMethod[] result = new ITestNGMethod[methods.length]; for(int i = 0; i < methods.length; i++) { result[i] = new ConfigurationMethod(methods[i].getConstructorOrMethod(), annotationFinder, false, false, false, false, false, false, false, false, new String[0], isBefore ? new String[0] : methods[i].getAfterGroups(), instance); } return result; } public static ITestNGMethod[] createTestMethodConfigurationMethods(ITestNGMethod[] methods, IAnnotationFinder annotationFinder, boolean isBefore, Object instance) { return createMethods(methods, annotationFinder, false, false, false, false, false, false, isBefore, !isBefore, new String[0], new String[0], instance); } /** * @return Returns the isAfterClassConfiguration. */ @Override public boolean isAfterClassConfiguration() { return m_isAfterClassConfiguration; } /** * @return Returns the isAfterMethodConfiguration. */ @Override public boolean isAfterMethodConfiguration() { return m_isAfterMethodConfiguration; } /** * @return Returns the isBeforeClassConfiguration. */ @Override public boolean isBeforeClassConfiguration() { return m_isBeforeClassConfiguration; } /** * @return Returns the isBeforeMethodConfiguration. */ @Override public boolean isBeforeMethodConfiguration() { return m_isBeforeMethodConfiguration; } /** * @return Returns the isAfterSuiteConfiguration. */ @Override public boolean isAfterSuiteConfiguration() { return m_isAfterSuiteConfiguration; } /** * @return Returns the isBeforeSuiteConfiguration. */ @Override public boolean isBeforeSuiteConfiguration() { return m_isBeforeSuiteConfiguration; } @Override public boolean isBeforeTestConfiguration() { return m_isBeforeTestConfiguration; } @Override public boolean isAfterTestConfiguration() { return m_isAfterTestConfiguration; } @Override public boolean isBeforeGroupsConfiguration() { return m_beforeGroups != null && m_beforeGroups.length > 0; } @Override public boolean isAfterGroupsConfiguration() { return m_afterGroups != null && m_afterGroups.length > 0; } private boolean inheritGroupsFromTestClass() { return m_inheritGroupsFromTestClass; } private void init() { IAnnotation a = AnnotationHelper.findConfiguration(m_annotationFinder, m_method.getMethod()); IConfigurationAnnotation annotation = (IConfigurationAnnotation) a; if (a != null) { m_inheritGroupsFromTestClass = annotation.getInheritGroups(); setEnabled(annotation.getEnabled()); setDescription(annotation.getDescription()); } if (annotation != null && annotation.isFakeConfiguration()) { if (annotation.getBeforeSuite()) { initGroups(IBeforeSuite.class); } if (annotation.getAfterSuite()) { initGroups(IAfterSuite.class); } if (annotation.getBeforeTest()) { initGroups(IBeforeTest.class); } if (annotation.getAfterTest()) { initGroups(IAfterTest.class); } if (annotation.getBeforeGroups().length != 0) { initGroups(IBeforeGroups.class); } if (annotation.getAfterGroups().length != 0) { initGroups(IAfterGroups.class); } if (annotation.getBeforeTestClass()) { initGroups(IBeforeClass.class); } if (annotation.getAfterTestClass()) { initGroups(IAfterClass.class); } if (annotation.getBeforeTestMethod()) { initGroups(IBeforeMethod.class); } if (annotation.getAfterTestMethod()) { initGroups(IAfterMethod.class); } } else { initGroups(IConfigurationAnnotation.class); } // If this configuration method has inherit-groups=true, add the groups // defined in the @Test class if (inheritGroupsFromTestClass()) { ITestAnnotation classAnnotation = m_annotationFinder.findAnnotation(m_methodClass, ITestAnnotation.class); if (classAnnotation != null) { String[] groups = classAnnotation.getGroups(); Map newGroups = Maps.newHashMap(); for (String g : getGroups()) { newGroups.put(g, g); } if (groups != null) { for (String g : groups) { newGroups.put(g, g); } setGroups(newGroups.values().toArray(new String[newGroups.size()])); } } } if (annotation != null) { setTimeOut(annotation.getTimeOut()); } } private static void ppp(String s) { System.out.println("[ConfigurationMethod] " + s); } @Override public ConfigurationMethod clone() { ConfigurationMethod clone= new ConfigurationMethod(getConstructorOrMethod(), getAnnotationFinder(), isBeforeSuiteConfiguration(), isAfterSuiteConfiguration(), isBeforeTestConfiguration(), isAfterTestConfiguration(), isBeforeClassConfiguration(), isAfterClassConfiguration(), isBeforeMethodConfiguration(), isAfterMethodConfiguration(), getBeforeGroups(), getAfterGroups(), false /* do not call init() */, getInstance() ); clone.m_testClass= getTestClass(); clone.setDate(getDate()); clone.setGroups(getGroups()); clone.setGroupsDependedUpon(getGroupsDependedUpon(), Collections.emptyList()); clone.setMethodsDependedUpon(getMethodsDependedUpon()); clone.setAlwaysRun(isAlwaysRun()); clone.setMissingGroup(getMissingGroup()); clone.setDescription(getDescription()); clone.setEnabled(getEnabled()); clone.setParameterInvocationCount(getParameterInvocationCount()); clone.m_inheritGroupsFromTestClass= inheritGroupsFromTestClass(); return clone; } public boolean isFirstTimeOnly() { boolean result = false; IAnnotation before = m_annotationFinder.findAnnotation(getMethod(), IBeforeMethod.class); if (before != null) { result = ((ConfigurationAnnotation) before).isFirstTimeOnly(); } return result; } public boolean isLastTimeOnly() { boolean result = false; IAnnotation before = m_annotationFinder.findAnnotation(getMethod(), IAfterMethod.class); if (before != null) { result = ((ConfigurationAnnotation) before).isLastTimeOnly(); } return result; } } testng-6.9.12/src/main/java/org/testng/internal/Yaml.java0000644000175000017500000002225212732165123022534 0ustar eugeneeugenepackage org.testng.internal; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlPackage; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import org.yaml.snakeyaml.TypeDescription; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeId; import org.yaml.snakeyaml.nodes.ScalarNode; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.List; import java.util.Map; /** * YAML support for TestNG. * * @author Cedric Beust */ public class Yaml { public static XmlSuite parse(String filePath, InputStream is) throws FileNotFoundException { Constructor constructor = new TestNGConstructor(XmlSuite.class); { TypeDescription suiteDescription = new TypeDescription(XmlSuite.class); suiteDescription.putListPropertyType("packages", XmlPackage.class); suiteDescription.putListPropertyType("listeners", String.class); suiteDescription.putListPropertyType("tests", XmlTest.class); suiteDescription.putListPropertyType("method-selectors", XmlMethodSelector.class); constructor.addTypeDescription(suiteDescription); } { TypeDescription testDescription = new TypeDescription(XmlTest.class); testDescription.putListPropertyType("classes", XmlClass.class); testDescription.putMapPropertyType("metaGroups", String.class, List.class); testDescription.putListPropertyType("method-selectors", XmlMethodSelector.class); constructor.addTypeDescription(testDescription); } org.yaml.snakeyaml.Yaml y = new org.yaml.snakeyaml.Yaml(constructor); if (is == null) is = new FileInputStream(new File(filePath)); XmlSuite result = (XmlSuite) y.load(is); result.setFileName(filePath); // DEBUG // System.out.println("[Yaml] " + result.toXml()); // Adjust XmlTest parents and indices for (XmlTest t : result.getTests()) { t.setSuite(result); int index = 0; for (XmlClass c : t.getClasses()) { c.setIndex(index++); } } return result; } private static void maybeAdd(StringBuilder sb, String key, Object value, Object def) { maybeAdd(sb, "", key, value, def); } private static void maybeAdd(StringBuilder sb, String sp, String key, Object value, Object def) { if (value != null && ! value.equals(def)) { sb.append(sp).append(key).append(": ").append(value.toString()).append("\n"); } } /** * The main entry point to convert an XmlSuite into YAML. This method is allowed to be used * by external tools (e.g. Eclipse). */ public static StringBuilder toYaml(XmlSuite suite) { StringBuilder result = new StringBuilder(); maybeAdd(result, "name", suite.getName(), null); maybeAdd(result, "junit", suite.isJUnit(), XmlSuite.DEFAULT_JUNIT); maybeAdd(result, "verbose", suite.getVerbose(), XmlSuite.DEFAULT_VERBOSE); maybeAdd(result, "threadCount", suite.getThreadCount(), XmlSuite.DEFAULT_THREAD_COUNT); maybeAdd(result, "dataProviderThreadCount", suite.getDataProviderThreadCount(), XmlSuite.DEFAULT_DATA_PROVIDER_THREAD_COUNT); maybeAdd(result, "timeOut", suite.getTimeOut(), null); maybeAdd(result, "parallel", suite.getParallel(), XmlSuite.DEFAULT_PARALLEL); maybeAdd(result, "skipFailedInvocationCounts", suite.skipFailedInvocationCounts(), XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS); toYaml(result, "parameters", "", suite.getParameters()); toYaml(result, suite.getPackages()); if (suite.getListeners().size() > 0) { result.append("listeners:\n"); toYaml(result, " ", suite.getListeners()); } if (suite.getPackages().size() > 0) { result.append("packages:\n"); toYaml(result, suite.getPackages()); } if (suite.getTests().size() > 0) { result.append("tests:\n"); for (XmlTest t : suite.getTests()) { toYaml(result, " ", t); } } if (suite.getChildSuites().size() > 0) { result.append("suite-files:\n"); toYaml(result, " ", suite.getSuiteFiles()); } return result; } private static void toYaml(StringBuilder result, String sp, XmlTest t) { String sp2 = sp + " "; result.append(sp).append("- name: ").append(t.getName()).append("\n"); maybeAdd(result, sp2, "junit", t.isJUnit(), XmlSuite.DEFAULT_JUNIT); maybeAdd(result, sp2, "verbose", t.getVerbose(), XmlSuite.DEFAULT_VERBOSE); maybeAdd(result, sp2, "timeOut", t.getTimeOut(), null); maybeAdd(result, sp2, "parallel", t.getParallel(), XmlSuite.DEFAULT_PARALLEL); maybeAdd(result, sp2, "skipFailedInvocationCounts", t.skipFailedInvocationCounts(), XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS); maybeAdd(result, "preserveOrder", sp2, t.getPreserveOrder(), XmlSuite.DEFAULT_PRESERVE_ORDER); toYaml(result, "parameters", sp2, t.getLocalParameters()); if (t.getIncludedGroups().size() > 0) { result.append(sp2).append("includedGroups: [ ") .append(Utils.join(t.getIncludedGroups(), ",")) .append(" ]\n"); } if (t.getExcludedGroups().size() > 0) { result.append(sp2).append("excludedGroups: [ ") .append(Utils.join(t.getExcludedGroups(), ",")) .append(" ]\n"); } Map> mg = t.getMetaGroups(); if (mg.size() > 0) { result.append(sp2).append("metaGroups: { "); boolean first = true; for (Map.Entry> entry : mg.entrySet()) { if (! first) result.append(", "); result.append(entry.getKey()).append(": [ ") .append(Utils.join(entry.getValue(), ",")).append(" ] "); first = false; } result.append(" }\n"); } if (t.getXmlPackages().size() > 0) { result.append(sp2).append("xmlPackages:\n"); for (XmlPackage xp : t.getXmlPackages()) { toYaml(result, sp2 + " - ", xp); } } if (t.getXmlClasses().size() > 0) { result.append(sp2).append("classes:\n"); for (XmlClass xc : t.getXmlClasses()) { toYaml(result, sp2 + " ", xc); } } result.append("\n"); } private static void toYaml(StringBuilder result, String sp2, XmlClass xc) { List im = xc.getIncludedMethods(); List em = xc.getExcludedMethods(); String name = im.size() > 0 || em.size() > 0 ? "name: " : ""; result.append(sp2).append("- " + name).append(xc.getName()).append("\n"); if (im.size() > 0) { result.append(sp2 + " includedMethods:\n"); for (XmlInclude xi : im) { toYaml(result, sp2 + " ", xi); } } if (em.size() > 0) { result.append(sp2 + " excludedMethods:\n"); toYaml(result, sp2 + " ", em); } } private static void toYaml(StringBuilder result, String sp2, XmlInclude xi) { result.append(sp2 + "- " + xi.getName()).append("\n"); } private static void toYaml(StringBuilder result, String sp, List strings) { for (String l : strings) { result.append(sp).append("- ").append(l).append("\n"); } } private static final String SP = " "; private static void toYaml(StringBuilder sb, List packages) { if (packages.size() > 0) { sb.append("packages:\n"); for (XmlPackage p : packages) { toYaml(sb, " ", p); } } for (XmlPackage p : packages) { toYaml(sb, " ", p); } } private static void toYaml(StringBuilder sb, String sp, XmlPackage p) { sb.append(sp).append("name: ").append(p.getName()).append("\n"); generateIncludeExclude(sb, sp, "includes", p.getInclude()); generateIncludeExclude(sb, sp, "excludes", p.getExclude()); } private static void generateIncludeExclude(StringBuilder sb, String sp, String key, List includes) { if (includes.size() > 0) { sb.append(sp).append(" ").append(key).append("\n"); for (String inc : includes) { sb.append(sp).append(" ").append(inc); } } } private static void mapToYaml(Map map, StringBuilder out) { if (map.size() > 0) { out.append("{ "); boolean first = true; for (Map.Entry e : map.entrySet()) { if (! first) out.append(", "); first = false; out.append(e.getKey() + ": " + e.getValue()); } out.append(" }\n"); } } private static void toYaml(StringBuilder sb, String key, String sp, Map parameters) { if (parameters.size() > 0) { sb.append(sp).append(key).append(": "); mapToYaml(parameters, sb); } } private static class TestNGConstructor extends Constructor { public TestNGConstructor(Class theRoot) { super(theRoot); yamlClassConstructors.put(NodeId.scalar, new ConstructParallelMode()); } private class ConstructParallelMode extends ConstructScalar { public Object construct(Node node) { if (node.getType().equals(XmlSuite.ParallelMode.class)) { String parallel = (String) constructScalar((ScalarNode) node); return XmlSuite.ParallelMode.getValidParallel(parallel); } return super.construct(node); } } } } testng-6.9.12/src/main/java/org/testng/internal/BaseClassFinder.java0000755000175000017500000000332712732165123024627 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IClass; import org.testng.ITestClassFinder; import org.testng.ITestContext; import org.testng.ITestObjectFactory; import org.testng.collections.Maps; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlClass; import org.testng.xml.XmlTest; import java.util.Map; /** * This class * * @author Cedric Beust */ abstract public class BaseClassFinder implements ITestClassFinder { private Map m_classes = Maps.newLinkedHashMap(); @Override public IClass getIClass(Class cls) { return m_classes.get(cls); } protected void putIClass(Class cls, IClass iClass) { if (! m_classes.containsKey(cls)) { m_classes.put(cls, iClass); } } private void ppp(String s) { System.out.println("[BaseClassFinder] " + s); } /** * @param cls * @return An IClass for the given class, or null if we have * already treated this class. */ protected IClass findOrCreateIClass(ITestContext context, Class cls, XmlClass xmlClass, Object instance, XmlTest xmlTest, IAnnotationFinder annotationFinder, ITestObjectFactory objectFactory) { IClass result = m_classes.get(cls); if (null == result) { result = new ClassImpl(context, cls, xmlClass, instance, m_classes, xmlTest, annotationFinder, objectFactory); m_classes.put(cls, result); } return result; } protected Map getExistingClasses() { return m_classes; } protected boolean classExists(Class cls) { return m_classes.containsKey(cls); } @Override public IClass[] findTestClasses() { return m_classes.values().toArray(new IClass[m_classes.size()]); } } testng-6.9.12/src/main/java/org/testng/internal/BshMock.java0000644000175000017500000000034112732165123023153 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ITestNGMethod; public class BshMock implements IBsh { @Override public boolean includeMethodFromExpression(String expression, ITestNGMethod tm) { return false; } } testng-6.9.12/src/main/java/org/testng/internal/ExtraOutput.java0000755000175000017500000000123712732165123024141 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IExtraOutput; import org.testng.collections.Lists; import java.util.List; /** * This class is used by Reporter to store the extra output to be later * included in the HTML report: * - User-generated report * - Parameter info * * Created on Feb 16, 2006 * @author Cedric Beust */ public class ExtraOutput implements IExtraOutput { /** * */ private static final long serialVersionUID = 8195388419611912192L; private List m_parameterOutput = Lists.newArrayList(); @Override public List getParameterOutput() { return m_parameterOutput; } } testng-6.9.12/src/main/java/org/testng/internal/ClassInfoMap.java0000644000175000017500000000301512732165123024145 0ustar eugeneeugenepackage org.testng.internal; import org.testng.collections.Maps; import org.testng.xml.XmlClass; import java.util.List; import java.util.Map; import java.util.Set; public class ClassInfoMap { private Map, XmlClass> m_map = Maps.newLinkedHashMap(); private boolean includeNestedClasses; public ClassInfoMap() { } public ClassInfoMap(List classes) { this(classes, true); } public ClassInfoMap(List classes, boolean includeNested) { includeNestedClasses = includeNested; for (XmlClass xmlClass : classes) { try { Class c = xmlClass.getSupportClass(); registerClass(c, xmlClass); } catch (NoClassDefFoundError e) { Utils.log("[ClassInfoMap]", 1, "Unable to open class " + xmlClass.getName() + " - unable to resolve class reference " + e.getMessage()); if (xmlClass.loadClasses()) { throw e; } } } } private void registerClass(Class cl, XmlClass xmlClass) { m_map.put(cl, xmlClass); if (includeNestedClasses) { for (Class c : cl.getClasses()) { if (! m_map.containsKey(c)) registerClass(c, xmlClass); } } } public void addClass(Class cls) { m_map.put(cls, null); } public XmlClass getXmlClass(Class cls) { return m_map.get(cls); } public void put(Class cls, XmlClass xmlClass) { m_map.put(cls, xmlClass); } public Set> getClasses() { return m_map.keySet(); } public int getSize() { return m_map.size(); } } testng-6.9.12/src/main/java/org/testng/internal/ThreeStateBoolean.java0000644000175000017500000000037712732165123025206 0ustar eugeneeugenepackage org.testng.internal; /** * For boolean use cases were 'non-existence' can not be defaulted to either true or false. * * @author Nitin Verma */ public enum ThreeStateBoolean { NONE, TRUE, FALSE; } testng-6.9.12/src/main/java/org/testng/internal/IBsh.java0000644000175000017500000000024612732165123022456 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ITestNGMethod; public interface IBsh { boolean includeMethodFromExpression(String expression, ITestNGMethod tm); } testng-6.9.12/src/main/java/org/testng/internal/ClonedMethod.java0000755000175000017500000001622312732165123024203 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IClass; import org.testng.IRetryAnalyzer; import org.testng.ITestClass; import org.testng.ITestNGMethod; import org.testng.collections.Lists; import org.testng.xml.XmlTest; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; public class ClonedMethod implements ITestNGMethod { private static final long serialVersionUID = 1L; private ITestNGMethod m_method; transient private Method m_javaMethod; private String m_id; private int m_currentInvocationCount; private long m_date; private List m_invocationNumbers = Lists.newArrayList(); private List m_failedInvocationNumbers = Lists.newArrayList(); public ClonedMethod(ITestNGMethod method, Method javaMethod) { m_method = method; m_javaMethod = javaMethod; } @Override public void addMethodDependedUpon(String methodName) { // nop } @Override public boolean canRunFromClass(IClass testClass) { return m_method.canRunFromClass(testClass); } @Override public String[] getAfterGroups() { return m_method.getAfterGroups(); } @Override public String[] getBeforeGroups() { return m_method.getBeforeGroups(); } @Override public int getCurrentInvocationCount() { return m_currentInvocationCount; } @Override public long getDate() { return m_method.getDate(); } @Override public String getDescription() { return ""; } @Override public void setDescription(String description) { m_method.setDescription(description); } @Override public boolean getEnabled() { return true; } @Override public String[] getGroups() { return m_method.getGroups(); } @Override public String[] getGroupsDependedUpon() { return new String[0]; } @Override public String getId() { return m_id; } @Override public long[] getInstanceHashCodes() { return m_method.getInstanceHashCodes(); } @Override public Object[] getInstances() { return m_method.getInstances(); } @Override public Object getInstance() { return m_method.getInstance(); } @Override public int getInvocationCount() { return 1; } @Override public int getTotalInvocationCount() { return 1; } @Override public long getInvocationTimeOut() { return m_method.getInvocationTimeOut(); } @Override public Method getMethod() { return m_javaMethod; } @Override public String getMethodName() { return m_javaMethod.getName(); } @Override public String[] getMethodsDependedUpon() { return new String[0]; } @Override public String getMissingGroup() { return null; } @Override public int getParameterInvocationCount() { return 1; } @Override public void setMoreInvocationChecker(Callable moreInvocationChecker) {} @Override public boolean hasMoreInvocation() { return false; } @Override public Class getRealClass() { return m_javaMethod.getClass(); } @Override public IRetryAnalyzer getRetryAnalyzer() { return m_method.getRetryAnalyzer(); } @Override public int getSuccessPercentage() { return 100; } @Override public ITestClass getTestClass() { return m_method.getTestClass(); } @Override public int getThreadPoolSize() { return m_method.getThreadPoolSize(); } @Override public long getTimeOut() { return m_method.getTimeOut(); } @Override public void setTimeOut(long timeOut) { m_method.setTimeOut(timeOut); } @Override public boolean ignoreMissingDependencies() { return false; } @Override public void incrementCurrentInvocationCount() { m_currentInvocationCount++; } @Override public boolean isAfterClassConfiguration() { return false; } @Override public boolean isAfterGroupsConfiguration() { return false; } @Override public boolean isAfterMethodConfiguration() { return false; } @Override public boolean isAfterSuiteConfiguration() { return false; } @Override public boolean isAfterTestConfiguration() { return false; } @Override public boolean isAlwaysRun() { return false; } @Override public boolean isBeforeClassConfiguration() { return false; } @Override public boolean isBeforeGroupsConfiguration() { return false; } @Override public boolean isBeforeMethodConfiguration() { return false; } @Override public boolean isBeforeSuiteConfiguration() { return false; } @Override public boolean isBeforeTestConfiguration() { return false; } @Override public boolean isTest() { return true; } @Override public void setDate(long date) { m_date = date; } @Override public void setId(String id) { m_id = id; } @Override public void setIgnoreMissingDependencies(boolean ignore) { } @Override public void setInvocationCount(int count) { } @Override public void setMissingGroup(String group) { } @Override public void setParameterInvocationCount(int n) { } @Override public void setRetryAnalyzer(IRetryAnalyzer retryAnalyzer) { } @Override public void setSkipFailedInvocations(boolean skip) { } @Override public void setTestClass(ITestClass cls) { } @Override public void setThreadPoolSize(int threadPoolSize) { } @Override public boolean skipFailedInvocations() { return false; } @Override public int compareTo(Object o) { int result = -2; Class thisClass = getRealClass(); Class otherClass = ((ITestNGMethod) o).getRealClass(); if (thisClass.isAssignableFrom(otherClass)) { result = -1; } else if (otherClass.isAssignableFrom(thisClass)) { result = 1; } else if (equals(o)) { result = 0; } return result; } @Override public ClonedMethod clone() { return new ClonedMethod(m_method, m_javaMethod); } @Override public String toString() { Method m = getMethod(); String cls = m.getDeclaringClass().getName(); StringBuffer result = new StringBuffer(cls + "." + m.getName() + "("); int i = 0; for (Class p : m.getParameterTypes()) { if (i++ > 0) { result.append(", "); } result.append(p.getName()); } result.append(")"); return result.toString(); } @Override public List getInvocationNumbers() { return m_invocationNumbers; } @Override public void setInvocationNumbers(List count) { m_invocationNumbers = count; } @Override public List getFailedInvocationNumbers() { return m_failedInvocationNumbers; } @Override public void addFailedInvocationNumber(int number) { m_failedInvocationNumbers.add(number); } @Override public int getPriority() { return m_method.getPriority(); } @Override public void setPriority(int priority) { // ignored } @Override public XmlTest getXmlTest() { return m_method.getXmlTest(); } @Override public ConstructorOrMethod getConstructorOrMethod() { return null; } @Override public Map findMethodParameters(XmlTest test) { return Collections.emptyMap(); } } testng-6.9.12/src/main/java/org/testng/internal/Configuration.java0000644000175000017500000000453212732165123024442 0ustar eugeneeugenepackage org.testng.internal; import org.testng.*; import org.testng.collections.Lists; import org.testng.internal.annotations.DefaultAnnotationTransformer; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.annotations.JDK15AnnotationFinder; import java.util.List; public class Configuration implements IConfiguration { IAnnotationFinder m_annotationFinder; ITestObjectFactory m_objectFactory; IHookable m_hookable; IConfigurable m_configurable; List m_executionListeners = Lists.newArrayList(); List m_alterSuiteListeners = Lists.newArrayList(); private List m_configurationListeners = Lists.newArrayList(); public Configuration() { init(new JDK15AnnotationFinder(new DefaultAnnotationTransformer())); } public Configuration(IAnnotationFinder finder) { init(finder); } private void init(IAnnotationFinder finder) { m_annotationFinder = finder; } @Override public IAnnotationFinder getAnnotationFinder() { return m_annotationFinder; } @Override public void setAnnotationFinder(IAnnotationFinder finder) { m_annotationFinder = finder; } @Override public ITestObjectFactory getObjectFactory() { return m_objectFactory; } @Override public void setObjectFactory(ITestObjectFactory factory) { m_objectFactory = factory; } @Override public IHookable getHookable() { return m_hookable; } @Override public void setHookable(IHookable h) { m_hookable = h; } @Override public IConfigurable getConfigurable() { return m_configurable; } @Override public void setConfigurable(IConfigurable c) { m_configurable = c; } @Override public List getExecutionListeners() { return m_executionListeners; } @Override public void addExecutionListener(IExecutionListener l) { m_executionListeners.add(l); } @Override public List getConfigurationListeners() { return Lists.newArrayList(m_configurationListeners); } @Override public void addConfigurationListener(IConfigurationListener cl) { if (! m_configurationListeners.contains(cl)) { m_configurationListeners.add(cl); } } @Override public List getAlterSuiteListeners() { return m_alterSuiteListeners; } } testng-6.9.12/src/main/java/org/testng/internal/TestResult.java0000644000175000017500000001636312732165123023756 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IAttributes; import org.testng.IClass; import org.testng.ITest; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.collections.Objects; import java.util.List; import java.util.Set; /** * This class represents the result of a test. * * @author Cedric Beust, May 2, 2004 */ public class TestResult implements ITestResult { private static final long serialVersionUID = 6273017418233324556L; private IClass m_testClass = null; private ITestNGMethod m_method = null; private int m_status = -1; private Throwable m_throwable = null; private long m_startMillis = 0; private long m_endMillis = 0; private String m_name = null; private String m_host; transient private Object[] m_parameters = {}; transient private Object m_instance; private String m_instanceName; private ITestContext m_context; public TestResult() { } public TestResult(IClass testClass, Object instance, ITestNGMethod method, Throwable throwable, long start, long end, ITestContext context) { init(testClass, instance, method, throwable, start, end, context); } /** * * @param testClass * @param instance * @param method * @param throwable * @param start * @param end */ public void init (IClass testClass, Object instance, ITestNGMethod method, Throwable throwable, long start, long end, ITestContext context) { m_testClass = testClass; m_throwable = throwable; m_instanceName = m_testClass.getName(); if (null == m_throwable) { m_status = ITestResult.SUCCESS; } m_startMillis = start; m_endMillis = end; m_method = method; m_context = context; m_instance = instance; // Calculate the name: either the method name, ITest#getTestName or // toString() if it's been overridden. if (m_instance == null) { m_name = m_method.getMethodName(); } else { if (m_instance instanceof ITest) { m_name = ((ITest) m_instance).getTestName(); } else if (testClass.getTestName() != null) { m_name = testClass.getTestName(); } else { String string = m_instance.toString(); // Only display toString() if it's been overridden by the user m_name = getMethod().getMethodName(); try { if (!Object.class.getMethod("toString") .equals(m_instance.getClass().getMethod("toString"))) { m_instanceName = string.startsWith("class ") ? string.substring("class ".length()) : string; m_name = m_name + " on " + m_instanceName; } } catch(NoSuchMethodException ignore) { // ignore } } } } private static void ppp(String s) { System.out.println("[TestResult] " + s); } @Override public void setEndMillis(long millis) { m_endMillis = millis; } /** * If this result's related instance implements ITest or use @Test(testName=...), returns its test name, * otherwise returns null. */ @Override public String getTestName() { if (m_instance instanceof ITest) { return ((ITest) m_instance).getTestName(); } if (m_testClass.getTestName() != null) { return m_testClass.getTestName(); } return null; } @Override public String getName() { return m_name; } /** * @return Returns the method. */ @Override public ITestNGMethod getMethod() { return m_method; } /** * @param method The method to set. */ public void setMethod(ITestNGMethod method) { m_method = method; } /** * @return Returns the status. */ @Override public int getStatus() { return m_status; } /** * @param status The status to set. */ @Override public void setStatus(int status) { m_status = status; } @Override public boolean isSuccess() { return ITestResult.SUCCESS == m_status; } /** * @return Returns the testClass. */ @Override public IClass getTestClass() { return m_testClass; } /** * @param testClass The testClass to set. */ public void setTestClass(IClass testClass) { m_testClass = testClass; } /** * @return Returns the throwable. */ @Override public Throwable getThrowable() { return m_throwable; } /** * @param throwable The throwable to set. */ @Override public void setThrowable(Throwable throwable) { m_throwable = throwable; } /** * @return Returns the endMillis. */ @Override public long getEndMillis() { return m_endMillis; } /** * @return Returns the startMillis. */ @Override public long getStartMillis() { return m_startMillis; } // public List getOutput() { // return m_output; // } @Override public String toString() { List output = Reporter.getOutput(this); String result = Objects.toStringHelper(getClass()) .omitNulls() .omitEmptyStrings() .add("name", getName()) .add("status", toString(m_status)) .add("method", m_method) .add("output", output != null && output.size() > 0 ? output.get(0) : null) .toString(); return result; } private String toString(int status) { switch(status) { case SUCCESS: return "SUCCESS"; case FAILURE: return "FAILURE"; case SKIP: return "SKIP"; case SUCCESS_PERCENTAGE_FAILURE: return "SUCCESS WITHIN PERCENTAGE"; case STARTED: return "STARTED"; default: throw new RuntimeException(); } } @Override public String getHost() { return m_host; } public void setHost(String host) { m_host = host; } @Override public Object[] getParameters() { return m_parameters; } @Override public void setParameters(Object[] parameters) { m_parameters = parameters; } @Override public Object getInstance() { return m_instance; } private IAttributes m_attributes = new Attributes(); @Override public Object getAttribute(String name) { return m_attributes.getAttribute(name); } @Override public void setAttribute(String name, Object value) { m_attributes.setAttribute(name, value); } @Override public Set getAttributeNames() { return m_attributes.getAttributeNames(); } @Override public Object removeAttribute(String name) { return m_attributes.removeAttribute(name); } @Override public ITestContext getTestContext() { return m_context; } public void setContext(ITestContext context) { m_context = context; } @Override public int compareTo(ITestResult comparison) { if( getStartMillis() > comparison.getStartMillis() ) { return 1; } else if( getStartMillis() < comparison.getStartMillis()) { return -1; } else { return 0; } } @Override public String getInstanceName() { return m_instanceName; } } testng-6.9.12/src/main/java/org/testng/internal/YamlParser.java0000644000175000017500000000114212732165123023704 0ustar eugeneeugenepackage org.testng.internal; import org.testng.TestNGException; import org.testng.xml.ISuiteParser; import org.testng.xml.XmlSuite; import java.io.FileNotFoundException; import java.io.InputStream; public class YamlParser implements ISuiteParser { @Override public XmlSuite parse(String filePath, InputStream is, boolean loadClasses) throws TestNGException { try { return Yaml.parse(filePath, is); } catch (FileNotFoundException e) { throw new TestNGException(e); } } @Override public boolean accept(String fileName) { return fileName.endsWith(".yaml"); } } testng-6.9.12/src/main/java/org/testng/internal/MethodInheritance.java0000755000175000017500000001163312732165123025230 0ustar eugeneeugenepackage org.testng.internal; import java.util.Collections; import java.util.List; import java.util.Map; import org.testng.ITestNGMethod; import org.testng.collections.Lists; import org.testng.collections.Maps; public class MethodInheritance { /** * Look in map for a class that is a superclass of methodClass */ private static List findMethodListSuperClass(Map> map, Class< ? extends ITestNGMethod> methodClass) { for (Map.Entry> entry : map.entrySet()) { if (entry.getKey().isAssignableFrom(methodClass)) { return entry.getValue(); } } return null; } /** * Look in map for a class that is a subclass of methodClass */ private static Class findSubClass(Map> map, Class< ? extends ITestNGMethod> methodClass) { for (Class cls : map.keySet()) { if (methodClass.isAssignableFrom(cls)) { return cls; } } return null; } /** * Fix the methodsDependedUpon to make sure that @Configuration methods * respect inheritance (before methods are invoked in the order Base first * and after methods are invoked in the order Child first) * * @param methods the list of methods * @param before true if we are handling a before method (meaning, the methods * need to be sorted base class first and subclass last). false otherwise (subclass * methods first, base classes last). */ public static void fixMethodInheritance(ITestNGMethod[] methods, boolean before) { // Map of classes -> List of methods that belong to this class or same hierarchy Map> map = Maps.newHashMap(); // // Put the list of methods in their hierarchy buckets // for (ITestNGMethod method : methods) { Class< ? extends ITestNGMethod> methodClass = method.getRealClass(); List l = findMethodListSuperClass(map, methodClass); if (null != l) { l.add(method); } else { Class subClass = findSubClass(map, methodClass); if (null != subClass) { l = map.get(subClass); l.add(method); map.remove(subClass); map.put(methodClass, l); } else { l = Lists.newArrayList(); l.add(method); map.put(methodClass, l); } } } // // Each bucket that has a list bigger than one element gets sorted // for (List l : map.values()) { if (l.size() > 1) { // Sort them sortMethodsByInheritance(l, before); /* * Set methodDependedUpon accordingly * E.g. Base class can have multiple @BeforeClass methods. Need to ensure * that @BeforeClass methods in derived class depend on all @BeforeClass methods * of base class. Vice versa for @AfterXXX methods */ for (int i = 0; i < l.size() - 1; i++) { ITestNGMethod m1 = l.get(i); for (int j = i + 1; j < l.size(); j++) { ITestNGMethod m2 = l.get(j); if (!equalsEffectiveClass(m1, m2) && !dependencyExists(m1, m2, methods)) { Utils.log("MethodInheritance", 4, m2 + " DEPENDS ON " + m1); m2.addMethodDependedUpon(MethodHelper.calculateMethodCanonicalName(m1)); } } } } } } private static boolean dependencyExists(ITestNGMethod m1, ITestNGMethod m2, ITestNGMethod[] methods) { return internalDependencyExists(m1, m2, methods) || internalDependencyExists(m2, m1, methods); } private static boolean internalDependencyExists(ITestNGMethod m1, ITestNGMethod m2, ITestNGMethod[] methods) { ITestNGMethod[] methodsNamed = MethodHelper.findDependedUponMethods(m1, methods); for (ITestNGMethod method : methodsNamed) { if (method.equals(m2)) { return true; } } for (String group : m1.getGroupsDependedUpon()) { ITestNGMethod[] methodsThatBelongToGroup = MethodGroupsHelper.findMethodsThatBelongToGroup(m1, methods, group); for (ITestNGMethod method : methodsThatBelongToGroup) { if (method.equals(m2)) { return true; } } } return false; } private static boolean equalsEffectiveClass(ITestNGMethod m1, ITestNGMethod m2) { try { Class c1 = m1.getRealClass(); Class c2 = m2.getRealClass(); return c1 == null ? c2 == null : c1.equals(c2); } catch(Exception ex) { return false; } } /** * Given a list of methods belonging to the same class hierarchy, orders them * from the base class to the child (if true) or from child to base class (if false) * @param methods */ private static void sortMethodsByInheritance(List methods, boolean baseClassToChild) { Collections.sort(methods); if (! baseClassToChild) { Collections.reverse(methods); } } } testng-6.9.12/src/main/java/org/testng/internal/MethodSelectorDescriptor.java0000755000175000017500000000211612732165123026612 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IMethodSelector; import org.testng.ITestNGMethod; import java.util.List; /** * This class describes a method selector: * - The class that implements it * - Its priority * * Created on Sep 26, 2005 * @author cbeust */ public class MethodSelectorDescriptor implements Comparable { private IMethodSelector m_methodSelector; private int m_priority; public int getPriority() { return m_priority; } public IMethodSelector getMethodSelector() { return m_methodSelector; } public MethodSelectorDescriptor(IMethodSelector selector, int priority) { m_methodSelector = selector; m_priority = priority; } @Override public int compareTo(MethodSelectorDescriptor other) { int result = 0; try { int p1 = getPriority(); int p2 = other.getPriority(); result = p1 - p2; } catch(Exception ex) { // ignore } return result; } public void setTestMethods(List testMethods) { m_methodSelector.setTestMethods(testMethods); } } testng-6.9.12/src/main/java/org/testng/internal/MethodHelper.java0000644000175000017500000003025712732165123024216 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import org.testng.ITestNGMethod; import org.testng.TestNGException; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.annotations.ITestOrConfiguration; import org.testng.collections.Lists; import org.testng.collections.Sets; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.collections.Pair; /** * Collection of helper methods to help sort and arrange methods. * * @author Cedric Beust * @author Alexandru Popescu */ public class MethodHelper { private static final Map> GRAPH_CACHE = new ConcurrentHashMap<>(); private static final Map CANONICAL_NAME_CACHE = new ConcurrentHashMap<>(); private static final Map, Boolean> MATCH_CACHE = new ConcurrentHashMap<>(); /** * Collects and orders test or configuration methods * @param methods methods to be worked on * @param forTests true for test methods, false for configuration methods * @param runInfo * @param finder annotation finder * @param unique true for unique methods, false otherwise * @param outExcludedMethods * @return list of ordered methods */ public static ITestNGMethod[] collectAndOrderMethods(List methods, boolean forTests, RunInfo runInfo, IAnnotationFinder finder, boolean unique, List outExcludedMethods) { List includedMethods = Lists.newArrayList(); MethodGroupsHelper.collectMethodsByGroup(methods.toArray(new ITestNGMethod[methods.size()]), forTests, includedMethods, outExcludedMethods, runInfo, finder, unique); return sortMethods(forTests, includedMethods, finder).toArray(new ITestNGMethod[]{}); } /** * Finds TestNG methods that the specified TestNG method depends upon * @param m TestNG method * @param methods list of methods to search for depended upon methods * @return list of methods that match the criteria */ protected static ITestNGMethod[] findDependedUponMethods(ITestNGMethod m, ITestNGMethod[] methods) { String canonicalMethodName = calculateMethodCanonicalName(m); List vResult = Lists.newArrayList(); String regexp = null; for (String fullyQualifiedRegexp : m.getMethodsDependedUpon()) { boolean foundAtLeastAMethod = false; if (null != fullyQualifiedRegexp) { // Escapes $ in regexps as it is not meant for end - line matching, but inner class matches. regexp = fullyQualifiedRegexp.replace("$", "\\$"); boolean usePackage = regexp.indexOf('.') != -1; Pattern pattern = Pattern.compile(regexp); for (ITestNGMethod method : methods) { Method thisMethod = method.getMethod(); String thisMethodName = thisMethod.getName(); String methodName = usePackage ? calculateMethodCanonicalName(thisMethod) : thisMethodName; Pair cacheKey = Pair.create(regexp, methodName); Boolean match = MATCH_CACHE.get(cacheKey); if (match == null) { match = pattern.matcher(methodName).matches(); MATCH_CACHE.put(cacheKey, match); } if (match) { vResult.add(method); foundAtLeastAMethod = true; } } } if (!foundAtLeastAMethod) { if (m.ignoreMissingDependencies()) { continue; } if (m.isAlwaysRun()) { continue; } Method maybeReferringTo = findMethodByName(m, regexp); if (maybeReferringTo != null) { throw new TestNGException(canonicalMethodName + "() is depending on method " + maybeReferringTo + ", which is not annotated with @Test or not included."); } throw new TestNGException(canonicalMethodName + "() depends on nonexistent method " + regexp); } }//end for return vResult.toArray(new ITestNGMethod[vResult.size()]); } /** * Finds method based on regex and TestNGMethod. If regex doesn't represent the * class name, uses the TestNG method's class name. * @param testngMethod TestNG method * @param regExp regex representing a method and/or related class name */ private static Method findMethodByName(ITestNGMethod testngMethod, String regExp) { if (regExp == null) { return null; } int lastDot = regExp.lastIndexOf('.'); String className, methodName; if (lastDot == -1) { className = testngMethod.getMethod().getDeclaringClass().getCanonicalName(); methodName = regExp; } else { methodName = regExp.substring(lastDot + 1); className = regExp.substring(0, lastDot); } try { Class c = Class.forName(className); for (Method m : c.getDeclaredMethods()) { if (methodName.equals(m.getName())) { return m; } } } catch (Exception e) { //only logging Utils.log("MethodHelper", 3, "Caught exception while searching for methods using regex"); } return null; } protected static boolean isEnabled(Class objectClass, IAnnotationFinder finder) { ITestAnnotation testClassAnnotation = AnnotationHelper.findTest(finder, objectClass); return isEnabled(testClassAnnotation); } protected static boolean isEnabled(Method m, IAnnotationFinder finder) { ITestAnnotation annotation = AnnotationHelper.findTest(finder, m); // If no method annotation, look for one on the class if (null == annotation) { annotation = AnnotationHelper.findTest(finder, m.getDeclaringClass()); } return isEnabled(annotation); } protected static boolean isEnabled(ITestOrConfiguration test) { return null == test || test.getEnabled(); } /** * Extracts the unique list of ITestNGMethods. */ public static List uniqueMethodList(Collection> methods) { Set resultSet = Sets.newHashSet(); for (List l : methods) { resultSet.addAll(l); } return Lists.newArrayList(resultSet); } private static Graph topologicalSort(ITestNGMethod[] methods, List sequentialList, List parallelList) { Graph result = new Graph<>(); if (methods.length == 0) { return result; } // // Create the graph // for (ITestNGMethod m : methods) { result.addNode(m); List predecessors = Lists.newArrayList(); String[] methodsDependedUpon = m.getMethodsDependedUpon(); String[] groupsDependedUpon = m.getGroupsDependedUpon(); if (methodsDependedUpon.length > 0) { ITestNGMethod[] methodsNamed = MethodHelper.findDependedUponMethods(m, methods); for (ITestNGMethod pred : methodsNamed) { predecessors.add(pred); } } if (groupsDependedUpon.length > 0) { for (String group : groupsDependedUpon) { ITestNGMethod[] methodsThatBelongToGroup = MethodGroupsHelper.findMethodsThatBelongToGroup(m, methods, group); for (ITestNGMethod pred : methodsThatBelongToGroup) { predecessors.add(pred); } } } for (ITestNGMethod predecessor : predecessors) { result.addPredecessor(m, predecessor); } } result.topologicalSort(); sequentialList.addAll(result.getStrictlySortedNodes()); parallelList.addAll(result.getIndependentNodes()); return result; } protected static String calculateMethodCanonicalName(ITestNGMethod m) { return calculateMethodCanonicalName(m.getMethod()); } private static String calculateMethodCanonicalName(Method m) { String result = CANONICAL_NAME_CACHE.get(m); if (result != null) { return result; } String packageName = m.getDeclaringClass().getName() + "." + m.getName(); // Try to find the method on this class or parents Class cls = m.getDeclaringClass(); while (cls != Object.class) { try { if (cls.getDeclaredMethod(m.getName(), m.getParameterTypes()) != null) { packageName = cls.getName(); break; } } catch (Exception e) { // ignore } cls = cls.getSuperclass(); } result = packageName + "." + m.getName(); CANONICAL_NAME_CACHE.put(m, result); return result; } private static List sortMethods(boolean forTests, List allMethods, IAnnotationFinder finder) { List sl = Lists.newArrayList(); List pl = Lists.newArrayList(); ITestNGMethod[] allMethodsArray = allMethods.toArray(new ITestNGMethod[allMethods.size()]); // Fix the method inheritance if these are @Configuration methods to make // sure base classes are invoked before child classes if 'before' and the // other way around if they are 'after' if (!forTests && allMethodsArray.length > 0) { ITestNGMethod m = allMethodsArray[0]; boolean before = m.isBeforeClassConfiguration() || m.isBeforeMethodConfiguration() || m.isBeforeSuiteConfiguration() || m.isBeforeTestConfiguration(); MethodInheritance.fixMethodInheritance(allMethodsArray, before); } topologicalSort(allMethodsArray, sl, pl); List result = Lists.newArrayList(); result.addAll(sl); result.addAll(pl); return result; } /** * @return A sorted array containing all the methods 'method' depends on */ public static List getMethodsDependedUpon(ITestNGMethod method, ITestNGMethod[] methods) { Graph g = GRAPH_CACHE.get(methods); if (g == null) { List parallelList = Lists.newArrayList(); List sequentialList = Lists.newArrayList(); g = topologicalSort(methods, sequentialList, parallelList); GRAPH_CACHE.put(methods, g); } List result = g.findPredecessors(method); return result; } protected static Iterator createArrayIterator(final Object[][] objects) { ArrayIterator result = new ArrayIterator(objects); return result; } protected static String calculateMethodCanonicalName(Class methodClass, String methodName) { Set methods = ClassHelper.getAvailableMethods(methodClass); // TESTNG-139 Method result = null; for (Method m : methods) { if (methodName.equals(m.getName())) { result = m; break; } } return result != null ? calculateMethodCanonicalName(result) : null; } protected static long calculateTimeOut(ITestNGMethod tm) { long result = tm.getTimeOut() > 0 ? tm.getTimeOut() : tm.getInvocationTimeOut(); return result; } } /** * Custom iterator class over a 2D array * */ class ArrayIterator implements Iterator { private Object[][] m_objects; private int m_count; public ArrayIterator(Object[][] objects) { m_objects = objects; m_count = 0; } @Override public boolean hasNext() { return m_count < m_objects.length; } @Override public Object[] next() { if (m_count >= m_objects.length) { throw new NoSuchElementException(); } return m_objects[m_count++]; } @Override public void remove() { throw new UnsupportedOperationException("Remove operation is not supported on this iterator"); } } testng-6.9.12/src/main/java/org/testng/internal/InvokeMethodRunnable.java0000644000175000017500000000426112732165123025715 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IHookable; import org.testng.ITestNGMethod; import org.testng.ITestResult; import java.lang.reflect.Method; /** * A Runnable Method invoker. * * @author Cedric Beust */ public class PackageUtils { private static String[] s_testClassPaths; /** The additional class loaders to find classes in. */ private static final List m_classLoaders = new Vector<>(); /** Add a class loader to the searchable loaders. */ public static void addClassLoader(final ClassLoader loader) { m_classLoaders.add(loader); } /** * * @param packageName * @return The list of all the classes inside this package * @throws IOException */ public static String[] findClassesInPackage(String packageName, List included, List excluded) throws IOException { String packageOnly = packageName; boolean recursive = false; if (packageName.endsWith(".*")) { packageOnly = packageName.substring(0, packageName.lastIndexOf(".*")); recursive = true; } List vResult = Lists.newArrayList(); String packageDirName = packageOnly.replace('.', '/') + (packageOnly.length() > 0 ? "/" : ""); Vector dirs = new Vector<>(); // go through additional class loaders Vector allClassLoaders = new Vector<>(); ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null) { allClassLoaders.add(contextClassLoader); } if (m_classLoaders != null) { allClassLoaders.addAll(m_classLoaders); } int count = 0; for (ClassLoader classLoader : allClassLoaders) { ++count; if (null == classLoader) { continue; } Enumeration dirEnumeration = classLoader.getResources(packageDirName); while(dirEnumeration.hasMoreElements()){ URL dir = dirEnumeration.nextElement(); dirs.add(dir); } } Iterator dirIterator = dirs.iterator(); while (dirIterator.hasNext()) { URL url = dirIterator.next(); String protocol = url.getProtocol(); if(!matchTestClasspath(url, packageDirName, recursive)) { continue; } if ("file".equals(protocol)) { findClassesInDirPackage(packageOnly, included, excluded, URLDecoder.decode(url.getFile(), "UTF-8"), recursive, vResult); } else if ("jar".equals(protocol)) { JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile(); Enumeration entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); if (name.charAt(0) == '/') { name = name.substring(1); } if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); if (idx != -1) { packageName = name.substring(0, idx).replace('/', '.'); } if (recursive || packageName.equals(packageOnly)) { //it's not inside a deeper dir Utils.log("PackageUtils", 4, "Package name is " + packageName); if (name.endsWith(".class") && !entry.isDirectory()) { String className = name.substring(packageName.length() + 1, name.length() - 6); Utils.log("PackageUtils", 4, "Found class " + className + ", seeing it if it's included or excluded"); includeOrExcludeClass(packageName, className, included, excluded, vResult); } } } } } else if ("bundleresource".equals(protocol)) { try { Class params[] = {}; // BundleURLConnection URLConnection connection = url.openConnection(); Method thisMethod = url.openConnection().getClass() .getDeclaredMethod("getFileURL", params); Object paramsObj[] = {}; URL fileUrl = (URL) thisMethod.invoke(connection, paramsObj); findClassesInDirPackage(packageOnly, included, excluded, URLDecoder.decode(fileUrl.getFile(), "UTF-8"), recursive, vResult); } catch (Exception ex) { // ignore - probably not an Eclipse OSGi bundle } } } String[] result = vResult.toArray(new String[vResult.size()]); return result; } private static String[] getTestClasspath() { if (null != s_testClassPaths) { return s_testClassPaths; } String testClasspath = System.getProperty(TestNG.TEST_CLASSPATH); if (null == testClasspath) { return null; } String[] classpathFragments= Utils.split(testClasspath, File.pathSeparator); s_testClassPaths= new String[classpathFragments.length]; for(int i= 0; i < classpathFragments.length; i++) { String path= null; if(classpathFragments[i].toLowerCase().endsWith(".jar") || classpathFragments[i].toLowerCase().endsWith(".zip")) { path= classpathFragments[i] + "!/"; } else { if(classpathFragments[i].endsWith(File.separator)) { path= classpathFragments[i]; } else { path= classpathFragments[i] + "/"; } } s_testClassPaths[i]= path.replace('\\', '/'); } return s_testClassPaths; } private static boolean matchTestClasspath(URL url, String lastFragment, boolean recursive) { String[] classpathFragments= getTestClasspath(); if(null == classpathFragments) { return true; } String fileName= null; try { fileName= URLDecoder.decode(url.getFile(), "UTF-8"); } catch(UnsupportedEncodingException ueex) { // ignore. should never happen } for(String classpathFrag: classpathFragments) { String path= classpathFrag + lastFragment; int idx= fileName.indexOf(path); if((idx == -1) || (idx > 0 && fileName.charAt(idx-1) != '/')) { continue; } if(fileName.endsWith(classpathFrag + lastFragment) || (recursive && fileName.charAt(idx + path.length()) == '/')) { return true; } } return false; } private static void findClassesInDirPackage(String packageName, List included, List excluded, String packagePath, final boolean recursive, List classes) { File dir = new File(packagePath); if (!dir.exists() || !dir.isDirectory()) { return; } File[] dirfiles = dir.listFiles(new FileFilter() { @Override public boolean accept(File file) { return (recursive && file.isDirectory()) || (file.getName().endsWith(".class")) || (file.getName().endsWith(".groovy")); } }); Utils.log("PackageUtils", 4, "Looking for test classes in the directory: " + dir); for (File file : dirfiles) { if (file.isDirectory()) { findClassesInDirPackage(makeFullClassName(packageName, file.getName()), included, excluded, file.getAbsolutePath(), recursive, classes); } else { String className = file.getName().substring(0, file.getName().lastIndexOf(".")); Utils.log("PackageUtils", 4, "Found class " + className + ", seeing it if it's included or excluded"); includeOrExcludeClass(packageName, className, included, excluded, classes); } } } private static String makeFullClassName(String pkg, String cls) { return pkg.length() > 0 ? pkg + "." + cls : cls; } private static void includeOrExcludeClass(String packageName, String className, List included, List excluded, List classes) { if (isIncluded(packageName, included, excluded)) { Utils.log("PackageUtils", 4, "... Including class " + className); classes.add(makeFullClassName(packageName, className)); } else { Utils.log("PackageUtils", 4, "... Excluding class " + className); } } /** * @return true if name should be included. */ private static boolean isIncluded(String name, List included, List excluded) { boolean result = false; // // If no includes nor excludes were specified, return true. // if (included.size() == 0 && excluded.size() == 0) { result = true; } else { boolean isIncluded = PackageUtils.find(name, included); boolean isExcluded = PackageUtils.find(name, excluded); if (isIncluded && !isExcluded) { result = true; } else if (isExcluded) { result = false; } else { result = included.size() == 0; } } return result; } private static boolean find(String name, List list) { for (String regexpStr : list) { if (Pattern.matches(regexpStr, name)) { return true; } } return false; } } testng-6.9.12/src/main/java/org/testng/internal/IResultListener.java0000755000175000017500000000053412732165123024731 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IConfigurationListener; import org.testng.ITestListener; /** * A convenient interface to use when implementing listeners. * @author Alexandru Popescu */ public interface IResultListener extends ITestListener, IConfigurationListener { } testng-6.9.12/src/main/java/org/testng/internal/ClassHelper.java0000644000175000017500000005045612732165123024046 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import org.testng.IClass; import org.testng.IMethodSelector; import org.testng.IObjectFactory; import org.testng.IObjectFactory2; import org.testng.ITestObjectFactory; import org.testng.TestNGException; import org.testng.TestRunner; import org.testng.annotations.IAnnotation; import org.testng.annotations.IFactoryAnnotation; import org.testng.annotations.IParametersAnnotation; import org.testng.collections.Sets; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.junit.IJUnitTestRunner; import org.testng.xml.XmlTest; /** * Utility class for different class manipulations. */ public final class ClassHelper { private static final String JUNIT_TESTRUNNER= "org.testng.junit.JUnitTestRunner"; private static final String JUNIT_4_TESTRUNNER = "org.testng.junit.JUnit4TestRunner"; /** The additional class loaders to find classes in. */ private static final List m_classLoaders = new Vector<>(); /** Add a class loader to the searchable loaders. */ public static void addClassLoader(final ClassLoader loader) { m_classLoaders.add(loader); } /** Hide constructor. */ private ClassHelper() { // Hide Constructor } public static T newInstance(Class clazz) { try { T instance = clazz.newInstance(); return instance; } catch(IllegalAccessException iae) { throw new TestNGException("Class " + clazz.getName() + " does not have a no-args constructor", iae); } catch(InstantiationException ie) { throw new TestNGException("Cannot instantiate class " + clazz.getName(), ie); } catch(ExceptionInInitializerError eiierr) { throw new TestNGException("An exception occurred in static initialization of class " + clazz.getName(), eiierr); } catch(SecurityException se) { throw new TestNGException(se); } } public static T newInstance(Constructor constructor, Object... parameters) { try { return constructor.newInstance(parameters); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new TestNGException("Cannot instantiate class " + constructor.getDeclaringClass().getName(), e); } } /** * Tries to load the specified class using the context ClassLoader or if none, * than from the default ClassLoader. This method differs from the standard * class loading methods in that it does not throw an exception if the class * is not found but returns null instead. * * @param className the class name to be loaded. * * @return the class or null if the class is not found. */ public static Class forName(final String className) { Vector allClassLoaders = new Vector<>(); ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); if (contextClassLoader != null) { allClassLoaders.add(contextClassLoader); } if (m_classLoaders != null) { allClassLoaders.addAll(m_classLoaders); } for (ClassLoader classLoader : allClassLoaders) { if (null == classLoader) { continue; } try { return classLoader.loadClass(className); } catch(ClassNotFoundException ex) { // With additional class loaders, it is legitimate to ignore ClassNotFoundException if (null == m_classLoaders || m_classLoaders.size() == 0) { logClassNotFoundError(className, ex); } } } try { return Class.forName(className); } catch(ClassNotFoundException cnfe) { logClassNotFoundError(className, cnfe); return null; } } private static void logClassNotFoundError(String className, Exception ex) { Utils.log("ClassHelper", 2, "Could not instantiate " + className + " : Class doesn't exist (" + ex.getMessage() + ")"); } /** * For the given class, returns the method annotated with @Factory or null * if none is found. This method does not search up the superclass hierarchy. * If more than one method is @Factory annotated, a TestNGException is thrown. * @param cls The class to search for the @Factory annotation. * @param finder The finder (JDK 1.4 or JDK 5.0+) use to search for the annotation. * * @return the @Factory method or null */ public static ConstructorOrMethod findDeclaredFactoryMethod(Class cls, IAnnotationFinder finder) { ConstructorOrMethod result = null; for (Method method : getAvailableMethods(cls)) { IFactoryAnnotation f = finder.findAnnotation(method, IFactoryAnnotation.class); if (null != f) { result = new ConstructorOrMethod(method); result.setEnabled(f.getEnabled()); break; } } if (result == null) { for (Constructor constructor : cls.getDeclaredConstructors()) { IAnnotation f = finder.findAnnotation(constructor, IFactoryAnnotation.class); if (f != null) { result = new ConstructorOrMethod(constructor); } } } // If we didn't find anything, look for nested classes // if (null == result) { // Class[] subClasses = cls.getClasses(); // for (Class subClass : subClasses) { // result = findFactoryMethod(subClass, finder); // if (null != result) { // break; // } // } // } return result; } /** * Extract all callable methods of a class and all its super (keeping in mind * the Java access rules). */ public static Set getAvailableMethods(Class clazz) { Set methods = Sets.newHashSet(); methods.addAll(Arrays.asList(clazz.getDeclaredMethods())); Class parent = clazz.getSuperclass(); while (null != parent) { methods.addAll(extractMethods(clazz, parent, methods)); parent = parent.getSuperclass(); } return methods; } public static IJUnitTestRunner createTestRunner(TestRunner runner) { try { //try to get runner for JUnit 4 first Class.forName("org.junit.Test"); IJUnitTestRunner tr = (IJUnitTestRunner) ClassHelper.forName(JUNIT_4_TESTRUNNER).newInstance(); tr.setTestResultNotifier(runner); return tr; } catch (Throwable t) { Utils.log("ClassHelper", 2, "JUnit 4 was not found on the classpath"); try { //fallback to JUnit 3 Class.forName("junit.framework.Test"); IJUnitTestRunner tr = (IJUnitTestRunner) ClassHelper.forName(JUNIT_TESTRUNNER).newInstance(); tr.setTestResultNotifier(runner); return tr; } catch (Exception ex) { Utils.log("ClassHelper", 2, "JUnit 3 was not found on the classpath"); //there's no JUnit on the classpath throw new TestNGException("Cannot create JUnit runner", ex); } } } private static Set extractMethods(Class childClass, Class clazz, Set collected) { Set methods = Sets.newHashSet(); Method[] declaredMethods = clazz.getDeclaredMethods(); Package childPackage = childClass.getPackage(); Package classPackage = clazz.getPackage(); boolean isSamePackage = false; if ((null == childPackage) && (null == classPackage)) { isSamePackage = true; } if ((null != childPackage) && (null != classPackage)) { isSamePackage = childPackage.getName().equals(classPackage.getName()); } for (Method method : declaredMethods) { int methodModifiers = method.getModifiers(); if ((Modifier.isPublic(methodModifiers) || Modifier.isProtected(methodModifiers)) || (isSamePackage && !Modifier.isPrivate(methodModifiers))) { if (!isOverridden(method, collected) && !Modifier.isAbstract(methodModifiers)) { methods.add(method); } } } return methods; } private static boolean isOverridden(Method method, Set collectedMethods) { Class methodClass = method.getDeclaringClass(); Class[] methodParams = method.getParameterTypes(); for (Method m: collectedMethods) { Class[] paramTypes = m.getParameterTypes(); if (method.getName().equals(m.getName()) && methodClass.isAssignableFrom(m.getDeclaringClass()) && methodParams.length == paramTypes.length) { boolean sameParameters = true; for (int i= 0; i < methodParams.length; i++) { if (!methodParams[i].equals(paramTypes[i])) { sameParameters = false; break; } } if (sameParameters) { return true; } } } return false; } public static IMethodSelector createSelector(org.testng.xml.XmlMethodSelector selector) { try { Class cls = Class.forName(selector.getClassName()); return (IMethodSelector) cls.newInstance(); } catch(Exception ex) { throw new TestNGException("Couldn't find method selector : " + selector.getClassName(), ex); } } /** * Create an instance for the given class. */ public static Object createInstance(Class declaringClass, Map classes, XmlTest xmlTest, IAnnotationFinder finder, ITestObjectFactory objectFactory) { if (objectFactory instanceof IObjectFactory) { return createInstance1(declaringClass, classes, xmlTest, finder, (IObjectFactory) objectFactory); } else if (objectFactory instanceof IObjectFactory2) { return createInstance2(declaringClass, (IObjectFactory2) objectFactory); } else { throw new AssertionError("Unknown object factory type:" + objectFactory); } } private static Object createInstance2(Class declaringClass, IObjectFactory2 objectFactory) { return objectFactory.newInstance(declaringClass); } public static Object createInstance1(Class declaringClass, Map classes, XmlTest xmlTest, IAnnotationFinder finder, IObjectFactory objectFactory) { Object result = null; try { // // Any annotated constructor? // Constructor constructor = findAnnotatedConstructor(finder, declaringClass); if (null != constructor) { IParametersAnnotation annotation = finder.findAnnotation(constructor, IParametersAnnotation.class); String[] parameterNames = annotation.getValue(); Object[] parameters = Parameters.createInstantiationParameters(constructor, "@Parameters", finder, parameterNames, xmlTest.getAllParameters(), xmlTest.getSuite()); result = objectFactory.newInstance(constructor, parameters); } // // No, just try to instantiate the parameterless constructor (or the one // with a String) // else { // If this class is a (non-static) nested class, the constructor contains a hidden // parameter of the type of the enclosing class Class[] parameterTypes = new Class[0]; Object[] parameters = new Object[0]; Class ec = getEnclosingClass(declaringClass); boolean isStatic = 0 != (declaringClass.getModifiers() & Modifier.STATIC); // Only add the extra parameter if the nested class is not static if ((null != ec) && !isStatic) { parameterTypes = new Class[] { ec }; // Create an instance of the enclosing class so we can instantiate // the nested class (actually, we reuse the existing instance). IClass enclosingIClass = classes.get(ec); Object[] enclosingInstances; if (null != enclosingIClass) { enclosingInstances = enclosingIClass.getInstances(false); if ((null == enclosingInstances) || (enclosingInstances.length == 0)) { Object o = objectFactory.newInstance(ec.getConstructor(parameterTypes)); enclosingIClass.addInstance(o); enclosingInstances = new Object[] { o }; } } else { enclosingInstances = new Object[] { ec.newInstance() }; } Object enclosingClassInstance = enclosingInstances[0]; // Utils.createInstance(ec, classes, xmlTest, finder); parameters = new Object[] { enclosingClassInstance }; } // isStatic Constructor ct; try { ct = declaringClass.getDeclaredConstructor(parameterTypes); } catch (NoSuchMethodException ex) { ct = declaringClass.getDeclaredConstructor(String.class); parameters = new Object[] { "Default test name" }; // If ct == null here, we'll pass a null // constructor to the factory and hope it can deal with it } result = objectFactory.newInstance(ct, parameters); } } catch (TestNGException ex) { throw ex; // throw new TestNGException("Couldn't instantiate class:" + declaringClass); } catch (NoSuchMethodException ex) { } catch (Throwable cause) { // Something else went wrong when running the constructor throw new TestNGException("An error occurred while instantiating class " + declaringClass.getName() + ": " + cause.getMessage(), cause); } if (result == null) { if (! Modifier.isPublic(declaringClass.getModifiers())) { //result should not be null throw new TestNGException("An error occurred while instantiating class " + declaringClass.getName() + ". Check to make sure it can be accessed/instantiated."); // } else { // Utils.log(ClassHelper.class.getName(), 2, "Couldn't instantiate class " + declaringClass); } } return result; } /** * Class.getEnclosingClass() only exists on JDK5, so reimplementing it * here. */ private static Class getEnclosingClass(Class declaringClass) { Class result = null; String className = declaringClass.getName(); int index = className.indexOf("$"); if (index != -1) { String ecn = className.substring(0, index); try { result = Class.forName(ecn); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return result; } /** * Find the best constructor given the parameters found on the annotation */ private static Constructor findAnnotatedConstructor(IAnnotationFinder finder, Class declaringClass) { Constructor[] constructors = declaringClass.getDeclaredConstructors(); for (Constructor result : constructors) { IParametersAnnotation annotation = finder.findAnnotation(result, IParametersAnnotation.class); if (null != annotation) { String[] parameters = annotation.getValue(); Class[] parameterTypes = result.getParameterTypes(); if (parameters.length != parameterTypes.length) { throw new TestNGException("Parameter count mismatch: " + result + "\naccepts " + parameterTypes.length + " parameters but the @Test annotation declares " + parameters.length); } else { return result; } } } return null; } public static T tryOtherConstructor(Class declaringClass) { T result; try { // Special case for inner classes if (declaringClass.getModifiers() == 0) { return null; } Constructor ctor = declaringClass.getConstructor(String.class); result = ctor.newInstance("Default test name"); } catch (Exception e) { String message = e.getMessage(); if ((message == null) && (e.getCause() != null)) { message = e.getCause().getMessage(); } String error = "Could not create an instance of class " + declaringClass + ((message != null) ? (": " + message) : "") + ".\nPlease make sure it has a constructor that accepts either a String or no parameter."; throw new TestNGException(error); } return result; } /** * When given a file name to form a class name, the file name is parsed and divided * into segments. For example, "c:/java/classes/com/foo/A.class" would be divided * into 6 segments {"C:" "java", "classes", "com", "foo", "A"}. The first segment * actually making up the class name is [3]. This value is saved in m_lastGoodRootIndex * so that when we parse the next file name, we will try 3 right away. If 3 fails we * will take the long approach. This is just a optimization cache value. */ private static int m_lastGoodRootIndex = -1; /** * Returns the Class object corresponding to the given name. The name may be * of the following form: *
    *
  • A class name: "org.testng.TestNG"
  • *
  • A class file name: "/testng/src/org/testng/TestNG.class"
  • *
  • A class source name: "d:\testng\src\org\testng\TestNG.java"
  • *
* * @param file * the class name. * @return the class corresponding to the name specified. */ public static Class fileToClass(String file) { Class result = null; if(!file.endsWith(".class") && !file.endsWith(".java")) { // Doesn't end in .java or .class, assume it's a class name if (file.startsWith("class ")) { file = file.substring("class ".length()); } result = ClassHelper.forName(file); if (null == result) { throw new TestNGException("Cannot load class from file: " + file); } return result; } int classIndex = file.lastIndexOf(".class"); if (-1 == classIndex) { classIndex = file.lastIndexOf(".java"); // // if(-1 == classIndex) { // result = ClassHelper.forName(file); // // if (null == result) { // throw new TestNGException("Cannot load class from file: " + file); // } // // return result; // } // } // Transforms the file name into a class name. // Remove the ".class" or ".java" extension. String shortFileName = file.substring(0, classIndex); // Split file name into segments. For example "c:/java/classes/com/foo/A" // becomes {"c:", "java", "classes", "com", "foo", "A"} String[] segments = shortFileName.split("[/\\\\]", -1); // // Check if the last good root index works for this one. For example, if the previous // name was "c:/java/classes/com/foo/A.class" then m_lastGoodRootIndex is 3 and we // try to make a class name ignoring the first m_lastGoodRootIndex segments (3). This // will succeed rapidly if the path is the same as the one from the previous name. // if (-1 != m_lastGoodRootIndex) { StringBuilder className = new StringBuilder(segments[m_lastGoodRootIndex]); for (int i = m_lastGoodRootIndex + 1; i < segments.length; i++) { className.append(".").append(segments[i]); } result = ClassHelper.forName(className.toString()); if (null != result) { return result; } } // // We haven't found a good root yet, start by resolving the class from the end segment // and work our way up. For example, if we start with "c:/java/classes/com/foo/A" // we'll start by resolving "A", then "foo.A", then "com.foo.A" until something // resolves. When it does, we remember the path we are at as "lastGoodRoodIndex". // // TODO CQ use a StringBuffer here String className = null; for (int i = segments.length - 1; i >= 0; i--) { if (null == className) { className = segments[i]; } else { className = segments[i] + "." + className; } result = ClassHelper.forName(className); if (null != result) { m_lastGoodRootIndex = i; break; } } if (null == result) { throw new TestNGException("Cannot load class from file: " + file); } return result; } } testng-6.9.12/src/main/java/org/testng/internal/PropertyUtils.java0000755000175000017500000000601712732165123024503 0ustar eugeneeugenepackage org.testng.internal; import org.testng.log4testng.Logger; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * Utility class for setting JavaBeans-style properties on instances. * * @author Cosmin Marginean, Apr 12, 2007 */ public class PropertyUtils { private static final Logger LOGGER = Logger.getLogger(PropertyUtils.class); public static void setProperty(Object instance, String name, String value) { if (instance == null) { LOGGER.warn("Cannot set property " + name + " with value " + value + ". The target instance is null"); return; } Class propClass = getPropertyType(instance.getClass(), name); if (propClass == null) { LOGGER.warn("Cannot set property " + name + " with value " + value + ". Property class could not be found"); return; } Object realValue = Parameters.convertType(propClass, value, name); //TODO: Here the property desc is serched again setPropertyRealValue(instance, name, realValue); } public static Class getPropertyType(Class instanceClass, String propertyName) { if (instanceClass == null) { LOGGER.warn("Cannot retrieve property class for " + propertyName + ". Target instance class is null"); } PropertyDescriptor propDesc = getPropertyDescriptor(instanceClass, propertyName); return propDesc.getPropertyType(); } private static PropertyDescriptor getPropertyDescriptor(Class targetClass, String propertyName) { PropertyDescriptor result = null; if (targetClass == null) { LOGGER.warn("Cannot retrieve property " + propertyName + ". Class is null"); } else { try { BeanInfo beanInfo = Introspector.getBeanInfo(targetClass); PropertyDescriptor[] propDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propDesc : propDescriptors) { if (propDesc.getName().equals(propertyName)) { result = propDesc; break; } } } catch (IntrospectionException ie) { LOGGER.warn("Cannot retrieve property " + propertyName + ". Cause is: " + ie); } } return result; } public static void setPropertyRealValue(Object instance, String name, Object value) { if (instance == null) { LOGGER.warn("Cannot set property " + name + " with value " + value + ". Targe instance is null"); return; } PropertyDescriptor propDesc = getPropertyDescriptor(instance.getClass(), name); if (propDesc == null) { LOGGER.warn("Cannot set property " + name + " with value " + value + ". Property does not exist"); return; } Method method = propDesc.getWriteMethod(); try { method.invoke(instance, new Object[]{value}); } catch (IllegalAccessException | InvocationTargetException iae) { LOGGER.warn("Cannot set property " + name + " with value " + value + ". Cause " + iae); } } } testng-6.9.12/src/main/java/org/testng/internal/RegexpExpectedExceptionsHolder.java0000755000175000017500000000371312732165123027752 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IExpectedExceptionsHolder; import org.testng.ITestNGMethod; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.internal.annotations.IAnnotationFinder; import java.util.regex.Pattern; /** * A class that contains the expected exceptions and the message regular expression. * @author cbeust */ public class RegexpExpectedExceptionsHolder implements IExpectedExceptionsHolder { public static final String DEFAULT_REGEXP = ".*"; private final IAnnotationFinder finder; private final ITestNGMethod method; public RegexpExpectedExceptionsHolder(IAnnotationFinder finder, ITestNGMethod method) { this.finder = finder; this.method = method; } /** * message / regEx .* other * null true false * non-null true match */ @Override public boolean isThrowableMatching(Throwable ite) { String messageRegExp = getRegExp(); if (DEFAULT_REGEXP.equals(messageRegExp)) { return true; } final String message = ite.getMessage(); return message != null && Pattern.compile(messageRegExp, Pattern.DOTALL).matcher(message).matches(); } public String getWrongExceptionMessage(Throwable ite) { return "The exception was thrown with the wrong message:" + " expected \"" + getRegExp() + "\"" + " but got \"" + ite.getMessage() + "\""; } private String getRegExp() { IExpectedExceptionsAnnotation expectedExceptions = finder.findAnnotation(method, IExpectedExceptionsAnnotation.class); if (expectedExceptions != null) { // Old syntax => default value return DEFAULT_REGEXP; } // New syntax ITestAnnotation testAnnotation = finder.findAnnotation(method, ITestAnnotation.class); if (testAnnotation != null) { return testAnnotation.getExpectedExceptionsMessageRegExp(); } return DEFAULT_REGEXP; } } testng-6.9.12/src/main/java/org/testng/internal/IResultListener2.java0000644000175000017500000000024212732165123025004 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IConfigurationListener2; public interface IResultListener2 extends IResultListener, IConfigurationListener2 { } testng-6.9.12/src/main/java/org/testng/internal/ObjectFactoryImpl.java0000755000175000017500000000242412732165123025214 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IObjectFactory; import org.testng.TestNGException; import java.lang.reflect.Constructor; /** * Default factory for test creation. * Note that if no constructor is found matching the specified parameters, * this factory will try to invoke a constructor that takes in a string object * * @author Hani Suleiman * Date: Mar 6, 2007 * Time: 12:00:27 PM * @since 5.6 */ public class ObjectFactoryImpl implements IObjectFactory { /** * */ private static final long serialVersionUID = -4547389328475540017L; @Override public Object newInstance(Constructor constructor, Object... params) { try { constructor.setAccessible(true); return constructor.newInstance(params); } catch (IllegalAccessException ex) { return ClassHelper.tryOtherConstructor(constructor.getDeclaringClass()); } catch (InstantiationException ex) { return ClassHelper.tryOtherConstructor(constructor.getDeclaringClass()); } catch(Exception ex) { throw new TestNGException("Cannot instantiate class " + (constructor != null ? constructor.getDeclaringClass().getName() : ": couldn't find a suitable constructor"), ex); } } } testng-6.9.12/src/main/java/org/testng/internal/thread/0000755000175000017500000000000012732165123022233 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/thread/ThreadTimeoutException.java0000755000175000017500000000102212732165123027531 0ustar eugeneeugenepackage org.testng.internal.thread; /** * Exception used to signal a thread timeout. * * @author Alexandru Popescu */ public class ThreadTimeoutException extends Exception { static final long serialVersionUID = 7009400729783393548L; public ThreadTimeoutException(String msg) { super(msg); } public ThreadTimeoutException(Throwable cause) { super(cause); } public ThreadTimeoutException(String msg, Throwable cause) { super(msg, cause); } }testng-6.9.12/src/main/java/org/testng/internal/thread/IFutureResult.java0000755000175000017500000000041212732165123025660 0ustar eugeneeugenepackage org.testng.internal.thread; /** * Reduced interface to mimic Future. * * @author Alexandru Popescu */ public interface IFutureResult { Object get() throws InterruptedException, ThreadExecutionException; } testng-6.9.12/src/main/java/org/testng/internal/thread/graph/0000755000175000017500000000000012732165123023334 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/thread/graph/IThreadWorkerFactory.java0000644000175000017500000000105312732165123030240 0ustar eugeneeugenepackage org.testng.internal.thread.graph; import java.util.List; import java.util.Set; /** * A factory that creates workers used by {@code GraphThreadPoolExecutor} * @author nullin * * @param */ public interface IThreadWorkerFactory { /** * Creates {@code IWorker} for specified set of tasks. It is not necessary that * number of workers returned be same as number of tasks entered. * * @param freeNodes tasks that need to be executed * @return list of workers */ List> createWorkers(List freeNodes); } testng-6.9.12/src/main/java/org/testng/internal/thread/graph/IWorker.java0000644000175000017500000000102612732165123025560 0ustar eugeneeugenepackage org.testng.internal.thread.graph; import java.util.List; /** * A runnable object that is used by {@code GraphThreadPoolExecutor} to execute * tasks */ public interface IWorker extends Runnable, Comparable> { /** * @return list of tasks this worker is working on. */ List getTasks(); /** * @return the maximum time allowed for the worker to complete the task. */ long getTimeOut(); /** * @return the priority of this task. */ int getPriority(); } testng-6.9.12/src/main/java/org/testng/internal/thread/graph/SuiteWorkerFactory.java0000644000175000017500000000233012732165123030010 0ustar eugeneeugenepackage org.testng.internal.thread.graph; import org.testng.ISuite; import org.testng.SuiteRunnerWorker; import org.testng.collections.Lists; import org.testng.internal.SuiteRunnerMap; import java.util.List; /** * An {@code IThreadWorkerFactory} for {@code SuiteRunner}s * * @author nullin * */ public class SuiteWorkerFactory implements IThreadWorkerFactory { private Integer m_verbose; private String m_defaultSuiteName; private SuiteRunnerMap m_suiteRunnerMap; public SuiteWorkerFactory(SuiteRunnerMap suiteRunnerMap, Integer verbose, String defaultSuiteName) { m_suiteRunnerMap = suiteRunnerMap; m_verbose = verbose; m_defaultSuiteName = defaultSuiteName; } /** * For each suite, creates a {@code SuiteRunnerWorker} * @param suites set of suite runners * @return list of suite runner workers */ @Override public List> createWorkers(List suites) { List> suiteWorkers = Lists.newArrayList(); for (ISuite suiteRunner : suites) { SuiteRunnerWorker worker = new SuiteRunnerWorker(suiteRunner, m_suiteRunnerMap, m_verbose, m_defaultSuiteName); suiteWorkers.add(worker); } return suiteWorkers; } } testng-6.9.12/src/main/java/org/testng/internal/thread/graph/GraphThreadPoolExecutor.java0000644000175000017500000001121212732165123030736 0ustar eugeneeugenepackage org.testng.internal.thread.graph; import org.testng.TestNGException; import org.testng.collections.Lists; import org.testng.internal.DynamicGraph; import org.testng.internal.DynamicGraph.Status; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * An Executor that launches tasks per batches. It takes a {@code DynamicGraph} * of tasks to be run and a {@code IThreadWorkerFactory} to initialize/create * {@code Runnable} wrappers around those tasks */ public class GraphThreadPoolExecutor extends ThreadPoolExecutor { private static final boolean DEBUG = false; /** Set to true if you want to generate GraphViz graphs */ private static final boolean DOT_FILES = false; private DynamicGraph m_graph; private List m_activeRunnables = Lists.newArrayList(); private IThreadWorkerFactory m_factory; private List m_dotFiles = Lists.newArrayList(); private int m_threadCount; public GraphThreadPoolExecutor(DynamicGraph graph, IThreadWorkerFactory factory, int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue /* , new TestNGThreadPoolFactory() */); ppp("Initializing executor with " + corePoolSize + " threads and following graph " + graph); m_threadCount = maximumPoolSize; m_graph = graph; m_factory = factory; if (m_graph.getFreeNodes().isEmpty()) { throw new TestNGException("The graph of methods contains a cycle:" + graph.getEdges()); } } public void run() { synchronized(m_graph) { if (DOT_FILES) { m_dotFiles.add(m_graph.toDot()); } List freeNodes = m_graph.getFreeNodes(); runNodes(freeNodes); } } /** * Create one worker per node and execute them. */ private void runNodes(List freeNodes) { List> runnables = m_factory.createWorkers(freeNodes); for (IWorker r : runnables) { m_activeRunnables.add(r); ppp("Added to active runnable"); setStatus(r, Status.RUNNING); ppp("Executing: " + r); try { execute(r); // if (m_threadCount > 1) execute(r); // else r.run(); } catch(Exception ex) { ex.printStackTrace(); } } } private void setStatus(IWorker worker, Status status) { ppp("Set status:" + worker + " status:" + status); if (status == Status.FINISHED) { m_activeRunnables.remove(worker); } synchronized(m_graph) { for (T m : worker.getTasks()) { m_graph.setStatus(m, status); } } } @Override public void afterExecute(Runnable r, Throwable t) { ppp("Finished runnable:" + r); setStatus((IWorker) r, Status.FINISHED); synchronized(m_graph) { ppp("Node count:" + m_graph.getNodeCount() + " and " + m_graph.getNodeCountWithStatus(Status.FINISHED) + " finished"); if (m_graph.getNodeCount() == m_graph.getNodeCountWithStatus(Status.FINISHED)) { ppp("Shutting down executor " + this); if (DOT_FILES) { generateFiles(m_dotFiles); } shutdown(); } else { if (DOT_FILES) { m_dotFiles.add(m_graph.toDot()); } List freeNodes = m_graph.getFreeNodes(); runNodes(freeNodes); } } // if (m_activeRunnables.isEmpty() && m_index < m_runnables.getSize()) { // runNodes(m_index++); // } } private void generateFiles(List files) { try { File dir = File.createTempFile("TestNG-", ""); dir.delete(); dir.mkdir(); for (int i = 0; i < files.size(); i++) { File f = new File(dir, "" + (i < 10 ? "0" : "") + i + ".dot"); BufferedWriter bw = new BufferedWriter(new FileWriter(f)); bw.append(files.get(i)); bw.close(); } if (DOT_FILES) { System.out.println("Created graph files in " + dir); } } catch(IOException ex) { ex.printStackTrace(); } } private void ppp(String string) { if (DEBUG) { System.out.println("============ [GraphThreadPoolExecutor] " + Thread.currentThread().getId() + " " + string); } } } class TestNGThreadPoolFactory implements ThreadFactory { private int m_count = 0; @Override public Thread newThread(Runnable r) { Thread result = new Thread(r); result.setName("TestNG-" + m_count++); return result; } } testng-6.9.12/src/main/java/org/testng/internal/thread/FutureResultAdapter.java0000755000175000017500000000131212732165123027050 0ustar eugeneeugenepackage org.testng.internal.thread; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; /** * A very reduced interface of Future. * * @author the_mindstorm */ public class ThreadExecutionException extends Exception { static final long serialVersionUID = -7766644143333236263L; public ThreadExecutionException(Throwable t) { super(t); } }testng-6.9.12/src/main/java/org/testng/internal/thread/IExecutor.java0000755000175000017500000000060012732165123025004 0ustar eugeneeugenepackage org.testng.internal.thread; /** * Reduced interface to mimic an ExecutorService. * * @author Alexandru Popescu */ public interface IExecutor { IFutureResult submitRunnable(Runnable runnable); void shutdown(); boolean awaitTermination(long timeout); void stopNow(); StackTraceElement[][] getStackTraces(); } testng-6.9.12/src/main/java/org/testng/internal/thread/IThreadFactory.java0000755000175000017500000000053312732165123025752 0ustar eugeneeugenepackage org.testng.internal.thread; import java.util.List; /** * Reduced interface to mimic ThreadFactory. * * @author Alexandru Popescu * @version $Revision$ */ public interface IThreadFactory { Thread newThread(Runnable run); Object getThreadFactory(); List getThreads(); } testng-6.9.12/src/main/java/org/testng/internal/thread/ExecutorAdapter.java0000755000175000017500000000342312732165123026202 0ustar eugeneeugenepackage org.testng.internal.thread; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * An implementation for IExecutor based on ThreadPoolExecutor * * @author threads = m_threadFactory.getThreads(); int threadCount = threads.size(); StackTraceElement[][] result = new StackTraceElement[threadCount][]; for (int i = 0; i < result.length; i++) { result[i] = threads.get(i).getStackTrace(); } return result; } }testng-6.9.12/src/main/java/org/testng/internal/thread/TestNGThread.java0000755000175000017500000000064012732165123025375 0ustar eugeneeugenepackage org.testng.internal.thread; /** * Custom named thread. * * @author Alexandru Popescu */ public class TestNGThread extends Thread { public TestNGThread(String methodName) { super("TestNGInvoker-" + methodName + "()"); } public TestNGThread(Runnable target, String methodName) { super(target, "TestNGInvoker-" + methodName + "()"); } }testng-6.9.12/src/main/java/org/testng/internal/thread/ThreadUtil.java0000644000175000017500000001015112732165123025141 0ustar eugeneeugenepackage org.testng.internal.thread; import org.testng.collections.Lists; import org.testng.internal.Utils; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * A helper class to interface TestNG concurrency usage. * * @author tasks. The startup is synchronized so this method * emulates a load test. * @param tasks the list of tasks to be run * @param threadPoolSize the size of the parallel threads to be used to execute the tasks * @param timeout a maximum timeout to wait for tasks finalization * @param triggerAtOnce true if the parallel execution of tasks should be trigger at once */ public static final void execute(List tasks, int threadPoolSize, long timeout, boolean triggerAtOnce) { final CountDownLatch startGate= new CountDownLatch(1); final CountDownLatch endGate= new CountDownLatch(tasks.size()); Utils.log("ThreadUtil", 2, "Starting executor timeOut:" + timeout + "ms" + " workers:" + tasks.size() + " threadPoolSize:" + threadPoolSize); ExecutorService pooledExecutor = // Executors.newFixedThreadPool(threadPoolSize); new ThreadPoolExecutor(threadPoolSize, threadPoolSize, timeout, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread result = new Thread(r); result.setName(THREAD_NAME); return result; } }); List> callables = Lists.newArrayList(); for (final Runnable task : tasks) { callables.add(new Callable() { @Override public Object call() throws Exception { task.run(); return null; } }); } try { if (timeout != 0) { pooledExecutor.invokeAll(callables, timeout, TimeUnit.MILLISECONDS); } else { pooledExecutor.invokeAll(callables); } } catch (InterruptedException handled) { handled.printStackTrace(); Thread.currentThread().interrupt(); } finally { pooledExecutor.shutdown(); } } /** * Returns a readable name of the current executing thread. */ public static final String currentThreadInfo() { Thread thread= Thread.currentThread(); return String.valueOf(thread.getName() + "@" + thread.hashCode()); } public static final IExecutor createExecutor(int threadCount, String threadFactoryName) { return new ExecutorAdapter(threadCount, createFactory(threadFactoryName)); } private static final IThreadFactory createFactory(String name) { return new ThreadFactoryImpl(name); } private static void log(int level, String msg) { Utils.log("ThreadUtil:" + ThreadUtil.currentThreadInfo(), level, msg); } public static class ThreadFactoryImpl implements IThreadFactory, ThreadFactory { private String m_methodName; private List m_threads = Lists.newArrayList(); public ThreadFactoryImpl(String name) { m_methodName= name; } @Override public Thread newThread(Runnable run) { Thread result = new TestNGThread(run, m_methodName); m_threads.add(result); return result; } @Override public Object getThreadFactory() { return this; } @Override public List getThreads() { return m_threads; } } } testng-6.9.12/src/main/java/org/testng/internal/FactoryMethod.java0000644000175000017500000000753612732165123024412 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.List; import java.util.Map; import org.testng.IInstanceInfo; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.TestNGException; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlTest; /** * This class represents a method annotated with @Factory * * @author Cedric Beust */ public class FactoryMethod extends BaseTestMethod { /** * */ private static final long serialVersionUID = -7329918821346197099L; private Object m_instance = null; private XmlTest m_xmlTest = null; private ITestContext m_testContext = null; public FactoryMethod(ConstructorOrMethod com, Object instance, XmlTest xmlTest, IAnnotationFinder annotationFinder, ITestContext testContext) { super(com.getName(), com, annotationFinder, instance); Utils.checkInstanceOrStatic(instance, com.getMethod()); Utils.checkReturnType(com.getMethod(), Object[].class, IInstanceInfo[].class); Class declaringClass = com.getDeclaringClass(); if (instance != null && ! declaringClass.isAssignableFrom(instance.getClass())) { throw new TestNGException("Mismatch between instance/method classes:" + instance.getClass() + " " + declaringClass); } if (instance == null && com.getMethod() != null && !Modifier.isStatic(com.getMethod().getModifiers())) { throw new TestNGException("An inner factory method MUST be static. But '" + com.getMethod().getName() + "' from '" + declaringClass.getName() + "' is not."); } if (com.getMethod() != null && !Modifier.isPublic(com.getMethod().getModifiers())) { try { com.getMethod().setAccessible(true); } catch (SecurityException e) { throw new TestNGException(e); } } m_instance = instance; m_xmlTest = xmlTest; m_testContext = testContext; NoOpTestClass tc = new NoOpTestClass(); tc.setTestClass(declaringClass); m_testClass = tc; } private static void ppp(String s) { System.out.println("[FactoryMethod] " + s); } public Object[] invoke() { List result = Lists.newArrayList(); Map allParameterNames = Maps.newHashMap(); Iterator parameterIterator = Parameters.handleParameters(this, allParameterNames, m_instance, new Parameters.MethodParameters(m_xmlTest.getAllParameters(), findMethodParameters(m_xmlTest), null, null, m_testContext, null /* testResult */), m_xmlTest.getSuite(), m_annotationFinder, null /* fedInstance */).parameters; try { while (parameterIterator.hasNext()) { Object[] parameters = parameterIterator.next(); Object[] testInstances; ConstructorOrMethod com = getConstructorOrMethod(); if (com.getMethod() != null) { testInstances = (Object[]) getMethod().invoke(m_instance, parameters); for (Object testInstance : testInstances) { result.add(testInstance); } } else { Object instance = com.getConstructor().newInstance(parameters); result.add(instance); } } } catch (Throwable t) { ConstructorOrMethod com = getConstructorOrMethod(); throw new TestNGException("The factory method " + com.getDeclaringClass() + "." + com.getName() + "() threw an exception", t); } return result.toArray(new Object[result.size()]); } @Override public ITestNGMethod clone() { throw new IllegalStateException("clone is not supported for FactoryMethod"); } } testng-6.9.12/src/main/java/org/testng/internal/invokers/0000755000175000017500000000000012732165123022624 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/invokers/InvokedMethodListenerMethod.java0000644000175000017500000000056612732165123031105 0ustar eugeneeugenepackage org.testng.internal.invokers; import org.testng.IInvokedMethodListener; import org.testng.IInvokedMethodListener2; /** * Indicates which of the methods of a {@link IInvokedMethodListener} or * {@link IInvokedMethodListener2} should be called. * * @author Ansgar Konermann */ public enum InvokedMethodListenerMethod { BEFORE_INVOCATION, AFTER_INVOCATION } testng-6.9.12/src/main/java/org/testng/internal/invokers/InvokedMethodListenerInvoker.java0000644000175000017500000001374612732165123031306 0ustar eugeneeugenepackage org.testng.internal.invokers; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.IInvokedMethodListener2; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.collections.Maps; import java.util.Map; import static org.testng.internal.invokers.InvokedMethodListenerMethod.AFTER_INVOCATION; import static org.testng.internal.invokers.InvokedMethodListenerMethod.BEFORE_INVOCATION; import static org.testng.internal.invokers.InvokedMethodListenerSubtype.EXTENDED_LISTENER; import static org.testng.internal.invokers.InvokedMethodListenerSubtype.SIMPLE_LISTENER; /** * Hides complexity of calling methods of {@link IInvokedMethodListener} and * {@link IInvokedMethodListener2}. * * @author Ansgar Konermann */ public class InvokedMethodListenerInvoker { private InvokedMethodListenerMethod m_listenerMethod; private ITestContext m_testContext; private ITestResult m_testResult; /** * Creates a new invoker instance which can be used to call the specified {@code listenerMethod} * on any number of {@link IInvokedMethodListener}s. * * @param listenerMethod method which should be called * @param testResult test result which should be passed to the listener method upon invocation * @param testContext test context which should be passed to the listener method upon invocation. * This parameter is only used when calling methods on an {@link IInvokedMethodListener2}. */ public InvokedMethodListenerInvoker(InvokedMethodListenerMethod listenerMethod, ITestResult testResult, ITestContext testContext) { m_listenerMethod = listenerMethod; m_testContext = testContext; m_testResult = testResult; } /** * Invoke the given {@code listenerInstance}, calling the method specified in the constructor of * this {@link InvokedMethodListenerInvoker}. * * @param listenerInstance the listener instance which should be invoked. * @param invokedMethod the {@link IInvokedMethod} instance which should be passed to the * {@link IInvokedMethodListener#beforeInvocation(IInvokedMethod, ITestResult)}, * {@link IInvokedMethodListener#afterInvocation(IInvokedMethod, ITestResult)}, * {@link IInvokedMethodListener2#beforeInvocation(IInvokedMethod, ITestResult, ITestContext)} * or {@link IInvokedMethodListener2#afterInvocation(IInvokedMethod, ITestResult, ITestContext)} * method. */ @SuppressWarnings("unchecked") public void invokeListener(IInvokedMethodListener listenerInstance, IInvokedMethod invokedMethod) { final InvocationStrategy strategy = obtainStrategyFor(listenerInstance, m_listenerMethod); strategy.callMethod(listenerInstance, invokedMethod, m_testResult, m_testContext); } private InvocationStrategy obtainStrategyFor(IInvokedMethodListener listenerInstance, InvokedMethodListenerMethod listenerMethod) { InvokedMethodListenerSubtype invokedMethodListenerSubtype = InvokedMethodListenerSubtype .fromListener(listenerInstance); Map strategiesForListenerType = strategies .get(invokedMethodListenerSubtype); InvocationStrategy invocationStrategy = strategiesForListenerType.get(listenerMethod); return invocationStrategy; } private static interface InvocationStrategy { void callMethod(LISTENER_TYPE listener, IInvokedMethod invokedMethod, ITestResult testResult, ITestContext testContext); } private static class InvokeBeforeInvocationWithoutContextStrategy implements InvocationStrategy { public void callMethod(IInvokedMethodListener listener, IInvokedMethod invokedMethod, ITestResult testResult, ITestContext testContext) { listener.beforeInvocation(invokedMethod, testResult); } } private static class InvokeBeforeInvocationWithContextStrategy implements InvocationStrategy { public void callMethod(IInvokedMethodListener2 listener, IInvokedMethod invokedMethod, ITestResult testResult, ITestContext testContext) { listener.beforeInvocation(invokedMethod, testResult, testContext); } } private static class InvokeAfterInvocationWithoutContextStrategy implements InvocationStrategy { public void callMethod(IInvokedMethodListener listener, IInvokedMethod invokedMethod, ITestResult testResult, ITestContext testContext) { listener.afterInvocation(invokedMethod, testResult); } } private static class InvokeAfterInvocationWithContextStrategy implements InvocationStrategy { public void callMethod(IInvokedMethodListener2 listener, IInvokedMethod invokedMethod, ITestResult testResult, ITestContext testContext) { listener.afterInvocation(invokedMethod, testResult, testContext); } } private static final Map> strategies = Maps.newHashMap(); private static final Map INVOKE_WITH_CONTEXT_STRATEGIES = Maps.newHashMap(); private static final Map INVOKE_WITHOUT_CONTEXT_STRATEGIES = Maps.newHashMap(); static { INVOKE_WITH_CONTEXT_STRATEGIES.put(BEFORE_INVOCATION, new InvokeBeforeInvocationWithContextStrategy()); INVOKE_WITH_CONTEXT_STRATEGIES.put(AFTER_INVOCATION, new InvokeAfterInvocationWithContextStrategy()); INVOKE_WITHOUT_CONTEXT_STRATEGIES.put(BEFORE_INVOCATION, new InvokeBeforeInvocationWithoutContextStrategy()); INVOKE_WITHOUT_CONTEXT_STRATEGIES.put(AFTER_INVOCATION, new InvokeAfterInvocationWithoutContextStrategy()); strategies.put(EXTENDED_LISTENER, INVOKE_WITH_CONTEXT_STRATEGIES); strategies.put(SIMPLE_LISTENER, INVOKE_WITHOUT_CONTEXT_STRATEGIES); } } testng-6.9.12/src/main/java/org/testng/internal/invokers/InvokedMethodListenerSubtype.java0000644000175000017500000000265712732165123031323 0ustar eugeneeugenepackage org.testng.internal.invokers; import org.testng.IInvokedMethodListener; import org.testng.IInvokedMethodListener2; import org.testng.TestNGException; /** * Indicates whether a {@link InvokedMethodListenerMethod} is to be called on a simple or an * extended invoked method listener. All {@link IInvokedMethodListener}s are considered * {@link #SIMPLE_LISTENER}, instances of {@link IInvokedMethodListener2} are all considered * {@link #EXTENDED_LISTENER}. * * @author Ansgar Konermann */ enum InvokedMethodListenerSubtype { EXTENDED_LISTENER(IInvokedMethodListener2.class), SIMPLE_LISTENER(IInvokedMethodListener.class); private Class m_matchingInterface; private InvokedMethodListenerSubtype(Class listenerClass) { m_matchingInterface = listenerClass; } private boolean isInstance(IInvokedMethodListener listenerInstance) { return m_matchingInterface.isInstance(listenerInstance); } public static InvokedMethodListenerSubtype fromListener(IInvokedMethodListener listenerInstance) { if (EXTENDED_LISTENER.isInstance(listenerInstance)) { return EXTENDED_LISTENER; } else if (SIMPLE_LISTENER.isInstance(listenerInstance)) { return SIMPLE_LISTENER; } throw new TestNGException("Illegal " + IInvokedMethodListener.class.getSimpleName() + " instance: " + listenerInstance.getClass().getName() + "."); } } testng-6.9.12/src/main/java/org/testng/internal/TestNGMethod.java0000755000175000017500000001567712732165123024157 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ITestClass; import org.testng.ITestNGMethod; import org.testng.annotations.ITestAnnotation; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlTest; import java.io.Serializable; import java.lang.reflect.Method; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * This class represents a test method. * * @author Cedric Beust, May 3, 2004 * @author Alexandru Popescu */ public class TestNGMethod extends BaseTestMethod implements Serializable { /** * */ private static final long serialVersionUID = -1742868891986775307L; private int m_threadPoolSize = 0; private int m_invocationCount = 1; private int m_totalInvocationCount = m_invocationCount; private int m_successPercentage = 100; /** * Constructs a TestNGMethod * * @param method * @param finder */ public TestNGMethod(Method method, IAnnotationFinder finder, XmlTest xmlTest, Object instance) { this(method, finder, true, xmlTest, instance); } private TestNGMethod(Method method, IAnnotationFinder finder, boolean initialize, XmlTest xmlTest, Object instance) { super(method.getName(), method, finder, instance); if(initialize) { init(xmlTest); } } /** * {@inheritDoc} */ @Override public int getInvocationCount() { return m_invocationCount; } /** * {@inheritDoc} */ @Override public int getTotalInvocationCount() { return m_totalInvocationCount; } /** * {@inheritDoc} */ @Override public int getSuccessPercentage() { return m_successPercentage; } /** * {@inheritDoc} */ @Override public boolean isTest() { return true; } private void ppp(String s) { System.out.println("[TestNGMethod] " + s); } private void init(XmlTest xmlTest) { setXmlTest(xmlTest); setInvocationNumbers(xmlTest.getInvocationNumbers( m_method.getDeclaringClass().getName() + "." + m_method.getName())); { ITestAnnotation testAnnotation = AnnotationHelper.findTest(getAnnotationFinder(), m_method.getMethod()); if (testAnnotation == null) { // Try on the class testAnnotation = AnnotationHelper.findTest(getAnnotationFinder(), m_method.getDeclaringClass()); } if (null != testAnnotation) { setTimeOut(testAnnotation.getTimeOut()); m_successPercentage = testAnnotation.getSuccessPercentage(); setInvocationCount(testAnnotation.getInvocationCount()); m_totalInvocationCount = testAnnotation.getInvocationCount(); setThreadPoolSize(testAnnotation.getThreadPoolSize()); setAlwaysRun(testAnnotation.getAlwaysRun()); setDescription(findDescription(testAnnotation, xmlTest)); setEnabled(testAnnotation.getEnabled()); setRetryAnalyzer(testAnnotation.getRetryAnalyzer()); setSkipFailedInvocations(testAnnotation.skipFailedInvocations()); setInvocationTimeOut(testAnnotation.invocationTimeOut()); setIgnoreMissingDependencies(testAnnotation.ignoreMissingDependencies()); setPriority(testAnnotation.getPriority()); } // Groups { initGroups(ITestAnnotation.class); } } } private String findDescription(ITestAnnotation testAnnotation, XmlTest xmlTest) { String result = testAnnotation.getDescription(); if (result == null) { List classes = xmlTest.getXmlClasses(); for (XmlClass c : classes) { if (c.getName().equals(m_method.getMethod().getDeclaringClass().getName())) { for (XmlInclude include : c.getIncludedMethods()) { if (include.getName().equals(m_method.getName())) { result = include.getDescription(); if (result != null) { break; } } } } } } return result; } /** * {@inheritDoc} */ @Override public int getThreadPoolSize() { return m_threadPoolSize; } /** * Sets the number of threads on which this method should be invoked. */ @Override public void setThreadPoolSize(int threadPoolSize) { m_threadPoolSize = threadPoolSize; } /** * Sets the number of invocations for this method. */ @Override public void setInvocationCount(int counter) { m_invocationCount= counter; } /** * Clones the current TestNGMethod and its @BeforeMethod and @AfterMethod methods. * @see org.testng.internal.BaseTestMethod#clone() */ @Override public BaseTestMethod clone() { TestNGMethod clone= new TestNGMethod(getMethod(), getAnnotationFinder(), false, getXmlTest(), getInstance()); ITestClass tc= getTestClass(); NoOpTestClass testClass= new NoOpTestClass(tc); testClass.setBeforeTestMethods(clone(tc.getBeforeTestMethods())); testClass.setAfterTestMethod(clone(tc.getAfterTestMethods())); clone.m_testClass= testClass; clone.setDate(getDate()); clone.setGroups(getGroups()); clone.setGroupsDependedUpon(getGroupsDependedUpon(), Collections.emptyList()); clone.setMethodsDependedUpon(getMethodsDependedUpon()); clone.setAlwaysRun(isAlwaysRun()); clone.m_beforeGroups= getBeforeGroups(); clone.m_afterGroups= getAfterGroups(); clone.m_currentInvocationCount= m_currentInvocationCount; clone.setMissingGroup(getMissingGroup()); clone.setThreadPoolSize(getThreadPoolSize()); clone.setDescription(getDescription()); clone.setEnabled(getEnabled()); clone.setParameterInvocationCount(getParameterInvocationCount()); clone.setInvocationCount(getInvocationCount()); clone.m_totalInvocationCount = getTotalInvocationCount(); clone.m_successPercentage = getSuccessPercentage(); clone.setTimeOut(getTimeOut()); clone.setRetryAnalyzer(getRetryAnalyzer()); clone.setSkipFailedInvocations(skipFailedInvocations()); clone.setInvocationNumbers(getInvocationNumbers()); clone.setPriority(getPriority()); return clone; } private ITestNGMethod[] clone(ITestNGMethod[] sources) { ITestNGMethod[] clones= new ITestNGMethod[sources.length]; for(int i= 0; i < sources.length; i++) { clones[i]= sources[i].clone(); } return clones; } /** Sorts ITestNGMethod by Class name. */ public static final Comparator SORT_BY_CLASS = new Comparator() { @Override public int compare(ITestNGMethod o1, ITestNGMethod o2) { String c1 = o1.getTestClass().getName(); String c2 = o2.getTestClass().getName(); return c1.compareTo(c2); } }; } testng-6.9.12/src/main/java/org/testng/internal/MethodGroupsHelper.java0000644000175000017500000002414212732165123025412 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import org.testng.ITestClass; import org.testng.ITestNGMethod; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.ITestOrConfiguration; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.collections.Pair; /** * Collections of helper methods to help deal with test methods * * @author Cedric Beust * @author nullin * */ public class MethodGroupsHelper { private static final Map PATTERN_CACHE = new ConcurrentHashMap<>(); private static final Map, Boolean> MATCH_CACHE = new ConcurrentHashMap<>(); /** * Collect all the methods that belong to the included groups and exclude all * the methods that belong to an excluded group. */ static void collectMethodsByGroup(ITestNGMethod[] methods, boolean forTests, List outIncludedMethods, List outExcludedMethods, RunInfo runInfo, IAnnotationFinder finder, boolean unique) { for (ITestNGMethod tm : methods) { boolean in = false; Method m = tm.getMethod(); // // @Test method // if (forTests) { in = MethodGroupsHelper.includeMethod(AnnotationHelper.findTest(finder, m), runInfo, tm, forTests, unique, outIncludedMethods); } // // @Configuration method // else { IConfigurationAnnotation annotation = AnnotationHelper.findConfiguration(finder, m); if (annotation.getAlwaysRun()) { if (!unique || !MethodGroupsHelper.isMethodAlreadyPresent(outIncludedMethods, tm)) { in = true; } } else { in = MethodGroupsHelper.includeMethod(AnnotationHelper.findTest(finder, tm), runInfo, tm, forTests, unique, outIncludedMethods); } } if (in) { outIncludedMethods.add(tm); } else { outExcludedMethods.add(tm); } } } private static boolean includeMethod(ITestOrConfiguration annotation, RunInfo runInfo, ITestNGMethod tm, boolean forTests, boolean unique, List outIncludedMethods) { boolean result = false; if (MethodHelper.isEnabled(annotation)) { if (runInfo.includeMethod(tm, forTests)) { if (unique) { if (!MethodGroupsHelper.isMethodAlreadyPresent(outIncludedMethods, tm)) { result = true; } } else { result = true; } } } return result; } /** * @param result * @param tm * @return true if a method by a similar name (and same hierarchy) already * exists */ private static boolean isMethodAlreadyPresent(List result, ITestNGMethod tm) { for (ITestNGMethod m : result) { Method jm1 = m.getMethod(); Method jm2 = tm.getMethod(); if (jm1.getName().equals(jm2.getName())) { // Same names, see if they are in the same hierarchy Class c1 = jm1.getDeclaringClass(); Class c2 = jm2.getDeclaringClass(); if (c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1)) { return true; } } } return false; } /** * Extracts the map of groups and their corresponding methods from the classes. */ public static Map> findGroupsMethods(Collection classes, boolean before) { Map> result = Maps.newHashMap(); for (ITestClass cls : classes) { ITestNGMethod[] methods = before ? cls.getBeforeGroupsMethods() : cls.getAfterGroupsMethods(); for (ITestNGMethod method : methods) { for (String group : before ? method.getBeforeGroups() : method.getAfterGroups()) { List methodList = result.get(group); if (methodList == null) { methodList = Lists.newArrayList(); result.put(group, methodList); } // NOTE(cbeust, 2007/01/23) // BeforeGroups/AfterGroups methods should only be invoked once. // I should probably use a map instead of a list for a contains(), but // this list should usually be fairly short if (! methodList.contains(method)) { methodList.add(method); } } } } return result; } protected static void findGroupTransitiveClosure(XmlMethodSelector xms, List includedMethods, List allMethods, String[] includedGroups, Set outGroups, Set outMethods) { Map runningMethods = Maps.newHashMap(); for (ITestNGMethod m : includedMethods) { runningMethods.put(m, m); } Map runningGroups = Maps.newHashMap(); for (String thisGroup : includedGroups) { runningGroups.put(thisGroup, thisGroup); } boolean keepGoing = true; Map newMethods = Maps.newHashMap(); while (keepGoing) { for (ITestNGMethod m : includedMethods) { // // Depends on groups? // Adds all included methods to runningMethods // String[] ig = m.getGroupsDependedUpon(); for (String g : ig) { if (! runningGroups.containsKey(g)) { // Found a new included group, add all the methods it contains to // our outMethod closure runningGroups.put(g, g); ITestNGMethod[] im = MethodGroupsHelper.findMethodsThatBelongToGroup(m, allMethods.toArray(new ITestNGMethod[allMethods.size()]), g); for (ITestNGMethod thisMethod : im) { if (! runningMethods.containsKey(thisMethod)) { runningMethods.put(thisMethod, thisMethod); newMethods.put(thisMethod, thisMethod); } } } } // groups // // Depends on methods? // Adds all depended methods to runningMethods // String[] mdu = m.getMethodsDependedUpon(); for (String tm : mdu) { ITestNGMethod thisMethod = MethodGroupsHelper.findMethodNamed(tm, allMethods); if (thisMethod != null && ! runningMethods.containsKey(thisMethod)) { runningMethods.put(thisMethod, thisMethod); newMethods.put(thisMethod, thisMethod); } } } // methods // // Only keep going if new methods have been added // keepGoing = newMethods.size() > 0; includedMethods = Lists.newArrayList(); includedMethods.addAll(newMethods.keySet()); newMethods = Maps.newHashMap(); } // while keepGoing outMethods.addAll(runningMethods.keySet()); outGroups.addAll(runningGroups.keySet()); } private static ITestNGMethod findMethodNamed(String tm, List allMethods) { for (ITestNGMethod m : allMethods) { // TODO(cbeust): account for package String methodName = m.getMethod().getDeclaringClass().getName() + "." + m.getMethodName(); if (methodName.equals(tm)) { return m; } } return null; } /** * Only used if a group is missing to flag an error on that method * * @param method if no group is found, group regex is set as this method's missing group * @param methods list of methods to search * @param groupRegexp regex representing the group * * @return all the methods that belong to the group specified by the regular * expression groupRegExp. methods[] is the list of all the methods we * are choosing from and method is the method that owns the dependsOnGroups * statement (only used if a group is missing to flag an error on that method). */ protected static ITestNGMethod[] findMethodsThatBelongToGroup( ITestNGMethod method, ITestNGMethod[] methods, String groupRegexp) { ITestNGMethod[] found = findMethodsThatBelongToGroup(methods, groupRegexp); if (found.length == 0) { method.setMissingGroup(groupRegexp); } return found; } /** * @param methods list of methods to search * @param groupRegexp regex representing the group * * @return all the methods that belong to the group specified by the regular * expression groupRegExp. methods[] is the list of all the methods we * are choosing from. */ protected static ITestNGMethod[] findMethodsThatBelongToGroup(ITestNGMethod[] methods, String groupRegexp) { List vResult = Lists.newArrayList(); final Pattern pattern = getPattern(groupRegexp); for (ITestNGMethod tm : methods) { String[] groups = tm.getGroups(); for (String group : groups) { Boolean match = isMatch(pattern, group); if (match) { vResult.add(tm); } } } return vResult.toArray(new ITestNGMethod[vResult.size()]); } private static Boolean isMatch(Pattern pattern, String group) { Pair cacheKey = Pair.create(pattern.pattern(), group); Boolean match = MATCH_CACHE.get(cacheKey); if (match == null) { match = pattern.matcher(group).matches(); MATCH_CACHE.put(cacheKey, match); } return match; } private static Pattern getPattern(String groupRegexp) { Pattern groupPattern = PATTERN_CACHE.get(groupRegexp); if (groupPattern == null) { groupPattern = Pattern.compile(groupRegexp); PATTERN_CACHE.put(groupRegexp, groupPattern); } return groupPattern; } } testng-6.9.12/src/main/java/org/testng/internal/InstanceInfo.java0000755000175000017500000000071212732165123024212 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IInstanceInfo; public class InstanceInfo implements IInstanceInfo { private final Class m_instanceClass; private final T m_instance; public InstanceInfo(Class cls, T instance) { m_instanceClass = cls; m_instance = instance; } @Override public T getInstance() { return m_instance; } @Override public Class getInstanceClass() { return m_instanceClass; } } testng-6.9.12/src/main/java/org/testng/internal/reflect/0000755000175000017500000000000012732165123022410 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/reflect/AbstractMethodMatcher.java0000644000175000017500000000225512732165123027467 0ustar eugeneeugenepackage org.testng.internal.reflect; import org.testng.internal.ThreeStateBoolean; import static org.testng.internal.ThreeStateBoolean.FALSE; import static org.testng.internal.ThreeStateBoolean.TRUE; /** * Created on 1/4/16. * * @author Nitin Verma */ public abstract class AbstractMethodMatcher implements MethodMatcher { private final MethodMatcherContext context; private ThreeStateBoolean conforms = ThreeStateBoolean.NONE; public AbstractMethodMatcher(final MethodMatcherContext context) { this.context = context; } protected MethodMatcherContext getContext() { return context; } protected ThreeStateBoolean getConforms() { return conforms; } /** * {@inheritDoc} */ @Override public boolean conforms() { boolean hasConformance = false; try { hasConformance = hasConformance(); } finally { conforms = hasConformance ? TRUE : FALSE; } return hasConformance; } /** * Checks if the arguments conform to the method. * * @return conformance * @throws MethodMatcherException if any internal failure. */ protected abstract boolean hasConformance(); } testng-6.9.12/src/main/java/org/testng/internal/reflect/DirectMethodMatcher.java0000644000175000017500000000233712732165123027137 0ustar eugeneeugenepackage org.testng.internal.reflect; import java.util.ArrayList; import java.util.List; import java.util.Set; import static org.testng.internal.reflect.InjectableParameter.Assistant.ALL_INJECTS; import static org.testng.internal.reflect.InjectableParameter.Assistant.NONE; /** * Checks for method argument match with or without filtering injectables. * * @author Nitin Verma */ public class DirectMethodMatcher extends AbstractNodeMethodMatcher { public DirectMethodMatcher(final MethodMatcherContext context) { super(context); } /** * {@inheritDoc} */ @Override protected List> getConformanceInjectsOrder() { final List> injectsOrder = new ArrayList<>(1); injectsOrder.add(ALL_INJECTS); injectsOrder.add(NONE); return injectsOrder; } /** * {@inheritDoc} */ @Override protected boolean match(final Parameter[] parameters, final Object[] arguments) { return ReflectionRecipes.exactMatch(parameters, getContext().getArguments()); } /** * {@inheritDoc} */ @Override protected Object[] matchingArguments(Parameter[] parameters, Object[] arguments) { return arguments; } } testng-6.9.12/src/main/java/org/testng/internal/reflect/ReflectionHelper.java0000644000175000017500000000263012732165123026506 0ustar eugeneeugenepackage org.testng.internal.reflect; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.LinkedList; import java.util.List; public class ReflectionHelper { /** * @return An array of all locally declared methods or equivalent thereof * (such as default methods on Java 8 based interfaces that the given class * implements). */ public static Method[] getLocalMethods(Class clazz) { Method[] result; Method[] declaredMethods = clazz.getDeclaredMethods(); List defaultMethods = getDefaultMethods(clazz); if (defaultMethods != null) { result = new Method[declaredMethods.length + defaultMethods.size()]; System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length); int index = declaredMethods.length; for (Method defaultMethod : defaultMethods) { result[index] = defaultMethod; index++; } } else { result = declaredMethods; } return result; } private static List getDefaultMethods(Class clazz) { List result = null; for (Class ifc : clazz.getInterfaces()) { for (Method ifcMethod : ifc.getMethods()) { if (!Modifier.isAbstract(ifcMethod.getModifiers())) { if (result == null) { result = new LinkedList(); } result.add(ifcMethod); } } } return result; } } testng-6.9.12/src/main/java/org/testng/internal/reflect/Parameter.java0000644000175000017500000000504712732165123025201 0ustar eugeneeugenepackage org.testng.internal.reflect; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * This class can be replaceable by java.lang.reflect.Parameter if using jdk 1.8. * * @author Nitin Verma */ public class Parameter implements AnnotatedElement { private final int index; private final Class type; /** * preserving the order of annotations. */ private final Annotation[] declaredAnnotations; /** * For efficient back to back searches. */ private final Map, Annotation> declaredAnnotationsMap; public Parameter(final int index, final Class type, final Annotation[] declaredAnnotations) { this.index = index; this.type = type; this.declaredAnnotations = declaredAnnotations; this.declaredAnnotationsMap = declaredAnnotations(declaredAnnotations); } private static Map, Annotation> declaredAnnotations(final Annotation[] ann) { final Map, Annotation> map = new HashMap<>(); if (ann != null) { for (int i = 0; i < ann.length; i++) { map.put(ann[i].annotationType(), ann[i]); } } return map; } @Override public String toString() { return "Parameter{" + "index=" + index + ", type=" + (type != null ? type.getName() : null) + ", declaredAnnotations=" + Arrays.toString(declaredAnnotations) + '}'; } /** * Returns a {@code Class} object that identifies the * declared type for the parameter represented by this * {@code Parameter} object. * * @return a {@code Class} object identifying the declared * type of the parameter represented by this object */ public Class getType() { return type; } /** * {@inheritDoc} */ @Override public boolean isAnnotationPresent(Class annotationClass) { return getAnnotation(annotationClass) != null; } /** * {@inheritDoc} */ @Override public T getAnnotation(final Class annotationClass) { return annotationClass.cast(declaredAnnotationsMap.get(annotationClass)); } /** * {@inheritDoc} */ @Override public Annotation[] getAnnotations() { // For parameter all annotations are declared. return getDeclaredAnnotations(); } /** * {@inheritDoc} */ @Override public Annotation[] getDeclaredAnnotations() { return declaredAnnotations; } } testng-6.9.12/src/main/java/org/testng/internal/reflect/DataProviderMethodMatcher.java0000644000175000017500000000313212732165123030303 0ustar eugeneeugenepackage org.testng.internal.reflect; import org.testng.internal.ThreeStateBoolean; import static org.testng.internal.ThreeStateBoolean.FALSE; import static org.testng.internal.ThreeStateBoolean.TRUE; /** * Checks the conformance as per data-provide specifications. * * @author Nitin Verma */ public class DataProviderMethodMatcher extends AbstractMethodMatcher { private final DirectMethodMatcher directMethodMatcher; private final ArrayEndingMethodMatcher arrayEndingMethodMatcher; private MethodMatcher matchingMatcher = null; public DataProviderMethodMatcher(final MethodMatcherContext context) { super(context); this.directMethodMatcher = new DirectMethodMatcher(context); this.arrayEndingMethodMatcher = new ArrayEndingMethodMatcher(context); } /** * {@inheritDoc} */ @Override protected boolean hasConformance() { boolean matching = false; if (directMethodMatcher.conforms()) { matching = true; matchingMatcher = directMethodMatcher; } else if (arrayEndingMethodMatcher.conforms()) { matching = true; matchingMatcher = arrayEndingMethodMatcher; } return matching; } /** * {@inheritDoc} */ @Override public Object[] getConformingArguments() throws MethodMatcherException { if (ThreeStateBoolean.NONE.equals(getConforms())) { conforms(); } if (matchingMatcher != null) { return matchingMatcher.getConformingArguments(); } throw new MethodMatcherException("Data provider mismatch", getContext().getMethod(), getContext().getArguments()); } } testng-6.9.12/src/main/java/org/testng/internal/reflect/InjectableParameter.java0000644000175000017500000000113412732165123027153 0ustar eugeneeugenepackage org.testng.internal.reflect; import java.util.EnumSet; import java.util.Set; /** * Enumeration of injectables. * * @author Nitin Verma */ public enum InjectableParameter { CURRENT_TEST_METHOD, ITEST_CONTEXT, ITEST_RESULT, XML_TEST; /** * convenience means to add and remove injectables. */ public static class Assistant { public static final Set NONE = EnumSet.noneOf(InjectableParameter.class); public static final Set ALL_INJECTS = EnumSet.allOf(InjectableParameter.class); } } testng-6.9.12/src/main/java/org/testng/internal/reflect/ReflectionRecipes.java0000644000175000017500000003234012732165123026662 0ustar eugeneeugenepackage org.testng.internal.reflect; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.TestNGException; import org.testng.annotations.NoInjection; import org.testng.xml.XmlTest; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * Utility class to handle reflection. * * @author Nitin Verma */ public final class ReflectionRecipes { private static final Map PRIMITIVE_MAPPING = new HashMap<>(); static { PRIMITIVE_MAPPING.put(boolean.class, Boolean.class); PRIMITIVE_MAPPING.put(byte.class, Byte.class); PRIMITIVE_MAPPING.put(short.class, Short.class); PRIMITIVE_MAPPING.put(int.class, Integer.class); PRIMITIVE_MAPPING.put(long.class, Long.class); PRIMITIVE_MAPPING.put(float.class, Float.class); PRIMITIVE_MAPPING.put(double.class, Double.class); PRIMITIVE_MAPPING.put(char.class, Character.class); PRIMITIVE_MAPPING.put(void.class, Void.class); } private ReflectionRecipes() { throw new TestNGException("Service is not meant to have instances"); } /** * Checks if an instance is an instance of the given class. * * @param reference reference class. * @param object instance to be tested. * @return is an instance-of or not */ public static boolean isInstanceOf(final Class reference, final Object object) { if (object == null) { return !reference.isPrimitive(); } boolean isInstanceOf = false; final boolean directInstance = reference.isInstance(object); if (!directInstance && reference.isPrimitive()) { isInstanceOf = PRIMITIVE_MAPPING.get(reference).isInstance(object); } else { isInstanceOf = directInstance; } return isInstanceOf; } /** * Checks a class instance for being a given interface or its implementation. * * @param reference reference interface instance. * @param clazz class instance to be tested. * @return would an instance of 'clazz' be an instance of reference interface. */ public static boolean isOrImplementsInterface(final Class reference, final Class clazz) { boolean implementsInterface = false; if (reference.isInterface()) { if (reference.equals(clazz)) { implementsInterface = true; } else { final Class[] interfaces = clazz.getInterfaces(); for (final Class interfaceClazz : interfaces) { implementsInterface = interfaceClazz.equals(reference); if (implementsInterface) break; } } } return implementsInterface; } /** * Checks a class instance for being a given class or its sub-class. * * @param reference reference class instance. * @param clazz class instance to be tested. * @return would an instance of 'clazz' be an instance of reference class. */ public static boolean isOrExtends(final Class reference, final Class clazz) { boolean extendsGiven = false; if (clazz != null) { if (!reference.isInterface()) { if (reference.equals(clazz)) { extendsGiven = true; } else { extendsGiven = isOrExtends(reference, clazz.getSuperclass()); } } } return extendsGiven; } /** * Extracts class instances from parameters. * * @param parameters an array of parameters. * @return parameter types. */ public static Class[] classesFromParameters(final Parameter[] parameters) { final Class[] classes = new Class[parameters.length]; int i = 0; for (final Parameter parameter : parameters) { classes[i] = parameter.getType(); i++; } return classes; } /** * Extracts method parameters. * * @param method any valid method. * @return extracted method parameters. */ public static Parameter[] getMethodParameters(final Method method) { if (method != null) { final Class parametersTypes[] = method.getParameterTypes(); final Annotation[][] parametersAnnotations = method.getParameterAnnotations(); final Parameter[] parameters = new Parameter[parametersTypes.length]; for (int i = 0; i < parametersTypes.length; i++) { parameters[i] = new Parameter(i, parametersTypes[i], parametersAnnotations[i]); } return parameters; } else { return null; } } /** * @return matches or not * @see #matchArrayEnding(Class[], Object[]) */ public static boolean matchArrayEnding(final Parameter[] parameters, final Object[] param) { return matchArrayEnding(classesFromParameters(parameters), param); } /** * Matches an array of class instances to an array of instances having last class instance an array. *

* Assuming upper case letters denote classes and corresponding lowercase its instances. Classes {A,B,C...}, * instances {a,b,c1,c2} ==> check for {a,b,{c1,c2}} match or Classes {A,B,C[]}, instances {a,b,c1,c2} ==> check for * {a,b,{c1,c2}} match both of the above cases are equivalent. * * @param classes array of class instances to check against. * @param args instances to be verified. * @return matches or not */ public static boolean matchArrayEnding(final Class[] classes, final Object[] args) { if (classes.length < 1) { return false; } if (!classes[classes.length - 1].isArray()) { return false; } boolean matching = true; int i = 0; if (classes.length <= args.length) { for (final Class clazz : classes) { if (i >= classes.length - 1) { break; } matching = ReflectionRecipes.isInstanceOf(clazz, args[i]); i++; if (!matching) break; } } else { matching = false; } if (matching) { final Class componentType = classes[classes.length - 1].getComponentType(); for (; i < args.length; i++) { matching = ReflectionRecipes.isInstanceOf(componentType, args[i]); if (!matching) break; } } return matching; } /** * Matches an array of parameters to an array of instances. * * @return matches or not * @see #exactMatch(Class[], Object[]) */ public static boolean exactMatch(final Parameter[] parameters, final Object[] args) { return exactMatch(classesFromParameters(parameters), args); } /** * Matches an array of class instances to an array of instances. * * @param classes array of class instances to check against. * @param args instances to be verified. * @return matches or not */ public static boolean exactMatch(final Class[] classes, final Object[] args) { boolean matching = true; if (classes.length == args.length) { int i = 0; for (final Class clazz : classes) { matching = ReflectionRecipes.isInstanceOf(clazz, args[i]); i++; if (!matching) break; } } else { matching = false; } return matching; } /** * Matches an array of parameters to an array of instances. * * @return matches or not * @see #lenientMatch(Class[], Object[]) */ public static boolean lenientMatch(final Parameter[] parameters, final Object[] args) { return lenientMatch(classesFromParameters(parameters), args); } /** * Matches an array of class instances to an array of instances. Such that {int, boolean, float} matches {int, * boolean} * * @param classes array of class instances to check against. * @param args instances to be verified. * @return matches or not */ public static boolean lenientMatch(final Class[] classes, final Object[] args) { boolean matching = true; int i = 0; for (final Class clazz : classes) { matching = ReflectionRecipes.isInstanceOf(clazz, args[i]); i++; if (!matching) break; } return matching; } /** * Omits 1. org.testng.ITestContext or its implementations from input array 2. org.testng.ITestResult or its * implementations from input array 3. org.testng.xml.XmlTest or its implementations from input array 4. First * method depending on filters. *

* An example would be Input: {ITestContext.class, int.class, Boolean.class, TestContext.class} Output: {int.class, * Boolean.class} * * @param parameters array of parameter instances under question. * @param filters filters to use. * @return Injects free array of class instances. */ public static Parameter[] filter(final Parameter[] parameters, final Set filters) { if (filters != null && !filters.isEmpty()) { boolean firstMethodFiltered = false; final List filterList = new ArrayList<>(parameters.length); for (final Parameter parameter : parameters) { boolean omit = false; for (final InjectableParameter injectableParameter : filters) { omit = canInject(parameter, injectableParameter); switch (injectableParameter) { case CURRENT_TEST_METHOD: if (omit && !firstMethodFiltered) { firstMethodFiltered = true; } else { omit = false; } break; default: break; } if (omit) { break; } } if (!omit) { filterList.add(parameter); } } final Parameter[] filteredArray = new Parameter[filterList.size()]; return filterList.toArray(filteredArray); } else { return parameters; } } /** * Injects appropriate arguments. * * @param parameters array of parameter instances under question. * @param filters filters to use. * @param args user supplied arguments. * @param injectionMethod current test method. * @param context current test context. * @param testResult on going test results. * @return injected arguments. */ public static Object[] inject(final Parameter[] parameters, final Set filters, final Object[] args, final Method injectionMethod, final ITestContext context, final ITestResult testResult) { if (filters != null && !filters.isEmpty()) { final ArrayList arguments = new ArrayList<>(args.length); final ListBackedImmutableQueue queue = new ListBackedImmutableQueue<>(args); boolean firstMethodInjected = false; for (final Parameter parameter : parameters) { boolean inject = false; Object injectObject = null; for (final InjectableParameter injectableParameter : filters) { inject = canInject(parameter, injectableParameter); switch (injectableParameter) { case CURRENT_TEST_METHOD: injectObject = injectionMethod; if (inject && !firstMethodInjected) { firstMethodInjected = true; } else { inject = false; } break; case ITEST_CONTEXT: injectObject = context; break; case ITEST_RESULT: injectObject = testResult; break; case XML_TEST: injectObject = context != null ? context.getCurrentXmlTest() : null; break; default: break; } if (inject) { arguments.add(injectObject); break; } } if (!inject) { arguments.add(queue.poll()); } } final Object[] injectedArray = new Object[arguments.size()]; return arguments.toArray(injectedArray); } else { return args; } } private static boolean canInject(final Parameter parameter, final InjectableParameter injectableParameter) { boolean canInject = false; if (parameter != null && injectableParameter != null) { final boolean inject = !parameter.isAnnotationPresent(NoInjection.class); switch (injectableParameter) { case CURRENT_TEST_METHOD: final boolean isMethod = isOrExtends(Method.class, parameter.getType()); canInject = inject && isMethod; break; case ITEST_CONTEXT: canInject = inject && isOrImplementsInterface(ITestContext.class, parameter.getType()); break; case ITEST_RESULT: canInject = inject && isOrImplementsInterface(ITestResult.class, parameter.getType()); break; case XML_TEST: canInject = inject && isOrExtends(XmlTest.class, parameter.getType()); break; default: canInject = false; break; } } return canInject; } private static class ListBackedImmutableQueue { private final List backingList; public ListBackedImmutableQueue(final T[] elements) { backingList = new ArrayList<>(elements.length); for (int i = 0; i < elements.length; i++) { // to ensure fifo & hold nulls backingList.add(elements[i]); } } public T poll() { if (!backingList.isEmpty()) { return backingList.remove(0); } throw new TestNGException("Queue exhausted"); } } } testng-6.9.12/src/main/java/org/testng/internal/reflect/MethodMatcher.java0000644000175000017500000000127612732165123026005 0ustar eugeneeugenepackage org.testng.internal.reflect; /** * An interface to validate conformance of input arguments to its target method. * * @author Nitin Verma */ public interface MethodMatcher { /** * Checks if the arguments conform to the method. * * @return conformance * @throws MethodMatcherException if any internal failure. */ boolean conforms() throws MethodMatcherException; /** * If possible gives an array consumable by java method invoker. * * @return conforming argument array * @throws MethodMatcherException internal failure or non-conformance */ Object[] getConformingArguments() throws MethodMatcherException; } testng-6.9.12/src/main/java/org/testng/internal/reflect/MethodMatcherContext.java0000644000175000017500000000257612732165123027356 0ustar eugeneeugenepackage org.testng.internal.reflect; import org.testng.ITestContext; import org.testng.ITestResult; import java.lang.reflect.Method; /** * Input context for MethodMatchers. * * @author Nitin Verma */ public class MethodMatcherContext { private final Method method; private final Parameter[] methodParameter; private final Object[] arguments; private final ITestContext testContext; private final ITestResult testResult; /** * Constructs a context for MethodMatchers. * * @param method current method. * @param arguments user arguments. * @param testContext current test context. * @param testResult current test results. */ public MethodMatcherContext( final Method method, final Object[] arguments, final ITestContext testContext, final ITestResult testResult) { this.method = method; this.methodParameter = ReflectionRecipes.getMethodParameters(method); this.arguments = arguments; this.testContext = testContext; this.testResult = testResult; } public Parameter[] getMethodParameter() { return methodParameter; } public Method getMethod() { return method; } public Object[] getArguments() { return arguments; } public ITestContext getTestContext() { return testContext; } public ITestResult getTestResult() { return testResult; } } testng-6.9.12/src/main/java/org/testng/internal/reflect/AbstractNodeMethodMatcher.java0000644000175000017500000000532212732165123030273 0ustar eugeneeugenepackage org.testng.internal.reflect; import org.testng.internal.ThreeStateBoolean; import java.util.List; import java.util.Set; /** * Created on 1/4/16. * * @author Nitin Verma */ public abstract class AbstractNodeMethodMatcher extends AbstractMethodMatcher { private Parameter[] conformingParameters = null; private Set conformingInjects = null; public AbstractNodeMethodMatcher(final MethodMatcherContext context) { super(context); } protected Parameter[] getConformingParameters() { return conformingParameters; } protected Set getConformingInjects() { return conformingInjects; } /** * {@inheritDoc} */ @Override protected boolean hasConformance() { boolean matching = false; for (final Set injects : getConformanceInjectsOrder()) { final Parameter[] parameters = ReflectionRecipes.filter(getContext().getMethodParameter(), injects); matching = match(parameters, getContext().getArguments()); if (matching) { conformingParameters = parameters; conformingInjects = injects; break; } } return matching; } /** * @return injects to check against. */ protected abstract List> getConformanceInjectsOrder(); /** * Checks if its possible to gives an array consumable by java method invoker. * * @param parameters array of parameter instances under question. * @param arguments instances to be verified. * @return matches or not */ protected abstract boolean match(final Parameter[] parameters, final Object[] arguments); /** * {@inheritDoc} */ @Override public Object[] getConformingArguments() throws MethodMatcherException { if (ThreeStateBoolean.NONE.equals(getConforms())) { conforms(); } if (getConformingParameters() == null) { throw new MethodMatcherException(this.getClass().getSimpleName() + " mismatch", getContext().getMethod(), getContext().getArguments()); } return ReflectionRecipes.inject( getContext().getMethodParameter(), InjectableParameter.Assistant.ALL_INJECTS, matchingArguments(getConformingParameters(), getContext().getArguments()), getContext().getMethod(), getContext().getTestContext(), getContext().getTestResult() ); } /** * If possible gives an array consumable by java method invoker. * * @param parameters array of parameter instances under question. * @param arguments instances to conform. * @return conforming argument array */ protected abstract Object[] matchingArguments(final Parameter[] parameters, final Object[] arguments); } testng-6.9.12/src/main/java/org/testng/internal/reflect/MethodMatcherException.java0000644000175000017500000000323112732165123027655 0ustar eugeneeugenepackage org.testng.internal.reflect; import org.testng.TestNGException; import java.lang.reflect.Method; import java.util.Arrays; /** * Thrown from MethodMatcher. * * @author Nitin Verma */ public class MethodMatcherException extends TestNGException { public MethodMatcherException(final String message, final Method method, final Object[] args) { this(generateMessage(message, method, args)); } public MethodMatcherException(String message) { super(message); } public MethodMatcherException(String message, Throwable cause) { super(message, cause); } public MethodMatcherException(Throwable cause) { super(cause); } private static String generateMessage(final String message, final Method method, final Object[] args) { final StringBuilder sb = new StringBuilder(); sb.append(message).append("\n").append("Method: "); if (method != null) { final Parameter[] parameter = ReflectionRecipes.getMethodParameters(method); sb.append(method.getName()).append("(").append(Arrays.toString(parameter)).append(")"); } else { sb.append("null"); } sb.append("\n").append("Arguments: "); if (args != null) { sb.append("["); for (int i = 0; i < args.length; i++) { final Object arg = args[i]; if (arg != null) { sb.append("(").append(arg.getClass().getName()).append(")").append(arg); } else { sb.append("null"); } if (i < args.length - 1) { sb.append(","); } } sb.append("]"); } else { sb.append("Arguments: null"); } return sb.toString(); } } testng-6.9.12/src/main/java/org/testng/internal/reflect/ArrayEndingMethodMatcher.java0000644000175000017500000000356412732165123030133 0ustar eugeneeugenepackage org.testng.internal.reflect; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.List; import java.util.Set; import static org.testng.internal.reflect.InjectableParameter.Assistant.ALL_INJECTS; /** * Checks for array ending method argument match with or without filtering injectables. * * @author Nitin Verma * @see ReflectionRecipes#matchArrayEnding(Class[], Object[]) */ public class ArrayEndingMethodMatcher extends AbstractNodeMethodMatcher { public ArrayEndingMethodMatcher(final MethodMatcherContext context) { super(context); } /** * {@inheritDoc} */ @Override protected List> getConformanceInjectsOrder() { final List> injectsOrder = new ArrayList<>(1); injectsOrder.add(ALL_INJECTS); return injectsOrder; } /** * {@inheritDoc} * * @see ReflectionRecipes#matchArrayEnding(Class[], Object[]) */ @Override protected boolean match(final Parameter[] parameters, final Object[] arguments) { return ReflectionRecipes.matchArrayEnding(parameters, getContext().getArguments()); } /** * {@inheritDoc} */ @Override protected Object[] matchingArguments(final Parameter[] parameters, final Object[] arguments) { final Class[] classes = ReflectionRecipes.classesFromParameters(parameters); final Object[] objects = new Object[classes.length]; final Class componentType = classes[classes.length - 1].getComponentType(); final Object array = Array.newInstance(componentType, arguments.length - classes.length + 1); System.arraycopy(arguments, 0, objects, 0, classes.length - 1); int j = 0; for (int i = classes.length - 1; i < arguments.length; i++, j++) { Array.set(array, j, arguments[i]); } objects[classes.length - 1] = array; return objects; } } testng-6.9.12/src/main/java/org/testng/internal/Invoker.java0000644000175000017500000017636712732165123023270 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.testng.IClass; import org.testng.IClassListener; import org.testng.IConfigurable; import org.testng.IConfigurationListener; import org.testng.IConfigurationListener2; import org.testng.IHookable; import org.testng.IInvokedMethod; import org.testng.IInvokedMethodListener; import org.testng.IRetryAnalyzer; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.SkipException; import org.testng.SuiteRunState; import org.testng.TestException; import org.testng.TestNGException; import org.testng.annotations.IConfigurationAnnotation; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.InvokeMethodRunnable.TestNGRuntimeException; import org.testng.internal.ParameterHolder.ParameterOrigin; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.invokers.InvokedMethodListenerInvoker; import org.testng.internal.invokers.InvokedMethodListenerMethod; import org.testng.internal.reflect.DataProviderMethodMatcher; import org.testng.internal.reflect.MethodMatcher; import org.testng.internal.reflect.MethodMatcherContext; import org.testng.internal.thread.ThreadExecutionException; import org.testng.internal.thread.ThreadUtil; import org.testng.internal.thread.graph.IWorker; import org.testng.xml.XmlClass; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import static org.testng.internal.invokers.InvokedMethodListenerMethod.AFTER_INVOCATION; import static org.testng.internal.invokers.InvokedMethodListenerMethod.BEFORE_INVOCATION; /** * This class is responsible for invoking methods: * - test methods * - configuration methods * - possibly in a separate thread * and then for notifying the result listeners. * * @author Cedric Beust * @author Alexandru Popescu */ public class Invoker implements IInvoker { private final ITestContext m_testContext; private final ITestResultNotifier m_notifier; private final IAnnotationFinder m_annotationFinder; private final SuiteRunState m_suiteState; private final boolean m_skipFailedInvocationCounts; private final Collection m_invokedMethodListeners; private final boolean m_continueOnFailedConfiguration; private final List m_classListeners; /** Group failures must be synced as the Invoker is accessed concurrently */ private Map m_beforegroupsFailures = Maps.newHashtable(); /** Class failures must be synced as the Invoker is accessed concurrently */ private Map, Set> m_classInvocationResults = Maps.newHashtable(); /** Test methods whose configuration methods have failed. */ private Map> m_methodInvocationResults = Maps.newHashtable(); private IConfiguration m_configuration; /** Predicate to filter methods */ private static Predicate CAN_RUN_FROM_CLASS = new CanRunFromClassPredicate(); /** Predicate to filter methods */ private static final Predicate SAME_CLASS = new SameClassNamePredicate(); private void setClassInvocationFailure(Class clazz, Object instance) { Set instances = m_classInvocationResults.get( clazz ); if (instances == null) { instances = Sets.newHashSet(); m_classInvocationResults.put(clazz, instances); } instances.add(instance); } private void setMethodInvocationFailure(ITestNGMethod method, Object instance) { Set instances = m_methodInvocationResults.get(method); if (instances == null) { instances = Sets.newHashSet(); m_methodInvocationResults.put(method, instances); } instances.add(getMethodInvocationToken(method, instance)); } public Invoker(IConfiguration configuration, ITestContext testContext, ITestResultNotifier notifier, SuiteRunState state, boolean skipFailedInvocationCounts, Collection invokedMethodListeners, List classListeners) { m_configuration = configuration; m_testContext= testContext; m_suiteState= state; m_notifier= notifier; m_annotationFinder= configuration.getAnnotationFinder(); m_skipFailedInvocationCounts = skipFailedInvocationCounts; m_invokedMethodListeners = invokedMethodListeners; m_continueOnFailedConfiguration = testContext.getSuite().getXmlSuite().getConfigFailurePolicy() == XmlSuite.FailurePolicy.CONTINUE; m_classListeners = classListeners; } /** * Invoke configuration methods if they belong to the same TestClass passed * in parameter..

TODO: Calculate ahead of time which methods should be * invoked for each class. Might speed things up for users who invoke the * same test class with different parameters in the same suite run. * * If instance is non-null, the configuration will be run on it. If it is null, * the configuration methods will be run on all the instances retrieved * from the ITestClass. */ @Override public void invokeConfigurations(IClass testClass, ITestNGMethod[] allMethods, XmlSuite suite, Map params, Object[] parameterValues, Object instance) { invokeConfigurations(testClass, null, allMethods, suite, params, parameterValues, instance, null); } private void invokeConfigurations(IClass testClass, ITestNGMethod currentTestMethod, ITestNGMethod[] allMethods, XmlSuite suite, Map params, Object[] parameterValues, Object instance, ITestResult testMethodResult) { if(null == allMethods || allMethods.length == 0) { log(5, "No configuration methods found"); return; } ITestNGMethod[] methods= filterMethods(testClass, allMethods, SAME_CLASS); for(ITestNGMethod tm : methods) { if(null == testClass) { testClass= tm.getTestClass(); } ITestResult testResult= new TestResult(testClass, instance, tm, null, System.currentTimeMillis(), System.currentTimeMillis(), m_testContext); IConfigurationAnnotation configurationAnnotation= null; try { Object inst = tm.getInstance(); if (inst == null) { inst = instance; } Class objectClass= inst.getClass(); Method method= tm.getMethod(); // Only run the configuration if // - the test is enabled and // - the Configuration method belongs to the same class or a parent configurationAnnotation = AnnotationHelper.findConfiguration(m_annotationFinder, method); boolean alwaysRun= isAlwaysRun(configurationAnnotation); if(MethodHelper.isEnabled(objectClass, m_annotationFinder) || alwaysRun) { if (MethodHelper.isEnabled(configurationAnnotation)) { if (!confInvocationPassed(tm, currentTestMethod, testClass, instance) && !alwaysRun) { handleConfigurationSkip(tm, testResult, configurationAnnotation, currentTestMethod, instance, suite); continue; } log(3, "Invoking " + Utils.detailedMethodName(tm, true)); Object[] parameters = Parameters.createConfigurationParameters(tm.getMethod(), params, parameterValues, currentTestMethod, m_annotationFinder, suite, m_testContext, testMethodResult); testResult.setParameters(parameters); Object newInstance = null != instance ? instance: inst; runConfigurationListeners(testResult, true /* before */); invokeConfigurationMethod(newInstance, tm, parameters, testResult); // TODO: probably we should trigger the event for each instance??? testResult.setEndMillis(System.currentTimeMillis()); runConfigurationListeners(testResult, false /* after */); } else { log(3, "Skipping " + Utils.detailedMethodName(tm, true) + " because it is not enabled"); } } // if is enabled else { log(3, "Skipping " + Utils.detailedMethodName(tm, true) + " because " + objectClass.getName() + " is not enabled"); } } catch(InvocationTargetException ex) { handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, currentTestMethod, instance, suite); } catch(Throwable ex) { // covers the non-wrapper exceptions handleConfigurationFailure(ex, tm, testResult, configurationAnnotation, currentTestMethod, instance, suite); } } // for methods } /** * Marks the current TestResult as skipped and invokes the listeners. */ private void handleConfigurationSkip(ITestNGMethod tm, ITestResult testResult, IConfigurationAnnotation annotation, ITestNGMethod currentTestMethod, Object instance, XmlSuite suite) { recordConfigurationInvocationFailed(tm, testResult.getTestClass(), annotation, currentTestMethod, instance, suite); testResult.setStatus(ITestResult.SKIP); runConfigurationListeners(testResult, false /* after */); } /** * Is the IConfiguration marked as alwaysRun. */ private boolean isAlwaysRun(IConfigurationAnnotation configurationAnnotation) { if(null == configurationAnnotation) { return false; } boolean alwaysRun= false; if ((configurationAnnotation.getAfterSuite() || configurationAnnotation.getAfterTest() || configurationAnnotation.getAfterTestClass() || configurationAnnotation.getAfterTestMethod() || configurationAnnotation.getBeforeTestMethod() || configurationAnnotation.getBeforeTestClass() || configurationAnnotation.getBeforeTest() || configurationAnnotation.getBeforeSuite()) && configurationAnnotation.getAlwaysRun()) { alwaysRun= true; } return alwaysRun; } private void handleConfigurationFailure(Throwable ite, ITestNGMethod tm, ITestResult testResult, IConfigurationAnnotation annotation, ITestNGMethod currentTestMethod, Object instance, XmlSuite suite) { Throwable cause= ite.getCause() != null ? ite.getCause() : ite; if(isSkipExceptionAndSkip(cause)) { testResult.setThrowable(cause); handleConfigurationSkip(tm, testResult, annotation, currentTestMethod, instance, suite); return; } Utils.log("", 3, "Failed to invoke configuration method " + tm.getRealClass().getName() + "." + tm.getMethodName() + ":" + cause.getMessage()); handleException(cause, tm, testResult, 1); runConfigurationListeners(testResult, false /* after */); // // If in TestNG mode, need to take a look at the annotation to figure out // what kind of @Configuration method we're dealing with // if (null != annotation) { recordConfigurationInvocationFailed(tm, testResult.getTestClass(), annotation, currentTestMethod, instance, suite); } } /** * @return All the classes that belong to the same tag as @param cls */ private XmlClass[] findClassesInSameTest(Class cls, XmlSuite suite) { Map vResult= Maps.newHashMap(); String className= cls.getName(); for(XmlTest test : suite.getTests()) { for(XmlClass testClass : test.getXmlClasses()) { if(testClass.getName().equals(className)) { // Found it, add all the classes in this test in the result for(XmlClass thisClass : test.getXmlClasses()) { vResult.put(thisClass.getName(), thisClass); } // Note: we need to iterate through the entire suite since the same // class might appear in several tags } } } XmlClass[] result= vResult.values().toArray(new XmlClass[vResult.size()]); return result; } /** * Record internally the failure of a Configuration, so that we can determine * later if @Test should be skipped. */ private void recordConfigurationInvocationFailed(ITestNGMethod tm, IClass testClass, IConfigurationAnnotation annotation, ITestNGMethod currentTestMethod, Object instance, XmlSuite suite) { // If beforeTestClass or afterTestClass failed, mark either the config method's // entire class as failed, or the class under tests as failed, depending on // the configuration failure policy if (annotation.getBeforeTestClass() || annotation.getAfterTestClass()) { // tm is the configuration method, and currentTestMethod is null for BeforeClass // methods, so we need testClass if (m_continueOnFailedConfiguration) { setClassInvocationFailure(testClass.getRealClass(), instance); } else { setClassInvocationFailure(tm.getRealClass(), instance); } } // If before/afterTestMethod failed, mark either the config method's entire // class as failed, or just the current test method as failed, depending on // the configuration failure policy else if (annotation.getBeforeTestMethod() || annotation.getAfterTestMethod()) { if (m_continueOnFailedConfiguration) { setMethodInvocationFailure(currentTestMethod, instance); } else { setClassInvocationFailure(tm.getRealClass(), instance); } } // If beforeSuite or afterSuite failed, mark *all* the classes as failed // for configurations. At this point, the entire Suite is screwed else if (annotation.getBeforeSuite() || annotation.getAfterSuite()) { m_suiteState.failed(); } // beforeTest or afterTest: mark all the classes in the same // stanza as failed for configuration else if (annotation.getBeforeTest() || annotation.getAfterTest()) { setClassInvocationFailure(tm.getRealClass(), instance); XmlClass[] classes= findClassesInSameTest(tm.getRealClass(), suite); for(XmlClass xmlClass : classes) { setClassInvocationFailure(xmlClass.getSupportClass(), instance); } } String[] beforeGroups= annotation.getBeforeGroups(); if(null != beforeGroups && beforeGroups.length > 0) { for(String group: beforeGroups) { m_beforegroupsFailures.put(group, Boolean.FALSE); } } } /** * @return true if this class or a parent class failed to initialize. */ private boolean classConfigurationFailed(Class cls) { for (Class c : m_classInvocationResults.keySet()) { if (c == cls || c.isAssignableFrom(cls)) { return true; } } return false; } /** * @return true if this class has successfully run all its @Configuration * method or false if at least one of these methods failed. */ private boolean confInvocationPassed(ITestNGMethod method, ITestNGMethod currentTestMethod, IClass testClass, Object instance) { boolean result= true; Class cls = testClass.getRealClass(); if(m_suiteState.isFailed()) { result= false; } else { if (classConfigurationFailed(cls)) { if (! m_continueOnFailedConfiguration) { result = !classConfigurationFailed(cls); } else { result = !m_classInvocationResults.get(cls).contains(instance); } } // if method is BeforeClass, currentTestMethod will be null else if (m_continueOnFailedConfiguration && currentTestMethod != null && m_methodInvocationResults.containsKey(currentTestMethod)) { result = !m_methodInvocationResults.get(currentTestMethod).contains(getMethodInvocationToken(currentTestMethod, instance)); } else if (! m_continueOnFailedConfiguration) { for(Class clazz: m_classInvocationResults.keySet()) { // if (clazz == cls) { if(clazz.isAssignableFrom(cls)) { result= false; break; } } } } // check if there are failed @BeforeGroups String[] groups= method.getGroups(); if(null != groups && groups.length > 0) { for(String group: groups) { if(m_beforegroupsFailures.containsKey(group)) { result= false; break; } } } return result; } // Creates a token for tracking a unique invocation of a method on an instance. // Is used when configFailurePolicy=continue. private Object getMethodInvocationToken(ITestNGMethod method, Object instance) { return String.format("%s+%d", instance.toString(), method.getCurrentInvocationCount()); } /** * Effectively invokes a configuration method on all passed in instances. * TODO: Should change this method to be more like invokeMethod() so that we can * handle calls to {@code IInvokedMethodListener} better. * * @param targetInstance the instance to invoke the configuration method on * @param tm the configuration method * @param params the parameters needed for method invocation * @param testResult * @throws InvocationTargetException * @throws IllegalAccessException */ private void invokeConfigurationMethod(Object targetInstance, ITestNGMethod tm, Object[] params, ITestResult testResult) throws InvocationTargetException, IllegalAccessException { // Mark this method with the current thread id tm.setId(ThreadUtil.currentThreadInfo()); { InvokedMethod invokedMethod= new InvokedMethod(targetInstance, tm, params, System.currentTimeMillis(), testResult); runInvokedMethodListeners(BEFORE_INVOCATION, invokedMethod, testResult); m_notifier.addInvokedMethod(invokedMethod); try { Reporter.setCurrentTestResult(testResult); Method method = tm.getMethod(); // // If this method is a IConfigurable, invoke its run() method // IConfigurable configurableInstance = IConfigurable.class.isAssignableFrom(tm.getMethod().getDeclaringClass()) ? (IConfigurable) targetInstance : m_configuration.getConfigurable(); if (configurableInstance != null) { MethodInvocationHelper.invokeConfigurable(targetInstance, params, configurableInstance, method, testResult); } else { // // Not a IConfigurable, invoke directly // if (MethodHelper.calculateTimeOut(tm) <= 0) { MethodInvocationHelper.invokeMethod(method, targetInstance, params); } else { MethodInvocationHelper.invokeWithTimeout(tm, targetInstance, params, testResult); if (!testResult.isSuccess()) { // A time out happened throwConfigurationFailure(testResult, testResult.getThrowable()); throw testResult.getThrowable(); } } } } catch (InvocationTargetException | IllegalAccessException ex) { throwConfigurationFailure(testResult, ex); throw ex; } catch (Throwable ex) { throwConfigurationFailure(testResult, ex); throw new TestNGException(ex); } finally { Reporter.setCurrentTestResult(testResult); runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult); Reporter.setCurrentTestResult(null); } } } private void throwConfigurationFailure(ITestResult testResult, Throwable ex) { testResult.setStatus(ITestResult.FAILURE); testResult.setThrowable(ex.getCause() == null ? ex : ex.getCause()); } private void runInvokedMethodListeners(InvokedMethodListenerMethod listenerMethod, IInvokedMethod invokedMethod, ITestResult testResult) { if ( noListenersPresent() ) { return; } InvokedMethodListenerInvoker invoker = new InvokedMethodListenerInvoker(listenerMethod, testResult, m_testContext); for (IInvokedMethodListener currentListener : m_invokedMethodListeners) { invoker.invokeListener(currentListener, invokedMethod); } } private boolean noListenersPresent() { return (m_invokedMethodListeners == null) || (m_invokedMethodListeners.size() == 0); } // pass both paramValues and paramIndex to be thread safe in case parallel=true + dataprovider. private ITestResult invokeMethod(Object instance, final ITestNGMethod tm, Object[] parameterValues, int parametersIndex, XmlSuite suite, Map params, ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, ConfigurationGroupMethods groupMethods, FailureContext failureContext) { TestResult testResult = new TestResult(); // // Invoke beforeGroups configurations // invokeBeforeGroupsConfigurations(testClass, tm, groupMethods, suite, params, instance); // // Invoke beforeMethods only if // - firstTimeOnly is not set // - firstTimeOnly is set, and we are reaching at the first invocationCount // invokeConfigurations(testClass, tm, filterConfigurationMethods(tm, beforeMethods, true /* beforeMethods */), suite, params, parameterValues, instance, testResult); // // Create the ExtraOutput for this method // InvokedMethod invokedMethod = null; try { testResult.init(testClass, instance, tm, null, System.currentTimeMillis(), 0, m_testContext); testResult.setParameters(parameterValues); testResult.setHost(m_testContext.getHost()); testResult.setStatus(ITestResult.STARTED); Reporter.setCurrentTestResult(testResult); invokedMethod= new InvokedMethod(instance, tm, parameterValues, System.currentTimeMillis(), testResult); // Fix from ansgarkonermann // invokedMethod is used in the finally, which can be invoked if // any of the test listeners throws an exception, therefore, // invokedMethod must have a value before we get here if (!m_suiteState.isFailed()) { runTestListeners(testResult); } runInvokedMethodListeners(BEFORE_INVOCATION, invokedMethod, testResult); m_notifier.addInvokedMethod(invokedMethod); Method thisMethod = tm.getConstructorOrMethod().getMethod(); if(confInvocationPassed(tm, tm, testClass, instance)) { log(3, "Invoking " + tm.getRealClass().getName() + "." + tm.getMethodName()); // If this method is a IHookable, invoke its run() method IHookable hookableInstance = IHookable.class.isAssignableFrom(tm.getRealClass()) ? (IHookable) instance : m_configuration.getHookable(); if (MethodHelper.calculateTimeOut(tm) <= 0) { if (hookableInstance != null) { MethodInvocationHelper.invokeHookable(instance, parameterValues, hookableInstance, thisMethod, testResult); } else { // Not a IHookable, invoke directly MethodInvocationHelper.invokeMethod(thisMethod, instance, parameterValues); } testResult.setStatus(ITestResult.SUCCESS); } else { // Method with a timeout MethodInvocationHelper.invokeWithTimeout(tm, instance, parameterValues, testResult, hookableInstance); } } else { testResult.setStatus(ITestResult.SKIP); } } catch(InvocationTargetException ite) { testResult.setThrowable(ite.getCause()); testResult.setStatus(ITestResult.FAILURE); } catch(ThreadExecutionException tee) { // wrapper for TestNGRuntimeException Throwable cause= tee.getCause(); if(TestNGRuntimeException.class.equals(cause.getClass())) { testResult.setThrowable(cause.getCause()); } else { testResult.setThrowable(cause); } testResult.setStatus(ITestResult.FAILURE); } catch(Throwable thr) { // covers the non-wrapper exceptions testResult.setThrowable(thr); testResult.setStatus(ITestResult.FAILURE); } finally { // Set end time ASAP testResult.setEndMillis(System.currentTimeMillis()); ExpectedExceptionsHolder expectedExceptionClasses = new ExpectedExceptionsHolder(m_annotationFinder, tm, new RegexpExpectedExceptionsHolder(m_annotationFinder, tm)); List results = Lists.newArrayList(testResult); handleInvocationResults(tm, results, expectedExceptionClasses, failureContext); // If this method has a data provider and just failed, memorize the number // at which it failed. // Note: we're not exactly testing that this method has a data provider, just // that it has parameters, so might have to revisit this if bugs get reported // for the case where this method has parameters that don't come from a data // provider if (testResult.getThrowable() != null && parameterValues.length > 0) { tm.addFailedInvocationNumber(parametersIndex); } // // Increment the invocation count for this method // tm.incrementCurrentInvocationCount(); // Run invokedMethodListeners after updating TestResult runInvokedMethodListeners(AFTER_INVOCATION, invokedMethod, testResult); runTestListeners(testResult); collectResults(tm, testResult); // // Invoke afterMethods only if // - lastTimeOnly is not set // - lastTimeOnly is set, and we are reaching the last invocationCount // invokeConfigurations(testClass, tm, filterConfigurationMethods(tm, afterMethods, false /* beforeMethods */), suite, params, parameterValues, instance, testResult); // // Invoke afterGroups configurations // invokeAfterGroupsConfigurations(testClass, tm, groupMethods, suite, params, instance); // Reset the test result last. If we do this too early, Reporter.log() // invocations from listeners will be discarded Reporter.setCurrentTestResult(null); } return testResult; } void collectResults(ITestNGMethod testMethod, ITestResult result) { // Collect the results final int status = result.getStatus(); if(ITestResult.SUCCESS == status) { m_notifier.addPassedTest(testMethod, result); } else if(ITestResult.SKIP == status) { m_notifier.addSkippedTest(testMethod, result); } else if(ITestResult.FAILURE == status) { m_notifier.addFailedTest(testMethod, result); } else if(ITestResult.SUCCESS_PERCENTAGE_FAILURE == status) { m_notifier.addFailedButWithinSuccessPercentageTest(testMethod, result); } else { assert false : "UNKNOWN STATUS:" + status; } } /** * The array of methods contains @BeforeMethods if isBefore if true, @AfterMethods * otherwise. This function removes all the methods that should not be run at this * point because they are either firstTimeOnly or lastTimeOnly and we haven't reached * the current invocationCount yet */ private ITestNGMethod[] filterConfigurationMethods(ITestNGMethod tm, ITestNGMethod[] methods, boolean isBefore) { List result = Lists.newArrayList(); for (ITestNGMethod m : methods) { ConfigurationMethod cm = (ConfigurationMethod) m; if (isBefore) { if (! cm.isFirstTimeOnly() || (cm.isFirstTimeOnly() && tm.getCurrentInvocationCount() == 0)) { result.add(m); } } else { if (! cm.isLastTimeOnly() || (cm.isLastTimeOnly() && !tm.hasMoreInvocation())) { result.add(m); } } } return result.toArray(new ITestNGMethod[result.size()]); } /** * invokeTestMethods() eventually converge here to invoke a single @Test method. *

* This method is responsible for actually invoking the method. It decides if the invocation * must be done: *

    *
  • through an IHookable
  • *
  • directly (through reflection)
  • *
  • in a separate thread (in case it needs to timeout) *
* *

* This method is also responsible for invoking @BeforeGroup, @BeforeMethod, @AfterMethod, @AfterGroup * if it is the case for the passed in @Test method. */ protected ITestResult invokeTestMethod(Object instance, final ITestNGMethod tm, Object[] parameterValues, int parametersIndex, XmlSuite suite, Map params, ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, ConfigurationGroupMethods groupMethods, FailureContext failureContext) { // Mark this method with the current thread id tm.setId(ThreadUtil.currentThreadInfo()); ITestResult result = invokeMethod(instance, tm, parameterValues, parametersIndex, suite, params, testClass, beforeMethods, afterMethods, groupMethods, failureContext); return result; } /** * Filter all the beforeGroups methods and invoke only those that apply * to the current test method */ private void invokeBeforeGroupsConfigurations(ITestClass testClass, ITestNGMethod currentTestMethod, ConfigurationGroupMethods groupMethods, XmlSuite suite, Map params, Object instance) { synchronized(groupMethods) { List filteredMethods = Lists.newArrayList(); String[] groups = currentTestMethod.getGroups(); Map> beforeGroupMap = groupMethods.getBeforeGroupsMap(); for (String group : groups) { List methods = beforeGroupMap.get(group); if (methods != null) { filteredMethods.addAll(methods); } } ITestNGMethod[] beforeMethodsArray = filteredMethods.toArray(new ITestNGMethod[filteredMethods.size()]); // // Invoke the right groups methods // if(beforeMethodsArray.length > 0) { // don't pass the IClass or the instance as the method may be external // the invocation must be similar to @BeforeTest/@BeforeSuite invokeConfigurations(null, beforeMethodsArray, suite, params, null, /* no parameter values */ null); } // // Remove them so they don't get run again // groupMethods.removeBeforeGroups(groups); } } private void invokeAfterGroupsConfigurations(ITestClass testClass, ITestNGMethod currentTestMethod, ConfigurationGroupMethods groupMethods, XmlSuite suite, Map params, Object instance) { // Skip this if the current method doesn't belong to any group // (only a method that belongs to a group can trigger the invocation // of afterGroups methods) if (currentTestMethod.getGroups().length == 0) { return; } // See if the currentMethod is the last method in any of the groups // it belongs to Map filteredGroups = Maps.newHashMap(); String[] groups = currentTestMethod.getGroups(); synchronized(groupMethods) { for (String group : groups) { if (groupMethods.isLastMethodForGroup(group, currentTestMethod)) { filteredGroups.put(group, group); } } if(filteredGroups.isEmpty()) { return; } // The list of afterMethods to run Map afterMethods = Maps.newHashMap(); // Now filteredGroups contains all the groups for which we need to run the afterGroups // method. Find all the methods that correspond to these groups and invoke them. Map> map = groupMethods.getAfterGroupsMap(); for (String g : filteredGroups.values()) { List methods = map.get(g); // Note: should put them in a map if we want to make sure the same afterGroups // doesn't get run twice if (methods != null) { for (ITestNGMethod m : methods) { afterMethods.put(m, m); } } } // Got our afterMethods, invoke them ITestNGMethod[] afterMethodsArray = afterMethods.keySet().toArray(new ITestNGMethod[afterMethods.size()]); // don't pass the IClass or the instance as the method may be external // the invocation must be similar to @BeforeTest/@BeforeSuite invokeConfigurations(null, afterMethodsArray, suite, params, null, /* no parameter values */ null); // Remove the groups so they don't get run again groupMethods.removeAfterGroups(filteredGroups.keySet()); } } private Object[] getParametersFromIndex(Iterator parametersValues, int index) { while (parametersValues.hasNext()) { Object[] parameters = parametersValues.next(); if (index == 0) { return parameters; } index--; } return null; } int retryFailed(Object instance, final ITestNGMethod tm, XmlSuite suite, ITestClass testClass, ITestNGMethod[] beforeMethods, ITestNGMethod[] afterMethods, ConfigurationGroupMethods groupMethods, List result, int failureCount, ExpectedExceptionsHolder expectedExceptionHolder, ITestContext testContext, Map parameters, int parametersIndex) { final FailureContext failure = new FailureContext(); failure.count = failureCount; do { failure.instances = Lists.newArrayList (); Map allParameters = Maps.newHashMap(); /** * TODO: This recreates all the parameters every time when we only need * one specific set. Should optimize it by only recreating the set needed. */ ParameterBag bag = createParameters(tm, parameters, allParameters, suite, testContext, null /* fedInstance */); Object[] parameterValues = getParametersFromIndex(bag.parameterHolder.parameters, parametersIndex); result.add(invokeMethod(instance, tm, parameterValues, parametersIndex, suite, allParameters, testClass, beforeMethods, afterMethods, groupMethods, failure)); } while (!failure.instances.isEmpty()); return failure.count; } private ParameterBag createParameters(ITestNGMethod testMethod, Map parameters, Map allParameterNames, XmlSuite suite, ITestContext testContext, Object fedInstance) { Object instance; if (fedInstance != null) { instance = fedInstance; } else { instance = testMethod.getInstance(); } ParameterBag bag = handleParameters(testMethod, instance, allParameterNames, parameters, null, suite, testContext, fedInstance, null); return bag; } /** * Invoke all the test methods. Note the plural: the method passed in * parameter might be invoked several times if the test class it belongs * to has more than one instance (i.e., if an @Factory method has been * declared somewhere that returns several instances of this TestClass). * If no @Factory method was specified, testMethod will only be invoked * once. *

* Note that this method also takes care of invoking the beforeTestMethod * and afterTestMethod, if any. * * Note (alex): this method can be refactored to use a SingleTestMethodWorker that * directly invokes * {@link #invokeTestMethod(Object, ITestNGMethod, Object[], int, XmlSuite, Map, ITestClass, ITestNGMethod[], ITestNGMethod[], ConfigurationGroupMethods, FailureContext)} * and this would simplify the implementation (see how DataTestMethodWorker is used) */ @Override public List invokeTestMethods(ITestNGMethod testMethod, XmlSuite suite, Map testParameters, ConfigurationGroupMethods groupMethods, Object instance, ITestContext testContext) { // Potential bug here if the test method was declared on a parent class assert null != testMethod.getTestClass() : "COULDN'T FIND TESTCLASS FOR " + testMethod.getRealClass(); if (!MethodHelper.isEnabled(testMethod.getMethod(), m_annotationFinder)) { // return if the method is not enabled. No need to do any more calculations return Collections.emptyList(); } // By the time this testMethod to be invoked, // all dependencies should be already run or we need to skip this method, // so invocation count should not affect dependencies check final String okToProceed = checkDependencies(testMethod, testContext.getAllTestMethods()); if (okToProceed != null) { // // Not okToProceed. Test is being skipped // ITestResult result = registerSkippedTestResult(testMethod, null, System.currentTimeMillis(), new Throwable(okToProceed)); m_notifier.addSkippedTest(testMethod, result); return Collections.singletonList(result); } final Map parameters = testMethod.findMethodParameters(testContext.getCurrentXmlTest()); // For invocationCount > 1 and threadPoolSize > 1 run this method in its own pool thread. if (testMethod.getInvocationCount() > 1 && testMethod.getThreadPoolSize() > 1) { return invokePooledTestMethods(testMethod, suite, parameters, groupMethods, testContext); } long timeOutInvocationCount = testMethod.getInvocationTimeOut(); //FIXME: Is this correct? boolean onlyOne = testMethod.getThreadPoolSize() > 1 || timeOutInvocationCount > 0; int invocationCount = onlyOne ? 1 : testMethod.getInvocationCount(); ExpectedExceptionsHolder expectedExceptionHolder = new ExpectedExceptionsHolder(m_annotationFinder, testMethod, new RegexpExpectedExceptionsHolder(m_annotationFinder, testMethod)); final ITestClass testClass= testMethod.getTestClass(); final List result = Lists.newArrayList(); final FailureContext failure = new FailureContext(); final ITestNGMethod[] beforeMethods = filterMethods(testClass, testClass.getBeforeTestMethods(), CAN_RUN_FROM_CLASS); final ITestNGMethod[] afterMethods = filterMethods(testClass, testClass.getAfterTestMethods(), CAN_RUN_FROM_CLASS); while(invocationCount-- > 0) { if(false) { // Prevent code formatting } // // No threads, regular invocation // else { // Used in catch statement long start = System.currentTimeMillis(); Map allParameterNames = Maps.newHashMap(); ParameterBag bag = createParameters(testMethod, parameters, allParameterNames, suite, testContext, instance); if (bag.hasErrors()) { final ITestResult tr = bag.errorResult; tr.setStatus(ITestResult.SKIP); runTestListeners(tr); m_notifier.addSkippedTest(testMethod, tr); result.add(tr); continue; } Iterator allParameterValues = bag.parameterHolder.parameters; int parametersIndex = 0; try { if (bag.parameterHolder.origin == ParameterOrigin.ORIGIN_DATA_PROVIDER && bag.parameterHolder.dataProviderHolder.annotation.isParallel()) { List workers = Lists.newArrayList(); while (allParameterValues.hasNext()) { Object[] next = allParameterValues.next(); if (next == null) { // skipped value continue; } Object[] parameterValues = injectParameters(next, testMethod.getMethod(), testContext, null /* test result */); TestMethodWithDataProviderMethodWorker w = new TestMethodWithDataProviderMethodWorker(this, testMethod, parametersIndex, parameterValues, instance, suite, parameters, testClass, beforeMethods, afterMethods, groupMethods, expectedExceptionHolder, testContext, m_skipFailedInvocationCounts, invocationCount, failure.count, m_notifier); workers.add(w); // testng387: increment the param index in the bag. parametersIndex++; } PoolService> ps = new PoolService<>(suite.getDataProviderThreadCount()); List> r = ps.submitTasksAndWait(workers); for (List l2 : r) { result.addAll(l2); } } else { while (allParameterValues.hasNext()) { Object[] next = allParameterValues.next(); if (next == null) { // skipped value continue; } Object[] parameterValues = injectParameters(next, testMethod.getMethod(), testContext, null /* test result */); List tmpResults = Lists.newArrayList(); try { tmpResults.add(invokeTestMethod(instance, testMethod, parameterValues, parametersIndex, suite, parameters, testClass, beforeMethods, afterMethods, groupMethods, failure)); } finally { if (failure.instances.isEmpty()) { result.addAll(tmpResults); } else { for (Object failedInstance : failure.instances) { List retryResults = Lists.newArrayList(); failure.count = retryFailed( failedInstance, testMethod, suite, testClass, beforeMethods, afterMethods, groupMethods, retryResults, failure.count, expectedExceptionHolder, testContext, parameters, parametersIndex); result.addAll(retryResults); } } // // If we have a failure, skip all the // other invocationCounts // if (failure.count > 0 && (m_skipFailedInvocationCounts || testMethod.skipFailedInvocations())) { while (invocationCount-- > 0) { result.add(registerSkippedTestResult(testMethod, instance, System.currentTimeMillis(), null)); } } }// end finally parametersIndex++; } } } catch (Throwable cause) { ITestResult r = new TestResult(testMethod.getTestClass(), instance, testMethod, cause, start, System.currentTimeMillis(), m_testContext); r.setStatus(TestResult.FAILURE); result.add(r); runTestListeners(r); m_notifier.addFailedTest(testMethod, r); } // catch } } return result; } // invokeTestMethod private ITestResult registerSkippedTestResult(ITestNGMethod testMethod, Object instance, long start, Throwable throwable) { ITestResult result = new TestResult(testMethod.getTestClass(), instance, testMethod, throwable, start, System.currentTimeMillis(), m_testContext); result.setStatus(TestResult.SKIP); runTestListeners(result); return result; } /** * Gets an array of parameter values returned by data provider or the ones that * are injected based on parameter type. The method also checks for {@code NoInjection} * annotation * * @param parameterValues parameter values from a data provider * @param method method to be invoked * @param context test context * @param testResult test result */ private Object[] injectParameters(Object[] parameterValues, Method method, ITestContext context, ITestResult testResult) throws TestNGException { final MethodMatcher matcher = new DataProviderMethodMatcher( new MethodMatcherContext(method, parameterValues, context, testResult) ); return matcher.getConformingArguments(); } private ParameterBag handleParameters(ITestNGMethod testMethod, Object instance, Map allParameterNames, Map parameters, Object[] parameterValues, XmlSuite suite, ITestContext testContext, Object fedInstance, ITestResult testResult) { try { return new ParameterBag( Parameters.handleParameters(testMethod, allParameterNames, instance, new Parameters.MethodParameters(parameters, testMethod.findMethodParameters(testContext.getCurrentXmlTest()), parameterValues, testMethod.getMethod(), testContext, testResult), suite, m_annotationFinder, fedInstance)); } catch(Throwable cause) { return new ParameterBag( new TestResult( testMethod.getTestClass(), instance, testMethod, cause, System.currentTimeMillis(), System.currentTimeMillis(), m_testContext)); } } /** * Invokes a method that has a specified threadPoolSize. */ private List invokePooledTestMethods(ITestNGMethod testMethod, XmlSuite suite, Map parameters, ConfigurationGroupMethods groupMethods, ITestContext testContext) { // // Create the workers // List> workers = Lists.newArrayList(); // Create one worker per invocationCount for (int i = 0; i < testMethod.getInvocationCount(); i++) { // we use clones for reporting purposes ITestNGMethod clonedMethod= testMethod.clone(); clonedMethod.setInvocationCount(1); clonedMethod.setThreadPoolSize(1); MethodInstance mi = new MethodInstance(clonedMethod); workers.add(new SingleTestMethodWorker(this, mi, suite, parameters, testContext, m_classListeners)); } return runWorkers(testMethod, workers, testMethod.getThreadPoolSize(), groupMethods, suite, parameters); } static class FailureContext { int count = 0; List instances = Lists.newArrayList(); } void handleInvocationResults(ITestNGMethod testMethod, List result, ExpectedExceptionsHolder expectedExceptionsHolder, FailureContext failure) { // // Go through all the results and create a TestResult for each of them // List resultsToRetry = Lists.newArrayList(); for (ITestResult testResult : result) { Throwable ite= testResult.getThrowable(); int status= testResult.getStatus(); boolean handled = false; // Exception thrown? if (status == ITestResult.FAILURE && ite != null) { // Invocation caused an exception, see if the method was annotated with @ExpectedException if (expectedExceptionsHolder != null) { if (expectedExceptionsHolder.isExpectedException(ite)) { testResult.setStatus(ITestResult.SUCCESS); status = ITestResult.SUCCESS; } else { if (isSkipExceptionAndSkip(ite)){ status = ITestResult.SKIP; } else { testResult.setThrowable(expectedExceptionsHolder.wrongException(ite)); status = ITestResult.FAILURE; } } } else { handleException(ite, testMethod, testResult, failure.count++); handled = true; status = testResult.getStatus(); } } // No exception thrown, make sure we weren't expecting one else if(status != ITestResult.SKIP && expectedExceptionsHolder != null) { TestException exception = expectedExceptionsHolder.noException(testMethod); if (exception != null) { testResult.setThrowable(exception); status= ITestResult.FAILURE; } } IRetryAnalyzer retryAnalyzer = testMethod.getRetryAnalyzer(); boolean willRetry = retryAnalyzer != null && status == ITestResult.FAILURE && failure.instances != null && retryAnalyzer.retry(testResult); if (willRetry) { resultsToRetry.add(testResult); failure.count++; failure.instances.add(testResult.getInstance()); testResult.setStatus(ITestResult.SKIP); } else { testResult.setStatus(status); if (status == ITestResult.FAILURE && !handled) { handleException(ite, testMethod, testResult, failure.count++); } } } // for results removeResultsToRetryFromResult(resultsToRetry, result, failure); } private boolean isSkipExceptionAndSkip(Throwable ite) { return SkipException.class.isAssignableFrom(ite.getClass()) && ((SkipException) ite).isSkip(); } private void removeResultsToRetryFromResult(List resultsToRetry, List result, FailureContext failure) { if (resultsToRetry != null) { for (ITestResult res : resultsToRetry) { result.remove(res); failure.count--; } } } /** * To reduce thread contention and also to correctly handle thread-confinement * this method invokes the @BeforeGroups and @AfterGroups corresponding to the current @Test method. */ private List runWorkers(ITestNGMethod testMethod, List> workers, int threadPoolSize, ConfigurationGroupMethods groupMethods, XmlSuite suite, Map parameters) { // Invoke @BeforeGroups on the original method (reduce thread contention, // and also solve thread confinement) ITestClass testClass= testMethod.getTestClass(); Object[] instances = testClass.getInstances(true); for(Object instance: instances) { invokeBeforeGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance); } long maxTimeOut= -1; // 10 seconds for(IWorker tmw : workers) { long mt= tmw.getTimeOut(); if(mt > maxTimeOut) { maxTimeOut= mt; } } ThreadUtil.execute(workers, threadPoolSize, maxTimeOut, true); // // Collect all the TestResults // List result = Lists.newArrayList(); for (IWorker tmw : workers) { if (tmw instanceof TestMethodWorker) { result.addAll(((TestMethodWorker)tmw).getTestResults()); } } for(Object instance: instances) { invokeAfterGroupsConfigurations(testClass, testMethod, groupMethods, suite, parameters, instance); } return result; } /** * Checks to see of the test method has certain dependencies that prevents * TestNG from executing it * @param testMethod test method being checked for * @return error message or null if dependencies have been run successfully */ private String checkDependencies(ITestNGMethod testMethod, ITestNGMethod[] allTestMethods) { // If this method is marked alwaysRun, no need to check for its dependencies if (testMethod.isAlwaysRun()) { return null; } // Any missing group? if (testMethod.getMissingGroup() != null && !testMethod.ignoreMissingDependencies()) { return "Method " + testMethod + " depends on nonexistent group \"" + testMethod.getMissingGroup() + "\""; } // If this method depends on groups, collect all the methods that // belong to these groups and make sure they have been run successfully final String[] groups = testMethod.getGroupsDependedUpon(); if (null != groups && groups.length > 0) { // Get all the methods that belong to the group depended upon for (String element : groups) { ITestNGMethod[] methods = MethodGroupsHelper.findMethodsThatBelongToGroup(testMethod, m_testContext.getAllTestMethods(), element); if (methods.length == 0 && !testMethod.ignoreMissingDependencies()) { // Group is missing return "Method " + testMethod + " depends on nonexistent group \"" + element + "\""; } if (!haveBeenRunSuccessfully(testMethod, methods)) { return "Method " + testMethod + " depends on not successfully finished methods in group \"" + element + "\""; } } } // depends on groups // If this method depends on other methods, make sure all these other // methods have been run successfully if (dependsOnMethods(testMethod)) { ITestNGMethod[] methods = MethodHelper.findDependedUponMethods(testMethod, allTestMethods); if (!haveBeenRunSuccessfully(testMethod, methods)) { return "Method " + testMethod + " depends on not successfully finished methods"; } } return null; } /** * @return the test results that apply to one of the instances of the testMethod. */ private Set keepSameInstances(ITestNGMethod method, Set results) { Set result = Sets.newHashSet(); for (ITestResult r : results) { final Object o = method.getInstance(); // Keep this instance if 1) It's on a different class or 2) It's on the same class // and on the same instance Object instance = r.getInstance() != null ? r.getInstance() : r.getMethod().getInstance(); if (r.getTestClass() != method.getTestClass() || instance == o) result.add(r); } return result; } /** * @return true if all the methods have been run successfully */ private boolean haveBeenRunSuccessfully(ITestNGMethod testMethod, ITestNGMethod[] methods) { // Make sure the method has been run successfully for (ITestNGMethod method : methods) { Set results = keepSameInstances(testMethod, m_notifier.getPassedTests(method)); Set failedAndSkippedMethods = Sets.newHashSet(); failedAndSkippedMethods.addAll(m_notifier.getFailedTests(method)); failedAndSkippedMethods.addAll(m_notifier.getSkippedTests(method)); Set failedresults = keepSameInstances(testMethod, failedAndSkippedMethods); // If failed results were returned on the same instance, then these tests didn't pass if (failedresults != null && failedresults.size() > 0) { return false; } for (ITestResult result : results) { if(!result.isSuccess()) { return false; } } } return true; } // private boolean containsInstance(Set failedresults, Object[] instances) { // for (ITestResult tr : failedresults) { // for (Object o : instances) { // if (o == tr.getInstance()) { // return true; // } // } // } // return false; // } /** * An exception was thrown by the test, determine if this method * should be marked as a failure or as failure_but_within_successPercentage */ private void handleException(Throwable throwable, ITestNGMethod testMethod, ITestResult testResult, int failureCount) { if (throwable != null) { testResult.setThrowable(throwable); } int successPercentage= testMethod.getSuccessPercentage(); int invocationCount= testMethod.getInvocationCount(); float numberOfTestsThatCanFail= ((100 - successPercentage) * invocationCount) / 100f; if(failureCount < numberOfTestsThatCanFail) { testResult.setStatus(ITestResult.SUCCESS_PERCENTAGE_FAILURE); } else { testResult.setStatus(ITestResult.FAILURE); } } static interface Predicate { boolean isTrue(K k, T v); } static class CanRunFromClassPredicate implements Predicate { @Override public boolean isTrue(ITestNGMethod m, IClass v) { return m.canRunFromClass(v); } } static class SameClassNamePredicate implements Predicate { @Override public boolean isTrue(ITestNGMethod m, IClass c) { return c == null || m.getTestClass().getName().equals(c.getName()); } } /** * @return Only the ITestNGMethods applicable for this testClass */ private ITestNGMethod[] filterMethods(IClass testClass, ITestNGMethod[] methods, Predicate predicate) { List vResult= Lists.newArrayList(); for(ITestNGMethod tm : methods) { if (predicate.isTrue(tm, testClass)) { log(10, "Keeping method " + tm + " for class " + testClass); vResult.add(tm); } else { log(10, "Filtering out method " + tm + " for class " + testClass); } } ITestNGMethod[] result= vResult.toArray(new ITestNGMethod[vResult.size()]); return result; } /** * @return true if this method depends on certain methods. */ private boolean dependsOnMethods(ITestNGMethod tm) { String[] methods = tm.getMethodsDependedUpon(); return null != methods && methods.length > 0; } private void runConfigurationListeners(ITestResult tr, boolean before) { if (before) { for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) { if (icl instanceof IConfigurationListener2) { ((IConfigurationListener2) icl).beforeConfiguration(tr); } } } else { for(IConfigurationListener icl: m_notifier.getConfigurationListeners()) { switch(tr.getStatus()) { case ITestResult.SKIP: icl.onConfigurationSkip(tr); break; case ITestResult.FAILURE: icl.onConfigurationFailure(tr); break; case ITestResult.SUCCESS: icl.onConfigurationSuccess(tr); break; default: throw new AssertionError("Unexpected value: " + tr.getStatus()); } } } } void runTestListeners(ITestResult tr) { runTestListeners(tr, m_notifier.getTestListeners()); } // TODO: move this from here as it is directly called from TestNG public static void runTestListeners(ITestResult tr, List listeners) { for (ITestListener itl : listeners) { switch(tr.getStatus()) { case ITestResult.SKIP: { itl.onTestSkipped(tr); break; } case ITestResult.SUCCESS_PERCENTAGE_FAILURE: { itl.onTestFailedButWithinSuccessPercentage(tr); break; } case ITestResult.FAILURE: { itl.onTestFailure(tr); break; } case ITestResult.SUCCESS: { itl.onTestSuccess(tr); break; } case ITestResult.STARTED: { itl.onTestStart(tr); break; } default: { assert false : "UNKNOWN STATUS:" + tr; } } } } private void log(int level, String s) { Utils.log("Invoker " + Thread.currentThread().hashCode(), level, s); } /** * This class holds a {@code ParameterHolder} or in case of an error, a non-null * {@code TestResult} containing the cause */ private static class ParameterBag { final ParameterHolder parameterHolder; final ITestResult errorResult; public ParameterBag(ParameterHolder parameterHolder) { this.parameterHolder = parameterHolder; this.errorResult = null; } public ParameterBag(ITestResult errorResult) { this.parameterHolder = null; this.errorResult = errorResult; } public boolean hasErrors() { return errorResult != null; } } } testng-6.9.12/src/main/java/org/testng/internal/PropertiesFile.java0000755000175000017500000000202112732165123024561 0ustar eugeneeugenepackage org.testng.internal; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; /** * This class loads and abstracts remote.properties * * @author cbeust * @author Guy Korland * @since April 13, 2006 */ public class PropertiesFile { private Properties m_properties = new Properties(); /** * Loads a Properties file. * * @param fileName properties file path * @throws IOException if an error occurred when reading from the Properties file. */ public PropertiesFile(String fileName) throws IOException { FileInputStream fis = null; // // Parse the Properties file // try { fis = new FileInputStream(new File(fileName)); m_properties.load(fis); } finally { if( fis != null) { fis.close(); } } } /** * Returns the properties loaded. * @return loaded properties. */ public Properties getProperties() { return m_properties; } } testng-6.9.12/src/main/java/org/testng/internal/MethodInvocationHelper.java0000644000175000017500000003102012732165123026235 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IConfigurable; import org.testng.IConfigureCallBack; import org.testng.IHookCallBack; import org.testng.IHookable; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.TestNGException; import org.testng.annotations.DataProvider; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.collections.Pair; import org.testng.internal.thread.IExecutor; import org.testng.internal.thread.IFutureResult; import org.testng.internal.thread.ThreadExecutionException; import org.testng.internal.thread.ThreadTimeoutException; import org.testng.internal.thread.ThreadUtil; import org.testng.xml.XmlSuite; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; /** * Collections of helper methods to help deal with invocation of TestNG methods * * @author Cedric Beust * @author nullin * */ public class MethodInvocationHelper { protected static Object invokeMethodNoCheckedException(Method thisMethod, Object instance, List parameters) { try { return invokeMethod(thisMethod, instance, parameters); } catch (InvocationTargetException | IllegalAccessException e) { // Don't throw TestNGException here or this test won't be reported as a // skip or failure throw new RuntimeException(e.getCause()); } } protected static Object invokeMethod(Method thisMethod, Object instance, List parameters) throws InvocationTargetException, IllegalAccessException { return invokeMethod(thisMethod, instance, parameters.toArray(new Object[parameters.size()])); } protected static Object invokeMethod(Method thisMethod, Object instance, Object[] parameters) throws InvocationTargetException, IllegalAccessException { Utils.checkInstanceOrStatic(instance, thisMethod); // TESTNG-326, allow IObjectFactory to load from non-standard classloader // If the instance has a different classloader, its class won't match the // method's class if (instance == null || !thisMethod.getDeclaringClass().isAssignableFrom(instance.getClass())) { // for some reason, we can't call this method on this class // is it static? boolean isStatic = Modifier.isStatic(thisMethod.getModifiers()); if (!isStatic) { // not static, so grab a method with the same name and signature in this case Class clazz = instance.getClass(); try { thisMethod = clazz.getMethod(thisMethod.getName(), thisMethod.getParameterTypes()); } catch (Exception e) { // ignore, the method may be private boolean found = false; for (; clazz != null; clazz = clazz.getSuperclass()) { try { thisMethod = clazz.getDeclaredMethod(thisMethod.getName(), thisMethod.getParameterTypes()); found = true; break; } catch (Exception e2) { } } if (!found) { // should we assert here? Or just allow it to fail on invocation? if (thisMethod.getDeclaringClass().getName().equals(instance.getClass().getName())) { throw new RuntimeException("Can't invoke method " + thisMethod + ", probably due to classloader mismatch"); } throw new RuntimeException("Can't invoke method " + thisMethod + " on this instance of " + instance.getClass() + " due to class mismatch"); } } } } synchronized(thisMethod) { if (! Modifier.isPublic(thisMethod.getModifiers()) || !thisMethod.isAccessible()) { thisMethod.setAccessible(true); } } return thisMethod.invoke(instance, parameters); } protected static Iterator invokeDataProvider(Object instance, Method dataProvider, ITestNGMethod method, ITestContext testContext, Object fedInstance, IAnnotationFinder annotationFinder) { List parameters = getParameters(dataProvider, method, testContext, fedInstance, annotationFinder); Class returnType = dataProvider.getReturnType(); // If it returns an Object[][], convert it to an Iterable if (Object[][].class.isAssignableFrom(returnType)) { Object[][] result = (Object[][]) invokeMethodNoCheckedException(dataProvider, instance, parameters); return new ArrayIterator(result); } else if (Iterator.class.isAssignableFrom(returnType)) { return (Iterator) invokeMethodNoCheckedException(dataProvider, instance, parameters); } else { throw new TestNGException("Data Provider " + dataProvider + " must return" + " either Object[][] or Iterator[], not " + returnType); } } private static List getParameters(Method dataProvider, ITestNGMethod method, ITestContext testContext, Object fedInstance, IAnnotationFinder annotationFinder) { // Go through all the parameters declared on this Data Provider and // make sure we have at most one Method and one ITestContext. // Anything else is an error List parameters = new ArrayList<>(); Collection>> unresolved = new ArrayList<>(); ConstructorOrMethod com = method.getConstructorOrMethod(); int i = 0; for (Class cls : dataProvider.getParameterTypes()) { if (cls.equals(Method.class)) { parameters.add(com.getMethod()); } else if (cls.equals(Constructor.class)) { parameters.add(com.getConstructor()); } else if (cls.equals(ConstructorOrMethod.class)) { parameters.add(com); } else if (cls.equals(ITestNGMethod.class)) { parameters.add(method); } else if (cls.equals(ITestContext.class)) { parameters.add(testContext); } else { boolean isTestInstance = annotationFinder.hasTestInstance(dataProvider, i); if (isTestInstance) { parameters.add(fedInstance); } else { unresolved.add(new Pair>(i, cls)); } } i++; } if (!unresolved.isEmpty()) { StringBuilder sb = new StringBuilder(); sb.append("Some DataProvider ").append(dataProvider).append(" parameters unresolved: "); for (Pair> pair : unresolved) { sb.append(" at ").append(pair.first()).append(" type ").append(pair.second()).append("\n"); } throw new TestNGException(sb.toString()); } return parameters; } /** * Invokes the run method of the IHookable. * * @param testInstance * the instance to invoke the method in * @param parameters * the parameters to be passed to IHookCallBack * @param thisMethod * the method to be invoked through the IHookCallBack * @param testResult * the current ITestResult passed to * IHookable.run * @throws NoSuchMethodException * @throws IllegalAccessException * @throws InvocationTargetException * @throws Throwable * thrown if the reflective call to * thisMethod results in an exception */ protected static void invokeHookable(final Object testInstance, final Object[] parameters, final IHookable hookable, final Method thisMethod, final ITestResult testResult) throws Throwable { final Throwable[] error = new Throwable[1]; IHookCallBack callback = new IHookCallBack() { @Override public void runTestMethod(ITestResult tr) { try { invokeMethod(thisMethod, testInstance, parameters); } catch (Throwable t) { error[0] = t; tr.setThrowable(t); // make Throwable available to IHookable } } @Override public Object[] getParameters() { return parameters; } }; hookable.run(callback, testResult); if (error[0] != null) { throw error[0]; } } /** * Invokes a method on a separate thread in order to allow us to timeout the * invocation. It uses as implementation an Executor and a * CountDownLatch. */ protected static void invokeWithTimeout(ITestNGMethod tm, Object instance, Object[] parameterValues, ITestResult testResult) throws InterruptedException, ThreadExecutionException { invokeWithTimeout(tm, instance, parameterValues, testResult, null); } protected static void invokeWithTimeout(ITestNGMethod tm, Object instance, Object[] parameterValues, ITestResult testResult, IHookable hookable) throws InterruptedException, ThreadExecutionException { if (ThreadUtil.isTestNGThread() && testResult.getTestContext().getCurrentXmlTest().getParallel() != XmlSuite.ParallelMode.TESTS) { // We are already running in our own executor, don't create another one (or we will // lose the time out of the enclosing executor). invokeWithTimeoutWithNoExecutor(tm, instance, parameterValues, testResult, hookable); } else { invokeWithTimeoutWithNewExecutor(tm, instance, parameterValues, testResult, hookable); } } private static void invokeWithTimeoutWithNoExecutor(ITestNGMethod tm, Object instance, Object[] parameterValues, ITestResult testResult, IHookable hookable) { InvokeMethodRunnable imr = new InvokeMethodRunnable(tm, instance, parameterValues, hookable, testResult); try { imr.run(); testResult.setStatus(ITestResult.SUCCESS); } catch (Exception ex) { testResult.setThrowable(ex.getCause()); testResult.setStatus(ITestResult.FAILURE); } } private static void invokeWithTimeoutWithNewExecutor(ITestNGMethod tm, Object instance, Object[] parameterValues, ITestResult testResult, IHookable hookable) throws InterruptedException, ThreadExecutionException { IExecutor exec = ThreadUtil.createExecutor(1, tm.getMethodName()); InvokeMethodRunnable imr = new InvokeMethodRunnable(tm, instance, parameterValues, hookable, testResult); IFutureResult future = exec.submitRunnable(imr); exec.shutdown(); long realTimeOut = MethodHelper.calculateTimeOut(tm); boolean finished = exec.awaitTermination(realTimeOut); if (!finished) { exec.stopNow(); ThreadTimeoutException exception = new ThreadTimeoutException("Method " + tm.getClass().getName() + "." + tm.getMethodName() + "()" + " didn't finish within the time-out " + realTimeOut); exception.setStackTrace(exec.getStackTraces()[0]); testResult.setThrowable(exception); testResult.setStatus(ITestResult.FAILURE); } else { Utils.log("Invoker " + Thread.currentThread().hashCode(), 3, "Method " + tm.getMethodName() + " completed within the time-out " + tm.getTimeOut()); // We don't need the result from the future but invoking get() on it // will trigger the exception that was thrown, if any future.get(); // done.await(); testResult.setStatus(ITestResult.SUCCESS); // if no exception till here // than SUCCESS } } protected static void invokeConfigurable(final Object instance, final Object[] parameters, final IConfigurable configurableInstance, final Method thisMethod, final ITestResult testResult) throws Throwable { final Throwable[] error = new Throwable[1]; IConfigureCallBack callback = new IConfigureCallBack() { @Override public void runConfigurationMethod(ITestResult tr) { try { invokeMethod(thisMethod, instance, parameters); } catch (Throwable t) { error[0] = t; tr.setThrowable(t); // make Throwable available to IConfigurable } } @Override public Object[] getParameters() { return parameters; } }; configurableInstance.run(callback, testResult); if (error[0] != null) { throw error[0]; } } } testng-6.9.12/src/main/java/org/testng/internal/TestNGClassFinder.java0000644000175000017500000002215012732165123025111 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import java.util.Map; import java.util.Set; import org.testng.IClass; import org.testng.IInstanceInfo; import org.testng.ITestContext; import org.testng.ITestObjectFactory; import org.testng.TestNGException; import org.testng.annotations.IAnnotation; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlClass; import org.testng.xml.XmlTest; import static org.testng.internal.ClassHelper.getAvailableMethods; /** * This class creates an ITestClass from a test class. * * @author Cedric Beust */ public class TestNGClassFinder extends BaseClassFinder { private ITestContext m_testContext = null; private Map> m_instanceMap = Maps.newHashMap(); public TestNGClassFinder(ClassInfoMap cim, Map> instanceMap, XmlTest xmlTest, IConfiguration configuration, ITestContext testContext) { m_testContext = testContext; if(null == instanceMap) { instanceMap= Maps.newHashMap(); } IAnnotationFinder annotationFinder = configuration.getAnnotationFinder(); ITestObjectFactory objectFactory = configuration.getObjectFactory(); // // Find all the new classes and their corresponding instances // Set> allClasses= cim.getClasses(); //very first pass is to find ObjectFactory, can't create anything else until then if(objectFactory == null) { objectFactory = new ObjectFactoryImpl(); outer: for (Class cls : allClasses) { try { if (null != cls) { Method[] ms; try { ms = cls.getMethods(); } catch (NoClassDefFoundError e) { // https://github.com/cbeust/testng/issues/602 ppp("Warning: Can't link and determine methods of " + cls); ms = new Method[0]; } for (Method m : ms) { IAnnotation a = annotationFinder.findAnnotation(m, org.testng.annotations.IObjectFactoryAnnotation.class); if (null != a) { if (!ITestObjectFactory.class.isAssignableFrom(m.getReturnType())) { throw new TestNGException("Return type of " + m + " is not IObjectFactory"); } try { Object instance = cls.newInstance(); if (m.getParameterTypes().length > 0 && m.getParameterTypes()[0].equals(ITestContext.class)) { objectFactory = (ITestObjectFactory) m.invoke(instance, testContext); } else { objectFactory = (ITestObjectFactory) m.invoke(instance); } break outer; } catch (Exception ex) { throw new TestNGException("Error creating object factory: " + cls, ex); } } } } } catch (NoClassDefFoundError e) { Utils.log("[TestNGClassFinder]", 1, "Unable to read methods on class " + cls.getName() + " - unable to resolve class reference " + e.getMessage()); for (XmlClass xmlClass : xmlTest.getXmlClasses()) { if (xmlClass.loadClasses() && xmlClass.getName().equals(cls.getName())) { throw e; } } } } } for(Class cls : allClasses) { if((null == cls)) { ppp("FOUND NULL CLASS IN FOLLOWING ARRAY:"); int i= 0; for(Class c : allClasses) { ppp(" " + i + ": " + c); } continue; } if(isTestNGClass(cls, annotationFinder)) { List allInstances= instanceMap.get(cls); Object thisInstance= (null != allInstances) ? allInstances.get(0) : null; // If annotation class and instances are abstract, skip them if ((null == thisInstance) && Modifier.isAbstract(cls.getModifiers())) { Utils.log("", 5, "[WARN] Found an abstract class with no valid instance attached: " + cls); continue; } IClass ic= findOrCreateIClass(m_testContext, cls, cim.getXmlClass(cls), thisInstance, xmlTest, annotationFinder, objectFactory); if(null != ic) { Object[] theseInstances = ic.getInstances(false); if (theseInstances.length == 0) { theseInstances = ic.getInstances(true); } Object instance = null; if (theseInstances.length != 0) { instance = theseInstances[0]; } putIClass(cls, ic); ConstructorOrMethod factoryMethod = ClassHelper.findDeclaredFactoryMethod(cls, annotationFinder); if (factoryMethod != null && factoryMethod.getEnabled()) { FactoryMethod fm = new FactoryMethod( /* cls, */ factoryMethod, instance, xmlTest, annotationFinder, m_testContext); ClassInfoMap moreClasses = new ClassInfoMap(); // // If the factory returned IInstanceInfo, get the class from it, // otherwise, just call getClass() on the returned instances // int i = 0; for (Object o : fm.invoke()) { if (o == null) { throw new TestNGException("The factory " + fm + " returned a null instance" + "at index " + i); } Class oneMoreClass; if(IInstanceInfo.class.isAssignableFrom(o.getClass())) { IInstanceInfo ii = (IInstanceInfo) o; addInstance(ii); oneMoreClass = ii.getInstanceClass(); } else { addInstance(o); oneMoreClass = o.getClass(); } if(!classExists(oneMoreClass)) { moreClasses.addClass(oneMoreClass); } i++; } if(moreClasses.getSize() > 0) { TestNGClassFinder finder= new TestNGClassFinder(moreClasses, m_instanceMap, xmlTest, configuration, m_testContext); IClass[] moreIClasses= finder.findTestClasses(); for(IClass ic2 : moreIClasses) { putIClass(ic2.getRealClass(), ic2); } } // if moreClasses.size() > 0 } } // null != ic } // if not TestNG class else { Utils.log("TestNGClassFinder", 3, "SKIPPING CLASS " + cls + " no TestNG annotations found"); } } // for // // Add all the instances we found to their respective IClasses // for(Map.Entry> entry : m_instanceMap.entrySet()) { Class clazz = entry.getKey(); for(Object instance : entry.getValue()) { IClass ic= getIClass(clazz); if(null != ic) { ic.addInstance(instance); } } } } /** * @return true if this class contains TestNG annotations (either on itself * or on a superclass). */ public static boolean isTestNGClass(Class c, IAnnotationFinder annotationFinder) { Class[] allAnnotations= AnnotationHelper.getAllAnnotations(); Class cls = c; try { for(Class annotation : allAnnotations) { for (cls = c; cls != null; cls = cls.getSuperclass()) { // Try on the methods for (Method m : getAvailableMethods(cls)) { IAnnotation ma= annotationFinder.findAnnotation(m, annotation); if(null != ma) { return true; } } // Try on the class IAnnotation a= annotationFinder.findAnnotation(cls, annotation); if(null != a) { return true; } // Try on the constructors for (Constructor ctor : cls.getConstructors()) { IAnnotation ca= annotationFinder.findAnnotation(ctor, annotation); if(null != ca) { return true; } } } } return false; } catch (NoClassDefFoundError e) { Utils.log("[TestNGClassFinder]", 1, "Unable to read methods on class " + cls.getName() + " - unable to resolve class reference " + e.getMessage()); return false; } } private void addInstance(IInstanceInfo ii) { addInstance(ii.getInstanceClass(), ii.getInstance()); } private void addInstance(T o) { addInstance(o.getClass(), o); } private void addInstance(Class clazz, T o) { List list= m_instanceMap.get(clazz); if(null == list) { list= Lists.newArrayList(); m_instanceMap.put(clazz, list); } list.add(o); } public static void ppp(String s) { System.out.println("[TestNGClassFinder] " + s); } } testng-6.9.12/src/main/java/org/testng/internal/RunInfo.java0000755000175000017500000000442312732165123023215 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IMethodSelector; import org.testng.IMethodSelectorContext; import org.testng.ITestNGMethod; import org.testng.collections.Lists; import java.io.Serializable; import java.util.Collections; import java.util.List; /** * This class contains all the information needed to determine * what methods should be run. It gets invoked by the TestRunner * and then goes through its list of method selectors to decide what methods * need to be run. * * @author Cedric Beust */ public class RunInfo implements Serializable { private static final long serialVersionUID = -9085221672822562888L; transient private List m_methodSelectors = Lists.newArrayList(); public void addMethodSelector(IMethodSelector selector, int priority) { Utils.log("RunInfo", 3, "Adding method selector: " + selector + " priority: " + priority); MethodSelectorDescriptor md = new MethodSelectorDescriptor(selector, priority); m_methodSelectors.add(md); } /** * @return true as soon as we fond a Method Selector that returns * true for the method "tm". */ public boolean includeMethod(ITestNGMethod tm, boolean isTestMethod) { Collections.sort(m_methodSelectors); boolean foundNegative = false; IMethodSelectorContext context = new DefaultMethodSelectorContext(); boolean result = false; for (MethodSelectorDescriptor mds : m_methodSelectors) { // If we found any negative priority, we break as soon as we encounter // a selector with a positive priority if (! foundNegative) { foundNegative = mds.getPriority() < 0; } if (foundNegative && mds.getPriority() >= 0) { break; } // Proceeed normally IMethodSelector md = mds.getMethodSelector(); result = md.includeMethod(context, tm, isTestMethod); if (context.isStopped()) { return result; } // This selector returned false, move on to the next } return result; } public static void ppp(String s) { System.out.println("[RunInfo] " + s); } public void setTestMethods(List testMethods) { for (MethodSelectorDescriptor mds : m_methodSelectors) { mds.setTestMethods(testMethods); } } } testng-6.9.12/src/main/java/org/testng/internal/Dynamic.java0000644000175000017500000000045612732165123023220 0ustar eugeneeugenepackage org.testng.internal; /** * Determine the availability of certain jar files at runtime. */ public class Dynamic { public static boolean hasBsh() { try { Class.forName("bsh.Interpreter"); return true; } catch (ClassNotFoundException e) { return false; } } } testng-6.9.12/src/main/java/org/testng/internal/Constants.java0000755000175000017500000000604712732165123023615 0ustar eugeneeugenepackage org.testng.internal; import java.util.Map; import java.util.Properties; import org.testng.ITestResult; import org.testng.collections.Maps; /** * Constants used by TestNG * * @author Cedric Beust, May 2, 2004 * */ public class Constants { private static final String NAMESPACE = "testng"; //////// // // Properties // public static final String PROP_OUTPUT_DIR = NAMESPACE + "." + "outputDir"; // public static final String PROP_NAME = NAMESPACE + "." + "name"; // public static final String PROP_INCLUDED_GROUPS = NAMESPACE + "." + "includedGroups"; // public static final String PROP_EXCLUDED_GROUPS = NAMESPACE + "." + "excludedGroups"; // public static final String PROP_CLASS_NAMES = NAMESPACE + "." + "classNames"; // public static final String PROP_VERBOSE = NAMESPACE + "." + "verbose"; // public static final String PROP_JUNIT= NAMESPACE + "." + "junit"; // public static final String PROP_QUIET= NAMESPACE + "." + "quiet"; // public static final String PROP_GROUP= NAMESPACE + "." + "group"; private static final TestNGProperty[] COMMAND_LINE_PARAMETERS = { new TestNGProperty("-d", PROP_OUTPUT_DIR, "Directory where the result files will be created.", "test-output"), }; private static final Map m_propertiesByName = Maps.newHashMap(); static { // for (int i = 0; i < PROPERTIES.length; i++) { // m_propertiesByName.put(PROPERTIES[i].getName(), PROPERTIES[i]); // } for (TestNGProperty element : COMMAND_LINE_PARAMETERS) { m_propertiesByName.put(element.getName(), element); } } private static TestNGProperty getProperty(String propertyName) { TestNGProperty result = m_propertiesByName.get(propertyName); assert null != result : "Unknown property : " + propertyName; return result; } public static String getPropertyValue(Properties p, String propertyName) { TestNGProperty r= getProperty(propertyName); assert null != r : "Unknown property : " + propertyName; String result = p.getProperty(r.getName()); return result; } public static boolean getBooleanPropertyValue(Properties properties, String propertyName) { TestNGProperty p = getProperty(propertyName); String r = properties.getProperty(propertyName, p.getDefault()); boolean result = "true".equalsIgnoreCase(r); return Boolean.valueOf(result); } public static int getIntegerPropertyValue(Properties properties, String propertyName) { TestNGProperty p = getProperty(propertyName); String r = properties.getProperty(propertyName, p.getDefault()); int result = Integer.parseInt(r); return result; } public static String getDefaultValueFor(String propertyName) { TestNGProperty p = getProperty(propertyName); return p.getDefault(); } public static String displayStatus(int status) { if (ITestResult.SKIP == status) { return "SKIP"; } else if (ITestResult.SUCCESS == status) { return "SUCCESS"; } else if (ITestResult.FAILURE == status) { return "FAILURE"; } else { return "UNKNOWN_STATUS"; } } } testng-6.9.12/src/main/java/org/testng/internal/Bsh.java0000644000175000017500000000354612732165123022353 0ustar eugeneeugenepackage org.testng.internal; import bsh.EvalError; import bsh.Interpreter; import org.testng.ITestNGMethod; import org.testng.TestNGException; import org.testng.collections.Maps; import java.lang.reflect.Method; import java.util.Map; public class Bsh implements IBsh { private static Interpreter s_interpreter; @Override public boolean includeMethodFromExpression(String expression, ITestNGMethod tm) { boolean result = false; Interpreter interpreter = getInterpreter(); try { Map groups = Maps.newHashMap(); for (String group : tm.getGroups()) { groups.put(group, group); } setContext(interpreter, tm.getMethod(), groups, tm); Object evalResult = interpreter.eval(expression); result = (Boolean) evalResult; } catch (EvalError evalError) { Utils.log("bsh.Interpreter", 2, "Cannot evaluate expression:" + expression + ":" + evalError.getMessage()); } finally { resetContext(interpreter); } return result; } private static Interpreter getInterpreter() { if(null == s_interpreter) { s_interpreter= new Interpreter(); } return s_interpreter; } private void setContext(Interpreter interpreter, Method method, Map groups, ITestNGMethod tm) { try { interpreter.set("method", method); interpreter.set("groups", groups); interpreter.set("testngMethod", tm); } catch(EvalError evalError) { throw new TestNGException("Cannot set BSH interpreter", evalError); } } private void resetContext(Interpreter interpreter) { try { interpreter.unset("method"); interpreter.unset("groups"); interpreter.unset("testngMethod"); } catch(EvalError evalError) { Utils.log("bsh.Interpreter", 2, "Cannot reset interpreter:" + evalError.getMessage()); } } } testng-6.9.12/src/main/java/org/testng/internal/PoolService.java0000755000175000017500000000331512732165123024066 0ustar eugeneeugenepackage org.testng.internal; import org.testng.TestNGException; import org.testng.collections.Lists; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; /** * Simple wrapper for an ExecutorCompletionService. */ public class PoolService { private ExecutorCompletionService m_completionService; private ThreadFactory m_threadFactory; private ExecutorService m_executor; public PoolService(int threadPoolSize) { m_threadFactory = new ThreadFactory() { private int m_threadIndex = 0; @Override public Thread newThread(Runnable r) { Thread result = new Thread(r); result.setName("PoolService-" + m_threadIndex); m_threadIndex++; return result; } }; m_executor = Executors.newFixedThreadPool(threadPoolSize, m_threadFactory); m_completionService = new ExecutorCompletionService<>(m_executor); } public List submitTasksAndWait(List> tasks) { List result = Lists.newArrayList(); for (Callable callable : tasks) { m_completionService.submit(callable); } for (int i = 0; i < tasks.size(); i++) { try { Future take = m_completionService.take(); result.add(take.get()); } catch (InterruptedException | ExecutionException e) { throw new TestNGException(e); } } m_executor.shutdown(); return result; } } testng-6.9.12/src/main/java/org/testng/internal/Utils.java0000644000175000017500000006154012732165123022735 0ustar eugeneeugenepackage org.testng.internal; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.testng.ITestNGMethod; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.TestRunner; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Lists; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.log.TextFormatter; import org.testng.reporters.XMLStringBuffer; import org.testng.xml.XmlClass; /** * Helper methods to parse annotations. * * @author Cedric Beust, Apr 26, 2004 */ public final class Utils { private static final String LINE_SEP = System.getProperty("line.separator"); public static final char[] SPECIAL_CHARACTERS = {'*','/','\\','?','%',':',';','<','>','&','~','|'}; public static final char CHAR_REPLACEMENT = '_'; public static final char UNICODE_REPLACEMENT = 0xFFFD; /** * Hide constructor for utility class. */ private Utils() { // Hide constructor } /** * Splits the given String s into tokens where the separator is * either the space character or the comma character. For example, * if s is "a,b, c" this method returns {"a", "b", "c"} * * @param s the string to split * @return the split token */ public static String[] stringToArray(String s) { // TODO CQ would s.split() be a better way of doing this? StringTokenizer st = new StringTokenizer(s, " ,"); String[] result = new String[st.countTokens()]; for (int i = 0; i < result.length; i++) { result[i] = st.nextToken(); } return result; } public static XmlClass[] classesToXmlClasses(Class[] classes) { List result = Lists.newArrayList(); for (Class cls : classes) { result.add(new XmlClass(cls, true /* load classes */)); } return result.toArray(new XmlClass[classes.length]); } public static String[] parseMultiLine(String line) { List vResult = Lists.newArrayList(); if (isStringNotBlank(line)) { StringTokenizer st = new StringTokenizer(line, " "); while (st.hasMoreTokens()) { vResult.add(st.nextToken()); } // Bug in split when passed " " : returns one too many result // result = line.split(" "); } return vResult.toArray(new String[vResult.size()]); } public static void writeUtf8File(@Nullable String outputDir, String fileName, XMLStringBuffer xsb, String prefix) { try { final File outDir = (outputDir != null) ? new File(outputDir) : new File("").getAbsoluteFile(); if (!outDir.exists()) { outDir.mkdirs(); } final File file = new File(outDir, fileName); if (!file.exists()) { file.createNewFile(); } final OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); if (prefix != null) { w.append(prefix); } xsb.toWriter(w); w.close(); } catch(IOException ex) { ex.printStackTrace(); } } /** * Writes the content of the sb string to the file named filename in outDir encoding the output as UTF-8. * If outDir does not exist, it is created. * * @param outputDir the output directory (may not exist). If null then current directory is used. * @param fileName the filename * @param sb the file content */ public static void writeUtf8File(@Nullable String outputDir, String fileName, String sb) { final String outDirPath= outputDir != null ? outputDir : ""; final File outDir= new File(outDirPath); writeFile(outDir, fileName, escapeUnicode(sb), "UTF-8", false /* don't append */); } /** * Writes the content of the sb string to the file named filename in outDir. If * outDir does not exist, it is created. * * @param outputDir the output directory (may not exist). If null then current directory is used. * @param fileName the filename * @param sb the file content */ public static void writeFile(@Nullable String outputDir, String fileName, String sb) { final String outDirPath= outputDir != null ? outputDir : ""; final File outDir= new File(outDirPath); writeFile(outDir, fileName, sb, null, false /* don't append */); } /** * Writes the content of the sb string to the file named filename in outDir. If * outDir does not exist, it is created. * * @param outDir the output directory (may not exist). If null then current directory is used. * @param fileName the filename * @param sb the file content */ private static void writeFile(@Nullable File outDir, String fileName, String sb, @Nullable String encoding, boolean append) { try { if (outDir == null) { outDir = new File("").getAbsoluteFile(); } if (!outDir.exists()) { outDir.mkdirs(); } fileName = replaceSpecialCharacters(fileName); File outputFile = new File(outDir, fileName); if (!append) { outputFile.delete(); log("Attempting to create " + outputFile); log(" Directory " + outDir + " exists: " + outDir.exists()); outputFile.createNewFile(); } writeFile(outputFile, sb, encoding, append); } catch (IOException e) { if (TestRunner.getVerbose() > 1) { e.printStackTrace(); } else { log("[Utils]", 1, e.getMessage()); } } } private static void writeFile(File outputFile, String sb, @Nullable String encoding, boolean append) { BufferedWriter fw = null; try { fw = openWriter(outputFile, encoding, append); fw.write(sb); Utils.log("", 3, "Creating " + outputFile.getAbsolutePath()); } catch(IOException ex) { if (TestRunner.getVerbose() > 1) { System.err.println("ERROR WHILE WRITING TO " + outputFile); ex.printStackTrace(); } else { log("[Utils]", 1, "Error while writing to " + outputFile + ": " + ex.getMessage()); } } finally { try { if (fw != null) { fw.close(); } } catch (IOException e) { // ignore } } } /** * Open a BufferedWriter for the specified file. If output directory doesn't * exist, it is created. If the output file exists, it is deleted. The output file is * created in any case. * @param outputDir output directory. If null, then current directory is used * @param fileName file name * @throws IOException if anything goes wrong while creating files. */ public static BufferedWriter openWriter(@Nullable String outputDir, String fileName) throws IOException { String outDirPath= outputDir != null ? outputDir : ""; File outDir= new File(outDirPath); if (!outDir.exists()) { outDir.mkdirs(); } fileName = replaceSpecialCharacters(fileName); File outputFile = new File(outDir, fileName); outputFile.delete(); return openWriter(outputFile, null, false); } private static BufferedWriter openWriter(File outputFile, @Nullable String encoding, boolean append) throws IOException { if (!outputFile.exists()) { outputFile.createNewFile(); } OutputStreamWriter osw= null; if (null != encoding) { osw = new OutputStreamWriter(new FileOutputStream(outputFile, append), encoding); } else { osw = new OutputStreamWriter(new FileOutputStream(outputFile, append)); } return new BufferedWriter(osw); } private static void ppp(String s) { Utils.log("Utils", 0, s); } /** * @param result */ public static void dumpMap(Map result) { System.out.println("vvvvv"); for (Map.Entry entry : result.entrySet()) { System.out.println(entry.getKey() + " => " + entry.getValue()); } System.out.println("^^^^^"); } /** * @param allMethods */ public static void dumpMethods(List allMethods) { ppp("======== METHODS:"); for (ITestNGMethod tm : allMethods) { ppp(" " + tm); } } /** * @return The list of dependent groups for this method, including the * class groups */ public static String[] dependentGroupsForThisMethodForTest(Method m, IAnnotationFinder finder) { List vResult = Lists.newArrayList(); Class cls = m.getDeclaringClass(); // Collect groups on the class ITestAnnotation tc = AnnotationHelper.findTest(finder, cls); if (null != tc) { for (String group : tc.getDependsOnGroups()) { vResult.add(group); } } // Collect groups on the method ITestAnnotation tm = AnnotationHelper.findTest(finder, m); if (null != tm) { String[] groups = tm.getDependsOnGroups(); // ppp("Method:" + m + " #Groups:" + groups.length); for (String group : groups) { vResult.add(group); } } return vResult.toArray(new String[vResult.size()]); } /** * @return The list of groups this method belongs to, including the * class groups */ public static String[] groupsForThisMethodForTest(Method m, IAnnotationFinder finder) { List vResult = Lists.newArrayList(); Class cls = m.getDeclaringClass(); // Collect groups on the class ITestAnnotation tc = AnnotationHelper.findTest(finder, cls); if (null != tc) { for (String group : tc.getGroups()) { vResult.add(group); } } // Collect groups on the method ITestAnnotation tm = AnnotationHelper.findTest(finder, m); if (null != tm) { String[] groups = tm.getGroups(); // ppp("Method:" + m + " #Groups:" + groups.length); for (String group : groups) { vResult.add(group); } } return vResult.toArray(new String[vResult.size()]); } /** * @return The list of groups this method belongs to, including the * class groups */ public static String[] groupsForThisMethodForConfiguration(Method m, IAnnotationFinder finder) { String[] result = {}; // Collect groups on the method ITestAnnotation tm = AnnotationHelper.findTest(finder, m); if (null != tm) { result = tm.getGroups(); } return result; } /** * @return The list of groups this method depends on, including the * class groups */ public static String[] dependentGroupsForThisMethodForConfiguration(Method m, IAnnotationFinder finder) { String[] result = {}; // Collect groups on the method IConfigurationAnnotation tm = AnnotationHelper.findConfiguration(finder, m); if (null != tm) { result = tm.getDependsOnGroups(); } return result; } public static void log(String msg) { log("Utils", 2, msg); } /** * Logs the the message to System.out if level is greater than * or equal to TestRunner.getVerbose(). The message is logged as: *
   *     "[cls] msg"
   * 
* * @param cls the class name to prefix the log message. * @param level the logging level of the message. * @param msg the message to log to System.out. */ public static void log(String cls, int level, String msg) { // Why this coupling on a static member of TestRunner.getVerbose()? if (TestRunner.getVerbose() >= level) { if (cls.length() > 0) { System.out.println("[" + cls + "] " + msg); } else { System.out.println(msg); } } } public static void error(String errorMessage) { System.err.println("[Error] " + errorMessage); } /** * @return The number of methods invoked, taking into account the number * of instances. */ // public static int calculateInvokedMethodCount(IResultMap map) { // return calculateInvokedMethodCount( // (ITestNGMethod[]) map.getAllMethods().toArray(new ITestNGMethod[map.size()])); // } public static int calculateInvokedMethodCount(ITestNGMethod[] methods) { return methods.length; // int result = 0; // // for (ITestNGMethod method : methods) { // int instanceCount = method.getInvocationCount(); // result += instanceCount; // } // // return result; } // public static int calculateInvokedMethodCount(Map methods) { // return calculateInvokedMethodCount(methods.keySet().toArray(new ITestNGMethod[methods.values() // .size()])); // } /** * Tokenize the string using the separator. */ public static String[] split(String string, String sep) { if ((string == null) || (string.length() == 0)) { return new String[0]; } // TODO How different is this from: // return string.split(sep); int start = 0; int idx = string.indexOf(sep, start); int len = sep.length(); List strings = Lists.newArrayList(); while (idx != -1) { strings.add(string.substring(start, idx).trim()); start = idx + len; idx = string.indexOf(sep, start); } strings.add(string.substring(start).trim()); return strings.toArray(new String[strings.size()]); } public static void logInvocation(String reason, Method thisMethod, Object[] parameters) { String clsName = thisMethod.getDeclaringClass().getName(); int n = clsName.lastIndexOf("."); if (n >= 0) { clsName = clsName.substring(n + 1); } String methodName = clsName + '.' + thisMethod.getName(); if (TestRunner.getVerbose() >= 2) { StringBuffer paramString = new StringBuffer(); if (parameters != null) { for (Object p : parameters) { paramString.append(p.toString()).append(' '); } } log("", 2, "Invoking " + reason + methodName + '(' + paramString + ')'); } } public static void writeResourceToFile(File file, String resourceName, Class clasz) throws IOException { InputStream inputStream = clasz.getResourceAsStream("/" + resourceName); if (inputStream == null) { System.err.println("Couldn't find resource on the class path: " + resourceName); // throw new IllegalArgumentException("Resource does not exist: " + resourceName); } else { try { FileOutputStream outputStream = new FileOutputStream(file); try { int nread; byte[] buffer = new byte[4096]; while (0 < (nread = inputStream.read(buffer))) { outputStream.write(buffer, 0, nread); } } finally { outputStream.close(); } } finally { inputStream.close(); } } } public static String defaultIfStringEmpty(String s, String defaultValue) { return isStringEmpty(s) ? defaultValue : s; } public static boolean isStringBlank(String s) { return s == null || "".equals(s.trim()); } public static boolean isStringEmpty(String s) { return s == null || "".equals(s); } public static boolean isStringNotBlank(String s) { return !isStringBlank(s); } public static boolean isStringNotEmpty(String s) { return !isStringEmpty(s); } /** * @return an array of two strings: the short stack trace and the long stack trace. */ public static String[] stackTrace(Throwable t, boolean toHtml) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); pw.flush(); String fullStackTrace = sw.getBuffer().toString(); String shortStackTrace; if (Boolean.getBoolean(TestNG.SHOW_TESTNG_STACK_FRAMES) || TestRunner.getVerbose() >= 2) { shortStackTrace = fullStackTrace; } else { shortStackTrace = filterTrace(sw.getBuffer().toString()); } if (toHtml) { shortStackTrace = escapeHtml(shortStackTrace); fullStackTrace = escapeHtml(fullStackTrace); } return new String[] { shortStackTrace, fullStackTrace }; } private static final Map ESCAPES = new HashMap() { private static final long serialVersionUID = 1285607660247157523L; { put('<', "<"); put('>', ">"); put('\'', "'"); put('"', """); put('&', "&"); }}; public static String escapeHtml(String s) { if (s == null) { return null; } StringBuilder result = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); String nc = ESCAPES.get(c); if (nc != null) { result.append(nc); } else { result.append(c); } } return result.toString(); } public static String escapeUnicode(String s) { if (s == null) { return null; } StringBuilder result = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); char ca = (Character.isDefined(c)) ? c: UNICODE_REPLACEMENT; result.append(ca); } return result.toString(); } private static String filterTrace(String trace) { StringReader stringReader = new StringReader(trace); BufferedReader bufferedReader = new BufferedReader(stringReader); StringBuffer buf = new StringBuffer(); try { // first line contains the thrown exception String line = bufferedReader.readLine(); if(line == null) { return ""; } buf.append(line).append(LINE_SEP); // // the stack frames of the trace // String[] excludedStrings = new String[] { "org.testng", "reflect", "org.apache.maven.surefire" }; int excludedCount = 0; while((line = bufferedReader.readLine()) != null) { boolean isExcluded = false; for (String excluded : excludedStrings) { if(line.contains(excluded)) { isExcluded = true; excludedCount++; break; } } if (! isExcluded) { buf.append(line).append(LINE_SEP); } } if (excludedCount > 0) { buf.append("... Removed " + excludedCount + " stack frames"); } } catch(IOException ioex) { // do nothing } return buf.toString(); } public static String toString(Object object, Class objectClass) { if(null == object) { return "null"; } final String toString= object.toString(); if(isStringEmpty(toString)) { return "\"\""; } else if (String.class.equals(objectClass)) { return "\"" + toString + '\"'; } else { return toString; } } public static String detailedMethodName(ITestNGMethod method, boolean fqn) { StringBuffer buf= new StringBuffer(); if(method.isBeforeSuiteConfiguration()) { buf.append("@BeforeSuite "); } else if(method.isBeforeTestConfiguration()) { buf.append("@BeforeTest "); } else if(method.isBeforeClassConfiguration()) { buf.append("@BeforeClass "); } else if(method.isBeforeGroupsConfiguration()) { buf.append("@BeforeGroups "); } else if(method.isBeforeMethodConfiguration()) { buf.append("@BeforeMethod "); } else if(method.isAfterMethodConfiguration()) { buf.append("@AfterMethod "); } else if(method.isAfterGroupsConfiguration()) { buf.append("@AfterGroups "); } else if(method.isAfterClassConfiguration()) { buf.append("@AfterClass "); } else if(method.isAfterTestConfiguration()) { buf.append("@AfterTest "); } else if(method.isAfterSuiteConfiguration()) { buf.append("@AfterSuite "); } return buf.append(fqn ? method.toString() : method.getMethodName()).toString(); } public static String arrayToString(String[] strings) { StringBuffer result = new StringBuffer(""); if ((strings != null) && (strings.length > 0)) { for (int i = 0; i < strings.length; i++) { result.append(strings[i]); if (i < strings.length - 1) { result.append(", "); } } } return result.toString(); } /** * If the file name contains special characters like *,/,\ and so on, * exception will be thrown and report file will not be created.
* Special characters are platform specific and they are not same for * example on Windows and Macintosh. * is not allowed on Windows, but it is on Macintosh.
* In order to have the same behavior of testng on the all platforms, characters like * will * be replaced on all platforms whether they are causing the problem or not. * * @param fileName file name that could contain special characters. * @return fileName with special characters replaced * @author Borojevic */ public static String replaceSpecialCharacters(String fileName) { if (fileName == null || fileName.length() == 0) { return fileName; } for (char element : SPECIAL_CHARACTERS) { fileName = fileName.replace(element, CHAR_REPLACEMENT); } return fileName; } public static String join(List objects, String separator) { StringBuilder result = new StringBuilder(); for (int i = 0; i < objects.size(); i++) { if (i > 0) { result.append(separator); } result.append(objects.get(i).toString()); } return result.toString(); } public static void copyFile(File from, File to) { to.getParentFile().mkdirs(); try (InputStream in = new FileInputStream(from); OutputStream out = new FileOutputStream(to)) { byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } catch(IOException e){ e.printStackTrace(); } } /** * @return a temporary file with the given content. */ public static File createTempFile(String content) { try { // Create temp file. File result = File.createTempFile("testng-tmp", ""); // Delete temp file when program exits. result.deleteOnExit(); // Write to temp file BufferedWriter out = new BufferedWriter(new FileWriter(result)); out.write(content); out.close(); return result; } catch (IOException e) { throw new TestNGException(e); } } /** * Make sure that either we have an instance or if not, that the method is static */ public static void checkInstanceOrStatic(Object instance, Method method) { if (instance == null && method != null && ! Modifier.isStatic(method.getModifiers())) { throw new TestNGException("Can't invoke " + method + ": either make it static or add " + "a no-args constructor to your class"); } } public static void checkReturnType(Method method, Class... returnTypes) { if (method == null) { return; } for (Class returnType : returnTypes) { if (method.getReturnType() == returnType) { return; } } throw new TestNGException(method.getDeclaringClass().getName() + "." + method.getName() + " MUST return " + toString(returnTypes) + " but returns " + method.getReturnType().getName()); } private static String toString(Class[] classes) { StringBuilder sb = new StringBuilder("[ "); for (int i=0; i clazz = classes[i]; if (clazz.isArray()) { sb.append(clazz.getComponentType().getName()).append("[]"); } else { sb.append(clazz.getName()); } if (++i < classes.length) { // increment and compare sb.append(" or "); } } sb.append(" ]"); return sb.toString(); } /** * Returns the string representation of the specified object, transparently * handling null references and arrays. * * @param obj * the object * @return the string representation */ public static String toString(Object obj) { String result; if (obj != null) { if (obj instanceof boolean[]) { result = Arrays.toString((boolean[]) obj); } else if (obj instanceof byte[]) { result = Arrays.toString((byte[]) obj); } else if (obj instanceof char[]) { result = Arrays.toString((char[]) obj); } else if (obj instanceof double[]) { result = Arrays.toString((double[]) obj); } else if (obj instanceof float[]) { result = Arrays.toString((float[]) obj); } else if (obj instanceof int[]) { result = Arrays.toString((int[]) obj); } else if (obj instanceof long[]) { result = Arrays.toString((long[]) obj); } else if (obj instanceof Object[]) { result = Arrays.deepToString((Object[]) obj); } else if (obj instanceof short[]) { result = Arrays.toString((short[]) obj); } else { result = obj.toString(); } } else { result = "null"; } return result; } } testng-6.9.12/src/main/java/org/testng/internal/ConfigurationGroupMethods.java0000755000175000017500000001077212732165123027011 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ITestNGMethod; import org.testng.collections.Lists; import org.testng.collections.Maps; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; /** * This class wraps access to beforeGroups and afterGroups methods, * since they are passed around the various invokers and potentially * modified in different threads. * * @author Cedric Beust * @author Alexandru Popescu * @since 5.3 (Mar 2, 2006) */ public class ConfigurationGroupMethods implements Serializable { /** Use serialVersionUID for interoperability. */ private final static long serialVersionUID= 1660798519864898480L; /** The list of beforeGroups methods keyed by the name of the group */ private final Map> m_beforeGroupsMethods; /** The list of afterGroups methods keyed by the name of the group */ private final Map> m_afterGroupsMethods; /** The list of all test methods */ private final ITestNGMethod[] m_allMethods; /**A map that returns the last method belonging to the given group */ private Map> m_afterGroupsMap= null; public ConfigurationGroupMethods(ITestNGMethod[] allMethods, Map> beforeGroupsMethods, Map> afterGroupsMethods) { m_allMethods= allMethods; m_beforeGroupsMethods= beforeGroupsMethods; m_afterGroupsMethods= afterGroupsMethods; } public Map> getBeforeGroupsMethods() { return m_beforeGroupsMethods; } public Map> getAfterGroupsMethods() { return m_afterGroupsMethods; } /** * @return true if the passed method is the last to run for the group. * This method is used to figure out when is the right time to invoke * afterGroups methods. */ public synchronized boolean isLastMethodForGroup(String group, ITestNGMethod method) { // If we have more invocation to do, this is not the last one yet if(method.hasMoreInvocation()) { return false; } // Lazy initialization since we might never be called if(m_afterGroupsMap == null) { m_afterGroupsMap= initializeAfterGroupsMap(); } List methodsInGroup= m_afterGroupsMap.get(group); if(null == methodsInGroup || methodsInGroup.isEmpty()) { return false; } methodsInGroup.remove(method); // Note: == is not good enough here as we may work with ITestNGMethod clones return methodsInGroup.isEmpty(); } private synchronized Map> initializeAfterGroupsMap() { Map> result= Maps.newHashMap(); for(ITestNGMethod m : m_allMethods) { String[] groups= m.getGroups(); for(String g : groups) { List methodsInGroup= result.get(g); if(null == methodsInGroup) { methodsInGroup= Lists.newArrayList(); result.put(g, methodsInGroup); } methodsInGroup.add(m); } } return result; } public synchronized void removeBeforeMethod(String group, ITestNGMethod method) { List methods= m_beforeGroupsMethods.get(group); if(methods != null) { Object success= methods.remove(method); if(success == null) { log("Couldn't remove beforeGroups method " + method + " for group " + group); } } else { log("Couldn't find any beforeGroups method for group " + group); } } private void log(String string) { Utils.log("ConfigurationGroupMethods", 2, string); } synchronized public Map> getBeforeGroupsMap() { return m_beforeGroupsMethods; } synchronized public Map> getAfterGroupsMap() { return m_afterGroupsMethods; } synchronized public void removeBeforeGroups(String[] groups) { for(String group : groups) { // log("Removing before group " + group); m_beforeGroupsMethods.remove(group); } } synchronized public void removeAfterGroups(Collection groups) { for(String group : groups) { // log("Removing before group " + group); m_afterGroupsMethods.remove(group); } } } testng-6.9.12/src/main/java/org/testng/internal/Tarjan.java0000755000175000017500000000340712732165123023055 0ustar eugeneeugenepackage org.testng.internal; import org.testng.collections.Lists; import org.testng.collections.Maps; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Stack; /** * Implementation of the Tarjan algorithm to find and display a cycle in a graph. * @author cbeust */ public class Tarjan { int m_index = 0; private Stack m_s; Map m_indices = Maps.newHashMap(); Map m_lowlinks = Maps.newHashMap(); private List m_cycle; public Tarjan(Graph graph, T start) { m_s = new Stack<>(); run(graph, start); } private void run(Graph graph, T v) { m_indices.put(v, m_index); m_lowlinks.put(v, m_index); m_index++; m_s.push(v); for (T vprime : graph.getPredecessors(v)) { if (! m_indices.containsKey(vprime)) { run(graph, vprime); int min = Math.min(m_lowlinks.get(v), m_lowlinks.get(vprime)); m_lowlinks.put(v, min); } else if (m_s.contains(vprime)) { m_lowlinks.put(v, Math.min(m_lowlinks.get(v), m_indices.get(vprime))); } } if (Objects.equals(m_lowlinks.get(v), m_indices.get(v))) { m_cycle = Lists.newArrayList(); T n; do { n = m_s.pop(); m_cycle.add(n); } while (! n.equals(v)); } } public static void main(String[] args) { Graph g = new Graph<>(); g.addNode("a"); g.addNode("b"); g.addNode("c"); g.addNode("d"); String[] edges = new String[] { "a", "b", "b", "a", "c", "d", "d", "a", "a", "c", }; for (int i = 0; i < edges.length; i += 2) { g.addPredecessor(edges[i], edges[i+1]); } new Tarjan<>(g, "a"); } public List getCycle() { return m_cycle; } } testng-6.9.12/src/main/java/org/testng/internal/BaseTestMethod.java0000755000175000017500000004630112732165123024511 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import org.testng.IClass; import org.testng.IRetryAnalyzer; import org.testng.ITestClass; import org.testng.ITestNGMethod; import org.testng.annotations.ITestOrConfiguration; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlTest; /** * Superclass to represent both @Test and @Configuration methods. */ public abstract class BaseTestMethod implements ITestNGMethod { private static final long serialVersionUID = -2666032602580652173L; private static final Pattern SPACE_SEPARATOR_PATTERN = Pattern.compile(" +"); /** * The test class on which the test method was found. Note that this is not * necessarily the declaring class. */ protected ITestClass m_testClass; protected final transient Class m_methodClass; protected final transient ConstructorOrMethod m_method; private transient String m_signature; protected String m_id = ""; protected long m_date = -1; protected final transient IAnnotationFinder m_annotationFinder; protected String[] m_groups = {}; protected String[] m_groupsDependedUpon = {}; protected String[] m_methodsDependedUpon = {}; protected String[] m_beforeGroups = {}; protected String[] m_afterGroups = {}; private boolean m_isAlwaysRun; private boolean m_enabled; private final String m_methodName; // If a depended group is not found private String m_missingGroup; private String m_description = null; protected AtomicInteger m_currentInvocationCount = new AtomicInteger(0); private int m_parameterInvocationCount = 1; private Callable m_moreInvocationChecker; private IRetryAnalyzer m_retryAnalyzer = null; private boolean m_skipFailedInvocations = true; private long m_invocationTimeOut = 0L; private List m_invocationNumbers = Lists.newArrayList(); private final List m_failedInvocationNumbers = Collections.synchronizedList(Lists.newArrayList()); private long m_timeOut = 0; private boolean m_ignoreMissingDependencies; private int m_priority; private XmlTest m_xmlTest; private Object m_instance; /** * Constructs a BaseTestMethod TODO cquezel JavaDoc. * * @param method * @param annotationFinder * @param instance */ public BaseTestMethod(String methodName, Method method, IAnnotationFinder annotationFinder, Object instance) { this(methodName, new ConstructorOrMethod(method), annotationFinder, instance); } public BaseTestMethod(String methodName, ConstructorOrMethod com, IAnnotationFinder annotationFinder, Object instance) { m_methodClass = com.getDeclaringClass(); m_method = com; m_methodName = methodName; m_annotationFinder = annotationFinder; m_instance = instance; } /** * {@inheritDoc} */ @Override public boolean isAlwaysRun() { return m_isAlwaysRun; } /** * TODO cquezel JavaDoc. * * @param alwaysRun */ protected void setAlwaysRun(boolean alwaysRun) { m_isAlwaysRun = alwaysRun; } /** * {@inheritDoc} */ @Override public Class getRealClass() { return m_methodClass; } /** * {@inheritDoc} */ @Override public ITestClass getTestClass() { return m_testClass; } /** * {@inheritDoc} */ @Override public void setTestClass(ITestClass tc) { assert null != tc; if (! tc.getRealClass().equals(m_method.getDeclaringClass())) { assert m_method.getDeclaringClass().isAssignableFrom(tc.getRealClass()) : "\nMISMATCH : " + tc.getRealClass() + " " + m_method.getDeclaringClass(); } m_testClass = tc; } @Override public int compareTo(Object o) { int result = -2; Class thisClass = getRealClass(); Class otherClass = ((ITestNGMethod) o).getRealClass(); if (this == o || equals(o)) { result = 0; } else if (thisClass.isAssignableFrom(otherClass)) { result = -1; } else if (otherClass.isAssignableFrom(thisClass)) { result = 1; } return result; } /** * {@inheritDoc} */ @Override public Method getMethod() { return m_method.getMethod(); } /** * {@inheritDoc} */ @Override public String getMethodName() { return m_methodName; } /** * {@inheritDoc} */ @Override public Object[] getInstances() { return new Object[] { getInstance() }; } @Override public Object getInstance() { return m_instance; } /** * {@inheritDoc} */ @Override public long[] getInstanceHashCodes() { return m_testClass.getInstanceHashCodes(); } /** * {@inheritDoc} * @return the addition of groups defined on the class and on this method. */ @Override public String[] getGroups() { return m_groups; } /** * {@inheritDoc} */ @Override public String[] getGroupsDependedUpon() { return m_groupsDependedUpon; } /** * {@inheritDoc} */ @Override public String[] getMethodsDependedUpon() { return m_methodsDependedUpon; } /** * {@inheritDoc} */ @Override public boolean isTest() { return false; } /** * {@inheritDoc} */ @Override public boolean isBeforeSuiteConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isAfterSuiteConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isBeforeTestConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isAfterTestConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isBeforeGroupsConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isAfterGroupsConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isBeforeClassConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isAfterClassConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isBeforeMethodConfiguration() { return false; } /** * {@inheritDoc} */ @Override public boolean isAfterMethodConfiguration() { return false; } /** * {@inheritDoc} */ @Override public long getTimeOut() { long result = m_timeOut != 0 ? m_timeOut : (m_xmlTest != null ? m_xmlTest.getTimeOut(0) : 0); return result; } @Override public void setTimeOut(long timeOut) { m_timeOut = timeOut; } /** * {@inheritDoc} * @return the number of times this method needs to be invoked. */ @Override public int getInvocationCount() { return 1; } /** * No-op. */ @Override public void setInvocationCount(int counter) { } /** * {@inheritDoc} * @return the number of times this method or one of its clones must be invoked. */ @Override public int getTotalInvocationCount() { return 1; } /** * {@inheritDoc} Default value for successPercentage. */ @Override public int getSuccessPercentage() { return 100; } /** * {@inheritDoc} */ @Override public String getId() { return m_id; } /** * {@inheritDoc} */ @Override public void setId(String id) { m_id = id; } /** * {@inheritDoc} * @return Returns the date. */ @Override public long getDate() { return m_date; } /** * {@inheritDoc} * @param date The date to set. */ @Override public void setDate(long date) { m_date = date; } /** * {@inheritDoc} */ @Override public boolean canRunFromClass(IClass testClass) { return m_methodClass.isAssignableFrom(testClass.getRealClass()); } /** * {@inheritDoc} Compares two BaseTestMethod using the test class then the associated * Java Method. */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } BaseTestMethod other = (BaseTestMethod) obj; boolean isEqual = m_testClass == null ? other.m_testClass == null : other.m_testClass != null && m_testClass.getRealClass().equals(other.m_testClass.getRealClass()) && m_instance == other.getInstance(); return isEqual && getConstructorOrMethod().equals(other.getConstructorOrMethod()); } /** * {@inheritDoc} This implementation returns the associated Java Method's hash code. * @return the associated Java Method's hash code. */ @Override public int hashCode() { return m_method.hashCode(); } protected void initGroups(Class annotationClass) { // // Init groups // { ITestOrConfiguration annotation = getAnnotationFinder().findAnnotation(getMethod(), annotationClass); ITestOrConfiguration classAnnotation = getAnnotationFinder().findAnnotation(getMethod().getDeclaringClass(), annotationClass); setGroups(getStringArray(null != annotation ? annotation.getGroups() : null, null != classAnnotation ? classAnnotation.getGroups() : null)); } // // Init groups depended upon // { ITestOrConfiguration annotation = getAnnotationFinder().findAnnotation(getMethod(), annotationClass); ITestOrConfiguration classAnnotation = getAnnotationFinder().findAnnotation(getMethod().getDeclaringClass(), annotationClass); Map> xgd = calculateXmlGroupDependencies(m_xmlTest); List xmlGroupDependencies = Lists.newArrayList(); for (String g : getGroups()) { Set gdu = xgd.get(g); if (gdu != null) { xmlGroupDependencies.addAll(gdu); } } setGroupsDependedUpon( getStringArray(null != annotation ? annotation.getDependsOnGroups() : null, null != classAnnotation ? classAnnotation.getDependsOnGroups() : null), xmlGroupDependencies); String[] methodsDependedUpon = getStringArray(null != annotation ? annotation.getDependsOnMethods() : null, null != classAnnotation ? classAnnotation.getDependsOnMethods() : null); // Qualify these methods if they don't have a package for (int i = 0; i < methodsDependedUpon.length; i++) { String m = methodsDependedUpon[i]; if (!m.contains(".")) { m = MethodHelper.calculateMethodCanonicalName(m_methodClass, methodsDependedUpon[i]); methodsDependedUpon[i] = m != null ? m : methodsDependedUpon[i]; } } setMethodsDependedUpon(methodsDependedUpon); } } private static Map> calculateXmlGroupDependencies(XmlTest xmlTest) { Map> result = Maps.newHashMap(); if (xmlTest == null) { return result; } for (Map.Entry e : xmlTest.getXmlDependencyGroups().entrySet()) { String name = e.getKey(); String dependsOn = e.getValue(); Set set = result.get(name); if (set == null) { set = Sets.newHashSet(); result.put(name, set); } set.addAll(Arrays.asList(SPACE_SEPARATOR_PATTERN.split(dependsOn))); } return result; } protected IAnnotationFinder getAnnotationFinder() { return m_annotationFinder; } protected IClass getIClass() { return m_testClass; } private String computeSignature() { String classLong = m_method.getDeclaringClass().getName(); String cls = classLong.substring(classLong.lastIndexOf(".") + 1); StringBuilder result = new StringBuilder(cls).append(".").append(m_method.getName()).append("("); int i = 0; for (Class p : m_method.getParameterTypes()) { if (i++ > 0) { result.append(", "); } result.append(p.getName()); } result.append(")"); result.append("[pri:").append(getPriority()).append(", instance:").append(m_instance).append("]"); return result.toString(); } public String getSimpleName() { return m_method.getDeclaringClass().getSimpleName() + "." + m_method.getName(); } protected String getSignature() { if (m_signature == null) { m_signature = computeSignature(); } return m_signature; } /** * {@inheritDoc} */ @Override public String toString() { return getSignature(); } protected String[] getStringArray(String[] methodArray, String[] classArray) { final Set vResult = Sets.newHashSet(); if (null != methodArray) { Collections.addAll(vResult, methodArray); } if (null != classArray) { Collections.addAll(vResult, classArray); } return vResult.toArray(new String[vResult.size()]); } protected void setGroups(String[] groups) { m_groups = groups; } protected void setGroupsDependedUpon(String[] groups, Collection xmlGroupDependencies) { List l = Lists.newArrayList(); l.addAll(Arrays.asList(groups)); l.addAll(xmlGroupDependencies); m_groupsDependedUpon = l.toArray(new String[l.size()]); } protected void setMethodsDependedUpon(String[] methods) { m_methodsDependedUpon = methods; } /** * {@inheritDoc} */ @Override public void addMethodDependedUpon(String method) { String[] newMethods = new String[m_methodsDependedUpon.length + 1]; newMethods[0] = method; System.arraycopy(m_methodsDependedUpon, 0, newMethods, 1, m_methodsDependedUpon.length); m_methodsDependedUpon = newMethods; } private static void ppp(String s) { System.out.println("[BaseTestMethod] " + s); } /** Compares two ITestNGMethod by date. */ public static final Comparator DATE_COMPARATOR = new Comparator() { @Override public int compare(Object o1, Object o2) { try { ITestNGMethod m1 = (ITestNGMethod) o1; ITestNGMethod m2 = (ITestNGMethod) o2; return (int) (m1.getDate() - m2.getDate()); } catch(Exception ex) { return 0; // TODO CQ document this logic } } }; /** * {@inheritDoc} */ @Override public String getMissingGroup() { return m_missingGroup; } /** * {@inheritDoc} */ @Override public void setMissingGroup(String group) { m_missingGroup = group; } /** * {@inheritDoc} */ @Override public int getThreadPoolSize() { return 0; } /** * No-op. */ @Override public void setThreadPoolSize(int threadPoolSize) { } @Override public void setDescription(String description) { m_description = description; } /** * {@inheritDoc} */ @Override public String getDescription() { return m_description; } public void setEnabled(boolean enabled) { m_enabled = enabled; } @Override public boolean getEnabled() { return m_enabled; } /** * {@inheritDoc} */ @Override public String[] getBeforeGroups() { return m_beforeGroups; } /** * {@inheritDoc} */ @Override public String[] getAfterGroups() { return m_afterGroups; } @Override public void incrementCurrentInvocationCount() { m_currentInvocationCount.incrementAndGet(); } @Override public int getCurrentInvocationCount() { return m_currentInvocationCount.get(); } @Override public void setParameterInvocationCount(int n) { m_parameterInvocationCount = n; } @Override public int getParameterInvocationCount() { return m_parameterInvocationCount; } @Override public void setMoreInvocationChecker(Callable moreInvocationChecker) { m_moreInvocationChecker = moreInvocationChecker; } @Override public boolean hasMoreInvocation() { if (m_moreInvocationChecker != null) { try { return m_moreInvocationChecker.call(); } catch (Exception e) { // Should never append throw new RuntimeException(e); } } return getCurrentInvocationCount() < getInvocationCount() * getParameterInvocationCount(); } @Override public abstract ITestNGMethod clone(); @Override public IRetryAnalyzer getRetryAnalyzer() { return m_retryAnalyzer; } @Override public void setRetryAnalyzer(IRetryAnalyzer retryAnalyzer) { m_retryAnalyzer = retryAnalyzer; } @Override public boolean skipFailedInvocations() { return m_skipFailedInvocations; } @Override public void setSkipFailedInvocations(boolean s) { m_skipFailedInvocations = s; } public void setInvocationTimeOut(long timeOut) { m_invocationTimeOut = timeOut; } @Override public long getInvocationTimeOut() { return m_invocationTimeOut; } @Override public boolean ignoreMissingDependencies() { return m_ignoreMissingDependencies; } @Override public void setIgnoreMissingDependencies(boolean i) { m_ignoreMissingDependencies = i; } @Override public List getInvocationNumbers() { return m_invocationNumbers; } @Override public void setInvocationNumbers(List numbers) { m_invocationNumbers = numbers; } @Override public List getFailedInvocationNumbers() { return m_failedInvocationNumbers; } @Override public void addFailedInvocationNumber(int number) { m_failedInvocationNumbers.add(number); } @Override public int getPriority() { return m_priority; } @Override public void setPriority(int priority) { m_priority = priority; } @Override public XmlTest getXmlTest() { return m_xmlTest; } public void setXmlTest(XmlTest xmlTest) { m_xmlTest = xmlTest; } @Override public ConstructorOrMethod getConstructorOrMethod() { return m_method; } @Override public Map findMethodParameters(XmlTest test) { // Get the test+suite parameters Map result = test.getAllParameters(); for (XmlClass xmlClass: test.getXmlClasses()) { if (xmlClass.getName().equals(getTestClass().getName())) { result.putAll(xmlClass.getLocalParameters()); for (XmlInclude include : xmlClass.getIncludedMethods()) { if (include.getName().equals(getMethodName())) { result.putAll(include.getLocalParameters()); break; } } } } return result; } } testng-6.9.12/src/main/java/org/testng/internal/XmlMethodSelector.java0000755000175000017500000002766212732165123025251 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import org.testng.IMethodSelector; import org.testng.IMethodSelectorContext; import org.testng.ITestNGMethod; import org.testng.TestNGException; import org.testng.collections.ListMultiMap; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.reflect.ReflectionHelper; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; /** * This class is the default method selector used by TestNG to determine * which methods need to be included and excluded based on the specification * given in testng.xml. * * Created on Sep 30, 2005 * @author cbeust */ public class XmlMethodSelector implements IMethodSelector { private static final long serialVersionUID = -9030548178025605629L; // Groups included and excluded for this run private Map m_includedGroups = Maps.newHashMap(); private Map m_excludedGroups = Maps.newHashMap(); private List m_classes = null; // The BeanShell expression for this test, if any private String m_expression = null; // List of methods included implicitly private ListMultiMap m_includedMethods = Maps.newListMultiMap(); private IBsh m_bsh = Dynamic.hasBsh() ? new Bsh() : new BshMock(); @Override public boolean includeMethod(IMethodSelectorContext context, ITestNGMethod tm, boolean isTestMethod) { // ppp("XML METHOD SELECTOR " + tm + " " + m_isInitialized); if (! m_isInitialized) { m_isInitialized = true; init(context); } boolean result = false; if (null != m_expression) { return m_bsh.includeMethodFromExpression(m_expression, tm); } else { result = includeMethodFromIncludeExclude(tm, isTestMethod); } return result; } private boolean includeMethodFromIncludeExclude(ITestNGMethod tm, boolean isTestMethod) { boolean result = false; Method m = tm.getMethod(); String[] groups = tm.getGroups(); Map includedGroups = m_includedGroups; Map excludedGroups = m_excludedGroups; List includeList = m_includedMethods.get(MethodHelper.calculateMethodCanonicalName(tm)); // // No groups were specified: // if (includedGroups.size() == 0 && excludedGroups.size() == 0 && ! hasIncludedMethods() && ! hasExcludedMethods()) // // If we don't include or exclude any methods, method is in // { result = true; } // // If it's a configuration method and no groups were requested, we want it in // else if (includedGroups.size() == 0 && excludedGroups.size() == 0 && ! isTestMethod) { result = true; } // // Is this method included implicitly? // else if (includeList != null) { result = true; } // // Include or Exclude groups were specified: // else { // // Only add this method if it belongs to an included group and not // to an excluded group // { boolean isIncludedInGroups = isIncluded(groups, m_includedGroups.values()); boolean isExcludedInGroups = isExcluded(groups, m_excludedGroups.values()); // // Calculate the run methods by groups first // if (isIncludedInGroups && !isExcludedInGroups) { result = true; } else if (isExcludedInGroups) { result = false; } } if(isTestMethod) { // // Now filter by method name // Method method = tm.getMethod(); Class methodClass = method.getDeclaringClass(); String fullMethodName = methodClass.getName() + "." + method.getName(); String[] fullyQualifiedMethodName = new String[] { fullMethodName }; // // Iterate through all the classes so we can gather all the included and // excluded methods // for (XmlClass xmlClass : m_classes) { // Only consider included/excluded methods that belong to the same class // we are looking at Class cls = xmlClass.getSupportClass(); if(!assignable(methodClass, cls)) { continue; } List includedMethods = createQualifiedMethodNames(xmlClass, toStringList(xmlClass.getIncludedMethods())); boolean isIncludedInMethods = isIncluded(fullyQualifiedMethodName, includedMethods); List excludedMethods = createQualifiedMethodNames(xmlClass, xmlClass.getExcludedMethods()); boolean isExcludedInMethods = isExcluded(fullyQualifiedMethodName, excludedMethods); if (result) { // If we're about to include this method by group, make sure // it's included by method and not excluded by method result = isIncludedInMethods && ! isExcludedInMethods; } // otherwise it's already excluded and nothing will bring it back, // since exclusions preempt inclusions } } } Package pkg = m.getDeclaringClass().getPackage(); String methodName = pkg != null ? pkg.getName() + "." + m.getName() : m.getName(); logInclusion(result ? "Including" : "Excluding", "method", methodName + "()"); return result; } @SuppressWarnings({"unchecked"}) private boolean assignable(Class sourceClass, Class targetClass) { return sourceClass.isAssignableFrom(targetClass) || targetClass.isAssignableFrom(sourceClass); } private Map m_logged = Maps.newHashMap(); private void logInclusion(String including, String type, String name) { if (! m_logged.containsKey(name)) { log(4, including + " " + type + " " + name); m_logged.put(name, name); } } private boolean hasIncludedMethods() { for (XmlClass xmlClass : m_classes) { if (xmlClass.getIncludedMethods().size() > 0) { return true; } } return false; } private boolean hasExcludedMethods() { for (XmlClass xmlClass : m_classes) { if (xmlClass.getExcludedMethods().size() > 0) { return true; } } return false; } private List toStringList(List methods) { List result = Lists.newArrayList(); for (XmlInclude m : methods) { result.add(m.getName()); } return result; } private List createQualifiedMethodNames(XmlClass xmlClass, List methods) { List vResult = Lists.newArrayList(); Class cls = xmlClass.getSupportClass(); while (null != cls) { for (String im : methods) { String methodName = im; Method[] allMethods = ReflectionHelper.getLocalMethods(cls); Pattern pattern = Pattern.compile(methodName); for (Method m : allMethods) { if (pattern.matcher(m.getName()).matches()) { vResult.add(makeMethodName(m.getDeclaringClass().getName(), m.getName())); } } } cls = cls.getSuperclass(); } return vResult; } private String makeMethodName(String className, String methodName) { return className + "." + methodName; } private void checkMethod(Class c, String methodName) { Pattern p = Pattern.compile(methodName); for (Method m : c.getMethods()) { if (p.matcher(m.getName()).matches()) { return; } } Utils.log("Warning", 2, "The regular expression \"" + methodName + "\" didn't match any" + " method in class " + c.getName()); } public void setXmlClasses(List classes) { m_classes = classes; for (XmlClass c : classes) { for (XmlInclude m : c.getIncludedMethods()) { checkMethod(c.getSupportClass(), m.getName()); String methodName = makeMethodName(c.getName(), m.getName()); m_includedMethods.put(methodName, m); } } } /** * @return Returns the excludedGroups. */ public Map getExcludedGroups() { return m_excludedGroups; } /** * @return Returns the includedGroups. */ public Map getIncludedGroups() { return m_includedGroups; } /** * @param excludedGroups The excludedGroups to set. */ public void setExcludedGroups(Map excludedGroups) { m_excludedGroups = excludedGroups; } /** * @param includedGroups The includedGroups to set. */ public void setIncludedGroups(Map includedGroups) { m_includedGroups = includedGroups; } private static boolean isIncluded(String[] groups, Collection includedGroups) { if (includedGroups.size() == 0) { return true; } else { return isMemberOf(groups, includedGroups); } } private static boolean isExcluded(String[] groups, Collection excludedGroups) { return isMemberOf(groups, excludedGroups); } /** * * @param groups Array of groups on the method * @param list Map of regexps of groups to be run */ private static boolean isMemberOf(String[] groups, Collection list) { for (String group : groups) { for (Object o : list) { String regexpStr = o.toString(); boolean match = Pattern.matches(regexpStr, group); if (match) { return true; } } } return false; } private static void log(int level, String s) { Utils.log("XmlMethodSelector", level, s); } private static void ppp(String s) { System.out.println("[XmlMethodSelector] " + s); } public void setExpression(String expression) { m_expression = expression; } private boolean m_isInitialized = false; private List m_testMethods = null; @Override public void setTestMethods(List testMethods) { // Caution: this variable is initialized with an empty list first and then modified // externally by the caller (TestRunner#fixMethodWithClass). Ugly. m_testMethods = testMethods; } private void init(IMethodSelectorContext context) { String[] groups = m_includedGroups.keySet().toArray(new String[m_includedGroups.size()]); Set groupClosure = new HashSet<>(); Set methodClosure = new HashSet<>(); List includedMethods = Lists.newArrayList(); for (ITestNGMethod m : m_testMethods) { if (includeMethod(context, m, true)) { includedMethods.add(m); } } MethodGroupsHelper.findGroupTransitiveClosure(this, includedMethods, m_testMethods, groups, groupClosure, methodClosure); // If we are asked to include or exclude specific groups, calculate // the transitive closure of all the included groups. If no include groups // were specified, don't do anything. // Any group that is part of the transitive closure but not part of // m_includedGroups is being added implicitly by TestNG so that if someone // includes a group z that depends on a, b and c, they don't need to // include a, b and c explicitly. if (m_includedGroups.size() > 0) { // Make the transitive closure our new included groups for (String g : groupClosure) { log(4, "Including group " + (m_includedGroups.containsKey(g) ? ": " : "(implicitly): ") + g); m_includedGroups.put(g, g); } // Make the transitive closure our new included methods for (ITestNGMethod m : methodClosure) { String methodName = m.getMethod().getDeclaringClass().getName() + "." + m.getMethodName(); // m_includedMethods.add(methodName); List includeList = m_includedMethods.get(methodName); XmlInclude xi = new XmlInclude(methodName); // TODO: set the XmlClass on this xi or we won't get inheritance of parameters m_includedMethods.put(methodName, xi); logInclusion("Including", "method ", methodName); } } } } testng-6.9.12/src/main/java/org/testng/internal/collections/0000755000175000017500000000000012732165123023302 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/internal/collections/Pair.java0000644000175000017500000000302312732165123025036 0ustar eugeneeugenepackage org.testng.internal.collections; import org.testng.collections.Objects; public class Pair { private final A first; private final B second; public Pair(A first, B second) { this.first = first; this.second = second; } public A first() { return first; } public B second() { return second; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((first == null) ? 0 : first.hashCode()); result = prime * result + ((second == null) ? 0 : second.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Pair other = (Pair) obj; if (first == null) { if (other.first != null) { return false; } } else if (!first.equals(other.first)) { return false; } if (second == null) { if (other.second != null) { return false; } } else if (!second.equals(other.second)) { return false; } return true; } public static Pair create(A first, B second) { return of(first, second); } public static Pair of(A a, B b) { return new Pair<>(a, b); } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("first", first()) .add("second", second()) .toString(); } }testng-6.9.12/src/main/java/org/testng/internal/DefaultMethodSelectorContext.java0000755000175000017500000000134612732165123027431 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IMethodSelectorContext; import org.testng.collections.Maps; import java.util.Map; /** * Simple implementation of IMethodSelectorContext * * Created on Jan 3, 2007 * @author Cedric Beust */ public class DefaultMethodSelectorContext implements IMethodSelectorContext { private Map m_userData = Maps.newHashMap(); private boolean m_isStopped = false; @Override public Map getUserData() { return m_userData; } @Override public boolean isStopped() { return m_isStopped; } @Override public void setStopped(boolean stopped) { m_isStopped = stopped; } } testng-6.9.12/src/main/java/org/testng/internal/DataProviderHolder.java0000755000175000017500000000075412732165123025362 0ustar eugeneeugenepackage org.testng.internal; import org.testng.annotations.IDataProviderAnnotation; import java.lang.reflect.Method; /** * A holder for a pair of Method and IDataProviderAnnotation */ public class DataProviderHolder { Object instance; Method method; IDataProviderAnnotation annotation; public DataProviderHolder(IDataProviderAnnotation annotation, Method method, Object instance) { this.annotation = annotation; this.method = method; this.instance = instance; } } testng-6.9.12/src/main/java/org/testng/internal/DynamicGraph.java0000644000175000017500000001363712732165123024207 0ustar eugeneeugenepackage org.testng.internal; import org.testng.collections.ListMultiMap; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; /** * Representation of the graph of methods. */ public class DynamicGraph { private static final boolean DEBUG = false; private List m_nodesReady = Lists.newArrayList(); private List m_nodesRunning = Lists.newArrayList(); private List m_nodesFinished = Lists.newArrayList(); private Comparator m_nodeComparator = null; private ListMultiMap m_dependedUpon = Maps.newListMultiMap(); private ListMultiMap m_dependingOn = Maps.newListMultiMap(); public static enum Status { READY, RUNNING, FINISHED } /** * Define a comparator for the nodes of this graph, which will be used * to order the free nodes when they are asked. */ public void setComparator(Comparator c) { m_nodeComparator = c; } /** * Add a node to the graph. */ public void addNode(T node) { m_nodesReady.add(node); } /** * Add an edge between two nodes. */ public void addEdge(T from, T... tos) { for (T to : tos) { m_dependingOn.put(to, from); m_dependedUpon.put(from, to); } } /** * @return a set of all the nodes that don't depend on any other nodes. */ public List getFreeNodes() { List result = Lists.newArrayList(); for (T m : m_nodesReady) { // A node is free if... List du = m_dependedUpon.get(m); // - no other nodes depend on it if (!m_dependedUpon.containsKey(m) || getUnfinishedNodes(du).size() == 0) { result.add(m); } } if (result.isEmpty() || m_nodeComparator == null) { return result; } // Sort the free nodes if requested (e.g. priorities) Collections.sort(result, m_nodeComparator); T node = result.get(0); ppp("Nodes after sorting:" + node); // Filter nodes List filteredNodes = Lists.newArrayList(); for (T currentNode : result) { if (m_nodeComparator.compare(node, currentNode) == 0) { filteredNodes.add(currentNode); } } return filteredNodes; } /** * @return a list of all the nodes that have a status other than FINISHED. */ private Collection getUnfinishedNodes(List nodes) { Set result = Sets.newHashSet(); for (T node : nodes) { if (m_nodesReady.contains(node) || m_nodesRunning.contains(node)) { result.add(node); } } return result; } /** * Set the status for a set of nodes. */ public void setStatus(Collection nodes, Status status) { for (T n : nodes) { setStatus(n, status); } } /** * Set the status for a node. */ public void setStatus(T node, Status status) { removeNode(node); switch(status) { case READY: m_nodesReady.add(node); break; case RUNNING: m_nodesRunning.add(node); break; case FINISHED: m_nodesFinished.add(node); break; default: throw new IllegalArgumentException(); } } private void removeNode(T node) { if (!m_nodesReady.remove(node)) { if (!m_nodesRunning.remove(node)) { m_nodesFinished.remove(node); } } } /** * @return the number of nodes in this graph. */ public int getNodeCount() { int result = m_nodesReady.size() + m_nodesRunning.size() + m_nodesFinished.size(); return result; } public int getNodeCountWithStatus(Status status) { switch(status) { case READY: return m_nodesReady.size(); case RUNNING: return m_nodesRunning.size(); case FINISHED: return m_nodesFinished.size(); default: throw new IllegalArgumentException(); } } private static void ppp(String string) { if (DEBUG) { System.out.println(" [GroupThreadPoolExecutor] " + Thread.currentThread().getId() + " " + string); } } @Override public String toString() { StringBuilder result = new StringBuilder("[DynamicGraph "); result.append("\n Ready:" + m_nodesReady); result.append("\n Running:" + m_nodesRunning); result.append("\n Finished:" + m_nodesFinished); result.append("\n Edges:\n"); for (Map.Entry> es : m_dependingOn.entrySet()) { result.append(" " + es.getKey() + "\n"); for (T t : es.getValue()) { result.append(" " + t + "\n"); } } result.append("]"); return result.toString(); } private String getName(T t) { String s = t.toString(); int n1 = s.lastIndexOf('.') + 1; int n2 = s.indexOf('('); return s.substring(n1, n2); } /** * @return a .dot file (GraphViz) version of this graph. */ public String toDot() { String FREE = "[style=filled color=yellow]"; String RUNNING = "[style=filled color=green]"; String FINISHED = "[style=filled color=grey]"; StringBuilder result = new StringBuilder("digraph g {\n"); List freeNodes = getFreeNodes(); String color; for (T n : m_nodesReady) { color = freeNodes.contains(n) ? FREE : ""; result.append(" " + getName(n) + color + "\n"); } for (T n : m_nodesRunning) { color = freeNodes.contains(n) ? FREE : RUNNING; result.append(" " + getName(n) + color + "\n"); } for (T n : m_nodesFinished) { result.append(" " + getName(n) + FINISHED+ "\n"); } result.append("\n"); for (T k : m_dependingOn.keySet()) { List nodes = m_dependingOn.get(k); for (T n : nodes) { String dotted = m_nodesFinished.contains(k) ? "style=dotted" : ""; result.append(" " + getName(k) + " -> " + getName(n) + " [dir=back " + dotted + "]\n"); } } result.append("}\n"); return result.toString(); } public ListMultiMap getEdges() { return m_dependingOn; } } testng-6.9.12/src/main/java/org/testng/internal/InvokedMethod.java0000755000175000017500000000442012732165123024372 0ustar eugeneeugenepackage org.testng.internal; import java.io.Serializable; import org.testng.IInvokedMethod; import org.testng.ITestNGMethod; import org.testng.ITestResult; public class InvokedMethod implements Serializable, IInvokedMethod { private static final long serialVersionUID = 2126127194102819222L; transient private Object m_instance; private ITestNGMethod m_testMethod; private Object[] m_parameters; private long m_date = System.currentTimeMillis(); private ITestResult m_testResult; public InvokedMethod(Object instance, ITestNGMethod method, Object[] parameters, long date, ITestResult testResult) { m_instance = instance; m_testMethod = method; m_parameters = parameters; m_date = date; m_testResult = testResult; } /* (non-Javadoc) * @see org.testng.internal.IInvokedMethod#isTestMethod() */ @Override public boolean isTestMethod() { return m_testMethod.isTest(); } @Override public String toString() { StringBuffer result = new StringBuffer(m_testMethod.toString()); for (Object p : m_parameters) { result.append(p).append(" "); } result.append(" ").append(m_instance != null ? m_instance.hashCode() : " "); return result.toString(); } /* (non-Javadoc) * @see org.testng.internal.IInvokedMethod#isConfigurationMethod() */ @Override public boolean isConfigurationMethod() { return m_testMethod.isBeforeMethodConfiguration() || m_testMethod.isAfterMethodConfiguration() || m_testMethod.isBeforeTestConfiguration() || m_testMethod.isAfterTestConfiguration() || m_testMethod.isBeforeClassConfiguration() || m_testMethod.isAfterClassConfiguration() || m_testMethod.isBeforeSuiteConfiguration() || m_testMethod.isAfterSuiteConfiguration(); } /* (non-Javadoc) * @see org.testng.internal.IInvokedMethod#getTestMethod() */ @Override public ITestNGMethod getTestMethod() { return m_testMethod; } /* (non-Javadoc) * @see org.testng.internal.IInvokedMethod#getDate() */ @Override public long getDate() { return m_date; } @Override public ITestResult getTestResult() { return m_testResult; } } testng-6.9.12/src/main/java/org/testng/internal/ParameterHolder.java0000755000175000017500000000134712732165123024715 0ustar eugeneeugenepackage org.testng.internal; import java.util.Iterator; /** * A simple holder for parameters that contains the parameters and where these came from * (data provider or testng.xml) * @author cbeust * */ public class ParameterHolder { /** * Origin of the parameters. */ public enum ParameterOrigin { ORIGIN_DATA_PROVIDER, // A data provider ORIGIN_XML // TestNG XML suite } public DataProviderHolder dataProviderHolder; public Iterator parameters; public ParameterOrigin origin; public ParameterHolder(Iterator parameters, ParameterOrigin origin, DataProviderHolder dph) { super(); this.parameters = parameters; this.origin = origin; this.dataProviderHolder = dph; } } testng-6.9.12/src/main/java/org/testng/internal/TestNGProperty.java0000755000175000017500000000206512732165123024546 0ustar eugeneeugenepackage org.testng.internal; /** * Describes a property * * @author Cedric Beust, May 2, 2004 * */ public class TestNGProperty { private String m_commandLineName = null; private String m_name = null; private String m_documentation = null; private String m_default = null; public TestNGProperty(String clName, String name, String doc, String def) { init(clName, name, doc, def); } public TestNGProperty(String name, String doc, String def) { init(name, name, doc, def); } private void init(String clName, String name, String doc, String def) { m_commandLineName = clName; m_name = name; m_documentation = doc; m_default = def; } /** * @return Returns the default. */ public String getDefault() { return m_default; } /** * @return Returns the documentation. */ public String getDocumentation() { return m_documentation; } /** * @return Returns the name. */ public String getName() { return m_name; } public String getCommandLineName() { return m_commandLineName; } } testng-6.9.12/src/main/java/org/testng/internal/Nullable.java0000644000175000017500000000051712732165123023370 0ustar eugeneeugenepackage org.testng.internal; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.PARAMETER; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @Target({FIELD, PARAMETER}) public @interface Nullable { } testng-6.9.12/src/main/java/org/testng/internal/ITestResultNotifier.java0000755000175000017500000000214012732165123025556 0ustar eugeneeugenepackage org.testng.internal; import java.util.List; import java.util.Set; import org.testng.IConfigurationListener; import org.testng.ITestListener; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.xml.XmlTest; /** * An interface defining the notification for @Test results and also * \@Configuration results. * * @author Cedric Beust * @author Alexandru Popescu */ public interface ITestResultNotifier { Set getPassedTests(ITestNGMethod tm); Set getFailedTests(ITestNGMethod tm); Set getSkippedTests(ITestNGMethod tm); void addPassedTest(ITestNGMethod tm, ITestResult tr); void addSkippedTest(ITestNGMethod tm, ITestResult tr); void addFailedTest(ITestNGMethod tm, ITestResult tr); void addFailedButWithinSuccessPercentageTest(ITestNGMethod tm, ITestResult tr); void addInvokedMethod(InvokedMethod im); XmlTest getTest(); List getTestListeners(); List getConfigurationListeners(); } testng-6.9.12/src/main/java/org/testng/internal/Parameters.java0000755000175000017500000004360712732165123023747 0ustar eugeneeugenepackage org.testng.internal; import com.google.inject.Injector; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.TestNGException; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IParameterizable; import org.testng.annotations.IParametersAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.ParameterHolder.ParameterOrigin; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.annotations.IDataProvidable; import org.testng.util.Strings; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; /** * Methods that bind parameters declared in testng.xml to actual values * used to invoke methods. * * @author Cedric Beust */ public class Parameters { public static final String NULL_VALUE= "null"; /** * Creates the parameters needed for constructing a test class instance. * @param finder TODO */ public static Object[] createInstantiationParameters(Constructor ctor, String methodAnnotation, IAnnotationFinder finder, String[] parameterNames, Map params, XmlSuite xmlSuite) { return createParameters(ctor.toString(), ctor.getParameterTypes(), finder.findOptionalValues(ctor), methodAnnotation, finder, parameterNames, new MethodParameters(params, Collections.emptyMap()), xmlSuite); } /** * Creates the parameters needed for the specified @Configuration Method. * * @param m the configuraton method * @param currentTestMethod the current @Test method or null if no @Test is available (this is not * only in case the configuration method is a @Before/@AfterMethod * @param finder the annotation finder */ public static Object[] createConfigurationParameters(Method m, Map params, Object[] parameterValues, @Nullable ITestNGMethod currentTestMethod, IAnnotationFinder finder, XmlSuite xmlSuite, ITestContext ctx, ITestResult testResult) { Method currentTestMeth= currentTestMethod != null ? currentTestMethod.getMethod() : null; Map methodParams = currentTestMethod != null ? currentTestMethod.findMethodParameters(ctx.getCurrentXmlTest()) : Collections.emptyMap(); return createParameters(m, new MethodParameters(params, methodParams, parameterValues, currentTestMeth, ctx, testResult), finder, xmlSuite, IConfigurationAnnotation.class, "@Configuration"); } //////////////////////////////////////////////////////// public static Object getInjectedParameter(Class c, Method method, ITestContext context, ITestResult testResult) { Object result = null; if (Method.class.equals(c)) { result = method; } else if (ITestContext.class.equals(c)) { result = context; } else if (XmlTest.class.equals(c)) { result = context.getCurrentXmlTest(); } else if (ITestResult.class.equals(c)) { result = testResult; } return result; } /** * @return An array of parameters suitable to invoke this method, possibly * picked from the property file */ private static Object[] createParameters(String methodName, Class[] parameterTypes, String[] optionalValues, String methodAnnotation, IAnnotationFinder finder, String[] parameterNames, MethodParameters params, XmlSuite xmlSuite) { Object[] result = new Object[0]; if(parameterTypes.length > 0) { List vResult = Lists.newArrayList(); checkParameterTypes(methodName, parameterTypes, methodAnnotation, parameterNames); for(int i = 0, j = 0; i < parameterTypes.length; i++) { Object inject = getInjectedParameter(parameterTypes[i], params.currentTestMethod, params.context, params.testResult); if (inject != null) { vResult.add(inject); } else { if (j < parameterNames.length) { String p = parameterNames[j]; String value = params.xmlParameters.get(p); if(null == value) { // try SysEnv entries value= System.getProperty(p); } if (null == value) { if (optionalValues != null) { value = optionalValues[i]; } if (null == value) { throw new TestNGException("Parameter '" + p + "' is required by " + methodAnnotation + " on method " + methodName + " but has not been marked @Optional or defined\n" + (xmlSuite.getFileName() != null ? "in " + xmlSuite.getFileName() : "")); } } vResult.add(convertType(parameterTypes[i], value, p)); j++; } } } result = vResult.toArray(new Object[vResult.size()]); } return result; } private static void checkParameterTypes(String methodName, Class[] parameterTypes, String methodAnnotation, String[] parameterNames) { int totalLength = parameterTypes.length; Set injectedTypes = new HashSet() { private static final long serialVersionUID = -5324894581793435812L; { add(ITestContext.class); add(ITestResult.class); add(XmlTest.class); add(Method.class); add(Object[].class); }}; for (Class parameterType : parameterTypes) { if (injectedTypes.contains(parameterType)) { totalLength--; } } if (parameterNames.length != totalLength) { throw new TestNGException( "Method " + methodName + " requires " + parameterTypes.length + " parameters but " + parameterNames.length + " were supplied in the " + methodAnnotation + " annotation."); } } public static Object convertType(Class type, String value, String paramName) { Object result = null; if(NULL_VALUE.equals(value.toLowerCase())) { if(type.isPrimitive()) { Utils.log("Parameters", 2, "Attempt to pass null value to primitive type parameter '" + paramName + "'"); } return null; // null value must be used } if(type == String.class) { result = value; } else if(type == int.class || type == Integer.class) { result = Integer.parseInt(value); } else if(type == boolean.class || type == Boolean.class) { result = Boolean.valueOf(value); } else if(type == byte.class || type == Byte.class) { result = Byte.parseByte(value); } else if(type == char.class || type == Character.class) { result = value.charAt(0); } else if(type == double.class || type == Double.class) { result = Double.parseDouble(value); } else if(type == float.class || type == Float.class) { result = Float.parseFloat(value); } else if(type == long.class || type == Long.class) { result = Long.parseLong(value); } else if(type == short.class || type == Short.class) { result = Short.parseShort(value); } else if (type.isEnum()) { result = Enum.valueOf(type, value); } else { assert false : "Unsupported type parameter : " + type; } return result; } private static DataProviderHolder findDataProvider(Object instance, ITestClass clazz, ConstructorOrMethod m, IAnnotationFinder finder, ITestContext context) { DataProviderHolder result = null; IDataProvidable dp = findDataProviderInfo(clazz, m, finder); if (dp != null) { String dataProviderName = dp.getDataProvider(); Class dataProviderClass = dp.getDataProviderClass(); if (! Utils.isStringEmpty(dataProviderName)) { result = findDataProvider(instance, clazz, finder, dataProviderName, dataProviderClass, context); if(null == result) { throw new TestNGException("Method " + m + " requires a @DataProvider named : " + dataProviderName + (dataProviderClass != null ? " in class " + dataProviderClass.getName() : "") ); } } } return result; } /** * Find the data provider info (data provider name and class) on either @Test(dataProvider), * @Factory(dataProvider) on a method or @Factory(dataProvider) on a constructor. */ private static IDataProvidable findDataProviderInfo(ITestClass clazz, ConstructorOrMethod m, IAnnotationFinder finder) { IDataProvidable result; if (m.getMethod() != null) { // // @Test(dataProvider) on a method // result = AnnotationHelper.findTest(finder, m.getMethod()); if (result == null) { // // @Factory(dataProvider) on a method // result = AnnotationHelper.findFactory(finder, m.getMethod()); } if (result == null) { // // @Test(dataProvider) on a class result = AnnotationHelper.findTest(finder, clazz.getRealClass()); } } else { // // @Factory(dataProvider) on a constructor // result = AnnotationHelper.findFactory(finder, m.getConstructor()); } return result; } /** * Find a method that has a @DataProvider(name=name) */ private static DataProviderHolder findDataProvider(Object instance, ITestClass clazz, IAnnotationFinder finder, String name, Class dataProviderClass, ITestContext context) { DataProviderHolder result = null; Class cls = clazz.getRealClass(); boolean shouldBeStatic = false; if (dataProviderClass != null) { cls = dataProviderClass; shouldBeStatic = true; } for (Method m : ClassHelper.getAvailableMethods(cls)) { IDataProviderAnnotation dp = finder.findAnnotation(m, IDataProviderAnnotation.class); if (null != dp && name.equals(getDataProviderName(dp, m))) { if (shouldBeStatic && (m.getModifiers() & Modifier.STATIC) == 0) { Injector injector = context.getInjector(clazz); if (injector != null) { instance = injector.getInstance(dataProviderClass); } } if (result != null) { throw new TestNGException("Found two providers called '" + name + "' on " + cls); } result = new DataProviderHolder(dp, m, instance); } } return result; } private static String getDataProviderName(IDataProviderAnnotation dp, Method m) { return Strings.isNullOrEmpty(dp.getName()) ? m.getName() : dp.getName(); } @SuppressWarnings({"deprecation"}) private static Object[] createParameters(Method m, MethodParameters params, IAnnotationFinder finder, XmlSuite xmlSuite, Class annotationClass, String atName) { List result = Lists.newArrayList(); Object[] extraParameters; // // Try to find an @Parameters annotation // IParametersAnnotation annotation = finder.findAnnotation(m, IParametersAnnotation.class); Class[] types = m.getParameterTypes(); if(null != annotation) { String[] parameterNames = annotation.getValue(); extraParameters = createParameters(m.getName(), types, finder.findOptionalValues(m), atName, finder, parameterNames, params, xmlSuite); } // // Else, use the deprecated syntax // else { IParameterizable a = (IParameterizable) finder.findAnnotation(m, annotationClass); if(null != a && a.getParameters().length > 0) { String[] parameterNames = a.getParameters(); extraParameters = createParameters(m.getName(), types, finder.findOptionalValues(m), atName, finder, parameterNames, params, xmlSuite); } else { extraParameters = createParameters(m.getName(), types, finder.findOptionalValues(m), atName, finder, new String[0], params, xmlSuite); } } // // Add the extra parameters we found // Collections.addAll(result, extraParameters); // If the method declared an Object[] parameter and we have parameter values, inject them for (int i = 0; i < types.length; i++) { if (Object[].class.equals(types[i])) { result.add(i, params.parameterValues); } } return result.toArray(new Object[result.size()]); } /** * If the method has parameters, fill them in. Either by using a @DataProvider * if any was provided, or by looking up in testng.xml * @return An Iterator over the values for each parameter of this * method. */ public static ParameterHolder handleParameters(ITestNGMethod testMethod, Map allParameterNames, Object instance, MethodParameters methodParams, XmlSuite xmlSuite, IAnnotationFinder annotationFinder, Object fedInstance) { /* * Do we have a @DataProvider? If yes, then we have several * sets of parameters for this method */ final DataProviderHolder dataProviderHolder = findDataProvider(instance, testMethod.getTestClass(), testMethod.getConstructorOrMethod(), annotationFinder, methodParams.context); if (null != dataProviderHolder) { int parameterCount = testMethod.getConstructorOrMethod().getParameterTypes().length; for (int i = 0; i < parameterCount; i++) { String n = "param" + i; allParameterNames.put(n, n); } final Iterator parameters = MethodInvocationHelper.invokeDataProvider( dataProviderHolder.instance, /* a test instance or null if the dataprovider is static*/ dataProviderHolder.method, testMethod, methodParams.context, fedInstance, annotationFinder); // If the data provider is restricting the indices to return, filter them out final List allIndices = new ArrayList<>(); allIndices.addAll(testMethod.getInvocationNumbers()); allIndices.addAll(dataProviderHolder.annotation.getIndices()); final Iterator filteredParameters = new Iterator() { int index = 0; boolean hasWarn = false; @Override public boolean hasNext() { if (index == 0 && !parameters.hasNext() && !hasWarn) { hasWarn = true; Utils.log("", 2, "Warning: the data provider '" + dataProviderHolder.annotation.getName() + "' returned an empty array or iterator, so this test is not doing anything"); } return parameters.hasNext(); } @Override public Object[] next() { Object[] next = parameters.next(); if (!allIndices.isEmpty() && !allIndices.contains(index)) { next = null; } index++; return next; } @Override public void remove() { throw new UnsupportedOperationException("remove"); } }; testMethod.setMoreInvocationChecker(new Callable() { @Override public Boolean call() throws Exception { return filteredParameters.hasNext(); } }); return new ParameterHolder(filteredParameters, ParameterOrigin.ORIGIN_DATA_PROVIDER, dataProviderHolder); } else { // // Normal case: we have only one set of parameters coming from testng.xml // allParameterNames.putAll(methodParams.xmlParameters); // Create an Object[][] containing just one row of parameters Object[][] allParameterValuesArray = new Object[1][]; allParameterValuesArray[0] = createParameters(testMethod.getMethod(), methodParams, annotationFinder, xmlSuite, ITestAnnotation.class, "@Test"); // Mark that this method needs to have at least a certain // number of invocations (needed later to call AfterGroups // at the right time). testMethod.setParameterInvocationCount(allParameterValuesArray.length); // Turn it into an Iterable Iterator parameters = MethodHelper.createArrayIterator(allParameterValuesArray); return new ParameterHolder(parameters, ParameterOrigin.ORIGIN_XML, null); } } /** A parameter passing helper class. */ public static class MethodParameters { private final Map xmlParameters; private final Method currentTestMethod; private final ITestContext context; private Object[] parameterValues; public ITestResult testResult; public MethodParameters(Map params, Map methodParams) { this(params, methodParams, null, null, null, null); } /** * @param params parameters found in the suite and test tags * @param methodParams parameters found in the include tag * @param pv * @param m * @param ctx * @param tr */ public MethodParameters(Map params, Map methodParams, Object[] pv, Method m, ITestContext ctx, ITestResult tr) { Map allParams = Maps.newHashMap(); allParams.putAll(params); allParams.putAll(methodParams); xmlParameters = allParams; currentTestMethod = m; context = ctx; parameterValues = pv; testResult = tr; } } } testng-6.9.12/src/main/java/org/testng/internal/Graph.java0000644000175000017500000002153212732165123022673 0ustar eugeneeugenepackage org.testng.internal; import org.testng.TestNGException; import org.testng.collections.Lists; import org.testng.collections.Maps; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * Simple graph class to implement topological sort (used to sort methods based on what groups * they depend on). * * @author Cedric Beust, Aug 19, 2004 */ public class Graph { private static boolean m_verbose = false; private Map> m_nodes = Maps.newLinkedHashMap(); private List m_strictlySortedNodes = null; // A map of nodes that are not the predecessors of any node // (not needed for the algorithm but convenient to calculate // the parallel/sequential lists in TestNG). private Map> m_independentNodes = null; public void addNode(T tm) { ppp("ADDING NODE " + tm + " " + tm.hashCode()); m_nodes.put(tm, new Node<>(tm)); // Initially, all the nodes are put in the independent list as well } public Set getPredecessors(T node) { return findNode(node).getPredecessors().keySet(); } public boolean isIndependent(T object) { return m_independentNodes.containsKey(object); } private Node findNode(T object) { return m_nodes.get(object); } public void addPredecessor(T tm, T predecessor) { Node node = findNode(tm); if (null == node) { throw new TestNGException("Non-existing node: " + tm); } else { node.addPredecessor(predecessor); addNeighbor(tm, predecessor); // Remove these two nodes from the independent list initializeIndependentNodes(); m_independentNodes.remove(predecessor); m_independentNodes.remove(tm); ppp(" REMOVED " + predecessor + " FROM INDEPENDENT OBJECTS"); } } private void addNeighbor(T tm, T predecessor) { findNode(tm).addNeighbor(findNode(predecessor)); } public Set getNeighbors(T t) { Set result = new HashSet<>(); for (Node n : findNode(t).getNeighbors()) { result.add(n.getObject()); } return result; } private Collection> getNodes() { return m_nodes.values(); } public Collection getNodeValues() { return m_nodes.keySet(); } /** * @return All the nodes that don't have any order with each other. */ public Set getIndependentNodes() { return m_independentNodes.keySet(); } /** * @return All the nodes that have an order with each other, sorted * in one of the valid sorts. */ public List getStrictlySortedNodes() { return m_strictlySortedNodes; } public void topologicalSort() { ppp("================ SORTING"); m_strictlySortedNodes = Lists.newArrayList(); initializeIndependentNodes(); // // Clone the list of nodes but only keep those that are // not independent. // List> nodes2 = Lists.newArrayList(); for (Node n : getNodes()) { if (! isIndependent(n.getObject())) { ppp("ADDING FOR SORT: " + n.getObject()); nodes2.add(n.clone()); } else { ppp("SKIPPING INDEPENDENT NODE " + n); } } // // Sort the nodes alphabetically to make sure that methods of the same class // get run close to each other as much as possible // Collections.sort(nodes2); // // Sort // while (! nodes2.isEmpty()) { // // Find all the nodes that don't have any predecessors, add // them to the result and mark them for removal // Node node = findNodeWithNoPredecessors(nodes2); if (null == node) { List cycle = new Tarjan<>(this, nodes2.get(0).getObject()).getCycle(); StringBuilder sb = new StringBuilder(); sb.append("The following methods have cyclic dependencies:\n"); for (T m : cycle) { sb.append(m).append("\n"); } throw new TestNGException(sb.toString()); } else { m_strictlySortedNodes.add(node.getObject()); removeFromNodes(nodes2, node); } } ppp("=============== DONE SORTING"); if (m_verbose) { dumpSortedNodes(); } } private void initializeIndependentNodes() { if (null == m_independentNodes) { List> list = Lists.newArrayList(m_nodes.values()); // Ideally, we should not have to sort this. However, due to a bug where it treats all the methods as // dependent nodes. Therefore, all the nodes were mostly sorted alphabetically. So we need to keep // the behavior for now. Collections.sort(list); m_independentNodes = Maps.newLinkedHashMap(); for (Node node : list) { m_independentNodes.put(node.getObject(), node); } } } private void dumpSortedNodes() { System.out.println("====== SORTED NODES"); for (T n : m_strictlySortedNodes) { System.out.println(" " + n); } System.out.println("====== END SORTED NODES"); } /** * Remove a node from a list of nodes and update the list of predecessors * for all the remaining nodes. */ private void removeFromNodes(List> nodes, Node node) { nodes.remove(node); for (Node n : nodes) { n.removePredecessor(node.getObject()); } } private static void ppp(String s) { if (m_verbose) { System.out.println("[Graph] " + s); } } private Node findNodeWithNoPredecessors(List> nodes) { for (Node n : nodes) { if (! n.hasPredecessors()) { return n; } } return null; } /** * @param o * @return A list of all the predecessors for o */ public List findPredecessors(T o) { // Locate the node Node node = findNode(o); if (null == node) { // This can happen if an interceptor returned new methods return Lists.newArrayList(); } // If we found the node, use breadth first search to find all // all of the predecessors of o. "result" is the growing list // of all predecessors. "visited" is the set of items we've // already encountered. "queue" is the queue of items whose // predecessors we haven't yet explored. LinkedList result = new LinkedList<>(); Set visited = new HashSet<>(); LinkedList queue = new LinkedList<>(); visited.add(o); queue.addLast(o); while (! queue.isEmpty()) { for (T obj : getPredecessors(queue.removeFirst())) { if (! visited.contains(obj)) { visited.add(obj); queue.addLast(obj); result.addFirst(obj); } } } return result; } @Override public String toString() { StringBuilder result = new StringBuilder("[Graph "); for (T node : m_nodes.keySet()) { result.append(findNode(node)).append(" "); } result.append("]"); return result.toString(); } ///// // class Node // public static class Node implements Comparable> { private T m_object = null; private Map m_predecessors = Maps.newHashMap(); public Node(T tm) { m_object = tm; } private Set> m_neighbors = new HashSet<>(); public void addNeighbor(Node neighbor) { m_neighbors.add(neighbor); } public Set> getNeighbors() { return m_neighbors; } @Override public Node clone() { Node result = new Node<>(m_object); for (T pred : m_predecessors.values()) { result.addPredecessor(pred); } return result; } public T getObject() { return m_object; } public Map getPredecessors() { return m_predecessors; } /** * * @return true if this predecessor was found and removed */ public boolean removePredecessor(T o) { boolean result = false; T pred = m_predecessors.get(o); if (null != pred) { result = null != m_predecessors.remove(o); if (result) { ppp(" REMOVED PRED " + o + " FROM NODE " + m_object); } else { ppp(" FAILED TO REMOVE PRED " + o + " FROM NODE " + m_object); } } return result; } @Override public String toString() { StringBuilder sb = new StringBuilder("[Node:" + m_object); sb.append(" pred:"); for (T o : m_predecessors.values()) { sb.append(" ").append(o); } sb.append("]"); String result = sb.toString(); return result; } public void addPredecessor(T tm) { ppp(" ADDING PREDECESSOR FOR " + m_object + " ==> " + tm); m_predecessors.put(tm, tm); } public boolean hasPredecessors() { return m_predecessors.size() > 0; } public boolean hasPredecessor(T m) { return m_predecessors.containsKey(m); } @Override public int compareTo(Node o) { return getObject().toString().compareTo(o.getObject().toString()); } } } testng-6.9.12/src/main/java/org/testng/internal/IInvoker.java0000755000175000017500000000335012732165123023361 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.xml.XmlSuite; import java.util.List; import java.util.Map; /** * This class defines an invoker. * * @author Cedric Beust */ public interface IInvoker { /** * Invoke configuration methods if they belong to the same TestClass * passed in parameter.. * * TODO: Calculate ahead of time which methods should be * invoked for each class. Might speed things up for users who invoke the same * test class with different parameters in the same suite run. * * @param testClass the class whose configuration methods must be run */ public void invokeConfigurations(IClass testClass, ITestNGMethod[] allMethods, XmlSuite suite, Map parameters, Object[] parameterValues, Object instance); /** * Invoke the given method * * @param testMethod * @param suite * @param parameters * @param groupMethods * * @return a list containing the results of the test methods invocations */ public List invokeTestMethods(ITestNGMethod testMethod, XmlSuite suite, Map parameters, ConfigurationGroupMethods groupMethods, Object instance, ITestContext testContext); } testng-6.9.12/src/main/java/org/testng/internal/ExpectedExceptionsHolder.java0000644000175000017500000000632012732165123026571 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IExpectedExceptionsHolder; import org.testng.ITestNGMethod; import org.testng.TestException; import org.testng.annotations.IExpectedExceptionsAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.internal.annotations.IAnnotationFinder; import java.util.Arrays; public class ExpectedExceptionsHolder { protected final IAnnotationFinder finder; protected final ITestNGMethod method; private final Class[] expectedClasses; private final IExpectedExceptionsHolder holder; protected ExpectedExceptionsHolder(IAnnotationFinder finder, ITestNGMethod method, IExpectedExceptionsHolder holder) { this.finder = finder; this.method = method; expectedClasses = findExpectedClasses(finder, method); this.holder = holder; } private static Class[] findExpectedClasses(IAnnotationFinder finder, ITestNGMethod method) { IExpectedExceptionsAnnotation expectedExceptions = finder.findAnnotation(method, IExpectedExceptionsAnnotation.class); // Old syntax if (expectedExceptions != null) { return expectedExceptions.getValue(); } // New syntax ITestAnnotation testAnnotation = finder.findAnnotation(method, ITestAnnotation.class); if (testAnnotation != null) { return testAnnotation.getExpectedExceptions(); } return new Class[0]; } /** * @param ite The exception that was just thrown * @return true if the exception that was just thrown is part of the * expected exceptions */ public boolean isExpectedException(Throwable ite) { if (!hasExpectedClasses()) { return false; } // TestException is the wrapper exception that TestNG will be throwing when an exception was // expected but not thrown if (ite.getClass() == TestException.class) { return false; } Class realExceptionClass= ite.getClass(); for (Class exception : expectedClasses) { if (exception.isAssignableFrom(realExceptionClass) && holder.isThrowableMatching(ite)) { return true; } } return false; } public Throwable wrongException(Throwable ite) { if (!hasExpectedClasses()) { return ite; } if (holder.isThrowableMatching(ite)) { return new TestException("Expected exception of " + getExpectedExceptionsPluralize() + " but got " + ite, ite); } else { return new TestException(holder.getWrongExceptionMessage(ite), ite); } } public TestException noException(ITestNGMethod testMethod) { if (!hasExpectedClasses()) { return null; } return new TestException("Method " + testMethod + " should have thrown an exception of " + getExpectedExceptionsPluralize()); } private boolean hasExpectedClasses() { return expectedClasses != null && expectedClasses.length > 0; } private String getExpectedExceptionsPluralize() { StringBuilder sb = new StringBuilder(); if (expectedClasses.length > 1) { sb.append("any of types "); sb.append(Arrays.toString(expectedClasses)); } else { sb.append("type "); sb.append(expectedClasses[0]); } return sb.toString(); } } testng-6.9.12/src/main/java/org/testng/internal/OverrideProcessor.java0000644000175000017500000000226412732165123025312 0ustar eugeneeugenepackage org.testng.internal; import org.testng.xml.IPostProcessor; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.util.Arrays; import java.util.Collection; /** * Override the groups included in the XML file with groups specified on the command line. * * @author Cedric Beust */ public class OverrideProcessor implements IPostProcessor { private String[] m_groups; private String[] m_excludedGroups; public OverrideProcessor(String[] groups, String[] excludedGroups) { m_groups = groups; m_excludedGroups = excludedGroups; } @Override public Collection process(Collection suites) { for (XmlSuite s : suites) { if (m_groups != null && m_groups.length > 0) { for (XmlTest t : s.getTests()) { t.getIncludedGroups().clear(); t.getIncludedGroups().addAll(Arrays.asList(m_groups)); } } if (m_excludedGroups != null && m_excludedGroups.length > 0) { for (XmlTest t : s.getTests()) { t.getExcludedGroups().clear(); t.getExcludedGroups().addAll(Arrays.asList(m_excludedGroups)); } } } return suites; } } testng-6.9.12/src/main/java/org/testng/internal/EclipseInterface.java0000644000175000017500000000131712732165123025036 0ustar eugeneeugenepackage org.testng.internal; /** * Symbols in this class are used by the Eclipse plug-in, do not modify them * without updating the plug-in as well. * * @author Cedric Beust * @since Aug 25, 2012 */ public class EclipseInterface { public static final Character OPENING_CHARACTER = '['; public static final Character CLOSING_CHARACTER = ']'; public static final String ASSERT_LEFT = "expected " + OPENING_CHARACTER; public static final String ASSERT_LEFT2 = "expected not same " + OPENING_CHARACTER; public static final String ASSERT_MIDDLE = CLOSING_CHARACTER + " but found " + OPENING_CHARACTER; public static final String ASSERT_RIGHT = Character.toString(CLOSING_CHARACTER); } testng-6.9.12/src/main/java/org/testng/internal/SuiteRunnerMap.java0000644000175000017500000000132112732165123024545 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ISuite; import org.testng.TestNGException; import org.testng.collections.Maps; import org.testng.xml.XmlSuite; import java.util.Collection; import java.util.Map; public class SuiteRunnerMap { private Map m_map = Maps.newHashMap(); public void put(XmlSuite xmlSuite, ISuite suite) { final String name = xmlSuite.getName(); if (m_map.containsKey(name)) { throw new TestNGException("SuiteRunnerMap already have runner for suite " + name); } m_map.put(name, suite); } public ISuite get(XmlSuite xmlSuite) { return m_map.get(xmlSuite.getName()); } public Collection values() { return m_map.values(); } } testng-6.9.12/src/main/java/org/testng/internal/ResultMap.java0000755000175000017500000000323712732165123023553 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IResultMap; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.collections.Objects; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class ResultMap implements IResultMap { /** * */ private static final long serialVersionUID = 80134376515999093L; private Map m_map = new ConcurrentHashMap<>(); @Override public void addResult(ITestResult result, ITestNGMethod method) { m_map.put(result, method); } @Override public Set getResults(ITestNGMethod method) { Set result = new HashSet<>(); for (Map.Entry entry : m_map.entrySet()) { if (entry.getValue().equals(method)) { result.add(entry.getKey()); } } return result; } @Override public void removeResult(ITestNGMethod m) { for (Entry entry : m_map.entrySet()) { if (entry.getValue().equals(m)) { m_map.remove(entry.getKey()); return; } } } @Override public void removeResult(ITestResult r) { m_map.remove(r); } @Override public Set getAllResults() { return m_map.keySet(); } @Override public int size() { return m_map.size(); } @Override public Collection getAllMethods() { return m_map.values(); } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("map", m_map) .toString(); } } testng-6.9.12/src/main/java/org/testng/internal/IConfiguration.java0000644000175000017500000000142412732165123024550 0ustar eugeneeugenepackage org.testng.internal; import org.testng.*; import org.testng.internal.annotations.IAnnotationFinder; import java.util.List; public interface IConfiguration { IAnnotationFinder getAnnotationFinder(); void setAnnotationFinder(IAnnotationFinder finder); ITestObjectFactory getObjectFactory(); void setObjectFactory(ITestObjectFactory m_objectFactory); IHookable getHookable(); void setHookable(IHookable h); IConfigurable getConfigurable(); void setConfigurable(IConfigurable c); List getExecutionListeners(); void addExecutionListener(IExecutionListener l); List getConfigurationListeners(); void addConfigurationListener(IConfigurationListener cl); List getAlterSuiteListeners(); } testng-6.9.12/src/main/java/org/testng/internal/TestMethodWorker.java0000644000175000017500000002257112732165123025110 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ClassMethodMap; import org.testng.IClassListener; import org.testng.IMethodInstance; import org.testng.ITestClass; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; import org.testng.collections.Lists; import org.testng.internal.thread.ThreadUtil; import org.testng.internal.thread.graph.IWorker; import org.testng.xml.XmlSuite; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * FIXME: reduce contention when this class is used through parallel invocation due to * invocationCount and threadPoolSize by not invoking the @BeforeClass and @AfterClass * which are already invoked on the original method. * * This class implements Runnable and will invoke the ITestMethod passed in its * constructor on its run() method. * * @author Cedric Beust * @author Alexandru Popescu */ public class TestMethodWorker implements IWorker { // Map of the test methods and their associated instances // It has to be a set because the same method can be passed several times // and associated to a different instance private IMethodInstance[] m_methodInstances; private final IInvoker m_invoker; private final Map m_parameters; private final XmlSuite m_suite; private List m_testResults = Lists.newArrayList(); private final ConfigurationGroupMethods m_groupMethods; private final ClassMethodMap m_classMethodMap; private final ITestContext m_testContext; private final List m_listeners; public TestMethodWorker(IInvoker invoker, IMethodInstance[] testMethods, XmlSuite suite, Map parameters, ConfigurationGroupMethods groupMethods, ClassMethodMap classMethodMap, ITestContext testContext, List listeners) { m_invoker = invoker; m_methodInstances = testMethods; m_suite = suite; m_parameters = parameters; m_groupMethods = groupMethods; m_classMethodMap = classMethodMap; m_testContext = testContext; m_listeners = listeners; } /** * Retrieves the maximum specified timeout of all ITestNGMethods to * be run. * * @return the max timeout or 0 if no timeout was specified */ @Override public long getTimeOut() { long result = 0; for (IMethodInstance mi : m_methodInstances) { ITestNGMethod tm = mi.getMethod(); if (tm.getTimeOut() > result) { result = tm.getTimeOut(); } } return result; } @Override public String toString() { StringBuilder result = new StringBuilder("[Worker thread:" + Thread.currentThread().getId() + " priority:" + getPriority() + " "); for (IMethodInstance m : m_methodInstances) { result.append(m.getMethod()).append(" "); } result.append("]"); return result.toString(); } /** * Run all the ITestNGMethods passed in through the constructor. * * @see java.lang.Runnable#run() */ @Override public void run() { for (IMethodInstance testMthdInst : m_methodInstances) { ITestNGMethod testMethod = testMthdInst.getMethod(); ITestClass testClass = testMethod.getTestClass(); invokeBeforeClassMethods(testClass, testMthdInst); // Invoke test method try { invokeTestMethods(testMethod, testMthdInst.getInstance(), m_testContext); } finally { invokeAfterClassMethods(testClass, testMthdInst); } } } protected void invokeTestMethods(ITestNGMethod tm, Object instance, ITestContext testContext) { // Potential bug here: we look up the method index of tm among all // the test methods (not very efficient) but if this method appears // several times and these methods are run in parallel, the results // are unpredictable... Need to think about this more (and make it // more efficient) List testResults = m_invoker.invokeTestMethods(tm, m_suite, m_parameters, m_groupMethods, instance, testContext); if (testResults != null) { m_testResults.addAll(testResults); } } /** * Invoke the @BeforeClass methods if not done already * @param testClass * @param mi */ protected void invokeBeforeClassMethods(ITestClass testClass, IMethodInstance mi) { // if no BeforeClass than return immediately // used for parallel case when BeforeClass were already invoked if (m_classMethodMap == null) { return; } // the whole invocation must be synchronized as other threads must // get a full initialized test object (not the same for @After) Map> invokedBeforeClassMethods = m_classMethodMap.getInvokedBeforeClassMethods(); synchronized(testClass) { Set instances= invokedBeforeClassMethods.get(testClass); if(null == instances) { instances= new HashSet<>(); invokedBeforeClassMethods.put(testClass, instances); } for(Object instance: mi.getInstances()) { if (! instances.contains(instance)) { instances.add(instance); for (IClassListener listener : m_listeners) { listener.onBeforeClass(testClass); } m_invoker.invokeConfigurations(testClass, testClass.getBeforeClassMethods(), m_suite, m_parameters, null, /* no parameter values */ instance); } } } } /** * Invoke the @AfterClass methods if not done already * @param testClass * @param mi */ protected void invokeAfterClassMethods(ITestClass testClass, IMethodInstance mi) { // if no BeforeClass than return immediately // used for parallel case when BeforeClass were already invoked if (m_classMethodMap == null) { return; } // // Invoke after class methods if this test method is the last one // List invokeInstances= Lists.newArrayList(); ITestNGMethod tm= mi.getMethod(); if (m_classMethodMap.removeAndCheckIfLast(tm, mi.getInstance())) { Map> invokedAfterClassMethods = m_classMethodMap.getInvokedAfterClassMethods(); synchronized(invokedAfterClassMethods) { Set instances = invokedAfterClassMethods.get(testClass); if(null == instances) { instances= new HashSet<>(); invokedAfterClassMethods.put(testClass, instances); } for(Object inst: mi.getInstances()) { if(! instances.contains(inst)) { invokeInstances.add(inst); } } } for (IClassListener listener : m_listeners) { listener.onAfterClass(testClass); } for(Object inst: invokeInstances) { m_invoker.invokeConfigurations(testClass, testClass.getAfterClassMethods(), m_suite, m_parameters, null, /* no parameter values */ inst); } } } protected int indexOf(ITestNGMethod tm, ITestNGMethod[] allTestMethods) { for (int i = 0; i < allTestMethods.length; i++) { if (allTestMethods[i] == tm) { return i; } } return -1; } public List getTestResults() { return m_testResults; } private void ppp(String s) { Utils.log("TestMethodWorker", 2, ThreadUtil.currentThreadInfo() + ":" + s); } @Override public List getTasks() { List result = Lists.newArrayList(); for (IMethodInstance m : m_methodInstances) { result.add(m.getMethod()); } return result; } @Override public int compareTo(IWorker other) { return getPriority() - other.getPriority(); } /** * The priority of a worker is the priority of the first method it's going to run. */ @Override public int getPriority() { return m_methodInstances.length > 0 ? m_methodInstances[0].getMethod().getPriority() : 0; } } /** * Extends {@code TestMethodWorker} and is used to work on only a single method * instance */ class SingleTestMethodWorker extends TestMethodWorker { private static final ConfigurationGroupMethods EMPTY_GROUP_METHODS = new ConfigurationGroupMethods(new ITestNGMethod[0], new HashMap>(), new HashMap>()); public SingleTestMethodWorker(IInvoker invoker, MethodInstance testMethod, XmlSuite suite, Map parameters, ITestContext testContext, List listeners) { super(invoker, new MethodInstance[] {testMethod}, suite, parameters, EMPTY_GROUP_METHODS, null, testContext, listeners); } } testng-6.9.12/src/main/java/org/testng/internal/ConstructorOrMethod.java0000644000175000017500000000424312732165123025621 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Constructor; import java.lang.reflect.Method; /** * Encapsulation of either a method or a constructor. * * @author Cedric Beust */ public class ConstructorOrMethod { private Method m_method; private Constructor m_constructor; private boolean m_enabled = true; public ConstructorOrMethod(Method m) { m_method = m; } public ConstructorOrMethod(Constructor c) { m_constructor = c; } public Class getDeclaringClass() { return getMethod() != null ? getMethod().getDeclaringClass() : getConstructor().getDeclaringClass(); } public String getName() { return getMethod() != null ? getMethod().getName() : getConstructor().getName(); } public Class[] getParameterTypes() { return getMethod() != null ? getMethod().getParameterTypes() : getConstructor().getParameterTypes(); } public Method getMethod() { return m_method; } public Constructor getConstructor() { return m_constructor; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getConstructor() == null) ? 0 : getConstructor().hashCode()); result = prime * result + ((getMethod() == null) ? 0 : getMethod().hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ConstructorOrMethod other = (ConstructorOrMethod) obj; if (getConstructor() == null) { if (other.getConstructor() != null) return false; } else if (!getConstructor().equals(other.getConstructor())) return false; if (getMethod() == null) { if (other.getMethod() != null) return false; } else if (!getMethod().equals(other.getMethod())) return false; return true; } public void setEnabled(boolean enabled) { m_enabled = enabled; } public boolean getEnabled() { return m_enabled; } @Override public String toString() { if (m_method != null) return m_method.toString(); else return m_constructor.toString(); } } testng-6.9.12/src/main/java/org/testng/internal/NoOpTestClass.java0000755000175000017500000001223012732165123024331 0ustar eugeneeugenepackage org.testng.internal; import org.testng.ITestClass; import org.testng.ITestNGMethod; import org.testng.xml.XmlClass; import org.testng.xml.XmlTest; public class NoOpTestClass implements ITestClass { private static final long serialVersionUID = -4544061405329040593L; protected Class m_testClass= null; // Test methods protected ITestNGMethod[] m_beforeClassMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_beforeTestMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_testMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_afterClassMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_afterTestMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_beforeSuiteMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_afterSuiteMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_beforeTestConfMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_afterTestConfMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_beforeGroupsMethods = new ITestNGMethod[0]; protected ITestNGMethod[] m_afterGroupsMethods = new ITestNGMethod[0]; private transient Object[] m_instances; private long[] m_instanceHashes; private XmlTest m_xmlTest; private XmlClass m_xmlClass; protected NoOpTestClass() { } public NoOpTestClass(ITestClass testClass) { m_testClass= testClass.getRealClass(); m_beforeSuiteMethods= testClass.getBeforeSuiteMethods(); m_beforeTestConfMethods= testClass.getBeforeTestConfigurationMethods(); m_beforeGroupsMethods= testClass.getBeforeGroupsMethods(); m_beforeClassMethods= testClass.getBeforeClassMethods(); m_beforeTestMethods= testClass.getBeforeTestMethods(); m_afterSuiteMethods= testClass.getAfterSuiteMethods(); m_afterTestConfMethods= testClass.getAfterTestConfigurationMethods(); m_afterGroupsMethods= testClass.getAfterGroupsMethods(); m_afterClassMethods= testClass.getAfterClassMethods(); m_afterTestMethods= testClass.getAfterTestMethods(); m_instances= testClass.getInstances(true); m_instanceHashes= testClass.getInstanceHashCodes(); m_xmlTest = testClass.getXmlTest(); m_xmlClass = testClass.getXmlClass(); } public void setBeforeTestMethods(ITestNGMethod[] beforeTestMethods) { m_beforeTestMethods= beforeTestMethods; } public void setAfterTestMethod(ITestNGMethod[] afterTestMethods) { m_afterTestMethods= afterTestMethods; } /** * @return Returns the afterClassMethods. */ @Override public ITestNGMethod[] getAfterClassMethods() { return m_afterClassMethods; } /** * @return Returns the afterTestMethods. */ @Override public ITestNGMethod[] getAfterTestMethods() { return m_afterTestMethods; } /** * @return Returns the beforeClassMethods. */ @Override public ITestNGMethod[] getBeforeClassMethods() { return m_beforeClassMethods; } /** * @return Returns the beforeTestMethods. */ @Override public ITestNGMethod[] getBeforeTestMethods() { return m_beforeTestMethods; } /** * @return Returns the testMethods. */ @Override public ITestNGMethod[] getTestMethods() { return m_testMethods; } @Override public ITestNGMethod[] getBeforeSuiteMethods() { return m_beforeSuiteMethods; } @Override public ITestNGMethod[] getAfterSuiteMethods() { return m_afterSuiteMethods; } @Override public ITestNGMethod[] getBeforeTestConfigurationMethods() { return m_beforeTestConfMethods; } @Override public ITestNGMethod[] getAfterTestConfigurationMethods() { return m_afterTestConfMethods; } /** * @return all @Configuration methods that should be invoked before certain groups */ @Override public ITestNGMethod[] getBeforeGroupsMethods() { return m_beforeGroupsMethods; } /** * @return all @Configuration methods that should be invoked after certain groups */ @Override public ITestNGMethod[] getAfterGroupsMethods() { return m_afterGroupsMethods; } @Deprecated @Override public int getInstanceCount() { return m_instances.length; } /** * @see org.testng.ITestClass#getInstanceHashCodes() */ @Override public long[] getInstanceHashCodes() { return m_instanceHashes; } /** * @see org.testng.ITestClass#getInstances(boolean) */ @Override public Object[] getInstances(boolean reuse) { return m_instances; } @Override public String getName() { return m_testClass.getName(); } @Override public Class getRealClass() { return m_testClass; } /** * @see org.testng.IClass#addInstance(java.lang.Object) */ @Override public void addInstance(Object instance) { } public void setTestClass(Class< ? > declaringClass) { m_testClass = declaringClass; } @Override public String getTestName() { // TODO Auto-generated method stub return null; } @Override public XmlTest getXmlTest() { return m_xmlTest; } @Override public XmlClass getXmlClass() { return m_xmlClass; } } testng-6.9.12/src/main/java/org/testng/internal/Attributes.java0000644000175000017500000000153212732165123023756 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IAttributes; import org.testng.collections.Maps; import java.util.Map; import java.util.Set; /** * Simple implementation of IAttributes. * * @author cbeust@google.com (Cedric Beust), March 16th, 2010 */ public class Attributes implements IAttributes { /** * */ private static final long serialVersionUID = 6701159979281335152L; private Map m_attributes = Maps.newHashMap(); @Override public Object getAttribute(String name) { return m_attributes.get(name); } @Override public Set getAttributeNames() { return m_attributes.keySet(); } @Override public void setAttribute(String name, Object value) { m_attributes.put(name, value); } @Override public Object removeAttribute(String name) { return m_attributes.remove(name); } } testng-6.9.12/src/main/java/org/testng/internal/MethodInstance.java0000755000175000017500000000635212732165123024545 0ustar eugeneeugenepackage org.testng.internal; import org.testng.IMethodInstance; import org.testng.ITestNGMethod; import org.testng.collections.Objects; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlTest; import java.util.Comparator; import java.util.List; public class MethodInstance implements IMethodInstance { private ITestNGMethod m_method; public MethodInstance(ITestNGMethod method) { m_method = method; } @Override public ITestNGMethod getMethod() { return m_method; } @Override public Object[] getInstances() { return new Object[] { getInstance() }; } @Override public Object getInstance() { return m_method.getInstance(); } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("method", m_method) .add("instance", getInstance()) .toString(); } public static final Comparator SORT_BY_INDEX = new Comparator() { @Override public int compare(IMethodInstance o1, IMethodInstance o2) { // If the two methods are in different XmlTest test1 = o1.getMethod().getTestClass().getXmlTest(); XmlTest test2 = o2.getMethod().getTestClass().getXmlTest(); // If the two methods are not in the same , we can't compare them if (! test1.getName().equals(test2.getName())) { return 0; } int result = 0; // If the two methods are in the same , compare them by their method // index, otherwise compare them with their class index. XmlClass class1 = o1.getMethod().getTestClass().getXmlClass(); XmlClass class2 = o2.getMethod().getTestClass().getXmlClass(); // This can happen if these classes came from a @Factory, in which case, they // don't have an associated XmlClass if (class1 == null || class2 == null) { if (class1 != null) return -1; if (class2 != null) return 1; return 0; } if (! class1.getName().equals(class2.getName())) { int index1 = class1.getIndex(); int index2 = class2.getIndex(); result = index1 - index2; } else { XmlInclude include1 = findXmlInclude(class1.getIncludedMethods(), o1.getMethod().getMethodName()); XmlInclude include2 = findXmlInclude(class2.getIncludedMethods(), o2.getMethod().getMethodName()); if (include1 != null && include2 != null) { result = include1.getIndex() - include2.getIndex(); } } return result; } private XmlInclude findXmlInclude(List includedMethods, String methodName) { for (XmlInclude xi : includedMethods) { if (xi.getName().equals(methodName)) { return xi; } } return null; } }; // public static final Comparator SORT_BY_CLASS // = new Comparator() { // public int compare(IMethodInstance o1, IMethodInstance o2) { // int result= o1.getMethod().getTestClass().getName() // .compareTo(o2.getMethod().getTestClass().getName()); // return result; // } // }; } testng-6.9.12/src/main/java/org/testng/internal/ClassImpl.java0000755000175000017500000001445212732165123023527 0ustar eugeneeugenepackage org.testng.internal; import static org.testng.internal.Utils.isStringNotEmpty; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Stage; import org.testng.IClass; import org.testng.IModuleFactory; import org.testng.ISuite; import org.testng.ITest; import org.testng.ITestContext; import org.testng.ITestObjectFactory; import org.testng.TestNGException; import org.testng.annotations.Guice; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Lists; import org.testng.collections.Objects; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlClass; import org.testng.xml.XmlTest; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.util.List; import java.util.Map; /** * Implementation of an IClass. * * @author Cedric Beust */ public class ClassImpl implements IClass { private static final long serialVersionUID = 1118178273317520344L; transient private Class m_class = null; transient private Object m_defaultInstance = null; private XmlTest m_xmlTest = null; transient private IAnnotationFinder m_annotationFinder = null; transient private List m_instances = Lists.newArrayList(); transient private Map m_classes = null; private int m_instanceCount; private long[] m_instanceHashCodes; private transient Object m_instance; private ITestObjectFactory m_objectFactory; private String m_testName = null; private XmlClass m_xmlClass; private ITestContext m_testContext; private final boolean m_hasParentModule; public ClassImpl(ITestContext context, Class cls, XmlClass xmlClass, Object instance, Map classes, XmlTest xmlTest, IAnnotationFinder annotationFinder, ITestObjectFactory objectFactory) { m_testContext = context; m_class = cls; m_classes = classes; m_xmlClass = xmlClass; m_xmlTest = xmlTest; m_annotationFinder = annotationFinder; m_instance = instance; m_objectFactory = objectFactory; if (instance instanceof ITest) { m_testName = ((ITest) instance).getTestName(); } if (m_testName == null) { ITestAnnotation annotation = m_annotationFinder.findAnnotation(cls, ITestAnnotation.class); if (annotation != null && !annotation.getTestName().isEmpty()) { m_testName = annotation.getTestName(); } } m_hasParentModule = isStringNotEmpty(m_testContext.getSuite().getParentModule()); } private static void ppp(String s) { System.out.println("[ClassImpl] " + s); } @Override public String getTestName() { return m_testName; } @Override public String getName() { return m_class.getName(); } @Override public Class getRealClass() { return m_class; } @Deprecated @Override public int getInstanceCount() { return m_instanceCount; } @Override public long[] getInstanceHashCodes() { return m_instanceHashCodes; } @Override public XmlTest getXmlTest() { return m_xmlTest; } @Override public XmlClass getXmlClass() { return m_xmlClass; } private Object getDefaultInstance() { if (m_defaultInstance == null) { if (m_instance != null) { m_defaultInstance = m_instance; } else { Object instance = getInstanceFromGuice(); if (instance != null) { m_defaultInstance = instance; } else { m_defaultInstance = ClassHelper.createInstance(m_class, m_classes, m_xmlTest, m_annotationFinder, m_objectFactory); } } } return m_defaultInstance; } /** * @return an instance from Guice if @Test(guiceModule) attribute was found, null otherwise */ @SuppressWarnings("unchecked") private Object getInstanceFromGuice() { Injector injector = m_testContext.getInjector(this); if (injector == null) return null; return injector.getInstance(m_class); } public Injector getParentInjector() { ISuite suite = m_testContext.getSuite(); // Reuse the previous parent injector, if any Injector injector = suite.getParentInjector(); if (injector == null) { String stageString = suite.getGuiceStage(); Stage stage; if (isStringNotEmpty(stageString)) { stage = Stage.valueOf(stageString); } else { stage = Stage.DEVELOPMENT; } if (m_hasParentModule) { Class parentModule = (Class) ClassHelper.forName(suite.getParentModule()); if (parentModule == null) { throw new TestNGException("Cannot load parent Guice module class: " + parentModule); } Module module = newModule(parentModule); injector = com.google.inject.Guice.createInjector(stage, module); } else { injector = com.google.inject.Guice.createInjector(stage); } suite.setParentInjector(injector); } return injector; } private Module newModule(Class module) { try { Constructor moduleConstructor = module.getDeclaredConstructor(ITestContext.class); return ClassHelper.newInstance(moduleConstructor, m_testContext); } catch (NoSuchMethodException e) { return ClassHelper.newInstance(module); } } @Override public Object[] getInstances(boolean create) { Object[] result = {}; if (m_xmlTest.isJUnit()) { if (create) { result = new Object[] { ClassHelper.createInstance(m_class, m_classes, m_xmlTest, m_annotationFinder, m_objectFactory) }; } } else { Object defaultInstance = getDefaultInstance(); if (defaultInstance != null) { result = new Object[]{defaultInstance}; } } if (m_instances.size() > 0) { result = m_instances.toArray(new Object[m_instances.size()]); } m_instanceCount = m_instances.size(); m_instanceHashCodes = new long[m_instanceCount]; for (int i = 0; i < m_instanceCount; i++) { m_instanceHashCodes[i] = m_instances.get(i).hashCode(); } return result; } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("class", m_class.getName()) .toString(); } @Override public void addInstance(Object instance) { m_instances.add(instance); } } testng-6.9.12/src/main/java/org/testng/internal/TestNGMethodFinder.java0000755000175000017500000002050312732165123025267 0ustar eugeneeugenepackage org.testng.internal; import java.lang.reflect.Method; import java.util.List; import java.util.Set; import org.testng.ITestMethodFinder; import org.testng.ITestNGMethod; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Lists; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.xml.XmlTest; /** * The default strategy for finding test methods: look up * annotations @Test in front of methods. * * @author Cedric Beust, May 3, 2004 * @author Alexandru Popescu */ public class TestNGMethodFinder implements ITestMethodFinder { private static final int BEFORE_SUITE = 1; private static final int AFTER_SUITE = 2; private static final int BEFORE_TEST = 3; private static final int AFTER_TEST = 4; private static final int BEFORE_CLASS = 5; private static final int AFTER_CLASS = 6; private static final int BEFORE_TEST_METHOD = 7; private static final int AFTER_TEST_METHOD = 8; private static final int BEFORE_GROUPS = 9; private static final int AFTER_GROUPS = 10; private RunInfo m_runInfo = null; private IAnnotationFinder m_annotationFinder = null; public TestNGMethodFinder(RunInfo runInfo, IAnnotationFinder annotationFinder) { m_runInfo = runInfo; m_annotationFinder = annotationFinder; } @Override public ITestNGMethod[] getTestMethods(Class clazz, XmlTest xmlTest) { return AnnotationHelper.findMethodsWithAnnotation( clazz, ITestAnnotation.class, m_annotationFinder, xmlTest); } @Override public ITestNGMethod[] getBeforeClassMethods(Class cls) { return findConfiguration(cls, BEFORE_CLASS); } @Override public ITestNGMethod[] getAfterClassMethods(Class cls) { return findConfiguration(cls, AFTER_CLASS); } @Override public ITestNGMethod[] getBeforeTestMethods(Class cls) { return findConfiguration(cls, BEFORE_TEST_METHOD); } @Override public ITestNGMethod[] getAfterTestMethods(Class cls) { return findConfiguration(cls, AFTER_TEST_METHOD); } @Override public ITestNGMethod[] getBeforeSuiteMethods(Class cls) { return findConfiguration(cls, BEFORE_SUITE); } @Override public ITestNGMethod[] getAfterSuiteMethods(Class cls) { return findConfiguration(cls, AFTER_SUITE); } @Override public ITestNGMethod[] getBeforeTestConfigurationMethods(Class clazz) { return findConfiguration(clazz, BEFORE_TEST); } @Override public ITestNGMethod[] getAfterTestConfigurationMethods(Class clazz) { return findConfiguration(clazz, AFTER_TEST); } @Override public ITestNGMethod[] getBeforeGroupsConfigurationMethods(Class clazz) { return findConfiguration(clazz, BEFORE_GROUPS); } @Override public ITestNGMethod[] getAfterGroupsConfigurationMethods(Class clazz) { return findConfiguration(clazz, AFTER_GROUPS); } private ITestNGMethod[] findConfiguration(final Class clazz, final int configurationType) { List vResult = Lists.newArrayList(); Set methods = ClassHelper.getAvailableMethods(clazz); for (Method m : methods) { IConfigurationAnnotation configuration = AnnotationHelper.findConfiguration(m_annotationFinder, m); if (null == configuration) { continue; } boolean create = false; boolean isBeforeSuite = false; boolean isAfterSuite = false; boolean isBeforeTest = false; boolean isAfterTest = false; boolean isBeforeClass = false; boolean isAfterClass = false; boolean isBeforeTestMethod = false; boolean isAfterTestMethod = false; String[] beforeGroups = null; String[] afterGroups = null; switch(configurationType) { case BEFORE_SUITE: create = configuration.getBeforeSuite(); isBeforeSuite = true; break; case AFTER_SUITE: create = configuration.getAfterSuite(); isAfterSuite = true; break; case BEFORE_TEST: create = configuration.getBeforeTest(); isBeforeTest = true; break; case AFTER_TEST: create = configuration.getAfterTest(); isAfterTest = true; break; case BEFORE_CLASS: create = configuration.getBeforeTestClass(); isBeforeClass = true; break; case AFTER_CLASS: create = configuration.getAfterTestClass(); isAfterClass = true; break; case BEFORE_TEST_METHOD: create = configuration.getBeforeTestMethod(); isBeforeTestMethod = true; break; case AFTER_TEST_METHOD: create = configuration.getAfterTestMethod(); isAfterTestMethod = true; break; case BEFORE_GROUPS: beforeGroups = configuration.getBeforeGroups(); create = beforeGroups.length > 0; isBeforeTestMethod = true; break; case AFTER_GROUPS: afterGroups = configuration.getAfterGroups(); create = afterGroups.length > 0; isBeforeTestMethod = true; break; default: throw new AssertionError("Unexpected value: " + configurationType); } if(create) { addConfigurationMethod(clazz, vResult, m, isBeforeSuite, isAfterSuite, isBeforeTest, isAfterTest, isBeforeClass, isAfterClass, isBeforeTestMethod, isAfterTestMethod, beforeGroups, afterGroups, null); /* @@@ */ } } List excludedMethods = Lists.newArrayList(); boolean unique = configurationType == BEFORE_SUITE || configurationType == AFTER_SUITE; ITestNGMethod[] tmResult = MethodHelper.collectAndOrderMethods(Lists.newArrayList(vResult), false /* forTests */, m_runInfo, m_annotationFinder, unique, excludedMethods); return tmResult; } private void addConfigurationMethod(Class clazz, List results, Method method, boolean isBeforeSuite, boolean isAfterSuite, boolean isBeforeTest, boolean isAfterTest, boolean isBeforeClass, boolean isAfterClass, boolean isBeforeTestMethod, boolean isAfterTestMethod, String[] beforeGroups, String[] afterGroups, Object instance) { if(method.getDeclaringClass().isAssignableFrom(clazz)) { ITestNGMethod confMethod = new ConfigurationMethod(new ConstructorOrMethod(method), m_annotationFinder, isBeforeSuite, isAfterSuite, isBeforeTest, isAfterTest, isBeforeClass, isAfterClass, isBeforeTestMethod, isAfterTestMethod, beforeGroups, afterGroups, instance); results.add(confMethod); } } } testng-6.9.12/src/main/java/org/testng/TimeBombSkipException.java0000755000175000017500000002070612732165123024227 0ustar eugeneeugenepackage org.testng; import java.io.PrintStream; import java.io.PrintWriter; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * A {@link SkipException} extension that transforms a skipped method * into a failed method based on a time trigger. *

* By default the time format is yyyy/MM/dd (according to {@code SimpleDateFormat}). * You can customize this by using the specialized constructors. Suppported date * formats are according to the {@code SimpleDateFormat}. * * @author Alex Popescu * @since 5.6 */ public class TimeBombSkipException extends SkipException { private static final long serialVersionUID = -8599821478834048537L; private static final SimpleDateFormat SDF= new SimpleDateFormat("yyyy/MM/dd"); private Calendar m_expireDate; private DateFormat m_inFormat= SDF; private DateFormat m_outFormat= SDF; /** * Creates a {@code TimeBombedSkipException} using the expirationDate. * The format used for date comparison is yyyy/MM/dd * @param msg exception message * @param expirationDate time limit after which the SKIP becomes a FAILURE */ public TimeBombSkipException(String msg, Date expirationDate) { super(msg); initExpireDate(expirationDate); } /** * Creates a {@code TimeBombedSkipException} using the expirationDate. * The format parameter wiil be used for performing the time comparison. * @param msg exception message * @param expirationDate time limit after which the SKIP becomes a FAILURE * @param format format for the time comparison */ public TimeBombSkipException(String msg, Date expirationDate, String format) { super(msg); m_inFormat= new SimpleDateFormat(format); m_outFormat= new SimpleDateFormat(format); initExpireDate(expirationDate); } /** * Creates a {@code TimeBombedSkipException} using the date * in the format yyyy/MM/dd. * @param msg exception message * @param date time limit after which the SKIP becomes a FAILURE */ public TimeBombSkipException(String msg, String date) { super(msg); initExpireDate(date); } /** * Creates a {@code TimeBombedSkipException} using the date * in the specified format format. The same format is used * when performing the time comparison. * @param msg exception message * @param date time limit after which the SKIP becomes a FAILURE * @param format format of the passed in date and of the time comparison */ public TimeBombSkipException(String msg, String date, String format) { this(msg, date, format, format); } /** * Creates a {@code TimeBombedSkipException} using the date * in the specified format inFormat. The outFormat will be * used to perform the time comparison and display. * @param msg exception message * @param date time limit after which the SKIP becomes a FAILURE * @param inFormat format of the passed in date * @param outFormat format of the time comparison */ public TimeBombSkipException(String msg, String date, String inFormat, String outFormat) { super(msg); m_inFormat= new SimpleDateFormat(inFormat); m_outFormat= new SimpleDateFormat(outFormat); initExpireDate(date); } /** * Creates a {@code TimeBombedSkipException} using the expirationDate. * The format used for date comparison is yyyy/MM/dd * @param msg exception message * @param expirationDate time limit after which the SKIP becomes a FAILURE * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public TimeBombSkipException(String msg, Date expirationDate, Throwable cause) { super(msg, cause); initExpireDate(expirationDate); } /** * Creates a {@code TimeBombedSkipException} using the expirationDate. * The format parameter wiil be used for performing the time comparison. * @param msg exception message * @param expirationDate time limit after which the SKIP becomes a FAILURE * @param format format for the time comparison * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public TimeBombSkipException(String msg, Date expirationDate, String format, Throwable cause) { super(msg, cause); m_inFormat= new SimpleDateFormat(format); m_outFormat= new SimpleDateFormat(format); initExpireDate(expirationDate); } /** * Creates a {@code TimeBombedSkipException} using the date * in the format yyyy/MM/dd. * @param msg exception message * @param date time limit after which the SKIP becomes a FAILURE * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public TimeBombSkipException(String msg, String date, Throwable cause) { super(msg, cause); initExpireDate(date); } /** * Creates a {@code TimeBombedSkipException} using the date * in the specified format format. The same format is used * when performing the time comparison. * @param msg exception message * @param date time limit after which the SKIP becomes a FAILURE * @param format format of the passed in date and of the time comparison * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public TimeBombSkipException(String msg, String date, String format, Throwable cause) { this(msg, date, format, format, cause); } /** * Creates a {@code TimeBombedSkipException} using the date * in the specified format inFormat. The outFormat will be * used to perform the time comparison and display. * @param msg exception message * @param date time limit after which the SKIP becomes a FAILURE * @param inFormat format of the passed in date * @param outFormat format of the time comparison * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method). (A null value is * permitted, and indicates that the cause is nonexistent or * unknown.) */ public TimeBombSkipException(String msg, String date, String inFormat, String outFormat, Throwable cause) { super(msg, cause); m_inFormat= new SimpleDateFormat(inFormat); m_outFormat= new SimpleDateFormat(outFormat); initExpireDate(date); } private void initExpireDate(Date expireDate) { m_expireDate= Calendar.getInstance(); m_expireDate.setTime(expireDate); } private void initExpireDate(String date) { try { // SimpleDateFormat is not thread-safe, and m_inFormat // is, by default, connected to the static SDF variable synchronized( m_inFormat ){ Date d = m_inFormat.parse(date); initExpireDate(d); } } catch(ParseException pex) { throw new TestNGException("Cannot parse date:" + date + " using pattern: " + m_inFormat, pex); } } @Override public boolean isSkip() { if (null == m_expireDate) { return false; } try { Calendar now= Calendar.getInstance(); Date nowDate= m_inFormat.parse(m_inFormat.format(now.getTime())); now.setTime(nowDate); return !now.after(m_expireDate); } catch(ParseException pex) { throw new TestNGException("Cannot compare dates."); } } @Override public String getMessage() { if(isSkip()) { return super.getMessage(); } else { return super.getMessage() + "; Test must have been enabled by: " + m_outFormat.format(m_expireDate.getTime()); } } @Override public void printStackTrace(PrintStream s) { reduceStackTrace(); super.printStackTrace(s); } @Override public void printStackTrace(PrintWriter s) { reduceStackTrace(); super.printStackTrace(s); } } testng-6.9.12/src/main/java/org/testng/IMethodInstance.java0000755000175000017500000000044312732165123023035 0ustar eugeneeugenepackage org.testng; /** * This interface captures a test method along with all the instances it should * be run on. */ public interface IMethodInstance { ITestNGMethod getMethod(); /** * @deprecated Use getInstance() */ Object[] getInstances(); Object getInstance(); } testng-6.9.12/src/main/java/org/testng/ITestObjectFactory.java0000644000175000017500000000033012732165123023516 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; /** * Parent interface of all the object factories. * * @author Cedric Beust */ public interface ITestObjectFactory extends Serializable { } testng-6.9.12/src/main/java/org/testng/CommandLineArgs.java0000644000175000017500000001446112732165123023024 0ustar eugeneeugenepackage org.testng; import com.beust.jcommander.Parameter; import com.beust.jcommander.converters.CommaParameterSplitter; import org.testng.collections.Lists; import org.testng.xml.XmlSuite; import java.util.ArrayList; import java.util.List; public class CommandLineArgs { @Parameter(description = "The XML suite files to run") public List suiteFiles = Lists.newArrayList(); public static final String LOG = "-log"; public static final String VERBOSE = "-verbose"; @Parameter(names = { LOG, VERBOSE }, description = "Level of verbosity") public Integer verbose; public static final String GROUPS = "-groups"; @Parameter(names = GROUPS, description = "Comma-separated list of group names to be run") public String groups; public static final String EXCLUDED_GROUPS = "-excludegroups"; @Parameter(names = EXCLUDED_GROUPS, description ="Comma-separated list of group names to " + " exclude") public String excludedGroups; public static final String OUTPUT_DIRECTORY = "-d"; @Parameter(names = OUTPUT_DIRECTORY, description ="Output directory") public String outputDirectory; public static final String JUNIT = "-junit"; @Parameter(names = JUNIT, description ="JUnit mode") public Boolean junit = Boolean.FALSE; public static final String MIXED = "-mixed"; @Parameter(names = MIXED, description ="Mixed mode - autodetect the type of current test" + " and run it with appropriate runner") public Boolean mixed = Boolean.FALSE; public static final String LISTENER = "-listener"; @Parameter(names = LISTENER, description = "List of .class files or list of class names" + " implementing ITestListener or ISuiteListener") public String listener; public static final String METHOD_SELECTORS = "-methodselectors"; @Parameter(names = METHOD_SELECTORS, description = "List of .class files or list of class " + "names implementing IMethodSelector") public String methodSelectors; public static final String OBJECT_FACTORY = "-objectfactory"; @Parameter(names = OBJECT_FACTORY, description = "List of .class files or list of class " + "names implementing ITestRunnerFactory") public String objectFactory; public static final String PARALLEL= "-parallel"; @Parameter(names = PARALLEL, description = "Parallel mode (methods, tests or classes)") public XmlSuite.ParallelMode parallelMode; public static final String CONFIG_FAILURE_POLICY = "-configfailurepolicy"; @Parameter(names = CONFIG_FAILURE_POLICY , description = "Configuration failure policy (skip or continue)") public String configFailurePolicy; public static final String THREAD_COUNT = "-threadcount"; @Parameter(names = THREAD_COUNT, description = "Number of threads to use when running tests " + "in parallel") public Integer threadCount; public static final String DATA_PROVIDER_THREAD_COUNT = "-dataproviderthreadcount"; @Parameter(names = DATA_PROVIDER_THREAD_COUNT, description = "Number of threads to use when " + "running data providers") public Integer dataProviderThreadCount; public static final String SUITE_NAME = "-suitename"; @Parameter(names = SUITE_NAME, description = "Default name of test suite, if not specified " + "in suite definition file or source code") public String suiteName; public static final String TEST_NAME = "-testname"; @Parameter(names = TEST_NAME, description = "Default name of test, if not specified in suite" + "definition file or source code") public String testName; public static final String REPORTER = "-reporter"; @Parameter(names = REPORTER, description = "Extended configuration for custom report listener") public String reporter; public static final String USE_DEFAULT_LISTENERS = "-usedefaultlisteners"; @Parameter(names = USE_DEFAULT_LISTENERS, description = "Whether to use the default listeners") public String useDefaultListeners = "true"; public static final String SKIP_FAILED_INVOCATION_COUNTS = "-skipfailedinvocationcounts"; @Parameter(names = SKIP_FAILED_INVOCATION_COUNTS, hidden = true) public Boolean skipFailedInvocationCounts; public static final String TEST_CLASS = "-testclass"; @Parameter(names = TEST_CLASS, description = "The list of test classes") public String testClass; public static final String TEST_NAMES = "-testnames"; @Parameter(names = TEST_NAMES, description = "The list of test names to run") public String testNames; public static final String TEST_JAR = "-testjar"; @Parameter(names = TEST_JAR, description = "A jar file containing the tests") public String testJar; public static final String XML_PATH_IN_JAR = "-xmlpathinjar"; public static final String XML_PATH_IN_JAR_DEFAULT = "testng.xml"; @Parameter(names = XML_PATH_IN_JAR, description = "The full path to the xml file inside the jar file (only valid if -testjar was specified)") public String xmlPathInJar = XML_PATH_IN_JAR_DEFAULT; public static final String TEST_RUNNER_FACTORY = "-testrunfactory"; @Parameter(names = { TEST_RUNNER_FACTORY, "-testRunFactory" }, description = "The factory used to create tests") public String testRunnerFactory; public static final String PORT = "-port"; @Parameter(names = PORT, description = "The port") public Integer port; public static final String HOST = "-host"; @Parameter(names = HOST, description = "The host", hidden = true) public String host; public static final String METHODS = "-methods"; @Parameter(names = METHODS, description = "Comma separated of test methods", splitter = CommaParameterSplitter.class) public List commandLineMethods = new ArrayList<>(); public static final String SUITE_THREAD_POOL_SIZE = "-suitethreadpoolsize"; public static final Integer SUITE_THREAD_POOL_SIZE_DEFAULT = 1; @Parameter(names = SUITE_THREAD_POOL_SIZE, description = "Size of the thread pool to use" + " to run suites") public Integer suiteThreadPoolSize = SUITE_THREAD_POOL_SIZE_DEFAULT; public static final String RANDOMIZE_SUITES = "-randomizesuites"; @Parameter(names = RANDOMIZE_SUITES, hidden = true, description = "Whether to run suites in same order as specified in XML or not") public Boolean randomizeSuites = Boolean.FALSE; public static final String DEBUG = "-debug"; @Parameter(names = DEBUG, hidden = true, description = "Used to debug TestNG") public Boolean debug = Boolean.FALSE; } testng-6.9.12/src/main/java/org/testng/ITestClass.java0000755000175000017500000000636412732165123022045 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; /** * This class represents a test class: *

    *
  • The test methods *
  • The configuration methods (test and method) *
  • The class file *
* * Note that the methods returned by instances of this class * are expected to be correct at runtime. In other words, * they might differ from what the ITestMethodFinder returned * since ITestClass will take into account the groups being * included and excluded. * * @author Cedric Beust */ public interface ITestClass extends IClass, Serializable { /** * Returns all the applicable test methods. * @return All the applicable test methods. */ ITestNGMethod[] getTestMethods(); /** * Returns all the methods that should be invoked * before a test method is invoked. * @return All the methods that should be invoked * before a test method is invoked. */ ITestNGMethod[] getBeforeTestMethods(); /** * Returns all the methods that should be invoked * after a test method completes. * @return All the methods that should be invoked * after a test method completes. */ ITestNGMethod[] getAfterTestMethods(); /** * Return all the methods that should be invoked * after the test class has been created and before * any of its test methods is invoked. * @return All the methods that should be invoked * after the test class has been created and before * any of its test methods is invoked. */ ITestNGMethod[] getBeforeClassMethods(); /** * Returns all the methods that should be invoked * after all the tests have been run on this class. * @return All the methods that should be invoked * after all the tests have been run on this class. */ ITestNGMethod[] getAfterClassMethods(); /** * Returns All the methods that should be invoked * before the suite is run. * @return All the methods that should be invoked * before the suite is run. */ ITestNGMethod[] getBeforeSuiteMethods(); /** * Returns all the methods that should be invoked * after the suite has run. * @return All the methods that should be invoked * after the suite has run. */ ITestNGMethod[] getAfterSuiteMethods(); /** * Returns all @Configuration methods that should be invoked before any others in the * current test. * @return all @Configuration methods that should be invoked before any others in the current test. */ ITestNGMethod[] getBeforeTestConfigurationMethods(); /** * Returns all @Configuration methods that should be invoked last before any others * in the current test. * @return all @Configuration methods that should be invoked last before any others * in the current test. */ ITestNGMethod[] getAfterTestConfigurationMethods(); /** * Returns all @Configuration methods that should be invoked before certain groups. * @return all @Configuration methods that should be invoked before certain groups. */ ITestNGMethod[] getBeforeGroupsMethods(); /** * Returns all @Configuration methods that should be invoked after certain groups. * @return all @Configuration methods that should be invoked after certain groups. */ ITestNGMethod[] getAfterGroupsMethods(); } testng-6.9.12/src/main/java/org/testng/ClassMethodMap.java0000755000175000017500000000551412732165123022667 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.XmlMethodSelector; import java.util.List; import java.util.Map; import java.util.Set; /** * This class maintains a map of >. * It is used by TestWorkers to determine if the method they just ran * is the last of its class, in which case it's time to invoke all the * afterClass methods. * * @author Alex Popescu */ public class ClassMethodMap { private Map> m_classMap = Maps.newHashMap(); // These two variables are used throughout the workers to keep track // of what beforeClass/afterClass methods have been invoked private Map> m_beforeClassMethods = Maps.newHashMap(); private Map> m_afterClassMethods = Maps.newHashMap(); public ClassMethodMap(List methods, XmlMethodSelector xmlMethodSelector) { for (ITestNGMethod m : methods) { // Only add to the class map methods that are included in the // method selector. We can pass a null context here since the selector // should already have been initialized if (xmlMethodSelector != null){ if (! xmlMethodSelector.includeMethod(null, m, true)) continue; } Object instance = m.getInstance(); List l = m_classMap.get(instance); if (l == null) { l = Lists.newArrayList(); m_classMap.put(instance, l); } l.add(m); } } /** * Remove the method from this map and returns true if it is the last * of its class. */ public synchronized boolean removeAndCheckIfLast(ITestNGMethod m, Object instance) { List l = m_classMap.get(instance); if (l != null) { l.remove(m); // It's the last method of this class if all the methods remaining in the list belong to a // different class for (ITestNGMethod tm : l) { if (tm.getEnabled() && tm.getTestClass().equals(m.getTestClass())) return false; } return true; } else { throw new AssertionError("l should not be null"); } } private Class getMethodClass(ITestNGMethod m) { return m.getTestClass().getRealClass(); } public Map> getInvokedBeforeClassMethods() { return m_beforeClassMethods; } public Map> getInvokedAfterClassMethods() { return m_afterClassMethods; } public void clear() { for(Set instances: m_beforeClassMethods.values()) { instances.clear(); instances= null; } for(Set instances: m_afterClassMethods.values()) { instances.clear(); instances= null; } m_beforeClassMethods.clear(); m_afterClassMethods.clear(); } } testng-6.9.12/src/main/java/org/testng/IAlterSuiteListener.java0000644000175000017500000000142312732165123023713 0ustar eugeneeugenepackage org.testng; import org.testng.xml.XmlSuite; import java.util.List; /** * Implementations of this interface will gain access to the {@link XmlSuite} object and thus let users be able to * alter a suite or a test based on their own needs. * This listener can be added ONLY via the following two ways : *
    *
  1. <listeners> tag in a suite file.
  2. *
  3. via Service loaders
  4. *
*

* Note: This listener will NOT be invoked if it is wired in via the @Listeners * annotation. */ public interface IAlterSuiteListener extends ITestNGListener { /** * @param suites - The list of {@link XmlSuite}s that are part of the current execution. */ void alter(List suites); } testng-6.9.12/src/main/java/org/testng/collections/0000755000175000017500000000000012732165123021466 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/collections/Objects.java0000644000175000017500000000412212732165123023721 0ustar eugeneeugenepackage org.testng.collections; import org.testng.util.Strings; import java.util.List; public final class Objects { private Objects() {} private static class ValueHolder { private String m_name; private String m_value; public ValueHolder(String name, String value) { m_name = name; m_value = value; } boolean isNull() { return m_value == null; } @Override public String toString() { return m_name + "=" + m_value; } public boolean isEmptyString() { return Strings.isNullOrEmpty(m_value); } } public static class ToStringHelper { private String m_className; private List values = Lists.newArrayList(); private boolean m_omitNulls = false; private boolean m_omitEmptyStrings = false; public ToStringHelper(String className) { m_className = className; } public ToStringHelper omitNulls() { m_omitNulls = true; return this; } public ToStringHelper omitEmptyStrings() { m_omitEmptyStrings = true; return this; } public ToStringHelper add(String name, String value) { values.add(new ValueHolder(name, s(value))); return this; } public ToStringHelper add(String name, Object value) { values.add(new ValueHolder(name, s(value))); return this; } private String s(Object o) { return o != null ? (o.toString().isEmpty() ? "\"\"" : o.toString()) : "{null}"; } @Override public String toString() { StringBuilder result = new StringBuilder("[" + m_className + " "); for (int i = 0; i < values.size(); i++) { ValueHolder vh = values.get(i); if (m_omitNulls && vh.isNull()) continue; if (m_omitEmptyStrings && vh.isEmptyString()) continue; if (i > 0) { result.append(" "); } result.append(vh.toString()); } result.append("]"); return result.toString(); } } public static ToStringHelper toStringHelper(Class class1) { return new ToStringHelper(class1.getSimpleName()); } } testng-6.9.12/src/main/java/org/testng/collections/MultiMap.java0000644000175000017500000000424612732165123024067 0ustar eugeneeugenepackage org.testng.collections; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public abstract class MultiMap> { protected final Map m_objects = Maps.newHashMap(); protected abstract C createValue(); public boolean put(K key, V method) { boolean setExists = true; C l = m_objects.get(key); if (l == null) { setExists = false; l = createValue(); m_objects.put(key, l); } return l.add(method) && setExists; } public C get(K key) { return m_objects.get(key); } @Deprecated public List getKeys() { return new ArrayList<>(keySet()); } public Set keySet() { return new HashSet(m_objects.keySet()); } public boolean containsKey(K k) { return m_objects.containsKey(k); } @Override public String toString() { StringBuilder result = new StringBuilder(); Set indices = keySet(); for (K i : indices) { result.append("\n ").append(i).append(" <-- "); for (Object o : m_objects.get(i)) { result.append(o).append(" "); } } return result.toString(); } public boolean isEmpty() { return m_objects.size() == 0; } @Deprecated public int getSize() { return size(); } public int size() { return m_objects.size(); } @Deprecated public C remove(K key) { return removeAll(key); } public boolean remove(K key, V value) { C values = get(key); if (values == null) { return false; } return values.remove(value); } public C removeAll(K key) { return m_objects.remove(key); } @Deprecated public Set> getEntrySet() { return entrySet(); } public Set> entrySet() { return m_objects.entrySet(); } @Deprecated public Collection getValues() { return values(); } public Collection values() { return m_objects.values(); } public boolean putAll(K k, Collection values) { boolean result = false; for (V v : values) { result = put(k, v) || result; } return result; } } testng-6.9.12/src/main/java/org/testng/collections/Lists.java0000755000175000017500000000116312732165123023433 0ustar eugeneeugenepackage org.testng.collections; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; public final class Lists { private Lists() {} public static List newArrayList() { return new ArrayList<>(); } public static List newArrayList(Collection c) { return new ArrayList<>(c); } public static List newArrayList(K... elements) { List result = new ArrayList<>(); Collections.addAll(result, elements); return result; } public static List newArrayList(int size) { return new ArrayList<>(size); } } testng-6.9.12/src/main/java/org/testng/collections/Maps.java0000755000175000017500000000133212732165123023233 0ustar eugeneeugenepackage org.testng.collections; import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.Map; public class Maps { public static Map newHashMap() { return new HashMap<>(); } public static Map newHashtable() { return new Hashtable<>(); } public static ListMultiMap newListMultiMap() { return new ListMultiMap<>(); } public static SetMultiMap newSetMultiMap() { return new SetMultiMap<>(); } public static Map newLinkedHashMap() { return new LinkedHashMap<>(); } public static Map newHashMap(Map parameters) { return new HashMap<>(parameters); } } testng-6.9.12/src/main/java/org/testng/collections/Sets.java0000644000175000017500000000067512732165123023257 0ustar eugeneeugenepackage org.testng.collections; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; public final class Sets { private Sets() {} public static Set newHashSet() { return new HashSet<>(); } public static Set newHashSet(Collection c) { return new HashSet<>(c); } public static Set newLinkedHashSet() { return new LinkedHashSet<>(); } } testng-6.9.12/src/main/java/org/testng/collections/CollectionUtils.java0000644000175000017500000000053712732165123025452 0ustar eugeneeugenepackage org.testng.collections; import java.util.Collection; import java.util.Map; public final class CollectionUtils { private CollectionUtils() {} public static boolean hasElements(Collection c) { return c != null && ! c.isEmpty(); } public static boolean hasElements(Map c) { return c != null && ! c.isEmpty(); } } testng-6.9.12/src/main/java/org/testng/collections/ListMultiMap.java0000644000175000017500000000056612732165123024724 0ustar eugeneeugenepackage org.testng.collections; import java.util.List; /** * A container to hold lists indexed by a key. */ public class ListMultiMap extends MultiMap> { @Override protected List createValue() { return Lists.newArrayList(); } @Deprecated public static ListMultiMap create() { return Maps.newListMultiMap(); } } testng-6.9.12/src/main/java/org/testng/collections/SetMultiMap.java0000644000175000017500000000040212732165123024531 0ustar eugeneeugenepackage org.testng.collections; import java.util.Set; /** * A container to hold sets indexed by a key. */ public class SetMultiMap extends MultiMap> { @Override protected Set createValue() { return Sets.newHashSet(); } } testng-6.9.12/src/main/java/org/testng/Reporter.java0000755000175000017500000001272512732165123021627 0ustar eugeneeugenepackage org.testng; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Vector; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.util.Strings; /** * This class is used for test methods to log messages that will be * included in the HTML reports generated by TestNG. *
*
* Implementation details. *
*
* The reporter keeps a combined output of strings (in m_output) and also * a record of which method output which line. In order to do this, callers * specify what the current method is with setCurrentTestResult() and the * Reporter maintains a mapping of each test result with a list of integers. * These integers are indices in the combined output (avoids duplicating * the output). * * Created on Nov 2, 2005 * @author cbeust */ public class Reporter { // when tests are run in parallel, each thread may be working with different // 'current test result'. Also, this value should be inherited if the test code // spawns its own thread. private static ThreadLocal m_currentTestResult = new InheritableThreadLocal<>(); /** * All output logged in a sequential order. */ private static List m_output = new Vector<>(); /** The key is the hashCode of the ITestResult */ private static Map> m_methodOutputMap = Maps.newHashMap(); private static boolean m_escapeHtml = false; //This variable is responsible for persisting all output that is yet to be associated with any //valid TestResult objects. private static ThreadLocal> m_orphanedOutput = new InheritableThreadLocal<>(); public static void setCurrentTestResult(ITestResult m) { m_currentTestResult.set(m); } public static List getOutput() { return m_output; } /** * Erase the content of all the output generated so far. */ public static void clear() { m_methodOutputMap.clear(); m_output.clear(); } /** * @param escapeHtml If true, use HTML entities for special HTML characters (<, >, &, ...). */ public static void setEscapeHtml(boolean escapeHtml) { m_escapeHtml = escapeHtml; } private static synchronized void log(String s, ITestResult m) { // Escape for the HTML reports if (m_escapeHtml) { s = Strings.escapeHtml(s); } if (m == null) { //Persist the output temporarily into a Threadlocal String list. if (m_orphanedOutput.get() == null) { m_orphanedOutput.set(new ArrayList()); } m_orphanedOutput.get().add(s); return; } // synchronization needed to ensure the line number and m_output are updated atomically int n = getOutput().size(); List lines = m_methodOutputMap.get(m.hashCode()); if (lines == null) { lines = Lists.newArrayList(); m_methodOutputMap.put(m.hashCode(), lines); } // Check if there was already some orphaned output for the current thread. if (m_orphanedOutput.get() != null) { n = n + m_orphanedOutput.get().size(); getOutput().addAll(m_orphanedOutput.get()); // Since we have already added all of the orphaned output to the current // TestResult, lets clear it off m_orphanedOutput.remove(); } lines.add(n); getOutput().add(s); } /** * Log the passed string to the HTML reports * @param s The message to log */ public static void log(String s) { log(s, getCurrentTestResult()); } /** * Log the passed string to the HTML reports if the current verbosity * is equal or greater than the one passed in parameter. If logToStandardOut * is true, the string will also be printed on standard out. * * @param s The message to log * @param level The verbosity of this message * @param logToStandardOut Whether to print this string on standard * out too */ public static void log(String s, int level, boolean logToStandardOut) { if (TestRunner.getVerbose() >= level) { log(s, getCurrentTestResult()); if (logToStandardOut) { System.out.println(s); } } } /** * Log the passed string to the HTML reports. If logToStandardOut * is true, the string will also be printed on standard out. * * @param s The message to log * @param logToStandardOut Whether to print this string on standard * out too */ public static void log(String s, boolean logToStandardOut) { log(s, getCurrentTestResult()); if (logToStandardOut) { System.out.println(s); } } /** * Log the passed string to the HTML reports if the current verbosity * is equal or greater than the one passed in parameter * * @param s The message to log * @param level The verbosity of this message */ public static void log(String s, int level) { if (TestRunner.getVerbose() >= level) { log(s, getCurrentTestResult()); } } /** * @return the current test result. */ public static ITestResult getCurrentTestResult() { return m_currentTestResult.get(); } public static synchronized List getOutput(ITestResult tr) { List result = Lists.newArrayList(); if (tr == null) { //guard against a possible NPE in scenarios wherein the test result object itself could be a null value. return result; } List lines = m_methodOutputMap.get(tr.hashCode()); if (lines != null) { for (Integer n : lines) { result.add(getOutput().get(n)); } } return result; } } testng-6.9.12/src/main/java/org/testng/IConfigurable.java0000644000175000017500000000073212732165123022526 0ustar eugeneeugenepackage org.testng; /** * If a test class implements this interface, its run() method * will be invoked instead of each configuration method found. The invocation of * the configuration method will then be performed upon invocation of the callBack() * method of the IConfigureCallBack parameter. * * @author cbeust * Sep 07, 2010 */ public interface IConfigurable extends ITestNGListener { public void run(IConfigureCallBack callBack, ITestResult testResult); } testng-6.9.12/src/main/java/org/testng/TestNG.java0000644000175000017500000017145712732165123021176 0ustar eugeneeugenepackage org.testng; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URLClassLoader; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.testng.annotations.ITestAnnotation; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.ClassHelper; import org.testng.internal.Configuration; import org.testng.internal.DynamicGraph; import org.testng.internal.IConfiguration; import org.testng.internal.IResultListener2; import org.testng.internal.OverrideProcessor; import org.testng.internal.SuiteRunnerMap; import org.testng.internal.Utils; import org.testng.internal.Version; import org.testng.internal.annotations.DefaultAnnotationTransformer; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.annotations.JDK15AnnotationFinder; import org.testng.internal.thread.graph.GraphThreadPoolExecutor; import org.testng.internal.thread.graph.IThreadWorkerFactory; import org.testng.internal.thread.graph.SuiteWorkerFactory; import org.testng.junit.JUnitTestFinder; import org.testng.log4testng.Logger; import org.testng.reporters.EmailableReporter; import org.testng.reporters.EmailableReporter2; import org.testng.reporters.FailedReporter; import org.testng.reporters.JUnitReportReporter; import org.testng.reporters.SuiteHTMLReporter; import org.testng.reporters.VerboseReporter; import org.testng.reporters.XMLReporter; import org.testng.reporters.jq.Main; import org.testng.xml.Parser; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlMethodSelector; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import com.beust.jcommander.JCommander; import com.beust.jcommander.ParameterException; import static org.testng.internal.Utils.defaultIfStringEmpty; import static org.testng.internal.Utils.isStringEmpty; import static org.testng.internal.Utils.isStringNotEmpty; import static org.testng.xml.XmlSuite.ParallelMode.skipDeprecatedValues; /** * This class is the main entry point for running tests in the TestNG framework. * Users can create their own TestNG object and invoke it in many different * ways: *

    *
  • On an existing testng.xml *
  • On a synthetic testng.xml, created entirely from Java *
  • By directly setting the test classes *
* You can also define which groups to include or exclude, assign parameters, etc... *

* The command line parameters are: *

    *
  • -d outputdir: specify the output directory
  • *
  • -testclass class_name: specifies one or several class names
  • *
  • -testjar jar_name: specifies the jar containing the tests
  • *
  • -sourcedir src1;src2: ; separated list of source directories * (used only when javadoc annotations are used)
  • *
  • -target
  • *
  • -groups
  • *
  • -testrunfactory
  • *
  • -listener
  • *
*

* Please consult documentation for more details. * * FIXME: should support more than simple paths for suite xmls * * @see #usage() * * @author Cedric Beust */ public class TestNG { /** This class' log4testng Logger. */ private static final Logger LOGGER = Logger.getLogger(TestNG.class); /** The default name for a suite launched from the command line */ public static final String DEFAULT_COMMAND_LINE_SUITE_NAME = "Command line suite"; /** The default name for a test launched from the command line */ public static final String DEFAULT_COMMAND_LINE_TEST_NAME = "Command line test"; /** The default name of the result's output directory (keep public, used by Eclipse). */ public static final String DEFAULT_OUTPUTDIR = "test-output"; /** System properties */ public static final String SHOW_TESTNG_STACK_FRAMES = "testng.show.stack.frames"; public static final String TEST_CLASSPATH = "testng.test.classpath"; private static TestNG m_instance; private static JCommander m_jCommander; private List m_commandLineMethods; protected List m_suites = Lists.newArrayList(); private List m_cmdlineSuites; private String m_outputDir = DEFAULT_OUTPUTDIR; private String[] m_includedGroups; private String[] m_excludedGroups; private Boolean m_isJUnit = XmlSuite.DEFAULT_JUNIT; private Boolean m_isMixed = XmlSuite.DEFAULT_MIXED; protected boolean m_useDefaultListeners = true; private ITestRunnerFactory m_testRunnerFactory; // These listeners can be overridden from the command line private List m_classListeners = Lists.newArrayList(); private List m_testListeners = Lists.newArrayList(); private List m_suiteListeners = Lists.newArrayList(); private Set m_reporters = Sets.newHashSet(); protected static final int HAS_FAILURE = 1; protected static final int HAS_SKIPPED = 2; protected static final int HAS_FSP = 4; protected static final int HAS_NO_TEST = 8; public static final Integer DEFAULT_VERBOSE = 1; private int m_status; private boolean m_hasTests= false; // Command line suite parameters private int m_threadCount = -1; private XmlSuite.ParallelMode m_parallelMode = null; private XmlSuite.FailurePolicy m_configFailurePolicy; private Class[] m_commandLineTestClasses; private String m_defaultSuiteName=DEFAULT_COMMAND_LINE_SUITE_NAME; private String m_defaultTestName=DEFAULT_COMMAND_LINE_TEST_NAME; private Map m_methodDescriptors = Maps.newHashMap(); private ITestObjectFactory m_objectFactory; private List m_invokedMethodListeners = Lists.newArrayList(); private Integer m_dataProviderThreadCount = null; private String m_jarPath; /** The path of the testng.xml file inside the jar file */ private String m_xmlPathInJar = CommandLineArgs.XML_PATH_IN_JAR_DEFAULT; private List m_stringSuites = Lists.newArrayList(); private IHookable m_hookable; private IConfigurable m_configurable; protected long m_end; protected long m_start; private List m_executionListeners = Lists.newArrayList(); private List m_alterSuiteListeners= Lists.newArrayList(); private boolean m_isInitialized = false; /** * Default constructor. Setting also usage of default listeners/reporters. */ public TestNG() { init(true); } /** * Used by maven2 to have 0 output of any kind come out * of testng. * @param useDefaultListeners Whether or not any default reports * should be added to tests. */ public TestNG(boolean useDefaultListeners) { init(useDefaultListeners); } private void init(boolean useDefaultListeners) { m_instance = this; m_useDefaultListeners = useDefaultListeners; m_configuration = new Configuration(); } public int getStatus() { return m_status; } private void setStatus(int status) { m_status |= status; } /** * Sets the output directory where the reports will be created. * @param outputdir The directory. */ public void setOutputDirectory(final String outputdir) { if (isStringNotEmpty(outputdir)) { m_outputDir = outputdir; } } /** * If this method is passed true before run(), the default listeners * will not be used. *

    *
  • org.testng.reporters.TestHTMLReporter *
  • org.testng.reporters.JUnitXMLReporter *
  • org.testng.reporters.XMLReporter *
* * @see org.testng.reporters.TestHTMLReporter * @see org.testng.reporters.JUnitXMLReporter * @see org.testng.reporters.XMLReporter */ public void setUseDefaultListeners(boolean useDefaultListeners) { m_useDefaultListeners = useDefaultListeners; } /** * Sets a jar containing a testng.xml file. * * @param jarPath */ public void setTestJar(String jarPath) { m_jarPath = jarPath; } /** * Sets the path to the XML file in the test jar file. */ public void setXmlPathInJar(String xmlPathInJar) { m_xmlPathInJar = xmlPathInJar; } public void initializeSuitesAndJarFile() { // The Eclipse plug-in (RemoteTestNG) might have invoked this method already // so don't initialize suites twice. if (m_isInitialized) { return; } m_isInitialized = true; if (m_suites.size() > 0) { //to parse the suite files (), if any for (XmlSuite s: m_suites) { for (String suiteFile : s.getSuiteFiles()) { Path rootPath = Paths.get(s.getFileName()).getParent(); try { Collection childSuites = getParser(rootPath.resolve(suiteFile).normalize().toString()).parse(); for (XmlSuite cSuite : childSuites){ cSuite.setParentSuite(s); s.getChildSuites().add(cSuite); } } catch (IOException e) { e.printStackTrace(System.out); } } } return; } // // Parse the suites that were passed on the command line // for (String suitePath : m_stringSuites) { if(LOGGER.isDebugEnabled()) { LOGGER.debug("suiteXmlPath: \"" + suitePath + "\""); } try { Collection allSuites = getParser(suitePath).parse(); for (XmlSuite s : allSuites) { // If test names were specified, only run these test names if (m_testNames != null) { m_suites.add(extractTestNames(s, m_testNames)); } else { m_suites.add(s); } } } catch(IOException e) { e.printStackTrace(System.out); } catch(Exception ex) { // Probably a Yaml exception, unnest it Throwable t = ex; while (t.getCause() != null) t = t.getCause(); // t.printStackTrace(); if (t instanceof TestNGException) throw (TestNGException) t; else throw new TestNGException(t); } } // // jar path // // If suites were passed on the command line, they take precedence over the suite file // inside that jar path if (m_jarPath != null && m_stringSuites.size() > 0) { StringBuilder suites = new StringBuilder(); for (String s : m_stringSuites) { suites.append(s); } Utils.log("TestNG", 2, "Ignoring the XML file inside " + m_jarPath + " and using " + suites + " instead"); return; } if (isStringEmpty(m_jarPath)) { return; } // We have a jar file and no XML file was specified: try to find an XML file inside the jar File jarFile = new File(m_jarPath); try { Utils.log("TestNG", 2, "Trying to open jar file:" + jarFile); boolean foundTestngXml = false; List classes = Lists.newArrayList(); try (JarFile jf = new JarFile(jarFile)) { // System.out.println(" result: " + jf); Enumeration entries = jf.entries(); while (entries.hasMoreElements()) { JarEntry je = entries.nextElement(); if (je.getName().equals(m_xmlPathInJar)) { Parser parser = getParser(jf.getInputStream(je)); Collection suites = parser.parse(); for (XmlSuite suite : suites) { // If test names were specified, only run these test names if (m_testNames != null) { m_suites.add(extractTestNames(suite, m_testNames)); } else { m_suites.add(suite); } } foundTestngXml = true; break; } else if (je.getName().endsWith(".class")) { int n = je.getName().length() - ".class".length(); classes.add(je.getName().replace("/", ".").substring(0, n)); } } } if (! foundTestngXml) { Utils.log("TestNG", 1, "Couldn't find the " + m_xmlPathInJar + " in the jar file, running all the classes"); XmlSuite xmlSuite = new XmlSuite(); xmlSuite.setVerbose(0); xmlSuite.setName("Jar suite"); XmlTest xmlTest = new XmlTest(xmlSuite); List xmlClasses = Lists.newArrayList(); for (String cls : classes) { XmlClass xmlClass = new XmlClass(cls); xmlClasses.add(xmlClass); } xmlTest.setXmlClasses(xmlClasses); m_suites.add(xmlSuite); } } catch(IOException ex) { ex.printStackTrace(); } } private Parser getParser(String path) { Parser result = new Parser(path); initProcessor(result); return result; } private Parser getParser(InputStream is) { Parser result = new Parser(is); initProcessor(result); return result; } private void initProcessor(Parser result) { result.setPostProcessor(new OverrideProcessor(m_includedGroups, m_excludedGroups)); } /** * If the XmlSuite contains at least one test named as testNames, return * an XmlSuite that's made only of these tests, otherwise, return the * original suite. */ private static XmlSuite extractTestNames(XmlSuite s, List testNames) { extractTestNamesFromChildSuites(s, testNames); List tests = Lists.newArrayList(); for (XmlTest xt : s.getTests()) { for (String tn : testNames) { if (xt.getName().equals(tn)) { tests.add(xt); } } } if (tests.size() == 0) { return s; } else { XmlSuite result = (XmlSuite) s.clone(); result.getTests().clear(); result.getTests().addAll(tests); return result; } } private static void extractTestNamesFromChildSuites(XmlSuite s, List testNames) { List childSuites = s.getChildSuites(); for (int i = 0; i < childSuites.size(); i++) { XmlSuite child = childSuites.get(i); XmlSuite extracted = extractTestNames(child, testNames); // if a new xml suite is created, which means some tests was extracted, then we replace the child if (extracted != child) { childSuites.set(i, extracted); } } } /** * Define the number of threads in the thread pool. */ public void setThreadCount(int threadCount) { if(threadCount < 1) { exitWithError("Cannot use a threadCount parameter less than 1; 1 > " + threadCount); } m_threadCount = threadCount; } /** * Define whether this run will be run in parallel mode. * @deprecated Use #setParallel(XmlSuite.ParallelMode) instead */ @Deprecated public void setParallel(String parallel) { if (parallel == null) { setParallel(XmlSuite.ParallelMode.NONE); } else { setParallel(XmlSuite.ParallelMode.getValidParallel(parallel)); } } public void setParallel(XmlSuite.ParallelMode parallel) { m_parallelMode = skipDeprecatedValues(parallel); } public void setCommandLineSuite(XmlSuite suite) { m_cmdlineSuites = Lists.newArrayList(); m_cmdlineSuites.add(suite); m_suites.add(suite); } /** * Set the test classes to be run by this TestNG object. This method * will create a dummy suite that will wrap these classes called * "Command Line Test". *

* If used together with threadCount, parallel, groups, excludedGroups than this one must be set first. * * @param classes An array of classes that contain TestNG annotations. */ public void setTestClasses(Class[] classes) { m_suites.clear(); m_commandLineTestClasses = classes; } /** * Given a string com.example.Foo.f1, return an array where [0] is the class and [1] * is the method. */ private String[] splitMethod(String m) { int index = m.lastIndexOf("."); if (index < 0) { throw new TestNGException("Bad format for command line method:" + m + ", expected ."); } return new String[] { m.substring(0, index), m.substring(index + 1).replaceAll("\\*", "\\.\\*") }; } /** * @return a list of XmlSuite objects that represent the list of classes and methods passed * in parameter. * * @param commandLineMethods a string with the form "com.example.Foo.f1,com.example.Bar.f2" */ private List createCommandLineSuitesForMethods(List commandLineMethods) { // // Create the tag // Set classes = Sets.newHashSet(); for (String m : commandLineMethods) { Class c = ClassHelper.forName(splitMethod(m)[0]); if (c != null) { classes.add(c); } } List result = createCommandLineSuitesForClasses(classes.toArray(new Class[0])); // // Add the method tags // List xmlClasses = Lists.newArrayList(); for (XmlSuite s : result) { for (XmlTest t : s.getTests()) { xmlClasses.addAll(t.getClasses()); } } for (XmlClass xc : xmlClasses) { for (String m : commandLineMethods) { String[] split = splitMethod(m); String className = split[0]; if (xc.getName().equals(className)) { XmlInclude includedMethod = new XmlInclude(split[1]); xc.getIncludedMethods().add(includedMethod); } } } return result; } private List createCommandLineSuitesForClasses(Class[] classes) { // // See if any of the classes has an xmlSuite or xmlTest attribute. // If it does, create the appropriate XmlSuite, otherwise, create // the default one // XmlClass[] xmlClasses = Utils.classesToXmlClasses(classes); Map suites = Maps.newHashMap(); IAnnotationFinder finder = m_configuration.getAnnotationFinder(); for (int i = 0; i < classes.length; i++) { Class c = classes[i]; ITestAnnotation test = finder.findAnnotation(c, ITestAnnotation.class); String suiteName = getDefaultSuiteName(); String testName = getDefaultTestName(); boolean isJUnit = false; if (test != null) { suiteName = defaultIfStringEmpty(test.getSuiteName(), suiteName); testName = defaultIfStringEmpty(test.getTestName(), testName); } else { if (m_isMixed && JUnitTestFinder.isJUnitTest(c)) { isJUnit = true; testName = c.getName(); } } XmlSuite xmlSuite = suites.get(suiteName); if (xmlSuite == null) { xmlSuite = new XmlSuite(); xmlSuite.setName(suiteName); suites.put(suiteName, xmlSuite); } if (m_dataProviderThreadCount != null) { xmlSuite.setDataProviderThreadCount(m_dataProviderThreadCount); } XmlTest xmlTest = null; for (XmlTest xt : xmlSuite.getTests()) { if (xt.getName().equals(testName)) { xmlTest = xt; break; } } if (xmlTest == null) { xmlTest = new XmlTest(xmlSuite); xmlTest.setName(testName); xmlTest.setJUnit(isJUnit); } xmlTest.getXmlClasses().add(xmlClasses[i]); } return new ArrayList<>(suites.values()); } public void addMethodSelector(String className, int priority) { m_methodDescriptors.put(className, priority); } /** * Set the suites file names to be run by this TestNG object. This method tries to load and * parse the specified TestNG suite xml files. If a file is missing, it is ignored. * * @param suites A list of paths to one more XML files defining the tests. For example: * *

   * TestNG tng = new TestNG();
   * List suites = Lists.newArrayList();
   * suites.add("c:/tests/testng1.xml");
   * suites.add("c:/tests/testng2.xml");
   * tng.setTestSuites(suites);
   * tng.run();
   * 
*/ public void setTestSuites(List suites) { m_stringSuites = suites; } /** * Specifies the XmlSuite objects to run. * @param suites * @see org.testng.xml.XmlSuite */ public void setXmlSuites(List suites) { m_suites = suites; } /** * Define which groups will be excluded from this run. * * @param groups A list of group names separated by a comma. */ public void setExcludedGroups(String groups) { m_excludedGroups = Utils.split(groups, ","); } /** * Define which groups will be included from this run. * * @param groups A list of group names separated by a comma. */ public void setGroups(String groups) { m_includedGroups = Utils.split(groups, ","); } private void setTestRunnerFactoryClass(Class testRunnerFactoryClass) { setTestRunnerFactory((ITestRunnerFactory) ClassHelper.newInstance(testRunnerFactoryClass)); } protected void setTestRunnerFactory(ITestRunnerFactory itrf) { m_testRunnerFactory= itrf; } public void setObjectFactory(Class c) { m_objectFactory = (ITestObjectFactory) ClassHelper.newInstance(c); } public void setObjectFactory(ITestObjectFactory factory) { m_objectFactory = factory; } /** * Define which listeners to user for this run. * * @param classes A list of classes, which must be either ISuiteListener, * ITestListener or IReporter */ public void setListenerClasses(List classes) { for (Class cls: classes) { addListener(ClassHelper.newInstance(cls)); } } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addListener(Object listener) { if (! (listener instanceof ITestNGListener)) { exitWithError("Listener " + listener + " must be one of ITestListener, ISuiteListener, IReporter, " + " IAnnotationTransformer, IMethodInterceptor or IInvokedMethodListener"); } addListener((ITestNGListener) listener); } public void addListener(ITestNGListener listener) { if (listener == null) { return; } if (listener instanceof ISuiteListener) { m_suiteListeners.add((ISuiteListener) listener); } if (listener instanceof ITestListener) { m_testListeners.add((ITestListener) listener); } if (listener instanceof IClassListener) { m_classListeners.add((IClassListener) listener); } if (listener instanceof IReporter) { m_reporters.add((IReporter) listener); } if (listener instanceof IAnnotationTransformer) { setAnnotationTransformer((IAnnotationTransformer) listener); } if (listener instanceof IMethodInterceptor) { m_methodInterceptors.add((IMethodInterceptor) listener); } if (listener instanceof IInvokedMethodListener) { m_invokedMethodListeners.add((IInvokedMethodListener) listener); } if (listener instanceof IHookable) { setHookable((IHookable) listener); } if (listener instanceof IConfigurable) { setConfigurable((IConfigurable) listener); } if (listener instanceof IExecutionListener) { m_executionListeners.add((IExecutionListener) listener); } if (listener instanceof IConfigurationListener) { getConfiguration().addConfigurationListener((IConfigurationListener) listener); } if (listener instanceof IAlterSuiteListener) { m_alterSuiteListeners.add((IAlterSuiteListener) listener); } } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addListener(IInvokedMethodListener listener) { addListener((ITestNGListener) listener); } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addListener(ISuiteListener listener) { addListener((ITestNGListener) listener); } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addListener(ITestListener listener) { addListener((ITestNGListener) listener); } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addListener(IClassListener listener) { addListener((ITestNGListener) listener); } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addListener(IReporter listener) { addListener((ITestNGListener) listener); } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addInvokedMethodListener(IInvokedMethodListener listener) { addListener((ITestNGListener) listener); } public Set getReporters() { return m_reporters; } public List getTestListeners() { return m_testListeners; } public List getSuiteListeners() { return m_suiteListeners; } /** If m_verbose gets set, it will override the verbose setting in testng.xml */ private Integer m_verbose = null; private final IAnnotationTransformer m_defaultAnnoProcessor = new DefaultAnnotationTransformer(); private IAnnotationTransformer m_annotationTransformer = m_defaultAnnoProcessor; private Boolean m_skipFailedInvocationCounts = false; private List m_methodInterceptors = new ArrayList(); /** The list of test names to run from the given suite */ private List m_testNames; private Integer m_suiteThreadPoolSize = CommandLineArgs.SUITE_THREAD_POOL_SIZE_DEFAULT; private boolean m_randomizeSuites = Boolean.FALSE; private boolean m_preserveOrder = false; private Boolean m_groupByInstances; private IConfiguration m_configuration; /** * Sets the level of verbosity. This value will override the value specified * in the test suites. * * @param verbose the verbosity level (0 to 10 where 10 is most detailed) * Actually, this is a lie: you can specify -1 and this will put TestNG * in debug mode (no longer slicing off stack traces and all). */ public void setVerbose(int verbose) { m_verbose = verbose; } private void initializeCommandLineSuites() { if (m_commandLineTestClasses != null || m_commandLineMethods != null) { if (null != m_commandLineMethods) { m_cmdlineSuites = createCommandLineSuitesForMethods(m_commandLineMethods); } else { m_cmdlineSuites = createCommandLineSuitesForClasses(m_commandLineTestClasses); } for (XmlSuite s : m_cmdlineSuites) { for (XmlTest t : s.getTests()) { t.setPreserveOrder(String.valueOf(m_preserveOrder)); } m_suites.add(s); if (m_groupByInstances != null) { s.setGroupByInstances(m_groupByInstances); } } } } private void initializeCommandLineSuitesParams() { if(null == m_cmdlineSuites) { return; } for (XmlSuite s : m_cmdlineSuites) { if (m_threadCount != -1) { s.setThreadCount(m_threadCount); } if (m_parallelMode != null) { s.setParallel(m_parallelMode); } if(m_configFailurePolicy != null) { s.setConfigFailurePolicy(m_configFailurePolicy); } } } private void initializeCommandLineSuitesGroups() { // If groups were specified on the command line, they should override groups // specified in the XML file boolean hasIncludedGroups = null != m_includedGroups && m_includedGroups.length > 0; boolean hasExcludedGroups = null != m_excludedGroups && m_excludedGroups.length > 0; List suites = m_cmdlineSuites != null ? m_cmdlineSuites : m_suites; if (hasIncludedGroups || hasExcludedGroups) { for (XmlSuite s : suites) { //set on each test, instead of just the first one of the suite for (XmlTest t : s.getTests()) { if(hasIncludedGroups) { t.setIncludedGroups(Arrays.asList(m_includedGroups)); } if(hasExcludedGroups) { t.setExcludedGroups(Arrays.asList(m_excludedGroups)); } } } } } private void addReporter(Class r) { m_reporters.add(ClassHelper.newInstance(r)); } private void initializeDefaultListeners() { m_testListeners.add(new ExitCodeListener(this)); if (m_useDefaultListeners) { addReporter(SuiteHTMLReporter.class); addReporter(Main.class); addReporter(FailedReporter.class); addReporter(XMLReporter.class); if (System.getProperty("oldTestngEmailableReporter") != null) { addReporter(EmailableReporter.class); } else if (System.getProperty("noEmailableReporter") == null) { addReporter(EmailableReporter2.class); } addReporter(JUnitReportReporter.class); if (m_verbose != null && m_verbose > 4) { addListener(new VerboseReporter("[TestNG] ")); } } } private void initializeConfiguration() { ITestObjectFactory factory = m_objectFactory; // // Install the listeners found in ServiceLoader (or use the class // loader for tests, if specified). // addServiceLoaderListeners(); // // Install the listeners found in the suites // for (XmlSuite s : m_suites) { for (String listenerName : s.getListeners()) { Class listenerClass = ClassHelper.forName(listenerName); // If specified listener does not exist, a TestNGException will be thrown if(listenerClass == null) { throw new TestNGException("Listener " + listenerName + " was not found in project's classpath"); } Object listener = ClassHelper.newInstance(listenerClass); addListener(listener); } // // Install the method selectors // for (XmlMethodSelector methodSelector : s.getMethodSelectors() ) { addMethodSelector(methodSelector.getClassName(), methodSelector.getPriority()); } // // Find if we have an object factory // if (s.getObjectFactory() != null) { if (factory == null) { factory = s.getObjectFactory(); } else { throw new TestNGException("Found more than one object-factory tag in your suites"); } } } m_configuration.setAnnotationFinder(new JDK15AnnotationFinder(getAnnotationTransformer())); m_configuration.setHookable(m_hookable); m_configuration.setConfigurable(m_configurable); m_configuration.setObjectFactory(factory); } /** * Using reflection to remain Java 5 compliant. */ private void addServiceLoaderListeners() { Iterable loader = m_serviceLoaderClassLoader != null ? ServiceLoader.load(ITestNGListener.class, m_serviceLoaderClassLoader) : ServiceLoader.load(ITestNGListener.class); for (ITestNGListener l : loader) { Utils.log("[TestNG]", 2, "Adding ServiceLoader listener:" + l); addListener(l); addServiceLoaderListener(l); } } /** * Before suites are executed, do a sanity check to ensure all required * conditions are met. If not, throw an exception to stop test execution * * @throws TestNGException if the sanity check fails */ private void sanityCheck() { checkTestNames(m_suites); checkSuiteNames(m_suites); } /** * Ensure that two XmlTest within the same XmlSuite don't have the same name */ private void checkTestNames(List suites) { for (XmlSuite suite : suites) { Set testNames = Sets.newHashSet(); for (XmlTest test : suite.getTests()) { if (testNames.contains(test.getName())) { throw new TestNGException("Two tests in the same suite " + "cannot have the same name: " + test.getName()); } else { testNames.add(test.getName()); } } checkTestNames(suite.getChildSuites()); } } /** * Ensure that two XmlSuite don't have the same name * Otherwise will be clash in SuiteRunnerMap * See issue #302 */ private void checkSuiteNames(List suites) { checkSuiteNamesInternal(suites, Sets.newHashSet()); } private void checkSuiteNamesInternal(List suites, Set names) { for (XmlSuite suite : suites) { final String name = suite.getName(); int count = 0; String tmpName = name; while (names.contains(tmpName)) { tmpName = name + " (" + count++ + ")"; } if (count > 0) { suite.setName(tmpName); names.add(tmpName); } else { names.add(name); } names.add(name); checkSuiteNamesInternal(suite.getChildSuites(), names); } } /** * Run TestNG. */ public void run() { initializeSuitesAndJarFile(); initializeConfiguration(); initializeDefaultListeners(); initializeCommandLineSuites(); initializeCommandLineSuitesParams(); initializeCommandLineSuitesGroups(); sanityCheck(); List suiteRunners = null; runSuiteAlterationListeners(); runExecutionListeners(true /* start */); m_start = System.currentTimeMillis(); suiteRunners = runSuites(); m_end = System.currentTimeMillis(); runExecutionListeners(false /* finish */); if(null != suiteRunners) { generateReports(suiteRunners); } if(!m_hasTests) { setStatus(HAS_NO_TEST); if (TestRunner.getVerbose() > 1) { System.err.println("[TestNG] No tests found. Nothing was run"); usage(); } } } /** * Run the test suites. *

* This method can be overridden by subclass.
* For example, DistributedTestNG to run in master/slave mode according to commandline args. *

* @return * @since 6.9.11 when moving distributed/remote classes out into separate project */ protected List runSuites() { return runSuitesLocally(); } private void runSuiteAlterationListeners() { for (List listeners : Arrays.asList(m_alterSuiteListeners, m_configuration.getAlterSuiteListeners())) { for (IAlterSuiteListener l : listeners) { l.alter(m_suites); } } } private void runExecutionListeners(boolean start) { for (List listeners : Arrays.asList(m_executionListeners, m_configuration.getExecutionListeners())) { for (IExecutionListener l : listeners) { if (start) l.onExecutionStart(); else l.onExecutionFinish(); } } } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addAlterSuiteListener(IAlterSuiteListener l) { addListener((ITestNGListener) l); } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO remove later @Deprecated public void addExecutionListener(IExecutionListener l) { addListener((ITestNGListener) l); } private static void usage() { if (m_jCommander == null) { m_jCommander = new JCommander(new CommandLineArgs()); } m_jCommander.usage(); } private void generateReports(List suiteRunners) { for (IReporter reporter : m_reporters) { try { long start = System.currentTimeMillis(); reporter.generateReport(m_suites, suiteRunners, m_outputDir); Utils.log("TestNG", 2, "Time taken by " + reporter + ": " + (System.currentTimeMillis() - start) + " ms"); } catch(Exception ex) { System.err.println("[TestNG] Reporter " + reporter + " failed"); ex.printStackTrace(System.err); } } } /** * This needs to be public for maven2, for now..At least * until an alternative mechanism is found. */ public List runSuitesLocally() { SuiteRunnerMap suiteRunnerMap = new SuiteRunnerMap(); if (m_suites.size() > 0) { if (m_suites.get(0).getVerbose() >= 2) { Version.displayBanner(); } // First initialize the suite runners to ensure there are no configuration issues. // Create a map with XmlSuite as key and corresponding SuiteRunner as value for (XmlSuite xmlSuite : m_suites) { createSuiteRunners(suiteRunnerMap, xmlSuite); } // // Run suites // if (m_suiteThreadPoolSize == 1 && !m_randomizeSuites) { // Single threaded and not randomized: run the suites in order for (XmlSuite xmlSuite : m_suites) { runSuitesSequentially(xmlSuite, suiteRunnerMap, getVerbose(xmlSuite), getDefaultSuiteName()); } } else { // Multithreaded: generate a dynamic graph that stores the suite hierarchy. This is then // used to run related suites in specific order. Parent suites are run only // once all the child suites have completed execution DynamicGraph suiteGraph = new DynamicGraph<>(); for (XmlSuite xmlSuite : m_suites) { populateSuiteGraph(suiteGraph, suiteRunnerMap, xmlSuite); } IThreadWorkerFactory factory = new SuiteWorkerFactory(suiteRunnerMap, 0 /* verbose hasn't been set yet */, getDefaultSuiteName()); GraphThreadPoolExecutor pooledExecutor = new GraphThreadPoolExecutor<>(suiteGraph, factory, m_suiteThreadPoolSize, m_suiteThreadPoolSize, Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); Utils.log("TestNG", 2, "Starting executor for all suites"); // Run all suites in parallel pooledExecutor.run(); try { pooledExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); pooledExecutor.shutdownNow(); } catch (InterruptedException handled) { Thread.currentThread().interrupt(); error("Error waiting for concurrent executors to finish " + handled.getMessage()); } } } else { setStatus(HAS_NO_TEST); error("No test suite found. Nothing to run"); usage(); } // // Generate the suites report // return Lists.newArrayList(suiteRunnerMap.values()); } private static void error(String s) { LOGGER.error(s); } /** * @return the verbose level, checking in order: the verbose level on * the suite, the verbose level on the TestNG object, or 1. */ private int getVerbose(XmlSuite xmlSuite) { int result = xmlSuite.getVerbose() != null ? xmlSuite.getVerbose() : (m_verbose != null ? m_verbose : DEFAULT_VERBOSE); return result; } /** * Recursively runs suites. Runs the children suites before running the parent * suite. This is done so that the results for parent suite can reflect the * combined results of the children suites. * * @param xmlSuite XML Suite to be executed * @param suiteRunnerMap Maps {@code XmlSuite}s to respective {@code ISuite} * @param verbose verbose level * @param defaultSuiteName default suite name */ private void runSuitesSequentially(XmlSuite xmlSuite, SuiteRunnerMap suiteRunnerMap, int verbose, String defaultSuiteName) { for (XmlSuite childSuite : xmlSuite.getChildSuites()) { runSuitesSequentially(childSuite, suiteRunnerMap, verbose, defaultSuiteName); } SuiteRunnerWorker srw = new SuiteRunnerWorker(suiteRunnerMap.get(xmlSuite), suiteRunnerMap, verbose, defaultSuiteName); srw.run(); } /** * Populates the dynamic graph with the reverse hierarchy of suites. Edges are * added pointing from child suite runners to parent suite runners, hence making * parent suite runners dependent on all the child suite runners * * @param suiteGraph dynamic graph representing the reverse hierarchy of SuiteRunners * @param suiteRunnerMap Map with XMLSuite as key and its respective SuiteRunner as value * @param xmlSuite XML Suite */ private void populateSuiteGraph(DynamicGraph suiteGraph /* OUT */, SuiteRunnerMap suiteRunnerMap, XmlSuite xmlSuite) { ISuite parentSuiteRunner = suiteRunnerMap.get(xmlSuite); if (xmlSuite.getChildSuites().isEmpty()) { suiteGraph.addNode(parentSuiteRunner); } else { for (XmlSuite childSuite : xmlSuite.getChildSuites()) { suiteGraph.addEdge(parentSuiteRunner, suiteRunnerMap.get(childSuite)); populateSuiteGraph(suiteGraph, suiteRunnerMap, childSuite); } } } /** * Creates the {@code SuiteRunner}s and populates the suite runner map with * this information * @param suiteRunnerMap Map with XMLSuite as key and it's respective * SuiteRunner as value. This is updated as part of this method call * @param xmlSuite Xml Suite (and its children) for which {@code SuiteRunner}s are created */ private void createSuiteRunners(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite) { if (null != m_isJUnit && ! m_isJUnit.equals(XmlSuite.DEFAULT_JUNIT)) { xmlSuite.setJUnit(m_isJUnit); } // If the skip flag was invoked on the command line, it // takes precedence if (null != m_skipFailedInvocationCounts) { xmlSuite.setSkipFailedInvocationCounts(m_skipFailedInvocationCounts); } // Override the XmlSuite verbose value with the one from TestNG if (m_verbose != null) { xmlSuite.setVerbose(m_verbose); } if (null != m_configFailurePolicy) { xmlSuite.setConfigFailurePolicy(m_configFailurePolicy); } for (XmlTest t : xmlSuite.getTests()) { for (Map.Entry ms : m_methodDescriptors.entrySet()) { XmlMethodSelector xms = new XmlMethodSelector(); xms.setName(ms.getKey()); xms.setPriority(ms.getValue()); t.getMethodSelectors().add(xms); } } suiteRunnerMap.put(xmlSuite, createSuiteRunner(xmlSuite)); for (XmlSuite childSuite : xmlSuite.getChildSuites()) { createSuiteRunners(suiteRunnerMap, childSuite); } } /** * Creates a suite runner and configures its initial state * @param xmlSuite * @return returns the newly created suite runner */ private SuiteRunner createSuiteRunner(XmlSuite xmlSuite) { SuiteRunner result = new SuiteRunner(getConfiguration(), xmlSuite, m_outputDir, m_testRunnerFactory, m_useDefaultListeners, m_methodInterceptors, m_invokedMethodListeners, m_testListeners, m_classListeners); for (ISuiteListener isl : m_suiteListeners) { result.addListener(isl); } for (IReporter r : result.getReporters()) { addListener(r); } for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) { result.addConfigurationListener(cl); } return result; } protected IConfiguration getConfiguration() { return m_configuration; } /** * The TestNG entry point for command line execution. * * @param argv the TestNG command line parameters. * @throws FileNotFoundException */ public static void main(String[] argv) { TestNG testng = privateMain(argv, null); System.exit(testng.getStatus()); } /** * Note: this method is not part of the public API and is meant for internal usage only. */ public static TestNG privateMain(String[] argv, ITestListener listener) { TestNG result = new TestNG(); if (null != listener) { result.addListener((Object)listener); } // // Parse the arguments // try { CommandLineArgs cla = new CommandLineArgs(); m_jCommander = new JCommander(cla, argv); validateCommandLineParameters(cla); result.configure(cla); } catch(ParameterException ex) { exitWithError(ex.getMessage()); } // // Run // try { result.run(); } catch(TestNGException ex) { if (TestRunner.getVerbose() > 1) { ex.printStackTrace(System.out); } else { error(ex.getMessage()); } result.setStatus(HAS_FAILURE); } return result; } /** * Configure the TestNG instance based on the command line parameters. */ protected void configure(CommandLineArgs cla) { if (cla.verbose != null) { setVerbose(cla.verbose); } setOutputDirectory(cla.outputDirectory); String testClasses = cla.testClass; if (null != testClasses) { String[] strClasses = testClasses.split(","); List classes = Lists.newArrayList(); for (String c : strClasses) { classes.add(ClassHelper.fileToClass(c)); } setTestClasses(classes.toArray(new Class[classes.size()])); } setOutputDirectory(cla.outputDirectory); if (cla.testNames != null) { setTestNames(Arrays.asList(cla.testNames.split(","))); } // List testNgXml = (List) cmdLineArgs.get(CommandLineArgs.SUITE_DEF); // if (null != testNgXml) { // setTestSuites(testNgXml); // } // Note: can't use a Boolean field here because we are allowing a boolean // parameter with an arity of 1 ("-usedefaultlisteners false") if (cla.useDefaultListeners != null) { setUseDefaultListeners("true".equalsIgnoreCase(cla.useDefaultListeners)); } setGroups(cla.groups); setExcludedGroups(cla.excludedGroups); setTestJar(cla.testJar); setXmlPathInJar(cla.xmlPathInJar); setJUnit(cla.junit); setMixed(cla.mixed); setSkipFailedInvocationCounts(cla.skipFailedInvocationCounts); if (cla.parallelMode != null) { setParallel(cla.parallelMode); } if (cla.configFailurePolicy != null) { setConfigFailurePolicy(cla.configFailurePolicy); } if (cla.threadCount != null) { setThreadCount(cla.threadCount); } if (cla.dataProviderThreadCount != null) { setDataProviderThreadCount(cla.dataProviderThreadCount); } if (cla.suiteName != null) { setDefaultSuiteName(cla.suiteName); } if (cla.testName != null) { setDefaultTestName(cla.testName); } if (cla.listener != null) { String sep = ";"; if (cla.listener.contains(",")) { sep = ","; } String[] strs = Utils.split(cla.listener, sep); List classes = Lists.newArrayList(); for (String cls : strs) { classes.add(ClassHelper.fileToClass(cls)); } setListenerClasses(classes); } if (null != cla.methodSelectors) { String[] strs = Utils.split(cla.methodSelectors, ","); for (String cls : strs) { String[] sel = Utils.split(cls, ":"); try { if (sel.length == 2) { addMethodSelector(sel[0], Integer.parseInt(sel[1])); } else { error("Method selector value was not in the format org.example.Selector:4"); } } catch (NumberFormatException nfe) { error("Method selector value was not in the format org.example.Selector:4"); } } } if (cla.objectFactory != null) { setObjectFactory(ClassHelper.fileToClass(cla.objectFactory)); } if (cla.testRunnerFactory != null) { setTestRunnerFactoryClass( ClassHelper.fileToClass(cla.testRunnerFactory)); } if (cla.reporter != null) { ReporterConfig reporterConfig = ReporterConfig.deserialize(cla.reporter); addReporter(reporterConfig); } if (cla.commandLineMethods.size() > 0) { m_commandLineMethods = cla.commandLineMethods; } if (cla.suiteFiles != null) { setTestSuites(cla.suiteFiles); } setSuiteThreadPoolSize(cla.suiteThreadPoolSize); setRandomizeSuites(cla.randomizeSuites); } public void setSuiteThreadPoolSize(Integer suiteThreadPoolSize) { m_suiteThreadPoolSize = suiteThreadPoolSize; } public Integer getSuiteThreadPoolSize() { return m_suiteThreadPoolSize; } public void setRandomizeSuites(boolean randomizeSuites) { m_randomizeSuites = randomizeSuites; } /** * This method is invoked by Maven's Surefire, only remove it once * Surefire has been modified to no longer call it. */ public void setSourcePath(String path) { // nop } /** * This method is invoked by Maven's Surefire to configure the runner, * do not remove unless you know for sure that Surefire has been updated * to use the new configure(CommandLineArgs) method. * * @deprecated use new configure(CommandLineArgs) method */ @SuppressWarnings({"unchecked"}) @Deprecated public void configure(Map cmdLineArgs) { CommandLineArgs result = new CommandLineArgs(); Integer verbose = (Integer) cmdLineArgs.get(CommandLineArgs.LOG); if (null != verbose) { result.verbose = verbose; } result.outputDirectory = (String) cmdLineArgs.get(CommandLineArgs.OUTPUT_DIRECTORY); String testClasses = (String) cmdLineArgs.get(CommandLineArgs.TEST_CLASS); if (null != testClasses) { result.testClass = testClasses; } String testNames = (String) cmdLineArgs.get(CommandLineArgs.TEST_NAMES); if (testNames != null) { result.testNames = testNames; } String useDefaultListeners = (String) cmdLineArgs.get(CommandLineArgs.USE_DEFAULT_LISTENERS); if (null != useDefaultListeners) { result.useDefaultListeners = useDefaultListeners; } result.groups = (String) cmdLineArgs.get(CommandLineArgs.GROUPS); result.excludedGroups = (String) cmdLineArgs.get(CommandLineArgs.EXCLUDED_GROUPS); result.testJar = (String) cmdLineArgs.get(CommandLineArgs.TEST_JAR); result.xmlPathInJar = (String) cmdLineArgs.get(CommandLineArgs.XML_PATH_IN_JAR); result.junit = (Boolean) cmdLineArgs.get(CommandLineArgs.JUNIT); result.mixed = (Boolean) cmdLineArgs.get(CommandLineArgs.MIXED); result.skipFailedInvocationCounts = (Boolean) cmdLineArgs.get( CommandLineArgs.SKIP_FAILED_INVOCATION_COUNTS); String parallelMode = (String) cmdLineArgs.get(CommandLineArgs.PARALLEL); if (parallelMode != null) { result.parallelMode = XmlSuite.ParallelMode.getValidParallel(parallelMode); } String threadCount = (String) cmdLineArgs.get(CommandLineArgs.THREAD_COUNT); if (threadCount != null) { result.threadCount = Integer.parseInt(threadCount); } // Not supported by Surefire yet Integer dptc = (Integer) cmdLineArgs.get(CommandLineArgs.DATA_PROVIDER_THREAD_COUNT); if (dptc != null) { result.dataProviderThreadCount = dptc; } String defaultSuiteName = (String) cmdLineArgs.get(CommandLineArgs.SUITE_NAME); if (defaultSuiteName != null) { result.suiteName = defaultSuiteName; } String defaultTestName = (String) cmdLineArgs.get(CommandLineArgs.TEST_NAME); if (defaultTestName != null) { result.testName = defaultTestName; } Object listeners = cmdLineArgs.get(CommandLineArgs.LISTENER); if (listeners instanceof List) { result.listener = Utils.join((List) listeners, ","); } else { result.listener = (String) listeners; } String ms = (String) cmdLineArgs.get(CommandLineArgs.METHOD_SELECTORS); if (null != ms) { result.methodSelectors = ms; } String objectFactory = (String) cmdLineArgs.get(CommandLineArgs.OBJECT_FACTORY); if(null != objectFactory) { result.objectFactory = objectFactory; } String runnerFactory = (String) cmdLineArgs.get(CommandLineArgs.TEST_RUNNER_FACTORY); if (null != runnerFactory) { result.testRunnerFactory = runnerFactory; } String reporterConfigs = (String) cmdLineArgs.get(CommandLineArgs.REPORTER); if (reporterConfigs != null) { result.reporter = reporterConfigs; } String failurePolicy = (String)cmdLineArgs.get(CommandLineArgs.CONFIG_FAILURE_POLICY); if (failurePolicy != null) { result.configFailurePolicy = failurePolicy; } Object suiteThreadPoolSize = cmdLineArgs.get(CommandLineArgs.SUITE_THREAD_POOL_SIZE); if (null != suiteThreadPoolSize) { if (suiteThreadPoolSize instanceof String){ result.suiteThreadPoolSize=Integer.parseInt((String) suiteThreadPoolSize); } if (suiteThreadPoolSize instanceof Integer){ result.suiteThreadPoolSize=(Integer) suiteThreadPoolSize; } } configure(result); } /** * Only run the specified tests from the suite. */ public void setTestNames(List testNames) { m_testNames = testNames; } public void setSkipFailedInvocationCounts(Boolean skip) { m_skipFailedInvocationCounts = skip; } private void addReporter(ReporterConfig reporterConfig) { Object instance = reporterConfig.newReporterInstance(); if (instance != null) { addListener(instance); } else { LOGGER.warn("Could not find reporte class : " + reporterConfig.getClassName()); } } /** * Specify if this run should be made in JUnit mode * * @param isJUnit */ public void setJUnit(Boolean isJUnit) { m_isJUnit = isJUnit; } /** * Specify if this run should be made in mixed mode */ public void setMixed(Boolean isMixed) { if(isMixed==null){ return; } m_isMixed = isMixed; } /** * @deprecated The TestNG version is now established at load time. This * method is not required anymore and is now a no-op. */ @Deprecated public static void setTestNGVersion() { LOGGER.info("setTestNGVersion has been deprecated."); } /** * Returns true if this is the JDK 1.4 JAR version of TestNG, false otherwise. * * @return true if this is the JDK 1.4 JAR version of TestNG, false otherwise. */ @Deprecated public static boolean isJdk14() { return false; } /** * Double check that the command line parameters are valid. */ protected static void validateCommandLineParameters(CommandLineArgs args) { String testClasses = args.testClass; List testNgXml = args.suiteFiles; String testJar = args.testJar; List methods = args.commandLineMethods; if (testClasses == null && testJar == null && (testNgXml == null || testNgXml.isEmpty()) && (methods == null || methods.isEmpty())) { throw new ParameterException("You need to specify at least one testng.xml, one class" + " or one method"); } String groups = args.groups; String excludedGroups = args.excludedGroups; if (testJar == null && (null != groups || null != excludedGroups) && testClasses == null && (testNgXml == null || testNgXml.isEmpty())) { throw new ParameterException("Groups option should be used with testclass option"); } Boolean junit = args.junit; Boolean mixed = args.mixed; if (junit && mixed) { throw new ParameterException(CommandLineArgs.MIXED + " can't be combined with " + CommandLineArgs.JUNIT); } } /** * @return true if at least one test failed. */ public boolean hasFailure() { return (getStatus() & HAS_FAILURE) == HAS_FAILURE; } /** * @return true if at least one test failed within success percentage. */ public boolean hasFailureWithinSuccessPercentage() { return (getStatus() & HAS_FSP) == HAS_FSP; } /** * @return true if at least one test was skipped. */ public boolean hasSkip() { return (getStatus() & HAS_SKIPPED) == HAS_SKIPPED; } static void exitWithError(String msg) { System.err.println(msg); usage(); System.exit(1); } public String getOutputDirectory() { return m_outputDir; } public IAnnotationTransformer getAnnotationTransformer() { return m_annotationTransformer; } /** * @deprecated Use addListener(ITestNGListener) instead */ // TODO make private @Deprecated public void setAnnotationTransformer(IAnnotationTransformer t) { // compare by reference! if (m_annotationTransformer != m_defaultAnnoProcessor && m_annotationTransformer != t) { LOGGER.warn("AnnotationTransformer already set"); } m_annotationTransformer = t; } /** * @return the defaultSuiteName */ public String getDefaultSuiteName() { return m_defaultSuiteName; } /** * @param defaultSuiteName the defaultSuiteName to set */ public void setDefaultSuiteName(String defaultSuiteName) { m_defaultSuiteName = defaultSuiteName; } /** * @return the defaultTestName */ public String getDefaultTestName() { return m_defaultTestName; } /** * @param defaultTestName the defaultTestName to set */ public void setDefaultTestName(String defaultTestName) { m_defaultTestName = defaultTestName; } /** * Sets the policy for whether or not to ever invoke a configuration method again after * it has failed once. Possible values are defined in {@link XmlSuite}. The default * value is {@link XmlSuite.FailurePolicy#SKIP}. * @param failurePolicy the configuration failure policy */ public void setConfigFailurePolicy(XmlSuite.FailurePolicy failurePolicy) { m_configFailurePolicy = failurePolicy; } /** * @deprecated Use {@link #setConfigFailurePolicy(org.testng.xml.XmlSuite.FailurePolicy)} instead */ @Deprecated public void setConfigFailurePolicy(String failurePolicy) { setConfigFailurePolicy(XmlSuite.FailurePolicy.getValidPolicy(failurePolicy)); } /** * Returns the configuration failure policy. * @return config failure policy */ public XmlSuite.FailurePolicy getConfigFailurePolicy() { return m_configFailurePolicy; } // DEPRECATED: to be removed after a major version change /** * @deprecated since 5.1 */ @Deprecated public static TestNG getDefault() { return m_instance; } /** * @deprecated since 5.1 */ @Deprecated public void setHasFailure(boolean hasFailure) { m_status |= HAS_FAILURE; } /** * @deprecated since 5.1 */ @Deprecated public void setHasFailureWithinSuccessPercentage(boolean hasFailureWithinSuccessPercentage) { m_status |= HAS_FSP; } /** * @deprecated since 5.1 */ @Deprecated public void setHasSkip(boolean hasSkip) { m_status |= HAS_SKIPPED; } public static class ExitCodeListener implements IResultListener2 { private TestNG m_mainRunner; public ExitCodeListener() { m_mainRunner = TestNG.m_instance; } public ExitCodeListener(TestNG runner) { m_mainRunner = runner; } @Override public void beforeConfiguration(ITestResult tr) { } @Override public void onTestFailure(ITestResult result) { setHasRunTests(); m_mainRunner.setStatus(HAS_FAILURE); } @Override public void onTestSkipped(ITestResult result) { setHasRunTests(); if ((m_mainRunner.getStatus() & HAS_FAILURE) != 0) { m_mainRunner.setStatus(HAS_SKIPPED); } } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult result) { setHasRunTests(); m_mainRunner.setStatus(HAS_FSP); } @Override public void onTestSuccess(ITestResult result) { setHasRunTests(); } @Override public void onStart(ITestContext context) { setHasRunTests(); } @Override public void onFinish(ITestContext context) { } @Override public void onTestStart(ITestResult result) { setHasRunTests(); } private void setHasRunTests() { m_mainRunner.m_hasTests= true; } /** * @see org.testng.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult) */ @Override public void onConfigurationFailure(ITestResult itr) { m_mainRunner.setStatus(HAS_FAILURE); } /** * @see org.testng.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult) */ @Override public void onConfigurationSkip(ITestResult itr) { m_mainRunner.setStatus(HAS_SKIPPED); } /** * @see org.testng.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult) */ @Override public void onConfigurationSuccess(ITestResult itr) { } } private void setConfigurable(IConfigurable c) { // compare by reference! if (m_configurable != null && m_configurable != c) { LOGGER.warn("Configurable already set"); } m_configurable = c; } private void setHookable(IHookable h) { // compare by reference! if (m_hookable != null && m_hookable != h) { LOGGER.warn("Hookable already set"); } m_hookable = h; } public void setMethodInterceptor(IMethodInterceptor methodInterceptor) { m_methodInterceptors.add(methodInterceptor); } public void setDataProviderThreadCount(int count) { m_dataProviderThreadCount = count; } /** Add a class loader to the searchable loaders. */ public void addClassLoader(final ClassLoader loader) { if (loader != null) { ClassHelper.addClassLoader(loader); } } public void setPreserveOrder(boolean b) { m_preserveOrder = b; } protected long getStart() { return m_start; } protected long getEnd() { return m_end; } public void setGroupByInstances(boolean b) { m_groupByInstances = b; } ///// // ServiceLoader testing // private URLClassLoader m_serviceLoaderClassLoader; private List m_serviceLoaderListeners = Lists.newArrayList(); /* * Used to test ServiceClassLoader */ public void setServiceLoaderClassLoader(URLClassLoader ucl) { m_serviceLoaderClassLoader = ucl; } /* * Used to test ServiceClassLoader */ private void addServiceLoaderListener(ITestNGListener l) { m_serviceLoaderListeners.add(l); } /* * Used to test ServiceClassLoader */ public List getServiceLoaderListeners() { return m_serviceLoaderListeners; } // // ServiceLoader testing ///// } testng-6.9.12/src/main/java/org/testng/SuiteRunner.java0000644000175000017500000005052412732165123022304 0ustar eugeneeugenepackage org.testng; import static org.testng.internal.Utils.isStringBlank; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.Attributes; import org.testng.internal.IConfiguration; import org.testng.internal.IInvoker; import org.testng.internal.Utils; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.thread.ThreadUtil; import org.testng.reporters.JUnitXMLReporter; import org.testng.reporters.TestHTMLReporter; import org.testng.reporters.TextReporter; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import java.io.File; import java.io.Serializable; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.google.inject.Injector; /** * SuiteRunner is responsible for running all the tests included in one * suite. The test start is triggered by {@link #run()} method. * * @author Cedric Beust, Apr 26, 2004 */ public class SuiteRunner implements ISuite, Serializable, IInvokedMethodListener { /* generated */ private static final long serialVersionUID = 5284208932089503131L; private static final String DEFAULT_OUTPUT_DIR = "test-output"; private Map m_suiteResults = Collections.synchronizedMap(Maps.newLinkedHashMap()); transient private List m_testRunners = Lists.newArrayList(); transient private Map, ISuiteListener> m_listeners = Maps.newHashMap(); transient private TestListenerAdapter m_textReporter = new TestListenerAdapter(); private String m_outputDir; // DEFAULT_OUTPUT_DIR; private XmlSuite m_suite; private Injector m_parentInjector; transient private List m_testListeners = Lists.newArrayList(); transient private List m_classListeners = Lists.newArrayList(); transient private ITestRunnerFactory m_tmpRunnerFactory; transient private ITestRunnerFactory m_runnerFactory; transient private boolean m_useDefaultListeners = true; // The remote host where this suite was run, or null if run locally private String m_host; // The configuration transient private IConfiguration m_configuration; transient private ITestObjectFactory m_objectFactory; transient private Boolean m_skipFailedInvocationCounts = Boolean.FALSE; transient private List m_methodInterceptors; private Map, IInvokedMethodListener> m_invokedMethodListeners; /** The list of all the methods invoked during this run */ private List m_invokedMethods = Collections.synchronizedList(Lists.newArrayList()); private List m_allTestMethods = Lists.newArrayList(); // transient private IAnnotationTransformer m_annotationTransformer = null; public SuiteRunner(IConfiguration configuration, XmlSuite suite, String outputDir) { this(configuration, suite, outputDir, null); } public SuiteRunner(IConfiguration configuration, XmlSuite suite, String outputDir, ITestRunnerFactory runnerFactory) { this(configuration, suite, outputDir, runnerFactory, false); } public SuiteRunner(IConfiguration configuration, XmlSuite suite, String outputDir, ITestRunnerFactory runnerFactory, boolean useDefaultListeners) { this(configuration, suite, outputDir, runnerFactory, useDefaultListeners, new ArrayList() /* method interceptor */, null /* invoked method listeners */, null /* test listeners */, null /* class listeners */); } protected SuiteRunner(IConfiguration configuration, XmlSuite suite, String outputDir, ITestRunnerFactory runnerFactory, boolean useDefaultListeners, List methodInterceptors, List invokedMethodListeners, List testListeners, List classListeners) { init(configuration, suite, outputDir, runnerFactory, useDefaultListeners, methodInterceptors, invokedMethodListeners, testListeners, classListeners); } private void init(IConfiguration configuration, XmlSuite suite, String outputDir, ITestRunnerFactory runnerFactory, boolean useDefaultListeners, List methodInterceptors, List invokedMethodListener, List testListeners, List classListeners) { m_configuration = configuration; m_suite = suite; m_useDefaultListeners = useDefaultListeners; m_tmpRunnerFactory= runnerFactory; m_methodInterceptors = methodInterceptors != null ? methodInterceptors : new ArrayList(); setOutputDir(outputDir); m_objectFactory = m_configuration.getObjectFactory(); if(m_objectFactory == null) { m_objectFactory = suite.getObjectFactory(); } // Add our own IInvokedMethodListener m_invokedMethodListeners = Maps.newHashMap(); if (invokedMethodListener != null) { for (IInvokedMethodListener listener : invokedMethodListener) { m_invokedMethodListeners.put(listener.getClass(), listener); } } m_invokedMethodListeners.put(getClass(), this); m_skipFailedInvocationCounts = suite.skipFailedInvocationCounts(); if (null != testListeners) { m_testListeners.addAll(testListeners); } if (null != classListeners) { m_classListeners.addAll(classListeners); } m_runnerFactory = buildRunnerFactory(); // Order the tags based on their order of appearance in testng.xml List xmlTests = m_suite.getTests(); Collections.sort(xmlTests, new Comparator() { @Override public int compare(XmlTest arg0, XmlTest arg1) { return arg0.getIndex() - arg1.getIndex(); } }); for (XmlTest test : xmlTests) { TestRunner tr = m_runnerFactory.newTestRunner(this, test, m_invokedMethodListeners.values(), m_classListeners); // // Install the method interceptor, if any was passed // for (IMethodInterceptor methodInterceptor : m_methodInterceptors) { tr.addMethodInterceptor(methodInterceptor); } // Reuse the same text reporter so we can accumulate all the results // (this is used to display the final suite report at the end) tr.addListener(m_textReporter); m_testRunners.add(tr); // Add the methods found in this test to our global count m_allTestMethods.addAll(Arrays.asList(tr.getAllTestMethods())); } } @Override public XmlSuite getXmlSuite() { return m_suite; } @Override public String getName() { return m_suite.getName(); } public void setObjectFactory(ITestObjectFactory objectFactory) { m_objectFactory = objectFactory; } public void setReportResults(boolean reportResults) { m_useDefaultListeners = reportResults; } private void invokeListeners(boolean start) { for (ISuiteListener sl : m_listeners.values()) { if (start) { sl.onStart(this); } else { sl.onFinish(this); } } } private void setOutputDir(String outputdir) { if (isStringBlank(outputdir) && m_useDefaultListeners) { outputdir = DEFAULT_OUTPUT_DIR; } m_outputDir = (null != outputdir) ? new File(outputdir).getAbsolutePath() : null; } private ITestRunnerFactory buildRunnerFactory() { ITestRunnerFactory factory = null; if (null == m_tmpRunnerFactory) { factory = new DefaultTestRunnerFactory(m_configuration, m_testListeners.toArray(new ITestListener[m_testListeners.size()]), m_useDefaultListeners, m_skipFailedInvocationCounts); } else { factory = new ProxyTestRunnerFactory( m_testListeners.toArray(new ITestListener[m_testListeners.size()]), m_tmpRunnerFactory); } return factory; } @Override public String getParallel() { return m_suite.getParallel().toString(); } public String getParentModule() { return m_suite.getParentModule(); } @Override public String getGuiceStage() { return m_suite.getGuiceStage(); } public Injector getParentInjector() { return m_parentInjector; } public void setParentInjector(Injector injector) { m_parentInjector = injector; } @Override public void run() { invokeListeners(true /* start */); try { privateRun(); } finally { invokeListeners(false /* stop */); } } private void privateRun() { // Map for unicity, Linked for guaranteed order Map beforeSuiteMethods= new LinkedHashMap<>(); Map afterSuiteMethods = new LinkedHashMap<>(); IInvoker invoker = null; // Get the invoker and find all the suite level methods for (TestRunner tr: m_testRunners) { // TODO: Code smell. Invoker should belong to SuiteRunner, not TestRunner // -- cbeust invoker = tr.getInvoker(); for (ITestNGMethod m : tr.getBeforeSuiteMethods()) { beforeSuiteMethods.put(m.getMethod(), m); } for (ITestNGMethod m : tr.getAfterSuiteMethods()) { afterSuiteMethods.put(m.getMethod(), m); } } // // Invoke beforeSuite methods (the invoker can be null // if the suite we are currently running only contains // a tag and no real tests) // if (invoker != null) { if(beforeSuiteMethods.values().size() > 0) { invoker.invokeConfigurations(null, beforeSuiteMethods.values().toArray(new ITestNGMethod[beforeSuiteMethods.size()]), m_suite, m_suite.getParameters(), null, /* no parameter values */ null /* instance */ ); } Utils.log("SuiteRunner", 3, "Created " + m_testRunners.size() + " TestRunners"); // // Run all the test runners // boolean testsInParallel = XmlSuite.ParallelMode.TESTS.equals(m_suite.getParallel()); if (!testsInParallel) { runSequentially(); } else { runInParallelTestMode(); } // SuitePlan sp = new SuitePlan(); // for (TestRunner tr : m_testRunners) { // sp.addTestPlan(tr.getTestPlan()); // } // sp.dump(); // // Invoke afterSuite methods // if (afterSuiteMethods.values().size() > 0) { invoker.invokeConfigurations(null, afterSuiteMethods.values().toArray(new ITestNGMethod[afterSuiteMethods.size()]), m_suite, m_suite.getAllParameters(), null, /* no parameter values */ null /* instance */); } } } private List m_reporters = Lists.newArrayList(); private void addReporter(IReporter listener) { m_reporters.add(listener); } void addConfigurationListener(IConfigurationListener listener) { m_configuration.addConfigurationListener(listener); } public List getReporters() { return m_reporters; } private void runSequentially() { for (TestRunner tr : m_testRunners) { runTest(tr); } } private void runTest(TestRunner tr) { tr.run(); ISuiteResult sr = new SuiteResult(m_suite, tr); m_suiteResults.put(tr.getName(), sr); } /** * Implement . * Since this kind of parallelism happens at the suite level, we need a special code path * to execute it. All the other parallelism strategies are implemented at the test level * in TestRunner#createParallelWorkers (but since this method deals with just one * tag, it can't implement , which is why we're doing it here). */ private void runInParallelTestMode() { List tasks= Lists.newArrayList(m_testRunners.size()); for(TestRunner tr: m_testRunners) { tasks.add(new SuiteWorker(tr)); } ThreadUtil.execute(tasks, m_suite.getThreadCount(), m_suite.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS), false); } private class SuiteWorker implements Runnable { private TestRunner m_testRunner; public SuiteWorker(TestRunner tr) { m_testRunner = tr; } @Override public void run() { Utils.log("[SuiteWorker]", 4, "Running XML Test '" + m_testRunner.getTest().getName() + "' in Parallel"); runTest(m_testRunner); } } /** * Registers ISuiteListeners interested in reporting the result of the current * suite. * * @param reporter */ protected void addListener(ISuiteListener reporter) { m_listeners.put(reporter.getClass(), reporter); } @Override public void addListener(ITestNGListener listener) { if (listener instanceof IInvokedMethodListener) { IInvokedMethodListener invokedMethodListener = (IInvokedMethodListener) listener; m_invokedMethodListeners.put(invokedMethodListener.getClass(), invokedMethodListener); } if (listener instanceof ISuiteListener) { addListener((ISuiteListener) listener); } if (listener instanceof IReporter) { addReporter((IReporter) listener); } if (listener instanceof IConfigurationListener) { addConfigurationListener((IConfigurationListener) listener); } } @Override public String getOutputDirectory() { return m_outputDir + File.separatorChar + getName(); } @Override public Map getResults() { return m_suiteResults; } /** * FIXME: should be removed? * * @see org.testng.ISuite#getParameter(java.lang.String) */ @Override public String getParameter(String parameterName) { return m_suite.getParameter(parameterName); } /** * @see org.testng.ISuite#getMethodsByGroups() */ @Override public Map> getMethodsByGroups() { Map> result = Maps.newHashMap(); for (TestRunner tr : m_testRunners) { ITestNGMethod[] methods = tr.getAllTestMethods(); for (ITestNGMethod m : methods) { String[] groups = m.getGroups(); for (String groupName : groups) { Collection testMethods = result.get(groupName); if (null == testMethods) { testMethods = Lists.newArrayList(); result.put(groupName, testMethods); } testMethods.add(m); } } } return result; } /** * @see org.testng.ISuite#getInvokedMethods() */ @Override public Collection getInvokedMethods() { return getIncludedOrExcludedMethods(true /* included */); } /** * @see org.testng.ISuite#getExcludedMethods() */ @Override public Collection getExcludedMethods() { return getIncludedOrExcludedMethods(false/* included */); } private Collection getIncludedOrExcludedMethods(boolean included) { List result= Lists.newArrayList(); for (TestRunner tr : m_testRunners) { Collection methods = included ? tr.getInvokedMethods() : tr.getExcludedMethods(); for (ITestNGMethod m : methods) { result.add(m); } } return result; } @Override public IObjectFactory getObjectFactory() { return m_objectFactory instanceof IObjectFactory ? (IObjectFactory) m_objectFactory : null; } @Override public IObjectFactory2 getObjectFactory2() { return m_objectFactory instanceof IObjectFactory2 ? (IObjectFactory2) m_objectFactory : null; } /** * Returns the annotation finder for the given annotation type. * @return the annotation finder for the given annotation type. */ @Override public IAnnotationFinder getAnnotationFinder() { return m_configuration.getAnnotationFinder(); } public static void ppp(String s) { System.out.println("[SuiteRunner] " + s); } /** * The default implementation of {@link ITestRunnerFactory}. */ private static class DefaultTestRunnerFactory implements ITestRunnerFactory { private ITestListener[] m_failureGenerators; private boolean m_useDefaultListeners; private boolean m_skipFailedInvocationCounts; private IConfiguration m_configuration; public DefaultTestRunnerFactory(IConfiguration configuration, ITestListener[] failureListeners, boolean useDefaultListeners, boolean skipFailedInvocationCounts) { m_configuration = configuration; m_failureGenerators = failureListeners; m_useDefaultListeners = useDefaultListeners; m_skipFailedInvocationCounts = skipFailedInvocationCounts; } @Override public TestRunner newTestRunner(ISuite suite, XmlTest test, Collection listeners, List classListeners) { boolean skip = m_skipFailedInvocationCounts; if (! skip) { skip = test.skipFailedInvocationCounts(); } TestRunner testRunner = new TestRunner(m_configuration, suite, test, suite.getOutputDirectory(), suite.getAnnotationFinder(), skip, listeners, classListeners); if (m_useDefaultListeners) { testRunner.addListener(new TestHTMLReporter()); testRunner.addListener(new JUnitXMLReporter()); //TODO: Moved these here because maven2 has output reporters running //already, the output from these causes directories to be created with //files. This is not the desired behaviour of running tests in maven2. //Don't know what to do about this though, are people relying on these //to be added even with defaultListeners set to false? testRunner.addListener(new TextReporter(testRunner.getName(), TestRunner.getVerbose())); } for (ITestListener itl : m_failureGenerators) { testRunner.addTestListener(itl); } for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) { testRunner.addConfigurationListener(cl); } return testRunner; } } private static class ProxyTestRunnerFactory implements ITestRunnerFactory { private ITestListener[] m_failureGenerators; private ITestRunnerFactory m_target; public ProxyTestRunnerFactory(ITestListener[] failureListeners, ITestRunnerFactory target) { m_failureGenerators = failureListeners; m_target= target; } @Override public TestRunner newTestRunner(ISuite suite, XmlTest test, Collection listeners, List classListeners) { TestRunner testRunner= m_target.newTestRunner(suite, test, listeners, classListeners); testRunner.addListener(new TextReporter(testRunner.getName(), TestRunner.getVerbose())); for (ITestListener itl : m_failureGenerators) { testRunner.addListener(itl); } return testRunner; } } public void setHost(String host) { m_host = host; } @Override public String getHost() { return m_host; } private SuiteRunState m_suiteState= new SuiteRunState(); /** * @see org.testng.ISuite#getSuiteState() */ @Override public SuiteRunState getSuiteState() { return m_suiteState; } public void setSkipFailedInvocationCounts(Boolean skipFailedInvocationCounts) { if (skipFailedInvocationCounts != null) { m_skipFailedInvocationCounts = skipFailedInvocationCounts; } } private IAttributes m_attributes = new Attributes(); @Override public Object getAttribute(String name) { return m_attributes.getAttribute(name); } @Override public void setAttribute(String name, Object value) { m_attributes.setAttribute(name, value); } @Override public Set getAttributeNames() { return m_attributes.getAttributeNames(); } @Override public Object removeAttribute(String name) { return m_attributes.removeAttribute(name); } ///// // implements IInvokedMethodListener // @Override public void afterInvocation(IInvokedMethod method, ITestResult testResult) { } @Override public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { if (method == null) { throw new NullPointerException("Method should not be null"); } m_invokedMethods.add(method); } // // implements IInvokedMethodListener ///// @Override public List getAllInvokedMethods() { return m_invokedMethods; } @Override public List getAllMethods() { return m_allTestMethods; } } testng-6.9.12/src/main/java/org/testng/IClassListener.java0000644000175000017500000000025112732165123022675 0ustar eugeneeugenepackage org.testng; public interface IClassListener extends ITestNGListener { void onBeforeClass(ITestClass testClass); void onAfterClass(ITestClass testClass); } testng-6.9.12/src/main/java/org/testng/TestException.java0000755000175000017500000000073012732165123022614 0ustar eugeneeugenepackage org.testng; /** * Exception thrown when an exception happens while running a test * method. * * @author Cedric Beust, Apr 26, 2004 * */ public class TestException extends TestNGException { private static final long serialVersionUID = -7946644025188038804L; public TestException(String s) { super(s); } public TestException(Throwable t) { super(t); } public TestException(String message, Throwable t) { super(message, t); } } testng-6.9.12/src/main/java/org/testng/SuiteRunState.java0000755000175000017500000000115012732165123022572 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; /** * A state object that records the status of the suite run. Mainly used to * figure out if there are any @BeforeSuite failures. * * @author Alexandru Popescu */ public class SuiteRunState implements Serializable { /** * */ private static final long serialVersionUID = -2716934905049123874L; private boolean m_hasFailures; public synchronized void failed() { m_hasFailures= true; } public synchronized boolean isFailed() { return m_hasFailures; } } testng-6.9.12/src/main/java/org/testng/ReporterConfig.java0000755000175000017500000000720112732165123022746 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Lists; import org.testng.internal.ClassHelper; import org.testng.internal.PropertyUtils; import org.testng.internal.Utils; import java.util.List; /** * Stores the information regarding the configuration of a pluggable report listener. Used also * in conjunction with the <reporter> sub-element of the Ant task * * NOTE: this class needs to be public. It's used by TestNG Ant task * * @author Cosmin Marginean, Apr 12, 2007 */ public class ReporterConfig { /** * The class name of the reporter listener */ private String m_className; /** * The properties of the reporter listener */ private List m_properties = Lists.newArrayList(); public void addProperty(Property property) { m_properties.add(property); } public List getProperties() { return m_properties; } public String getClassName() { return m_className; } public void setClassName(String className) { this.m_className = className; } public String serialize() { StringBuffer sb = new StringBuffer(); sb.append(m_className); if (!m_properties.isEmpty()) { sb.append(":"); for (int i = 0; i < m_properties.size(); i++) { ReporterConfig.Property property = m_properties.get(i); sb.append(property.getName()); sb.append("="); sb.append(property.getValue()); if (i < m_properties.size() - 1) { sb.append(","); } } } return sb.toString(); } public static ReporterConfig deserialize(String inputString) { ReporterConfig reporterConfig = null; if (!Utils.isStringEmpty(inputString)) { reporterConfig = new ReporterConfig(); int clsNameEndIndex = inputString.indexOf(":"); if (clsNameEndIndex == -1) { reporterConfig.setClassName(inputString); } else { reporterConfig.setClassName(inputString.substring(0, clsNameEndIndex)); String propString = inputString.substring(clsNameEndIndex + 1, inputString.length()); String[] props = propString.split(","); if ((props != null) && (props.length > 0)) { for (String prop : props) { String[] propNameAndVal = prop.split("="); if ((propNameAndVal != null) && (propNameAndVal.length == 2)) { Property property = new Property(); property.setName(propNameAndVal[0]); property.setValue(propNameAndVal[1]); reporterConfig.addProperty(property); } } } } } return reporterConfig; } /** * Creates a reporter based on the current configuration */ public Object newReporterInstance() { Object result = null; Class reporterClass = ClassHelper.forName(m_className); if (reporterClass != null) { result = ClassHelper.newInstance(reporterClass); for (ReporterConfig.Property property : m_properties) { PropertyUtils.setProperty(result, property.getName(), property.getValue()); } } return result; } public static class Property { private String name; private String value; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } @Override public String toString() { StringBuffer buf = new StringBuffer(); buf.append("\nClass = " + m_className); for (Property prop : m_properties) { buf.append("\n\t " + prop.getName() + "=" + prop.getValue()); } return buf.toString(); } } testng-6.9.12/src/main/java/org/testng/DependencyMap.java0000644000175000017500000000446412732165123022537 0ustar eugeneeugenepackage org.testng; import org.testng.collections.ListMultiMap; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; /** * Helper class to keep track of dependencies. * * @author Cedric Beust */ public class DependencyMap { private ListMultiMap m_dependencies = Maps.newListMultiMap(); private ListMultiMap m_groups = Maps.newListMultiMap(); public DependencyMap(ITestNGMethod[] methods) { for (ITestNGMethod m : methods) { m_dependencies.put( m.getRealClass().getName() + "." + m.getMethodName(), m); for (String g : m.getGroups()) { m_groups.put(g, m); } } } public List getMethodsThatBelongTo(String group, ITestNGMethod fromMethod) { Set uniqueKeys = m_groups.keySet(); List result = Lists.newArrayList(); for (String k : uniqueKeys) { if (Pattern.matches(group, k)) { List temp = m_groups.get(k); if (temp != null) result.addAll(m_groups.get(k)); } } if (result.isEmpty() && !fromMethod.ignoreMissingDependencies()) { throw new TestNGException("DependencyMap::Method \"" + fromMethod + "\" depends on nonexistent group \"" + group + "\""); } else { return result; } } public ITestNGMethod getMethodDependingOn(String methodName, ITestNGMethod fromMethod) { List l = m_dependencies.get(methodName); if (l == null && fromMethod.ignoreMissingDependencies()){ return fromMethod; } if (l != null) { for (ITestNGMethod m : l) { // If they are in the same class hierarchy, they must belong to the same instance, // otherwise, it's a method depending on a method in a different class so we // don't bother checking the instance if (fromMethod.getRealClass().isAssignableFrom(m.getRealClass())) { if (m.getInstance() == fromMethod.getInstance()) return m; } else { return m; } } } throw new TestNGException("Method \"" + fromMethod + "\" depends on nonexistent method \"" + methodName + "\""); } } testng-6.9.12/src/main/java/org/testng/IHookable.java0000755000175000017500000000160112732165123021651 0ustar eugeneeugenepackage org.testng; /** * If a test class implements this interface, its run() method * will be invoked instead of each @Test method found. The invocation of * the test method will then be performed upon invocation of the callBack() * method of the IHookCallBack parameter. * * This is useful to test classes that require JAAS authentication, which can * be implemented as follows: * *
 * public void run(final IHookCallBack icb, ITestResult testResult) {
 *   // Preferably initialized in a @Configuration method
 *   mySubject = authenticateWithJAAs();
 *
 *   Subject.doAs(mySubject, new PrivilegedExceptionAction() {
 *     public Object run() {
 *       icb.callback(testResult);
 *     }
 *   };
 * }
 * 
* * @author cbeust * Jan 28, 2006 */ public interface IHookable extends ITestNGListener { public void run(IHookCallBack callBack, ITestResult testResult); } testng-6.9.12/src/main/java/org/testng/IConfigurationListener.java0000755000175000017500000000102512732165123024442 0ustar eugeneeugenepackage org.testng; /** * Listener interface for events related to configuration methods. */ public interface IConfigurationListener extends ITestNGListener { /** * Invoked whenever a configuration method succeeded. */ void onConfigurationSuccess(ITestResult itr); /** * Invoked whenever a configuration method failed. */ void onConfigurationFailure(ITestResult itr); /** * Invoked whenever a configuration method was skipped. */ void onConfigurationSkip(ITestResult itr); } testng-6.9.12/src/main/java/org/testng/ITest.java0000755000175000017500000000060412732165123021046 0ustar eugeneeugenepackage org.testng; /** * If a test class implements this interface, it will receive a * special treatment, such as having the test name displayed * in the HTML reports. * * @author cbeust * Jun 6, 2006 */ public interface ITest { /** * The name of test instance(s). * @return name associated with a particular instance of a test. */ public String getTestName(); } testng-6.9.12/src/main/java/org/testng/SkipException.java0000755000175000017500000000433412732165123022607 0ustar eugeneeugenepackage org.testng; /** * The root exception for special skip handling. In case a @Test or @Configuration * throws this exception the method will be considered a skip or a failure according to the * return of {@link #isSkip()}. * Users may provide extensions to this mechanism by extending this class. * * @author Alex Popescu * @since 5.6 */ public class SkipException extends RuntimeException { private static final long serialVersionUID = 4052142657885527260L; private StackTraceElement[] m_stackTrace; private volatile boolean m_stackReduced; public SkipException(String skipMessage) { super(skipMessage); } public SkipException(String skipMessage, Throwable cause) { super(skipMessage, cause); } /** * Flag if the current exception marks a skipped method (true) * or a failure (false). By default Subclasses should override this method * in order to provide smarter behavior. * * @return true if the method should be considered a skip, * false if the method should be considered failed. If not * overwritten it returns true */ public boolean isSkip() { return true; } /** * Subclasses may use this method to reduce the printed stack trace. * This method keeps only the last frame. * Important: after calling this method the preserved internally * and can be restored called {@link #restoreStackTrace}. */ protected void reduceStackTrace() { if(!m_stackReduced) { synchronized(this) { StackTraceElement[] newStack= new StackTraceElement[1]; StackTraceElement[] originalStack= getStackTrace(); if(originalStack.length > 0) { m_stackTrace= originalStack; newStack[0]= getStackTrace()[0]; setStackTrace(newStack); } m_stackReduced= true; } } } /** * Restores the original exception stack trace after a * previous call to {@link #reduceStackTrace()}. * */ protected void restoreStackTrace() { if(m_stackReduced && null != m_stackTrace) { synchronized(this) { setStackTrace(m_stackTrace); m_stackReduced= false; } } } } testng-6.9.12/src/main/java/org/testng/SuiteRunnerWorker.java0000644000175000017500000001142412732165123023472 0ustar eugeneeugenepackage org.testng; import org.testng.collections.Lists; import org.testng.collections.Objects; import org.testng.internal.SuiteRunnerMap; import org.testng.internal.Utils; import org.testng.internal.thread.graph.IWorker; import org.testng.xml.XmlSuite; import java.util.Collection; import java.util.List; import java.util.Map; /** * An {@code IWorker} that is used to encapsulate and run Suite Runners * * @author cbeust, nullin */ public class SuiteRunnerWorker implements IWorker { private SuiteRunner m_suiteRunner; private Integer m_verbose; private String m_defaultSuiteName; private SuiteRunnerMap m_suiteRunnerMap; public SuiteRunnerWorker(ISuite suiteRunner, SuiteRunnerMap suiteRunnerMap, int verbose, String defaultSuiteName) { m_suiteRunnerMap = suiteRunnerMap; m_suiteRunner = (SuiteRunner) suiteRunner; m_verbose = verbose; m_defaultSuiteName = defaultSuiteName; } /** * Runs a suite * @param suiteRunnerMap map of suiteRunners that are updated with test results * @param xmlSuite XML suites to run */ private void runSuite(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite) { if (m_verbose > 0) { StringBuffer allFiles = new StringBuffer(); allFiles.append(" ").append(xmlSuite.getFileName() != null ? xmlSuite.getFileName() : m_defaultSuiteName).append('\n'); Utils.log("TestNG", 0, "Running:\n" + allFiles.toString()); } SuiteRunner suiteRunner = (SuiteRunner) suiteRunnerMap.get(xmlSuite); suiteRunner.run(); //TODO: this should be handled properly // for (IReporter r : suiteRunner.getReporters()) { // addListener(r); // } // PoolService.getInstance().shutdown(); // // Display the final statistics // if (xmlSuite.getVerbose() > 0) { SuiteResultCounts counts = new SuiteResultCounts(); synchronized (suiteRunnerMap) { counts.calculateResultCounts(xmlSuite, suiteRunnerMap); } StringBuffer bufLog = new StringBuffer("\n===============================================\n") .append(xmlSuite.getName()); bufLog.append("\nTotal tests run: ") .append(counts.m_total).append(", Failures: ").append(counts.m_failed) .append(", Skips: ").append(counts.m_skipped); if(counts.m_confFailures > 0 || counts.m_confSkips > 0) { bufLog.append("\nConfiguration Failures: ").append(counts.m_confFailures) .append(", Skips: ").append(counts.m_confSkips); } bufLog.append("\n===============================================\n"); System.out.println(bufLog.toString()); } } @Override public void run() { runSuite(m_suiteRunnerMap, m_suiteRunner.getXmlSuite()); } @Override public int compareTo(IWorker arg0) { /* * Dummy Implementation * * Used by IWorkers to prioritize execution in parallel. Not required by * this Worker in current implementation */ return 0; } @Override public List getTasks() { List suiteRunnerList = Lists.newArrayList(); suiteRunnerList.add(m_suiteRunner); return suiteRunnerList; } @Override public String toString() { return Objects.toStringHelper(getClass()) .add("name", m_suiteRunner.getName()) .toString(); } @Override public long getTimeOut() { return m_suiteRunner.getXmlSuite().getTimeOut(Long.MAX_VALUE); } @Override public int getPriority() { // this class doesnt support priorities yet return 0; } } /** * Class to help calculate result counts for tests run as part of a suite and * its children suites * * @author nullin * */ class SuiteResultCounts { int m_total = 0; int m_skipped = 0; int m_failed = 0; int m_confFailures = 0; int m_confSkips = 0; public void calculateResultCounts(XmlSuite xmlSuite, SuiteRunnerMap suiteRunnerMap) { ISuite iSuite = suiteRunnerMap.get(xmlSuite); if (iSuite != null) { Map results = iSuite.getResults(); if (results != null) { Collection tempSuiteResult = results.values(); for (ISuiteResult isr : tempSuiteResult) { ITestContext ctx = isr.getTestContext(); int skipped = ctx.getSkippedTests().size(); int failed = ctx.getFailedTests().size() + ctx.getFailedButWithinSuccessPercentageTests().size(); m_skipped += skipped; m_failed += failed; m_confFailures += ctx.getFailedConfigurations().size(); m_confSkips += ctx.getSkippedConfigurations().size(); m_total += ctx.getPassedTests().size() + failed + skipped; } for (XmlSuite childSuite : xmlSuite.getChildSuites()) { calculateResultCounts(childSuite, suiteRunnerMap); } } } } } testng-6.9.12/src/main/java/org/testng/ITestNGListener.java0000755000175000017500000000026412732165123023003 0ustar eugeneeugenepackage org.testng; /** * This is a marker interface for all objects that can be passed * as a -listener argument. * * @author cbeust */ public interface ITestNGListener { } testng-6.9.12/src/main/java/org/testng/IConfigurationListener2.java0000644000175000017500000000032212732165123024520 0ustar eugeneeugenepackage org.testng; public interface IConfigurationListener2 extends IConfigurationListener { /** * Invoked before a configuration method is invoked. */ void beforeConfiguration(ITestResult tr); } testng-6.9.12/src/main/java/org/testng/log/0000755000175000017500000000000012732165123017731 5ustar eugeneeugenetestng-6.9.12/src/main/java/org/testng/log/TextFormatter.java0000755000175000017500000000111012732165123023400 0ustar eugeneeugenepackage org.testng.log; import java.util.logging.LogRecord; import java.util.logging.SimpleFormatter; /** * This class implements a simple TextFormatter because the brainded * default formatter of java.util.logging outputs everything on two * lines and it's ugly as butt. * * @author Cedric Beust, May 2, 2004 * */ public class TextFormatter extends SimpleFormatter { @Override public synchronized String format(LogRecord record) { StringBuffer result = new StringBuffer(); result.append(record.getMessage()).append("\n"); return result.toString(); } } testng-6.9.12/src/main/java/org/testng/IExtraOutput.java0000755000175000017500000000107512732165123022436 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; import java.util.List; /** * This class is used by Reporter to store the extra output to be later * included in the HTML report: * - User-generated report * - Parameter info * * Created on Feb 16, 2006 * @author Cedric Beust */ public interface IExtraOutput extends Serializable { /** * @return a List representing the parameters passed * to this test method, or an empty List if no parameters were used. */ public List getParameterOutput(); } testng-6.9.12/src/main/java/org/testng/ConversionUtils.java0000644000175000017500000000247212732165123023166 0ustar eugeneeugenepackage org.testng; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * Helper methods used by the Eclipse plug-in when converting tests from JUnit. * * @author Cedric Beust * */ public class ConversionUtils { /** * Turns the output of a JUnit 4 @Parameters style data provider into * one that is suitable for TestNG's @DataProvider. */ public static Object[] wrapDataProvider(Class cls, Collection data) { List result = new ArrayList(); for (Object o : data) { Object[] parameters = (Object[]) o; Constructor ctor = null; try { for (Constructor c : cls.getConstructors()) { // Just comparing parameter array sizes. Comparing the parameter types // is more error prone since we need to take conversions into account // (int -> Integer, etc...). if (c.getParameterTypes().length == parameters.length) { ctor = c; break; } } if (ctor == null) { throw new TestNGException("Couldn't find a constructor in " + cls); } result.add(ctor.newInstance(parameters)); } catch (Exception ex) { ex.printStackTrace(); } } return result.toArray(); } } testng-6.9.12/src/main/java/org/testng/IHookCallBack.java0000755000175000017500000000123612732165123022406 0ustar eugeneeugenepackage org.testng; /** * A parameter of this type will be passed to the run() method of a IHookable. * Invoking runTestMethod() on that parameter will cause the test method currently * being diverted to be invoked. * *

* * This interface is not meant to be implemented by clients, only by TestNG. * * @see org.testng.IHookable * * * @author cbeust * Jan 28, 2006 */ public interface IHookCallBack { /** * Invoke the test method currently being hijacked. */ public void runTestMethod(ITestResult testResult); /** * @return the parameters that will be used to invoke the test method. */ public Object[] getParameters(); } testng-6.9.12/src/main/java/org/testng/IMethodSelectorContext.java0000755000175000017500000000165412732165123024423 0ustar eugeneeugenepackage org.testng; import java.util.Map; /** * An implementation of this interface is passed to all the Method Selectors * when their includeMethod() is invoked. Method selectors can invoke * any method of this context at that time. * * Created on Jan 3, 2007 * @author Cedric Beust */ public interface IMethodSelectorContext { /** * @return true if no more Method Selectors should be invoked after * the current one. */ public boolean isStopped(); /** * Indicate that no other Method Selectors should be invoked after the * current one if stopped is false. * @param stopped */ public void setStopped(boolean stopped); /** * @return a Map that can be freely manipulated by the Method Selector. * This can be used to share information among several Method Selectors. */ public Map getUserData(); } testng-6.9.12/src/main/java/org/testng/IResultMap.java0000755000175000017500000000075612732165123022053 0ustar eugeneeugenepackage org.testng; import java.io.Serializable; import java.util.Collection; import java.util.Set; public interface IResultMap extends Serializable { public void addResult(ITestResult result, ITestNGMethod method); public Set getResults(ITestNGMethod method); public Set getAllResults(); public void removeResult(ITestNGMethod m); public void removeResult(ITestResult r); public Collection getAllMethods(); public int size(); } testng-6.9.12/src/main/java/org/testng/TestRunner.java0000644000175000017500000015431212732165123022132 0ustar eugeneeugenepackage org.testng; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.testng.annotations.Guice; import org.testng.annotations.IListenersAnnotation; import org.testng.collections.ListMultiMap; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.collections.Sets; import org.testng.internal.Attributes; import org.testng.internal.ClassHelper; import org.testng.internal.ClassImpl; import org.testng.internal.ClassInfoMap; import org.testng.internal.ConfigurationGroupMethods; import org.testng.internal.Constants; import org.testng.internal.DynamicGraph; import org.testng.internal.DynamicGraph.Status; import org.testng.internal.IConfiguration; import org.testng.internal.IInvoker; import org.testng.internal.ITestResultNotifier; import org.testng.internal.InvokedMethod; import org.testng.internal.Invoker; import org.testng.internal.MethodGroupsHelper; import org.testng.internal.MethodHelper; import org.testng.internal.MethodInstance; import org.testng.internal.ResultMap; import org.testng.internal.RunInfo; import org.testng.internal.TestMethodWorker; import org.testng.internal.TestNGClassFinder; import org.testng.internal.TestNGMethodFinder; import org.testng.internal.Utils; import org.testng.internal.XmlMethodSelector; import org.testng.internal.annotations.AnnotationHelper; import org.testng.internal.annotations.IAnnotationFinder; import org.testng.internal.annotations.IListeners; import org.testng.internal.thread.graph.GraphThreadPoolExecutor; import org.testng.internal.thread.graph.IThreadWorkerFactory; import org.testng.internal.thread.graph.IWorker; import org.testng.junit.IJUnitTestRunner; import org.testng.xml.XmlClass; import org.testng.xml.XmlInclude; import org.testng.xml.XmlPackage; import org.testng.xml.XmlSuite; import org.testng.xml.XmlTest; import com.google.inject.Injector; import com.google.inject.Module; /** * This class takes care of running one Test. * * @author Cedric Beust, Apr 26, 2004 */ public class TestRunner implements ITestContext, ITestResultNotifier, IThreadWorkerFactory { /* generated */ private static final long serialVersionUID = 4247820024988306670L; private ISuite m_suite; private XmlTest m_xmlTest; private String m_testName; transient private List m_testClassesFromXml= null; transient private List m_packageNamesFromXml= null; transient private IInvoker m_invoker= null; transient private IAnnotationFinder m_annotationFinder= null; /** ITestListeners support. */ transient private List m_testListeners = Lists.newArrayList(); transient private Set m_configurationListeners = Sets.newHashSet(); transient private IConfigurationListener m_confListener= new ConfigurationListener(); transient private boolean m_skipFailedInvocationCounts; transient private Collection m_invokedMethodListeners = Lists.newArrayList(); transient private List m_classListeners = Lists.newArrayList(); /** * All the test methods we found, associated with their respective classes. * Note that these test methods might belong to different classes. * We pick which ones to run at runtime. */ private ITestNGMethod[] m_allTestMethods = new ITestNGMethod[0]; // Information about this test run private Date m_startDate = null; private Date m_endDate = null; /** A map to keep track of Class <-> IClass. */ transient private Map, ITestClass> m_classMap = Maps.newLinkedHashMap(); /** Where the reports will be created. */ private String m_outputDirectory= Constants.getDefaultValueFor(Constants.PROP_OUTPUT_DIR); // The XML method selector (groups/methods included/excluded in XML) private XmlMethodSelector m_xmlMethodSelector = new XmlMethodSelector(); private static int m_verbose = 1; // // These next fields contain all the configuration methods found on this class. // At initialization time, they just contain all the various @Configuration methods // found in all the classes we are going to run. When comes the time to run them, // only a subset of them are run: those that are enabled and belong on the same class as // (or a parent of) the test class. // /** */ private ITestNGMethod[] m_beforeSuiteMethods = {}; private ITestNGMethod[] m_afterSuiteMethods = {}; private ITestNGMethod[] m_beforeXmlTestMethods = {}; private ITestNGMethod[] m_afterXmlTestMethods = {}; private List m_excludedMethods = Lists.newArrayList(); private ConfigurationGroupMethods m_groupMethods = null; // Meta groups private Map> m_metaGroups = Maps.newHashMap(); // All the tests that were run along with their result private IResultMap m_passedTests = new ResultMap(); private IResultMap m_failedTests = new ResultMap(); private IResultMap m_failedButWithinSuccessPercentageTests = new ResultMap(); private IResultMap m_skippedTests = new ResultMap(); private RunInfo m_runInfo= new RunInfo(); // The host where this test was run, or null if run locally private String m_host; // Defined dynamically depending on transient private List m_methodInterceptors; private transient ClassMethodMap m_classMethodMap; private transient TestNGClassFinder m_testClassFinder; private transient IConfiguration m_configuration; private IMethodInterceptor builtinInterceptor; protected TestRunner(IConfiguration configuration, ISuite suite, XmlTest test, String outputDirectory, IAnnotationFinder finder, boolean skipFailedInvocationCounts, Collection invokedMethodListeners, List classListeners) { init(configuration, suite, test, outputDirectory, finder, skipFailedInvocationCounts, invokedMethodListeners, classListeners); } public TestRunner(IConfiguration configuration, ISuite suite, XmlTest test, boolean skipFailedInvocationCounts, Collection invokedMethodListeners, List classListeners) { init(configuration, suite, test, suite.getOutputDirectory(), suite.getAnnotationFinder(), skipFailedInvocationCounts, invokedMethodListeners, classListeners); } private void init(IConfiguration configuration, ISuite suite, XmlTest test, String outputDirectory, IAnnotationFinder annotationFinder, boolean skipFailedInvocationCounts, Collection invokedMethodListeners, List classListeners) { m_configuration = configuration; m_xmlTest= test; m_suite = suite; m_testName = test.getName(); m_host = suite.getHost(); m_testClassesFromXml= test.getXmlClasses(); m_skipFailedInvocationCounts = skipFailedInvocationCounts; setVerbose(test.getVerbose()); boolean preserveOrder = "true".equalsIgnoreCase(test.getPreserveOrder()); m_methodInterceptors = new ArrayList(); builtinInterceptor = preserveOrder ? new PreserveOrderMethodInterceptor() : new InstanceOrderingMethodInterceptor(); m_packageNamesFromXml= test.getXmlPackages(); if(null != m_packageNamesFromXml) { for(XmlPackage xp: m_packageNamesFromXml) { m_testClassesFromXml.addAll(xp.getXmlClasses()); } } m_annotationFinder= annotationFinder; m_invokedMethodListeners = invokedMethodListeners; m_classListeners = classListeners; m_invoker = new Invoker(m_configuration, this, this, m_suite.getSuiteState(), m_skipFailedInvocationCounts, invokedMethodListeners, classListeners); if (suite.getParallel() != null) { log(3, "Running the tests in '" + test.getName() + "' with parallel mode:" + suite.getParallel()); } setOutputDirectory(outputDirectory); // Finish our initialization init(); } public IInvoker getInvoker() { return m_invoker; } public ITestNGMethod[] getBeforeSuiteMethods() { return m_beforeSuiteMethods; } public ITestNGMethod[] getAfterSuiteMethods() { return m_afterSuiteMethods; } public ITestNGMethod[] getBeforeTestConfigurationMethods() { return m_beforeXmlTestMethods; } public ITestNGMethod[] getAfterTestConfigurationMethods() { return m_afterXmlTestMethods; } private void init() { initMetaGroups(m_xmlTest); initRunInfo(m_xmlTest); // Init methods and class map // JUnit behavior is different and doesn't need this initialization step if(!m_xmlTest.isJUnit()) { initMethods(); } initListeners(); addConfigurationListener(m_confListener); } private static class ListenerHolder { private List> listenerClasses; private Class listenerFactoryClass; } /** * @return all the @Listeners annotations found in the current class and its * superclasses. */ private ListenerHolder findAllListeners(Class cls) { ListenerHolder result = new ListenerHolder(); result.listenerClasses = Lists.newArrayList(); do { IListenersAnnotation l = m_annotationFinder.findAnnotation(cls, IListenersAnnotation.class); if (l != null) { Class[] classes = l.getValue(); for (Class c : classes) { result.listenerClasses.add(c); if (ITestNGListenerFactory.class.isAssignableFrom(c)) { if (result.listenerFactoryClass == null) { result.listenerFactoryClass = (Class) c; } else { throw new TestNGException("Found more than one class implementing" + "ITestNGListenerFactory:" + c + " and " + result.listenerFactoryClass); } } } } cls = cls.getSuperclass(); } while (cls != Object.class); return result; } private void initListeners() { // // Find all the listener factories and collect all the listeners requested in a // @Listeners annotation. // Set> listenerClasses = Sets.newHashSet(); Class listenerFactoryClass = null; for (IClass cls : getTestClasses()) { Class realClass = cls.getRealClass(); ListenerHolder listenerHolder = findAllListeners(realClass); if (listenerFactoryClass == null) { listenerFactoryClass = listenerHolder.listenerFactoryClass; } listenerClasses.addAll(listenerHolder.listenerClasses); } // // Now we have all the listeners collected from @Listeners and at most one // listener factory collected from a class implementing ITestNGListenerFactory. // Instantiate all the requested listeners. // ITestNGListenerFactory listenerFactory = null; // If we found a test listener factory, instantiate it. try { if (m_testClassFinder != null) { IClass ic = m_testClassFinder.getIClass(listenerFactoryClass); if (ic != null) { listenerFactory = (ITestNGListenerFactory) ic.getInstances(false)[0]; } } if (listenerFactory == null) { listenerFactory = listenerFactoryClass != null ? listenerFactoryClass.newInstance() : null; } } catch(Exception ex) { throw new TestNGException("Couldn't instantiate the ITestNGListenerFactory: " + ex); } // Instantiate all the listeners for (Class c : listenerClasses) { ITestNGListener listener = listenerFactory != null ? listenerFactory.createListener(c) : null; if (listener == null) { listener = ClassHelper.newInstance(c); } addListener(listener); } } /** * Initialize meta groups */ private void initMetaGroups(XmlTest xmlTest) { Map> metaGroups = xmlTest.getMetaGroups(); for (Map.Entry> entry : metaGroups.entrySet()) { addMetaGroup(entry.getKey(), entry.getValue()); } } private void initRunInfo(final XmlTest xmlTest) { // Groups m_xmlMethodSelector.setIncludedGroups(createGroups(m_xmlTest.getIncludedGroups())); m_xmlMethodSelector.setExcludedGroups(createGroups(m_xmlTest.getExcludedGroups())); m_xmlMethodSelector.setExpression(m_xmlTest.getExpression()); // Methods m_xmlMethodSelector.setXmlClasses(m_xmlTest.getXmlClasses()); m_runInfo.addMethodSelector(m_xmlMethodSelector, 10); // Add user-specified method selectors (only class selectors, we can ignore // script selectors here) if (null != xmlTest.getMethodSelectors()) { for (org.testng.xml.XmlMethodSelector selector : xmlTest.getMethodSelectors()) { if (selector.getClassName() != null) { IMethodSelector s = ClassHelper.createSelector(selector); m_runInfo.addMethodSelector(s, selector.getPriority()); } } } } private void initMethods() { // // Calculate all the methods we need to invoke // List beforeClassMethods = Lists.newArrayList(); List testMethods = Lists.newArrayList(); List afterClassMethods = Lists.newArrayList(); List beforeSuiteMethods = Lists.newArrayList(); List afterSuiteMethods = Lists.newArrayList(); List beforeXmlTestMethods = Lists.newArrayList(); List afterXmlTestMethods = Lists.newArrayList(); ClassInfoMap classMap = new ClassInfoMap(m_testClassesFromXml); m_testClassFinder= new TestNGClassFinder(classMap, null, m_xmlTest, m_configuration, this); ITestMethodFinder testMethodFinder = new TestNGMethodFinder(m_runInfo, m_annotationFinder); m_runInfo.setTestMethods(testMethods); // // Initialize TestClasses // IClass[] classes = m_testClassFinder.findTestClasses(); for (IClass ic : classes) { // Create TestClass ITestClass tc = new TestClass(ic, testMethodFinder, m_annotationFinder, m_runInfo, m_xmlTest, classMap.getXmlClass(ic.getRealClass())); m_classMap.put(ic.getRealClass(), tc); } // // Calculate groups methods // Map> beforeGroupMethods = MethodGroupsHelper.findGroupsMethods(m_classMap.values(), true); Map> afterGroupMethods = MethodGroupsHelper.findGroupsMethods(m_classMap.values(), false); // // Walk through all the TestClasses, store their method // and initialize them with the correct ITestClass // for (ITestClass tc : m_classMap.values()) { fixMethodsWithClass(tc.getTestMethods(), tc, testMethods); fixMethodsWithClass(tc.getBeforeClassMethods(), tc, beforeClassMethods); fixMethodsWithClass(tc.getBeforeTestMethods(), tc, null); fixMethodsWithClass(tc.getAfterTestMethods(), tc, null); fixMethodsWithClass(tc.getAfterClassMethods(), tc, afterClassMethods); fixMethodsWithClass(tc.getBeforeSuiteMethods(), tc, beforeSuiteMethods); fixMethodsWithClass(tc.getAfterSuiteMethods(), tc, afterSuiteMethods); fixMethodsWithClass(tc.getBeforeTestConfigurationMethods(), tc, beforeXmlTestMethods); fixMethodsWithClass(tc.getAfterTestConfigurationMethods(), tc, afterXmlTestMethods); fixMethodsWithClass(tc.getBeforeGroupsMethods(), tc, MethodHelper.uniqueMethodList(beforeGroupMethods.values())); fixMethodsWithClass(tc.getAfterGroupsMethods(), tc, MethodHelper.uniqueMethodList(afterGroupMethods.values())); } // // Sort the methods // m_beforeSuiteMethods = MethodHelper.collectAndOrderMethods(beforeSuiteMethods, false /* forTests */, m_runInfo, m_annotationFinder, true /* unique */, m_excludedMethods); m_beforeXmlTestMethods = MethodHelper.collectAndOrderMethods(beforeXmlTestMethods, false /* forTests */, m_runInfo, m_annotationFinder, true /* unique (CQ added by me)*/, m_excludedMethods); m_allTestMethods = MethodHelper.collectAndOrderMethods(testMethods, true /* forTest? */, m_runInfo, m_annotationFinder, false /* unique */, m_excludedMethods); m_classMethodMap = new ClassMethodMap(testMethods, m_xmlMethodSelector); m_afterXmlTestMethods = MethodHelper.collectAndOrderMethods(afterXmlTestMethods, false /* forTests */, m_runInfo, m_annotationFinder, true /* unique (CQ added by me)*/, m_excludedMethods); m_afterSuiteMethods = MethodHelper.collectAndOrderMethods(afterSuiteMethods, false /* forTests */, m_runInfo, m_annotationFinder, true /* unique */, m_excludedMethods); // shared group methods m_groupMethods = new ConfigurationGroupMethods(m_allTestMethods, beforeGroupMethods, afterGroupMethods); } private void fixMethodsWithClass(ITestNGMethod[] methods, ITestClass testCls, List methodList) { for (ITestNGMethod itm : methods) { itm.setTestClass(testCls); if (methodList != null) { methodList.add(itm); } } } public Collection getTestClasses() { return m_classMap.values(); } public void setTestName(String name) { m_testName = name; } public void setOutputDirectory(String od) { m_outputDirectory= od; // FIX: empty directories were created // if (od == null) { m_outputDirectory = null; return; } //for maven2 // File file = new File(od); // file.mkdirs(); // m_outputDirectory= file.getAbsolutePath(); } private void addMetaGroup(String name, List groupNames) { m_metaGroups.put(name, groupNames); } /** * Calculate the transitive closure of all the MetaGroups * * @param groups * @param unfinishedGroups * @param result The transitive closure containing all the groups found */ private void collectGroups(String[] groups, List unfinishedGroups, Map result) { for (String gn : groups) { List subGroups = m_metaGroups.get(gn); if (null != subGroups) { for (String sg : subGroups) { if (null == result.get(sg)) { result.put(sg, sg); unfinishedGroups.add(sg); } } } } } private Map createGroups(List groups) { return createGroups(groups.toArray(new String[groups.size()])); } private Map createGroups(String[] groups) { Map result = Maps.newHashMap(); // Groups that were passed on the command line for (String group : groups) { result.put(group, group); } // See if we have any MetaGroups and // expand them if they match one of the groups // we have just been passed List unfinishedGroups = Lists.newArrayList(); if (m_metaGroups.size() > 0) { collectGroups(groups, unfinishedGroups, result); // Do we need to loop over unfinished groups? while (unfinishedGroups.size() > 0) { String[] uGroups = unfinishedGroups.toArray(new String[unfinishedGroups.size()]); unfinishedGroups = Lists.newArrayList(); collectGroups(uGroups, unfinishedGroups, result); } } // Utils.dumpMap(result); return result; } /** * The main entry method for TestRunner. * * This is where all the hard work is done: * - Invoke configuration methods * - Invoke test methods * - Catch exceptions * - Collect results * - Invoke listeners * - etc... */ public void run() { beforeRun(); try { XmlTest test= getTest(); if(test.isJUnit()) { privateRunJUnit(test); } else { privateRun(test); } } finally { afterRun(); } } /** Before run preparements. */ private void beforeRun() { // // Log the start date // m_startDate = new Date(System.currentTimeMillis()); // Log start logStart(); // Invoke listeners fireEvent(true /*start*/); // invoke @BeforeTest ITestNGMethod[] testConfigurationMethods= getBeforeTestConfigurationMethods(); if(null != testConfigurationMethods && testConfigurationMethods.length > 0) { m_invoker.invokeConfigurations(null, testConfigurationMethods, m_xmlTest.getSuite(), m_xmlTest.getAllParameters(), null, /* no parameter values */ null /* instance */); } } private void privateRunJUnit(XmlTest xmlTest) { final ClassInfoMap cim = new ClassInfoMap(m_testClassesFromXml, false); final Set> classes = cim.getClasses(); final List runMethods = Lists.newArrayList(); List> workers = Lists.newArrayList(); // FIXME: directly referencing JUnitTestRunner which uses JUnit classes // may result in an class resolution exception under different JVMs // The resolution process is not specified in the JVM spec with a specific implementation, // so it can be eager => failure workers.add(new IWorker() { /** * @see TestMethodWorker#getTimeOut() */ @Override public long getTimeOut() { return 0; } /** * @see java.lang.Runnable#run() */ @Override public void run() { for(Class tc: classes) { List includedMethods = cim.getXmlClass(tc).getIncludedMethods(); List methods = Lists.newArrayList(); for (XmlInclude inc: includedMethods) { methods.add(inc.getName()); } IJUnitTestRunner tr= ClassHelper.createTestRunner(TestRunner.this); tr.setInvokedMethodListeners(m_invokedMethodListeners); try { tr.run(tc, methods.toArray(new String[methods.size()])); } catch(Exception ex) { ex.printStackTrace(); } finally { runMethods.addAll(tr.getTestMethods()); } } } @Override public List getTasks() { throw new TestNGException("JUnit not supported"); } @Override public int getPriority() { if (m_allTestMethods.length == 1) { return m_allTestMethods[0].getPriority(); } else { return 0; } } @Override public int compareTo(IWorker other) { return getPriority() - other.getPriority(); } }); runJUnitWorkers(workers); m_allTestMethods= runMethods.toArray(new ITestNGMethod[runMethods.size()]); } /** * Main method that create a graph of methods and then pass it to the * graph executor to run them. */ private void privateRun(XmlTest xmlTest) { boolean parallel = xmlTest.getParallel().isParallel(); { // parallel int threadCount = parallel ? xmlTest.getThreadCount() : 1; // Make sure we create a graph based on the intercepted methods, otherwise an interceptor // removing methods would cause the graph never to terminate (because it would expect // termination from methods that never get invoked). DynamicGraph graph = createDynamicGraph(intercept(m_allTestMethods)); if (parallel) { if (graph.getNodeCount() > 0) { GraphThreadPoolExecutor executor = new GraphThreadPoolExecutor<>(graph, this, threadCount, threadCount, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); executor.run(); try { long timeOut = m_xmlTest.getTimeOut(XmlTest.DEFAULT_TIMEOUT_MS); Utils.log("TestRunner", 2, "Starting executor for test " + m_xmlTest.getName() + " with time out:" + timeOut + " milliseconds."); executor.awaitTermination(timeOut, TimeUnit.MILLISECONDS); executor.shutdownNow(); } catch (InterruptedException handled) { handled.printStackTrace(); Thread.currentThread().interrupt(); } } } else { boolean debug = false; List freeNodes = graph.getFreeNodes(); if (debug) { System.out.println("Free nodes:" + freeNodes); } if (graph.getNodeCount() > 0 && freeNodes.isEmpty()) { throw new TestNGException("No free nodes found in:" + graph); } while (! freeNodes.isEmpty()) { List> runnables = createWorkers(freeNodes); for (IWorker r : runnables) { r.run(); } graph.setStatus(freeNodes, Status.FINISHED); freeNodes = graph.getFreeNodes(); if (debug) { System.out.println("Free nodes:" + freeNodes); } } } } } /** * Apply the method interceptor (if applicable) to the list of methods. */ private ITestNGMethod[] intercept(ITestNGMethod[] methods) { List methodInstances = methodsToMethodInstances(Arrays.asList(methods)); // add built-in interceptor (PreserveOrderMethodInterceptor or InstanceOrderingMethodInterceptor at the end of the list m_methodInterceptors.add(builtinInterceptor); for (IMethodInterceptor m_methodInterceptor : m_methodInterceptors) { methodInstances = m_methodInterceptor.intercept(methodInstances, this); } List result = Lists.newArrayList(); for (IMethodInstance imi : methodInstances) { result.add(imi.getMethod()); } //Since an interceptor is involved, we would need to ensure that the ClassMethodMap object is in sync with the //output of the interceptor, else @AfterClass doesn't get executed at all when interceptors are involved. //so let's update the current classMethodMap object with the list of methods obtained from the interceptor. this.m_classMethodMap = new ClassMethodMap(result, null); return result.toArray(new ITestNGMethod[result.size()]); } /** * Create a list of workers to run the methods passed in parameter. * Each test method is run in its own worker except in the following cases: * - The method belongs to a class that has @Test(sequential=true) * - The parallel attribute is set to "classes" * In both these cases, all the methods belonging to that class will then * be put in the same worker in order to run in the same thread. */ @Override public List> createWorkers(List methods) { List> result; if (XmlSuite.ParallelMode.INSTANCES.equals(m_xmlTest.getParallel())) { result = createInstanceBasedParallelWorkers(methods); } else { result = createClassBasedParallelWorkers(methods); } return result; } /** * Create workers for parallel="classes" and similar cases. */ private List> createClassBasedParallelWorkers(List methods) { List> result = Lists.newArrayList(); // Methods that belong to classes with a sequential=true or parallel=classes // attribute must all be run in the same worker Set sequentialClasses = Sets.newHashSet(); for (ITestNGMethod m : methods) { Class cls = m.getRealClass(); org.testng.annotations.ITestAnnotation test = m_annotationFinder.findAnnotation(cls, org.testng.annotations.ITestAnnotation.class); // If either sequential=true or parallel=classes, mark this class sequential if (test != null && (test.getSequential() || test.getSingleThreaded()) || XmlSuite.ParallelMode.CLASSES.equals(m_xmlTest.getParallel())) { sequentialClasses.add(cls); } } List methodInstances = Lists.newArrayList(); for (ITestNGMethod tm : methods) { methodInstances.addAll(methodsToMultipleMethodInstances(tm)); } Map params = m_xmlTest.getAllParameters(); Set> processedClasses = Sets.newHashSet(); for (IMethodInstance im : methodInstances) { Class c = im.getMethod().getTestClass().getRealClass(); if (sequentialClasses.contains(c)) { if (!processedClasses.contains(c)) { processedClasses.add(c); if (System.getProperty("experimental") != null) { List> instances = createInstances(methodInstances); for (List inst : instances) { TestMethodWorker worker = createTestMethodWorker(inst, params, c); result.add(worker); } } else { // Sequential class: all methods in one worker TestMethodWorker worker = createTestMethodWorker(methodInstances, params, c); result.add(worker); } } } else { // Parallel class: each method in its own worker TestMethodWorker worker = createTestMethodWorker(Arrays.asList(im), params, c); result.add(worker); } } // Sort by priorities Collections.sort(result); return result; } /** * Create workers for parallel="instances". */ private List> createInstanceBasedParallelWorkers(List methods) { List> result = Lists.newArrayList(); ListMultiMap lmm = Maps.newListMultiMap(); for (ITestNGMethod m : methods) { lmm.put(m.getInstance(), m); } for (Map.Entry> es : lmm.entrySet()) { List methodInstances = Lists.newArrayList(); for (ITestNGMethod m : es.getValue()) { methodInstances.add(new MethodInstance(m)); } TestMethodWorker tmw = new TestMethodWorker(m_invoker, methodInstances.toArray(new IMethodInstance[methodInstances.size()]), m_xmlTest.getSuite(), m_xmlTest.getAllParameters(), m_groupMethods, m_classMethodMap, this, m_classListeners); result.add(tmw); } return result; } private List> createInstances(List methodInstances) { Map> map = Maps.newHashMap(); // MapList map = new MapList(); for (IMethodInstance imi : methodInstances) { for (Object o : imi.getInstances()) { System.out.println(o); List l = map.get(o); if (l == null) { l = Lists.newArrayList(); map.put(o, l); } l.add(imi); } // for (Object instance : imi.getInstances()) { // map.put(imi, instance); // } } // return map.getKeys(); // System.out.println(map); return new ArrayList<>(map.values()); } private TestMethodWorker createTestMethodWorker( List methodInstances, Map params, Class c) { return new TestMethodWorker(m_invoker, findClasses(methodInstances, c), m_xmlTest.getSuite(), params, m_groupMethods, m_classMethodMap, this, m_classListeners); } private IMethodInstance[] findClasses(List methodInstances, Class c) { List result = Lists.newArrayList(); for (IMethodInstance mi : methodInstances) { if (mi.getMethod().getTestClass().getRealClass() == c) { result.add(mi); } } return result.toArray(new IMethodInstance[result.size()]); } /** * @@@ remove this */ private List methodsToMultipleMethodInstances(ITestNGMethod... sl) { List vResult = Lists.newArrayList(); for (ITestNGMethod m : sl) { vResult.add(new MethodInstance(m)); } return vResult; } private List methodsToMethodInstances(List sl) { List result = new ArrayList<>(); for (ITestNGMethod iTestNGMethod : sl) { result.add(new MethodInstance(iTestNGMethod)); } return result; } // // Invoke the workers // private void runJUnitWorkers(List> workers) { // // Sequential run // for (IWorker tmw : workers) { tmw.run(); } } private void afterRun() { // invoke @AfterTest ITestNGMethod[] testConfigurationMethods= getAfterTestConfigurationMethods(); if(null != testConfigurationMethods && testConfigurationMethods.length > 0) { m_invoker.invokeConfigurations(null, testConfigurationMethods, m_xmlTest.getSuite(), m_xmlTest.getAllParameters(), null, /* no parameter values */ null /* instance */); } // // Log the end date // m_endDate = new Date(System.currentTimeMillis()); if (getVerbose() >= 3) { dumpInvokedMethods(); } // Invoke listeners fireEvent(false /*stop*/); // Statistics // logResults(); } private DynamicGraph createDynamicGraph(ITestNGMethod[] methods) { DynamicGraph result = new DynamicGraph<>(); result.setComparator(new Comparator() { @Override public int compare(ITestNGMethod o1, ITestNGMethod o2) { return o1.getPriority() - o2.getPriority(); } }); DependencyMap dependencyMap = new DependencyMap(methods); // Keep track of whether we have group dependencies. If we do, preserve-order needs // to be ignored since group dependencies create inter-class dependencies which can // end up creating cycles when combined with preserve-order. boolean hasDependencies = false; for (ITestNGMethod m : methods) { result.addNode(m); // Dependent methods { String[] dependentMethods = m.getMethodsDependedUpon(); if (dependentMethods != null) { for (String d : dependentMethods) { ITestNGMethod dm = dependencyMap.getMethodDependingOn(d, m); if (m != dm){ result.addEdge(m, dm); } } } } // Dependent groups { String[] dependentGroups = m.getGroupsDependedUpon(); for (String d : dependentGroups) { hasDependencies = true; List dg = dependencyMap.getMethodsThatBelongTo(d, m); if (dg == null) { throw new TestNGException("Method \"" + m + "\" depends on nonexistent group \"" + d + "\""); } for (ITestNGMethod ddm : dg) { result.addEdge(m, ddm); } } } } // Preserve order // Don't preserve the ordering if we're running in parallel, otherwise the suite will // create multiple threads but these threads will be created one after the other, // giving the impression of parallelism (multiple thread id's) while still running // sequentially. if (! hasDependencies && getCurrentXmlTest().getParallel() == XmlSuite.ParallelMode.NONE && "true".equalsIgnoreCase(getCurrentXmlTest().getPreserveOrder())) { // If preserve-order was specified and the class order is A, B // create a new set of dependencies where each method of B depends // on all the methods of A ListMultiMap classDependencies = createClassDependencies(methods, getCurrentXmlTest()); for (Map.Entry> es : classDependencies.entrySet()) { for (ITestNGMethod dm : es.getValue()) { result.addEdge(dm, es.getKey()); } } } // Group by instances if (getCurrentXmlTest().getGroupByInstances()) { ListMultiMap instanceDependencies = createInstanceDependencies(methods, getCurrentXmlTest()); for (Map.Entry> es : instanceDependencies.entrySet()) { for (ITestNGMethod dm : es.getValue()) { result.addEdge(dm, es.getKey()); } } } return result; } private ListMultiMap createInstanceDependencies( ITestNGMethod[] methods, XmlTest currentXmlTest) { ListMultiMap instanceMap = Maps.newListMultiMap(); for (ITestNGMethod m : methods) { instanceMap.put(m.getInstance(), m); } ListMultiMap result = Maps.newListMultiMap(); Object previousInstance = null; for (Map.Entry> es : instanceMap.entrySet()) { if (previousInstance == null) { previousInstance = es.getKey(); } else { List previousMethods = instanceMap.get(previousInstance); Object currentInstance = es.getKey(); List currentMethods = instanceMap.get(currentInstance); // Make all the methods from the current instance depend on the methods of // the previous instance for (ITestNGMethod cm : currentMethods) { for (ITestNGMethod pm : previousMethods) { result.put(cm, pm); } } previousInstance = currentInstance; } } return result; } private ListMultiMap createClassDependencies( ITestNGMethod[] methods, XmlTest test) { Map> classes = Maps.newHashMap(); // Note: use a List here to preserve the ordering but make sure // we don't add the same class twice List sortedClasses = Lists.newArrayList(); for (XmlClass c : test.getXmlClasses()) { classes.put(c.getName(), new ArrayList()); if (! sortedClasses.contains(c)) sortedClasses.add(c); } // Sort the classes based on their order of appearance in the XML Collections.sort(sortedClasses, new Comparator() { @Override public int compare(XmlClass arg0, XmlClass arg1) { return arg0.getIndex() - arg1.getIndex(); } }); Map indexedClasses1 = Maps.newHashMap(); Map indexedClasses2 = Maps.newHashMap(); int i = 0; for (XmlClass c : sortedClasses) { indexedClasses1.put(c.getName(), i); indexedClasses2.put(i, c.getName()); i++; } ListMultiMap methodsFromClass = Maps.newListMultiMap(); for (ITestNGMethod m : methods) { methodsFromClass.put(m.getTestClass().getName(), m); } ListMultiMap result = Maps.newListMultiMap(); for (ITestNGMethod m : methods) { String name = m.getTestClass().getName(); Integer index = indexedClasses1.get(name); // The index could be null if the classes listed in the XML are different // from the methods being run (e.g. the .xml only contains a factory that // instantiates methods from a different class). In this case, we cannot // perform any ordering. if (index != null && index > 0) { // Make this method depend on all the methods of the class in the previous // index String classDependedUpon = indexedClasses2.get(index - 1); List methodsDependedUpon = methodsFromClass.get(classDependedUpon); if (methodsDependedUpon != null) { for (ITestNGMethod mdu : methodsDependedUpon) { result.put(mdu, m); } } } } return result; } /** * Logs the beginning of the {@link #beforeRun()} . */ private void logStart() { log(3, "Running test " + m_testName + " on " + m_classMap.size() + " " + " classes, " + " included groups:[" + mapToString(m_xmlMethodSelector.getIncludedGroups()) + "] excluded groups:[" + mapToString(m_xmlMethodSelector.getExcludedGroups()) + "]"); if (getVerbose() >= 3) { for (ITestClass tc : m_classMap.values()) { ((TestClass) tc).dump(); } } } /** * Trigger the start/finish event. * * @param isStart true if the event is for start, false if the * event is for finish */ private void fireEvent(boolean isStart) { for (ITestListener itl : m_testListeners) { if (isStart) { itl.onStart(this); } else { itl.onFinish(this); } } } ///// // ITestContext // @Override public String getName() { return m_testName; } /** * @return Returns the startDate. */ @Override public Date getStartDate() { return m_startDate; } /** * @return Returns the endDate. */ @Override public Date getEndDate() { return m_endDate; } @Override public IResultMap getPassedTests() { return m_passedTests; } @Override public IResultMap getSkippedTests() { return m_skippedTests; } @Override public IResultMap getFailedTests() { return m_failedTests; } @Override public IResultMap getFailedButWithinSuccessPercentageTests() { return m_failedButWithinSuccessPercentageTests; } @Override public String[] getIncludedGroups() { Map ig= m_xmlMethodSelector.getIncludedGroups(); String[] result= ig.values().toArray((new String[ig.size()])); return result; } @Override public String[] getExcludedGroups() { Map eg= m_xmlMethodSelector.getExcludedGroups(); String[] result= eg.values().toArray((new String[eg.size()])); return result; } @Override public String getOutputDirectory() { return m_outputDirectory; } /** * @return Returns the suite. */ @Override public ISuite getSuite() { return m_suite; } @Override public ITestNGMethod[] getAllTestMethods() { return m_allTestMethods; } @Override public String getHost() { return m_host; } @Override public Collection getExcludedMethods() { Map vResult = Maps.newHashMap(); for (ITestNGMethod m : m_excludedMethods) { vResult.put(m, m); } return vResult.keySet(); } /** * @see org.testng.ITestContext#getFailedConfigurations() */ @Override public IResultMap getFailedConfigurations() { return m_failedConfigurations; } /** * @see org.testng.ITestContext#getPassedConfigurations() */ @Override public IResultMap getPassedConfigurations() { return m_passedConfigurations; } /** * @see org.testng.ITestContext#getSkippedConfigurations() */ @Override public IResultMap getSkippedConfigurations() { return m_skippedConfigurations; } // // ITestContext ///// ///// // ITestResultNotifier // @Override public void addPassedTest(ITestNGMethod tm, ITestResult tr) { m_passedTests.addResult(tr, tm); } @Override public Set getPassedTests(ITestNGMethod tm) { return m_passedTests.getResults(tm); } @Override public Set getFailedTests(ITestNGMethod tm) { return m_failedTests.getResults(tm); } @Override public Set getSkippedTests(ITestNGMethod tm) { return m_skippedTests.getResults(tm); } @Override public void addSkippedTest(ITestNGMethod tm, ITestResult tr) { m_skippedTests.addResult(tr, tm); } @Override public void addInvokedMethod(InvokedMethod im) { synchronized(m_invokedMethods) { m_invokedMethods.add(im); } } @Override public void addFailedTest(ITestNGMethod testMethod, ITestResult result) { logFailedTest(testMethod, result, false /* withinSuccessPercentage */); } @Override public void addFailedButWithinSuccessPercentageTest(ITestNGMethod testMethod, ITestResult result) { logFailedTest(testMethod, result, true /* withinSuccessPercentage */); } @Override public XmlTest getTest() { return m_xmlTest; } @Override public List getTestListeners() { return m_testListeners; } @Override public List getConfigurationListeners() { return Lists.newArrayList(m_configurationListeners); } // // ITestResultNotifier ///// private void logFailedTest(ITestNGMethod method, ITestResult tr, boolean withinSuccessPercentage) { /* * We should not remove a passed method from m_passedTests so that we can * account for the passed instances of this test method. */ //m_passedTests.removeResult(method); if (withinSuccessPercentage) { m_failedButWithinSuccessPercentageTests.addResult(tr, method); } else { m_failedTests.addResult(tr, method); } } private String mapToString(Map m) { StringBuffer result= new StringBuffer(); for (Object o : m.values()) { result.append(o.toString()).append(" "); } return result.toString(); } private void log(int level, String s) { Utils.log("TestRunner", level, s); } public static int getVerbose() { return m_verbose; } public void setVerbose(int n) { m_verbose = n; } private void log(String s) { Utils.log("TestRunner", 2, s); } ///// // Listeners // /** * @deprecated addListener(ITestNGListener) should be used instead */ // TODO remove it @Deprecated public void addListener(Object listener) { if (listener instanceof ITestNGListener) { addListener((ITestNGListener) listener); } } public void addListener(ITestNGListener listener) { // TODO a listener may be added many times if it implements many interfaces if (listener instanceof IMethodInterceptor) { m_methodInterceptors.add((IMethodInterceptor) listener); } if (listener instanceof ISuiteListener) { m_suite.addListener(listener); } if (listener instanceof IInvokedMethodListener) { m_suite.addListener(listener); } if (listener instanceof ITestListener) { // At this point, the field m_testListeners has already been used in the creation addTestListener((ITestListener) listener); } if (listener instanceof IClassListener) { m_classListeners.add((IClassListener) listener); } if (listener instanceof IConfigurationListener) { addConfigurationListener((IConfigurationListener) listener); } if (listener instanceof IReporter) { m_suite.addListener(listener); } if (listener instanceof IConfigurable) { m_configuration.setConfigurable((IConfigurable) listener); } if (listener instanceof IHookable) { m_configuration.setHookable((IHookable) listener); } if (listener instanceof IExecutionListener) { IExecutionListener iel = (IExecutionListener) listener; iel.onExecutionStart(); m_configuration.addExecutionListener(iel); } } /** * @deprecated addListener(ITestNGListener) should be used instead */ // TODO change public to package visibility @Deprecated public void addTestListener(ITestListener il) { m_testListeners.add(il); } void addConfigurationListener(IConfigurationListener icl) { m_configurationListeners.add(icl); } // // Listeners ///// private final List m_invokedMethods = Lists.newArrayList(); private void dumpInvokedMethods() { System.out.println("===== Invoked methods"); for (IInvokedMethod im : m_invokedMethods) { if (im.isTestMethod()) { System.out.print(" "); } else if (im.isConfigurationMethod()) { System.out.print(" "); } else { continue; } System.out.println("" + im); } System.out.println("====="); } public List getInvokedMethods() { List result= Lists.newArrayList(); synchronized(m_invokedMethods) { for (IInvokedMethod im : m_invokedMethods) { ITestNGMethod tm= im.getTestMethod(); tm.setDate(im.getDate()); result.add(tm); } } return result; } private IResultMap m_passedConfigurations= new ResultMap(); private IResultMap m_skippedConfigurations= new ResultMap(); private IResultMap m_failedConfigurations= new ResultMap(); private class ConfigurationListener implements IConfigurationListener2 { @Override public void beforeConfiguration(ITestResult tr) { } @Override public void onConfigurationFailure(ITestResult itr) { m_failedConfigurations.addResult(itr, itr.getMethod()); } @Override public void onConfigurationSkip(ITestResult itr) { m_skippedConfigurations.addResult(itr, itr.getMethod()); } @Override public void onConfigurationSuccess(ITestResult itr) { m_passedConfigurations.addResult(itr, itr.getMethod()); } } @Deprecated public void setMethodInterceptor(IMethodInterceptor methodInterceptor){ m_methodInterceptors.add(methodInterceptor); } public void addMethodInterceptor(IMethodInterceptor methodInterceptor){ m_methodInterceptors.add(methodInterceptor); } @Override public XmlTest getCurrentXmlTest() { return m_xmlTest; } private IAttributes m_attributes = new Attributes(); @Override public Object getAttribute(String name) { return m_attributes.getAttribute(name); } @Override public void setAttribute(String name, Object value) { m_attributes.setAttribute(name, value); } @Override public Set getAttributeNames() { return m_attributes.getAttributeNames(); } @Override public Object removeAttribute(String name) { return m_attributes.removeAttribute(name); } private ListMultiMap, Module> m_guiceModules = Maps.newListMultiMap(); @Override public List getGuiceModules(Class cls) { List result = m_guiceModules.get(cls); return result; } private void addGuiceModule(Class cls, Module module) { m_guiceModules.put(cls, module); } private Map, Injector> m_injectors = Maps.newHashMap(); @Override public Injector getInjector(List moduleInstances) { return m_injectors .get(moduleInstances); } @Override public Injector getInjector(IClass iClass) { Annotation annotation = AnnotationHelper.findAnnotationSuperClasses(Guice.class, iClass.getRealClass()); if (annotation == null) return null; if (iClass instanceof TestClass) { iClass = ((TestClass)iClass).getIClass(); } if (!(iClass instanceof ClassImpl)) return null; Injector parentInjector = ((ClassImpl)iClass).getParentInjector(); Guice guice = (Guice) annotation; List moduleInstances = Lists.newArrayList(getModules(guice, parentInjector, iClass.getRealClass())); // Reuse the previous injector, if any Injector injector = getInjector(moduleInstances); if (injector == null) { injector = parentInjector.createChildInjector(moduleInstances); addInjector(moduleInstances, injector); } return injector; } private Module[] getModules(Guice guice, Injector parentInjector, Class testClass) { List result = Lists.newArrayList(); for (Class moduleClass : guice.modules()) { List modules = getGuiceModules(moduleClass); if (modules != null && modules.size() > 0) { result.addAll(modules); } else { Module instance = parentInjector.getInstance(moduleClass); result.add(instance); addGuiceModule(moduleClass, instance); } } Class factory = guice.moduleFactory(); if (factory != IModuleFactory.class) { IModuleFactory factoryInstance = parentInjector.getInstance(factory); Module moduleClass = factoryInstance.createModule(this, testClass); if (moduleClass != null) { result.add(moduleClass); } } return result.toArray(new Module[result.size()]); } @Override public void addInjector(List moduleInstances, Injector injector) { m_injectors.put(moduleInstances, injector); } } // TestRunner testng-6.9.12/src/main/java/main.iml0000644000175000017500000000155312732165123016510 0ustar eugeneeugene testng-6.9.12/src/main/resources/0000755000175000017500000000000012732165123016146 5ustar eugeneeugenetestng-6.9.12/src/main/resources/skipped.png0000644000175000017500000000170712732165123020320 0ustar eugeneeugenePNG  IHDR Vu\iCCPICC ProfilexTkPe:g >hndStCkWZ6!Hm\$~ًo:w> كo{ a"L"4M'S9'^qZ/USO^C+hMJ&G@Ӳylto߫c՚  5"Yi\t։15LsX g8ocግ#f45@ B:K@8i ΁'&.)@ry[:Vͦ#wQ?HBd(B acĪL"JitTy8;(Gx_^[%׎ŷQ麲uan7m QH^eOQu6Su 2%vX ^*l O—ޭˀq,>S%LdB1CZ$M9P 'w\/].r#E|!3>_oa۾d1Zӑz'=~V+cjJtO%mN |-bWO+ o ^ IH.;S]i_s9*p.7U^s.3u |^,<;c=ma>Vt.[՟Ϫ x# ¡_2dIDAT(c|{? `p B-BkxwYf3H $p tMAjX@2@քl2L 0A|43mB6EL1L6Mp qibyL^*#IENDB`testng-6.9.12/src/main/resources/collapseall.gif0000644000175000017500000000023512732165123021130 0ustar eugeneeugeneGIF89aFz! ,JpI6C D(h9tMNj{0#RP(0Z1rqbL4f;testng-6.9.12/src/main/resources/testng-reports.js0000644000175000017500000000674312732165123021516 0ustar eugeneeugene$(document).ready(function() { $('a.navigator-link').click(function() { // Extract the panel for this link var panel = getPanelName($(this)); // Mark this link as currently selected $('.navigator-link').parent().removeClass('navigator-selected'); $(this).parent().addClass('navigator-selected'); showPanel(panel); }); installMethodHandlers('failed'); installMethodHandlers('skipped'); installMethodHandlers('passed', true); // hide passed methods by default $('a.method').click(function() { showMethod($(this)); return false; }); // Hide all the panels and display the first one (do this last // to make sure the click() will invoke the listeners) $('.panel').hide(); $('.navigator-link').first().click(); // Collapse/expand the suites $('a.collapse-all-link').click(function() { var contents = $('.navigator-suite-content'); if (contents.css('display') == 'none') { contents.show(); } else { contents.hide(); } }); }); // The handlers that take care of showing/hiding the methods function installMethodHandlers(name, hide) { function getContent(t) { return $('.method-list-content.' + name + "." + t.attr('panel-name')); } function getHideLink(t, name) { var s = 'a.hide-methods.' + name + "." + t.attr('panel-name'); return $(s); } function getShowLink(t, name) { return $('a.show-methods.' + name + "." + t.attr('panel-name')); } function getMethodPanelClassSel(element, name) { var panelName = getPanelName(element); var sel = '.' + panelName + "-class-" + name; return $(sel); } $('a.hide-methods.' + name).click(function() { var w = getContent($(this)); w.hide(); getHideLink($(this), name).hide(); getShowLink($(this), name).show(); getMethodPanelClassSel($(this), name).hide(); }); $('a.show-methods.' + name).click(function() { var w = getContent($(this)); w.show(); getHideLink($(this), name).show(); getShowLink($(this), name).hide(); showPanel(getPanelName($(this))); getMethodPanelClassSel($(this), name).show(); }); if (hide) { $('a.hide-methods.' + name).click(); } else { $('a.show-methods.' + name).click(); } } function getHashForMethod(element) { return element.attr('hash-for-method'); } function getPanelName(element) { return element.attr('panel-name'); } function showPanel(panelName) { $('.panel').hide(); var panel = $('.panel[panel-name="' + panelName + '"]'); panel.show(); } function showMethod(element) { var hashTag = getHashForMethod(element); var panelName = getPanelName(element); showPanel(panelName); var current = document.location.href; var base = current.substring(0, current.indexOf('#')) document.location.href = base + '#' + hashTag; var newPosition = $(document).scrollTop() - 65; $(document).scrollTop(newPosition); } function drawTable() { for (var i = 0; i < suiteTableInitFunctions.length; i++) { window[suiteTableInitFunctions[i]](); } for (var k in window.suiteTableData) { var v = window.suiteTableData[k]; var div = v.tableDiv; var data = v.tableData var table = new google.visualization.Table(document.getElementById(div)); table.draw(data, { showRowNumber : false }); } } testng-6.9.12/src/main/resources/testng.css0000644000175000017500000000047012732165123020165 0ustar eugeneeugene.invocation-failed, .test-failed { background-color: #DD0000; } .invocation-percent, .test-percent { background-color: #006600; } .invocation-passed, .test-passed { background-color: #00AA00; } .invocation-skipped, .test-skipped { background-color: #CCCC00; } .main-page { font-size: x-large; } testng-6.9.12/src/main/resources/navigator-bullet.png0000644000175000017500000000054012732165123022132 0ustar eugeneeugenePNG  IHDR 7gAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?1 D|xgh }Դ~*d7yϨ@~HLdd`cesx%ыgJѝW/ .p ;™ 8^scX ͌ * & X2121k1h )WۇPMܖASp"[ T=xUv(hJу{P "f$6 -vQpAJIENDB`testng-6.9.12/src/main/resources/jquery-1.7.1.min.js0000644000175000017500000026725412732165123021267 0ustar eugeneeugene/*! jQuery v1.7.1 jquery.com | jquery.org/license */ (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="

"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() {for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);testng-6.9.12/src/main/resources/header0000644000175000017500000000137512732165123017327 0ustar eugeneeugene TestNG reports testng-6.9.12/src/main/resources/testngtasks0000644000175000017500000000004012732165123020435 0ustar eugeneeugenetestng=org.testng.TestNGAntTask testng-6.9.12/src/main/resources/META-INF/0000755000175000017500000000000012732165123017306 5ustar eugeneeugenetestng-6.9.12/src/main/resources/META-INF/services/0000755000175000017500000000000012732165123021131 5ustar eugeneeugenetestng-6.9.12/src/main/resources/META-INF/services/org.testng.xml.ISuiteParser0000644000175000017500000000003612732165123026322 0ustar eugeneeugeneorg.testng.internal.YamlParsertestng-6.9.12/src/main/resources/failed.png0000644000175000017500000000172112732165123020101 0ustar eugeneeugenePNG  IHDR Vu\iCCPICC ProfilexTkPe:g >hndStCkWZ6!Hm\$~ًo:w> كo{ a"L"4M'S9'^qZ/USO^C+hMJ&G@Ӳylto߫c՚  5"Yi\t։15LsX g8ocግ#f45@ B:K@8i ΁'&.)@ry[:Vͦ#wQ?HBd(B acĪL"JitTy8;(Gx_^[%׎ŷQ麲uan7m QH^eOQu6Su 2%vX ^*l O—ޭˀq,>S%LdB1CZ$M9P 'w\/].r#E|!3>_oa۾d1Zӑz'=~V+cjJtO%mN |-bWO+ o ^ IH.;S]i_s9*p.7U^s.3u |^,<;c=ma>Vt.[՟Ϫ x# ¡_2nIDAT(c&DZRpEkĮ, \H]bFlلl2H1Obh9y0cP4$ik@WKVOc6`&y+IENDB`testng-6.9.12/src/main/resources/testng-1.0.dtd0000755000175000017500000002022112732165123020443 0ustar eugeneeugene testng-6.9.12/src/main/resources/org/0000755000175000017500000000000012732165123016735 5ustar eugeneeugenetestng-6.9.12/src/main/resources/org/testng/0000755000175000017500000000000012732165123020241 5ustar eugeneeugenetestng-6.9.12/src/main/resources/org/testng/internal/0000755000175000017500000000000012732165123022055 5ustar eugeneeugenetestng-6.9.12/src/main/resources/org/testng/internal/VersionTemplateJava0000644000175000017500000000037512732165123025730 0ustar eugeneeugenepackage org.testng.internal; public class Version { public static final String VERSION = "@version@"; public static void displayBanner() { System.out.println("...\n... TestNG " + VERSION + " by Cédric Beust (cedric@beust.com)\n...\n"); } } testng-6.9.12/src/main/resources/passed.png0000644000175000017500000000177312732165123020143 0ustar eugeneeugenePNG  IHDR Vu\iCCPICC ProfilexTkPe:g >hndStCkWZ6!Hm\$~ًo:w> كo{ a"L"4M'S9'^qZ/USO^C+hMJ&G@Ӳylto߫c՚  5"Yi\t։15LsX g8ocግ#f45@ B:K@8i ΁'&.)@ry[:Vͦ#wQ?HBd(B acĪL"JitTy8;(Gx_^[%׎ŷQ麲uan7m QH^eOQu6Su 2%vX ^*l O—ޭˀq,>S%LdB1CZ$M9P 'w\/].r#E|!3>_oa۾d1Zӑz'=~V+cjJtO%mN |-bWO+ o ^ IH.;S]i_s9*p.7U^s.3u |^,<;c=ma>Vt.[՟Ϫ x# ¡_2IDAT(cDZR5`+"a 5I !J`k[8Y%߿q;C k@qȤSV_gC(&e`\VTu×P48 $s]B8 A|b 334 AJ(/Knb>%Ͱί??~c|A@Uu2Ā>~g0Tg@ 10p*`d`Rݗ @{Q  u @ jvo|h ;+3 @74~} @N)[q71`PqP .IENDB`testng-6.9.12/src/main/resources/testng-reports.css0000644000175000017500000001165212732165123021665 0ustar eugeneeugenebody { margin: 0px 0px 5px 5px; } ul { margin: 0px; } li { list-style-type: none; } a { text-decoration: none; } a:hover { text-decoration: underline; } .navigator-selected { background: #ffa500; } .wrapper { position: absolute; top: 60px; bottom: 0; left: 400px; right: 0; overflow: auto; } .navigator-root { position: absolute; top: 60px; bottom: 0; left: 0; width: 400px; overflow-y: auto; } .suite { margin: 0px 10px 10px 0px; background-color: #fff8dc; } .suite-name { padding-left: 10px; font-size: 25px; font-family: Times; } .main-panel-header { padding: 5px; background-color: #9FB4D9; //afeeee; font-family: monospace; font-size: 18px; } .main-panel-content { padding: 5px; margin-bottom: 10px; background-color: #DEE8FC; //d0ffff; } .rounded-window { border-radius: 10px; border-style: solid; border-width: 1px; } .rounded-window-top { border-top-right-radius: 10px 10px; border-top-left-radius: 10px 10px; border-style: solid; border-width: 1px; overflow: auto; } .light-rounded-window-top { border-top-right-radius: 10px 10px; border-top-left-radius: 10px 10px; } .rounded-window-bottom { border-style: solid; border-width: 0px 1px 1px 1px; border-bottom-right-radius: 10px 10px; border-bottom-left-radius: 10px 10px; overflow: auto; } .method-name { font-size: 12px; font-family: monospace; } .method-content { border-style: solid; border-width: 0px 0px 1px 0px; margin-bottom: 10; padding-bottom: 5px; width: 80%; } .parameters { font-size: 14px; font-family: monospace; } .stack-trace { white-space: pre; font-family: monospace; font-size: 12px; font-weight: bold; margin-top: 0px; margin-left: 20px; } .testng-xml { font-family: monospace; } .method-list-content { margin-left: 10px; } .navigator-suite-content { margin-left: 10px; font: 12px 'Lucida Grande'; } .suite-section-title { margin-top: 10px; width: 80%; border-style: solid; border-width: 1px 0px 0px 0px; font-family: Times; font-size: 18px; font-weight: bold; } .suite-section-content { list-style-image: url(bullet_point.png); } .top-banner-root { position: absolute; top: 0; height: 45px; left: 0; right: 0; padding: 5px; margin: 0px 0px 5px 0px; background-color: #0066ff; font-family: Times; color: #fff; text-align: center; } .top-banner-title-font { font-size: 25px; } .test-name { font-family: 'Lucida Grande'; font-size: 16px; } .suite-icon { padding: 5px; float: right; height: 20; } .test-group { font: 20px 'Lucida Grande'; margin: 5px 5px 10px 5px; border-width: 0px 0px 1px 0px; border-style: solid; padding: 5px; } .test-group-name { font-weight: bold; } .method-in-group { font-size: 16px; margin-left: 80px; } table.google-visualization-table-table { width: 100%; } .reporter-method-name { font-size: 14px; font-family: monospace; } .reporter-method-output-div { padding: 5px; margin: 0px 0px 5px 20px; font-size: 12px; font-family: monospace; border-width: 0px 0px 0px 1px; border-style: solid; } .ignored-class-div { font-size: 14px; font-family: monospace; } .ignored-methods-div { padding: 5px; margin: 0px 0px 5px 20px; font-size: 12px; font-family: monospace; border-width: 0px 0px 0px 1px; border-style: solid; } .border-failed { border-top-left-radius: 10px 10px; border-bottom-left-radius: 10px 10px; border-style: solid; border-width: 0px 0px 0px 10px; border-color: #f00; } .border-skipped { border-top-left-radius: 10px 10px; border-bottom-left-radius: 10px 10px; border-style: solid; border-width: 0px 0px 0px 10px; border-color: #edc600; } .border-passed { border-top-left-radius: 10px 10px; border-bottom-left-radius: 10px 10px; border-style: solid; border-width: 0px 0px 0px 10px; border-color: #19f52d; } .times-div { text-align: center; padding: 5px; } .suite-total-time { font: 16px 'Lucida Grande'; } .configuration-suite { margin-left: 20px; } .configuration-test { margin-left: 40px; } .configuration-class { margin-left: 60px; } .configuration-method { margin-left: 80px; } .test-method { margin-left: 100px; } .chronological-class { background-color: #0ccff; border-style: solid; border-width: 0px 0px 1px 1px; } .method-start { float: right; } .chronological-class-name { padding: 0px 0px 0px 5px; color: #008; } .after, .before, .test-method { font-family: monospace; font-size: 14px; } .navigator-suite-header { font-size: 22px; margin: 0px 10px 5px 0px; background-color: #deb887; text-align: center; } .collapse-all-icon { padding: 5px; float: right; } testng-6.9.12/kobalt/0000755000175000017500000000000012732165123013675 5ustar eugeneeugenetestng-6.9.12/kobalt/wrapper/0000755000175000017500000000000012735760204015361 5ustar eugeneeugenetestng-6.9.12/kobalt/wrapper/kobalt-wrapper.properties0000644000175000017500000000002412732165123022421 0ustar eugeneeugenekobalt.version=0.818testng-6.9.12/kobalt/_Build.kt.iml0000644000175000017500000000076112732165123016217 0ustar eugeneeugene testng-6.9.12/kobalt/Build.kt.iml0000644000175000017500000000105112732165123016051 0ustar eugeneeugene testng-6.9.12/kobalt/src/0000755000175000017500000000000012732165123014464 5ustar eugeneeugenetestng-6.9.12/kobalt/src/Build.kt0000644000175000017500000000273212732165123016067 0ustar eugeneeugene import com.beust.kobalt.TaskResult import com.beust.kobalt.api.Project import com.beust.kobalt.api.annotation.Task import com.beust.kobalt.plugin.packaging.assemble import com.beust.kobalt.project import com.beust.kobalt.test import java.io.File val VERSION = "6.9.11-SNAPSHOT" val p = project { name = "testng" group = "org.testng" artifactId = name version = VERSION sourceDirectories { path("src/generated/java") } dependencies { compile("com.beust:jcommander:1.48", "com.google.inject:guice:4.0", "junit:junit:4.10", "org.apache.ant:ant:1.7.0", "org.beanshell:bsh:2.0b4", "org.yaml:snakeyaml:1.15") } dependenciesTest { compile("org.assertj:assertj-core:2.0.0", "org.testng:testng:6.9.9") } test { jvmArgs("-Dtest.resources.dir=src/test/resources") } assemble { jar { fatJar = true } } } @Task(name = "createVersion", runBefore = arrayOf("compile"), runAfter = arrayOf("clean"), description = "") fun taskCreateVersion(project: Project): TaskResult { val path = "org/testng/internal" with(arrayListOf()) { File("src/main/resources/$path/VersionTemplateJava").forEachLine { add(it.replace("@version@", VERSION)) } File("src/generated/java/$path/Version.java").writeText(joinToString("\n")) } return TaskResult() } testng-6.9.12/build.gradle0000644000175000017500000001111112732165123014673 0ustar eugeneeugenebuildscript { def a_user = hasProperty('artifactory_user') ? artifactory_user : System.getenv('artifactory_user') def a_password = hasProperty('artifactory_password') ? artifactory_password : System.getenv('artifactory_password') repositories { mavenCentral() jcenter() maven { url 'http://dl.bintray.com/cbeust/maven' } maven { url 'http://oss.jfrog.org/artifactory/plugins-release' credentials { username = "${a_user}" password = "${a_password}" } } } dependencies { classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3" } } plugins { id "com.jfrog.bintray" version "1.6" id "com.jfrog.artifactory" version "4.3.0" id "org.sonarqube" version "2.0.1" id "nebula.optional-base" version "3.0.3" id "nebula.provided-base" version "3.0.3" } task wrapper(type: Wrapper) { gradleVersion = '2.13' } group = 'org.testng' version = '6.9.12-SNAPSHOT' apply plugin: 'java' apply plugin: 'groovy' apply plugin: 'jacoco' apply plugin: 'osgi' targetCompatibility = "1.7" sourceCompatibility = "1.7" repositories { mavenCentral() jcenter() maven { url 'http://dl.bintray.com/cbeust/maven' } } dependencies { compile 'org.beanshell:bsh:2.0b4' compile 'com.beust:jcommander:1.48' compile 'org.apache.ant:ant:1.7.0' compile 'junit:junit:4.12', optional compile 'org.yaml:snakeyaml:1.15', optional provided 'com.google.inject:guice:4.0:no_aop' testCompile 'org.assertj:assertj-core:2.0.0' testCompile 'org.testng:testng:6.9.4' testCompile 'org.codehaus.groovy:groovy-all:2.4.7' testCompile 'org.spockframework:spock-core:1.0-groovy-2.4' } task sourceJar(type: Jar) { group 'Build' description 'An archive of the source code' classifier 'sources' from sourceSets.main.allSource } artifacts { sourceJar } import org.apache.tools.ant.filters.ReplaceTokens def generatedSourcesFolder = projectDir.toString() + '/src/generated/java' def dirFrom = projectDir.toString() + '/src/main/resources/org/testng/internal' def dirTo = generatedSourcesFolder + "/org/testng/internal" def fileFrom = 'VersionTemplateJava' def fileTo = 'Version.java' task removeVersion { delete dirTo + fileTo } sourceSets { generated { java { srcDir 'src/generated/java' } resources { srcDir 'src/generated/resources' } } } sourceSets { main { compileClasspath += generated.output runtimeClasspath += generated.output } } gradle.projectsEvaluated { compileJava.dependsOn(myDir) } task myDir { delete dirTo + "/" + fileTo mkdir(dirTo) } // Include the generated Version.class in the jar jar { manifest { instruction 'Bundle-License', 'http://apache.org/licenses/LICENSE-2.0' instruction 'Bundle-Description', 'TestNG is a testing framework.' instruction 'Import-Package', 'bsh.*;version="[2.0.0,3.0.0)";resolution:=optional', 'com.beust.jcommander.*;version="[1.7.0,3.0.0)";resolution:=optional', 'com.google.inject.*;version="[1.2,1.3)";resolution:=optional', 'junit.framework;version="[3.8.1, 5.0.0)";resolution:=optional', 'org.junit.*;resolution:=optional', 'org.apache.tools.ant.*;version="[1.7.0, 2.0.0)";resolution:=optional', 'org.yaml.*;version="[1.6,2.0)";resolution:=optional', '!com.beust.testng', '!org.testng.*', '!com.sun.*', '*' } from "$buildDir/classes/generated" } task createVersion(type: Copy, dependsOn: myDir) { println("Creating Version file: ${version} in ${dirTo}") from dirFrom include fileFrom into(dirTo) rename(fileFrom, fileTo) filter(ReplaceTokens, tokens: [version: version]) } compileJava.dependsOn(createVersion) test { useTestNG() { suites 'src/test/resources/testng.xml' } // testLogging.showStandardStreams = true systemProperties = System.getProperties() systemProperties['test.resources.dir'] = 'build/resources/test/' } if (JavaVersion.current().isJava8Compatible()) { allprojects { tasks.withType(Javadoc) { options.addStringOption('Xdoclint:none', '-quiet') } } } sonarqube { properties { property "sonar.host.url", "https://nemo.sonarqube.org" property "sonar.github.repository", "cbeust/testng" property "sonar.github.login", "testng-bot" } } apply from: 'gradle/publishing.gradle' testng-6.9.12/doc/0000755000175000017500000000000012732165123013166 5ustar eugeneeugenetestng-6.9.12/doc/misc.html0000644000175000017500000002665212732165123015022 0ustar eugeneeugene TestNG - Miscellaneous

MORE TESTNG READING

Here are several articles and presentations about TestNG (English, French, German).

English

French

German

CONTRIBUTORS

TestNG has received a lot of help from various people throughout its existence.

With code:

  • Alexandru Popescu, who ported TestNG to JDK 1.4 and has been tirelessly contributing ever since.

  • Hani Suleiman and Mark Derricutt (IDEA plug-in).

  • Andrew Glover and Jesse Kuhnert/Brett Porter (Maven 1 and Maven 2 plug-ins respectively).

  • Jolly Chen (JUnitReport plug-in).

  • Thierry Janaudy (PDF report plug-in).

And also with ideas, articles and bug reports:

  • Filippo Diotalevi, Matthew Schmidt Robert McIntosh, JR Boyens, Robert Watkins, Aleksi Kallio, Doug Lea, Eron Wright, Guillaume Laforge, Owen Griffiths, Jean-Louis Berliet, Morten Christensen and many others...

 

SPECIAL THANKS

To YourKit for helping us profiling TestNG.

 

TESTIMONIES

A great product is nothing without testimonies, so here is what people have to say about TestNG:

"It's a lot of fun.  Not as fun as Seinfeld, but more fun than Chris Rock on a bad day"
    - A buddy 

"Are you going to eat your dessert?"
    - Someone I met at the cafeteria
 
"Rock on, dude"
    - A skateboarder
 
"Okay, I'll try it.  Can I have my laptop back now"?
    - A scared contractor
 
"Cedric, stop talking to him, he's sleeping"
    - Some random person who should mind their own business

testng-6.9.12/doc/migrating.html0000644000175000017500000001122712732165123016040 0ustar eugeneeugene TestNG - Migrating from JUnit

Migrating from JUnit

Using Eclipse

The easiest way to convert your JUnit tests to TestNG is to use the Eclipse TestNG plug-in refactoring support. You will find a full description of its features in the Eclipse section.

Asserts

Note that the class org.testng.Assert uses a different argument ordering than the ones used by JUnit. If you are porting code that uses JUnit's asserts, you might want to us a static import of that class:
import static org.testng.AssertJUnit.*;

Running JUnit Tests

TestNG can automatically recognize and run JUnit tests, so you can use TestNG as a runner for all your existing tests and write new tests using TestNG.

All you have to do is to put JUnit library on the TestNG classpath, so it can find and use JUnit classes, change your test runner from JUnit to TestNG in Ant and then run TestNG in "mixed" mode. This way you can have all your tests in the same project, even in the same package, and start using TestNG. This approach also allows you to convert your existing JUnit tests to TestNG incrementally.

Example - replacing JUnit Ant task with TestNG one

JUnit version:
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true">
    <batchtest todir="${build.test.results.dir}">
        <fileset dir="${test.src.dir}">
            <include name="**/*Test.*"/>
    </batchtest>
    <classpath>
        <path path="${run.test.classpath}"/>
    </classpath>
    <syspropertyset>
        <propertyref prefix="test-sys-prop."/>
        <mapper from="test-sys-prop.*" to="*" type="glob"/>
    </syspropertyset>
    <formatter type="xml"/>
    <jvmarg value="-ea"/>
    <jvmarg line="${run.jvmargs}"/>
</junit>
TestNG version:
<taskdef name="testng" classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}"/>

<fileset id="mixed.tests" dir="${test.src.dir}">
    <include name="**/*Test.*"/>
</fileset>

<testng mode="mixed" classfilesetref="mixed.tests" workingDir="${work.dir}" failureProperty="tests.failed" outputdir="${build.test.results.dir}">
    <classpath>
        <pathelement path="${build.test.classes.dir}"/>
        <pathelement path="${run.test.classpath}"/>
        <pathelement path="${junit.lib}"/>
    </classpath>
    <propertyset>
        <propertyref prefix="test-sys-prop."/>
        <mapper from="test-sys-prop.*" to="*" type="glob"/>
    </propertyset>
    <jvmarg line="${run.jvmargs}"/>
</testng>

Related reading

testng-6.9.12/doc/faq0000644000175000017500000000024612732165123013662 0ustar eugeneeugene- I'm running groups and now, my @Before methods are no longer running. - How to return various numbers of parameters in a data provider based on the group being run testng-6.9.12/doc/index.html0000644000175000017500000002131012732165123015160 0ustar eugeneeugene TestNG - Welcome

TestNG

Now available

Click for more details.

Cédric Beust (cedric at beust.com)
Current version: 6.9.10
Created: April 27th, 2004
Last Modified:  December 19th, 2015

TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities that make it more powerful and easier to use, such as:

  • Annotations.
  • Run your tests in arbitrarily big thread pools with various policies available (all methods in their own thread, one thread per test class, etc...).
  • Test that your code is multithread safe.
  • Flexible test configuration.
  • Support for data-driven testing (with @DataProvider).
  • Support for parameters.
  • Powerful execution model (no more TestSuite).
  • Supported by a variety of tools and plug-ins (Eclipse, IDEA, Maven, etc...).
  • Embeds BeanShell for further flexibility.
  • Default JDK functions for runtime and logging (no dependencies).
  • Dependent methods for application server testing.

TestNG is designed to cover all categories of tests:  unit, functional, end-to-end, integration, etc...

I started TestNG out of frustration for some JUnit deficiencies which I have documented on my weblog here and here Reading these entries might give you a better idea of the goal I am trying to achieve with TestNG.  You can also check out a quick overview of the main features and an article describing a very concrete example where the combined use of several TestNG's features provides for a very intuitive and maintainable testing design.

Here is a very simple test:

SimpleTest.java

package example1;

import org.testng.annotations.*;

public class SimpleTest {

 @BeforeClass
 public void setUp() {
   // code that will be invoked when this test is instantiated
 }

 @Test(groups = { "fast" })
 public void aFastTest() {
   System.out.println("Fast test");
 }

 @Test(groups = { "slow" })
 public void aSlowTest() {
    System.out.println("Slow test");
 }

}
The method setUp() will be invoked after the test class has been built and before any test method is run.  In this example, we will be running the group fast, so aFastTest() will be invoked while aSlowTest() will be skipped.

Things to note:

  • No need to extend a class or implement an interface.
  • Even though the example above uses the JUnit conventions, our methods can be called any name you like, it's the annotations that tell TestNG what they are.
  • A test method can belong to one or several groups.

Once you have compiled your test class into the build directory, you can invoke your test with the command line, an ant task (shown below) or an XML file:

build.xml

<project default="test">

 <path id="cp">
   <pathelement location="lib/testng-testng-5.13.1.jar"/>
   <pathelement location="build"/>
 </path>

 <taskdef name="testng" classpathref="cp"
          classname="org.testng.TestNGAntTask" />

 <target name="test">
   <testng classpathref="cp" groups="fast">
     <classfileset dir="build" includes="example1/*.class"/>
   </testng>
 </target>

</project>
Use ant to invoke it:
c:> ant
Buildfile: build.xml

test:
[testng] Fast test
[testng] ===============================================
[testng] Suite for Command line test
[testng] Total tests run: 1, Failures: 0, Skips: 0
[testng] ===============================================


BUILD SUCCESSFUL
Total time: 4 seconds
Then you can browse the result of your tests:
start test-output\index.html (on Windows)

Requirements

TestNG requires JDK 7 or higher.

Mailing-lists

Locations of the projects

If you are interested in contributing to TestNG or one of the IDE plug-ins, you will find them in the following locations:

Bug reports

If you think you found a bug, here is how to report it:
  • Create a small project that will allow us to reproduce this bug. In most cases, one or two Java source files and a testng.xml file should be sufficient. Then you can either zip it and email it to the testng-dev mailing-list or make it available on an open source hosting site, such as github or Google code and email testng-dev so we know about it. Please make sure that this project is self contained so that we can build it right away (remove the dependencies on external or proprietary frameworks, etc...).
  • If the bug you observed is on the Eclipse plug-in, make sure your sample project contains the .project and .classpath files.
  • File a bug.

For more information, you can either download TestNG, read the manual or browse the links at thetop.

License

Apache 2.0 testng-6.9.12/doc/selenium.html0000644000175000017500000002763112732165123015706 0ustar eugeneeugene TestNG

Selenium and TestNG

This documentation was written by Felipe Knorr Kuhn and is adapted from a series of articles posted on his blog.

Content

  1. How to use TestNG configuration methods with parameters
  2. How to configure your test
  3. Creating the XML file for TestNG
  4. Lauching your tests with Eclipse
  5. How to make the test design a little better for the future

Modeling your test case

Before writing a test case, you need to know how and what will be validated. Let's use the WordPress "Create New Post" test case.

  1. Go to http://demo.opensourcecms.com/wordpress/wp-login.php
  2. Enter "admin" in the "Username" field
  3. Enter "demo123" in the "Password" field
  4. Click on the "Log In" button
  5. Verify that the text "Howdy, admin" is present
  6. Click on the "Posts" link
  7. Click on the "Add New" button
  8. Type "Selenium Demo Post" in the title field
  9. Click on the "Publish" button
  10. Verify that the text "Post published" is present

Considering this scenario, the first thing that comes to mind is creating a long test case that goes through all the steps. This might be a good approach if you are writing a manual test case. However, since we are writing an automated test, we want to write our script as modular as possible to be able to reuse parts of it in future scenarios.

This is how I would break down the test:

  1. Launch the WordPress site
  2. Open the Admin Login page
  3. Enter valid login data
  4. Navigate to the Write Post page
  5. Write the post
  6. Publish the post
  7. Verify that it was actually post

Keep in mind that this is just an example. You are free to model your tests in any way you want, as long as they have business value and will validate your business logic.

Let's see how to do that with actual Java code:

@Test(description="Launches the WordPress site")
public void launchSite(){
  selenium.open("");
  selenium.waitForPageToLoad("30000");
  assertEquals(selenium.getTitle(), "Demo | Just another WordPress site");
}
 
@Test(description="Navigates to the admin page")
  public void openAdminPage() {
  selenium.open("wp-admin");
  selenium.waitForPageToLoad("30000");
  assertEquals(selenium.getTitle(), "Demo › Log In");
}
 
@Test(description="Enters valid login data")
  public void loginAsAdmin() {
  selenium.type("user_login", "admin");
  selenium.type("user_pass", "demo123");
  selenium.click("wp-submit");
  selenium.waitForPageToLoad("30000");
  assertTrue(selenium.isTextPresent("Howdy, admin"));
}
 
@Test(description="Navigates to the New Post screen")
public void navigateNewPost() {
  selenium.click("//a[contains(text(),'Posts')]/following::a[contains(text(),'Add New')][1]");
  selenium.waitForPageToLoad("30000");
  assertTrue(selenium.isTextPresent("Add New Post"));
}
 
@Test(description="Writes the new post")
public void writeBlogPost() {
  selenium.type("title", "New Blog Post");
  selenium.click("edButtonHTML");
  selenium.type("content", "This is a new post");
  //TODO:Assert
}
 
@Test(description="Publishes the post")
public void publishBlogPost() {
  selenium.click("submitdiv");
  selenium.click("publish");
  selenium.waitForPageToLoad("30000");
  assertTrue(selenium.isTextPresent("Post published."));
}
 
@Test(description="Verifies the post")
public void verifyBlogPost() {
  selenium.click("//a[contains(text(),'Posts') and contains(@class,'wp-first-item')]");
  selenium.waitForPageToLoad("30000");
  assertTrue(selenium.isElementPresent("//a[text()='New Blog Post']"));
}
 
@Test(description="Logs out")
public void logout() {
  selenium.click("//a[text()='Log Out']");
  //TODO:Assert
}

These are the test methods (or steps) we are going to use.

Configuration methods

If you are familiar with unit testing frameworks, you probably know about the setup and teardown methods. TestNG goes beyond that idea and allows you to define methods that will be run after or before your test suites, test groups or test methods. This is very useful for our Selenium tests because you can create a Selenium server and browser instance before you start running your test suite.)

To achieve this, we will use two TestNG annotations: @BeforeSuite and @AfterSuite:

 
@BeforeSuite(alwaysRun = true)
public void setupBeforeSuite(ITestContext context) {
  String seleniumHost = context.getCurrentXmlTest().getParameter("selenium.host");
  String seleniumPort = context.getCurrentXmlTest().getParameter("selenium.port");
  String seleniumBrowser = context.getCurrentXmlTest().getParameter("selenium.browser");
  String seleniumUrl = context.getCurrentXmlTest().getParameter("selenium.url");
 
  RemoteControlConfiguration rcc = new RemoteControlConfiguration();
  rcc.setSingleWindow(true);
  rcc.setPort(Integer.parseInt(seleniumPort));
 
  try {
    server = new SeleniumServer(false, rcc);
    server.boot();
  } catch (Exception e) {
    throw new IllegalStateException("Can't start selenium server", e);
  }
 
  proc = new HttpCommandProcessor(seleniumHost, Integer.parseInt(seleniumPort),
      seleniumBrowser, seleniumUrl);
  selenium = new DefaultSelenium(proc);
  selenium.start();
}
 
@AfterSuite(alwaysRun = true)
public void setupAfterSuite() {
  selenium.stop();
  server.stop();
}

PS: Did you notice those weird parameters? They are stored in the XML file (we are going to see in the next section) and accessed by a ITestContext object, which was injected.

By adding these annotations, the TestNG engine will invoke the configuration methods automatically before/after your test suite (make sure the test methods are annotated with @Test), launching the Selenium server and instantiating the Selenium client object only once, reusing the same browser session across the tests.

Creating the XML file

To define the order of the tests, we will have to create an XML file listing the test methods we would like to run. Make sure that the test methods are annotated with @Test, or else the TestNG engine will not invoke them.

Before TestNG 5.13.1, you had to use Method Interceptors if you wanted to run the tests in the order defined in the XML file. I have posted my implementation of a Method Interceptor on my Github account. From TestNG 5.13.1+, you can just add the preserve-order parameter to your test tag and include the methods you would like to run, reducing unecessary code in your test suite.

Here is the XML file:




  <parameter name="selenium.host" value="localhost" />
  <parameter name="selenium.port" value="3737" />
  <parameter name="selenium.browser" value="*firefox" />
  <parameter name="selenium.url" value="http://demo.opensourcecms.com/wordpress/" />

  
    
      
        
          <include name="launchSite" />
          <include name="openAdminPage" />
          <include name="loginAsAdmin" />
          <include name="navigateNewPost" />
          <include name="writeBlogPost" />
          <include name="publishBlogPost" />
          <include name="verifyBlogPost" />
        
      
    
  

Launching your tests in Eclipse

We finished writing our tests, now how can we run them?

You can launch TestNG from the command line, using a Eclipse plugin or even programatically. We are going to use the Eclipse plugin. Follow the steps described on the official TestNG documentation over here

If you installed TestNG correctly, you will see this menu when you right click on the XML file:

Click on “Run as TestNG Suite” and your test will start running. You will then see this nice results tree:

Thinking about the future

If you really want to think about the future of your test suite, I would recommend you to read Adam Goucher’s article published on PragPub. He talks about Selenium 2 and the Page Objects Model (a very nice way to model your tests, especially if you use Selenium 2).

Since there are lots of people still using Selenium 1, I'll stick to that for a while, but Selenium 2 will eventually be covered here.

As the number of tests in your test suite grows, you will find that grouping them in different test classes is a good idea. If you do that, you can take advantage of object oriented programming and create a new class named BaseTest (for example), and leave your configuration logic there. That way, every test class must extend the BaseTest class and use static attributes.

public class WordPressAdmin extends BaseTest {
@Test
public void test1(){
  selenium.open("");
  //...
}

@Test
public void test2(){
  selenium.open("");
  //...
}
}

This is better than leaving your configuration methods in the test class.

testng-6.9.12/doc/testng.css0000644000175000017500000000502412732165123015205 0ustar eugeneeugenebody, td, th { font-family: Lucida Grande, Tahoma, Verdana, Arial, sans-serif; font-size: 9pt; } table,th,tr,td { border: none; } th { background: #aaa; } td { background: #efefef; } td { padding-top: 3px; padding-right: 4px; padding-left: 4px; padding-bottom: 3px; } h2 { text-align: center; } h3 { background: #efefef; letter-spacing: 0.12em; border-bottom: 1px dotted #aaa; padding-top: 8px; padding-left: 4px; width: 70%; } hr { height: 5px; border: 0; color: #aaa; background-color: #aaa; } .doctype { color: red } .xml-comment { color: green; } .attribute { color: blue; } .tag { color: #7f0055; font-weight: bold; } .float-right { float: right; } .code { margin-left: 20px; margin-top: 10px; background-color: #ffffdd; border: 1pt solid silver; border-color: #ccc #999 #999 #CCC; color: #000000; padding: 5px 5px 5px 7px; font-size: 11px; padding: .3em .6em; font-family: Courier New } .box { border: 1pt solid silver; border-color: #ccc #999 #999 #CCC; background-color: #ffffdd; } #menu { font-size: small; line-height: 0.9em; clear: both; margin-top: 10px; } #menu li { margin-bottom: 7px; } #menu li li { margin-top: 2px; margin-bottom: 2px; } #menu li.submenuitems { margin-bottom: 2px; } #menu a { text-decoration: none; } .e{margin-left:1em;text-indent:-1em;margin-right:1em} .m{color:blue} .t{color:#990000} A:link { text-decoration: none; } A:hover.summary { text-decoration: none; color: #ff9900; } A:visited { text-decoration: none; } /*********************************************/ /* The following rules apply to the top menu */ /*********************************************/ #topmenu a { text-decoration: none; } #topmenu a:link { color: #0066bb; } #topmenu a:visited { color: #006699; } #topmenu a:active { color: red; } #topmenu a:hover { color: red; } #topmenu table { background-color: #ffcc66; text-align: center; } #topmenu td { font-size: small; font-weight: bold; } #topmenu td.current { background: #ffff00; } /* The next rule is a patch because other rules are not scoped correctly */ #topmenu td { background-color: #ffcc66; } testng-6.9.12/doc/prettify.js0000644000175000017500000012171712732165123015403 0ustar eugeneeugene// Copyright 2005 Google Inc. // All Rights Reserved. // // msamuel@google.com // Usage: // 1) include this source file in an html page via // // 2) define style rules. See the example page for examples. // 3) mark the
 and  tags in your source with class=prettyprint.
//    You can also use the (html deprecated)  tag, but the pretty printer
//    needs to do more substantial DOM manipulations to support that, so some
//    css styles may not be preserved.

// Change log:
// cbeust, 2006/08/22
//   Java annotations (start with "@") are now captured as literals ("lit")
// 

var PR_keywords = new Object();
/** initialize the keyword list for our target languages. */
(function () {
  var CPP_KEYWORDS = (
    "bool break case catch char class const const_cast continue default " +
    "delete deprecated dllexport dllimport do double dynamic_cast else enum " +
    "explicit extern false float for friend goto if inline int long mutable " +
    "naked namespace new noinline noreturn nothrow novtable operator private " +
    "property protected public register reinterpret_cast return selectany " +
    "short signed sizeof static static_cast struct switch template this " +
    "thread throw true try typedef typeid typename union unsigned using " +
    "declaration, using directive uuid virtual void volatile while typeof");
  var JAVA_KEYWORDS = (
    "abstract default goto package synchronized boolean do if private this " +
    "break double implements protected throw byte else import public throws " +
    "case enum instanceof return transient catch extends int short try char " +
    "final interface static void class finally long strictfp volatile const " +
    "float native super while continue for new switch");
  var PYTHON_KEYWORDS = (
    "and assert break class continue def del elif else except exec finally " +
    "for from global if import in is lambda not or pass print raise return " +
    "try while yield");
  var JSCRIPT_KEYWORDS = (
    "abstract boolean break byte case catch char class const continue " +
    "debugger default delete do double else enum export extends false final " +
    "finally float for function goto if implements import in instanceof int " +
    "interface long native new null package private protected public return " +
    "short static super switch synchronized this throw throws transient " +
    "true try typeof var void volatile while with NaN Infinity");
  var PERL_KEYWORDS = (
    "foreach require sub unless until use elsif BEGIN END");
  var SH_KEYWORDS = (
    "if then do else fi end");
  var KEYWORDS = [CPP_KEYWORDS, JAVA_KEYWORDS, PYTHON_KEYWORDS,
                  JSCRIPT_KEYWORDS, PERL_KEYWORDS, SH_KEYWORDS];
  for (var k = 0; k < KEYWORDS.length; k++) {
    var kw = KEYWORDS[k].split(' ');
    for (var i = 0; i < kw.length; i++) {
      if (kw[i]) { PR_keywords[kw[i]] = true; }
    }
  }
}).call(this);

// token style names.  correspond to css classes
/** token style for a string literal */
var PR_STRING = 'str';
/** token style for a keyword */
var PR_KEYWORD = 'kwd';
/** token style for a comment */
var PR_COMMENT = 'com';
/** token style for a type */
var PR_TYPE = 'typ';
/** token style for a literal value.  e.g. 1, null, true. */
var PR_LITERAL = 'lit';
/** token style for a punctuation string. */
var PR_PUNCTUATION = 'pun';
/** token style for a punctuation string. */
var PR_PLAIN = 'pln';

/** token style for an sgml tag. */
var PR_TAG = 'tag';
/** token style for a markup declaration such as a DOCTYPE. */
var PR_DECLARATION = 'dec';
/** token style for embedded source. */
var PR_SOURCE = 'src';
/** token style for an sgml attribute name. */
var PR_ATTRIB_NAME = 'atn';
/** token style for an sgml attribute value. */
var PR_ATTRIB_VALUE = 'atv';

/** the position of the end of a token during.  A division of a string into
  * n tokens can be represented as a series n - 1 token ends, as long as
  * runs of whitespace warrant their own token.
  * @private
  */
function PR_TokenEnd(end, style) {
  if (undefined === style) { throw new Error('BAD'); }
  if ('number' != typeof(end)) { throw new Error('BAD'); }
  this.end = end;
  this.style = style;
}
PR_TokenEnd.prototype.toString = function () {
  return '[PR_TokenEnd ' + this.end +
    (this.style ? ':' + this.style : '') + ']';
};


/** a chunk of text with a style.  These are used to represent both the output
  * from the lexing functions as well as intermediate results.
  * @constructor
  * @param token the token text
  * @param style one of the token styles defined in designdoc-template, or null
  *   for a styleless token, such as an embedded html tag.
  * @private
  */
function PR_Token(token, style) {
  if (undefined === style) { throw new Error('BAD'); }
  this.token = token;
  this.style = style;
}

PR_Token.prototype.toString = function () {
  return '[PR_Token ' + this.token + (this.style ? ':' + this.style : '') + ']';
};


/** a helper class that decodes common html entities used to escape source and
  * markup punctuation characters in html.
  * @constructor
  * @private
  */
function PR_DecodeHelper() {
  this.next = 0;
  this.ch = '\0';
}

PR_DecodeHelper.prototype.decode = function (s, i) {
  var next = i + 1;
  var ch = s.charAt(i);
  if ('&' == ch) {
    var semi = s.indexOf(';', next);
    if (semi >= 0 && semi < next + 4) {
      var entityName = s.substring(next, semi).toLowerCase();
      next = semi + 1;
      if ('lt' == entityName) {
        ch = '<';
      } else if ('gt' == entityName) {
        ch = '>';
      } else if ('quot' == entityName) {
        ch = '"';
      } else if ('apos' == entityName) {
        ch = '\'';
      } else if ('amp' == entityName) {
        ch = '&';
      } else {
        next = i + 1;
      }
    }
  }
  this.next = next;
  this.ch = ch;
  return this.ch;
}


// some string utilities
function PR_isWordChar(ch) {
  return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}

function PR_isIdentifierStart(ch) {
  return PR_isWordChar(ch) || ch == '_' || ch == '$' || ch == '@';
}

function PR_isIdentifierPart(ch) {
  return PR_isIdentifierStart(ch) || PR_isDigitChar(ch);
}

function PR_isSpaceChar(ch) {
  return "\t \r\n".indexOf(ch) >= 0;
}

function PR_isDigitChar(ch) {
  return ch >= '0' && ch <= '9';
}

function PR_trim(s) {
  var i = 0, j = s.length - 1;
  while (i <= j && PR_isSpaceChar(s.charAt(i))) { ++i; }
  while (j > i && PR_isSpaceChar(s.charAt(j))) { --j; }
  return s.substring(i, j + 1);
}

function PR_startsWith(s, prefix) {
  return s.length >= prefix.length && prefix == s.substring(0, prefix.length);
}

function PR_endsWith(s, suffix) {
  return s.length >= suffix.length &&
         suffix == s.substring(s.length - suffix.length, s.length);
}

/** true iff prefix matches the first prefix characters in chars[0:len].
  * @private
  */
function PR_prefixMatch(chars, len, prefix) {
  if (len < prefix.length) { return false; }
  for (var i = 0, n = prefix.length; i < n; ++i) {
    if (prefix.charAt(i) != chars[i]) { return false; }
  }
  return true;
}

/** used to convert html special characters embedded in XMP tags into html. */
function PR_textToHtml(str) {
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}


/** split markup into chunks of html tags (style null) and
  * plain text (style {@link #PR_PLAIN}).
  *
  * @param s a String of html.
  * @return an Array of PR_Tokens of style PR_PLAIN and null.
  * @private
  */
function PR_chunkify(s) {
  var chunks = new Array();
  var state = 0;
  var start = 0;
  var pos = -1;
  for (var i = 0, n = s.length; i < n; ++i) {
    var ch = s.charAt(i);
    switch (state) {
      case 0:
        if ('<' == ch) { state = 1; }
        break;
      case 1:
        pos = i - 1;
        if ('/' == ch) { state = 2; }
        else if (PR_isWordChar(ch)) { state = 3; }
        else if ('<' == ch) { state = 1; }
        else { state = 0; }
        break;
      case 2:
        if (PR_isWordChar(ch)) { state = 3; }
        else if ('<' == ch) { state = 1; }
        else { state = 0; }
        break;
      case 3:
        if ('>' == ch) {
          if (pos > start) {
            chunks.push(new PR_Token(s.substring(start, pos), PR_PLAIN));
          }
          chunks.push(new PR_Token(s.substring(pos, i + 1), null));
          start = i + 1;
          pos = -1;
          state = 0;
        }
        break;
    }
  }
  if (s.length > start) {
    chunks.push(new PR_Token(s.substring(start, s.length), PR_PLAIN));
  }
  return chunks;
}

/** splits chunks around entities.
  * @private
  */
function PR_splitEntities(chunks) {
  var chunksOut = new Array();
  var state = 0;
  for (var ci = 0, nc = chunks.length; ci < nc; ++ci) {
    var chunk = chunks[ci];
    if (PR_PLAIN != chunk.style) {
      chunksOut.push(chunk);
      continue;
    }
    var s = chunk.token;
    var pos = 0;
    var start;
    for (var i = 0; i < s.length; ++i) {
      var ch = s.charAt(i);
      switch (state) {
        case 0:
          if ('&' == ch) { state = 1; }
          break;
        case 1:
          if ('#' == ch || PR_isWordChar(ch)) {
            start = i - 1;
            state = 2;
          } else {
            state = 0;
          }
          break;
        case 2:
          if (';' == ch) {
            if (start > pos) {
              chunksOut.push(
                  new PR_Token(s.substring(pos, start), chunk.style));
            }
            chunksOut.push(new PR_Token(s.substring(start, i + 1), null));
            pos = i + 1;
            state = 0;
          }
          break;
      }
    }
    if (s.length > pos) {
      chunksOut.push(pos ?
                     new PR_Token(s.substring(pos, s.length), chunk.style) :
                     chunk);
    }
  }
  return chunksOut;
}

/** walk the tokenEnds list and the chunk list in parallel to generate a list
  * of split tokens.
  * @private
  */
function PR_splitChunks(chunks, tokenEnds) {
  var tokens = new Array();  // the output

  var ci = 0;  // index into chunks
  // position of beginning of amount written so far in absolute space.
  var posAbs = 0;
  // position of amount written so far in chunk space
  var posChunk = 0;

  // current chunk
  var chunk = new PR_Token('', null);

  for (var ei = 0, ne = tokenEnds.length; ei < ne; ++ei) {
    var tokenEnd = tokenEnds[ei];
    var end = tokenEnd.end;

    var tokLen = end - posAbs;
    var remainingInChunk = chunk.token.length - posChunk;
    while (remainingInChunk <= tokLen) {
      if (remainingInChunk > 0) {
        tokens.push(
            new PR_Token(chunk.token.substring(posChunk, chunk.token.length),
                         null == chunk.style ? null : tokenEnd.style));
      }
      posAbs += remainingInChunk;
      posChunk = 0;
      if (ci < chunks.length) { chunk = chunks[ci++]; }

      tokLen = end - posAbs;
      remainingInChunk = chunk.token.length - posChunk;
    }

    if (tokLen) {
      tokens.push(
          new PR_Token(chunk.token.substring(posChunk, posChunk + tokLen),
                       tokenEnd.style));
      posAbs += tokLen;
      posChunk += tokLen;
    }
  }

  return tokens;
}

/** splits markup tokens into declarations, tags, and source chunks.
  * @private
  */
function PR_splitMarkup(chunks) {
  // A state machine to split out declarations, tags, etc.
  // This state machine deals with absolute space in the text, indexed by k,
  // and position in the current chunk, indexed by pos and tokenStart to
  // generate a list of the ends of tokens.
  // Absolute space is calculated by considering the chunks as appended into
  // one big string, as they were before being split.

  // Known failure cases
  // Server side scripting sections such as <?...?> in attributes.
  // i.e. <span class="<? foo ?>">
  // Handling this would require a stack, and we don't use PHP.

  // The output: a list of pairs of PR_TokenEnd instances
  var tokenEnds = new Array();

  var state = 0;  // FSM state variable
  var k = 0;  // position in absolute space of the start of the current chunk
  var tokenStart = -1;  // the start of the current token

  // Try to find a closing tag for any open <style> or <script> tags
  // We can't do this at a later stage because then the following case
  // would fail:
  // <script>document.writeln('<!--');</script>

  // We use tokenChars[:tokenCharsI] to accumulate the tag name so that we
  // can check whether to enter into a no scripting section when the tag ends.
  var tokenChars = new Array(12);
  var tokenCharsI = 0;
  // if non null, the tag prefix that we need to see to break out.
  var endScriptTag = null;
  var decodeHelper = new PR_DecodeHelper();

  for (var ci = 0, nc = chunks.length; ci < nc; ++ci) {
    var chunk = chunks[ci];
    if (PR_PLAIN != chunk.style) {
      k += chunk.token.length;
      continue;
    }

    var s = chunk.token;
    var pos = 0;  // the position past the last character processed so far in s

    for (var i = 0, n = s.length; i < n; /* i = next at bottom */) {
      decodeHelper.decode(s, i);
      var ch = decodeHelper.ch;
      var next = decodeHelper.next;

      var tokenStyle = null;
      switch (state) {
        case 0:
          if ('<' == ch) { state = 1; }
          break;
        case 1:
          tokenCharsI = 0;
          if ('/' == ch) {  // only consider close tags if we're in script/style
            state = 7;
          } else if (null == endScriptTag) {
            if ('!' == ch) {
              state = 2;
            } else if (PR_isWordChar(ch)) {
              state = 8;
            } else if ('?' == ch) {
              state = 9;
            } else if ('%' == ch) {
              state = 11;
            } else if ('<' != ch) {
              state = 0;
            }
          } else if ('<' != ch) {
            state = 0;
          }
          break;
        case 2:
          if ('-' == ch) {
            state = 4;
          } else if (PR_isWordChar(ch)) {
            state = 3;
          } else if ('<' == ch) {
            state = 1;
          } else {
            state = 0;
          }
          break;
        case 3:
          if ('>' == ch) {
            state = 0;
            tokenStyle = PR_DECLARATION;
          }
          break;
        case 4:
          if ('-' == ch) { state = 5; }
          break;
        case 5:
          if ('-' == ch) { state = 6; }
          break;
        case 6:
          if ('>' == ch) {
            state = 0;
            tokenStyle = PR_COMMENT;
          } else if ('-' == ch) {
            state = 6;
          } else {
            state = 4;
          }
          break;
        case 7:
          if (PR_isWordChar(ch)) {
            state = 8;
          } else if ('<' == ch) {
            state = 1;
          } else {
            state = 0;
          }
          break;
        case 8:
          if ('>' == ch) {
            state = 0;
            tokenStyle = PR_TAG;
          }
          break;
        case 9:
          if ('?' == ch) { state = 10; }
          break;
        case 10:
          if ('>' == ch) {
            state = 0;
            tokenStyle = PR_SOURCE;
          } else if ('?' != ch) {
            state = 9;
          }
          break;
        case 11:
          if ('%' == ch) { state = 12; }
          break;
        case 12:
          if ('>' == ch) {
            state = 0;
            tokenStyle = PR_SOURCE;
          } else if ('%' != ch) {
            state = 11;
          }
          break;
      }

      if (tokenCharsI < tokenChars.length) {
        tokenChars[tokenCharsI++] = ch.toLowerCase();
      }
      if (1 == state) { tokenStart = k + i; }
      i = next;
      if (tokenStyle != null) {
        if (null != tokenStyle) {
          if (endScriptTag) {
            if (PR_prefixMatch(tokenChars, tokenCharsI, endScriptTag)) {
              endScriptTag = null;
            }
          } else {
            if (PR_prefixMatch(tokenChars, tokenCharsI, 'script')) {
              endScriptTag = '/script';
            } else if (PR_prefixMatch(tokenChars, tokenCharsI, 'style')) {
              endScriptTag = '/style';
            } else if (PR_prefixMatch(tokenChars, tokenCharsI, 'xmp')) {
              endScriptTag = '/xmp';
            }
          }
          // disallow the tag if endScriptTag is set and this was not an open
          // tag.
          if (endScriptTag && tokenCharsI && '/' == tokenChars[0]) {
            tokenStyle = null;
          }
        }
        if (null != tokenStyle) {
          tokenEnds.push(new PR_TokenEnd(tokenStart, PR_PLAIN));
          tokenEnds.push(new PR_TokenEnd(k + next, tokenStyle));
        }
      }
    }
    k += chunk.token.length;
  }
  tokenEnds.push(new PR_TokenEnd(k, PR_PLAIN));

  return tokenEnds;
}

/** splits the given string into comment, string, and "other" tokens.
  * @return an array of PR_Tokens with style in
  *   (PR_STRING, PR_COMMENT, PR_PLAIN, null)
  *   The result array may contain spurious zero length tokens.  Ignore them.
  *
  * @private
  */
function PR_splitStringAndCommentTokens(chunks) {
  // a state machine to split out comments, strings, and other stuff
  var tokenEnds = new Array();  // positions of ends of tokens in absolute space
  var state = 0;  // FSM state variable
  var delim = -1;  // string delimiter
  var k = 0;  // absolute position of beginning of current chunk
  for (var ci = 0, nc = chunks.length; ci < nc; ++ci) {
    var chunk = chunks[ci];
    var s = chunk.token;
    if (PR_PLAIN == chunk.style) {
      for (var i = 0, n = s.length; i < n; ++i) {
        var ch = s.charAt(i);
        if (0 == state) {
          if (ch == '"' || ch == '\'' || ch == '`') {
            tokenEnds.push(new PR_TokenEnd(k + i, PR_PLAIN));
            state = 1;
            delim = ch;
          } else if (ch == '/') {
            state = 3;
          } else if (ch == '#') {
            tokenEnds.push(new PR_TokenEnd(k + i, PR_PLAIN));
            state = 4;
          }
        } else if (1 == state) {
          if (ch == delim) {
            state = 0;
            tokenEnds.push(new PR_TokenEnd(k + i + 1, PR_STRING));
          } else if (ch == '\\') {
            state = 2;
          }
        } else if (2 == state) {
          state = 1;
        } else if (3 == state) {
          if (ch == '/') {
            state = 4;
            tokenEnds.push(new PR_TokenEnd(k + i - 1, PR_PLAIN));
          } else if (ch == '*') {
            state = 5;
            tokenEnds.push(new PR_TokenEnd(k + i - 1, PR_PLAIN));
          } else {
            state = 0;
            // next loop will reenter state 0 without same value of i, so
            // ch will be reconsidered as start of new token.
            --i;
          }
        } else if (4 == state) {
          if (ch == '\r' || ch == '\n') {
            state = 0;
            tokenEnds.push(new PR_TokenEnd(k + i, PR_COMMENT));
          }
        } else if (5 == state) {
          if (ch == '*') {
            state = 6;
          }
        } else if (6 == state) {
          if (ch == '/') {
            state = 0;
            tokenEnds.push(new PR_TokenEnd(k + i + 1, PR_COMMENT));
          } else if (ch != '*') {
            state = 5;
          }
        }
      }
    }
    k += s.length;
  }
  tokenEnds.push(new PR_TokenEnd(k, PR_PLAIN));  // a token ends at the end

  return PR_splitChunks(chunks, tokenEnds);
}

/** used by lexSource to split a non string, non comment token.
  * @private
  */
function PR_splitNonStringNonCommentToken(s, outlist) {
  var pos = 0;
  var state = 0;
  for (var i = 0; i <= s.length; i++) {
    var ch = s.charAt(i);
    // the next state.
    // if set to -1 then it will cause a reentry to state 0 without consuming
    // another character.
    var nstate = state;

    if (i == s.length) {
      // nstate will not be equal to state, so it will append the token
      nstate = -2;
    } else {
      switch (state) {
      case 0:  // whitespace state
        if (PR_isIdentifierStart(ch)) {
          nstate = 1;
        } else if (PR_isDigitChar(ch)) {
          nstate = 2;
        } else if (!PR_isSpaceChar(ch)) {
          nstate = 3;
        }
        if (nstate && pos < i) {
          var t = s.substring(pos, i);
          outlist.push(new PR_Token(t, PR_PLAIN));
          pos = i;
        }
        break;
      case 1:  // identifier state
        if (!PR_isIdentifierPart(ch)) {
          nstate = -1;
        }
        break;
      case 2:  // number literal state
        // handle numeric literals like
        // 0x7f 300UL 100_000

        // this does not treat floating point values as a single literal
        //   0.1 and 3e-6
        // are each split into multiple tokens
        if (!(PR_isDigitChar(ch) || PR_isWordChar(ch) || ch == '_')) {
          nstate = -1;
        }
        break;
      case 3:  // punctuation state
        if (PR_isIdentifierStart(ch) || PR_isDigitChar(ch) ||
            PR_isSpaceChar(ch)) {
          nstate = -1;
        }
        break;
      }
    }

    if (nstate != state) {
      if (nstate < 0) {
        if (i > pos) {
          var t = s.substring(pos, i);
          var ch0 = t.charAt(0);
          var style;
          if (PR_isIdentifierStart(ch0)) {
            if (PR_keywords[t]) {
              style = PR_KEYWORD;
            }
            else if (ch0 == '@') {
              style = PR_LITERAL;
            } else {
              // Treat any word that starts with an uppercase character and
              // contains at least one lowercase character as a type, or
              // ends with _t.
              // This works perfectly for Java, pretty well for C++, and
              // passably for Python.  The _t catches C structs.
              var isType = false;
              if (ch0 >= 'A' && ch0 <= 'Z') {
                for (var j = 1; j < t.length; j++) {
                  var ch1 = t.charAt(j);
                  if (ch1 >= 'a' && ch1 <= 'z') {
                    isType = true;
                    break;
                  }
                }
                if (!isType && t.length >= 2 &&
                    t.substring(t.length - 2) == '_t') {
                  isType = true;
                }
              }
              style = isType ? PR_TYPE : PR_PLAIN;
            }
          } else if (PR_isDigitChar(ch0)) {
            style = PR_LITERAL;
          } else if (!PR_isSpaceChar(ch0)) {
            style = PR_PUNCTUATION;
          } else {
            style = PR_PLAIN;
          }
          pos = i;
          outlist.push(new PR_Token(t, style));
        }

        state = 0;
        if (nstate == -1) {
          // don't increment.  This allows us to use state 0 to redispatch based
          // on the current character.
          i--;
          continue;
        }
      }
      state = nstate;
    }
  }
}

/** split a group of chunks of markup.
  * @private
  */
function PR_tokenizeMarkup(chunks) {
  if (!(chunks && chunks.length)) { return chunks; }

  var tokenEnds = PR_splitMarkup(chunks);
  return PR_splitChunks(chunks, tokenEnds);
}

/** split tags attributes and their values out from the tag name, and
  * recursively lex source chunks.
  * @private
  */
function PR_splitTagAttributes(tokens) {
  var tokensOut = new Array();
  var state = 0;
  var stateStyle = PR_TAG;
  var delim = null;  // attribute delimiter for quoted value state.
  var decodeHelper = new PR_DecodeHelper();
  for (var ci = 0; ci < tokens.length; ++ci) {
    var tok = tokens[ci];
    if (PR_TAG == tok.style) {
      var s = tok.token;
      var start = 0;
      for (var i = 0; i < s.length; /* i = next at bottom */) {
        decodeHelper.decode(s, i);
        var ch = decodeHelper.ch;
        var next = decodeHelper.next;

        var emitEnd = null;  // null or position of end of chunk to emit.
        var nextStyle = null;  // null or next value of stateStyle
        if (ch == '>') {
          if (PR_TAG != stateStyle) {
            emitEnd = i;
            nextStyle = PR_TAG;
          }
        } else {
          switch (state) {
            case 0:
              if ('<' == ch) { state = 1; }
              break;
            case 1:
              if (PR_isSpaceChar(ch)) { state = 2; }
              break;
            case 2:
              if (!PR_isSpaceChar(ch)) {
                nextStyle = PR_ATTRIB_NAME;
                emitEnd = i;
                state = 3;
              }
              break;
            case 3:
              if ('=' == ch) {
                emitEnd = i;
                nextStyle = PR_TAG;
                state = 5;
              } else if (PR_isSpaceChar(ch)) {
                emitEnd = i;
                nextStyle = PR_TAG;
                state = 4;
              }
              break;
            case 4:
              if ('=' == ch) {
                state = 5;
              } else if (!PR_isSpaceChar(ch)) {
                emitEnd = i;
                nextStyle = PR_ATTRIB_NAME;
                state = 3;
              }
              break;
            case 5:
              if ('"' == ch || '\'' == ch) {
                emitEnd = i;
                nextStyle = PR_ATTRIB_VALUE;
                state = 6;
                delim = ch;
              } else if (!PR_isSpaceChar(ch)) {
                emitEnd = i;
                nextStyle = PR_ATTRIB_VALUE;
                state = 7;
              }
              break;
            case 6:
              if (ch == delim) {
                emitEnd = next;
                nextStyle = PR_TAG;
                state = 2;
              }
              break;
            case 7:
              if (PR_isSpaceChar(ch)) {
                emitEnd = i;
                nextStyle = PR_TAG;
                state = 2;
              }
              break;
          }
        }
        if (emitEnd) {
          if (emitEnd > start) {
            tokensOut.push(
                new PR_Token(s.substring(start, emitEnd), stateStyle));
            start = emitEnd;
          }
          stateStyle = nextStyle;
        }
        i = next;
      }
      if (s.length > start) {
        tokensOut.push(new PR_Token(s.substring(start, s.length), stateStyle));
      }
    } else {
      if (tok.style) {
        state = 0;
        stateStyle = PR_TAG;
      }
      tokensOut.push(tok);
    }
  }
  return tokensOut;
}

/** identify regions of markup that are really source code, and recursivley
  * lex them.
  * @private
  */
function PR_splitSourceNodes(tokens) {
  var tokensOut = new Array();
  // when we see a <script> tag, store '/' here so that we know to end the
  // source processing
  var endScriptTag = null;
  var decodeHelper = new PR_DecodeHelper();

  var sourceChunks = null;

  for (var ci = 0, nc = tokens.length; ci < nc; ++ci) {
    var tok = tokens[ci];
    if (null == tok.style) {
      tokens.push(tok);
      continue;
    }

    var s = tok.token;

    if (null == endScriptTag) {
      if (PR_SOURCE == tok.style) {
        // split off any starting and trailing <?, <%
        if ('<' == decodeHelper.decode(s, 0)) {
          decodeHelper.decode(s, decodeHelper.next);
          if ('%' == decodeHelper.ch || '?' == decodeHelper.ch) {
            endScriptTag = decodeHelper.ch;
            tokensOut.push(new PR_Token(s.substring(0, decodeHelper.next),
                                        PR_TAG));
            s = s.substring(decodeHelper.next, s.length);
          }
        }
      } else if (PR_TAG == tok.style) {
        if ('<' == decodeHelper.decode(s, 0) &&
            '/' != s.charAt(decodeHelper.next)) {
          var tagContent = s.substring(decodeHelper.next).toLowerCase();
          // FIXME(msamuel): this does not mirror exactly the code in
          // in PR_splitMarkup that defers splitting tags inside script and
          // style blocks.
          if (PR_startsWith(tagContent, 'script') ||
              PR_startsWith(tagContent, 'style') ||
              PR_startsWith(tagContent, 'xmp')) {
            endScriptTag = '/';
          }
        }
      }
    }

    if (null != endScriptTag) {
      var endTok = null;
      if (PR_SOURCE == tok.style) {
        if (endScriptTag == '%' || endScriptTag == '?') {
          var pos = s.lastIndexOf(endScriptTag);
          if (pos >= 0 && '>' == decodeHelper.decode(s, pos + 1) &&
              s.length == decodeHelper.next) {
            endTok = new PR_Token(s.substring(pos, s.length), PR_TAG);
            s = s.substring(0, pos);
          }
        }
        if (null == sourceChunks) { sourceChunks = new Array(); }
        sourceChunks.push(new PR_Token(s, PR_PLAIN));
      } else if (PR_PLAIN == tok.style) {
        if (null == sourceChunks) { sourceChunks = new Array(); }
        sourceChunks.push(tok);
      } else if (PR_TAG == tok.style) {
        // if it starts with </ then it must be the end tag.
        if ('<' == decodeHelper.decode(tok.token, 0) &&
            tok.token.length > decodeHelper.next &&
            '/' == decodeHelper.decode(tok.token, decodeHelper.next)) {
          endTok = tok;
        } else {
          tokensOut.push(tok);
        }
      } else {
        if (sourceChunks) {
          sourceChunks.push(tok);
        } else {
          // push remaining tag and attribute tokens from the opening tag
          tokensOut.push(tok);
        }
      }
      if (endTok) {
        if (sourceChunks) {
          var sourceTokens = PR_lexSource(sourceChunks);
          tokensOut.push(new PR_Token('<span class=embsrc>', null));
          for (var si = 0, ns = sourceTokens.length; si < ns; ++si) {
            tokensOut.push(sourceTokens[si]);
          }
          tokensOut.push(new PR_Token('</span>', null));
          sourceChunks = null;
        }
        tokensOut.push(endTok);
        endScriptTag = null;
      }
    } else {
      tokensOut.push(tok);
    }
  }
  return tokensOut;
}

/** splits the quotes from an attribute value.
  * ['"foo"'] -> ['"', 'foo', '"']
  * @private
  */
function PR_splitAttributeQuotes(tokens) {
  var firstPlain = null, lastPlain = null;
  for (var i = 0; i < tokens.length; ++i) {
    if (PR_PLAIN = tokens[i].style) {
      firstPlain = i;
      break;
    }
  }
  for (var i = tokens.length; --i >= 0;) {
    if (PR_PLAIN = tokens[i].style) {
      lastPlain = i;
      break;
    }
  }
  if (null == firstPlain) { return tokens; }

  var decodeHelper = new PR_DecodeHelper();
  var fs = tokens[firstPlain].token;
  var fc = decodeHelper.decode(fs, 0);
  if ('"' != fc && '\'' != fc) {
    return tokens;
  }
  var fpos = decodeHelper.next;

  var ls = tokens[lastPlain].token;
  var lpos = ls.lastIndexOf('&');
  if (lpos < 0) { lpos = ls.length - 1; }
  var lc = decodeHelper.decode(ls, lpos);
  if (lc != fc || decodeHelper.next != ls.length) {
    lc = null;
    lpos = ls.length;
  }

  var tokensOut = new Array();
  for (var i = 0; i < firstPlain; ++i) {
    tokensOut.push(tokens[i]);
  }
  tokensOut.push(new PR_Token(fs.substring(0, fpos), PR_ATTRIB_VALUE));
  if (lastPlain == firstPlain) {
    tokensOut.push(new PR_Token(fs.substring(fpos, lpos), PR_PLAIN));
  } else {
    tokensOut.push(new PR_Token(fs.substring(fpos, fs.length), PR_PLAIN));
    for (var i = firstPlain + 1; i < lastPlain; ++i) {
      tokensOut.push(tokens[i]);
    }
    if (lc) {
      tokens.push(new PR_Token(ls.substring(0, lpos), PR_PLAIN));
    } else {
      tokens.push(tokens[lastPlain]);
    }
  }
  if (lc) {
    tokensOut.push(new PR_Token(ls.substring(lpos, ls.length), PR_PLAIN));
  }
  for (var i = lastPlain + 1; i < tokens.length; ++i) {
    tokensOut.push(tokens[i]);
  }
  return tokensOut;
}

/** identify attribute values that really contain source code and recursively
  * lex them.
  * @private
  */
function PR_splitSourceAttributes(tokens) {
  var tokensOut = new Array();

  var sourceChunks = null;
  var inSource = false;
  var name = '';

  for (var ci = 0, nc = tokens.length; ci < nc; ++ci) {
    var tok = tokens[ci];
    var outList = tokensOut;
    if (PR_TAG == tok.style) {
      if (inSource) {
        inSource = false;
        name = '';
        if (sourceChunks) {
          tokensOut.push(new PR_Token('<span class=embsrc>', null));
          var sourceTokens =
            PR_lexSource(PR_splitAttributeQuotes(sourceChunks));
          for (var si = 0, ns = sourceTokens.length; si < ns; ++si) {
            tokensOut.push(sourceTokens[si]);
          }
          tokensOut.push(new PR_Token('</span>', null));
          sourceChunks = null;
        }
      } else if (name && tok.token.indexOf('=') >= 0) {
        var nameLower = name.toLowerCase();
        if (PR_startsWith(nameLower, 'on') || 'style' == nameLower) {
          inSource = true;
        }
      } else {
        name = '';
      }
    } else if (PR_ATTRIB_NAME == tok.style) {
      name += tok.token;
    } else if (PR_ATTRIB_VALUE == tok.style) {
      if (inSource) {
        if (null == sourceChunks) { sourceChunks = new Array(); }
        outList = sourceChunks;
        tok = new PR_Token(tok.token, PR_PLAIN);
      }
    } else {
      if (sourceChunks) {
        outList = sourceChunks;
      }
    }
    outList.push(tok);
  }
  return tokensOut;
}

/** returns a list of PR_Token objects given chunks of source code.
  *
  * This code assumes that < tokens are html escaped, but " are not.
  * It will do a resonable job with <, but will not recognize an &quot;
  * as starting a string.
  *
  * This code treats ", ', and ` as string delimiters, and \ as a string escape.
  * It does not recognize double delimiter escapes, or perl's qq() style
  * strings.
  *
  * It recognizes C, C++, and shell style comments.
  *
  * @param chunks PR_Tokens with style in (null, PR_PLAIN)
  */
function PR_lexSource(chunks) {
  // positions of ends of tokens in order
  var tokensIn = PR_splitStringAndCommentTokens(chunks);

  // split entities out of so that we know to treat them as single units.
  tokensIn = PR_splitEntities(tokensIn);

  // split non comment|string tokens on whitespace and word boundaries
  var tokensOut = new Array();
  for (var i = 0; i < tokensIn.length; ++i) {
    var tok = tokensIn[i];
    var t = tok.token;
    var s = tok.style;

    if (PR_PLAIN == s) {
      PR_splitNonStringNonCommentToken(t, tokensOut);
      continue;
    }
    tokensOut.push(tok);
  }

  return tokensOut;
}

/** returns a list of PR_Token objects given a string of markup.
  *
  * This code assumes that < tokens are html escaped, but " are not.
  * It will do a resonable job with <, but will not recognize an &quot;
  * as starting a string.
  *
  * This code recognizes a number of constructs.
  * <!-- ... --> comment
  * <!\w ... >   declaration
  * <\w ... >    tag
  * </\w ... >   tag
  * <?...?>      embedded source
  * &[#\w]...;   entity
  *
  * It does not recognizes %foo; entities.
  *
  * It will recurse into any <style>, <script>, and on* attributes using
  * PR_lexSource.
  */
function PR_lexMarkup(chunks) {
  // This function works as follows:
  // 1) Start by splitting the markup into text and tag chunks
  //    Input:  String s
  //    Output: List<PR_Token> where style in (PR_PLAIN, null)
  // 2) Then split the text chunks further into comments, declarations,
  //    tags, etc.
  //    After each split, consider whether the token is the start of an
  //    embedded source section, i.e. is an open <script> tag.  If it is,
  //    find the corresponding close token, and don't bother to lex in between.
  //    Input:  List<String>
  //    Output: List<PR_Token> with style in (PR_TAG, PR_PLAIN, PR_SOURCE, null)
  // 3) Finally go over each tag token and split out attribute names and values.
  //    Input:  List<PR_Token>
  //    Output: List<PR_Token> where style in
  //            (PR_TAG, PR_PLAIN, PR_SOURCE, NAME, VALUE, null)
  var tokensOut = PR_tokenizeMarkup(chunks);
  tokensOut = PR_splitTagAttributes(tokensOut);
  tokensOut = PR_splitSourceNodes(tokensOut);
  tokensOut = PR_splitSourceAttributes(tokensOut);
  return tokensOut;
}

/** classify the string as either source or markup and lex appropriately. */
function PR_lexOne(s) {
  var chunks = PR_chunkify(s);
  // treat it as markup if the first non whitespace character is a < and the
  // last non-whitespace character is a >
  var isMarkup = false;
  for (var i = 0; i < chunks.length; ++i) {
    if (PR_PLAIN == chunks[i].style) {
      if (PR_startsWith(PR_trim(chunks[i].token), '&lt;')) {
        for (var j = chunks.length; --j >= 0;) {
          if (PR_PLAIN == chunks[j].style) {
            isMarkup = PR_endsWith(PR_trim(chunks[j].token), '&gt;');
            break;
          }
        }
      }
      break;
    }
  }
  return isMarkup ? PR_lexMarkup(chunks) : PR_lexSource(chunks);
}

/** pretty print a chunk of code.
  *
  * @param s code as html
  * @return code as html, but prettier
  */
function prettyPrintOne(s) {
  try {
    var tokens = PR_lexOne(s);
    var out = '';
    var lastStyle = null;
    for (var i = 0; i < tokens.length; i++) {
      var t = tokens[i];
      if (t.style != lastStyle) {
        if (lastStyle != null) {
          out += '</span>';
        }
        if (t.style != null) {
          out += '<span class=' + t.style + '>';
        }
        lastStyle = t.style;
      }
      var html = t.token;
      if (null != t.style) {
        // This interacts badly with the wiki which introduces paragraph tags
        // int pre blocks for some strange reason.
        // It's necessary for IE though which seems to lose the preformattedness
        // of <pre> tags when their innerHTML is assigned.
        html = html.replace(/(?:\r\n?)|\n/g, '<br>').replace(/  /g, '&nbsp; ');
      }
      out += html;
    }
    if (lastStyle != null) {
      out += '</span>';
    }
    return out;
  } catch (e) {
    //alert(e.stack);  // DISABLE in production
    return s;
  }
}

/** find all the < pre > and < code > tags in the DOM with class=prettyprint and
  * prettify them.
  */
function prettyPrint() {
  // fetch a list of nodes to rewrite
  var codeSegments = [
      document.getElementsByTagName('pre'),
      document.getElementsByTagName('code'),
      document.getElementsByTagName('xmp') ];
  var elements = [];
  for (var i = 0; i < codeSegments.length; ++i) {
    for (var j = 0; j < codeSegments[i].length; ++j) {
      elements.push(codeSegments[i][j]);
    }
  }
  codeSegments = null;

  // the loop is broken into a series of continuations to make sure that we
  // don't make the browser unresponsive when rewriting a large page.
  var k = 0;

  function doWork() {
    var endTime = new Date().getTime() + 250;
    for (; k < elements.length && new Date().getTime() < endTime; k++) {
      var cs = elements[k];
      if (cs.className && cs.className.indexOf('prettyprint') >= 0) {

        // make sure this is not nested in an already prettified element
        var nested = false;
        for (var p = cs.parentNode; p != null; p = p.parentNode) {
          if ((p.tagName == 'pre' || p.tagName == 'code' ||
               p.tagName == 'xmp') &&
              p.className && p.className.indexOf('prettyprint') >= 0) {
            nested = true;
            break;
          }
        }
        if (!nested) {
          // XMP tags contain unescaped entities so require special handling.
          var isRawContent = 'XMP' == cs.tagName;

          // fetch the content as a snippet of properly escaped HTML
          var content = cs.innerHTML;
          if (isRawContent) {
            content = PR_textToHtml(content);
          }

          // do the pretty printing
          var newContent = prettyPrintOne(content);

          // push the prettified html back into the tag.
          if (!isRawContent) {
            // just replace the old html with the new
            cs.innerHTML = newContent;
          } else {
            // we need to change the tag to a <pre> since <xmp>s do not allow
            // embedded tags such as the span tags used to attach styles to
            // sections of source code.
            var pre = document.createElement('PRE');
            for (var i = 0; i < cs.attributes.length; ++i) {
              var a = cs.attributes[i];
              if (a.specified) {
                pre.setAttribute(a.name, a.value);
              }
            }
            pre.innerHTML = newContent;
            // remove the old
            cs.parentNode.replaceChild(pre, cs);
          }
        }
      }
    }
    if (k < elements.length) {
      // finish up in a continuation
      setTimeout(doWork, 250);
    }
  }

  doWork();
}
�������������������������������������������������testng-6.9.12/doc/maven.html������������������������������������������������������������������������0000644�0001750�0001750�00000016433�12732165123�015171� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
    <head>
        <title>TestNG - Maven</title>

        <link rel="stylesheet" href="testng.css" type="text/css" />
        <link type="text/css" rel="stylesheet" href="http://beust.com/beust.css"  />
        <script type="text/javascript" src="http://beust.com/prettify.js"></script>
        <script type="text/javascript" src="banner.js"></script>

        <script type="text/javascript" src="http://beust.com/scripts/shCore.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushJava.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushXml.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushBash.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushPlain.js"></script>
        <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shCore.css"/>
        <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shThemeCedric.css"/>
        <script type="text/javascript">
          SyntaxHighlighter.config.clipboardSwf = 'scripts/clipboard.swf';
          SyntaxHighlighter.defaults['gutter'] = false;
          SyntaxHighlighter.all();
        </script>

</head>

<body onLoad="prettyPrint()">

<script type="text/javascript">
    displayMenu("maven.html")
</script>


<style type="text/css">
    *.P1 { font-family:Sans; font-size:10pt; margin-left:0in; margin-right:0in; text-align:left ! important; text-indent:0inch; color:#a52a2a; }
    *.P2 { font-family:Sans; font-size:10pt; margin-left:0in; margin-right:0in; text-align:left ! important; text-indent:0inch; }
    *.P3 { font-family:'Nimbus Roman No9 L'; font-size:12pt; margin-left:0in; margin-right:0in; text-align:left ! important; text-indent:0inch; }
    *.Standard { font-family:'Nimbus Roman No9 L'; font-size:12pt; }
    *.Textbody { font-family:'Nimbus Roman No9 L'; font-size:12pt; margin-top:0in; margin-bottom:0.0835in; }
    *.T1 { font-weight:bold; }
    *.T2 { color:#353535; }
    *.T3 { color:#a52a2a; font-weight:bold; }
    *.T4 { color:#a52a2a; }
    *.T5 { color:#353535; font-family:Sans; font-size:10pt; }
    *.T6 { color:#a52a2a; font-family:Sans; font-size:10pt; font-weight:bold; }
    *.T7 { color:#a52a2a; font-family:Sans; font-size:10pt; }
  p,pre { width: 80%; }

  ul.toc {
    list-style: none;
    margin:0 0.7em 0;
    padding:0;
    font-family: verdana, arial, sans-serif;
  }
  ul.toc li {
    padding:0;
    margin: 0.2em 0 0;
  }
  ul ul {
    margin:0 2em 0;
    padding: 0;
    list-style-type: none;
  }
  li a {
    display: block;
    text-decoration: none;
    padding: 2px 10px;
    width: 140px;
  }
  ul.sub li a {
    display: block;
    border-top: none;
    padding: 2px 10px;
    background-color: transparent;
  }
</style>

<h2>TestNG Maven plug-ins</h2>

<h4>Table of Contents</h4>
<ul class="toc">
  <li class="first">
    <a class="summary" href="#maven2">Maven2 Plugin</a>

    <ul class="sub">
      <li><a href="#archetype">Archetype</a></li>
    </ul>
  </li>
  
  <li class="last"><a class="summary" href="#maven1">Maven 1 Plugin</a></li>
</ul>

<!--  begin maven2  -->
<h3 id="maven2">Maven 2</h3>

<p>Maven 2 supports TestNG out of the box without the need to download any additional plugins <em>(other than TestNG itself)</em>. It is recommended that you use version 2.4 or above of the Surefire plugin (this is the case in all recent versions of Maven).</p>

<p>
You can find the full instructions on the <a href="http://maven.apache.org/plugins/maven-surefire-plugin/">Maven Surefire Plugin web site</a>. There are also <a href="http://maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html">TestNG-specific instructions</a>.
</p>

<h4>Specifying your pom.xml</h4>

The dependency in your project should look like the following:

<pre class="brush: xml">
 &lt;dependency&gt;
   &lt;groupId&gt;org.testng&lt;/groupId&gt;
   &lt;artifactId&gt;testng&lt;/artifactId&gt;
   &lt;version&gt;6.8&lt;/version&gt;
   &lt;scope&gt;test&lt;/scope&gt;
 &lt;/dependency&gt;
</pre>

<h4>Sample Report</h4>
<p>
A sample surefire report with TestNG can be found <a href="samplereport/index.html">here</a>.
</p>
<br/>
<!--  end maven2  -->

<!-- maven2 archetype -->
<h3 id="archetype">Maven TestNG Archetype <em>(Martin Gilday)</em></h3>
<p>
  Martin Gilday has added a new archetype for Maven2: to create a project using the archetype you simply have to specify my repository and the archetype ID.
</p>
  <pre class="brush: text">
  mvn archetype:create -DgroupId=org.martingilday -DartifactId=test1 -DarchetypeGroupId=org.martingilday -DarchetypeArtifactId=testng-archetype
    -DarchetypeVersion=1.0-SNAPSHOT -DremoteRepositories=http://www.martingilday.org/repository/</pre>

<p>Of course substitute in your own groupId and artifactId.</p>
<p>Don't forget to keep checking back at <a href="http://www.martingilday.org/updates/Maven+TestNG+Archetype">Martin's blog</a> for more updates. </p>
<!-- end maven2 archetype -->

<br/><br/>
<h3 id="maven1">Maven 1 (by Andrew Glover)</h3>

<p>The TestNG Maven plug-in is quite simple and consists of
two goals and a series of optional properties.</p>

<p>Currently the 1.1 version of the plug-in is bundled with
official releases of TestNG. To utilize the plug-in, copy the
<tt>maven-testng-plugin-<version>.jar</tt> to the <tt>$MAVEN_HOME/plugins</tt>
directory.</p>

<p>For the latest version of the plug-in (1.2 as of 12/12/05),
update your <tt>maven.repo.remote</tt> to include <tt>http://www.vanwardtechnologies.com/repository/</tt>
and then issue the following command: <tt>maven plugin:download</tt>. Maven will issue a series of questions,
answer them as follows: <BR>
<BR>
<TABLE border="1" id="table1">
    <TR>
        <TD><tt>artifactId:</tt></TD>
        <TD><tt>maven-testng-plugin</tt></TD>
    </TR>
    <TR>
        <TD>groupId:</TD>
        <TD><tt>testng</tt></TD>
    </TR>
    <TR>
        <TD>version:</TD>
        <TD><tt>1.2</tt></TD>
    </TR>
</TABLE>
</p>


<h4>Goals</h4>
<table border="1" id="table2">
    <tr>
        <th>Goal</th>
        <th>Description</th>
    </tr>
    <tr>
        <td><tt>testng</tt></td>
        <td>Runs TestNG</td>
    </tr>
    <tr>
        <td><tt>testng:junit-report</tt></td>
        <td>Creates a JUnit style report</td>
    </tr>
</table>
<h4>Properties</h4>
<table border="1" id="table3">
    <tr>
        <th>Property</th>
        <th>Optional?</th>
        <th>Description</th>
    </tr>
    <tr>
        <td><tt>maven.testng.suitexml.name</tt></td>
        <td>Yes</td>
        <td>XML file name- defaults to <tt>testng.xml</tt></td>
    </tr>
    <tr>
        <td><tt>maven.testng.suitexml.dir</tt></td>
        <td>Yes</td>
        <td>Directory where XML file lives. Defaults to <tt>${basedir}/test/conf</tt></td>
    </tr>
    <tr>
        <td><tt>maven.testng.output.dir</tt></td>
        <td>Yes</td>
        <td>Default report directory. Defaults to <tt>${maven.build.dir}/testng-output</tt></td>
    </tr>
    <tr>
        <td><tt>maven.testng.report.dir</tt></td>
        <td>Yes</td>
        <td>Directory for JUnit reports. Defaults to <tt>${maven.build.dir}/testngJunitReport</tt></td>
    </tr>
</table>

<!-- end maven stuff -->

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>
	
</body>
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/pics/�����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�12732165123�014124� 5����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/pics/chronological-methods.png����������������������������������������������������0000644�0001750�0001750�00000040267�12732165123�021127� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR��`��^���l�� �IDATx]PTg}uVQ[M@tӐΎ?vȆRFN4VgHINNdG-LLr1ѲiS	;b^ 6kHsV~]-4tӿx<okА����nu����/$��� A��	"���4H��A���
D���h ��@544~���AD),,8���'b��FDEmmTAAҗ9$	n8

$\("GP!6$
G\A"b10���
D���h ��@���$���Ј"AtM!>W]cVx8!��`|z|hhh5w㛣&/Z[6%Il��Ľ ɠ:WDT:44Ze!^Dr��Q$'*Uϩ&��$[♠LsMY9~<i}Tv:`ǕND|
qU;ܥ0��̈%JDZUmqT;&P.ǎ[Ea;dJh[9Ǖ+%)tX\{{CLUJ2inU�@R67*)WX}=pj\I5qݓfjf4Nk��IdAt)i2@k?FM'
ĺv��d.A,;h5xɔ@u%ڵ�2ORQX5)qXQ]Mbv/S{i%޵�duh[]tgVSP؉8kV9Wyx6TO,bSխcVrGu^847ěJ$ڵ13|VDq˽}„1xޟa{}Ȕ�!
c"aEz[˿Q'[/w^SJ/:~e>/	-Xս}M܇[[[=ע!x2a}LV)4=wjsk'gXK<g$YN\OfB[:
!vhHt#̸k0C@wS7zg%ykS?X}|3o4LVU~klmSI'*t?-j1$[
s=PcNjޔ1iw[(?.>-F-3<	"3*ZAz"XPCyAτgl
Ķj*Iͼ6wOxMJZٳj4hG�5=&+>*)DDDߖ&L.YЇ~4CFxŞ={ώ$I
Lo
(+SLխqjRWЃ|*RygE}wʚU{>#ǭ^[5:1O
xuu^



VW{}Sxxڟ;|{M7n<X

AA2ͣ<Sc`Aĸ3a)ӣcUADLUʌ})&JOŎ6D}zS9/5vFs]&SuUz#ğļ6ƑE$W2'ZaftBFha7
3?Q>S;`$ʴ}퀷ȴjs]##zÄ×YjjjB-O棒F'E|
}|/}ƴ "ny>(<{L0aB\}<mgGЃ~oiRǞ>V_U6Ś7
Rs90J|8t0hz@5D/mՄreq_n&]S	zPJ	pԬqՏ6c8#[r".Vemх^"YHƟ|?j/2+"A~<єSꁽ4] >F^:_wm:*/~M&tQ;G5kz{[}Zپ{}o,ک.J=DYKS'P;yhq bh(uw>y;'sn~R41'-
_Uh[{K|~9}
_ay4`|lHAƒjrq\
/K
2tàb<y!fGMyz|x親֑)(g[M'ah@xQS^P}`V580URYpSBQBF	2ғI<ă+VkL^QF�MH'~Ҽ{>8%qxVިC	ٱX{#D3YC[%߫P"W:6=LJ[5�V{Oh2y<2سg*jWw~:l݆qZ�� zQ'ʐkިv;yL���dtA'
���DuF?*nw���}Pv'-(���`Fq>N!\q*v<Q :BDbb<$GkUVmU}Tǃl+ZF^LUCUz^("w[ZO騮U-6*ߘ|k0U���Q{E*cզ>Q0x���puj+QD��0N=T:6C^��7: �� aDAlhh8"H7qBE0pL��c���ᆘQ#תOC$IBDbb<01ɜщ#$IpWhH,X$:��A���
D���h ��@���zcgOȬ/eDcocxC_q~['.y]-CޱƗ>K�@"ї ~ӿZA,j|P&5
N;{W?xv謍l0o<;E~9}6��F!恖]6*RY7N_%aËn-oh+1vN6EzYej5o͟Y?Pw��#:ľ)3Hu/\qCƕCG_:t`S_M1ʍ0_w��:{~_M65N{E
Ȭl/}70)J,w򒲿7
9x<fHߕo\|iG*7Hj~Y_\V3%sqbz2Y9yY��IzėϮY]9ҡ_9_S}WrO
TZ8/TXqξqe{H1twSڰ(7j|J]3#W~9}iA߯tdi=Xxy'��/os70&0_\*;TߕDdrY"ї}/"Ƃg׼5ȬJ2鰫38
k6fȍZt50��=3R'K/}c>SLj*erY_N/yKξѯ?*y[j�
"aYaLNZN=,KD˜ƱO_Qǩ;���Ďјat]fD*3u2/`|у5Z,_]ˍ+RHȀ|㍲,w:LIsS��g95̳M<۸}nj6N^SwE]K߀,
f=_dxGy7^Mf|J?aj*"AYepz��}T<[wKWdL0)9xH[욲Tٟ_L"Y욍"Y+{U.oW,j'^9g"Ϯ)Ɨ5zU%+cg=-dM_kyk��`]<|Mո/ZAHj[#ј\V^+日H@"~YgOk+0<��Q*f���k$r+���Nbn=Y�� ��@#B⿙WNO$IBDb"M;PXX8&���`1���pCњQ#zLH7qBxaщ#$IpWhH,X$:��A���
D���h ��@���zSEǚ^ˈFwuxZ4a"þXO=Ӳ>6_{.dm><C�H_2_\ִwNq'=:S4%|nG{58Uz?~|xoeM{5(;~uփV��0$c;YcK6
ǷsӐ&iQɅon˴I"cM{\MYzROh맇{)݇*Rp��0H^no'>2nwcT?O[TtvP9}|ݎo=&_}k,-��9~I2Mr;)stߺ'2)\y"r{;dm>=|aNH_z],~&iY(;y?}gުoƝݎoev>g[VHsYK}wf%.(Ѿ(>_OU *u|gf��JUSw]ִQyy^Чn<ڴwYӋS}WOMh)25;fG{5]Q?ޱ?|]˚9uxN^zwPP
 t���}8b6i݋Y"uuG<cj|\.|s[sw}ezެ|?sKN]?sӝD*23iݶeM{[*"~gJE�� t1O|dtwLgJQVLh2QWSt[&I׈O2)=vWsYKEN~¹fJ��[:IKt3?M*z|,& g4ǚ>?IS3	~M.Fw0`ܮ6k;T$ц�� 1g>¹n-[+37sJi&L]_<‡_칽xb?uvCY(VA2qT0F�� =Iemw_}TuQI^̪y([z>uԝ{QV1Oݹ=|‡"*3ފz閩;>)71u2QdSîvɴKI~>IϹW1�� >joZG{bI~˚|ݻ=\"f>)"^6;};��Jmn���3$��� A��	"���4",R)OFdI# XhHt544I4���s1��@#ow/8%I# XhO"AoQ	#$IpWhH,X$:��A���
D���h ��@���z>}4Nal91".V6ljxo�x/A<w}WH$Ts)ѲDe\],-+Wǝr/ȥQ��0V$}EDWKN4-sӐfܴ(zNfD$]ѕ'Z<mHUruO��;:Ζ놴lنΖ*}+Ν>-Nsu{X=ie˥ρٹEz
��xDxH_i6LWpb$|9wiK~aNEP鲢~%m˲;\"ҿD2u^o{ɖK-|m=l1mNxzjK)D��b+1W1/u}宽g҅>ղ]ŮՃ>͕}Ձ}+w]WÖeu}Y|[9u6agNS:@\HyzAΏPW{]3��@,Asu[djB8Z=H>0ߢٗZI_w'=:]Sɹ?Uj6my^VTA,1(azkز]?ͽ|05��Č1ې&c>SLj*%m˲]&SVrhec
S=*ڜ.tj?_e;)E6���å#A?3c1QD<Vڧb joh+-۠.FY\,pVg@=-2%1악6d���ghgkg>gQֲ?eG]\[sfv~ٞܥw4--Yܿ%JxfUOOm	6b���1obwgvKncS(:(OPr-vmvO+tQKuI]m۟wxѮ}E.<U3-'D3xѮOE-Obiw~>I+NOW;->]?޽9X���wJe64
|+W|¢ӕEኄ:h(l`/Ί��@%67���D���h ��@���m8"H7qBE044wpL��c���ᆘ?]9jqnkeF<D$+4H$Z,Ɠsynt(~"Ip$-!f���h ��@���$��� A��+<tRxb`H^a-#rzp}Q��GyW3_C*8_ڢ)aԤzL]=UYz]z(���+zĞ_XvXED>VpҦᰅMCJ]F&_SjX6Xs~0>~,SDzj>I��;:āF@FS2r
2E?Z:ly3p1biH][`OX[���	=m6uIz~ePY?aCh:2ÜgÖR3xВw+@2u(?ly谒jyO+3GDD{wv/ﴩ�� ss*oᔭ~,_o?S'R+5@~R{j>yŖJɑ$qz;ę;ڔ=~_yǼ�� OGlvR!EM`Z)kџR/vX"GjsM1HU2DD$jrR#;I2)3l=k[=-"0]j^/b���1_2%#Wh2ϔ1Jɝ3"h,Tߵ-Cyq@O婳LJkGzjT{ZD\[+5WJ��[:zS[SۺhK}ښH)3,'_ooɰf*cOe1/es@nPh�� 1gTlmE-Voy2OF)i\[**rғCk|V"]=bK]!,e \lH%l��b@dhx%_DZ>!k=lS/-J;=
N$sG<"Voe_to,R~r~Q_D-ފz2Dz$sJaKFe2}�� �IDAT+3wڮU|:Wzl_k_j-6yj��	CCC~
Eӕ<7Qi¿̈H7qB8��� fH��A���
D���hDZoQ	C$IpWhH,X$p��b��F!غxj0!$
G\A"b1DxQD$+4H$Z,C��� A��	"���4H��A���HORq8z#"R}ݻ	~awZ|̈P_mI��/z/<sdʻ[*D1uMy[{n]ep'\ߓܺw٣tV��`\ғ .پDD$c
9d]ݩ6P!T/B>(9REdCO&J��$t$=}'u,RszφЊJߟQ]O%ό)2��#H2%3.cJ4+.J3/HƼ}zBATX1=="n
'()rg6\پTv]8+[Z󚜵+>_*fCnOmSY-%1:p3$sKߜמJu|
ux+��T⥽Dzy5	u*L"%>sh]3v}SۓSg=|^ݕy[D:vu{nݻ"">mz3L2Hkjmf_,%?aŻ=j{qI\}|/п=Ƨ@톓l<+͊Qx��0zO{~YnO#{uyO=yl*Ô9H7{z2=*N.ߦe
?}~HuY[ƔσҼ=GO>S2Sr$rۼ3OnЉ��Dt%RswLgJQV]{??!h!""]pvj}kXjH؛O95KK"qg)>aOK"%Dl���"+AҌI_vwddDX}]v>D{JK͙%sGO:sfMQ5,=*߱
��CzI\ڦ{ϑ5ctv3Kϭ
ض&̩?Z=߼z4`CO>	|M/WE?QO!gwmwlƼo��ƥ	CCC~
E?.^S<G98&ORa4Eg=ׇ̮VTf&c燦qs>]z,Rv^6߯j֔:Hw{wQ_[$ep` XhO&c_Q
G\A"b1{���	"���4H��A��� NytQD$+4H$Z,]U���HB1��@#oW֎ZAƫO<>1"Ip$-I9O[5:qD?$	n8

D3���4H��A���
D���h ��@Co;fqc1'v���IG_غq}NΛo<(N��gzĎ>'"RR?cVPs0DJw,ϋx���zڟ6-'c,2ļ7M-3c?>nc��ęOR藜&Ӕ\*-\[}3ODZ7qFIܼiO=cY|QV_t_$Kg㙭RR`G��NG39SرU$Oۡnf?~K^lI{kV��H
os=^FbP^#rOoL)Q[]LHZA���xALIӌ)LI#ʪ7wD8C1f���LOyi\lZi*u8o7W?���AyLy0&a3Y)���DE"[ơSc{kE?lqqQ֏n=V{U�� ]Ŝͥ1$FJwv+>A^3�� E���	"���4H��A���Tщ#$IpWhH,X$	CCC~
$���9��n?I# XhO"A̝j8"H7qBEc���$��� A��	"���4H��?AݗN	vNm��؈͍SJ71ԩˋޞ;��`LA\ˏ8~Tkim&;�G֞u &5Zkpy‘�{P	CA]_~dkO,\N?"��"ީY-kw_^zÏr{?E0f 5o?Y._^zTР�Y|Q{N>dy~yi6Q.~jO>yǿ0Ӄ("/Z1WDdS,llC4k��|l+6z%Yl-Ù+�L}z\��O&xy_EޥKmLG<"_ϕ?x[#31>8��${A6#J~/#D ޹۫=p#3c_䝴O �'m≗Oy6ѿ^wK%)Lۼ<M
S0ʢ([NWy񢷕D̷]{=�ą<d{IS6~{'EOrO~hqJLۼ-s>1t&O6��0Nxjё|N\rъE13��0 ��@���$���ЈHdSQD$+4H$Z,݄!C


c
���C���7?}rx$IpWhH,X' N5NO$IBDb"1���
D���h ��@���$���ЈG^o//Zp;ݯcEdx�+Z֞dyXG�DgxTk"21ԩˋ&5(mZ֞䝴 @9ļpyёp6o߿rԧ"27r?V@"?ĵd#
�m'()ս;".C2P�H@I//?2D`T~y{27ȶ|]ܓED$m˓N*iY󢖵?bj%"#o9C|ɇ7/1�$a$uMEGK^?U/3ʌ?:{'Oث.C߿Gޖ|G;S֩~yi6Q9_;-QR�cbYxъ""3zdac7e1 }򚈤x*`\S2qE+ۏ8G{rimȤ /1GگJ�0\g-S2QVSN
~m.w)ҟE�gez\^Ay[ёmr~nec#/g;{gcDExnŏ̸֢;Aw�`M\rёmE~^6AN99Bb˧.T_ֿ%�`\rl9^ŋV3^~w"aw�X(ԟϩ_oQᴅF;-kwmޖ'ltb~jgy;-kO�ICg#F0�a3Zt)﷛_}9(�[Ø�����$��� A��FE*%
F''$
G\A"b&

jhh(,,h���0b��F!?-7jqʛ;8"Ip$-I9H8"H7qBEc���$��� A��	"���4H��7A71Θlgv6#��Ikή~V:lW\euvoĦ+A7a-r\*b��I)R0EaɎPU_`Q8Mvw﫴]<z`t$:lcmj[٦؄�@Go_ĒnW{_%ΎEoUZ˜HIdMYc4AO8Ő-}vOcu6g,��HhQw߉h94=xEx`KxZtlT��$4nk٦%sSDbCeN
@SyWN)sD;W-)פ8QAo)193ZmotdfAу>";%Ei[��u`b.uaKRe8.V:E\4:q["nʧC2;<HUf1:FqvԹR38M^^zbo:S隣V#Dcn9equt,al��ΎA99il
Xa;:\
C_#bWż ")2.eU:S*s:gNΙݛh1vׅ$oِsښ#"8r,"vGg9J{b
��hpED$E&[ϰoٹ9GG_[] S+w
`K:]">MD\NI2EDUg[̜Kn>��`l655W:!2%sEA++ې"gwX|u)ْz'ϔ9Rj�Jz&C_gigsY۠:kjӥ9nl4Zޤna7̩HwOy:#Atu;EMK~�C
KAY͟^0떽=q0@uI6(cCNEz}Q|>7Q[bhojT,,J[ *fZL6ݳv{oe	#؄!C


"~13
eI# XhO1�� ) ��@���$���ЈyGDI# XhHtV1�� 	1���pCZ8o7wzH7qBxabl?$	n8

D3���4H��A���
D���h ��@#*f{әJHif#%'{D� )
/pX̥K;.9EDst|Uښ%X=:YjپJ[]BFDWL8kAbY۠|_eS_,� )TXJfgԡ/;?Xf}[kZzڔboz: t$:lcm[٦>E��`]|{"t*qv0-z2Z<^zS֕Ra-P4;7"]AO8Ő-}vOcu6g,��HhQPEfl2w"on2MeHf]9qF.HWyszY:F6*��{`IϴBl~TB1ZHJx+'[vuԹ{w|Pkꨠ\FE[:ʚd82	JGbthrڛnY4��sC\갖:,sq)x{V_@7SءteV*{SKf8;\JKRu&i/39J`~+Q:.흮׈Xk[fo/{dD\]3*b��コkPgx j/k0sì51V:쎎:WHXUe1/0HJKkmIR*s:gNΙݛh1vz>%;w#Wk˱jB!5GDpXDvos2[;�"~4)-Rfo6ٚ}}ͱ88*f2YXVP;]ID\NI	?0;`͋ ozATt59	=~즑}�5%)8MM͕NcmȴLD,s.haeRDON!%[RB/<H2HLTg)d��D%=g=OemPI/M.`
Ӎ2iv8hBvmvÜtG{):ל
5=2{{Hi��an1p/ItښsnٛOXwlOMI>6TgwslʽU:.֙Nk˒
_RkRikVeTN]oAb044wPDpo2i7jYq<D$+4H$Z,C���H
$��� A��	"���4"b~QD$+4H$Z,]U���HB1��@#8z͝=6$
G\A"b1D?[}O$IBDb"1���
D���h ��@���$���Јt)"mZr:7H9m��HJu\""simζeA}f	VOd2{{ZlQa<Ճho:S)kZX6=W��HJ)R("vGG7Eb.udow`Z갖6x0^H]uNc(""ZMM}��$:{YKQ\u~8;Uk-sp|/)%Ms6~LO8Ő-}vOcu6g,��Hha߉h94=VzNMJ!K1蜃8	*oN5KgF�@Bs61Z`VJ(ZtI04wd+®:qA~jݒyMzC7u].ÿM[:zӧ[d@`(tb}��GصKjv,Ra#NWk7ݳ)u<ٗewXyMb.us).g.qXK%̮~ۛT(_e9,R k-wevϑ,kfAEc�`\pvp
נD\eMfcvn&
SQ2V)ʵ,%IɖAw)c-IJy^̩5t9S6{-9v>y	o
99"#"bwp{Y�@AI9m2{3Dvn|W1V)']B2NנSä,.`SR*BO1lh9}md2sb.ux_,idD��s
vJ*/fSSs:R;\b16$haeRDON!%[RB/<q6&":W'ϔ9Rj�Jz&C_{8ա_^P.]0deӐo/hB{Ebg[0"=lDgqd;c1/=2{{Hi#*�� a~$RikVg8)eorOL/P>aER
>5}&eؐSniߵMgA*VlXg6ڛ;-K*,K~';HmJY==SfHKaӧGڋ	LG蝀RvG�Ra)Yijgx+a1
<DUwv!b��@R A��	"���4H��aʴG''$
G\A"b&

jhh(,,h��Y���fIDAT�0b��F!yG-_SC$IBDbb<08wQD$+4H$Z,C��� A��	"���4H���,d|����IENDB`�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/pics/show-output2.png�������������������������������������������������������������0000644�0001750�0001750�00000006431�12732165123�017236� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR�����p���dy��IDATxMrdz_++|"fk7\Bu^9..Qۉx9g!K Dp8(T*A~y}}%?~^2"9�)ϵ�!��<@H��!CUU.�7K|%FAw�&&Aw��<@H��!C~H":/FYAN6D=Q1Yo&D-	ڒr|M5Dja@E%^vC$Uar
5Qi"IB=rBRVMod@3]3j\^ڻIY#$'4	sQm]TbvL]wcڿ]k(vD;fH}f7NYVq־E~[zj܋k-)Q֓1YV!wײ<Sq'5vmgnk8B4rz6$QKnGXT&zXje]ҕۼu&W�Xg^%Uco<ײd%EJ=X!trjRNSɪ>W'ީq''-kzգU;!1{+1уuß~Njs'5>C:z:҉3T
oԖJOurl:aG[GW'nXMnqMTb4DnG36"5Dz -Γ8&zr[qws_((P)CD0n~z9{4'.znHE-\MB`zbFBiS3%?t.SUk-aE>\SR(j5>oL\
ϻ<Aϻ6!Ř;Y�~:TUV ŞK!U<UIH&ci%'ቧ!LI7^5Brδc+vD
HKt/<d._Q\jzoABi/29u8lnR9[B1gC7ڠ	� $�x�B!`{"6ϳҏ'ʴ1_X=*WZIW.Vz'7o>`Q<^S[fU	lEL!sh6m6zgl$S-1LJ|;hYDh\aL;rSwKlj;T2	^1dk9͛fcYl9>t%:յt>I'":jkK^x�gcGw3IZN
|bF|Sʺ161LaXu7
v>n[k|oxp)Tܰ;%=a>NXDTEǍ^HC[YHj!ԅ/0,(WKBMnurw6IU[9UoYrj0*9ĤP^pcl7:|3¹~U�:uq713hy|ߦn!_3f>Vo	O^NQ`avފ~x{wt0^dqno6lhvSIzp
�X	� $�xX!$�A󴯟NA8ABE|9w9ns hNA8AkLԥhߧIv<R"JNP^JI
Mԥ8MY6eC""%!YxAIMM<ԉ@DDؗ:ՉMѝ؄k!fJ#V}kt_I
 N.~/le'Jew3DauǷ~p(Ds%kiEY'D$s,I	p]&u'!+|?He
4	ft+nڱIewfYOr'lʲ(^d1u쨓:bTE2./˜DEHM)(+DC�$aߔJQ$u]F&[]jae}wxS8á8}D4tLU.y$DV$RT`&6$ʤGRY6CL\ZQt::/D_$,kH>b*##8"l`FL$U9CBVD2$3~Q&:k{R"	MlV͸)(	Vɐl4,YFúZŇ8\s0ɜ9Jj؄2 藜byP=eHg#鱍;_siGmQ'CdΪ!+2Hu#|^;"{YRU۝U#>ϝpB5KZ.~	3%.9{܁q>)	� $�xX=wXF3<FAn'+)qI˜(k;Όx'_TK$~sNvLBH2x8X\NYvTaFuW+AgFaR/4ƁWbew+e>q؏a*glԥOulOδ.&	,{Hx\F*O\	nB<ǵW
um~򔟭r=MR?}-9sIX2ڄeGV#Ճ�bzdT2׵,"-?wDH2oy{lz!QUvƩԶB'%88:<ѸYs\3:(vaF!`|anLV?3u0e](IQFlY:
NFG{Oz$ f?c%V3`D"%j\]h\T!<e8u2Qh('*z^H!ԉ=4Qٵ.93K
F4mpڼ,�eAJЖBk>v=}9͵w^k]&f]4$uy0x3n&j'mښ:'C\OYBUnwȥT^9K`\,8B	� $�x�!hUwK|oln�t�I<yr�pθ�nB	� $�x�B	� $�x�B	� $�x�BvY\����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/pics/parameters.png���������������������������������������������������������������0000644�0001750�0001750�00000012044�12732165123�016776� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR�����e���}x��IDATxϑ^ڪlrV VVs\7%1
"@kjkʫH@
"Cc~!"E���|?l���<|v���$kPo{$�����8#ٹ���p,~�o	<?��pF`���3T 
iхB=vr-ѳ`>+"HK+׏ܬrQRm޾;=&冒>~}8װRԎNt'j]K.DsJt'
{oDwƢ-#Dy*~߉+WjoK;=t˃CWW~"nD%-(t\PzєaP$d{o]p%$M0UD55QEm*,:e+d閙ݰvo4;\f<VxG٦j\fgf*϶UL&dxf?UD.^/S\Ն~^-$u5db<Z+{-FTˣeci$$w]IpEpKv6RJ
DэFu^,kz]%gvQ;m@Ʌu'a<ߔԦ*0KІ8{Q-u޼	[Vta3)1RJI7T#6#[}
koшm
-<ҙ?:6XkD5A
G:\Qs;ԅ?Z[O Trm-{XMBu.Çx-ҤT?-PrCT=H^t.&>&-k/Su\"n)
J*s4Bu]HWFNRhLB3,,xO3/Xs_pl_Y5\2_E[cOj5PSj+1ԇ~AI\VF=
@u[).dgB^]D03vKN7͚Bҕfq;[\csiYkq篈A!$\Iz'l#*?bQvR_0q)ִ5%ԻX6<3VaW=Ur	KR>쎔(,4ŋ*T㖲գO;:țuHQo:n	")\ǫwuR�KdNy&j)5d0<؛!.eJ.{Rʵ:)pV]5wnB]^_WsqKtK'LYfkv>zIb.6Mt	wo$zr?r.Z%,m+:wtnxcJ.|Ivr	SvjF"-QRhW֕gHur[JWQTw*}ѫPWzKͭ/UaS좲}&?Y7UWh5H?UHr]^)ԏ˲+@hi[Xnuz~fh)>ZJvuֽgWOGr;K>{wK4|wѕfIŹFA4&Ėp5?e5ѽ<ւKE=pfLo7dч<֔frއ~^"dY�
N$ZSeW}5\s֚7eFqJRk[P;i}OR<B=?�����X��8#��pF`��)Xi7կTkWĎ̍vST~Bt[D�VX:t_rCĪJC"Y(z4�`=?rևM?m.+Oo3Ed|*cL?� "0[νۊpSmK9OI5_	{�/lL9LR4JXu2xfh9=ŚNW
zSe9<:8t>%|S��C0w8K#ec=pl+G9D¼*ӯt^8hN=@䅦W5ljH ǣ
/G
l-&R��f_숬fTkq**CAiu<E̪(MPR]n跑+\l'Y
+G3pjʜH­H2s�9!|
0+FFkllڒ-Ob1SŻa?0iPVO8�xyIkIIUhsǩsyٗ3dB�{}KgnXuV6 >(A^;zZՔ+΄ɃBt]T~ƣ��`LzEd5-+QHLur͏Џ(bߢ#K@yS5"
["v\k0"o�87��v�$^���إ�ؗ-3��0�3��gds�?�7��8#ٹ���p,S+>��#���3��g��ScR\Vq^Ŝٜ	qԚ\~stEDuQiiU$]zdAPwU2d1ϳñV}qHڭ%čv%s|:YR*|y=*@t`c졫+?g۸M[Aors7뗈aP$dFWQؼ*>e8:ck@)tW^YN&-3
aHW%w2V!<>cs_0l2X3MdW
ے̚Lٶ߃6Z[~`SZE2)8?Luj#umH["{h:o9 M^kIEw,9 %Q|]Q]6T{�b~jp1:޺@{nGəƹ]o"s[-Pra݉h7.)Ja$La!A.^vKݠ7iBy#]ELJdcRM)7Hğ
VDD[4m$e[C^9zǯM c׍QKTs9@pEePr j;Zl>Y +Sʵmmcq[7	ڻp5*hHNR@
QUV yj妺܇pJ�HNs4(uӐ2vsuy#]iܺO:QJ1	u6v;'*?|Jbe}	eHnr],Wo?%@eJLt\ǸRw%FsY֮zKzۗ7\%=RlwΟyuϤ:-:4k
KW<n)sΥk~dŝ"ʇ|Ds%MσjL
\>Eȣ_?JE|yWYX֔Pb;KXeJ^YTN%,IƊ;RR[./<Si;[V"uǟPyN}"Sx M2AT4xN
`|)$[ִ5%ԻF6f{3ĥL%uXTV'ΪKC2-0Yj.nn)䂑)̹.0'RO:SEކR	~.8YM3D/CBN%S뼄me[".Ӟ1o�<WɅu7)r.W.aaN(Sd2J
MʺNnK)~SOtϟ"_|³|>U(JtK*CIа)evQيZԟlᛪ+jm4`KUsK$U}eu$.NWGe i^7H{V
=?34-|c%:tލ3˂+WwHEn'#RuĥQ=˻mBkh
Jw3$\#IF{MbK2sYk%OƞKKlz3&yЁOJWkJg39NyC?~/ynf
,ZvR^~ur])+.@9kM웲_Jz8%I-Uʾjq){!Ξ���K��?��X��8#��pF`�Xu�CǗv+2`ý9K�^u	:ߒ`~Oڀ9Yڊ?oCԠ~Sn`x{~䈫. bt'Ec=kLdIr<2&,S2ܻ8lyc}�ÓF̚:p-;-�>ϔc$.M#fV/ZNf/f-qoe6nRf'4RzPeH,-@	#BIR)UpB�?u|h~#ղ8U|[>6yU_'輢qМ8NɿG0ە!}:r'U:2Hps7|$.$on�މ9_Oʺ|]JYX	ܐ PBO#R2<˟q%�C64A's~$l�oϏjswmYi4X5Zhז$hyZZ^P}.EKiiW[1c$)<(%>�%3
:+@JMrýDߒ+,EǮ$I!Q}�x7[<s K+BJ{OQ0z*U$%{oGtQ|}�x7
o4MՑ97	rgF!1m 5?6_YqT%LРQ6>,y_YxU>rJ"Edc̾=�_^0r�`pQpp&`Q1p�m
?��X��8#ߋW��x]!��x~��d��L^_����g��4.W:����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/pics/show-output1.png�������������������������������������������������������������0000644�0001750�0001750�00000005757�12732165123�017247� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR�����o���ns��IDATx?oƟKHi"5ꮸZ.'H\`Q;mqRԻU`K!<JO#>K>?~L&�;#4trrPPPPPP PW
g0x-�B\\+b`
,K`
Ov̞J6ƒ㧊^<4Q%*=Mox0*Xɒc\{nRQЛC(Ն!yNh&0fq+n� ..LnBk_]I�bljI=f&U@hFWR_OH-h^#I%dFySjye¹2J`9q2HdUJV
U�J	SϼNS	a3:c#V?a,L60U:MuRVE)>:jmT=w21Z�TAXQ˫Ѽd2)+d2WL1/H~UB,:GvɒUŏ 5BѾ*!c'p6<hAbCUbCUbCUb3cgߌIσH/ġ0m%>{C{8xbjI
"1Ō]aywx<!~(Ozn"_k_mj\[QS}POvLKmы\F^ԧSKv]*(̤Y'f-KBQ}5P{&xBu3}$<{!	wI5ʹ[d7y�V"3q~nhOQ:ɢqB0rRfj0[1jL4>WPRX6卫Fn7BB5NmK]cT[=y&M)#3]QM")̸[j1B9μrBn}OWꐩ,Ly*Q!^RꝚi(~bhqQ<Pr~�O?�T]V^�Cz񞐃|:U0Y($JӐLp=}*MZ4nk#]\JO's:R](nEz;?M!aOgo)k<3=7J*kP<Gэ_2(OŧhH4IE?8kY㙞N&P/̸G;/ӊ]ҏ޾pQOӥ>uv�2Ue>+{~2,IePFQ-
R+86L/ܩf@G1c߅2X�ym/7=mg64�.}
i2[!
Yא?W#&|2n1gR_gZF15BhV^l}cQ8)HB$͋|jܗ,{	ũlŬ9NsPR=h|Ufz-(B-(Bl
Bl
Bl
Bl
Bl<ffOiLD>+mZuQD/ Cx
:R}ŧfsq+ !-((gb>J
gm׋$rиBIN=Ӎd:O^Q7,Ū>eE{Ӗ\ř8_
02¨m+YE3>\fYKk=vUzRovbV.mǛTJL"+`yȬ}mz%U>`%O
)AE,0uwSftlɘٕP9Y2޻aD6M<7,PTu'~0ʹ?QM4"zpLQLiFN	#Q
;9rHL3lGϳZci
-œK
Yrn-U3
6Bu @ ߶}oPVn�n(7֬c͡i1Mv#.sSN 3᱿BΐvαaV-x|u~9(uڹQ")!9ۜ`U)pp!6\H
UA
UA
UA
UA
UA
UA
UA:�t䡮c�QH̫<CRETCZTwylDl0>Tt`�KWy7I^*"yk"*t:	}pD[ؤyA
*R=]|].iʗʞ
.(WE}ۛXW!H8blys]b7U%H2늦 Q9s֗/_{��W:Ftl&UVmO{$U?$]t۟6h~ۦ݇vm?|b(}#xWoqU-_^ݯo
QEڟweU51۞)HNٰ^sDe~W?nW$i7K$i�tČ>:n&2J\1ϮHPá#2UI
׫:DP%PAw/o�@o6ZI4I"nH"88"`FhJ,¯paazTQ	xJ8[eiA>M�ucsVADbjsA&a]'DD4Ѿ.@ftRDB7$՛:wa暌TzJ5`bU!J7݄vNWx&
u`&.]&"Wo{7YE(p:A13AG=HYBU!6T!6T!6T!6T!6T!6T!6T!6T!6T!6T!6T!6LGэ6A����IENDB`�����������������testng-6.9.12/doc/documentation-main.html�����������������������������������������������������������0000644�0001750�0001750�00000304132�12732165123�017652� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
    <head>
        <title>TestNG</title>

        <link rel="stylesheet" href="testng.css" type="text/css" />
        <link type="text/css" rel="stylesheet" href="http://beust.com/beust.css"  />
        <script type="text/javascript" src="banner.js"></script>

      <script type="text/javascript" src="http://beust.com/scripts/shCore.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushJava.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushXml.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushBash.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushPlain.js"></script>
      <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shCore.css"/>
      <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shThemeCedric.css"/>
      <script type="text/javascript">
        SyntaxHighlighter.config.clipboardSwf = 'scripts/clipboard.swf';
        SyntaxHighlighter.defaults['gutter'] = false;
        SyntaxHighlighter.all();
      </script>
      <script type="text/javascript" src="http://beust.com/toc.js"></script>

        <style type="text/css">
            /* Set the command-line table option column width. */
            #command-line colgroup.option {
                 width: 7em;
            }
        </style>
    </head>
<body onLoad="generateToc();">

<script type="text/javascript">
    displayMenu("documentation-main.html")
</script>

<h2 align="center">TestNG</h2>

<!-- --------------------------

<table class="float-right">
  <tr>
    <td>
<script type="text/javascript"><!--
google_ad_client = "pub-1467757024002850";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_channel ="5560744946";
//-->
<!-- 

</script>

<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>      
    </td>
  </tr>
</table>

------------------------------- -->

<!-------------------------------------
  TOC
  ------------------------------------>

<h3>Table of Contents</h3>

<div id="table-of-contents">
</div>


<!-------------------------------------
  INTRODUCTION
  ------------------------------------>
<h3><a class="section" name="introduction">Introduction</a></h3>

TestNG is a testing framework designed to simplify a broad range of testing needs, from unit testing (testing a class in isolation of the others) to integration testing (testing entire systems made of several classes, several packages and even several external frameworks, such as application servers).

<p>

Writing a test is typically a three-step process:

<ul>
<li>Write the business logic of your test and insert <a href="#annotations">TestNG annotations</a> in your code.
</li>
<li>Add the information about your test (e.g. the class name, the groups you wish to run, etc...) in a <tt><a href="#testng-xml">testng.xml</a></tt> file or in build.xml.
</li>
<li><a href="ant.html">Run TestNG</a>.
</li>
</ul>
You can find a quick example on the <a href="index.html">Welcome page</a>.
<p>
The concepts used in this documentation are as follows:

<ul>
<li>
A suite is represented by one XML file.  It can contain one or more tests and is defined by the <tt>&lt;suite&gt;</tt> tag.
</li>
<li>
A test is represented by <tt>&lt;test&gt;</tt> and can contain one or more TestNG classes.
</li>
<li>
A TestNG class is a Java class that contains at least one TestNG annotation.  It is represented by the <tt>&lt;class&gt;</tt> tag and can contain one or more test methods.
</li>
<li>
A test method is a Java method annotated by <tt>@Test</tt> in your source.
</li></ul>A TestNG test can be configured by <tt>@BeforeXXX and @AfterXXX </tt>annotations which allows to perform some Java logic before and after a certain point, these points being either of the items listed above.<p>
The rest of this manual will explain the following:
<p>
<ul>
<li>A list of all the annotations with a brief explanation.  This will give you an idea of the various functionalities offered by TestNG but you will probably want to consult the section dedicated to each of these annotations to learn the details.
</li>
<li>A description of the testng.xml file, its syntax and what you can specify in it.
</li>
<li>A detailed list of the various features and how to use them with a combination of annotations and testng.xml.
</li>
</ul>


<!-------------------------------------
  ANNOTATIONS
  ------------------------------------>

<h3><a class="section" name="annotations">Annotations</a></h3>

Here is a quick overview of the annotations available in TestNG along with their attributes.

<p>

<table>

<tr>
<td colspan="2"><b><tt>@BeforeSuite<br>@AfterSuite<br>@BeforeTest<br>@AfterTest<br>@BeforeGroups<br>@AfterGroups<br>@BeforeClass<br>@AfterClass<br>@BeforeMethod<br>@AfterMethod</tt></b></td><td><b>Configuration information for a TestNG class:</b>

<br>

<br><b>@BeforeSuite: </b>The annotated method will be run before all tests in this suite have run.

<br><b>@AfterSuite: </b> The annotated method will be run after all tests in this suite have run. 

<br><b>@BeforeTest</b>: The annotated method will be run before any test method belonging to the classes inside the &lt;test&gt; tag is run.

<br><b>@AfterTest</b>: The annotated method will be run after all the test methods belonging to the classes inside the &lt;test&gt; tag have run.

<br><b>@BeforeGroups</b>:   The list of groups that this configuration method will run before. This method is guaranteed to run shortly before the first test method that belongs to any of these groups is invoked.

<br><b>@AfterGroups</b>:   The list of groups that this configuration method will run after.  This method is guaranteed to run shortly after the last test method that belongs to any of these groups is invoked.

<br><b>@BeforeClass</b>: The annotated method will be run before the first test method in the current class is invoked.

<br><b>@AfterClass</b>: The annotated method will be run after all the test methods in the current class have been run. 

<br><b>@BeforeMethod</b>: The annotated method will be run before each test method.

<br><b>@AfterMethod</b>: The annotated method will be run after each test method.

</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>alwaysRun</tt>
</td>
<td>
   For before methods (beforeSuite, beforeTest, beforeTestClass and
   beforeTestMethod, but not beforeGroups):
   If set to true, this configuration method will be run
   regardless of what groups it belongs to. 
   <br>
   For after methods (afterSuite, afterClass, ...): 
   If set to true, this configuration method will be run
   even if one or more methods invoked previously failed or
   was skipped.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>dependsOnGroups</tt>
</td>
<td>
          The list of groups this method depends on.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>dependsOnMethods</tt>
</td>
<td>
          The list of methods this method depends on.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>enabled</tt>
</td>
<td>
          Whether methods on this class/method are enabled.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>groups</tt>
</td>
<td>
          The list of groups this class/method belongs to.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>inheritGroups</tt>
</td>
<td>
          If true, this method will belong to groups specified in the @Test annotation at the class level.
</td>
</tr>

<tr class="separator">
<td colspan="3">&nbsp;</td>
</tr>

<tr>
<td colspan="2"><tt><b>@DataProvider</b></tt></td><td><b>Marks a method as supplying data for a test method. The annotated method must return an Object[][] where each Object[] can be assigned the parameter list of the test method. The @Test method that wants to receive data from this DataProvider needs to use a dataProvider name equals to the name of this annotation.</b></td></tr><tr>
<td>
</td>
<td>
<tt>name</tt>
</td>
<td>
The name of this data provider. If it's not supplied, the name of this data provider will automatically be set to the name of the method.
</td>
</tr>
<tr>
<td>
</td>
<td>
<tt>parallel</tt>
</td>
<td>
If set to true, tests generated using this data provider are run in parallel. Default value is false.
</td>
</tr>
<tr>
<td colspan="3">&nbsp;</td>
</tr>

<tr>
<td colspan="2"><b><tt>@Factory</tt></b></td><td><b> Marks a method as a factory that returns objects that will be used by TestNG as Test classes.  The method must return Object[].</b></td></tr><tr>
<td colspan="3">&nbsp;</td>
</tr>

<tr>
<td colspan="2"><b><tt>@Listeners</tt></b></td><td><b>Defines listeners on a test class.</b></td></tr>
<tr>
  <td></td>
  <td>
    <tt>value</tt>
  </td>
  <td>
    An array of classes that extend <tt>org.testng.ITestNGListener</tt>.
  </td>
</tr>

<tr>
<td colspan="3">&nbsp;</td>
</tr>

<td colspan="2"><b><tt>@Parameters</tt></b></td><td><b>Describes how to pass parameters to a @Test method.</b></td></tr><tr>
<td>
</td>
<td>
<tt>value</tt>
</td>
<td>
The list of variables used to fill the parameters of this method.
</td>
</tr>

<tr>
<td colspan="3">&nbsp;</td>
</tr>

<tr>
<td colspan="2"><b>@Test</b></td><td><b>Marks a class or a method as part of the test.</b></td></tr><tr>
<td>
</td>
<td>
<tt>alwaysRun</tt>
</td>
<td>
          If set to true, this test method will always be run even if it depends on a method that failed.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>dataProvider</tt>
</td>
<td>
The name of the data provider for this test method.
</td>
</tr>


<tr>
<td>
</td>
<td>
<tt>dataProviderClass</tt>
</td>
<td>
The class where to look for the data provider.  If not specified, the data provider will be looked on the class of the current test method or one of its base classes. If this attribute is specified, the data provider method needs to be static on the specified class.  
</td>
</tr>






<tr>
<td>
</td>
<td>
<tt>dependsOnGroups</tt>
</td>
<td>
          The list of groups this method depends on.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>dependsOnMethods</tt>
</td>
<td>
          The list of methods this method depends on.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>description</tt>
</td>
<td>
          The description for this method.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>enabled</tt>
</td>
<td>
          Whether methods on this class/method are enabled.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>expectedExceptions</tt>
</td>
<td>
           The list of exceptions that a test method is expected to throw.  If no exception or a different than one on this list is thrown, this test will be marked a failure.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>groups</tt>
</td>
<td>
          The list of groups this class/method belongs to.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>invocationCount</tt>
</td>
<td>
          The number of times this method should be invoked.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>invocationTimeOut</tt>
</td>
<td>
          The maximum number of milliseconds this test should take for the cumulated time of all the invocationcounts.  This attribute will be ignored if invocationCount is not specified.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>priority</tt>
</td>
<td>
          The priority for this test method. Lower priorities will be scheduled first.
</td>
</tr>

<tr>
<td>
</td>
<td>

<tt>successPercentage</tt>
</td>
<td>
          The percentage of success expected from this method
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>singleThreaded</tt>
</td>
<td>
             If set to true, all the methods on this test class are guaranteed to run in the same thread, even if the tests are currently being run with parallel="methods". This attribute can only be used at the class level and it will be ignored if used at the method level. Note: this attribute used to be called <tt>sequential</tt> (now deprecated).

</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>timeOut</tt>
</td>
<td>
          The maximum number of milliseconds this test should take.
</td>
</tr>

<tr>
<td>
</td>
<td>
<tt>threadPoolSize</tt>
</td>
<td>
             The size of the thread pool for this method.  
The method will be invoked from multiple threads as specified by 
invocationCount. <br>Note:  this attribute is ignored if invocationCount is not specified

</td>
</tr>

</table>




</pre>
<!-------------------------------------
  TESTNG.XML
  ------------------------------------>
<h3><a class="section" name="testng-xml">testng.xml</a></h3>

<p>You can invoke TestNG in several different ways:</p><ul>
	<li>With a <tt>testng.xml</tt> file</li><li><a href="http://testng.org/doc/ant.html">With ant</a></li><li>From the command line</li></ul><p>This section describes the format of <tt>testng.xml</tt> (you will find documentation 
on ant and the command line below).</p><p>The current DTD for <tt>testng.xml</tt> can be found on the main Web site:&nbsp;
<a href="http://testng.org/testng-1.0.dtd">http://testng.org/testng-1.0.dtd</a> 
(for your convenience, you might prefer to browse the
<a href="http://testng.org/dtd">HTML version</a>).</p>

Here is an example <tt>testng.xml</tt> file:

<p>
<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" &gt;
 
&lt;suite name="Suite1" verbose="1" &gt;
  &lt;test name="Nopackage" &gt;
    &lt;classes&gt;
       &lt;class name="NoPackageTest" /&gt;
    &lt;/classes&gt;
  &lt;/test&gt;

  &lt;test name="Regression1"&gt;
    &lt;classes&gt;
      &lt;class name="test.sample.ParameterSample"/&gt;
      &lt;class name="test.sample.ParameterTest"/&gt;
    &lt;/classes&gt;
  &lt;/test&gt;
&lt;/suite&gt;
</pre>

You can specify package names instead of class names:

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml; highlight: [5,6,7]">
&lt;!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" &gt;

&lt;suite name="Suite1" verbose="1" &gt;
  &lt;test name="Regression1"   &gt;
    &lt;packages&gt;
      &lt;package name="test.sample" /&gt;
   &lt;/packages&gt;
 &lt;/test&gt;
&lt;/suite&gt;
</pre>


<p>In this example, TestNG will look at all the classes in the package 
	<tt>test.sample</tt> and will retain only classes that have TestNG annotations.</p>

You can also specify groups and methods to be included and excluded:

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="Regression1"&gt;
  &lt;groups&gt;
    &lt;run&gt;
      &lt;exclude name="brokenTests"  /&gt;
      &lt;include name="checkinTests"  /&gt;
    &lt;/run&gt;
  &lt;/groups&gt;
 
  &lt;classes&gt;
    &lt;class name="test.IndividualMethodsTest"&gt;
      &lt;methods&gt;
        &lt;include name="testMethod" /&gt;
      &lt;/methods&gt;
    &lt;/class&gt;
  &lt;/classes&gt;
&lt;/test&gt;
</pre>

<p>You can also define new groups inside <tt>testng.xml</tt> and specify additional details in attributes, such as whether to run the tests in parallel, how many threads to use, whether you are running JUnit tests, etc...&nbsp;
<p>

By default, TestNG will run your tests in the order they are found in the XML
file. If you want the classes and methods listed in this file to be
run in an unpredictible order, set the <tt>preserve-order</tt>
attribute to <tt>false</tt>

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="Regression1" preserve-order="false"&gt;
  &lt;classes&gt;

    &lt;class name="test.Test1"&gt;
      &lt;methods&gt;
        &lt;include name="m1" /&gt;
        &lt;include name="m2" /&gt;
      &lt;/methods&gt;
    &lt;/class&gt;

    &lt;class name="test.Test2" /&gt;

  &lt;/classes&gt;
&lt;/test&gt;
</pre>

<p>

Please see the DTD for a complete list of the features, or read on.</p>

<!-------------------------------------
  RUNNING TESTNG
  ------------------------------------>

<h3><a class="section" name="running-testng">Running TestNG</a></h3>

TestNG can be invoked in different ways:

<ul>
<li>Command line
</li>
<li><a href="ant.html">ant</a>
</li>
<li><a href="eclipse.html">Eclipse</a>
</li>
<li><a href="idea.html">IntelliJ's IDEA</a>
</li>
</ul>

This section only explains how to invoke TestNG from the command line.  Please click on one of the links above if you are interested in one of the other ways.
<p>
Assuming that you have TestNG in your class path, the simplest way to invoke TestNG is as follows:

<pre class="brush: text">
java org.testng.TestNG testng1.xml [testng2.xml testng3.xml ...]
</pre>

You need to specify at least one XML file describing the TestNG suite you are trying to run.  Additionally, the following command-line switches are available:

</p>

<table id="command-line">
    <caption>Command Line Parameters</caption><colgroup class="option"/>
    <colgroup class="argument"/>
    <colgroup class="documentation"/>
    <thead>

        <tr>
            <th>Option</th>
    	<th>Argument</th>
    	<th>Documentation</th>
        </tr>
    </thead>

    <tbody>
        <tr>
            <td>-configfailurepolicy</td>
	    <td><tt>skip</tt>|<tt>continue</tt></td>
	    <td>Whether TestNG should <tt>continue</tt> to execute the remaining tests in the suite or <tt>skip</tt> them if
            an @Before* method fails.  Default behavior is <tt>skip</tt>.</td>
        </tr>

        <tr>
            <td>-d</td>
	    <td>A directory</td>
	    <td>The directory where the reports will be generated (defaults to <tt>test-output</tt>).</td>
        </tr>

        <tr>
            <td>-dataproviderthreadcount</td>
	    <td>The default number of threads to use for data
            providers when running tests in parallel.</td>
	    <td>This sets the default maximum number of threads to use
            for data providers when running tests in parallel. It will only take effect if the parallel mode has been selected (for example, with the -parallel option). This can be overridden in the suite definition.</td>
        </tr>

	<tr>
            <td>-excludegroups</td>
	    <td>A comma-separated list of groups.</td><td>The list of groups you want to be excluded from this run.</td>
        </tr>
	  
        <tr>
            <td>-groups</td>
	    <td>A comma-separated list of groups.</td>
	    <td>The list of groups you want to run (e.g. <tt>"windows,linux,regression"</tt>).</td>
	</tr>

        <tr>
            <td>-listener</td>
	    <td>A comma-separated list of Java classes that can be found on your classpath.</td>
	    <td>Lets you specify your own test listeners.  The classes need to implement <a href="../javadocs/org/testng/ITestListener.html"> <tt>org.testng.ITestListener</tt></a></td>
        </tr>

	<tr>
            <td>-methods</td>
	    <td>A comma separated list of fully qualified class name and method. For example <tt>com.example.Foo.f1,com.example.Bar.f2</tt>.</td>
	    <td>Lets you specify individual methods to run.</tt></a></td>
        </tr>

        <tr>
            <td>-methodselectors</td>
	    <td>A comma-separated list of Java classes and method
            priorities that define method selectors.</td>
	    <td>Lets you specify method selectors on the command
            line. For example: <tt>com.example.Selector1:3,com.example.Selector2:2</tt></td>
        </tr>

	<tr>
            <td>-parallel</td>
	    <td>methods|tests|classes</td>
	    <td>If specified, sets the default mechanism used to determine how to use parallel threads when running tests. If not set, default mechanism is not to use parallel threads at all. This can be overridden in the suite definition.</td>
        </tr>

        <tr>
            <td>-reporter</td>
	    <td>The extended configuration for a custom report listener.</td>
	    <td>Similar to the <tt>-listener</tt> option, except that it allows the configuration of JavaBeans-style properties on the reporter instance.
	      <br>
            Example: <tt>-reporter com.test.MyReporter:methodFilter=*insert*,enableFiltering=true</tt>
	      <br>
            You can have as many occurences of this option, one for each reporter that needs to be added.</td>
        </tr>

        <tr>
            <td>-sourcedir</td>
    	    <td>A semi-colon separated list of directories.</td>
            <td>The directories where your javadoc annotated test sources are. This option is only necessary if you are using javadoc type annotations. (e.g. <tt>"src/test"</tt> or <tt>"src/test/org/testng/eclipse-plugin;src/test/org/testng/testng"</tt>).</td>
        </tr>

       <tr>
           <td>-suitename</td>
	   <td>The default name to use for a test suite.</td>
	   <td>This specifies the suite name for a test suite defined on the command line. This option is ignored if the suite.xml file or the source code specifies a different suite name.  It is possible to create a suite name with spaces in it if you surround it with double-quotes "like this".</td>
        </tr>
        
        <tr>
            <td>-testclass</td>
	    <td>A comma-separated list of classes that can be found in your classpath.</td><td>A list of class files separated by commas (e.g. <tt>"org.foo.Test1,org.foo.test2"</tt>).</td>
	</tr>

         <tr>
            <td>-testjar</td>
	    <td>A jar file.</td>
	    <td>Specifies a jar file that contains test classes.  If a <tt>testng.xml</tt> file is found at the root of that jar file, it will be used, otherwise, all the test classes found in this jar file will be considered test classes.</td>
        </tr>

        <tr>
            <td>-testname</td>
	    <td>The default name to use for a test.</td>
	    <td>This specifies the name for a test defined on the command line. This option is ignored if the suite.xml file or the source code specifies a different test name. It is possible to create a test name with spaces in it if you surround it with double-quotes "like this".</td>
        </tr>

        <tr>
            <td>-testnames</td>
	    <td>A comma separated list of test names.</td>
	    <td>Only tests defined in a &lt;test&gt; tag matching one of these names will be run.</td>
        </tr>

        <tr>
            <td>-testrunfactory</td>
	    <td>A Java classes that can be found on your classpath.</td>
	    <td>Lets you specify your own test runners.  The class needs to implement <a href="../javadocs/org/testng/ITestRunnerFactory.html"> <tt>org.testng.ITestRunnerFactory</tt></a>.</td>
        </tr>

        <tr>
            <td>-threadcount</td>
	    <td>The default number of threads to use when running tests in parallel.</td>
	    <td>This sets the default maximum number of threads to use for running tests in parallel. It will only take effect if the parallel mode has been selected (for example, with the -parallel option). This can be overridden in the suite definition.</td>
        </tr>

	<tr>
            <td>-xmlpathinjar</td>
	    <td>The path of the XML file inside the jar file.</td>
	    <td>This attribute should contain the path to a valid XML file inside the test jar (e.g. <tt>"resources/testng.xml"</tt>). The default is <tt>"testng.xml"</tt>, which means a file called "<tt>testng.xml</tt>" at the root of the jar file. This option will be ignored unless <tt>-testjar</tt> is specified.</td>
        </tr>

      </tbody>
</table>

<p>

This documentation can be obtained by invoking TestNG without any arguments.

<p>

You can also put the command line switches in a text file, say <tt>c:\command.txt</tt>, and tell TestNG to use that file to retrieve its parameters:

<pre class="brush: text">
  C:> more c:\command.txt
  -d test-output testng.xml
  C:> java org.testng.TestNG @c:\command.txt
</pre>

<p>

Additionally, TestNG can be passed properties on the command line of the Java Virtual Machine, for example

<pre class="brush: text">
java -Dtestng.test.classpath="c:/build;c:/java/classes;" org.testng.TestNG testng.xml
</pre>

Here are the properties that TestNG understands:

<table id="system=properties">
    <caption>System properties</caption>
    <colgroup class="option"/>
    <colgroup class="type"/>
    <colgroup class="documentation"/>
    <thead>
      <tr><th>Property</th>
      <th>Type</th>
      <th>Documentation</th></tr>
    </thead>

    <tr>
    <td>testng.test.classpath</td>
    <td>A semi-colon separated series of directories that contain your test classes.</td>
    <td>If this property is set, TestNG will use it to look for your test classes instead of the class path.  This is convenient if you are using the <tt>package</tt> tag in your XML file and you have a lot of classes in your classpath, most of them not being test classes.
    </tr>
</table>

<br>

<b>Example:</b>

<pre class="brush: text">
java org.testng.TestNG -groups windows,linux -testclass org.test.MyTest
</pre>

The <a href="ant.html">ant task</a> and <a href="#testng-xml">testng.xml</a> allow you to launch TestNG with more parameters (methods to include, specifying parameters, etc...), so you should consider using the command line only when you are trying to learn about TestNG and you want to get up and running quickly.

<p>

<em>Important</em>: The command line flags that specify what tests should be run will be ignored if you also specify a <tt>testng.xml</tt> file, with the exception of <tt>-includedgroups</tt> and <tt>-excludedgroups</tt>, which will override all the group inclusions/exclusions found in <tt>testng.xml</tt>.

<!-------------------------------------
  METHODS
  ------------------------------------>

<h3><a class="section" name="methods">Test methods, Test classes and Test groups</a></h3>

<h4><a class="section" indent=".." name="test-methods">Test methods</a></h4>

Test methods are annotated with <tt>@Test</tt>. Methods annotated with <tt>@Test</tt> that happen to return a value will be ignored, unless you set <tt>allow-return-values</tt> to <tt>true</tt> in your <tt>testng.xml</tt>:

<pre class="brush: xml">
&lt;suite allow-return-values="true"&gt;

or

&lt;test allow-return-values="true"&gt;
</pre>


<h4><a class="section" indent=".." name="test-groups">Test groups</a></h4>

<p>

TestNG allows you to perform sophisticated groupings of test methods. Not 
only can you declare that methods belong to groups, but you can also specify 
groups that contain other groups. Then TestNG can be invoked and asked to 
include a certain set of groups (or regular expressions) while excluding another 
set.&nbsp; This gives you maximum flexibility in how you partition your tests 
and doesn't require you to recompile anything if you want to run two different 
sets of tests back to back.</p>

<p>
Groups are specified in your <tt>testng.xml</tt> file and can be found either under the <tt>&lt;test&gt;</tt> or <tt>&lt;suite&gt;</tt> tag. Groups specified in the <tt>&lt;suite&gt;</tt> tag apply to all the <tt>&lt;test&gt;</tt> tags underneath. Note that groups are accumulative in these tags: if you specify group "a" in <tt>&lt;suite&gt;</tt> and "b" in <tt>&lt;test&gt;</tt>, then both "a" and "b" will be included.

<p>

<p>For example, it is quite common to have at least two categories of tests</p><ul>
  <li>Check-in tests.&nbsp; These tests should be run before you submit new 
	code.&nbsp; They should typically be fast and just make sure no basic 
	functionality was broken.<br>
&nbsp;</li>
  <li>Functional tests.&nbsp; These tests should cover all the functionalities 
	of your software and be run at least once a day, although ideally you would 
	want to run them continuously.</li></ul>


	Typically, check-in tests are a subset of functional tests.&nbsp; TestNG 
allows you to specify this in a very intuitive way with test groups.&nbsp; For 
example, you could structure your test by saying that your entire test class 
belongs to the &quot;functest&quot; group, and additionally that a couple of methods 
belong to the group &quot;checkintest&quot;:

<h3 class="sourcetitle">Test1.java</h3>
<pre class="brush: java">
public class Test1 {
  @Test(groups = { "functest", "checkintest" })
  public void testMethod1() {
  }

  @Test(groups = {"functest", "checkintest"} )
  public void testMethod2() {
  }

  @Test(groups = { "functest" })
  public void testMethod3() {
  }
}
</pre>

Invoking TestNG with
	<br>

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="Test1"&gt;
  &lt;groups&gt;
    &lt;run&gt;
      &lt;include name="functest"/&gt;
    &lt;/run&gt;
  &lt;/groups&gt;
  &lt;classes&gt;
    &lt;class name="example1.Test1"/&gt;
  &lt;/classes&gt;
&lt;/test&gt;
</pre>

<p>will run all the test methods in that classes, while invoking it with <tt>checkintest</tt> will only run 
<tt>testMethod1()</tt> and <tt>testMethod2()</tt>.</p>


Here is another example, using regular expressions this time.&nbsp; Assume 
that some of your test methods should not be run on Linux, your test would look 
like:

<h3 class="sourcetitle">Test1.java</h3>
<pre class="brush: java">
@Test
public class Test1 {
  @Test(groups = { "windows.checkintest" }) 
  public void testWindowsOnly() {
  }

  @Test(groups = {"linux.checkintest"} )
  public void testLinuxOnly() {
  }

  @Test(groups = { "windows.functest" )
  public void testWindowsToo() {
  }
}
</pre>


You could use the following testng.xml to launch only the Windows methods:

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml; highlight: [4,9]">
&lt;test name="Test1"&gt;
  &lt;groups&gt;
    &lt;run&gt;
      &lt;include name="windows.*"/&gt;
    &lt;/run&gt;
  &lt;/groups&gt;

  &lt;classes&gt;
    &lt;class name="example1.Test1"/&gt;
  &lt;/classes&gt;
&lt;/test&gt;
</pre>

<blockquote>
<em>Note:  TestNG uses <a href="http://en.wikipedia.org/wiki/Regular_expression">regular expressions</a>, and not <a href="http://en.wikipedia.org/wiki/Wildmat">wildmats</a>.  Be aware of the difference (for example, "anything" is matched by ".*" -- dot star -- and not "*").</em>
</blockquote>

<h4><a name="method-groups">Method groups</a></h4>

You can also exclude or include individual methods:

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="Test1"&gt;
  &lt;classes&gt;
    &lt;class name="example1.Test1"&gt;
      &lt;methods&gt;
        &lt;include name=".*enabledTestMethod.*"/&gt;
        &lt;exclude name=".*brokenTestMethod.*"/&gt;
      &lt;/methods&gt;
     &lt;/class&gt;
  &lt;/classes&gt;
&lt;/test&gt;
</pre>

This can come in handy to deactivate a single method without having to recompile 
anything, but I don't recommend using this technique too much since it makes 
your testing framework likely to break if you start refactoring your Java code 
(the regular expressions used in the tags might not match your methods any 
more).


<h4><a class="section" indent=".." name="groups-of-groups">Groups of groups</a></h4>

Groups can also include other groups.&nbsp;These groups are called &quot;MetaGroups&quot;.&nbsp; 
For example, you might want to define a group &quot;all&quot; that includes &quot;checkintest&quot; 
and &quot;functest&quot;.&nbsp; &quot;functest&quot; itself will contain the groups &quot;windows&quot; and 
&quot;linux&quot; while &quot;checkintest will only contain &quot;windows&quot;.&nbsp; Here is how you 
would define this in your property file:


<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="Regression1"&gt;
  &lt;groups&gt;
    &lt;define name="functest"&gt;
      &lt;include name="windows"/&gt;
      &lt;include name="linux"/&gt;
    &lt;/define&gt;
 
    &lt;define name="all"&gt;
      &lt;include name="functest"/&gt;
      &lt;include name="checkintest"/&gt;
    &lt;/define&gt;
 
    &lt;run&gt;
      &lt;include name="all"/&gt;
    &lt;/run&gt;
  &lt;/groups&gt;
 
  &lt;classes&gt;
    &lt;class name="test.sample.Test1"/&gt;
  &lt;/classes&gt;
&lt;/test&gt;
</pre>

</p><!-------------------------------------
  EXCLUSION
  ------------------------------------>

<h4><a class="section" indent=".." name="exclusions">Exclusion groups</a></h4>

<p>TestNG allows you to include groups as well as exclude them.</p>


For example, it is quite usual to have tests that temporarily break because 
of a recent change, and you don't have time to fix the breakage yet.&nbsp; 4
However, you do want to have clean runs of your functional tests, so you need to 
deactivate these tests but keep in mind they will need to be reactivated.</p><p>A simple way to solve this problem is to create a group called &quot;broken&quot; and 
make these test methods belong to it.&nbsp; For example, in the above example, I 
know that testMethod2() is now broken so I want to disable it:


<h3 class="sourcetitle">Java</h3>
<pre class="brush: java">
@Test(groups = {"checkintest", "broken"} )
public void testMethod2() {
}
</pre>

All I need to do now is to exclude this group from the run:

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml; highlight: 5">
&lt;test name="Simple example"&gt;
  &lt;groups&gt;
    &lt;run&gt;
      &lt;include name="checkintest"/&gt;
      &lt;exclude name="broken"/&gt;
    &lt;/run&gt;
  &lt;/groups&gt;
 
  &lt;classes&gt;
    &lt;class name="example1.Test1"/&gt;
  &lt;/classes&gt;
&lt;/test&gt;
</pre>

<p>This way, I will get a clean test run while keeping track of what tests are 
broken and need to be fixed later.</p>

<blockquote>
	<p><i>Note:&nbsp; you can also disable tests on an individual basis by using the 
&quot;enabled&quot; property available on both @Test and @Before/After
	annotations.</i></p>
</blockquote>


<!-------------------------------------
  PARTIAL GROUPS
  ------------------------------------>

<h4><a class="section" indent=".." name="partial-groups">Partial groups</a></h4>

You can define  groups at the class level and then add groups at the method level:

<h3 class="sourcetitle">All.java</h3>
<pre class="brush: java">
@Test(groups = { "checkin-test" })
public class All {

  @Test(groups = { "func-test" )
  public void method1() { ... }

  public void method2() { ... }
}
</pre>

In this class, method2() is part of the group &quot;checkin-test&quot;, which is defined 
at the class level, while method1() belongs to both &quot;checkin-test&quot; and 
&quot;func-test&quot;.

<!-------------------------------------
  PARAMETERS
  ------------------------------------>

<h4><a class="section" indent=".." name="parameters">Parameters</a></h4>

<p>


Test methods don't have to be parameterless.&nbsp; You can use an arbitrary 
number of parameters on each of your test method, and you instruct TestNG to 
pass you the correct parameters with the <tt>@Parameters</tt> annotation.</p><p>


There are two ways to set these parameters:&nbsp; with <tt>testng.xml</tt> or 
programmatically.</p>


<h5><a class="section" indent="..." name="parameters-testng-xml">Parameters from <tt>testng.xml</tt></a></h5>


If you are using simple values for your parameters, you can specify them in your 
<tt>testng.xml</tt>:


<h3 class="sourcetitle">Java</h3>
<pre class="brush: java">
@Parameters({ "first-name" })
@Test
public void testSingleString(String firstName) { 
  System.out.println("Invoked testString " + firstName);
  assert "Cedric".equals(firstName);
}
</pre>

In this code, we specify that the parameter <tt>firstName</tt> of your Java method 
should receive the value of the XML parameter called <tt>first-name</tt><i>.</i>&nbsp; 
This XML parameter is defined in <tt>testng.xml</tt>:<p>

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;suite name="My suite"&gt;
  &lt;parameter name="first-name"  value="Cedric"/&gt;
  &lt;test name="Simple example"&gt;
  &lt;-- ... --&gt;
</pre>

<h4><span style="font-weight: 400">The same technique can be used for <tt>@Before/After </tt>and <tt>@Factory</tt> annotations:</span></h4>

<pre class="brush: java">
@Parameters({ "datasource", "jdbcDriver" })
@BeforeMethod
public void beforeTest(String ds, String driver) {
  m_dataSource = ...;                              // look up the value of datasource
  m_jdbcDriver = driver;
}
</pre>

This time, the two Java parameter <i>ds</i> 
and <i>driver</i> will receive the value given to the properties <tt>datasource</tt> 
and <tt>jdbc-driver </tt>respectively.&nbsp;

<p>

Parameters can be declared optional with the <a href="../javadocs/org/testng/annotations/Optional.html"><tt>Optional</tt></a> annotation:

<pre class="brush: java">
@Parameters("db")
@Test
public void testNonExistentParameter(@Optional("mysql") String db) { ... }
</pre>

If no parameter named "db" is found in your <tt>testng.xml</tt> file, your test method will receive the default value specified inside the <tt>@Optional</tt> annotation: "mysql".

<p>The <tt>@Parameters</tt> annotation can be placed at the following locations:</p><ul>
	<li>On any method that already has a <tt>@Test</tt>, <tt>@Before/After</tt> 
	or <tt>@Factory</tt> annotation.</li><li>On at most one constructor of your test class.&nbsp; In this case, 
	TestNG will invoke this particular constructor with the parameters 
	initialized to the values specified in <tt>testng.xml</tt> whenever it needs 
	to instantiate your test class.&nbsp; This feature can be used to initialize fields 
	inside your classes to values that will then be used by your
	test methods.</li></ul>
	<blockquote>
	<p><i>Notes:

</i>
	<ul>
		<li><i>The XML parameters are mapped to the Java parameters in the same order as 
they are found in the annotation, and TestNG will issue an error if the numbers 
don't match. </i>
		<li><i>Parameters are scoped. In <tt>testng.xml</tt>, you can declare them either under a 
		<tt>&lt;suite&gt;</tt> tag or under <tt>&lt;test&gt;</tt>. If two parameters have the same name, it's the one 
defined in <tt>&lt;test&gt;</tt> that has precedence. This is convenient if you need to specify 
a parameter applicable to all your tests and override its value only for certain 
tests. </i>
		</ul>
	<p></p>
</blockquote>


<h5><a class="section" indent="..." name="parameters-dataproviders">Parameters with DataProviders</a></h5>


<p>Specifying parameters in <tt>testng.xml</tt> might not be sufficient if you need to pass complex parameters, or parameters that need to be created  from Java (complex objects, objects read from a property file or a database, etc...). In this case, you can use a Data Provider to supply the values you need to test.&nbsp; A Data Provider is a method on your class that returns an array of array of objects.&nbsp; This method is annotated with <tt>@DataProvider</tt>:

<h3 class="sourcetitle">Java</h3>
<pre class="brush: java">
//This method will provide data to any test method that declares that its Data Provider
//is named "test1"
@DataProvider(name = "test1")
public Object[][] createData1() {
 return new Object[][] {
   { "Cedric", new Integer(36) },
   { "Anne", new Integer(37)}, 
 };
}

//This test method declares that its data should be supplied by the Data Provider
//named "test1"
@Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
 System.out.println(n1 + " " + n2);
} 
</pre>
will print

<pre class="brush: text">
Cedric 36
Anne 37
</pre>

A <tt>@Test</tt> method specifies its Data Provider with the <tt>dataProvider</tt> attribute.&nbsp; 
This name must correspond to a method on the same class annotated with <tt>@DataProvider(name=&quot;...&quot;)</tt> 
with a matching name.

<p>
By default, the data provider will be looked for in the current test class or one of its base classes.  If you want to put your data provider in a different class, it needs to be a static method or a class with a non-arg constructor, and you specify the class where it can be found in the <tt>dataProviderClass</tt> attribute:

<h3 class="sourcetitle">StaticProvider.java</h3>
<pre class="brush: java">
public class StaticProvider {
  @DataProvider(name = "create")
  public static Object[][] createData() {
    return new Object[][] {
      new Object[] { new Integer(42) }
    };
  }
}

public class MyTest {
  @Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
  public void test(Integer n) {
    // ...
  }
}
</pre>

The data provider supports injection too. TestNG will use the test context for the injection.

The Data Provider method can return one of the following two types:

<ul>
<li>An array of array of objects (<tt>Object[][]</tt>) where the first dimension's size is the number of times the test method will be invoked and the second dimension size contains an array of objects that must be compatible with the parameter types of the test method. This is the cast illustrated by the example above.</li><li>An <tt>Iterator&lt;Object[]&gt;</tt>.  The only difference with <tt>Object[][]</tt> is that an <tt>Iterator</tt> lets you create your test data lazily.  TestNG will invoke the iterator and then the test method with the parameters returned by this iterator one by one.  This is particularly useful if you have a lot of parameter sets to pass to the method and you don't want to create all of them upfront.
</ul>
Here is an example of this feature:

<pre class="brush: java">
@DataProvider(name = "test1")
public Iterator&lt;Object[]> createData() {
  return new MyIterator(DATA);
} 
</pre>

If you declare your <tt>@DataProvider</tt> as taking a <tt>java.lang.reflect.Method</tt>
as first parameter, TestNG will pass the current test method for this
first parameter.  This is particularly useful when several test methods
use the same <tt>@DataProvider</tt> and you want it to return different
values depending on which test method it is supplying data for.
<p>
For example, the following code prints the name of the test method inside its <tt>@DataProvider</tt>:

<pre class="brush: java">
@DataProvider(name = "dp")
public Object[][] createData(Method m) {
  System.out.println(m.getName());  // print test method name
  return new Object[][] { new Object[] { "Cedric" }};
}

@Test(dataProvider = "dp")
public void test1(String s) {
}

@Test(dataProvider = "dp")
public void test2(String s) {
}
</pre>

and will therefore display:

<pre class="brush: text">
test1
test2
</pre>

Data providers can run in parallel with the attribute <tt>parallel</tt>:

<pre class="brush: java">
@DataProvider(parallel = true)
// ...
</pre>

Parallel data providers running from an XML file share the same pool of threads, which has a size of 10 by default.  You can modify this value in the <tt>&lt;suite&gt;</tt> tag of your XML file:


<pre class="brush: xml">
&lt;suite name="Suite1" data-provider-thread-count="20" &gt;
... 
</pre>

If you want to run a few specific data providers in a different thread pool, you need to run them from a different XML file.

<p>

<h5><a class="section" indent="..." name="parameters-reports">Parameters in reports</a></h5>

<p>

Parameters used to invoke your test methods are shown in the HTML reports generated by TestNG.  Here is an example:

<p align="center">
<img src="pics/parameters.png" />
</p>


</p>


<!-------------------------------------
  DEPENDENCIES
  ------------------------------------>


<h4><a class="section" indent=".." name="dependent-methods">Dependencies</a></h4>

<p>Sometimes, you need
your test methods to be invoked in a certain order.&nbsp; Here are a
few examples:

<ul>
<li>To make sure a certain number of test methods have completed and succeeded 
before running more test methods.
<li>To initialize your tests while wanting this initialization methods to be 
test methods as well (methods tagged with <tt>@Before/After</tt> will not be part of the 
final report).
</ul>

TestNG allows you to specify dependencies either with annotations or
in XML.

<h5><a class="section" indent="..." name="dependencies-with-annotations">Dependencies with annotations</a></h5>

<p>You can use the attributes <tt>dependsOnMethods</tt> or <tt>dependsOnGroups</tt>, found on the <tt>@Test</tt> annotation.</p>There are two kinds of dependencies:

<ul>
<li><b>Hard dependencies</b>.  All the methods you depend on must have run and succeeded for you to run.  If at least one failure occurred in your dependencies, you will not be invoked and marked as a SKIP in the report.
</li>
<li><b>Soft dependencies</b>.  You will always be run after the methods you depend on, even if some of them have failed.  This is useful when you just want to make sure that your test methods are run in a certain order but their success doesn't really depend on the success of others.  A soft dependency is obtained by adding <tt>"alwaysRun=true"</tt> in your <tt>@Test</tt> annotation.
</ul>

Here is an example of a hard dependency:

<pre class="brush: java">
@Test
public void serverStartedOk() {}

@Test(dependsOnMethods = { "serverStartedOk" })
public void method1() {}
</pre>

<p>In this example, <tt>method1()</tt> is declared as depending on method 
serverStartedOk(), which guarantees that serverStartedOk() 
will always be invoked first.</p><p>You can also have methods that depend on entire groups:</p>

<pre class="brush: java">
@Test(groups = { "init" })
public void serverStartedOk() {}

@Test(groups = { "init" })
public void initEnvironment() {}

@Test(dependsOnGroups = { "init.*" })
public void method1() {}
</pre>

<p>In this example, method1() is declared as depending on any group matching the 
regular expression &quot;init.*&quot;, which guarantees that the methods <tt>serverStartedOk()</tt> 
and <tt>initEnvironment()</tt> will always be invoked before <tt>method1()</tt>.&nbsp; </p>
<blockquote>
	<p><i>Note:&nbsp; as stated before, the order of invocation for methods that 
	belong in the same group is not guaranteed to be the same across test runs.</i></p></blockquote><p>If a method depended upon fails and you have a hard dependency on it (<tt>alwaysRun=false</tt>, which is the default), the methods that depend on it are <b>not</b> 
marked as <tt>FAIL</tt> but as <tt>SKIP</tt>.&nbsp; Skipped methods will be reported as such in 
the final report (in a color that is neither red nor green in HTML), 
which is important since skipped methods are not necessarily failures.</p><p>Both <tt>dependsOnGroups</tt> and <tt>dependsOnMethods</tt> accept regular 
expressions as parameters.&nbsp; For <tt>dependsOnMethods</tt>, if you are 
depending on a method which happens to have several overloaded versions, all the 
overloaded methods will be invoked.&nbsp; If you only want to invoke one of the 
overloaded methods, you should use <tt>dependsOnGroups</tt>.</p><p>For a more advanced example of dependent methods, please refer to 
<a href="http://beust.com/weblog/archives/000171.html">this article</a>, which 
uses inheritance to provide an elegant solution to the problem of multiple 
dependencies.</p>

By default, dependent methods are grouped by class. For example, if method <tt>b()</tt> depends on method <tt>a()</tt> and you have several instances of the class that contains these methods (because of a factory of a data provider), then the invocation order will be as follows:

<pre class="brush: plain">
a(1)
a(2)
b(2)
b(2)
</pre>

TestNG will not run <tt>b()</tt> until all the instances have invoked their <tt>a()</tt> method.

<p>

This behavior might not be desirable in certain scenarios, such as for example testing a sign in and sign out of a web browser for various countries. In such a case, you would like the following ordering:

<pre class="brush: plain">
signIn("us")
signOut("us")
signIn("uk")
signOut("uk")
</pre>

For this ordering, you can use the XML attribute <tt>group-by-instances</tt>. This attribute is valid either on &lt;suite&gt; or &lt;test&gt;:

<pre class="brush: xml">
  &lt;suite name="Factory" group-by-instances="true"&gt;
or
  &lt;test name="Factory" group-by-instances="true"&gt;
</pre>


<h5><a class="section" indent="..." name="dependencies-in-xml">Dependencies in XML</a></h5>

Alternatively, you can specify your group dependencies in the <tt>testng.xml</tt> file. You use the <tt>&lt;dependencies&gt;</tt> tag to achieve this:

<pre class="brush: xml">
  &lt;test name="My suite"&gt;
    &lt;groups&gt;
      &lt;dependencies&gt;
        &lt;group name="c" depends-on="a  b" /&gt;
        &lt;group name="z" depends-on="c" /&gt;
      &lt;/dependencies&gt;
    &lt;/groups&gt;
  &lt;/test&gt;
</pre>

The <tt>&lt;depends-on&gt;</tt> attribute contains a space-separated list of groups.


<!-------------------------------------
  FACTORIES
  ------------------------------------>

<h4><a class="section" indent=".." name="factories">Factories</a></h4>

Factories allow you to create tests dynamically. For example, imagine you 
want to create a test method that will access a page on a Web site several 
times, and you want to invoke it with different values:

<h3 class="sourcetitle">TestWebServer.java</h3>
<pre class="brush: java">
public class TestWebServer {
  @Test(parameters = { "number-of-times" })
  public void accessPage(int numberOfTimes) {
    while (numberOfTimes-- > 0) {
     // access the web page
    }
  }
}
</pre>

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: java">
&lt;test name="T1"&gt;
&nbsp;&nbsp;&lt;parameter name="number-of-times" value="10"/&gt;
&nbsp;&nbsp;&lt;class name= "TestWebServer" /&gt;
&lt;/test&gt;

&lt;test name="T2"&gt;
&nbsp;&nbsp;&lt;parameter name="number-of-times" value="20"/&gt;
&nbsp;&nbsp;&lt;class name= "TestWebServer"/&gt;
&lt;/test&gt;

&lt;test name="T3"&gt;
&nbsp;&nbsp;&lt;parameter name="number-of-times" value="30"/&gt;
&nbsp;&nbsp;&lt;class name= "TestWebServer"/&gt;
&lt;/test&gt;
</pre>

This can become quickly impossible to manage, so instead, you should use a factory:

<h3 class="sourcetitle">WebTestFactory.java</h3>
<pre class="brush: java">
public class WebTestFactory {
  @Factory
  public Object[] createInstances() {
   Object[] result = new Object[10];  
   for (int i = 0; i < 10; i++) {
      result[i] = new WebTest(i * 10);
    }
    return result;
  }
}
</pre>

and the new test class is now:

<h3 class="sourcetitle">WebTest.java</h3>
<pre class="brush: java">
public class WebTest {
  private int m_numberOfTimes;
  public WebTest(int numberOfTimes) {
    m_numberOfTimes = numberOfTimes;
  }

  @Test
  public void testServer() {
   for (int i = 0; i < m_numberOfTimes; i++) {
     // access the web page
    }
  }
}
</pre>

<p>Your <tt>testng.xml</tt> only needs to reference the class that 
contains the factory method, since the test instances themselves will be created 
at runtime:</p>

<pre class="brush: java">
&lt;class name="WebTestFactory" /&gt;
</pre>

<p>The factory method can receive parameters just like <tt>@Test</tt> and <tt>@Before/After</tt> and it must return <tt>Object[]</tt>.&nbsp; 
The objects returned can be of any class (not necessarily the same class as the 
factory class) and they don't even need to contain TestNG annotations (in which 
case they will be ignored by TestNG).</p>

<p>

Factories can also be used with data providers, and you can leverage this functionality by putting the <tt>@Factory</tt> annotation either on a regular method or on a constructor. Here is an example of a constructor factory:

<pre class="brush:java">
  @Factory(dataProvider = "dp")
  public FactoryDataProviderSampleTest(int n) {
    super(n);
  }

  @DataProvider
  static public Object[][] dp() {
    return new Object[][] {
      new Object[] { 41 },
      new Object[] { 42 },
    };
  }
</pre>

The example will make TestNG create two test classes, on with the constructor invoked with the value 41 and the other with 42.



<!-------------------------------------
  CLASS LEVEL ANNOTATIONS
  ------------------------------------>

<h4><a class="section" indent=".." name="class-level">Class level annotations</a></h4>

The <tt>@Test</tt> annotation can be put on a class instead of a test method:

<h3 class="sourcetitle">Test1.java</h3>
<pre class="brush: java">
@Test
public class Test1 {
  public void test1() {
  }

  public void test2() {
  }
}
</pre>
The effect of a class level <tt>@Test</tt> annotation is to make all the public methods of this class to become test methods even if they are not annotated.  You can still repeat the <tt>@Test</tt> annotation on a method if you want to add certain attributes.
<p>

For example:

<h3 class="sourcetitle">Test1.java</h3>
<pre class="brush: java">
@Test
public class Test1 {
  public void test1() {
  }

  @Test(groups = "g1")
  public void test2() {
  }
}
</pre>
will make both <tt>test1()</tt> and <tt>test2()</tt> test methods but on top of that, <tt>test2()</tt> now belongs to the group "g1".
<p>



<!-------------------------------------
  PARALLEL RUNNING
  ------------------------------------>

<h4><a class="section" indent=".." name="parallel-running">Parallelism and time-outs</a></h4>

You can  instruct TestNG to run your tests in separate threads in various ways.

<h5><a class="section" indent="..." name="parallel-suites">Parallel suites</a></h5>

This is useful if you are running several suite files (e.g. "<tt>java org.testng.TestNG testng1.xml testng2.xml"</tt>) and you want each of these suites to be run in a separate thread. You can use the following command line flag to specify the size of a thread pool:

<pre class="brush: plain">
java org.testng.TestNG -suitethreadpoolsize 3 testng1.xml testng2.xml testng3.xml
</pre>

The corresponding ant task name is <tt>suitethreadpoolsize</tt>.

<h5><a class="section" indent="..." name="parallel-tests">Parallel tests, classes and methods</a></h5>
The <i>parallel</i> attribute on the &lt;suite&gt; tag can take one of following values:

<pre class="brush: xml">
&lt;suite name="My suite" parallel="methods" thread-count="5"&gt;
</pre>

<pre class="brush: xml">
&lt;suite name="My suite" parallel="tests" thread-count="5"&gt;
</pre>

<pre class="brush: xml">
&lt;suite name="My suite" parallel="classes" thread-count="5"&gt;
</pre>

<pre class="brush: xml">
&lt;suite name="My suite" parallel="instances" thread-count="5"&gt;
</pre>

<ul>
<li>
<b><tt>parallel="methods"</tt></b>:  TestNG will run all your test methods in separate threads. Dependent methods will also run in separate threads but they will respect the order that you specified.
</li>

<br>

<li>
<b><tt>parallel="tests"</tt></b>:  TestNG will run all the methods in the same &lt;test&gt; tag in the same thread, but each &lt;test&gt; tag will be in a separate thread.  This allows you to group all your classes that are not thread safe in the same &lt;test&gt; and guarantee they will all run in the same thread while taking advantage of TestNG using as many threads as possible to run your tests.
</li>

<br>

<li>
<b><tt>parallel="classes"</tt></b>:  TestNG will run all the methods in the same class in the same thread, but each class will be run in a separate thread.
</li>

<br/>

<li>
<b><tt>parallel="instances"</tt></b>:  TestNG will run all the methods in the same instance in the same thread, but two methods on two different instances will be running in different threads.
</li>

</ul>

<p>


Additionally, the attribute <i>
thread-count</i> allows you to specify how many threads should be allocated for 
this execution.<blockquote>
	<p><i>Note: the <tt>@Test</tt> attribute <tt>timeOut</tt> works in both 
	parallel and non-parallel mode.</i></p></blockquote>You can also specify that a <tt>@Test</tt> method should be invoked from different threads.  You can use the attribute <tt>threadPoolSize</tt> to achieve this result:

<pre class="brush: java">
@Test(threadPoolSize = 3, invocationCount = 10,  timeOut = 10000)
public void testServer() {
</pre>
In this example, the function <tt>testServer</tt> will be invoked ten times from three different threads.  Additionally, a time-out of ten seconds guarantees that none of the threads will block on this thread forever. 

<!-------------------------------------
  RERUNNING
  ------------------------------------>


<h4><a class="section" indent=".." name="rerunning">Rerunning failed tests</a></h4>

Every time tests fail in a suite, TestNG creates a file called <tt>testng-failed.xml</tt> in the output directory.
This XML file contains the necessary information to rerun only these methods 
that failed, allowing you to quickly reproduce the failures without having to 
run the entirety of your tests.&nbsp; Therefore, a typical session would look 
like this:

<pre class="brush: text">
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs testng.xml
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -d test-outputs test-outputs\testng-failed.xml
</pre>

<p>Note that <tt>testng-failed.xml</tt> will contain all the necessary dependent 
methods so that you are guaranteed to run the methods that failed without any 
SKIP failures.</p>

<h4><a class="section" indent=".." name="junit">JUnit tests</a></h4>

TestNG can run JUnit 3 and JUnit 4 tests.&nbsp; All you need to do is
put the JUnit jar file on the classpath, specify your JUnit test classes in the <tt>testng.classNames</tt>
property and set the <tt>testng.junit</tt> property to true:

<p></p>
<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="Test1" junit="true"&gt;
  &lt;classes&gt;
    &lt;!-- ... --&gt;
</pre>

<p>The behavior of TestNG in this case is similar to JUnit depending on the JUnit version found on the class path:<br>
</p>
<ul>
    <li>JUnit 3:
<ul>
  <li>All methods starting with test* in your classes will be run</li><li>If there is a method setUp() on your test class, it will be invoked before 
	every test method</li><li>If there is a method tearDown() on your test class, it will be invoked 
	before after every test method</li><li>If your test class contains a method suite(), all the tests returned by 
	this method will be invoked</li></ul>
    </li>
    <li>JUnit 4:
        <ul>
            <li>TestNG will use the <tt>org.junit.runner.JUnitCore</tt> runner to run your tests</li>
        </ul>
    </li>
</ul>

<!-------------------------------------
  JUNIT
--------------------------------------->


<!-------------------------------------
  RUNNING TESTNG
 ------------------------------------>
<h4><a class="section" indent=".." name="running-testng-programmatically">Running TestNG programmatically</a></h4>

You can invoke TestNG from your own programs very easily:

<h3 class="sourcetitle">Java</h3>
<pre class="brush: java">
TestListenerAdapter tla = new TestListenerAdapter();
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { Run2.class });
testng.addListener(tla);
testng.run(); 
</pre>

This example creates a <tt><a href="http://testng.org/javadocs/org/testng/TestNG.html">TestNG</a></tt> object and runs the test class <tt>Run2</tt>.  It also adds a <tt>TestListener</tt>.  You can either use the adapter class <tt><a href="http://testng.org/javadocs/org/testng/TestListenerAdapter.html">org.testng.TestListenerAdapter</a></tt> or implement <tt><a href="http://testng.org/javadocs/org/testng/ITestListener.html">org.testng.ITestListener</a></tt> yourself.  This interface contains various callback methods that let you keep track of when a test starts, succeeds, fails, etc... 
<p>
Similary, you can invoke TestNG on a <tt>testng.xml</tt> file or you can create a virtual <tt>testng.xml</tt> file yourself.  In order to do this, you can use the classes found the package <tt><a href="http://testng.org/javadocs/org/testng/xml/package-frame.html">org.testng.xml</a></tt>:  <tt><a href="http://testng.org/javadocs/org/testng/xml/XmlClass.html">XmlClass</a></tt>, <tt><a href="http://testng.org/javadocs/org/testng/xml/XmlTest.html">XmlTest</a></tt>, etc...  Each of these classes correspond to their XML tag counterpart.
<p>
For example, suppose you want to create the following virtual file:

<pre class="brush: java">
&lt;suite name="TmpSuite" &gt;
  &lt;test name="TmpTest" &gt;
    &lt;classes&gt;
      &lt;class name="test.failures.Child"  /&gt;
    &lt;classes&gt;
    &lt;/test&gt;
&lt;/suite&gt;
</pre>

You would use the following code:

<pre class="brush: java">
XmlSuite suite = new XmlSuite();
suite.setName("TmpSuite");

XmlTest test = new XmlTest(suite);
test.setName("TmpTest");
List&lt;XmlClass&gt; classes = new ArrayList&lt;XmlClass&gt;();
classes.add(new XmlClass("test.failures.Child"));
test.setXmlClasses(classes) ;
</pre>
And then you can pass this <tt>XmlSuite</tt> to TestNG:

<pre class="brush: java">
List&lt;XmlSuite&gt; suites = new ArrayList&lt;XmlSuite&gt;();
suites.add(suite);
TestNG tng = new TestNG();
tng.setXmlSuites(suites);
tng.run(); 
</pre>

<p>Please see the <a href="../doc/javadocs/org/testng/package-summary.html" target="mainFrame">JavaDocs</a> for the entire API.</p><p>


<!-------------------------------------
  BEANSHELL
 ------------------------------------>
	
<h4><a class="section" indent=".." name="beanshell">BeanShell and advanced group selection</a></h4>


	<p>If the <tt>&lt;include&gt;</tt> and <tt>&lt;exclude&gt;</tt> tags in <tt>testng.xml</tt> are not enough for your needs, you can use a <a href="http://beanshell.org">BeanShell</a> expression to decide whether a certain test method should be included in a test run or not. You specify this expression just under the <tt>&lt;test&gt;</tt> tag:</p>

<h3 class="sourcetitle">testng.xml</h3>
<pre class="brush: xml">
&lt;test name="BeanShell test"&gt;
   &lt;method-selectors&gt;
     &lt;method-selector&gt;
       &lt;script language="beanshell"&gt;&lt;![CDATA[
         groups.containsKey("test1")
       ]]&gt;&lt;/script&gt;
     &lt;/method-selector&gt;
   &lt;/method-selectors&gt;
  &lt;!-- ... --&gt;
</pre>

When a <tt>&lt;script&gt;</tt> tag is found in <tt>testng.xml</tt>, TestNG will ignore subsequent <tt>&lt;include&gt;</tt> and <tt>&lt;exclude&gt;</tt> of groups and methods in the current <tt>&lt;test&gt;</tt> tag:&nbsp; your BeanShell expression will be the only way to decide whether a test method is included or not.</p><p>Here are additional information on the BeanShell script:</p><ul>
<li>
It must return a boolean value.&nbsp; Except for this constraint, any valid BeanShell code is allowed (for example, you might want to return <tt>true </tt>during week days and false during weekends, which would allow you to run tests differently depending on the date).<br>&nbsp;
</li>
<li>
TestNG defines the following variables for your convenience:<br>&nbsp; <b><tt>java.lang.reflect.Method method</tt></b>:&nbsp; the current test method.<br>&nbsp; <b>org.testng.ITestNGMethod testngMethod</b>:&nbsp; the description of the current test method.<br>&nbsp; <b><tt>java.util.Map&lt;String, String&gt; groups</tt></b>:&nbsp; a map of the groups the current test method belongs to.<br>&nbsp;
</li>
<li>
You might want to surround your expression with a <tt>CDATA</tt> declaration (as shown above) to avoid tedious quoting of reserved XML characters).<br>&nbsp;
</li>
</ul>

<!-------------------------------------
  ANNOTATION TRANSFORMERS
 ------------------------------------>
	
<h4><a class="section" indent=".." name="annotationtransformers">Annotation Transformers</a></h4>

TestNG allows you to modify the content of all the annotations at runtime.  This is especially useful if the annotations in the source code are right most of the time, but there are a few situations where you'd like to override their value.
<p>

In order to achieve this, you need to use an Annotation Transformer.

<p>

An Annotation Transformer is a class that implements the following interface:

<pre class="brush: java">
public interface IAnnotationTransformer {

  /**
   * This method will be invoked by TestNG to give you a chance
   * to modify a TestNG annotation read from your test classes.
   * You can change the values you need by calling any of the
   * setters on the ITest interface.
   * 
   * Note that only one of the three parameters testClass,
   * testConstructor and testMethod will be non-null.
   * 
   * @param annotation The annotation that was read from your
   * test class.
   * @param testClass If the annotation was found on a class, this
   * parameter represents this class (null otherwise).
   * @param testConstructor If the annotation was found on a constructor,
   * this parameter represents this constructor (null otherwise).
   * @param testMethod If the annotation was found on a method,
   * this parameter represents this method (null otherwise).
   */
  public void transform(ITest annotation, Class testClass,
      Constructor testConstructor, Method testMethod);
}
</pre>

Like all the other TestNG listeners, you can specify this class either on the command line or with ant:

<p>

<pre class="brush: java">
  java org.testng.TestNG -listener MyTransformer testng.xml
</pre>

or programmatically:

<p>

<pre class="brush: java">
  TestNG tng = new TestNG();
  tng.setAnnotationTransformer(new MyTransformer());
  // ...
</pre>

When the method <tt>transform()</tt> is invoked, you can call any of the setters on the <tt>ITest test</tt> parameter to alter its value before TestNG proceeds further.
<p>
For example, here is how you would override the attribute <tt>invocationCount</tt> but only on the test method <tt>invoke()</tt> of one of your test classes:

<pre class="brush: java">
  public class MyTransformer implements IAnnotationTransformer {
    public void transform(ITest annotation, Class testClass,
        Constructor testConstructor, Method testMethod)
    {
      if ("invoke".equals(testMethod.getName())) {
        annotation.setInvocationCount(5);
      }
    }
  }
</pre>

<tt>IAnnotationTransformer</tt> only lets you modify a <tt>@Test</tt> annotation.  If you need to modify another TestNG annotation (a configuration annotation, <tt>@Factory</tt> or <tt>@DataProvider</tt>), use an <tt>IAnnotationTransformer2</tt>.

<!-------------------------------------
  METHOD INTERCEPTORS
 ------------------------------------>
	
<h4><a class="section" indent=".." name="methodinterceptors">Method Interceptors</a></h4>

Once TestNG has calculated in what order the test methods will be invoked, these methods are split in two groups:

<ul>
  <li><em>Methods run sequentially</em>.  These are all the test methods that have dependencies or dependents.  These methods will be run in a specific order.
  <li><em>Methods run in no particular order</em>.  These are all the methods that don't belong in the first category.  The order in which these test methods are run is random and can vary from one run to the next (although by default, TestNG will try to group test methods by class).
</ul>

In order to give you more control on the methods that belong to the second category, TestNG defines the following interface:

<pre class="brush: java">
public interface IMethodInterceptor {
  
  List&lt;IMethodInstance&gt; intercept(List&lt;IMethodInstance&gt; methods, ITestContext context);

}

</pre>

The list of methods passed in parameters are all the methods that can be run in any order.  Your <tt>intercept</tt> method is expected to return a similar list of <tt>IMethodInstance</tt>, which can be either of the following:

<ul>
  <li>The same list you received in parameter but in a different order.
  <li>A smaller list of <tt>IMethodInstance</tt> objects.
  <li>A bigger list of <tt>IMethodInstance</tt> objects.
</ul>

Once you have defined your interceptor, you pass it to TestNG as a listener.  For example:

<p>

<h3 class="sourcetitle">Shell</h3>
<pre class="brush: text">
java -classpath "testng-jdk15.jar:test/build" org.testng.TestNG -listener test.methodinterceptors.NullMethodInterceptor
   -testclass test.methodinterceptors.FooTest
</pre>

For the equivalent <tt>ant</tt> syntax, see the <tt>listeners</tt> attribute in the <a href="ant.html">ant documentation</a>.
<p>
For example, here is a Method Interceptor that will reorder the methods so that test methods that belong to the group "fast" are always run first:

<pre class="brush: java">
public List&lt;IMethodInstance&gt; intercept(List&lt;IMethodInstance&gt; methods, ITestContext context) {
  List&lt;IMethodInstance&gt; result = new ArrayList&lt;IMethodInstance&gt;();
  for (IMethodInstance m : methods) {
    Test test = m.getMethod().getConstructorOrMethod().getAnnotation(Test.class);
    Set&lt;String&gt; groups = new HashSet&lt;String&gt;();
    for (String group : test.groups()) {
      groups.add(group);
    }
    if (groups.contains("fast")) {
      result.add(0, m);
    }
    else {
      result.add(m);
    }
  }
  return result;
}
</pre>


<!-------------------------------------
  TESTNG LISTENERS
 ------------------------------------>
	
<h4><a class="section" indent=".." name="testng-listeners">TestNG Listeners</a></h4>

There are several interfaces that allow you to modify TestNG's behavior.  These interfaces are broadly called "TestNG Listeners".  Here are a few listeners:

<ul>
  <li><tt>IAnnotationTransformer</tt> (<a href="#annotationtransformers">doc</a>, <a href="../javadocs/org/testng/IAnnotationTransformer.html">javadoc</a>)
  <li><tt>IAnnotationTransformer2</tt> (<a href="#annotationtransformers">doc</a>, <a href="../javadocs/org/testng/IAnnotationTransformer2.html">javadoc</a>)
  <li><tt>IHookable</tt> (<a href="#ihookable">doc</a>, <a href="../javadocs/org/testng/IHookable.html">javadoc</a>)
  <li><tt>IInvokedMethodListener</tt> (doc, <a href="../javadocs/org/testng/IInvokedMethodListener.html">javadoc</a>)
  <li><tt>IMethodInterceptor</tt> (<a href="#methodinterceptors">doc</a>, <a href="../javadocs/org/testng/IMethodInterceptor.html">javadoc</a>)
  <li><tt>IReporter</tt> (<a href="#logging-reporters">doc</a>, <a href="../javadocs/org/testng/IReporter.html">javadoc</a>)
  <li><tt>ISuiteListener</tt> (doc, <a href="../javadocs/org/testng/ISuiteListener.html">javadoc</a>)
  <li><tt>ITestListener</tt> (<a href="#logging-listeners">doc</a>, <a href="../javadocs/org/testng/ITestListener.html">javadoc</a>)
</ul>

When you implement one of these interfaces, you can let TestNG know about it with either of the following ways:

<ul>
  <li><a href="#running-testng">Using -listener on the command line.</a>
  <li><a href="ant.html">Using &lt;listeners&gt; with ant.</a>
  <li>Using &lt;listeners&gt; in your <tt>testng.xml</tt> file.
  <li>Using the <tt>@Listeners</tt> annotation on any of your test classes.
  <li>Using <tt>ServiceLoader</tt>.
</ul>

<h5><a class="section" indent="..." name="listeners-testng-xml">Specifying listeners with <tt>testng.xml</tt> or in Java</a></h5>

Here is how you can define listeners in your <tt>testng.xml</tt> file:

<pre class="brush: xml">
&lt;suite&gt;

  &lt;listeners&gt;
    &lt;listener class-name="com.example.MyListener" /&gt;
    &lt;listener class-name="com.example.MyMethodInterceptor" /&gt;
  &lt;/listeners&gt;

...

</pre>

Or if you prefer to define these listeners in Java:

<pre class="brush: java">
@Listeners({ com.example.MyListener.class, com.example.MyMethodInterceptor.class })
public class MyTest {
  // ...
}
</pre>

The <tt>@Listeners</tt> annotation can contain any class that extends <tt>org.testng.ITestNGListener</tt> <b>except</b> <tt>IAnnotationTransformer</tt> and <tt>IAnnotationTransformer2</tt>.  The reason is that these listeners need to be known very early in the process so that TestNG can use them to rewrite your annotations, therefore you need to specify these listeners in your <tt>testng.xml</tt> file.

<p>

Note that the <tt>@Listeners</tt> annotation will apply to your entire suite file, just as if you had specified it in a <tt>testng.xml</tt> file. If you want to restrict its scope (for example, only running on the current class), the code in your listener could first check the test method that's about to run and decide what to do then.

<h5><a class="section" indent="..." name="listeners-service-loader">Specifying listeners with <tt>ServiceLoader</tt></a></h5>

Finally, the JDK offers a very elegant mechanism to specify implementations of interfaces on the class path via the <tt><a href="http://download.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html">ServiceLoader</a></tt> class.

<p>
With ServiceLoader, all you need to do is create a jar file that contains your listener(s) and a few configuration files, put that jar file on the classpath when you run TestNG and TestNG will automatically find them.
<p>

Here is a concrete example of how it works.

<p>

Let's start by creating a listener (any TestNG listener should work):

<pre class="brush: java">
package test.tmp;

public class TmpSuiteListener implements ISuiteListener {
  @Override
  public void onFinish(ISuite suite) {
    System.out.println("Finishing");
  }

  @Override
  public void onStart(ISuite suite) {
    System.out.println("Starting");
  }
}
</pre>

Compile this file, then create a file at the location <tt>META-INF/services/org.testng.ITestNGListener</tt>, which will name the implementation(s) you want for this interface.

<p>

You should end up with the following directory structure, with only two files:

<pre class="brush: plain; highlight: [4, 7]">
$ tree
|____META-INF
| |____services
| | |____org.testng.ITestNGListener
|____test
| |____tmp
| | |____TmpSuiteListener.class

$ cat META-INF/services/org.testng.ITestNGListener
test.tmp.TmpSuiteListener
</pre>

Create a jar of this directory:

<pre class="brush: plain">
$ jar cvf ../sl.jar .
added manifest
ignoring entry META-INF/
adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
adding: META-INF/services/org.testng.ITestNGListener(in = 26) (out= 28)(deflated -7%)
adding: test/(in = 0) (out= 0)(stored 0%)
adding: test/tmp/(in = 0) (out= 0)(stored 0%)
adding: test/tmp/TmpSuiteListener.class(in = 849) (out= 470)(deflated 44%)
</pre>

Next, put this jar file on your classpath when you invoke TestNG:

<pre class="brush: plain">
$ java -classpath sl.jar:testng.jar org.testng.TestNG testng-single.yaml
Starting
f2 11 2
PASSED: f2("2")
Finishing
</pre>

This mechanism allows you to apply the same set of listeners to an entire organization just by adding a jar file to the classpath, instead of asking every single developer to remember to specify these listeners in their testng.xml file. 

<!-------------------------------------
  DEPENDENCY INJECTION
 ------------------------------------>
	
<h4><a class="section" indent=".." name="dependency-injection">Dependency injection</a></h4>

TestNG supports two different kinds of dependency injection: native (performed by TestNG itself) and external (performed by a dependency injection framework such as Guice).

<h5><a class="section" indent="..." name="native-dependency-injection">Native dependency injection</a></h5>

TestNG lets you declare additional parameters in your methods.  When this happens, TestNG will automatically fill these parameters with the right value.  Dependency injection can be used in the following places:

<ul>
  
<li>
  Any @Before method or @Test method can declare a parameter of type <tt>ITestContext</tt>.
<li>
  Any @AfterMethod method can declare a parameter of type <tt>ITestResult</tt>, which will reflect the result of the test method that was just run.
<li>
  Any @Before and @After methods can declare a parameter of type <tt>XmlTest</tt>, which contain the current <tt>&lt;test&gt;</tt> tag.
<li>
  Any @BeforeMethod (and @AfterMethod) can declare a parameter of type
  <tt>java.lang.reflect.Method</tt>.  This parameter will receive the
  test method that will be called once this @BeforeMethod finishes (or
  after the method as run for @AfterMethod).
<li>
  Any @BeforeMethod can declare a parameter of type <tt>Object[]</tt>.  This parameter will receive the list of parameters that are about to be fed to the upcoming test method, which could be either injected by TestNG, such as <tt>java.lang.reflect.Method</tt> or come from a <tt>@DataProvider</tt>.
<li>
  Any @DataProvider can declare a parameter of type
  <tt>ITestContext</tt> or <tt>java.lang.reflect.Method</tt>.  The
  latter parameter will receive the test method that is about to be invoked.
</ul>

You can turn off injection with the <tt>@NoInjection</tt> annotation:

<pre class="brush: java; highlight: [9]">
public class NoInjectionTest {

  @DataProvider(name = "provider")
  public Object[][] provide() throws Exception {
      return new Object[][] { { CC.class.getMethod("f") } };
  }

  @Test(dataProvider = "provider")
  public void withoutInjection(@NoInjection Method m) {
      Assert.assertEquals(m.getName(), "f");
  }

  @Test(dataProvider = "provider")
  public void withInjection(Method m) {
      Assert.assertEquals(m.getName(), "withInjection");
  }
}
</pre>

<h5><a class="section" indent="..." name="guice-dependency-injection">Guice dependency injection</a></h5>

If you use Guice, TestNG gives you an easy way to inject your test objects with a Guice module:

<pre class="brush: java">
@Guice(modules = GuiceExampleModule.class)
public class GuiceTest extends SimpleBaseTest {

  @Inject
  ISingleton m_singleton;

  @Test
  public void singletonShouldWork() {
    m_singleton.doSomething();
  }

}
</pre>

In this example, <tt>GuiceExampleModule</tt> is expected to bind the interface <tt>ISingleton</tt> to some concrete class:

<pre class="brush: java">
public class GuiceExampleModule implements Module {

  @Override
  public void configure(Binder binder) {
    binder.bind(ISingleton.class).to(ExampleSingleton.class).in(Singleton.class);
  }

}
</pre>

If you need more flexibility in specifying which modules should be used to instantiate your test classes, you can specify a module factory:

<pre class="brush: java">
@Guice(moduleFactory = ModuleFactory.class)
public class GuiceModuleFactoryTest {

  @Inject
  ISingleton m_singleton;

  @Test
  public void singletonShouldWork() {
    m_singleton.doSomething();
  }
}
</pre>

The module factory needs to implement the interface <a href="../javadocs/org/testng/IModuleFactory.html">IModuleFactory</a>:

<pre class="brush: java">
public interface IModuleFactory {
 /**
   * @param context The current test context
   * @param testClass The test class
   *
   * @return The Guice module that should be used to get an instance of this
   * test class.
   */
  Module createModule(ITestContext context, Class&lt;?&gt; testClass);
}
</pre>

Your factory will be passed an instance of the test context and the test class that TestNG needs to instantiate. Your <tt>createModule</tt> method should return a Guice Module that will know how to instantiate this test class. You can use the test context to find out more information about your environment, such as parameters specified in <tt>testng.xml</tt>, etc...

You will get even more flexibility and Guice power with <tt>parent-module</tt> and <tt>guice-stage</tt> suite parameters.
<tt>guice-stage</tt> allow you to chose the <a href="https://github.com/google/guice/wiki/Bootstrap"><tt>Stage</tt></a> used to create the parent injector.
The default one is <tt>DEVELOPMENT</tt>. Other allowed values are <tt>PRODUCTION</tt> and <tt>TOOL</tt>.
Here is how you can define parent-module in your test.xml file:

<pre class="brush: xml">
<suite parent-module="com.example.SuiteParenModule" guice-stage="PRODUCTION">
</suite>
</pre>

TestNG will create this module only once for given suite. Will also use this module for obtaining instances of test specific Guice modules and module factories, then will create child injector for each test class.

With such approach you can declare all common bindings in parent-module also you can inject binding declared in parent-module in module and module factory. Here is an example of this functionality:

<pre class="brush: java">
package com.example;

public class ParentModule extends AbstractModule {
  @Override
  protected void conigure() {
    bind(MyService.class).toProvider(MyServiceProvider.class);
    bind(MyContext.class).to(MyContextImpl.class).in(Singleton.class);
  }
}
</pre>

<pre class="brush: java">
package com.example;

public class TestModule extends AbstractModule {
  private final MyContext myContext;

  @Inject
  TestModule(MyContext myContext) {
    this.myContext = myContext
  }
  
  @Override
  protected void configure() {
    bind(MySession.class).toInstance(myContext.getSession());
  }
}
</pre>

<pre class="brush: xml">
<suite parent-module="com.example.ParentModule">
</suite>
</pre>

<pre class="brush: java">
package com.example;

@Test
@Guice(modules = TestModule.class)
public class TestClass {
  @Inject
  MyService myService;
  @Inject
  MySession mySession;
  
  public void testServiceWithSession() {
    myService.serve(mySession);
  }
}
</pre>

As you see ParentModule declares binding for MyService and MyContext classes. Then MyContext is injected using constructor injection into TestModule class, which also declare binding for MySession. Then parent-module in test XML file is set to ParentModule class, this enables injection in TestModule. Later in TestClass you see two injections:
 * MyService - binding taken from ParentModule
 * MySession - binding taken from TestModule
This configuration ensures you that all tests in this suite will be run with same session instance, the MyContextImpl object is only created once per suite, this give you possibility to configure common environment state for all tests in suite. 

<!-------------------------------------
  INVOKED METHOD LISTENERS
 ------------------------------------>
	
<h4><a class="section" indent=".." name="invokedmethodlistener">Listening to method invocations</a></h4>

The listener <tt><a href="../javadocs/org/testng/IInvokedMethodListener.html">IInvokedMethodListener</a></tt> allows you to be notified whenever TestNG is about to invoke a test (annotated with <tt>@Test</tt>) or configuration (annotated with any of the <tt>@Before</tt> or <tt>@After</tt> annotation) method.  You need to implement the following interface:

<pre class="brush: java">
public interface IInvokedMethodListener extends ITestNGListener {
  void beforeInvocation(IInvokedMethod method, ITestResult testResult);
  void afterInvocation(IInvokedMethod method, ITestResult testResult);
}
</pre>

and declare it as a listener, as explained in <a href="#testng-listeners">the section about TestNG listeners</a>.

<p>


<!-------------------------------------
  IHOOKABLE AND ICONFIGURABLE
  ------------------------------------>

<h4><a class="section" indent=".." name="ihookable">Overriding test methods</a></h4>

TestNG allows you to override and possibly skip the invocation of test methods. One example of where this is useful is if you need to your test methods with a specific security manager. You achieve this by providing a listener that implements <a href="../javadocs/org/testng/IHookable.html"><tt>IHookable</tt></a>.
<p>
Here is an example with JAAS:

<pre class="brush: java">
public class MyHook implements IHookable {
  public void run(final IHookCallBack icb, ITestResult testResult) {
    // Preferably initialized in a @Configuration method
    mySubject = authenticateWithJAAs();
   
    Subject.doAs(mySubject, new PrivilegedExceptionAction() {
      public Object run() {
        icb.callback(testResult);
      }
    };
  }
}
</pre>

<p>
<!-------------------------------------
  IALTERSUITELISTENER
  ------------------------------------>

<h4><a class="section" indent=".." name="ialtersuite">Altering suites (or) tests</a></h4>
Sometimes you may need to just want to alter a suite (or) a test tag in a suite xml in runtime without having to
change the contents of a suite file.

<p>
A classic example for this would be to try and leverage your existing suite file and try using it for simulating a load test
on your "Application under test".
At the minimum you would end up duplicating the contents of your &lt;test&gt; tag multiple
times and create a new suite xml file and work with. But this doesn't seem to scale a lot.

<p>
TestNG allows you to alter a suite (or) a test tag in your suite xml file at runtime via listeners.
You achieve this by providing a listener that implements <a href="../javadocs/org/testng/IAlterSuiteListener.html"><tt>IAlterSuiteListener</tt></a>.
Please refer to <a href="#testng-listeners">Listeners section</a> to learn about listeners.
<p>
Here is an example that shows how the suite name is getting altered in runtime:

<pre class="brush: java">
public class AlterSuiteNameListener implements IAlterSuiteListener {

    @Override
    public void alter(List&lt;XmlSuite&gt; suites) {
        XmlSuite suite = suites.get(0);
        suite.setName(getClass().getSimpleName());
    }
}
</pre>

This listener can only be added with either of the following ways: 
<ul>
  <li>Through the <tt>&lt;listeners&gt;</tt> tag in the suite xml file.</li>
  <li>Through a <a href="#listeners-service-loader">Service Loader</a></li>
</ul>

This listener cannot be added to execution using the <tt>@Listeners</tt> annotation.

<!------------------------------------
  TEST SUCCESS
  ------------------------------------>

<h3><a class="section" indent="." name="test-results">Test results</a></h3>


<h4><a class="section" indent=".." name="success-failure">Success, failure and assert</a></h4>


<p>A test is considered successful if it completed without throwing any 
exception or if&nbsp; it threw an exception that was expected (see the 
documentation for the <tt>expectedExceptions</tt> attribute found on the <tt>@Test</tt> annotation).
</p>

<p>Your test methods will typically be made of calls that can throw an 
exception, or of various assertions (using the Java &quot;assert&quot; keyword).&nbsp; An 
&quot;assert&quot; failing will trigger an AssertionErrorException, which in turn will 
mark the method as failed (remember to use -ea on the JVM if you are not seeing 
the assertion errors).</p><p>Here is an example test method:</p>

<pre class="brush: java">
@Test
public void verifyLastName() {
  assert "Beust".equals(m_lastName) : "Expected name Beust, for" + m_lastName;
}
</pre>

TestNG also include JUnit's Assert class, which lets you perform 
assertions on complex objects:

<pre class="brush: java">
import static org.testng.AssertJUnit.*;
//...
@Test
public void verify() {
  assertEquals("Beust", m_lastName);
}
</pre>
<p>Note that the above code use a static import in order to be able to use the
<tt>assertEquals</tt> method without having to prefix it by its class.

<!-------------------------------------
  LOGGING
  ------------------------------------>
</p>

<h4><a class="section" indent=".." name="logging">Logging and results</a></h4>

The results of the test run are created in a file called <tt>index.html</tt> in the 
directory specified when launching SuiteRunner.&nbsp; This file points to 
various other HTML and text files that contain the result of the entire test 
run.&nbsp; You can see a typical example
<a href="http://testng.org/test-output/index.html">here</a>.

<p>
It's very easy to generate your own reports with TestNG with Listeners and Reporters:

<ul>
<li><b>Listeners</b> implement the interface <a href="../javadocs/org/testng/ITestListener.html"><tt>org.testng.ITestListener</tt></a> and are notified in real time of when a test starts, passes, fails, etc...</li><li><b>Reporters</b> implement the interface <a href="../javadocs/org/testng/IReporter.html"><tt>org.testng.IReporter</tt></a> and are notified when all the suites have been run by TestNG.  The IReporter instance receives a list of objects that describe the entire test run.</li></ul>For example, if you want to generate a PDF report of your test run, you don't need to be notified in real time of the test run so you should probably use an <tt>IReporter</tt>.  If you'd like to write a real-time reporting of your tests, such as a GUI with a progress bar or a text reporter displaying dots (".") as each test is invoked (as is explained below), <tt>ITestListener</tt> is your best choice.

<h5><a class="section" indent="..." name="logging-listeners">Logging Listeners</a></h5>

Here is a listener that displays a "." for each passed test, a "F" for each failure and a "S" for each skip:

<pre class="brush: java">
public class DotTestListener extends TestListenerAdapter {
  private int m_count = 0;

  @Override
  public void onTestFailure(ITestResult tr) {
    log("F");
  }

  @Override
  public void onTestSkipped(ITestResult tr) {
    log("S");
  }

  @Override
  public void onTestSuccess(ITestResult tr) {
    log(".");
  }

  private void log(String string) {
    System.out.print(string);
    if (++m_count % 40 == 0) {
      System.out.println("");
    }
  }
} 
</pre>

In this example, I chose to extend <a href="../javadocs/org/testng/TestListenerAdapter.html"><tt>TestListenerAdapter</tt></a>, which implements <a href="../javadocs/org/testng/ITestListener.html"><tt>ITestListener</tt></a> with empty methods, so I don't have to override other methods from the interface that I have no interest in.  You can implement the interface directly if you prefer.

<p>
Here is how I invoke TestNG to use this new listener:

<h3 class="sourcetitle">Shell</h3>
<pre class="brush: text">
java -classpath testng.jar;%CLASSPATH% org.testng.TestNG -listener org.testng.reporters.DotTestListener test\testng.xml
</pre>

and the output:

<p>

<h3 class="sourcetitle">Shell</h3>
<pre class="brush: text">
........................................
........................................
........................................
........................................
........................................
.........................
===============================================
TestNG JDK 1.5
Total tests run: 226, Failures: 0, Skips: 0
===============================================
</pre>

Note that when you use <tt>-listener</tt>, TestNG will automatically determine the type of listener you want to use.

<h5><a class="section" indent="..." name="logging-reporters">Logging Reporters</a></h5>

The <a href="../javadocs/org/testng/IReporter.html"><tt>org.testng.IReporter</tt></a> interface only has one method:

<pre class="brush: java">
public void generateReport(List&lt;ISuite</a>&gt; suites, String outputDirectory)
</pre>

This method will be invoked by TestNG when all the suites have been run and you can inspect its parameters to access all the information on the run that was just completed.

<p>

<h5><a class="section" indent="..." name="logging-junitreports">JUnitReports</a></h5>

<p>


TestNG contains a listener that takes the TestNG results 
and outputs an XML file that can then be fed to JUnitReport.  <a href="http://testng.org/test-report/junit-noframes.html">
Here</a> is an example, and the ant task to create this report:

<h3 class="sourcetitle">build.xml</h3>
<pre class="brush: xml">
&lt;target name="reports"&gt;
  &lt;junitreport todir="test-report"&gt;
    &lt;fileset dir="test-output"&gt;
      &lt;include name="*/*.xml"/&gt;
    &lt;/fileset&gt;
 
    &lt;report format="noframes"  todir="test-report"/&gt;
  &lt;/junitreport&gt;
&lt;/target&gt;
</pre>
<blockquote>
	<em>Note:&nbsp; a current incompatibility between the JDK 1.5 and JUnitReports 
prevents the frame version from working, so you need to specify &quot;noframes&quot; to 
get this to work for now.</em>
	</blockquote>

<h5><a class="section" indent="..." name="logging-reporter-api">Reporter API</a></h5>

<p>
If you need to log messages that should appear in the generated HTML reports, you can use the class <tt><a href="../javadocs/org/testng/Reporter.html">org.testng.Reporter</a></tt>:

<blockquote class="brush: text">
<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">Reporter.log</font><font color="#000000">(</font><font color="#2a00ff">&#34;M3 WAS CALLED&#34;</font><font color="#000000">)</font><font color="#000000">;</font>

</blockquote>

<p align="center">

<img src="pics/show-output1.png" />
<img src="pics/show-output2.png" />

</p>

<h5><a class="section" indent="..." name="logging-xml-reports">XML Reports</a></h5>

<p>
TestNG offers an XML reporter capturing TestNG specific information that is not available in JUnit reports. This is particulary useful when the user's test environment needs to consume XML results with TestNG-specific data that the JUnit format can't provide.  Below is a sample of the output of such a reporter:
</p>

<pre class="brush: xml">
&lt;testng-results&gt;
  &lt;suite name=&quot;Suite1&quot;&gt;
    &lt;groups&gt;
      &lt;group name=&quot;group1&quot;&gt;
        &lt;method signature=&quot;com.test.TestOne.test2()&quot; name=&quot;test2&quot; class=&quot;com.test.TestOne&quot;/&gt;
        &lt;method signature=&quot;com.test.TestOne.test1()&quot; name=&quot;test1&quot; class=&quot;com.test.TestOne&quot;/&gt;
      &lt;/group&gt;
      &lt;group name=&quot;group2&quot;&gt;
        &lt;method signature=&quot;com.test.TestOne.test2()&quot; name=&quot;test2&quot; class=&quot;com.test.TestOne&quot;/&gt;
      &lt;/group&gt;
    &lt;/groups&gt;
    &lt;test name=&quot;test1&quot;&gt;
      &lt;class name=&quot;com.test.TestOne&quot;&gt;
        &lt;test-method status=&quot;FAIL&quot; signature=&quot;test1()&quot; name=&quot;test1&quot; duration-ms=&quot;0&quot;
              started-at=&quot;2007-05-28T12:14:37Z&quot; description=&quot;someDescription2&quot;
              finished-at=&quot;2007-05-28T12:14:37Z&quot;&gt;
          &lt;exception class=&quot;java.lang.AssertionError&quot;&gt;
            &lt;short-stacktrace&gt;
              &lt;![CDATA[
                java.lang.AssertionError
                ... Removed 22 stack frames
              ]]&gt;
            &lt;/short-stacktrace&gt;
          &lt;/exception&gt;
        &lt;/test-method&gt;
        &lt;test-method status=&quot;PASS&quot; signature=&quot;test2()&quot; name=&quot;test2&quot; duration-ms=&quot;0&quot;
              started-at=&quot;2007-05-28T12:14:37Z&quot; description=&quot;someDescription1&quot;
              finished-at=&quot;2007-05-28T12:14:37Z&quot;&gt;
        &lt;/test-method&gt;
        &lt;test-method status=&quot;PASS&quot; signature=&quot;setUp()&quot; name=&quot;setUp&quot; is-config=&quot;true&quot; duration-ms=&quot;15&quot;
              started-at=&quot;2007-05-28T12:14:37Z&quot; finished-at=&quot;2007-05-28T12:14:37Z&quot;&gt;
        &lt;/test-method&gt;
      &lt;/class&gt;
    &lt;/test&gt;
  &lt;/suite&gt;
&lt;/testng-results&gt;
</pre>
<p>This reporter is injected along with the other default listeners so you can get this type of output by default. The listener provides some properties that can tweak the reporter to fit your needs. The following table contains a list of these properties with a short explanation:
</p>
<table border="1" width="100%" id="table6">
  <tr>
    <th>Property</th>
    <th>Comment</th>
    <th>Default value</th>
  </tr>
  <tr>
    <td>outputDirectory</td>
    <td>A <tt>String</tt> indicating the directory where should the XML files be outputed.</td>
    <td>The TestNG output directory</td>
  </tr>
  <tr>
    <td>timestampFormat</td>
    <td>Specifies the format of date fields that are generated by this reporter</td>
    <td>yyyy-MM-dd'T'HH:mm:ss'Z'</td>
  </tr>
  <tr>
    <td>fileFragmentationLevel</td>
    <td>An integer having the values 1, 2 or 3, indicating the way that the XML files are generated:
      <br>
<pre>
   1 - will generate all the results in one file.
   2 - each suite is generated in a separate XML file that is linked to the main file.
   3 - same as 2 plus separate files for test-cases that are referenced from the suite files.
</pre>
    </td>
    <td>1</td>
  </tr>
  <tr>
    <td>splitClassAndPackageNames</td>
    <td>This boolean specifies the way that class names are generated for the <tt>&lt;class&gt;</tt> element.
      For example, you will get <tt>&lt;class class="com.test.MyTest"&gt;</tt> for false and <tt>&lt;class class="MyTest" package="com.test"&gt;</tt> for true.
    </td>
    <td>false</td>
  </tr>
  <tr>
    <td>generateGroupsAttribute</td>
    <td>A boolean indicating if a <tt>groups</tt> attribute should be generated for the <tt>&lt;test-method&gt;</tt> element. This feature aims at providing a
      straight-forward method of retrieving the groups that include a test method without having to surf through the <tt>&lt;group&gt;</tt> elements.
    </td>
    <td>false</td>
  </tr>
  <tr>
    <td>generateTestResultAttributes</td>
    <td>
      A boolean indicating if an <tt>&lt;attributes&gt;</tt> tag should be generated for each <tt>&lt;test-method&gt;</tt> element, containing the test result
      attributes (See <tt>ITestResult.setAttribute()</tt> about setting test result attributes). Each attribute <tt>toString()</tt> representation will be
      written in a <tt>&lt;attribute name="[attribute name]"&gt;</tt> tag.
    </td>
    <td>false</td>
  </tr>
  <tr>
    <td>stackTraceOutputMethod</td>
    <td>Specifies the type of stack trace that is to be generated for exceptions and has the following values:
         <br>
<pre>
   0 - no stacktrace (just Exception class and message).
   1 - a short version of the stack trace keeping just a few lines from the top
   2 - the complete stacktrace with all the inner exceptions
   3 - both short and long stacktrace
</pre>
    </td>
    <td>2</td>
  </tr>
  <tr>
    <td>generateDependsOnMethods</td>
    <td>Use this attribute to enable/disable the generation of a <tt>depends-on-methods</tt> attribute for the <tt>&lt;test-method&gt;</tt> element.
    </td>
    <td>true</td>
  </tr>
  <tr>
    <td>generateDependsOnGroups</td>
    <td>Enable/disable the generation of a <tt>depends-on-groups</tt> attribute for the <tt>&lt;test-method&gt;</tt> element.
    </td>
    <td>true</td>
  </tr>
</table>
<p>
  In order to configure this reporter you can use the <tt>-reporter</tt> option in the command line or the <a href="http://testng.org/doc/ant.html">Ant</a>
  task with the nested <tt>&lt;reporter&gt;</tt> element. For each of these you must specify the class <tt>org.testng.reporters.XMLReporter</tt>.
  Please note that you cannot configure the built-in reporter because this one will only use default settings. If you need just the XML report with custom settings
  you will have to add it manually with one of the two methods and disable the default listeners.
</p>

<!------------------------------------
  YAML
  ------------------------------------>

<h3><a class="section" name="yaml">YAML</a></h3>

TestNG supports <a href="http://www.yaml.org/">YAML</a> as an alternate way of specifying your suite file. For example, the following XML file:

<pre class="brush: xml">
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >

<suite name="SingleSuite" verbose="2" thread-count="4" >

  &lt;parameter name="n" value="42" /&gt;

  <test name="Regression2">
    <groups>
      <run>
        &lt;exclude name="broken" /&gt;
      </run>
    </groups>

    <classes>
      &lt;class name="test.listeners.ResultEndMillisTest" /&gt;
    </classes>
  </test>
</suite>
</pre>
<p>and here is its YAML version:</p>
<pre class="brush: plain">
name: SingleSuite
threadCount: 4
parameters: { n: 42 }

tests:
  - name: Regression2
    parameters: { count: 10 }
    excludedGroups: [ broken ]
    classes:
      - test.listeners.ResultEndMillisTest
</pre>

Here is <a href="https://github.com/cbeust/testng/blob/master/src/test/resources/testng.xml">TestNG's own suite file</a>, and its <a href="https://github.com/cbeust/testng/blob/master/src/test/resources/testng.yaml">YAML counterpart</a>.

<p>

You might find the YAML file format easier to read and to maintain. YAML files are also recognized by the TestNG Eclipse plug-in. You can find more information about YAML and TestNG in this <a href="http://beust.com/weblog/2010/08/15/yaml-the-forgotten-victim-of-the-format-wars/">blog post</a>.


<!---------------------------------------------------------------------->

<a name="testng-dtd">
&nbsp;<hr width="100%">
<p>Back to my <a href="http://beust.com/weblog">home page</a>.</p><p>Or check out some of my other projects:</p><ul>
	<li><a href="http://beust.com/ejbgen">EJBGen</a>:&nbsp; an EJB tag 
	generator.</li><li><a href="http://testng.org">TestNG</a>:&nbsp; A testing framework using annotations, test groups and method parameters. </li><li><a href="http://beust.com/doclipse">Doclipse</a>:&nbsp; a JavaDoc tag 
	Eclipse plug-in.</li><li><a href="http://beust.com/j15">J15</a>:&nbsp; an Eclipse plug-in to help 
	you migrate your code to the new JDK 1.5 constructs.</li><li><a href="http://beust.com/sgen">SGen</a>:&nbsp; a replacement for 
	XDoclet with an easy plug-in architecture.</li><li><a href="http://beust.com/canvas">Canvas</a>:&nbsp; a template generator 
	based on the Groovy language.</li></ul><p>
</p>

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>
	
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/book.html�������������������������������������������������������������������������0000644�0001750�0001750�00000007615�12732165123�015017� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
   <head>
       <title>Next Generation Java Testing</title>

       <link rel="stylesheet" href="testng.css" type="text/css" />
       <link type="text/css" rel="stylesheet" href="http://beust.com/beust.css"  />
       <script type="text/javascript" src="http://beust.com/prettify.js"></script>
       <script type="text/javascript" src="http://testng.org/doc/banner.js"></script>
     </head>

<body onload="prettyPrint()">

<script type="text/javascript">
   displayMenu("book.html");
</script>


<p align="center">
<a href="http://www.amazon.com/Next-Generation-Java-Testing-Advanced/dp/0321503104/ref=pd_bbs_sr_1/104-7105897-1187923?ie=UTF8&s=books&qid=1193417110&sr=8-1">
<img border="0" src="http://beust.com/pics/book-cover.jpg" />
</a>
</p>

Our book is now <a href="http://www.amazon.com/Next-Generation-Java-Testing-Advanced/dp/0321503104/ref=pd_bbs_sr_1/104-7105897-1187923?ie=UTF8&s=books&qid=1193417110&sr=8-1">available from Amazon</a> and various other retail stores (check out <a href="book-toc.html">the table of contents</a>).

<P>

<b>Book Description</b><br>
 <p>Enterprise Java developers must achieve broader, deeper test coverage, going beyond unit testing to implement functional and integration testing with systematic acceptance. <b><i>Next Generation Java Testing</i></b> introduces breakthrough Java testing techniques and TestNG, a powerful open source Java testing platform.</p><p>Cdric Beust, TestNG's creator, and leading Java developer Hani Suleiman, present powerful, flexible testing patterns that will work with virtually any testing tool, framework, or language. They show how to leverage key Java platform improvements designed to facilitate effective testing, such as dependency injection and mock objects. They also thoroughly introduce TestNG, demonstrating how it overcomes the limitations of older frameworks and enables new techniques, making it far easier to test today's complex software systems.</p><p>Pragmatic and results-focused, <b><i>Next Generation Java Testing</i></b> will help Java developers build more robust!
 code for today's mission-critical environments.</p><p>This book</p><ul><li>Illuminates the tradeoffs associated with testing, so you can make better decisions about what and how to test</li><li>Introduces TestNG, explains its goals and features, and shows how to apply them in real-world environments</li><li>Shows how to integrate TestNG with your existing code, development frameworks, and software libraries </li><li>Demonstrates how to test crucial code features, such as encapsulation, state sharing, scopes, and thread safety</li><li>Shows how to test application elements, including JavaEE APIs, databases, Web pages, and XML files </li><li>Presents advanced techniques: testing partial failures, factories, dependent testing, remote invocation, cluster-based test farms, and more</li><li>Walks through installing and using TestNG plug-ins for Eclipse, and IDEA</li><li>Contains extensive code examples</li></ul><p>Whether you use TestNG, JUnit, or another testing framework, the !
 testing design patterns presented in this book will show you how to im
prove your tests by giving you concrete advice on how to make your code and your design more testable.</p>


<br><br>
     <b>About the Author</b><br>
 <p><b>Cdric Beust,</b> a senior software engineer at Google, is an active member of the Java Community Process who has been extensively involved in the development of the latest Java release. He is the creator and main contributor to the TestNG project.</p><p><b>Hani Suleiman</b> is CTO of Formicary, a consulting and portal company specializing in financial applications. He is one of two individual members who has been elected to the Executive Committee of the Java Community Process.</p>



<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>


</body>

</html>
 �������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/download.html���������������������������������������������������������������������0000644�0001750�0001750�00000010032�12732165123�015657� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
    <head>
        <title>TestNG - Download Current Release and Beta Versions</title>

        <link rel="stylesheet" href="testng.css" type="text/css" />
        <link type="text/css" rel="stylesheet" href="http://beust.com/beust.css"  />
        <script type="text/javascript" src="banner.js"></script>

      <script type="text/javascript" src="http://beust.com/scripts/shCore.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushJava.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushXml.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushBash.js"></script>
      <script type="text/javascript" src="http://beust.com/scripts/shBrushPlain.js"></script>
      <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shCore.css"/>
      <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shThemeCedric.css"/>
      <script type="text/javascript">
        SyntaxHighlighter.config.clipboardSwf = 'scripts/clipboard.swf';
        SyntaxHighlighter.defaults['gutter'] = false;
        SyntaxHighlighter.all();
      </script>
      <script type="text/javascript" src="http://beust.com/toc.js"></script>

        <style type="text/css">
            /* Set the command-line table option column width. */
            #command-line colgroup.option {
                 width: 7em;
            }
        </style
      </head>
<body onload="prettyPrint()">

<script type="text/javascript">
    displayMenu("download.html")
</script>


<h2 align="center">Downloading TestNG</h2>

<h3>Current Release Version</h3>

<h4>Maven</h4>

<pre class="brush: xml">
    &lt;repositories&gt;
      &lt;repository&gt;
        &lt;id&gt;central&lt;/id&gt;
        &lt;name&gt;bintray&lt;/name&gt;
        &lt;url&gt;http://jcenter.bintray.com&lt;/url&gt;
      &lt;/repository&gt;
    &lt;/repositories&gt;

    &lt;dependency&gt;
      &lt;groupId&gt;org.testng&lt;/groupId&gt;
      &lt;artifactId&gt;testng&lt;/artifactId&gt;
      &lt;version&gt;6.9.10&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
</pre>

<h4>Gradle</h4>

<pre class="brush: java">
repositories {
    jcenter()
}

dependencies {
    testCompile 'org.testng:testng:6.9.10'
}
</pre>

<h3>Snapshots</h3>

TestNG <a href="https://oss.sonatype.org/content/repositories/snapshots/org/testng/testng/">automatically uploads snapshots to Sonatype</a> which you can access by adding the following repository:

<pre class="brush: java">
repositories {
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots'
    }
}
</pre>

<h3>Eclipse plug-in</h3>
<p>You can use either the Eclipse Market Place or the update site:</p>
<ul>
	<li>Select<i> Help / Install new software.</i> 
	</li>
	<li><i>Search for new features to install.</i> 
	</li>
	<li><i>New remote site.</i> 
	</li>
	<li>For Eclipse 3.4 and above, enter <a href="http://beust.com/eclipse">http://beust.com/eclipse</a>.
	<li>For Eclipse 3.3 and below, enter <a href="http://beust.com/eclipse1">http://beust.com/eclipse1</a>.
	</li>
	<li>Make sure the check box next to URL is checked and click <i>Next</i>. 
	</li>
	<li>Eclipse will then guide you through the process. </li>
</ul>

<p>You can also install older versions of the plug-ins <a href="http://beust.com/eclipse-old">here</a>. Note that the URL's on this page are update sites as well, not direct download links.

<p>TestNG is also <a href="http://github.com/cbeust/testng">hosted on GitHub</a>, where you can download the source and build the distribution yourself:

<pre class="brush: plain">
$ git clone git://github.com/cbeust/testng.git
$ cd testng
$ mvn package
</pre>

<p>You will then find the jar file in the <tt>target</tt> directory</p>

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>


</body>

</html>
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/ant.html��������������������������������������������������������������������������0000644�0001750�0001750�00000034024�12732165123�014641� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
    <head>
        <title>TestNG - Ant</title>

        <link rel="stylesheet" href="testng.css" type="text/css" />
        <link type="text/css" rel="stylesheet" href="http://beust.com/beust.css"  />
        <script type="text/javascript" src="http://beust.com/prettify.js"></script>
        <script type="text/javascript" src="banner.js"></script>

        <script type="text/javascript" src="http://beust.com/scripts/shCore.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushJava.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushXml.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushBash.js"></script>
        <script type="text/javascript" src="http://beust.com/scripts/shBrushPlain.js"></script>
        <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shCore.css"/>
        <link type="text/css" rel="stylesheet" href="http://beust.com/styles/shThemeCedric.css"/>
        <script type="text/javascript">
          SyntaxHighlighter.config.clipboardSwf = 'scripts/clipboard.swf';
          SyntaxHighlighter.defaults['gutter'] = false;
          SyntaxHighlighter.all();
        </script>

</head>

<body onLoad="prettyPrint()">

<script type="text/javascript">
    displayMenu("ant.html")
</script>

<h2 align="center">TestNG Ant Task</h2>
<p>You define the TestNG ant task as follows:</p>

<pre class="brush: xml">
&lt;taskdef resource="testngtasks" classpath="testng.jar"/&gt;
</pre>

This task runs TestNG tests and is always run in a forked JVM.&nbsp; It 
accepts the following attributes: <br>
&nbsp;<table border="2" id="table1">
	<tr>
		<th>Attribute </th>
		<th>Description </th>
		<th>Required </th>
	</tr>
	<tr>
		<td><tt>classfilesetref</tt> </td>
		<td>A reference to a
		<a href="http://ant.apache.org/manual/Types/resources.html#collection">ResourceCollection</a>
		containing the test classes to be run. Only File based
                <a href="http://ant.apache.org/manual/Types/resources.html#collection">ResourceCollection</a>s
                are supported (ie. <a href="http://ant.apache.org/manual/Types/fileset.html">FileSet</a>).</td>
		<td>&nbsp; </td>
	</tr>
	<tr>
		<td><tt>classpath</tt> </td>
		<td>A PATH-like structure for the tests to be run. </td>
		<td>&nbsp; </td>
	</tr>
	<tr>
		<td><tt>classpathref</tt> </td>
		<td>A reference to a PATH-like structure for the tests to be run. </td>
		<td>&nbsp; </td>
	</tr>
	<tr>
		<td><tt>configFailurePolicy</tt> </td>
		<td>Whether TestNG should <tt>continue</tt> to execute the remaining tests in the suite or <tt>skip</tt> them if an @Before* method fails.</td>
		<td>No. Defaults to <tt>skip</tt></td>
	</tr>
	<tr>
		<td><tt>dataProviderThreadCount</tt> </td>
		<td>The number of threads to use for data providers
		for this run. Ignored unless the parallel mode is also specified</td>
		<td>1</td>
	</tr>
	<tr>
		<td><tt>delegateCommandSystemProperties</tt> </td>
		<td>Pass the command line properties as system properties.</td>
		<td>No. Defaults to false </td>
	</tr>
	<tr>
		<td><tt>dumpCommand</tt> </td>
		<td>Print the TestNG launcher command. </td>
		<td>No. Defaults to false </td>
	</tr>
	<tr>
		<td><tt>failureProperty</tt> </td>
		<td>The name of a property to set in the event of a failure. It is used 
		only if the <tt>haltonfailure</tt> is not set. </td>
		<td>No.</td>
	</tr>
	<tr>
		<td><tt>haltonfailure</tt> </td>
		<td>Stop the build process if a failure has occurred during the test 
		run. </td>
		<td>No. Defaults to false 
		</td>
		<td>&nbsp;</td>
	</tr>
	<tr>
		<td><tt>haltonskipped</tt> </td>
		<td>Stop the build process if there is at least on skipped test. </td>
		<td>No. Default to false </td>
	</tr>
	<tr>
	  <td><tt>groups</tt></td>
	  <td>
   	The list of groups to run, separated by spaces or commas.</td>
	  <td>
   	</td>
	</tr>
	<tr>
	  <td><tt>excludedgroups</tt></td>
	  <td>
   	The list of groups to exclude, separated by spaces or commas</td>
	  <td>
   	</td>
	</tr>
	<tr>
		<td><tt>jvm</tt></td>
		<td>The JVM to use, which will be run by <tt>Runtime.exec()</tt></td>
		<td><tt>java</tt></td>
	</tr>
	<tr>
		<td><tt>listeners</tt></td>
		<td>A comma or space-separated list of fully qualified classes that are TestNG listeners (for example<tt>
		<a href="http://testng.org/javadocs/org/testng/ITestListener.html">
		org.testng.ITestListener</a></tt> or <tt>
		<a href="http://testng.org/javadocs/org/testng/IReporter.html">
		org.testng.IReporter</a>)</tt></td>
		<td>No.</td>
	</tr>

        <tr>
		<td><tt>methods</tt></td>
		<td>A comma separated list of fully qualified class name and method. For example <tt>com.example.Foo.f1,com.example.Bar.f2</tt>.</td>
		<td>No.</td>
        </tr>

        <tr>
		<td><tt>mode</tt></td>
                <td>Either <tt>"testng"</tt>, <tt>"junit"</tt> or <tt>"mixed"</tt>. Whether TestNG should run only TestNG tests, JUnit tests or both.</td>
		<td>No. Defaults to "testng".</td>
        </tr>

	<tr>
		<td><tt>outputdir</tt> </td>
		<td>Directory for reports output. 
		</td>
		<td>No. Defaults to <tt>test-output</tt>. </td>
	</tr>
	<tr>
		<td><tt>skippedProperty</tt> </td>
		<td>The name of a property to set in the event of a skipped test. It is 
		used only if the <tt>haltonskipped</tt> is not set. </td>
		<td>No. </td>
	</tr>
	<tr>
		<td><tt>suiteRunnerClass</tt> </td>
		<td>A fully qualified name of a TestNG starter. </td>
		<td>
		<p align="left">No.&nbsp; Defaults to <tt>
		<a href="http://testng.org/javadocs/org/testng/TestNG.html">org.testng.TestNG</a> </tt></td>
	</tr>
	
	<tr>
		<td><tt>suiteThreadPoolSize</tt> </td>
		<td>The size of a thread pool to run suites.</td>
		<td>
		<p align="left">No.&nbsp; Defaults to 1.</td>
	</tr>

	<tr>
		<td><tt>parallel</tt> </td>
		<td>The parallel mode to use for running the tests - either methods or tests</td>
		<td>No - if not present, parallel mode will not be selected</td>
	</tr>

	<tr>
		<td><tt>suitename</tt> </td>
		<td>Sets the default name of the test suite, if one is not specified in a suite xml file or in the source code</td>
		<td>No. Defaults to "Ant suite"</td>
	</tr>

	<tr>
		<td><tt>testJar</tt> </td>
		<td>Path to a jar containing tests and a suite definition. </td>
		<td>&nbsp;</td>
	</tr>

	<tr>
		<td><tt>testname</tt> </td>
		<td>Sets the default name of the test, if one is not specified in a suite xml file or in the source code</td>
		<td>No. defaults to "Ant test"</td>
	</tr>

	<tr>
		<td><tt>testnames</tt> </td>
		<td>A comma separated list of test names, as defined
		in the &lt;test&gt; tag. Only these tests will be run.</td>
		<td>No. defaults to "Ant test"</td>
	</tr>

	<tr>
		<td><tt>threadCount</tt> </td>
		<td>The number of threads to use for this run. Ignored unless the parallel mode is also specified</td>
		<td>1</td>
	</tr>

	<tr>
		<td><tt>timeOut</tt></td>
		<td>The maximum time out in milliseconds that all the tests should run 
		under.</td>
		<td>&nbsp;</td>
	</tr>

	<tr>
		<td><tt>useDefaultListeners</tt></td>
		<td>Whether the default listeners and reporters should be used.</td>
		<td>Defaults to true.</td>
	</tr>
	<tr>
		<td><tt>workingDir</tt></td>
		<td>The directory where the ant task should change to before running 
		TestNG.</td>
		<td>&nbsp;</td>
	</tr>
	<tr>
		<td><tt>xmlfilesetref</tt> </td>
		<td>A reference to a
		<a href="http://ant.apache.org/manual/Types/resources.html#collection">ResourceCollection</a>
		containing the suite definitions to be run. Only File based
                <a href="http://ant.apache.org/manual/Types/resources.html#collection">ResourceCollection</a>s
                are supported (ie. <a href="http://ant.apache.org/manual/Types/fileset.html">FileSet</a>).</td>
		<td>&nbsp; </td>
	</tr>

	<tr>
		<td><tt>xmlPathInJar</tt></td>
		<td>The path of the XML file inside the jar file, only applicable if <tt>testJar</tt> was specified</td>
		<td>testng.xml</td>
	</tr>
</table>
<br>
One of attributes <tt>classpath</tt>, <tt>classpathref</tt> or nested <tt>
&lt;classpath&gt;</tt> must be used for providing the tests classpath. 
<p>One of the attributes <tt>xmlfilesetref</tt>, <tt>classfilesetref</tt> or 
nested <tt>&lt;xmlfileset&gt;</tt>, respectively <tt>&lt;classfileset&gt;</tt> must be used 
for providing the tests. </p>

<h3>TestNG modes</h3>
<p>The TestNG mode gets applied when tests are passed to TestNG using <tt>classfilesetref</tt>, <tt>methods</tt>
or nested <tt>&lt;classfileset&gt;</tt> and tells TestNG what kind of
tests it should look for and run:

<ul>
  <li><tt>"testng"</tt>: find and run TestNG tests.
  <li><tt>"junit"</tt>: find and run JUnit tests.
  <li><tt>"mixed"</tt>: run both TestNG and JUnit tests.
</ul>

<p><em>Note</em>: <tt>"junit"</tt> and <tt>"mixed"</tt> modes require the JUnit jar file on the classpath.</p>

<h3><a name="nested">Nested Elements</a></h3>
<h4>classpath</h4>
<p>The <tt>&lt;testng&gt;</tt> task supports a nested <tt>&lt;classpath&gt;</tt> element 
that represents a <em>PATH</em>-like structure. </p>
<h4>bootclasspath</h4>
<p>The location of bootstrap class files can be specified using this <em>
PATH-like</em> structure - will be ignored if <tt>fork </tt>is not set. </p>
<h4>xmlfileset</h4>
<p>The suite definitions (<tt>testng.xml</tt>) can be passed to the task with a
<tt><a href="http://ant.apache.org/manual/Types/fileset.html">FileSet</a></tt>
structure. </p>
<h4>classfileset</h4>
<p>TestNG can also run directly on classes, also supplied with a <tt>
<a href="http://ant.apache.org/manual/Types/fileset.html">FileSet</a></tt>
structure.</p>
<h4>jvmarg</h4>
<p>Additional parameters may be passed to the new VM via nested <tt>&lt;jvmarg&gt;</tt> 
elements. For example: </p>

<pre class="brush: xml">
&lt;testng&gt;
   &lt;jvmarg value="-Djava.compiler=NONE" /&gt;
   &lt;!-- ... --&gt;
&lt;/testng&gt;
</pre>

<h4>sysproperty</h4>
<p>Use nested <tt>&lt;sysproperty&gt;</tt> elements to specify system properties 
required by the class. These properties will be made available to the virtual 
machine during the execution of the test. The attributes for this element are 
the same as for <em>environment variables</em>:</p>

<pre class="brush: xml">
&lt;testng&gt;
   &lt;sysproperty key="basedir" value="${basedir}"/&gt;
   &lt;!-- ... --&gt;
&lt;/testng&gt;
</pre>

<p>will run the test and make the <code>basedir</code> property 
available to the test.</p>

<h4>propertyset</h4>
<p>You may also use a nested <tt>&lt;propertyset&gt;</tt> element to specify a set of system properties that are defined 
outside of the TestNG ant task. This allows for more flexible definitions of system properties, for instance selecting
all properties with a specific prefix or matching a regex. See the 
<a href="http://ant.apache.org/manual/Types/propertyset.html">PropertySet page</a> in the 
<a href="http://ant.apache.org/manual/">Ant manual</a> for full details. Here's a simple example:</p>
<pre class="brush: xml">
      &lt;property name="myprop1" value="value 1"/&gt;
      &lt;property name="myprop2" value="value 2"/>
	
      &lt;propertyset id="propset1"&gt;
          &lt;propertyref name="myprop1"/&gt;
          &lt;propertyref name="myprop2"/&gt;
      &lt;/propertyset&gt;

      &lt;testng outputdir="${testng.report.dir}" classpathref="run.cp"&gt;
          &lt;xmlfileset dir="${test15.dir}" includes="testng-single3.xml"/&gt;
          &lt;propertyset refid="propset1"/&gt;
      &lt;/testng&gt;
</pre>
<p>In this case, the system properties named "myprop1" and "myprop2" are passed along to the TestNG process.</p>

<h4>reporter</h4>
<p>An inner <tt>&lt;reporter&gt;</tt> element is an alternative way to inject a
custom report listener allowing the user to set custom properties in order to fine-tune
the behavior of the reporter at run-time.
<br>
The element has one <tt>classname</tt> attribute which is mandatory, indicating
the class of the custom listener. In order to set the properties of the reporter, the
<tt>&lt;reporter&gt;</tt> element can contain several nested <tt>&lt;property&gt;</tt>
elements which will provide the <tt>name</tt> and <tt>value</tt> attributes as seen below:
</p>
<pre class="brush: xml">
&lt;testng ...&gt;
   ...
   &lt;reporter classname="com.test.MyReporter"&gt;
      &lt;property name="methodFilter" value="*insert*"/&gt;
      &lt;property name="enableFiltering" value="true"/&gt;
   &lt;/reporter&gt;
   ...
&lt;/testng&gt;
</pre>
<pre class="brush: java">
public class MyReporter {

  public String getMethodFilter() {...}
  public void setMethodFilter(String methodFilter) {...}
  public boolean isEnableFiltering() {...}
  public void setEnableFiltering(boolean enableFiltering) {...}
  ...
}
</pre>
You have to consider though that for the moment only a limited set of property types are supported:
<tt>String, int, boolean, byte, char, double, float, long, short</tt>.

<h4>env</h4>
<p>It is possible to specify environment variables to pass to the TestNG forked 
virtual machine via nested <tt>&lt;env&gt;</tt> elements. For a description of the <tt>
&lt;env&gt;</tt> element's attributes, see the description in the <em>
<a href="http://ant.apache.org/manual/CoreTasks/exec.html">exec</a></em> task.</p>
<h3>Examples</h3>
<h4>Suite xml</h4>

<pre class="brush: text">
&lt;testng classpathref="run.cp"
        outputDir="${testng.report.dir}"
        sourcedir="${test.src.dir}"
        haltOnfailure="true"&gt;
 
   &lt;xmlfileset dir="${test14.dir}" includes="testng.xml"/&gt;
&lt;/testng&gt;
</pre>

<h4>Class FileSet</h4>
<pre class="brush: xml">
&lt;testng classpathref="run.cp"
		outputDir="${testng.report.dir}"
		haltOnFailure="true" verbose="2"&gt;
	&lt;classfileset dir="${test.build.dir}" includes="**/*.class" /&gt;
&lt;/testng&gt;
</pre>

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>

</body>

</html>
������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/prettify.css����������������������������������������������������������������������0000644�0001750�0001750�00000001206�12732165123�015545� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.prettyprint .kwd, .tag {
  font-weight: bold;
  color: #7f0055;
}

.prettyprint .str,.atv {
  color: #0000cc;
}

.prettyprint .com {
  color: #008800;
}

.prettyprint .lit {
  color: #cc2222;
  font-weight: bold;
}


pre.prettyprint { padding: 2px; border: 1px solid #888; }

@media print {
  .str { color: #060; }
  .kwd { color: #006; font-weight: bold; }
  .com { color: #600; font-style: italic; }
  .typ { color: #404; font-weight: bold; }
  .lit { color: #044; }
  .pun { color: #440; }
  .pln { color: #000; }
  .tag { color: #006; font-weight: bold; }
  .atn { color: #404; }
  .atv { color: #060; }
}

������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/book-toc.html���������������������������������������������������������������������0000644�0001750�0001750�00000241656�12732165123�015607� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><META http-equiv="Content-Type" content="text/html; charset=utf-8"><style type="text/css" media="print">.hide{display:none}</style></head>


<body style="margin:0;padding:0"><div class="hide">





<div bgcolor="#ffffff" vlink="blue" link="blue">
<table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_1"><b>Page 1</b></a></font></td></tr></table><font size="3" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:1148;left:738">v</div>
</span></font>
<font size="6" face="Times"><span style="font-size:48px;font-family:Times">

<div style="position:absolute;top:355;left:162"><b>Contents</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:512;left:270">Foreword</div>
<div style="position:absolute;top:512;left:730">xiii</div>
<div style="position:absolute;top:530;left:270">Preface</div>
<div style="position:absolute;top:530;left:734">xv</div>
<div style="position:absolute;top:548;left:270">Acknowledgments</div>
<div style="position:absolute;top:548;left:730">xxi</div>
<div style="position:absolute;top:566;left:270">About the Authors</div>

<div style="position:absolute;top:566;left:723">xxiii</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:611;left:162">Chapter 1</div>
<div style="position:absolute;top:611;left:270">Getting Started</div>
<div style="position:absolute;top:611;left:736">1</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:640;left:270">Beyond JUnit 3</div>
<div style="position:absolute;top:640;left:738">3</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:660;left:288">Stateful Classes</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:659;left:738">3</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:676;left:288">Parameters</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:675;left:738">4</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:693;left:288">Base Classes</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:692;left:738">4</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:709;left:288">Exceptions Are Not That Exceptional</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:708;left:738">4</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:726;left:288">Running Tests</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:725;left:738">5</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:743;left:288">Real-World Testing</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:741;left:738">6</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:759;left:288">Configuration Methods</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:758;left:738">6</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:775;left:288">Dependencies</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:774;left:738">6</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:792;left:288">Epiphanies</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:791;left:738">7</div>
<div style="position:absolute;top:808;left:270">JUnit 4</div>
<div style="position:absolute;top:808;left:738">7</div>
<div style="position:absolute;top:828;left:270">Designing for Testability</div>
<div style="position:absolute;top:828;left:738">8</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:847;left:288">Object-Oriented Programming and Encapsulation</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:846;left:738">8</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:864;left:288">The Design Patterns Revolution</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:863;left:738">9</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:880;left:288">Identifying the Enemy</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:879;left:729">10</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:897;left:288">Recommendations</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:896;left:729">16</div>
<div style="position:absolute;top:913;left:270">TestNG</div>
<div style="position:absolute;top:913;left:729">17</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:933;left:288">Annotations</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:932;left:729">17</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:950;left:288">Tests, Suites, and Configuration Annotations</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:948;left:729">18</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:966;left:288">Groups</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:965;left:729">20</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:983;left:288"><b>testng.xml</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:981;left:729">21</div>
<div style="position:absolute;top:999;left:270">Conclusion</div>
<div style="position:absolute;top:999;left:729">21</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:1045;left:162">Chapter 2</div>
<div style="position:absolute;top:1045;left:270">Testing Design Patterns</div>

<div style="position:absolute;top:1045;left:725">23</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1075;left:270">Testing for Failures</div>
<div style="position:absolute;top:1075;left:729">23</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1094;left:288">Reporting Errors</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1093;left:729">24</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1111;left:288">Runtime and Checked Exceptions</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1110;left:729">25</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:202;left:90">Beust.book  Page v  Thursday, August 16, 2007  10:22 AM</div>
</span></font>

<div style="position:absolute;top:1282;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_2"><b>Page 2</b></a></font></td></tr></table></div><font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:1387;left:117">vi</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1390;left:189">Contents</div>
<div style="position:absolute;top:1444;left:243">Testing Whether Your Code Handles Failures Gracefully</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1443;left:684">27</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1460;left:243">When Not to Use <b>expectedExceptions</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:1459;left:684">31</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1477;left:243"><b>testng-failed.xml</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1476;left:684">32</div>
<div style="position:absolute;top:1493;left:225">Factories</div>
<div style="position:absolute;top:1493;left:684">34</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1513;left:243"><b>@Factory</b></div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1512;left:684">35</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1530;left:243"><b>org.testng.ITest</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1528;left:684">38</div>
<div style="position:absolute;top:1546;left:225">Data-Driven Testing</div>
<div style="position:absolute;top:1546;left:684">39</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1565;left:243">Parameters and Test Methods</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1564;left:684">42</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1582;left:243">Passing Parameters with <b>testng.xml</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1581;left:684">44</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1598;left:243">Passing Parameters with <b>@DataProvider</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1597;left:684">47</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1615;left:243">Parameters for Data Providers</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1614;left:684">50</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1631;left:243">The <b>Method </b>Parameter</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1630;left:684">50</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1648;left:243">The <b>ITestContext </b>Parameter</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:1647;left:684">52</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1664;left:243">Lazy Data Providers</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1663;left:684">54</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1681;left:243">Pros and Cons of Both Approaches</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1680;left:684">59</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1697;left:243">Supplying the Data</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1696;left:684">60</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1714;left:243">Data Provider or Factory?</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1713;left:684">62</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1730;left:243">Tying It All Together</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1729;left:684">63</div>
<div style="position:absolute;top:1747;left:225">Asynchronous Testing</div>
<div style="position:absolute;top:1747;left:684">67</div>
<div style="position:absolute;top:1766;left:225">Testing Multithreaded Code</div>
<div style="position:absolute;top:1766;left:684">71</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:1786;left:243">Concurrent Testing</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1785;left:684">72</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1803;left:243"><b>threadPoolSize</b>, <b>invocationCount</b>, and <b>timeOut</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1801;left:684">75</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1819;left:243">Concurrent Running</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1818;left:684">79</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1835;left:243">Turning on the Parallel Bit</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1834;left:684">82</div>
<div style="position:absolute;top:1852;left:225">Performance Testing</div>

<div style="position:absolute;top:1852;left:684">83</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1871;left:243">Algorithm Complexity</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1870;left:684">84</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1888;left:243">Testing Complexity</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1887;left:684">87</div>

<div style="position:absolute;top:1904;left:225">Mocks and Stubs</div>
<div style="position:absolute;top:1904;left:684">90</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1924;left:243">Mocks versus Stubs</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1923;left:684">90</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1940;left:243">Designing for Mockability</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1939;left:684">95</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1957;left:243">Mock Libraries</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1956;left:684">96</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1973;left:243">Selecting the Right Strategy</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:1972;left:684">99</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:1990;left:243">Mock Pitfalls</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:1989;left:675">100</div>
<div style="position:absolute;top:2006;left:225">Dependent Testing</div>
<div style="position:absolute;top:2006;left:675">103</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2026;left:243">Dependent Code</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2025;left:675">104</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2042;left:243">Dependent Testing with TestNG</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2041;left:675">105</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2059;left:243">Deciding Whether to Depend on Groups or on Methods</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2058;left:675">106</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2075;left:243">Dependent Testing and Threads</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2074;left:675">110</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2092;left:243">Failures of Configuration Methods</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:2091;left:675">110</div>
<div style="position:absolute;top:2108;left:225">Inheritance and Annotation Scopes</div>
<div style="position:absolute;top:2108;left:675">113</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2128;left:243">The Problem</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2127;left:675">113</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2144;left:243">Pitfalls of Inheritance</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2143;left:675">116</div>
<div style="position:absolute;top:2161;left:225">Test Groups</div>
<div style="position:absolute;top:2161;left:675">119</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2180;left:243">Syntax</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2179;left:675">120</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2197;left:243">Groups and Runtime</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2196;left:675">122</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2213;left:243">Running Groups</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2212;left:675">125</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:2230;left:243">Using Groups Effectively</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2229;left:675">127</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:1309;left:90">Beust.book  Page vi  Thursday, August 16, 2007  10:22 AM</div>
</span></font>

<div style="position:absolute;top:2389;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_3"><b>Page 3</b></a></font></td></tr></table></div><font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2497;left:620">Contents</div>
</span></font>

<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:2494;left:729">vii</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2551;left:270">Code Coverage</div>
<div style="position:absolute;top:2551;left:720">132</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2570;left:288">A Coverage Example</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2569;left:720">133</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2587;left:288">Coverage Metrics</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2586;left:720">134</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2603;left:288">Coverage Tools</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2602;left:720">136</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2620;left:288">Implementation</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2619;left:720">146</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2636;left:288">Beware!</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2635;left:720">147</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:2653;left:288">A Guide to Successful Coverage</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2652;left:720">147</div>
<div style="position:absolute;top:2669;left:270">Conclusion</div>
<div style="position:absolute;top:2669;left:720">150</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:2716;left:162">Chapter 3</div>
<div style="position:absolute;top:2716;left:270">Enterprise Testing</div>
<div style="position:absolute;top:2716;left:715">153</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2745;left:270">A Typical Enterprise Scenario</div>
<div style="position:absolute;top:2745;left:720">154</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2764;left:288">Participants</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2763;left:720">155</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2781;left:288">Testing Methodology</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2780;left:720">155</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2797;left:288">Issues with the Current Approach</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2796;left:720">156</div>
<div style="position:absolute;top:2814;left:270">A Concrete Example</div>
<div style="position:absolute;top:2814;left:720">157</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2833;left:288">Goals</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2832;left:720">159</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2850;left:288">Nongoals</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2849;left:720">160</div>
<div style="position:absolute;top:2866;left:270">Test Implementation</div>

<div style="position:absolute;top:2866;left:720">160</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2886;left:288">Testing for Success</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2885;left:720">161</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2903;left:288">Building Test Data</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2901;left:720">163</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2919;left:288">Test Setup Issues</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2918;left:720">166</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2935;left:288">Error Handling</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2934;left:720">172</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2952;left:288">Emerging Unit Tests</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2951;left:720">175</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:2968;left:288">Coping with In-Container Components</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2967;left:720">177</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:2985;left:288">Putting It All Together</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:2984;left:720">178</div>
<div style="position:absolute;top:3001;left:270">Exploring the Competing Consumers Pattern</div>
<div style="position:absolute;top:3001;left:720">182</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3021;left:288">The Pattern</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3020;left:720">182</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3038;left:288">The Test</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3036;left:720">184</div>
<div style="position:absolute;top:3054;left:270">The Role of Refactoring</div>
<div style="position:absolute;top:3054;left:720">186</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3074;left:288">A Concrete Example</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3072;left:720">187</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3090;left:288">An In-Container Approach</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3089;left:720">193</div>
<div style="position:absolute;top:3106;left:270">Conclusion</div>
<div style="position:absolute;top:3106;left:720">194</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">

<div style="position:absolute;top:3153;left:162">Chapter 4</div>
<div style="position:absolute;top:3153;left:270">Java EE Testing</div>
<div style="position:absolute;top:3153;left:715">197</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3182;left:270">In-Container versus Out-of-Container Testing</div>
<div style="position:absolute;top:3182;left:720">198</div>
<div style="position:absolute;top:3202;left:270">In-Container Testing</div>
<div style="position:absolute;top:3202;left:720">200</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3221;left:288">Creating a Test Environment</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3220;left:720">200</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3238;left:288">Identifying Tests</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3237;left:720">201</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:3254;left:288">Registering Tests</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3253;left:720">203</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3271;left:288">Registering a Results Listener</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3270;left:720">204</div>
<div style="position:absolute;top:3287;left:270">Java Naming and Directory Interface (JNDI)</div>
<div style="position:absolute;top:3287;left:720">207</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3307;left:288">Understanding JNDI\u2019s Bootstrapping</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3306;left:720">207</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3323;left:288">Spring\u2019s <b>SimpleNamingContextBuilder</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3322;left:720">209</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3340;left:288">Avoiding JNDI</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3339;left:720">210</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:2416;left:90">Beust.book  Page vii  Thursday, August 16, 2007  10:22 AM</div>
</span></font>

<div style="position:absolute;top:3496;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_4"><b>Page 4</b></a></font></td></tr></table></div><font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:3601;left:117">viii</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3604;left:189">Contents</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3658;left:225">Java Database Connectivity (JDBC)</div>
<div style="position:absolute;top:3658;left:675">210</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3677;left:243">c3p0</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3676;left:675">212</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3694;left:243">Commons DBCP</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3693;left:675">213</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3710;left:243">Spring</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3709;left:675">213</div>
<div style="position:absolute;top:3727;left:225">Java Transaction API (JTA)</div>

<div style="position:absolute;top:3727;left:675">215</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3746;left:243">Java Open Transaction Manager (JOTM)</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3745;left:675">217</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3763;left:243">Atomikos TransactionEssentials </div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3762;left:675">218</div>

<div style="position:absolute;top:3779;left:225">Java Messaging Service (JMS)</div>
<div style="position:absolute;top:3779;left:675">219</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3799;left:243">Creating a Sender/Receiver Test</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3798;left:675">219</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3815;left:243">Using ActiveMQ for Tests</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3814;left:675">221</div>
<div style="position:absolute;top:3832;left:225">Java Persistence API (JPA)</div>
<div style="position:absolute;top:3832;left:675">225</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3851;left:243">Configuring the Database</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3850;left:675">227</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:3868;left:243">Configuring the JPA Provider</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3867;left:675">227</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3884;left:243">Writing the Test</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3883;left:675">229</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3901;left:243">Simulating a Container</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3900;left:675">230</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3917;left:243">Using Spring as the Container</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3916;left:675">231</div>
<div style="position:absolute;top:3934;left:225">Enterprise Java Beans 3.0 (EJB3)</div>
<div style="position:absolute;top:3934;left:675">236</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3953;left:243">Message-Driven Beans</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3952;left:675">237</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:3970;left:243">Session Beans</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3969;left:675">240</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:3986;left:243">Another Spring Container</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:3985;left:675">243</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4003;left:243">Disadvantages of a Full Container</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4002;left:675">244</div>
<div style="position:absolute;top:4019;left:225">Java API for XML Web Services (JAX-WS)</div>
<div style="position:absolute;top:4019;left:675">246</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4039;left:243">Recording Requests</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4038;left:675">248</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4055;left:243">Setting Up the Test Environment</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4054;left:675">248</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4072;left:243">Creating the Service Test</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4071;left:675">251</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4088;left:243">XPath Testing</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4087;left:675">253</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:4105;left:243">Testing Remote Services</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4104;left:675">254</div>
<div style="position:absolute;top:4121;left:225">Servlets</div>
<div style="position:absolute;top:4121;left:675">255</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4141;left:243">In-Container Testing</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4140;left:675">255</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4157;left:243">Mock/Stub Objects</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4156;left:675">255</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4174;left:243">Refactoring</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4173;left:675">257</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4190;left:243">Embedded Container</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4189;left:675">257</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4207;left:243">In-Memory Invocation</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4206;left:675">260</div>
<div style="position:absolute;top:4223;left:225">XML</div>

<div style="position:absolute;top:4223;left:675">262</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4243;left:243">Using dom4j</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4242;left:675">263</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4259;left:243">Using XMLUnit</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4258;left:675">264</div>

<div style="position:absolute;top:4276;left:225">Conclusion</div>
<div style="position:absolute;top:4276;left:675">266</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:4322;left:117">Chapter 5</div>
<div style="position:absolute;top:4322;left:225">Integration</div>
<div style="position:absolute;top:4322;left:670">269</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4351;left:225">Spring</div>
<div style="position:absolute;top:4351;left:675">270</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4371;left:243">Spring\u2019s Test Package Features</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4370;left:675">271</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4388;left:243">Test Class Hierarchy</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4386;left:675">272</div>
<div style="position:absolute;top:4404;left:225">Guice</div>

<div style="position:absolute;top:4404;left:675">280</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4424;left:243">The Issue with Spring</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4422;left:675">280</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4440;left:243">Enter Guice</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4439;left:675">281</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4456;left:243">A Typical Dependency Scenario</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4455;left:675">282</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:3523;left:90">Beust.book  Page viii  Thursday, August 16, 2007  10:22 AM</div>
</span></font>

<div style="position:absolute;top:4603;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_5"><b>Page 5</b></a></font></td></tr></table></div><font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4711;left:620">Contents</div>

</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:4708;left:733">ix</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4765;left:288">The Object Factory</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4764;left:720">284</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4781;left:288">Guice Configuration</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4780;left:720">286</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4798;left:288">Guice-Based Test</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4797;left:720">290</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4814;left:288">Grouping Test Dependencies</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:4813;left:720">291</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4831;left:288">Injecting Configuration</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4830;left:720">293</div>
<div style="position:absolute;top:4847;left:270">DbUnit</div>
<div style="position:absolute;top:4847;left:720">295</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4867;left:288">Configuration</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4866;left:720">295</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4883;left:288">Usage</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4882;left:720">297</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4900;left:288">Verifying Results</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4899;left:720">299</div>
<div style="position:absolute;top:4916;left:270">HtmlUnit</div>
<div style="position:absolute;top:4916;left:720">303</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:4936;left:288">Configuration</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4935;left:720">304</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:4952;left:288">Usage</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:4951;left:720">305</div>
<div style="position:absolute;top:4969;left:270">Selenium</div>
<div style="position:absolute;top:4969;left:720">310</div>
<div style="position:absolute;top:4988;left:270">Swing UI Testing</div>
<div style="position:absolute;top:4988;left:720">312</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5008;left:288">Testing Approach</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5007;left:720">312</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5024;left:288">Configuration</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5023;left:720">313</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5041;left:288">Usage</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5040;left:720">314</div>
<div style="position:absolute;top:5057;left:270">Tests for Painting Code</div>
<div style="position:absolute;top:5057;left:720">316</div>
<div style="position:absolute;top:5077;left:270">Continuous Integration</div>
<div style="position:absolute;top:5077;left:720">320</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5096;left:288">Why Bother?</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:5095;left:720">320</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5113;left:288">CI Server Features</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5112;left:720">320</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5129;left:288">TestNG Integration</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5128;left:720">321</div>

<div style="position:absolute;top:5146;left:270">Conclusion</div>
<div style="position:absolute;top:5146;left:720">322</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:5192;left:162">Chapter 6</div>
<div style="position:absolute;top:5192;left:270">Extending TestNG</div>
<div style="position:absolute;top:5192;left:715">325</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5221;left:270">The TestNG API</div>
<div style="position:absolute;top:5221;left:720">325</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5242;left:288"><b>org.testng.TestNG</b>, <b>ITestResult</b>, <b>ITestListener</b>, </div>
<div style="position:absolute;top:5258;left:306"><b>ITestNGMethod</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5256;left:720">325</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:5274;left:288">A Concrete Example</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5273;left:720">328</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5290;left:288">The XML API</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5289;left:720">331</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5307;left:288">Synthetic XML Files</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5306;left:720">333</div>
<div style="position:absolute;top:5323;left:270">BeanShell</div>
<div style="position:absolute;top:5323;left:720">335</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5343;left:288">BeanShell Overview</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5342;left:720">335</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5360;left:288">TestNG and BeanShell</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5358;left:720">337</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5376;left:288">Interactive Execution</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5375;left:720">339</div>
<div style="position:absolute;top:5392;left:270">Method Selectors</div>

<div style="position:absolute;top:5392;left:720">341</div>
<div style="position:absolute;top:5412;left:270">Annotation Transformers</div>
<div style="position:absolute;top:5412;left:720">346</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5432;left:288">Annotation History</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5430;left:720">346</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5448;left:288">Pros and Cons</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5447;left:720">348</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5464;left:288">Using TestNG Annotation Transformers</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5463;left:720">348</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5481;left:288">Possible Uses of Annotation Transformers</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5480;left:720">353</div>
<div style="position:absolute;top:5497;left:270">Reports</div>
<div style="position:absolute;top:5497;left:720">355</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5517;left:288">Default Reports</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5516;left:720">355</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:5534;left:288">The Reporter API</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5533;left:720">360</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5550;left:288">The Report Plug-in API</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5549;left:720">360</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:4630;left:90">Beust.book  Page ix  Thursday, August 16, 2007  10:22 AM</div>

</span></font>

<div style="position:absolute;top:5710;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_6"><b>Page 6</b></a></font></td></tr></table></div><font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:5815;left:117">x</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5818;left:189">Contents</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5872;left:225">Writing Custom Annotations</div>
<div style="position:absolute;top:5872;left:675">366</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5891;left:243">Implementation</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5890;left:675">367</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:5908;left:243">Testing</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:5907;left:675">371</div>
<div style="position:absolute;top:5924;left:225">Conclusion</div>

<div style="position:absolute;top:5924;left:675">375</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:5971;left:117">Chapter 7</div>
<div style="position:absolute;top:5971;left:225">Digressions</div>
<div style="position:absolute;top:5971;left:670">377</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6000;left:225">Motivation</div>
<div style="position:absolute;top:6000;left:675">377</div>
<div style="position:absolute;top:6019;left:225">The TestNG Philosophy</div>

<div style="position:absolute;top:6019;left:675">378</div>
<div style="position:absolute;top:6039;left:225">The Care and Feeding of Exceptions</div>
<div style="position:absolute;top:6039;left:675">378</div>
<div style="position:absolute;top:6058;left:225">Stateful Tests</div>
<div style="position:absolute;top:6058;left:675">382</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6078;left:243">Immutable State</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6077;left:675">382</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6094;left:243">Mutable State</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6093;left:675">383</div>
<div style="position:absolute;top:6111;left:225">The Pitfalls of Test-Driven Development</div>
<div style="position:absolute;top:6111;left:675">385</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6130;left:243">TDD Promotes Microdesign over Macrodesign</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6129;left:675">385</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6147;left:243">TDD Is Hard to Apply</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6146;left:675">386</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6163;left:243">Extracting the Good from Test-Driven Development</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:6162;left:675">388</div>
<div style="position:absolute;top:6180;left:225">Testing Private Methods</div>
<div style="position:absolute;top:6180;left:675">388</div>
<div style="position:absolute;top:6199;left:225">Testing versus Encapsulation</div>
<div style="position:absolute;top:6199;left:675">391</div>
<div style="position:absolute;top:6219;left:225">The Power of Debuggers</div>
<div style="position:absolute;top:6219;left:675">392</div>
<div style="position:absolute;top:6238;left:225">Logging Best Practices</div>
<div style="position:absolute;top:6238;left:675">394</div>

<div style="position:absolute;top:6258;left:225">The Value of Time</div>
<div style="position:absolute;top:6258;left:675">397</div>
<div style="position:absolute;top:6277;left:225">Conclusion</div>
<div style="position:absolute;top:6277;left:675">399</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:6324;left:117">Appendix A IDE Integration</div>
<div style="position:absolute;top:6324;left:670">401</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6353;left:225">Eclipse</div>

<div style="position:absolute;top:6353;left:675">401</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6373;left:243">Installing the Plug-in</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6372;left:675">401</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6389;left:243">Verifying the Installation</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6388;left:675">404</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6406;left:243">Creating a Launch Configuration</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6405;left:675">404</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6422;left:243">Configuring Preferences</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6421;left:675">410</div>
</span></font>

<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6439;left:243">Converting JUnit Tests</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6438;left:675">410</div>
<div style="position:absolute;top:6455;left:225">IntelliJ IDEA</div>
<div style="position:absolute;top:6455;left:675">411</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6475;left:243">Installing the Plug-in</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:6474;left:675">411</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6491;left:243">Running Tests</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6490;left:675">412</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6508;left:243">Running Shortcuts</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6507;left:675">417</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6524;left:243">Viewing Test Results</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6523;left:675">418</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6541;left:243">Running Plug-in Refactorings</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6540;left:675">419</div>
</span></font>

<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:6584;left:117">Appendix B TestNG Javadocs</div>
<div style="position:absolute;top:6584;left:670">421</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6613;left:225">JDK 1.4 and JDK 5</div>
<div style="position:absolute;top:6613;left:675">421</div>
<div style="position:absolute;top:6633;left:225">Shortcut Syntax for JDK 5 Annotations</div>
<div style="position:absolute;top:6633;left:675">423</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">

<div style="position:absolute;top:5737;left:90">Beust.book  Page x  Thursday, August 16, 2007  10:22 AM</div>
</span></font>

<div style="position:absolute;top:6817;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_7"><b>Page 7</b></a></font></td></tr></table></div><font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6925;left:620">Contents</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:6922;left:733">xi</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6979;left:270">Annotation Javadocs</div>
<div style="position:absolute;top:6979;left:720">423</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:6999;left:288"><b>@<a href="mailto:DataProvider/@testng.data-provider" target="_blank">DataProvider/@testng.data<WBR>-provider</a></b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:6997;left:720">425</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7015;left:288"><b>@<a href="mailto:Factory/@testng.factory" target="_blank">Factory/@testng.factory</a></b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:7014;left:720">426</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7032;left:288"><b>@<a href="mailto:Parameters/@testng.parameters" target="_blank">Parameters/@testng.parameters</a></b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7030;left:720">426</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7048;left:288"><b>@<a href="mailto:Test/@testng.test" target="_blank">Test/@testng.test</a></b></div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7047;left:720">427</div>
<div style="position:absolute;top:7064;left:270">The </div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7066;left:298"><b>org.testng.TestNG</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7064;left:441">Class</div>
<div style="position:absolute;top:7064;left:720">428</div>
<div style="position:absolute;top:7084;left:270">The XML API</div>

<div style="position:absolute;top:7084;left:720">432</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:7130;left:162">Appendix C <b>testng.xml</b></div>
<div style="position:absolute;top:7131;left:715"><b>435</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7159;left:270">Overview</div>
<div style="position:absolute;top:7159;left:720">436</div>
<div style="position:absolute;top:7179;left:270">Scopes</div>

<div style="position:absolute;top:7179;left:720">437</div>
<div style="position:absolute;top:7198;left:270">XML Tags</div>
<div style="position:absolute;top:7198;left:720">437</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7219;left:288"><b>&lt;suite&gt;</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7217;left:720">437</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7235;left:288"><b>&lt;packages&gt; </b>and <b>&lt;package&gt;</b></div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7233;left:720">440</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7252;left:288"><b>&lt;parameter&gt;</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7250;left:720">441</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7268;left:288"><b>&lt;suite-files&gt; </b>and <b>&lt;suite-file&gt;</b></div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7266;left:720">442</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7285;left:288"><b>&lt;method-selectors&gt;</b>, <b>&lt;method-selector&gt;</b>, </div>
<div style="position:absolute;top:7301;left:306"><b>&lt;selector-class&gt;</b>, and <b>&lt;script&gt;</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:7299;left:720">443</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7318;left:288"><b>&lt;test&gt;</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7316;left:720">444</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7334;left:288"><b>&lt;groups&gt;</b>, <b>&lt;define&gt;</b>, and <b>&lt;run&gt;</b></div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7332;left:720">446</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7351;left:288"><b>&lt;classes&gt; </b>and <b>&lt;class&gt;</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7349;left:720">446</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:7367;left:288"><b>&lt;methods&gt;</b></div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7365;left:720">447</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:7410;left:162">Appendix D Migrating from JUnit</div>
<div style="position:absolute;top:7410;left:715">449</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7441;left:270"><b>JUnitConverter</b></div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7439;left:720">449</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7459;left:288">From the Command Line</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7458;left:720">449</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7475;left:288">From <b>ant</b></div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7474;left:720">452</div>
<div style="position:absolute;top:7492;left:270">Integrated Development Environments</div>
<div style="position:absolute;top:7492;left:720">453</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7511;left:288">Eclipse</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7510;left:720">453</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">

<div style="position:absolute;top:7528;left:288">IDEA</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7527;left:720">454</div>
<div style="position:absolute;top:7544;left:270">Incremental Migration and JUnit Mode</div>
<div style="position:absolute;top:7544;left:720">455</div>
<div style="position:absolute;top:7564;left:270">Converting JUnit Code</div>
<div style="position:absolute;top:7564;left:720">456</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7583;left:288">Assertions</div>

</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7582;left:720">457</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7600;left:288">Running a Single Test</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7599;left:720">458</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7616;left:288">Maintaining State between Invocations</div>
</span></font>

<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7615;left:720">461</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7633;left:288">Suite-wide Initialization</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7632;left:720">463</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7649;left:288">Class-wide Initialization</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">

<div style="position:absolute;top:7648;left:720">463</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7666;left:288">The AllTests Pattern</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7665;left:720">463</div>
</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7682;left:288">Testing Exceptions</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7681;left:720">467</div>

</span></font>
<font size="8" face="Times"><span style="font-size:11px;font-family:Times">
<div style="position:absolute;top:7699;left:288">The Parameterized Test Case Pattern</div>
</span></font>
<font size="8" face="Times"><span style="font-size:12px;font-family:Times">
<div style="position:absolute;top:7698;left:720">469</div>
</span></font>
<font size="8" face="Times"><span style="font-size:16px;font-family:Times">
<div style="position:absolute;top:7742;left:270">Index</div>
<div style="position:absolute;top:7742;left:715">471</div>
</span></font>
<font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:6844;left:90">Beust.book  Page xi  Thursday, August 16, 2007  10:22 AM</div>

</span></font>

<div style="position:absolute;top:7924;left:0"><hr><table border="0" width="100%"><tr><td bgcolor="eeeeee" align="right"><font face="arial,sans-serif"><a name="0.1_8"><b>Page 8</b></a></font></td></tr></table></div><font size="2" face="Times"><span style="font-size:8px;font-family:Times">
<div style="position:absolute;top:7951;left:90">Beust.book  Page xii  Thursday, August 16, 2007  10:22 AM</div>
</span></font>
</div>

</div></body></html>
����������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/���������������������������������������������������������������������0000755�0001750�0001750�00000000000�12732165123�015703� 5����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/��������������������������������������������������������������0000755�0001750�0001750�00000000000�12732165123�017150� 5����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/file.gif������������������������������������������������������0000644�0001750�0001750�00000000230�12732165123�020551� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a��	�鯯333������������������!��	�,�������EHr#iDp$(16H`�
Hnr lIraL."�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_infosml.gif����������������������������������������������0000644�0001750�0001750�00000000115�12732165123�022313� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a������������!���,�������	wlzO=wiXMbL[�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_sortleft.gif���������������������������������������������0000644�0001750�0001750�00000000171�12732165123�022510� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������j?S-Z}ZJt)���������������������!���,�������&IXLqAXIJu=0�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_success_lrg.gif������������������������������������������0000644�0001750�0001750�00000002724�12732165123�023170� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������]yXsTnLcG\|CWu[vWqRjPhNeKaI_H]}DXvb5D[hgpt{Öřǝɡ˨Ϭѱ԰ӳշ׶ָؽۿܾ*7Iʤͺٹ`{gNd|VuvQo}tkRwndq@]G;Q@KuSGkM]bqpËۣ~|àʩ~zQKc[zHpADi=Bd;ۙЇّ㟩⚫>\5:U2╧▩<W3eI[C߉ߍfv7N-9Q/݂ڀޅއ߉wzx~q[ۀ~[:]mjtpqXqYuxb7^5g:e9a7_6K+Q.W2j?U2d}YlQ҆Ύd6t?m<k;\3[2W0Gx'Dr%q>l<j;g:g9e8^5Z2Y1U/o>^5X1S/Q-J}*~MvHW}R|_r{hɞӲƬ|Cv@q=o<T-E{CzByByAj:V/U.T-}D\2T.b6q>JJX7yR+Q+O~*N{)Jt)!���,���� � ���	H_$@ǎ衃Fq@ǏA`FE@e�.#8qt2LCfXItVDc8mJCE|8T�)QŠKK!@Ppʥ%K0[\†ϟ<[H%r=%³a3c.1‹=!re1cS4hKӄA-%P`zc;ZCT-NL31%9i#jrz2,&EDIѶڦ26N#<'O-cRuEyUDR(`=s:`PsgK�\^�#L8A,\a@J<E_t",pQ=#.Q

tB4Q71Ũ@EHqhPC<S7e)
+A
:4SN:872L/$KtD�c:3dsK+@3,`%031M4Ь㌫@>~D6p3Jͼ+ϱO?Q=(BgnuaG}"~4#e,A9P
1BD
)	&'eP?"�'=�,,K 4@X`h0<�;��������������������������������������������testng-6.9.12/doc/samplereport/images/icon_error_sml.gif��������������������������������������������0000644�0001750�0001750�00000001762�12732165123�022661� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������
q	
x
v
m;@GJf46_
i
[
~
}
s	q	p	n	XVL


v
l	~"",9?6;{6:df島$')OWͱ-/*"4"3s}%8&:(=*@+A*?5H=MM\+B.F/G0I2M3O2N<S5R6S7Uނ:Y:Y<\;[=^?a@bBeH 1K"4H!3F 1I"4g1Lm9Xr@bxHn>%9J.FprN3Ovx{@-EL6RO8V08G3O1:bGm3=4>7 C5AgOx?2ME7TmW|d}gu^V������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������;	H AJ�gN޴Yc*
FrM/]HIh $5iΌ
%BT0P8$2,ㅋ,Z(DL@;G�k$<Hd
>`'�!\2?vhp
u@
.X=	q0	)f$Tp"FQGr̉C�;��������������testng-6.9.12/doc/samplereport/images/external.png��������������������������������������������������0000644�0001750�0001750�00000000346�12732165123�021503� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR������	���Ӻ&���gAMA��7���tEXtSoftware�Adobe ImageReadyqe<���PLTEuuu��P���tRNS�@*���PIDATxb`&& @P6#@`�X�Ć2 d@�A3 (��*�t����IENDB`������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/strich.gif����������������������������������������������������0000644�0001750�0001750�00000000053�12732165123�021131� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������!�����,�������
�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowmembers2_sml.gif������������������������������������0000644�0001750�0001750�00000002060�12732165123�024307� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������4D[Rj4CY!*8tds^hwgp~ѱԲԽۿܾ7H`=PjŚǺ[jzYjnY[ZTlXC\A>l*6]#`Gfs`TxAd&c&T+r>r?R.Ew(hF=	c&a&a&f-i/h0c.j3j4l6i4s;,JxEa"`&_(r?6XTY ](S[(PLq(-OJvN|!1Knjoc#Ed?P
9=wtz~иkc͵jսoηp'D\b«igf
��TXrMP`hrFmEnGrJVUU̫lll������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������?	H*HP>3)Q�:
C1%d!s
B3]ypC\СQ=u!'K\j鏟<q*ʩҁJj`F�jի(,5&ҤGR	mZ\4XBF)1ĤkT@3$`I8ՁKrR|`Ct(X(!ZpǑ(Wl#&‚"B  'UxR4n
å.dΨQ( �;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_success_sml.gif������������������������������������������0000644�0001750�0001750�00000001736�12732165123�023201� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������Χμc~w˗éSq*/%(#8='*!37,/(CH'AF&>B/2*,)FI"!PrkjtŲFcO7G;ȝȣ֩۴߲2B.ᥳ⦷㫸䬸䭺导屏€㩲ࢲࣜΈޘܙٗۗ]B΅ԋۑ̈́՗]>Ԅሻfrmjb7Jw*U0W2im;Ag$r?o=e8f8b7Z2Y1S.Jt)Qy1WYuQeFcE{{hGv@u?k:h7`3Jr(E^3Q|,S~-Dh%}DEi&QŢIm&Qx+Ot)Mo(Ll&Ig%Gc$������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������	HA!,XE
aCF5pAƏ*01#"NT0�A=Y& 	NRI1bJ':o8b3-e˓у>|¥(qŋ4hԱ(ЋmT"J;*d("4lp	,P( �;����������������������������������testng-6.9.12/doc/samplereport/images/update.gif����������������������������������������������������0000644�0001750�0001750�00000000300�12732165123�021112� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����ٕ\Ҫ?!y~LWA(xdGϾV.6+Vqg!��
�,������mPI8!Hhy7E"[\Ӭ'
�OHvhz߉u 
"y.�F#J*`< ��c`
Af{	��;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_doc_lrg.gif����������������������������������������������0000644�0001750�0001750�00000002467�12732165123�022271� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������]y[wYtXsUoSlOgLcJ`G\|CWua~ZuWqRjQiPhNeMdKaI_H]}DXv?Rm5E\bUnLbI^~6F]3BXhgmprtwz{~’ØƗŝɜȡ˦ΨϧΩЭҬѫб԰ӲԳյַ׶ָؽۼڿܾ^{*7IcÕŔĚǟʞɤ̢ͣˮҺٹ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,���� � ���+	H+A9`0#B#%	v	1� AE�\	R
%`D	c8qDdELuP.aI"DPJ =|fdlJ	σ`zH
Pxl5[	#Rp3ċڄ\˷/'y\A.S)I$PLLre2쀜8|:RƍgHq4Hx?nA8q;vAPA&
{"5zA:iի[>�MȟnӘ"@
*pV/\90]U$#҇!,dхYwlWL@FGH"h�^lGSD#Cˑd$"
Ca||X!O,GGD)jajGdCi WPEL$t1@t	!8$t1@0cN,jE!Dp
!dd
`@HЁ|@(P
(k%�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/none.png������������������������������������������������������0000644�0001750�0001750�00000001662�12732165123�020622� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR������������gAMA��|Q��� cHRM��z%��������u0��`��:��o_F���PLTE������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������e
���tRNS�0J���	pHYs��������IDATc`�i��2ag~����IENDB`������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_usergroups_lrg.gif���������������������������������������0000644�0001750�0001750�00000002760�12732165123�023736� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������燦
k
@C_e&,2&6ഺ4J]h>XN&Mg]|tfbdb`arIjzgJ2M5=	'SG]~\wRipƣ̱Ծ.?S,0FkDؕ߬ȓvtN
s?wDairBVq;ZXcn8P;{k3\;hg.Mh2x[opnFhd):PnX|}y}~mڎݮ鷈}njB@0*&ƸxٞMD%r|ueۀxƱh߃иkȰgpԼnѹl˴iӼni{'Db`^[ƮfĬeªdRQNLV|IOsCm@^T?{_wb>;/{_(o-],\rtz9LޓPn@xJvګ͸aiemlx%ۀ2܇=ۋHZ<#ؓYenM1fM~wp\>OaXdr)w6ӈOە_ǐekwme۷SXG'h&l4{D~LW"k:D
ĀZ9W"@_?/1S(z!:??fff!���,���� � ���	H*\ȐL2Y4BO3`@M4 .^(dA~
8̙p-tiӢJ菡Ho)5!' AeN%>D	RQ�u�3L
1/y@zh^XBxѠm^7JYAvv<	޾lR	(L|2Y'š:j4SBs'~EYZN)6$F~�PѨzh>9j!Q*-r*>:Uԩ4ʔ-ӢPODeޔTL?].,P?X6D2B-1?2O6E?E',ޢ?V!t:C
b0-4٤.hDA#
I,F^x131R1Xs�iC<St,BK,RK09L8Tch5D8 DD+yRK0L)5Ԅ#8H?:J//@#7k2HCC$qıP/é147l
9ؒLADDN �S1Lͻ#:3NJ;O8G/F;mی9鸣0<ܳHB,o:	<ē?WhqOTDLDQ
ŔM7o!S
AW'gc';ﰓM$TOtH�;����������������testng-6.9.12/doc/samplereport/images/icon_arrowwaste1_sml.gif��������������������������������������0000644�0001750�0001750�00000001136�12732165123�024002� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������4W냗Ӱ`}\xPhEYxbUn`{hjlkyƗŝɧΩЭҫб԰ӲԳյֶּڿcǟʮҹVUUlll������������������������������������������������������������������������������������������������������������������������������������������������!��O�,�������O'!!;<	F
3/6)BAKO+
817*J+?C77D6I*5C%9LLƆ*11,(:LMӄ)72#"M8C-:N'G,@3I>I
aƒU%-=n}BbY=0Fg("E է0c
�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_min_036.gif������������������������������������������������0000644�0001750�0001750�00000000055�12732165123�021516� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����3f!���,�������Q�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowfolderopen2_sml.gif���������������������������������0000644�0001750�0001750�00000001230�12732165123�025010� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a!�������י}~ً|vutqվo}x{tكӂ{̴ipѹlϷkɱhsӼnDznlijzż`]ZŭecOWT}IwFLoBh=u^7jR0VUUmmm������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!��C�,����!���C.-,,"!0C0
)*,30%/1

52&#3!/6,-44C?>1
"$56-#-'>=88Bׄ2014<+	h.^( Q*X>@Gh <yN�emW!0FFUpI*#p#I5fx5R7"QÀ;lH#:Fl"@�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_members_sml.gif������������������������������������������0000644�0001750�0001750�00000001777�12732165123�023170� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������4D[Rj4CY!*8tds^hwgp~ѱԲԽۿܾ7H`=PjŚǺ[jzYjnY[ZTlXC\A>l*6]#`Gfs`TxAd&c&T+r>r?R.Ew(hF=	c&a&a&f-i/h0c.j3j4l6i4s;,JxEa"`&_(r?6XTY ](S[(PLq(-OJvN|!1Knjoc#Ed?P
9=wtz~иkc͵jսoηp'D\b«igf
��TXrMP`hrFmEnGrJ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������3	HA	JG p 6n!�BcN<2mp@:4
72?yG
2` =RqMI(z4+Zh"%L<^RB�
"Bx̘N uƒA12X@@EpǑ(Wl#&2!HI,^1&MALc҅5�;�testng-6.9.12/doc/samplereport/images/icon_info_sml.gif���������������������������������������������0000644�0001750�0001750�00000001136�12732165123�022456� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������r	'SG]}]yVpOgLcJ`EYxCWtI^~FZyehgjlmpXltvdyw|~wunzw…ǘƂ˦ΩЭҬџ԰ӵָؼݲ@TpAUqy}ŞɧŹ���������������������������������������!��r�,�������r`fg`l\d
LG^qqopnQmbj.MObhNgr\oP6[ig%dmE4k_^eL	PRahYcHBjfV<JD@>
F`\-5Z=97D`]
I'130@KICA@,"�c
$XA ?tr兊!8h2†@Pab
�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_warning_lrg.gif������������������������������������������0000644�0001750�0001750�00000002723�12732165123�023164� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������fbd|P]ylexVdzam]yXsTnLcG\|CWu[vWqRjPhNeKaI_H]}DXvb5D[ghprYlu{~—ŝɡ˨ϧάѱ԰ӳյַ׶ֵոؽۿܾ*7IÕŚǟʤͺٹkW?^P?eI+eVFmN/hK-\B(bG+n?j<T:#T;$kL.V=&jKQ7!W5R8"nCFjgdWUM
F|;
wvsrplhgedcba`_[[YZZQPOOL
K
J
y:
xunnlg]WSMH
G
=xB
yRge{]vr}"Zw!^"l?O5!ӨˤšUG<~%)e!_.y-e&4f,:iM;?~:Dj4AALp<Ol;^s]TN[V̅]~h~jL>6rJ|Qibgrq|Ҍlyv{䞇ǛТxw!���,���� � ���	HdNeI@ǏHaF`@�	.G8q<^f
YITnD#sJN`8T�8A`ÊB4p�Cbo߿)GO<8UDyܵsɀ˘/qSc|8X7^9wAFylM[8
LK{\`ϝ:ٮM{\̗kc8GiϜ
rʤcWNО)u;lqGܸo]%#7d/$�@aւ9`5ijQ<*CA@Q f`cM5<L2%I+H2	%sCXD3K,,"'LR%�#A?aFd1F,/%lTL'`+xrA>Șa܂J#F1'tr+œ@\A\>	xh�nj(J�*B2"B
()@9hS<фY%r(")+,@2TAE7X|!v{G CL:NE@Ѕ[�݀I+#0C
6АI!p $P	|p	(,̤�;���������������������������������������������testng-6.9.12/doc/samplereport/images/icon_waste_sml.gif��������������������������������������������0000644�0001750�0001750�00000001062�12732165123�022644� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������4W냗Ӱ`}\xPhEYxbUn`{hjlkyƗŝɧΩЭҫб԰ӲԳյֶּڿcǟʮҹ������������������������������������������������������������������������������������������������������������������������������������������������������������������!��I�,�������I'!!;<	I
3/6I)BA+
817*?C77D6*5C%911,(:)72#"͒8C-:'G, Ӎ
>6&1@:.A=I0EA^?&�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/sw_min.gif����������������������������������������������������0000644�0001750�0001750�00000000055�12732165123�021133� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������DP�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/newwindow.png�������������������������������������������������0000644�0001750�0001750�00000000334�12732165123�021677� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR������	���Ӻ&���gAMA��7���tEXtSoftware�Adobe ImageReadyqe<���PLTEuuu��8���tRNS�@*���FIDATxb`fff�f�b�@ � 8@�!
@`6��L��&�^����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/logos/��������������������������������������������������������0000755�0001750�0001750�00000000000�12732165123�020273� 5����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/logos/maven-feather.png���������������������������������������0000644�0001750�0001750�00000005533�12732165123�023531� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR���Z������a	x���gAMA��a���tIME:���bKGD������	pHYs��."��."ݒ��
IDAThZPTYM48怎\T#IADPa芨:cvR$Ӏ`fY1U[;;cUoλI~ٳgVDEEٳg8x ܹ#t͛7_o9s:::.|A틇1cEsO@ӳW\իWŋFD<}x}}~||<?.>y$ۇ>}`ɒ%HKK謬,,_ׯǍ7Ľ#;;}ff&\aMp[
�w.B

GaݺuҥpС׀0`�<==}vZJ`;"N:b8__ݺu//@	u/_^;+c\Jb"Ty+.A2ܾP;~9r$N:]	AkEPQE!I9zp,C>نC{!wt	QO)S^32/--JJJz.u//4Pqeeeĉ$=6l2_QUgVi%yȖ!U3U]os倶®]Ē|VX!�  <mnذ\)\>k,ͼyдiSAٳG�[q%\vM)|>.qU'[e'DJCR!9!9A(WOd4S㈈رcѹsgfΜ)P�			=z3g7qDᕳg6F*sEqqk?)1bv*ƪ-Zȶm3V:ű	~2z¹3jm}t5
o?L?[",�Fa�?K;@o}H	mnٓKmIyl܁
[v z~NVS4F;|z5GKwL2	A;[ew+#^̒#3rdj:"2|ܰy8s䟸VRϞ@scsvv4L
B졎HA;’a
}{|i
եۻ:tj}0l%W/^!O	y"SKoh56a66ףfr8?58#
OJ0Veל*hG�o
5ݤL1^3-#"keI
ZoW.6F|Fn[6.ͳ{qRQ0%犐Cap
dM></x@úXo>kL.`W]oؙ٢ɗh"{}#]C4E7u1L`>\=N\S51JAұ`ݎ'~@SA2+-
C+qry
E֮ȫ&(gi<'c{LSjX#{T3_62%9Y}uOkG=FX~<׸%Y.=ŋq(rmG̓&ðv kVnFE!H[ppi#qGD٫yrg8d'!=}D@WrzDzexdށuG%H" HdpCpEr7Od 
~H5IK2$ !f>HG!א*ʄ;0z>S{V%ٸ
8qAAH_.uɓrXaNOؽ{"yd			"ܿ𱱱ŽU>{EEE…rߥg(EQh4%IBƍQNgZ]hڵk+k/^5kmz)]ߺur!7jHx%##۷/7X*$XF
ժm۶m+wheYرjdC}f̈́AbQX
m;)LLL@Zj077/wh	
}Q8ԵjJ	^�@RYw'Աd.3@޽{С7o\p%''D޺uK�ˮʉ
#,hz>Aiӄ3?z*KII:a3ddǎv\u,p>}auu{瀦I_	zVZ8w\q	24e˖-[l)6zB3OWt,ײrH YJ=�ͦ>|BGt\\J=Wo
4ٯ_~_WWr@3-'GaN͛7܌ySjJSh^//ܽ{WphɓT.8)Ms,l,rcVfh4088XDEyKWࡃZƍ'<Dy"`Q&wT@SHj 77R)@T
4ƨb͍M6b
m('6{ 34ROa1cF9=#cbb:ݻwopc$󜒇dI,*q4i"cΕCV/]vډx"\UM}ͣ,eZ?B;ꕣ08ʱ#2KT+>}4Eԓ>VBwOɿ6"UQ����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/poweredby_036.gif���������������������������������������������0000644�0001750�0001750�00000001450�12732165123�022227� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89af�&�������3f@p0YPsq���������!���,����f�&��pI8;`(dihľp,ρ;S{5n䁌2[Wc"MfFҘR#F*Tbi[XڊKJuv7$f}W<VVZ,sA.cBihj		Ĭ	% 
! 		#Pw`@\�{�U@2&�4& �Xŗ�a�X@H N`e�,lC*43iFV2L ZЌBہЧ�"Z�VvC\|8duRԴ)%@@S	pVl.-CprN
3fB]	B|VqY3;{XjDI5L8"lwZ`ɗ?w,"s	dܰ	�ӳ.gaptL@^<QC%Ĥ�ƛ`=9cfEF5]=G&ܥw%WTYobV5POnh`Q'@5ddkZa @TSqĒkUmd9!4,SOgq=mhq˔VOUcTfǔe	 XzJj\R:)NDń*ꨤjꩨ*,��;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_sortright.gif��������������������������������������������0000644�0001750�0001750�00000000172�12732165123�022674� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������j?S-Z}ZJt)���������������������!���,�������'IW`+Φ}@fE[ =d[�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_sortdown.gif���������������������������������������������0000644�0001750�0001750�00000000165�12732165123�022530� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������j?S-Z}ZJt)���������������������!���,�������"I8뽅QAE1qk檬\|E�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_confirmsml.gif�������������������������������������������0000644�0001750�0001750�00000000136�12732165123�023020� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a������������!�����,�������/+(7`נ�Ꙇ+BBZ"��;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/pdf.gif�������������������������������������������������������0000644�0001750�0001750�00000001666�12732165123�020421� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����
�?&#"5*++A:@1G8Z>ecGJ^O[bhaeqmw~zxr5' ,942&(ITBYWL\O^]HHMTWa[jLa_t`MdYarfpffinayrz~xwvKOMSKPKQPKPJ^ZCgrqvxsyzws}̉oσưЀӇ݁܊ډވًݐӜݙٞڗۧߧܮνئޡؽ珍툎鎝钘䟤䪞릟梡楫䮢꯱ೠⳡ簩꽸ôƶ���!���,��������	8cA*rE5A.^`ɓw&`s)yBh˴5]LJ0 cU*a
Ac!;=iQR7*SAb([m4@slQ1Opę#D%		�;��������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_med_hi.gif�������������������������������������������������0000644�0001750�0001750�00000000057�12732165123�021572� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������a�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_waste_lrg.gif��������������������������������������������0000644�0001750�0001750�00000001414�12732165123�022636� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������PqRiy~[vYsWqTmRjOfNe_{]x\wWpSkPgMccb~UmQhOeNdgjkppqtu|ÙǗŘŝɜȡ˨ϩϭҬѰӳշ׸ؼھ\uÓßʤ͹؃ɝظѫ���������������������������������������������������������������������������������������������������������������������������������!��T�,���� � ��TEGDC	AF'2CC:?>F:QQ:<G9
''7
'::225TBź''3	C2'1@ݤ/MQݻ>BXKtx0H%$+jbB_ʐ]1ä#	˜�EaKRZ"1!l̚4a=0?]AJa45tHN)jS$Ԫ5LWi<vdSTu"%a,<lN$H2+0$Юz
 �Yf]jrH@C!ذ
y0j&]`3sA„(`+�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/se_maj_rond.gif�����������������������������������������������0000644�0001750�0001750�00000000062�12732165123�022115� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������	
y�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_info_lrg.gif���������������������������������������������0000644�0001750�0001750�00000002547�12732165123�022456� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������Um	'S(Bi+Fm6OsG_H^H^_|]yYtVpSlRkLcJ``}XrRjQiOfNeMdH]}bLbI^~egjlmoWlpqtuzg|{~luxzt~wz’Å|ǘƗŗÝɜȐ˕ΨϧΩМѫС±԰ӲԳյֶ֧Ÿؽۼڬȯʭȿ߸\xco}Ŕǃʤ̢ͣˮҤúٹدɮȳ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,���� � ���k	H*\ȰBqsGΜ:qAL10*�Rʚ5`�'B8NJ)`%K�)j(%|ҩr�OvJUL:eO4h0!PTӍtx%KBŊ*WDƑ5w'էW88'PZ9hH-T72kKSChS8h	̪`bMLRAd0S-:mA<sX39cEw͔9qܤ8eյ}ݥ`A;tܠt Jw}yF|DAV_]\^1IDEcP\CuEzhAl!+@AU~e<rAHx$p�ܵHxA#T@A@7a]LTE$XB!!C=~3uĕSDpi~<pWRP"{4DsvEу9(F<T FYDbD;0
qBb 
5dB0
*@B`"hP&C+n@�;���������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/collapsed.gif�������������������������������������������������0000644�0001750�0001750�00000000065�12732165123�021606� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����������!
��,�������D`c5
�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/sw_med_rond.gif�����������������������������������������������0000644�0001750�0001750�00000000056�12732165123�022140� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������DnP�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/help_logo.gif�������������������������������������������������0000644�0001750�0001750�00000004101�12732165123�021603� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�4������111mb6a䅳_܅ߍ!
1*KB!_T,^S,ZP*OF%SJ'dY0nb5l`4h]3yCi]4|EK~GzDwk<V{FMɵh`W{wvutsqϹlebWU݁ۀ~}|zyyxxʵj_^\ZYXނ{ԿpӾpف'!
;3SI'иk̴iʳhȰgcMq־oӻmѹlϷk͵jYq׿pսoӼnưgVT+$yFb[Zba`__^]]J}I{HƮfŭeëdLKOWVUUTSRQYXzGJ{HxFNMK|IMLKuDsCqBn@xFoAg<}f;{d:k>|e;x`8t]6r[5{c:w_8nV2qY4ȼ}}}pppcccWWWJJJ>>>���������������������������������������������������������������������������!���,�����4���	H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@
JtKa6TɑK IBHHEwZ
`(44TVbHH@B	xEA=|AFۚ_^(`
mɣgӤLH(؀"ɕ-cFO5<ˬ@	0BDА#VXVfa0-Y!j&K$lB'PON
~bswy{GrŐMkзysˤm\7_.I1XtJpӍ~qxIE �uKx
N\A EGma�ِe#7l
9`c,)r1!r<1vdFA9q3�9shĊ
>d�rI!%qG_R#ŒyAPZ73Jp׭!tTd0uT(zФe*pR()qtXlXH$Tc*qj4d^zUA77Iݔ{.BvHκ6߈#7ꍾ{)rqpa$tH'ɀ;ݔ3M
$l<8$I豙tq91cIct<2"I(<3"Nja8+8b9$$8#'6**8]3q8p㦬FvmcmDr
3G#=!;6!�=6\M!fMP[N6rp]|H%1У'Ҍ	NNڬi7d.D@aLw]xaz%PM"z.貌Qh9/NȎ.zA`s$2Q.L!Sq+P
QE,dROlԧM.x$x?mDȳ2NbUT'L@ɂˆBP%65YQ͑aP~d"n%.@D�okgQfT!4f~-�8|xC ~kc,1^43qdLp9FǕ##Q|? <p4l8c1p DȲ#,>h?+2鍐
 f$FhB)Hh^a�
cpd$5Aqs&Ւ(k!I8)#HB͓XpLڸbXDLYO\f?ρՉڙІ:	�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/newwindow-classic.png�����������������������������������������0000644�0001750�0001750�00000001667�12732165123�023330� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR������	���Ӻ&���tIME
8e1���	pHYs����iTS���gAMA��a���PLTE�0`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������e���tRNS�
A���+IDATxc`bbb�&	L2022"x0s`d��Z����IENDB`�������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/expanded.gif��������������������������������������������������0000644�0001750�0001750�00000000064�12732165123�021427� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����������!
��,�������j
�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_folder_lrg.gif�������������������������������������������0000644�0001750�0001750�00000003014�12732165123�022764� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������߭׈ܑܓٓߪڴچ֍ԌˉǽwyLjʜ䈾puzۂr}|{wvuttssۀۀ~}|{zzyyxxwvڀиkζj̴iʲhʳhɱgȰgǯfcqp־oԼnӻmҺmѹlϷk͵j˳irq׿pսoӼnYb[Zbaa`__^^]]\[ƮfŭeĬeëdªdOWVUUTSSRQY|zGwEJxFM~JLKxuDsCqBoAn@xFvEpBoAm@yGʁɀg<}f;{d:k>i=~f<|e;l?j>rZ4s\5r[5{c:ya9kT1fN.٪vԠt節|ަ{ۢyߢ|ߞ}~桂ܛ|���������������������������������������������������������������������������������������������������������������������!���,���� � ���	Hʳg>n"=mظ�CHadHԨMN�\iQJ�$y�ѣPtLh@B.6>hybTyL5p]ŠCB
N,\ɲE#JLQo [e2fȑ!+@ "Af
ԂGl1w�zI+8:Ј+Y1<E0SX11np�f
1fPz "g E
%0PKQ!GhXqS$H9^9֬6_>FB@r@l152Elxaod
 \@ƒXQ/PFFH$#w.Q5Ҙw}ыA%*huRK~2CeqVWlGqCH2cPF&!grԑA&fT1EoaP'Ё	.(AaWg\Bs`r-E&,)UaFXlȚn!bGek|h&4.-hjDxP pڱH'(3`_ZH!Hp	
2X0\la hH.Ǥb@� xBA%|2L2\<*RC~!%b,*J,oG#K0A\"tRL2} Xr""-ŞhM@�;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/remove.gif����������������������������������������������������0000644�0001750�0001750�00000000343�12732165123�021134� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����!ᕔHJG=9121۽NJgduqMusVQLH!���,������IûeY(jh ,Bǫ.xD]/Y0`h� �@N0-PpV2�GA\ތ@`PC‚h &<)<]
X%
ng~
v?\	
c
8W�TM�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_min_hi.gif�������������������������������������������������0000644�0001750�0001750�00000000056�12732165123�021607� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������sP�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_doc_sml.gif����������������������������������������������0000644�0001750�0001750�00000000543�12732165123�022271� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������хtWp#.>]y[wYtXsUoJ`\xRjDXvtzŧΩЬѰӳյֶֽۿܾßʣ̢���������!��<�,�������@/Z,&N($lrh�[@W'CH`Fhp(i4咉8dVTmo%'d:5	$M2%Nd-4*#N vM.;63	($ 1N9n%/M)"0/BBA�;�������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_sortup.gif�����������������������������������������������0000644�0001750�0001750�00000000165�12732165123�022205� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������j?S-Z}ZJt)���������������������!���,�������"I8ͩql!AXIZVGmn<�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/add.gif�������������������������������������������������������0000644�0001750�0001750�00000000317�12732165123�020370� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����*|~Η0XpN>tA9CGOs+ج!���,������|I8kl_@4DJ,lѠ*e|q8HH ET8(`"B`�A`iM0[!KǸ|NianVXp\�
KXDNNRmKcEXcJn#�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowusergroups1_sml.gif���������������������������������0000644�0001750�0001750�00000002060�12732165123�025072� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������JS
SAb.iVm[DCY^#T"[5bFIK/a
PR@;%P<}f|T:{:u!=|VNɌwt}{z~̴иkc͵j˳iսoӼnηphǵx՜'D\b«igfWTYrw|ILM}LP`huHrFtHrJya|jZAzTl_KoHwS(QF9]OVK?U*�wvsrpvzys_yz"$`8*r4x>zell
iwv|'P%�Zad}m_WRO]IJ�KM%	FD	C�<0=�%;7
�3	�2�VUUӫlll������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������k	H",c"
#"U$d̓Zcظq`B.JhB@X8s|EP
*hHsĈ1|ʕ,YfI͒ /
a
zu5_hӃ3a18V*UY@KSL!Dw]@H`�?|-$hP(@v#HoP*Ѐ	rʣ#L
\B	%NHBaC>atiSQNRV	 F
N%PPb* �;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/fix.gif�������������������������������������������������������0000644�0001750�0001750�00000000265�12732165123�020430� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����-H/Ʊ8)&#騦rT:$TRTxwv!���,������b9
^+_'nYE1REAeWܮQ!{pK�e0�`!5�	VJ`Q7
 )�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/folder-closed.gif���������������������������������������������0000644�0001750�0001750�00000000334�12732165123�022361� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���zzzfff������������!���,�������pIxN)Kq��A0Hr@*)'RAp`�A:8B`xb�UU( ]Ja
(N
mwqG
`Sc+&t#5CE5ZuA7)f!)+	qz�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_maj_rond.gif�����������������������������������������������0000644�0001750�0001750�00000000063�12732165123�022133� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������

��;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/sw_maj_rond.gif�����������������������������������������������0000644�0001750�0001750�00000000063�12732165123�022140� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������
D~Κ��;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowmembers1_sml.gif������������������������������������0000644�0001750�0001750�00000002061�12732165123�024307� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������4D[Rj4CY!*8tds^hwgp~ѱԲԽۿܾ7H`=PjŚǺ[jzYjnY[ZTlXC\A>l*6]#`Gfs`TxAd&c&T+r>r?R.Ew(hF=	c&a&a&f-i/h0c.j3j4l6i4s;,JxEa"`&_(r?6XTY ](S[(PLq(-OJvN|!1Knjoc#Ed?P
9=wtz~иkc͵jսoηp'D\b«igf
��TXrMP`hrFmEnGrJVUU̫lll������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������?	H*HP>
(P�aΡ? @H|iH8
!
i`	H-'A1]ĉSN0RX02HO^ZRk"MzD)Xt+
VDJ&w;%(a&( "nj)IpĀ^$G!E R2X@@EIO
:@00"
G\0E@	ANd4i~4K*]ȜQhQ@�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_maj_hi.gif�������������������������������������������������0000644�0001750�0001750�00000000063�12732165123�021571� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������

��;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_help_lrg.gif���������������������������������������������0000644�0001750�0001750�00000002612�12732165123�022444� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������mb6a䅳_܅ߍ!
1*KB!_T,^S,ZP*OF%SJ'dY0nb5l`4h]3yCi]4|EK~GzDwk<V{FMɵh`W{wvutsqϹlebWU݁ۀ~}|zyyxxʵj_^\ZYXނ{ԿpӾpف'!
;3SI'иk̴iʳhȰgcMq־oӻmѹlϷk͵jYq׿pսoӼnưgVT+$yFb[Za`__^]]J}I{HƮfŭeëdLKOWVUUTSRQYXzGJ{HxFNMK|IMLKuDsCqBn@xFoAg<}f;{d:k>|e;x`8t]6r[5{c:w_8nV2qY4������������������������������������������������������������������������������������������������������������������������������!���,���� � ���	Hv"IQ$C}zp % 	8РA
%?|!`Hu#8H+~ٳ̙5zqB
*jHO=CE*L0Ubz+>id�h(2D#UںMFMR*r##`n5[^ltaR$rsCm_OIi6nhAX"'acd1}p-t
eF+s,H7\ulljd%u#IT)zlEϟJHt'	#rP"1 ejDY TQUb1yofGDvd1	%<0 Fd\R%*s)5noQQ$�&ɈF*ׅd4r"'0s-k`w!QI($s+G|L""@	
tAE|NBdL	r2Hr*b'R-('E.fgh2/t!*,$#MGK/K.(sk'.31Ō,`0~kn3ܢVC,j324$DQ@�;����������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowwaste2_sml.gif��������������������������������������0000644�0001750�0001750�00000001141�12732165123�023777� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������4W냗Ӱ`}\xPhEYxbUn`{hjlkyƗŝɧΩЭҫб԰ӲԳյֶּڿcǟʮҹVUUlll������������������������������������������������������������������������������������������������������������������������������������������������!��O�,�������O'!!;<	F
3/6)BA+
817*+?C77D6KJ*5C%9JIILLMMN11,(:J؆)72#"م8C-:JM
Xw `�6LxP+҂ˀ!.9ЃGC`)"'QF9P �;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_warning_sml.gif������������������������������������������0000644�0001750�0001750�00000001100�12732165123�023157� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������b`awr}~j|fsη⣴[M@K?
kTN
GJ$wsrpiffecb_[ZTQOJ
EDE?i2	nm]XWVH
A=h2	]-bz{z&Zi&i(j&127m-D2%p4BI|Du@Ya\}R׈[v[mI:2̓`vّs=.()+*砅.!ӗ<,&餍5&!:*%y*vp묜*,-~zǟ���������������������������!��v�,�������v	oaed][sv
iT
u^PW\ZMIgXUGADSRQ?4VONK)#CnJHFE0=7'6*vB@%+8,l !5"9.:/Lt"$&(-3:cYf3cđ#
;��;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_folder_sml.gif�������������������������������������������0000644�0001750�0001750�00000001172�12732165123�022776� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������ـ{~r}|wvuts~}|zyxxwtиkζj̴iʲhȰgcq־oԼnӻmѹl͵j˳irսoӼnb\[aa``__^]]\[ƮfŭeĬeëdyOPWVUTTSRRPNYXwEJ}IMK|IO}\oAtDpBoAm@yGi=j>zb9ya9lY:nV2mU2kT1jZBdM.bM1bM2���������!��|�,�������׀eJHHIO|#!:N|_UH`@F78b7*
4i_Sf$A"%4?_KWD&]|g#XF;*f|W#B
	 4.Z|[#-7#)371?\|U'E+(!602GSH|40p
N&UX!xxB$H,TADeN�eL9=ad/WAȑ9GhGJ͚o֐sQ/z�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_usergroups_sml.gif���������������������������������������0000644�0001750�0001750�00000002002�12732165123�023732� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������JS
SAb.iVm[DCY^#T"[5bFIK/a
PR@;%P<}f|T:{:u!=|VNɌwt}{z~̴иkc͵j˳iսoӼnηphǵx՜'D\b«igfWTYrw|ILM}LP`huHrFtHrJya|jZAzTl_KoHwS(QF9]OVK?U*�wvsrpvzys_yz"$`8*r4x>zell
iwv|'P%�Zad}m_WRO]IJ�KM%	FD	C�<0=�%;7
�3	�2����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������m	HAjD@14N`)kBD<3><9ŋ+ɱF7L19PĐc,M!/eHL%t'G0=jtI`\8PgP F2B$A`PgQ"@
QDg
&P?&u
2l ǐ%NBJu
>(QVrʖ!HCJRZ%+ �;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_alertsml.gif���������������������������������������������0000644�0001750�0001750�00000000232�12732165123�022467� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������ӯz{{aaj__������!��
�,�������G�L�FU6*J|޼He" q
a,	
r0b)ϖ�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_med.gif����������������������������������������������������0000644�0001750�0001750�00000000060�12732165123�021104� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������a
�;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_error_lrg.gif��������������������������������������������0000644�0001750�0001750�00000002773�12732165123�022655� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � ������
i	c	_FGBCfg
w	t	[



~

|

z

r	p	n	f

y

w

j	t

s

g	!{lZ$&FHilfhjmdf٨#"!)!,U[".$1&2,;)6W`)1BJL-;v!*ۯ6H".8KP:Nh']"-9䱷8KAW>RCYBXD=LS]G^@UJbF!H"M%ܶOiT*PjQlPjIaH%Zh]#09L= UqToOi[jXvYxZyJ*Xv`^~e-<E\^*9echws{:Ni~oQlIaSn[zove{bsm}Ɲ[wXsTnLcG\|CWuWqRjPhNeKaI_H]}DXvb_z[u5D[gq{~ØƝɡ˨ϧάѱԳյַ׸ؽۿܾ*7IŚǟʤͯӺٹ3.@?=<!���,���� � ���	HZ-4@ǏρvF@X3.Wc7e8qwMSfN[I0D#>Jʆ
;T`Ê,][Ī
ɾpGW3ok1v4_*5jO1%
\(L,ARd(7m=<P <qЀid`W@aiѢʗx叻]o\'ډ9'N2dHydAhQu)e$9"t63hR
	S,ͣ a£D}qFmQ=4p	�)'ocFMP
(XuuJRܳ	`pQTdF[�

p(bw)}	oQ<DD|�A,hpG{+S	N(qBd�Cp@܃NTƒ9L G�GCxA/1*tI<HH`�	Q!|LEzKp4	ؐi _2:9
SL`@#<P�%0B9( Jl0"4\JAɴ9t6\S0alBA7@V[0S*h"/�60p
7dc;HN4Ь"tr ;|%31I/Ҷr.ȒK.,̤�;�����testng-6.9.12/doc/samplereport/images/icon_arrowusergroups2_sml.gif���������������������������������0000644�0001750�0001750�00000002064�12732165123�025077� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������JS
SAb.iVm[DCY^#T"[5bFIK/a
PR@;%P<}f|T:{:u!=|VNɌwt}{z~̴иkc͵j˳iսoӼnηphǵx՜'D\b«igfWTYrw|ILM}LP`huHrFtHrJya|jZAzTl_KoHwS(QF9]OVK?U*�wvsrpvzys_yz"$`8*r4x>zell
iwv|'P%�Zad}m_WRO]IJ�KM%	FD	C�<0=�%;7
�3	�2�VUUӫlll������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������k	H",c"a)<E	3D|53Ojb	S
ra,VE-\HQ)KVKjPA#G#F|Y?	YE^PA#LħO
\%0=H9Mh4%4I"I*έ"J!K
<p!Cʃk)Ѐ	rʣ#L
L]kA
0h'PK8"%j@2taK:2u**K�1"Ou**jV�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_alert.gif������������������������������������������������0000644�0001750�0001750�00000002140�12732165123�021753� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aj�g������((;;QQ__~~���������������������������������������������!���,����j�g��` dihlp,tmx|pH,#A0h
pZV \tZ	tiv2
݂dH^wtGlrHmHewFw@

_		6
	W	

1m+¿f	
%Т_۬#
w
f�ͭ[`Pzn	IA@kP\[
nD7'hP$[�dڥls-Mo,tĈHY2WT1NhItJ6a\$7A)0j&֩#	i�6n]ݦhVHegOr4bvJ^}_4WVfG	\c2Cv-CI7.j(	6.~:{[os 9.>Y�+@{կڏr|(ٿX'v3lO=47< V@`#) 0B_pVy<$a‰4Ő\ :TX":Ds;dc7CBP =z4�†`)KswS$fRa`=f%Hsb&0s͛)i3e
.Rw8l^(y yX_#�ʐb@#|z]Em *
z&\a(G)	ɑakښ6M`H`[,(*M4$;[~xQ
l:V"]N2,tZ�ӎdG!�VQ!(/+[׊"yQJ<C�wBr-rr*0S
@@$q=^FC0{خNIGSOX_4	匵,lBD_C$	-J6?7o76{߀.^G�;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_help_sml.gif���������������������������������������������0000644�0001750�0001750�00000001773�12732165123�022462� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������~K|sH~݁{ۃ*$6/KB"bW/aV/HRSWW}{wuttq[݁~}|{zyyxwvuuƱh܁ڀ}zw܂<4dW/rd8~GSζjʳhȰg`qpҺmйl͵j˳icr׿pӼn4,Y[Xb`_]\ZƮfŭeªdǯgXWVUTSRQPYwEJ}I{HN~J|IOMuDqBn@m@yG{d:k>|e;rZ4x`8t]6jS0nV2qY4iR0X@&������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������5JF7pرBF6.H(�
:�F`
$Xx@aB
AftltA&@DH
7s4!"$?h#"2f*W¡
 F<r [hѣI%X"H,TabD	/khf+iΞDX&̘.lSg;u'C>݈Ds,�;�����testng-6.9.12/doc/samplereport/images/folder-open.gif�����������������������������������������������0000644�0001750�0001750�00000000345�12732165123�022053� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���fffvvv������������!���,�������pIx!�0d@@:m.4R@� @�ЂJ CPD%l	"�(`@@{Ԑ괶uNolO)L&s#	!PxYE<'M4%w	LB|�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_maj.gif����������������������������������������������������0000644�0001750�0001750�00000000061�12732165123�021107� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������
B�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_min.gif����������������������������������������������������0000644�0001750�0001750�00000000063�12732165123�021125� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a����������!���,�������-!R�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/product_logo.gif����������������������������������������������0000644�0001750�0001750�00000001250�12732165123�022335� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a��������3f5]u���������!���,�������I8ͻ`(dih,Am}/υ0Hlv$1cS*'Jt
{2DSOK
MBcuTwM}%O
k2
{B10b/g[n1{fV&^PrfbOCh	BŚxCJ&J1̼P
[gz	F	AfY#O$cC`L=D<ŒI	Q T,Y8S&O`{ӂ]FM0cLn�%)҃G�;0mR-zÂY&])tG!pY!miE8gPe*{4i6YCG]o 9"_QNr,Wn쵲O,KS$s+f?ZOX-\T	0Mdh(iL./UeV5sn@bU�д�1vht	СklO%DUmMM'AwuLE쀍I:C a}2G(@<Xf@Fd7%Q!@)DN�;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowfolderclosed1_sml.gif�������������������������������0000644�0001750�0001750�00000000671�12732165123�025327� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������뀀יވً|vutqվo}x{~ك{̴ipѹlϷkɱhsӼnl„`]ZŭecOWT}IwFLoBh=u^7jR0VUUmmm������������!��;�,�������pH,HQ(V0;oPaaPZ(q -#Lq0$+_sP(wD722E,
&	0_C,x2;!&'
"q:;#+'C7B1'
"#3_t4+ &15,rt;/+-4ha `ԸF4D
Za��;�����������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowfolder2_sml.gif�������������������������������������0000644�0001750�0001750�00000002070�12732165123�024131� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������ـ{~r}|wvuts~}|zyxxwtиkζj̴iʲhȰgcq־oԼnӻmѹl͵j˳irսoӼnb\[aa``__^]]\[ƮfŭeĬeëdyOPWVUTTSRRPNYXwEJ}IMK|IO}\oAtDpBoAm@yGi=j>zb9ya9lY:nV2mU2kT1jZBdM.bM1bM2VUU׫lll���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������	H`%H$y2pDN
J	 
b&x‚T( @iL13R" "r˒+D p0ѥ3#6`1Ã
蠁fX!xe!
 @4\hgϞ?�
-nذa3ne rJrȊ~QCƑ)H[ 
p48F(FT	c @~H"/	R%:~$ƖHeN�eL9=NTæ%_FH7r0'5߬!cz^D1�;������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_arrowfolder1_sml.gif�������������������������������������0000644�0001750�0001750�00000002072�12732165123�024132� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a�������ـ{~r}|wvuts~}|zyxxwtиkζj̴iʲhȰgcq־oԼnӻmѹl͵j˳irսoӼnb\[aa``__^]]\[ƮfŭeĬeëdyOPWVUTTSRRPNYXwEJ}IMK|IO}\oAtDpBoAm@yGi=j>zb9ya9lY:nV2mU2kT1jZBdM.bM1bM2VUU׫lll���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!���,��������	H`%H$y2pDN
J	 
b&8ƅ(P@�
4|b`>$"g	?,B]lÏ
X:h9ϟ?L%^A$p
Zl~-nذa3nE.?t%V9Qd�(B؀!$H
N&UX	H3I"AdBǏM9	 `3G9ad/WACrD7r0'YCΝy}@�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/icon_members_lrg.gif������������������������������������������0000644�0001750�0001750�00000003042�12732165123�023144� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a!� ������燱ԋDXv]]b&2CXsSlRk^zWqH]}EYxdhz˧βԷ׶ֽ۲߹Ўtɣ̺ٞvyz⢦iT^sNq/-//.37<>CEKn9PVT\\e|TczKeՊgxUy}*{),~+|*8EITb8_mr}w%{(y'x&z(}-}.2:MR[`etxLUAu$t#r"u$t#s#v%w'z,j(~5FYjpr!p o q!q"t'>Rbmnu*Ekiw/Wq(ghy4eg"ca|_w_yvX^t]q[len;UcFK~HMW\*GJxylHKEFFF?>lhNutsۀ}{yxx܁иkʳhȰgԼnѹl͵jrӼnb^[ªdaŭfWKyGOMqAzf?k?lAoX4eM-e\P!���,����!� ���	H<Nv)Hp^i͞	@ʼn	PVY2fӴ߼o%[fXG.@Q'Az]T4d@UQ׭bˊ
,Y
w7hM)kGG
 -A{q
FdM
p#c7VU:ٮyUw=PtigC^:seÆ[4;͏_GK'9kԸWPn$aǽ{؍Wn޽
͖ @+ˇ=z<E@9S(?~eFhd2sw^y58_|!F/fsF!!u>q@Wd`Ae5q"x>yEV`rxAMa$9JHD;4QTX! sB!\r	&t7RHFmQp bI!„
V:RYk1~�H Tʥp=Yq!zAy(҈$P
(b
BYh�!~q"8ˆ&|b*
C :�@Ђ\B#tI)
++.B0{jvI)+B.@j	$0I#k.<K-.l P	"DkL-|,>hpmd	"!JH"1L/4P38]!P?P�vIX0 sDwwA�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/external-classic.png������������������������������������������0000644�0001750�0001750�00000001674�12732165123�023127� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG

���
IHDR������	���Ӻ&���tIME
89���	pHYs����iTS���gAMA��a���PLTE�0`���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������e���tRNS�
A���0IDATx=A�0`+q0uȄGzZy6S߱�^ȱ����IENDB`��������������������������������������������������������������������testng-6.9.12/doc/samplereport/images/nw_med_rond.gif�����������������������������������������������0000644�0001750�0001750�00000000056�12732165123�022133� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a���!���,�������\�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/index.html�����������������������������������������������������������0000644�0001750�0001750�00000027033�12732165123�017705� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������





<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title></title>
    <style type="text/css" media="all">
      @import url("./css/maven-base.css");
      @import url("./css/maven-theme.css");
      @import url("./css/site.css");
    </style>
    <link rel="stylesheet" href="./css/print.css" type="text/css" media="print" />
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  </head>
  <body class="composite">
    <div id="banner">
                          <span id="bannerLeft">
    
            Core Library
    
            </span>
                    <div class="clear">
        <hr/>
      </div>
    </div>
    <div id="breadcrumbs">
      <div class="xleft">Last Published: Tue Jan 24 22:40:49 EST 2006</div>
      <div class="xright">      <a href="http://tacos.sourceforge.net">Core Library</a>
      </div>
      <div class="clear">
        <hr/>
      </div>
    </div>
    <div id="leftColumn"><div id="navcolumn">      <h5>Project Documentation</h5>
    <ul>
              
        <li class="collapsed">
          <ul>
                  
    <li class="none">
          <strong><a href="surefire-report.html">Maven Surefire Report</a></strong>
        </li>
              </ul>
        </li>
          </ul>
  <a href="http://maven.apache.org/" title="Built by Maven" id="poweredBy">
              <img alt="Built by Maven" src="./images/logos/maven-feather.png"></img>
            </a>
    </div></div>
    <div id="bodyColumn">
      <div id="contentBox">
        <script type="text/javascript">
function toggleDisplay(elementId) {
 var elm = document.getElementById(elementId + 'error');
 if (elm && typeof elm.style != "undefined") {
 if (elm.style.display == "none") {
 elm.style.display = "";
 document.getElementById(elementId + 'off').style.display = "none";
 document.getElementById(elementId + 'on').style.display = "inline";
 } else if (elm.style.display == "") { elm.style.display = "none";
 document.getElementById(elementId + 'off').style.display = "inline";
 document.getElementById(elementId + 'on').style.display = "none";
 } 
 } 
 }
</script><h2><a name="Summary"></a>Summary</h2><div class="section">[<a href="#Summary">Summary</a>][<a href="#Package_List">Package List</a>][<a href="#Test_Cases">Test Cases</a>]</div><table class="bodyTable"><tr class="a"></tr><tr class="b"></tr></table><table class="bodyTable"><tr class="a"><th>Tests</th><th>Errors </th><th>Failures</th><th>Success Rate</th><th>Time</th></tr><tr class="b"><td>7</td><td>0</td><td>1</td><td>85.714%</td><td>190.072</td></tr></table><br />Note: failures are anticipated and checked for with assertions while errors are unanticipated.<table class="bodyTable"><tr class="a"></tr><tr class="b"></tr></table><h2><a name="Package_List"></a>Package List</h2><div class="section">[<a href="#Summary">Summary</a>][<a href="#Package_List">Package List</a>][<a href="#Test_Cases">Test Cases</a>]</div><table class="bodyTable"><tr class="a"></tr><tr class="b"></tr></table><table class="bodyTable"><tr class="a"><th>Package</th><th>Tests</th><th>Errors </th><th>Failures</th><th>Success Rate</th><th>Time</th></tr><tr class="b"><td><a href="#TestNG Suite">TestNG Suite</a></td><td>7</td><td>0</td><td>1</td><td>85.714%</td><td>190.072</td></tr></table><br />Note: package statistics are not computed recursively, they only sum up all of its testsuites numbers.<h3><a name="TestNG Suite"></a>TestNG Suite</h3><table class="bodyTable"><tr class="a"><th></th><th>Class</th><th>Tests</th><th>Errors </th><th>Failures</th><th>Success Rate</th><th>Time</th></tr><tr class="b"><td><a href="#TestNG SuiteTestNG Suite"><img src="images/icon_warning_sml.gif" /></a></td><td><a href="#TestNG SuiteTestNG Suite">TestNG Suite</a></td><td>7</td><td>0</td><td>1</td><td>85.714%</td><td>190.072</td></tr></table><table class="bodyTable"><tr class="a"></tr><tr class="b"></tr></table><h2><a name="Test_Cases"></a>Test Cases</h2><div class="section">[<a href="#Summary">Summary</a>][<a href="#Package_List">Package List</a>][<a href="#Test_Cases">Test Cases</a>]</div><h3><a name="TestNG SuiteTestNG Suite"></a>TestNG Suite</h3><table class="bodyTable"><tr class="a"><td><a href="#TestNG Suite.TestNG Suite.net.sf.tacos.ajax.components.DialogTest#testClickDialog"><img src="images/icon_error_sml.gif" /></a></td><td>net.sf.tacos.ajax.components.DialogTest#testClickDialog  <div class="detailToggle" style="display:inline"><a href="javascript:toggleDisplay('net.sf.tacos.ajax.components.DialogTest#testClickDialog');"><span style="display: inline;" id="net.sf.tacos.ajax.components.DialogTest#testClickDialogoff">+</span><span id="net.sf.tacos.ajax.components.DialogTest#testClickDialogon" style="display: none;">-</span> [ Detail ]</a></div></td><td>189.174</td></tr><tr class="b"><td></td><td>Connection timed out</td><td></td></tr><tr class="a"><td></td><td>  <div id="net.sf.tacos.ajax.components.DialogTest#testClickDialogerror" style="display:none;">java.net.ConnectException: Connection timed out<br />at java.net.PlainSocketImpl.socketConnect(Native Method)<br />at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:372)<br />at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:233)<br />at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:220)<br />at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:378)<br />at java.net.Socket.connect(Socket.java:536)<br />at java.net.Socket.connect(Socket.java:486)<br />at java.net.Socket.<init>(Socket.java:394)<br />at java.net.Socket.<init>(Socket.java:267)<br />at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:79)<br />at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:121)<br />at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:704)<br />at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:384)<br />at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)<br />at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)<br />at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)<br />at com.gargoylesoftware.htmlunit.HttpWebConnection.getResponse(HttpWebConnection.java:139)<br />at com.gargoylesoftware.htmlunit.WebClient.loadWebResponse(WebClient.java:1523)<br />at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:325)<br />at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:377)<br />at net.sf.tacos.ajax.components.DialogTest.testClickDialog(DialogTest.java:50)<br />at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br />at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)<br />at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br />at java.lang.reflect.Method.invoke(Method.java:615)<br />at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:461)<br />at org.testng.internal.Invoker.invokeMethod(Invoker.java:378)<br />at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:580)<br />at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:89)<br />at org.testng.TestRunner.privateRun(TestRunner.java:612)<br />at org.testng.TestRunner.run(TestRunner.java:503)<br />at org.testng.SuiteRunner.privateRun(SuiteRunner.java:218)<br />at org.testng.SuiteRunner.run(SuiteRunner.java:144)<br />at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:576)<br />at org.testng.TestNG.runSuitesLocally(TestNG.java:539)<br />at org.apache.maven.surefire.Surefire.run(Surefire.java:236)<br />at org.apache.maven.surefire.Surefire.run(Surefire.java:128)<br />at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br />at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)<br />at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br />at java.lang.reflect.Method.invoke(Method.java:615)<br />at org.apache.maven.surefire.SurefireBooter.runTestsInProcess(SurefireBooter.java:345)<br />at org.apache.maven.surefire.SurefireBooter.run(SurefireBooter.java:258)<br />at org.apache.maven.test.SurefirePlugin.execute(SurefirePlugin.java:477)<br />at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:415)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:531)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:472)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.forkProjectLifecycle(DefaultLifecycleExecutor.java:859)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.forkLifecycle(DefaultLifecycleExecutor.java:731)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:522)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:472)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:451)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:303)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:270)<br />at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:139)<br />at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:322)<br />at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:115)<br />at org.apache.maven.cli.MavenCli.main(MavenCli.java:249)<br />at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br />at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)<br />at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)<br />at java.lang.reflect.Method.invoke(Method.java:615)<br />at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)<br />at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)<br />at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)<br />at org.codehaus.classworlds.Launcher.main(Launcher.java:375)<br /></div></td><td></td></tr><tr class="b"><td><img src="images/icon_success_sml.gif" /></td><td>net.sf.tacos.services.SiteMapTest#testInitialize</td><td>0.006</td></tr><tr class="a"><td><img src="images/icon_success_sml.gif" /></td><td>net.sf.tacos.services.SiteMapTest#testCategory</td><td>0.569</td></tr><tr class="b"><td><img src="images/icon_success_sml.gif" /></td><td>net.sf.tacos.services.SiteMapTest#testContains</td><td>0.138</td></tr><tr class="a"><td><img src="images/icon_success_sml.gif" /></td><td>net.sf.tacos.services.SiteMapTest#testSitemapXml1</td><td>0.05</td></tr><tr class="b"><td><img src="images/icon_success_sml.gif" /></td><td>net.sf.tacos.services.SiteMapTest#testCategoryLists</td><td>0.117</td></tr><tr class="a"><td><img src="images/icon_success_sml.gif" /></td><td>net.sf.tacos.services.SiteMapTest#testUnsetResource</td><td>0</td></tr></table><table class="bodyTable"><tr class="b"></tr><tr class="a"></tr></table><table class="bodyTable"><tr class="b"></tr><tr class="a"></tr></table>
      </div>
    </div>
    <div class="clear">
      <hr/>
    </div>
    <div id="footer">
      <div class="xright">&#169;  
          2001-2006
    
          Sourceforge
      </div>
      <div class="clear">
        <hr/>
      </div>
    </div>
  </body>
</html>
�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/css/�����������������������������������������������������������������0000755�0001750�0001750�00000000000�12732165123�016473� 5����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/css/maven-base.css���������������������������������������������������0000644�0001750�0001750�00000004532�12732165123�021227� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������body {
  margin: 0px;
  padding: 0px;
}
img {
  border:none;
}
table {
  padding:0px;
  width: 100%;
  margin-left: -2px;
  margin-right: -2px;
}
acronym {
  cursor: help;
  border-bottom: 1px dotted #feb;
}
table.bodyTable th, table.bodyTable td {
  padding: 2px 4px 2px 4px;
  vertical-align: top;
}
div.clear{
  clear:both;
  visibility: hidden;
}
div.clear hr{
  display: none;
}
#bannerLeft, #bannerRight {
  font-size: xx-large; 
  font-weight: bold;
}
#bannerLeft img, #bannerRight img {
  margin: 0px;
}
.xleft, #bannerLeft img {
  float:left;
  text-shadow: #7CFC00;
}
.xright, #bannerRight img {
  float:right;
  text-shadow: #7CFC00;
}
#banner {
  padding: 0px;
}
#banner img {
  border: none;
}
#breadcrumbs {
  padding: 3px 10px 3px 10px;
}
#leftColumn {
 width: 150px;
 float:left;
}
#bodyColumn {
  margin-right: 1.5em;
  margin-left: 177px;
}
#legend {
  padding: 8px 0 8px 0;
}
#navcolumn {
  padding: 8px 4px 0 8px;
}
#navcolumn h5 {
  margin: 0;
  padding: 0;
  font-size: small;
}
#navcolumn ul {
  margin: 0;
  padding: 0;
  font-size: small;
}
#navcolumn li {
  list-style-type: none;
  background-image: none;
  background-repeat: no-repeat;
  background-position: 0 0.4em;
  padding-left: 16px;
  list-style-position: ouside;
  line-height: 1.2em;
  font-size: smaller;
}
#navcolumn li.expanded {
  background-image: url(../images/expanded.gif);
}
#navcolumn li.collapsed {
  background-image: url(../images/collapsed.gif);
}
#poweredBy {
  text-align: center;
}
#navcolumn img {
  margin-top: 10px;
  margin-bottom: 3px;
}
#poweredBy img {
  display:block;
  margin: 20px 0 20px 17px;
  border: 1px solid black;
  width: 90px;
  height: 30px;
}
#search img {
    margin: 0px;
    display: block;
}
#search #q, #search #btnG {
    border: 1px solid #999;
    margin-bottom:10px;
}
#search form {
    margin: 0px;
}
#lastPublished {
  font-size: x-small;
}
.navSection {
  margin-bottom: 2px;
  padding: 8px;
}
.navSectionHead {
  font-weight: bold;
  font-size: x-small;
}
.section {
  padding: 4px;
}
#footer {
  padding: 3px 10px 3px 10px;
  font-size: x-small;
}
#breadcrumbs {
  font-size: x-small;
  margin: 0pt;
}
.source {
  padding: 12px;
  margin: 1em 7px 1em 7px;
}
.source pre {
  margin: 0px;
  padding: 0px;
}
����������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/css/maven-classic.css������������������������������������������������0000644�0001750�0001750�00000035465�12732165123�021747� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������body {
 background: #fff;
 color: #000;
  padding: 0px 0px 10px 0px;
 }

.contentBox h2 {
 color: #fff;
 background-color: #036;
 }

.contentBox h3 {
 color: #fff;
 background-color: #888;
 }

.a td { 
 background: #ddd;
 color: #000;
 }

.b td { 
 background: #efefef;
 color: #000;
 }

.contentBox th {
 background-color: #bbb;
 color: #fff;
 }

div#banner {
 border-top: 1px solid #369;
 border-bottom: 1px solid #003;
 }

#banner, #banner td { 
 background: #036;
 color: #fff;
 }
#banner {
  border-bottom: 1px solid #fff;
}

#leftColumn {
 background: #eee;
 color: #000;
 border-right: 1px solid #aaa;
 border-bottom: 1px solid #aaa;
 border-top: 1px solid #fff;
}

#navcolumn {
/* bad for IE
 background: #eee;
*/
 color: #000;
 border-right: none;
 border-bottom: none;
 border-top: none;
 }

#breadcrumbs {
 background-color: #ddd;
 color: #000;
 border-top: 1px solid #fff;
 border-bottom: 1px solid #aaa;
 }

.source {
 background-color: #fff;
 color: #000;
 border-right: 1px solid #888; 
 border-left: 1px solid #888; 
 border-top: 1px solid #888; 
 border-bottom: 1px solid #888; 
 margin-right: 7px;
 margin-left: 7px;
 margin-top: 1em;
 }

.source pre {
 margin-right: 7px;
 margin-left: 7px;
 }

a[name]:hover, #leftColumn a[name]:hover {
 color: inherit !important;
 }

a:link, #breadcrumbs a:visited, #navcolumn a:visited, .contentBox a:visited, .tasknav a:visited {
 color: blue;
 }

a:active, a:hover, #leftColumn a:active, #leftColumn a:hover {
 color: #f30 !important;
 }

a:link.selfref, a:visited.selfref {
 color: #555 !important;
 }

#legend li.externalLink {
  background: url(../images/external-classic.png) left top no-repeat;
  padding-left: 18px;
}
a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
  background: url(../images/external-classic.png) right center no-repeat;
  padding-right: 18px;
}

#legend li.newWindow {
  background: url(../images/newwindow-classic.png) left top no-repeat;
  padding-left: 18px;
}
a.newWindow, a.newWindow:link, a.newWindow:visited, a.newWindow:active, a.newWindow:hover {
  background: url(../images/newwindow-classic.png) right center no-repeat;
  padding-right: 18px;
}

h2, h3 {
 margin-top: 1em;
 margin-bottom: 0;
 }

img.handle {
 border: 0;
 padding-right: 2px;
}

#navcolumn div div  {
 background-image: none;
 background-repeat: no-repeat;
}

#navcolumn div div {
  padding-left: 10px;
}
/* $Id$
  
  This file defines basic default formatting for HTML conforming to Tigris application style. To extend or override these rules for your instance, edit inst.css instead of this file. */

/* colors, backgrounds, borders, link indication */
.contentBox h2, .contentBox h3, .tabs td, .tabs th, .functnbar {
  background-image: url(../images/nw_maj_rond.gif);
  background-repeat: no-repeat;
}

.functnbar, .functnbar2 {
  background-color: #aaa;
}

.functnbar2, .functnbar3 {
  background-color: #aaa;
  background-image: url(../images/sw_maj_rond.gif);
  background-repeat: no-repeat;
  background-position: bottom left;
}

.functnbar3 {
  background-color: #ddd;
  background-image: url(../images/sw_med_rond.gif);
}

.functnbar, .functnbar2, .functnbar3 {
  color: #000;
}

.functnbar a, .functnbar2 a, .functnbar3 a {
  color: #000;
  text-decoration: underline;
}

#navcolumn .body div, body.docs #toc li li {
  background-image: url(../images/strich.gif);
  background-repeat: no-repeat;
  background-position: .5em .5em;
}

#searchbox .body div, #navcolumn .body .heading {
  background-image: none;
}

a:link.selfref, a:visited.selfref {
  text-decoration: none;
}

#leftColumn a, #breadcrumbs a {
  text-decoration: none;
}

/* Unsure of this. TODO */
.contentBox h2 a:link, .contentBox h2 a:visited, .contentBox h3 a:link, .contentBox h3 a:visited {
  color: #fff !important;
  text-decoration: underline;
}

table, th, td {
  border: none;
}

div.colbar {
  background: #eee;
  border-color: #999 #EEE #EEE #999;
  border-width: 1px;
  border-style: solid;
}

.toolgroup {
  background: #efefef;
}

.toolgroup .label {
  border-bottom: 1px solid #666;
  border-right: 1px solid #666;
  background: #ddd;
  color: #555;
}

.toolgroup .body {
  border-right: 1px solid #aaa;
  border-bottom: 1px solid #aaa;
}

#main {
  border-top: 1px solid #999;
}

#rightcol div.www, #rightcol div.help {
  border: 1px solid #ddd;
}

body.docs div.docs {
  background-color: #fff;
  border-left: 1px solid #ddd;
  border-top: 1px solid #ddd;
}

#helptext .label {
  background-image: url(../images/icon_help_sml.gif);
  background-repeat: no-repeat;
  background-position: 97%;
}

body.docs {
  background: #eee url(../images/help_logo.gif) top right no-repeat !important;
}

.docs h2, .docs h3 {
  border-top: solid 1px #000;
}

#apphead h2 em {
  color: #777;
}

.tabs th {
  border-right: 1px solid #333;
  background-color: #ddd;
  color: #fff;
  border-left: 1px solid #fff;
}

.tabs td {
  background-color: #999;
  border-bottom: 1px solid #fff;
  border-right: 1px solid #fff;
  border-left: 1px solid #fff;
}

.tabs {
  border-bottom: 6px #ddd solid;
}

.tabs th, .tabs th a:link, .tabs th a:visited {
  color: #555;
}

.tabs td, .tabs td a:link, .tabs td a:visited {
  color: #fff;
}

.tabs a {
  text-decoration: none;
}

.axial th {
  background-color: #ddd;
  color: black;
}

.alert {
  background-color: #ff9;
}

.expandedwaste {
  background: url(../images/icon_arrowwaste2_sml.gif) no-repeat;
}

.collapsedwaste {
  background: url(../images/icon_arrowwaste1_sml.gif) no-repeat;
}

.filebrowse .expanded, .filebrowse-alt .expanded {
  background-image: url(../images/icon_arrowfolderopen2_sml.gif);
  background-repeat: no-repeat;
}

.filebrowse .collapsed, .filebrowse-alt .collapsed {
  background-image: url(../images/icon_arrowfolderclosed1_sml.gif);
  background-repeat: no-repeat;
}

.filebrowse .leafnode, .filebrowse-alt .leafnode {
  background-image: url(../images/icon_folder_sml.gif);
  background-repeat: no-repeat;
}

.filebrowse .leaf, .filebrowse-alt .leaf {
  background-image: url(../images/icon_doc_sml.gif);
  background-repeat: no-repeat;
}

.sortup {
  background: url(../images/icon_sortup.gif) no-repeat;
}

.sortdown {
  background: url(../images/icon_sortdown.gif) no-repeat;
}

.collapsedwaste {
  background: url(../images/icon_arrowwaste1_sml.gif) no-repeat;
}

body .grid td {
  border-top: 1px solid #ccc;
  border-left: 1px solid #ccc;
  background-color: transparent;
}

.confirm {
  color: #090;
}

.info {
  color: #069;
}

.errormessage, .warningmessage, .donemessage, .infomessage {
  border-top: 5px solid #900;
  border-left: 1px solid #900;
  background-image: url(../images/icon_error_lrg.gif);
  background-repeat: no-repeat;
  background-position: 5px 1.33em;
}

.warningmessage {
  background-image: url(../images/icon_warning_lrg.gif);
  border-color: #c60;
}

.donemessage {
  background-image: url(../images/icon_success_lrg.gif);
  border-color: #090;
}

.infomessage {
  background-image: url(../images/icon_info_lrg.gif);
  border-color: #069;
}

.docinfo {
  background: url(../images/icon_doc_lrg.gif) no-repeat;
}

.dirinfo {
  background: url(../images/icon_folder_lrg.gif) no-repeat;
}

.memberinfo {
  background: url(../images/icon_members_lrg.gif) no-repeat;
}

.usergroupinfo {
  background: url(../images/icon_usergroups_lrg.gif) no-repeat;
}

.errormark, .warningmark, .donemark, .infomark {
  background: url(../images/icon_error_sml.gif) no-repeat;
}

.warningmark {
  background-image: url(../images/icon_warning_sml.gif);
}

.donemark {
  background-image: url(../images/icon_success_sml.gif);
}

.infomark {
  background-image: url(../images/icon_info_sml.gif);
}

.cvsdiff, .cvsblame {
  background-color: #ccc;
}

.cvsdiffadd {
  background-color: #afa;
}

.cvsdiffremove {
  background-color: #faa;
}

.cvsdiffchanges1 {
  background-color: #ff7;
}

.cvsdiffchanges2 {
  background-color: #ff7;
}

li.selection ul a {
  background: #fff;
}

.band1 {
  color: #fff;
  background-color: #663;
}

.band2 {
  color: #fff;
  background-color: #66C;
}

.band3 {
  background-color: #C99;
}

.band4 {
  background-color: #CFF;
}

.band5 {
  color: #fff;
  background-color: #336;
}

.band6 {
  color: #fff;
  background-color: #966;
}

.band7 {
  background-color: #9CC;
}

.band8 {
  background-color: #FFC;
}

.band9 {
  color: #fff;
  background-color: #633;
}

.band10 {
  color: #fff;
  background-color: #699;
}

.band11 {
  background-color: #CC9;
}

.band12 {
  background-color: #CCF;
}

.band13 {
  color: #fff;
  background-color: #366;
}

.band14 {
  color: #fff;
  background-color: #996;
}

.band15 {
  background-color: #99C;
}

.band16 {
  background-color: #FCC;
}

.contentBox .helplink, #helptext .helplink {
  cursor: help;
}

.legend th, .bars th {
  background-color: #fff;
}

/* font and text properties, exclusive of link indication, alignment, text-indent */
body, th, td, input, select {
  font-family: Verdana, Helvetica, Arial, sans-serif;
}

code, pre {
  font-family: 'Andale Mono', Courier, monospace;
}

body, .contentBox h2, .contentBox h3, #rightcol h2, pre, code, #apphead h2 small, h3, th, td {
  font-size: x-small;
  voice-family: "\"}\"";
  voice-family: inherit;
  font-size: small;
}

small, div#footer, div#login, div.tabs th, div.tabs td, input, select, .paginate, .functnbar, .functnbar2, .functnbar3, #breadcrumbs, .courtesylinks, #rightcol div.help, .colbar, .tasknav, body.docs div#toc, #leftColumn, .legend, .bars {
  font-size: xx-small;
  voice-family: "\"}\"";
  voice-family: inherit;
  font-size: x-small;
}

.tabs td, .tabs th, dt, .tasknav .selfref, #login .username, .selection {
  font-weight: bold;
}

li.selection ul {
  font-weight: normal;
}

#apphead h2 em {
  font-style: normal;
}

#banner h1 {
  font-size: 1.25em;
}

/* box properties (exclusive of borders), positioning, alignments, list types, text-indent */
#bodyColumn h2 {
  margin-top: .3em;
  margin-bottom: .5em;
}

p, ul, ol, dl, .bars table {
  margin-top: .67em;
  margin-bottom: .67em;
}

form {
  margin: 0;
}

#bodyColumn {
  padding-left: 12px;
  padding-right: 12px;
  width: 100%;
  voice-family: "\"}\"";
  voice-family: inherit;
  width: auto;
}

html>body #bodyColumn {
  width: auto;
}

.docs {
  line-height: 1.4;
}

ol ol {
  list-style-type: lower-alpha;
}

ol ol ol {
  list-style-type: lower-roman;
}

.contentBox h2, .contentBox h3 {
  padding: 5px;
  margin-right: 2px;
}

.contentBox td, .contentBox th {
  padding: 2px 3px;
}

.h2 p, .h3 p, .h2 dt, .h3 dt {
  margin-right: 7px;
  margin-left: 7px;
}

.tasknav {
  margin-bottom: 1.33em;
}

div.colbar {
  padding: 3px;
  margin: 2px 2px 0;
}

.tabs {
  margin-top: .67em;
  margin-right: 2px;
  margin-left: 2px;
  padding-left: 8px;
}

.tabs td, .tabs th {
  padding: 3px 9px;
}

#rightcol div.www, #rightcol div.help {
  padding: 0 .5em;
}

body.docs #toc {
  position: absolute;
  top: 15px;
  left: 0px;
  width: 120px;
  padding: 0 20px 0 0;
}

body.docs #toc ul, #toc ol {
  margin-left: 0;
  padding-left: 0;
}

body.docs #toc li {
  margin-top: 7px;
  padding-left: 10px;
  list-style-type: none;
}

body.docs div.docs {
  margin: 61px 0 0 150px;
  padding: 1em 2em 1em 1em !important;
}

.docs p+p {
  text-indent: 5%;
  margin-top: -.67em;
}

.docs h2, .docs h3 {
  margin-bottom: .1em;
  padding-top: .3em;
}

.functnbar, .functnbar2, .functnbar3 {
  padding: 5px;
  margin: .67em 2px;
}

.functnbar3 {
  margin-top: 0;
}

body {
  padding: 1em;
}

body.composite, body.docs {
  margin: 0;
  padding: 0;
}

th, td {
  text-align: left;
  vertical-align: top;
}

.right {
  text-align: right !important;
}

.center {
  text-align: center !important;
}

.axial th, .axial th .strut {
  text-align: right;
}

.contentBox .axial td th {
  text-align: left;
}

body .stb {
  margin-top: 1em;
  text-indent: 0;
}

body .mtb {
  margin-top: 2em;
  text-indent: 0;
}

.courtesylinks {
  margin-top: 1em;
  padding-top: 1em;
}

dd {
  margin-bottom: .67em;
}

.toolgroup {
  margin-bottom: 6px;
}

.toolgroup .body {
  padding: 4px 4px 4px 0;
}

.toolgroup .label {
  padding: 4px;
}

.toolgroup .body div {
  padding-bottom: .3em;
  padding-left: 1em;
}

.toolgroup .body div div {
  margin-top: .3em;
  padding-bottom: 0;
}

.tier1 {
  margin-left: 0;
}

.tier2 {
  margin-left: 1.5em;
}

.tier3 {
  margin-left: 3em;
}

.tier4 {
  margin-left: 4.5em;
}

.tier5 {
  margin-left: 6em;
}

.tier6 {
  margin-left: 7.5em;
}

.tier7 {
  margin-left: 9em;
}

.tier8 {
  margin-left: 10.5em;
}

.tier9 {
  margin-left: 12em;
}

.tier10 {
  margin-left: 13.5em;
}

.filebrowse .expanded, .filebrowse .collapsed {
  padding-left: 34px;
}

.filebrowse .leafnode, .filebrowse .leaf {
  padding-left: 20px;
}

.messagechild {
  padding-left: 34px;
}

.filebrowse-alt .expanded, .filebrowse-alt .collapsed, .filebrowse-alt .leaf, .filebrowse-alt .leafnode, .expandedwaste, .collapsedwaste, .sortup, .sortdown {
  /* hide from macie5\*/
  float: left;
  /* resume */
  display: inline-block;
  height: 15px;
  width: 34px;
  padding-left: 0 !important;
}

.filebrowse-alt .leaf, .filebrowse-alt .leafnode, .sortup, .sortdown {
  width: 20px;
}

.filebrowse ul, .filebrowse-alt ul {
  list-style-type: none;
  padding-left: 0;
  margin-left: 0;
}

.filebrowse ul ul, .filebrowse-alt ul ul {
  margin-left: 1.5em;
  margin-top: 0;
  padding-top: .67em;
}

.filebrowse li, .filebrowse-alt li {
  margin-bottom: .67em;
}

td.filebrowse h2 {
  margin-top: 0;
}

.errormessage, .warningmessage, .donemessage, .infomessage, .docinfo, .dirinfo, .memberinfo, .usergroupinfo {
  margin: .67em 0;
  padding: .33em 0 .67em 42px;
  min-height: 32px;
}

.errormark, .warningmark, .donemark, .infomark {
  padding-left: 20px;
  min-height: 15px;
}

.alt {
  display: none;
}

#banner h1 {
  margin: 0;
}

.axial th, .axial th .strut, #leftColumn .strut {
  width: 12em;
}

#breadcrumbs {
  padding: 2px 8px;
}

/* Bad for IE
.contentBox h2, .contentBox h3, .bars {
  clear: both;
}
*/

.legend {
  float: right;
}

.legend th, .bars th {
  text-align: right;
  padding-left: 1em;
}

.bars table {
  table-layout: fixed;
}

.bars th {
  width: 12em;
}

#projectdocumentlist td.filebrowse-alt {
  padding-right: .75em;
}
#organizationLogo img, #projectLogo img, #projectLogo span{
  margin: 8px;
}
�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/css/print.css��������������������������������������������������������0000644�0001750�0001750�00000000336�12732165123�020343� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#banner, #footer, #leftcol, #breadcrumbs, .docs #toc, .docs .courtesylinks, #leftColumn, #navColumn {
	display: none !important;
}
#bodyColumn, body.docs div.docs {
	margin: 0 !important;
	border: none !important
}
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/samplereport/css/maven-theme.css��������������������������������������������������0000644�0001750�0001750�00000004632�12732165123�021420� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������body {
  padding: 0px 0px 10px 0px;
}
body, td, select, input, li{
  font-family: Verdana, Helvetica, Arial, sans-serif;
  font-size: 13px;
}
code{
  font-family: Courier, monospace;
  font-size: 13px;
}
a {
  text-decoration: none;
}
a:link {
  color:#36a;
}
a:visited  {
  color:#47a;
}
a:active, a:hover {
  color:#69c;
}
#legend li.externalLink {
  background: url(../images/external.png) left top no-repeat;
  padding-left: 18px;
}
a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
  background: url(../images/external.png) right center no-repeat;
  padding-right: 18px;
}
#legend li.newWindow {
  background: url(../images/newwindow.png) left top no-repeat;
  padding-left: 18px;
}
a.newWindow, a.newWindow:link, a.newWindow:visited, a.newWindow:active, a.newWindow:hover {
  background: url(../images/newwindow.png) right center no-repeat;
  padding-right: 18px;
}
h2 {
  padding: 4px 4px 4px 6px;
  border: 1px solid #999;
  color: #900;
  background-color: #ddd;
  font-weight:900;
  font-size: x-large;
}
h3 {
  padding: 4px 4px 4px 6px;
  border: 1px solid #aaa;
  color: #900;
  background-color: #eee;
  font-weight: normal;
  font-size: large;
}
h4 {
  padding: 4px 4px 4px 6px;
  border: 1px solid #bbb;
  color: #900;
  background-color: #fff;
  font-weight: normal;
  font-size: large;
}
h5 {
  padding: 4px 4px 4px 6px;
  color: #900;
  font-size: normal;
}
p {
  line-height: 1.3em;
  font-size: small;
}
#breadcrumbs {
  border-top: 1px solid #aaa;
  border-bottom: 1px solid #aaa;
  background-color: #ccc;
}
#leftColumn {
  margin: 10px 0 0 5px;
  border: 1px solid #999;
  background-color: #eee;
}
#navcolumn h5 {
  font-size: smaller;
  border-bottom: 1px solid #aaaaaa;
  padding-top: 2px;
  color: #000;
}

table.bodyTable th {
  color: white;
  background-color: #bbb;
  text-align: left;
  font-weight: bold;
}

table.bodyTable th, table.bodyTable td {
  font-size: 1em;
}

table.bodyTable tr.a {
  background-color: #ddd;
}

table.bodyTable tr.b {
  background-color: #eee;
}

.source {
  border: 1px solid #999;
}
dl {
  padding: 4px 4px 4px 6px;
  border: 1px solid #aaa;
  background-color: #ffc;
}
dt {
  color: #900;
}
#organizationLogo img, #projectLogo img, #projectLogo span{
  margin: 8px;
}
#banner {
  border-bottom: 1px solid #fff;
}
������������������������������������������������������������������������������������������������������testng-6.9.12/doc/banner.js�������������������������������������������������������������������������0000644�0001750�0001750�00000004555�12732165123�015002� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//****************************************************************
// Writes a table data element to the document. If pHRef equals
// pCurrentPage then 'class="current"' is added to the td element.
// For example:
//    writeTD("a.html", "a.html", "b")
// Would write
//    <td class="current"><a href="a.html">b</a><td>
//
// @param pCurrentPage the current page. For example "index.html"
// @param pHRef the string that should apear in the href
// @param pValue the string that should apear as the value
//****************************************************************
function writeTD(pCurrentPage, pHRef, pValue)
{
   document.write('                <td')
   document.write(pCurrentPage == pHRef ? ' class="current"' : '')
   document.write('><a href="')
   document.write(pHRef)
   document.write('">')
   document.write(pValue)
   document.writeln('</a></td>')
}

//******************************************************************
// Writes the main menu to the document.
// @param pCurrentPage the current page. For example "index.html"
//******************************************************************
function displayMenu(pCurrentPage) {
   document.writeln('<div id="topmenu">')
   document.writeln('    <table width="100%">')
   document.writeln('            <tr>')
       writeTD(pCurrentPage,             "index.html", "Welcome")
       writeTD(pCurrentPage,          "download.html", "Download")
       writeTD(pCurrentPage,"documentation-main.html", "Documentation")
       writeTD(pCurrentPage,         "migrating.html", "Migrating from JUnit")
       writeTD(pCurrentPage, "../javadocs/index.html", "JavaDoc")
       writeTD(pCurrentPage, "selenium.html", "Selenium")
   document.writeln('            </tr>')
   document.writeln('            <tr>')
       writeTD(pCurrentPage,           "eclipse.html", "Eclipse")
       writeTD(pCurrentPage,              "idea.html", "IDEA")
       writeTD(pCurrentPage,             "maven.html", "Maven")
       writeTD(pCurrentPage,               "ant.html", "Ant")
       writeTD(pCurrentPage,              "misc.html", "Miscellaneous")
       writeTD(pCurrentPage,              "book.html", "Book")
       writeTD(pCurrentPage,              "http://beust.com/kobalt", "Kobalt")
   document.writeln('            </tr>')
   document.writeln('        </table>')
   document.writeln('    </div>')

}

���������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/idea.html�������������������������������������������������������������������������0000644�0001750�0001750�00000005301�12732165123�014755� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
    <head>
        <title>TestNG - IDEA Plugin</title>
        <script type="text/javascript" src="banner.js"></script>
        <link rel="stylesheet" href="testng.css" type="text/css" />
      </head>
<body>

<script type="text/javascript">
    displayMenu("idea.html")
</script>

<h2 align="center">TestNG IDEA Plug-in</h2>



<p align="center">
<img src="http://testng.org/pictures/idea-output.png" />
</p>

<h3>IDEA 7</h3>

TestNG is bundled in IDEA 7 onwards, no extra plugins need to be installed.  The full documentation can be found <a href="http://www.jetbrains.com/idea/features/junit_testng.html#TestNG">here</a>.

<h3>IDEA 6 and older </h3>


TestNG has an IDEA plug-in that mirrors much of the behavior of the built-in JUnit support. You should be able to run tests within IDEA without defining any files externally, as well as quickly and easily migrate JUnit code. The plug-in also provides the same output test view as JUnit tests.

Installation

<ul>
	<li>From IDEA, go to Preferences -> Plugins.</li>
	<li>Click over to the Available Plugins tab.</li>
</ul>
<p>The latest version of the TestNG plugin will be listed there, ready to download and install.&nbsp;
Also, you can go to the <a href="http://svn.jetbrains.org/idea/Trunk/bundled/testng">
TestNG IDEA plug-in project page</a> and download its source from there.</p>
<p>Please note that this plug-in only works on IDEA 5.0 and 6.0.</p>

<p><b>Creating a TestNG Run/Debug configuration</b></p>
<p>Once you have installed the plug-in and restarted IDEA, and have some TestNG classes you would like to run, simply
open the Run/Debug window. You will see a TestNG tab, where you can add a configuration.

</p>
<p>There are a number of methods for determining the set of tests that will be run. These are:</p>
<ul>
	<li>Package: Specify a package to run. All tests in this package and below will be included.</li>
	<li>Group: Specify a TestNG group to run.</li>
	<li>Suite: Specify an external testng.xml file to run.</li>
	<li>Class: Run all tests in a single class.</li>
	<li>Method: Run a single test method.

</li>
</ul>
<p>Once you create the run configuration, you can run it. Upon running, the plug-in will launch an external process to run your tests. The test results will be display in a tree view, with passed and failed tests highlighted. You can narrow down on the console output for a specify test by clicking on it, while double clicking a test will navigate to its source code.
</p>

<p align="center">
<img src="http://testng.org/pictures/idea-rundialog.png" />
</p>


<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>

</body>

</html>
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������testng-6.9.12/doc/eclipse.html����������������������������������������������������������������������0000644�0001750�0001750�00000040606�12732165123�015506� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html>
    <head>
        <title>TestNG - Eclipse</title>
        <script type="text/javascript" src="banner.js"></script>
        <link rel="stylesheet" href="testng.css" type="text/css" />
      </head>
<body>

<script type="text/javascript">
    displayMenu("eclipse.html")
</script>


<h2 align="center">TestNG Eclipse plug-in</h2>
<p>The TestNG Eclipse plug-in allows you to run your TestNG tests from Eclipse 
and easily monitor their execution and their output. It has its own <a href="http://github.com/cbeust/testng-eclipse">project repository called <tt>testng-eclipse</tt></a>.</p>


<h3>Table of Contents</h3>

&nbsp;&nbsp;<a class="summary" href="#eclipse-installation">1 - Installation</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-creating">2 - Creating a TestNG class</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-create-launch">3 - Launch configurations</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-create-class">3.1 - From a class file</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-create-groups">3.2 - From groups</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-create-xml">3.3 - From an XML file</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-create-method">3.4 - From a method</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-listeners">3.5 - Specifying listeners and other settings</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-viewing">4 - Viewing the results</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-search">5 - Search</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-summary">6 - The Summary tab</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-quickfix">7 - Converting JUnit tests</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-quickfixes">8 - Quick fixes</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-preferences">9 - Preferences and Properties</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-workbench-preferences">9.1 - Workbench Preferences</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#eclipse-project-properties">9.2 - Project Properties</a>
<br>
&nbsp;&nbsp;<a class="summary" href="#testng-xml"></a>

<!--
  Installation
-->
<h3><a name="eclipse-installation">1 - Installation</a></h3><p>
Once you have <a href="http://testng.org/doc/download.html">installed the plug-in</a>, restart Eclipse and select the menu <tt>Window / Show View 
/ Other...</tt>&nbsp; and you should see the TestNG view listed in the Java category.</p><p align="center">
<img border="0" src="http://testng.org/pictures/view.png" />
</p>
<p>
NOTE: since TestNG Eclipse Plugin 6.9.8, the minimum required TestNG version is <b>6.5.1</b>
</p>

<!--
  Creating
-->
<h3><a name="eclipse-creating">2 - Creating a TestNG class</a></h3><p>

To create a new TestNG class, select the menu File / New / TestNG:

<p align="center">
<img border="0" src="http://testng.org/pictures/new-1.png" />
</p>

If you currently have a Java file open in the editor or if you have a Java file selected in the Navigator, the first page of the wizard will show you a list of all the public methods of that class and it will give you the option to select the ones you want to test. Each method you select on this page will be included in the new TestNG class with a default implementation that throws an exception, so you remember to implement it.

<p align="center">
<img border="0" src="http://testng.org/pictures/new-2.png" />
</p>

The next page lets you specify where that file will be created, whether it should contain default implementation for some configuration methods, if you'd like a data provider and finally, if a <tt>testng.xml</tt> file should be generated.

<p align="center">
<img border="0" src="http://testng.org/pictures/new-3.png" />
</p>

The plug-in will make a guess about the best location where this file should be created (for example, if you are using Maven, the default location will be under <tt>src/test/java</tt>).

<h3><a name="eclipse-create-launch">3 - Launch configuration</a></h3><p>Once you have created classes that contain TestNG annotations and/or one or 
more <tt>testng.xml</tt> files, you can create a TestNG Launch Configuration.&nbsp; 
Select the <tt>Run / Run...</tt> (or <tt>Run / Debug...</tt>) menu and create a new TestNG 
configuration:</p><p align="center">
<img border="0" src="http://testng.org/pictures/launch.png" />
</p>
<p>You should change the name of this configuration and pick a project, which 
can be selected by clicking on the <tt>Browse...</tt> button at the top of the window.</p>
<p>
Runtime options:
<ul>
<li><b>Log Level</b>: specify the value (0-10) for different verbose log levels</li>
<li><b>Verbose</b>: enable the runtime TestNG verbose log</li>
<li><b>Debug</b>: enable more runtime TestNG debug info</li>
<li><b>Serialization Protocol</b>: the serialization protocol used for communicating between TestNG Eclipse Plugin and TestNG runtime.
The default is "Object Serialization", the other option ("String Serialization") is deprecated.</li>
<li><b>Add the POM's JVM Arguments when launch</b>: for maven based project, we normally define maven-surefire-plugin for test phase and maven-failsafe-plugin for integration test phase, there might be having the testing runtime JVM arguments defined in the "argLine" element of the maven plugin configuration. If you check this option, TestNG Eclipse Plugin will try to recognize the JVM arguments in "argLine", add them to TestNG runtime JVM arguments when launch.<br/>
NOTE 1: these JVM arguments are put on front of user defined VM arguments on "Arguments" tab, which means you can overide the POM defined JVM argumetns with the ones on "Arguments" tab.<br/>
NOTE 2: if there are multiple "argLine" elements in the pom.xml, the first presence will be used. If it's not the desired behaviour, you can simply uncheck this option, and type your JVM arguments on the "Arguments" tab next to this "Test" tab.</li>
</ul>
</p>
<p>Then you choose to launch your TestNG tests in the following ways:</p><h4><a name="eclipse-launch-class">4.2.1 - From a class file</a></h4><p>Make sure the box near <tt>Class</tt> is checked and then pick a class from your 
project.&nbsp; You can click on the <tt>Browse...</tt> button and pick it directly from a 
list.&nbsp; This list only contains classes that contain TestNG annotations:</p><p align="center">
<img border="0" src="http://testng.org/pictures/classes.png" />
</p>


<h4><a name="eclipse-create-groups">3.2 - From groups</a></h4>
<p>If you only want to launch one or several groups, you can type them in the 
text field or pick them from a list by clicking on the <tt>Browse...</tt> button&nbsp;

<p align="center">
<img border="0" src="http://testng.org/pictures/groups.png" />
</p>


<h4><a name="eclipse-create-xml">3.3 - From a definition file</a></h4>
Finally, you can select a suite definition from your project.  It doesn't have to be named
<tt>testng.xml</tt>, the plug-in will automatically identify all the applicable TestNG XML files 
in your project:
<p align="center">
<img border="0" src="http://testng.org/pictures/suites.png" />
</p>
You can type the regex on the filter text field to narrow down to suite definition files matching your search from a long list of files.

<h4>
<a name="eclipse-create-method">3.4 - From a method </a>
</h4>
<p>This launch isn't accomplished from the Launch dialog but 
directly from your Outline view:</p><p align="center">
<img border="0" src="http://testng.org/pictures/outline.png" />
</p>
You can right-click on any test methods and select <tt>Run as... / TestNG test</tt> and only the selected
method will be run (not shown on the above screenshot because I couldn't find a way to capture
a contextual menu).<p>Method launching is also available from the Package 
Explorer view and from the Java Browser perspective.</p><p>Once you have selected one of these launches, you can also choose the logging of level. Then you can launch the tests by pressing the <tt>Debug</tt> (or <tt>Run</tt>) button, which will switch you to the Debug perspective and will open the main TestNG view.</p>

<h4>
<a name="eclipse-listeners">3.5 -Specifying listeners and other settings </a>
</h4>

As you saw above, the plug-in will let you start tests in many different ways:  from an XML file, from a method, a class, etc...  When you are running an XML file, you can specify all the settings you want for this run in the XML file, but what if you want to run a package in parallel mode with specific listeners?  How can you configure the settings for all the launches that are not done from an XML file?

<p>

In order to give you access to the most flexibility, TestNG lets you specify an XML suite file for all these launches, which you can find in the Preferences menu:

<p align="center">
<img border="0" src="http://testng.org/pictures/template.png"/>
</p>

If you specify a valid suite file as "XML template file", TestNG will reuse all the settings found in this XML file, such as parallel, name, listeners, thread pool size, etc...  Only the <tt>&lt;test&gt;</tt> tags in this file will be ignored since the plug-in will replace these by a generated <tt>&lt;test&gt;</tt> tag that represents the launch you chose.

<!--
  Viewing
-->
<h3>
<a name="eclipse-viewing">4 - Viewing the test results </a>
</h3>

<p align="center">
<img border="0" src="http://testng.org/pictures/success.png" />
</p>

<p>The above view shows a successful run of the tests:&nbsp; the bar is green 
and no failed tests are reported.&nbsp; The <tt>All tests</tt> tab shows you a list of 
all the classes and methods that were run.</p><p>If your test run contains failures, the view will look like this:</p><p align="center">
<img border="0" src="http://testng.org/pictures/failure.png" />
</p>

<p>You can use the <tt>Failed tests</tt> tab to display only these tests that failed, and 
when you select such a test, the stack trace will be shown on the right-hand 
pane.&nbsp; You can double click on the offending line to be taken directly to 
the failure in your code.</p>

<h3>
<a name="eclipse-search">5 - Search </a>
</h3>


<p align="center">
<img border="0" src="http://testng.org/pictures/search.png" />
</p>

<p>When you have hundreds of tests running, finding a specific one is not always easy, so you can type a few letters of the test method or its parameters in the Search box and the content of the tree will automatically narrow down to methods matching your search. Note in the screen shot above that the search also works on parameters provided by <tt>@DataProvider</tt>.</p>

<h3>
<a name="eclipse-summary">6 - Summary </a>
</h3>


<p align="center"> 
<img border="0" src="http://testng.org/pictures/summary1.png" />
</p> 
<p>The Summary tab gives you statistics on your test run, such as the timings, the test names, the number of methods and classes, etc&#8230; Since the results are shown in a table, you can also sort on any criterion you like for easier parsing. This is especially handy when you are trying to determine what tests take the longest time.</p>

<p>The search box works in this view as well, and note that in the screen shot below, the Time column is sorted in decreasing order:</p> 
<p align="center"> 
<img border="0" src="http://testng.org/pictures/summary2.png" />



<h3><a name="eclipse-quickfix">7 - Converting JUnit tests</a></h3>

You can easily convert JUnit 3 and JUnit 4 tests to TestNG.

<p>

Your first option is to use the Quick Fix function:

<p>

<p align="center"> 
<img border="0" src="http://testng.org/pictures/convert1.png" />
<br>
<b>Convert from JUnit 3</b>
</p>

<p align="center"> 
<img border="0" src="http://testng.org/pictures/convert2.png" />
<br>
<b>Convert from JUnit 4</b>
</p>

You can also convert packages or entire source folders with the conversion refactoring:

<p align="center"> 
<img border="0" src="http://testng.org/pictures/refactoring1.png" />
</p>

The refactoring wizard contains several pages:

<p align="center"> 
<img border="0" src="http://beust.com/pics/menu-convert2.png " />
</p>
 
This page lets you generate a testng.xml automatically. You can configure whether to include your test classes individually or by package, the suite and test name and also whether these tests should run in parallel.

<p align="center"> 
<img border="0" src="http://testng.org/pictures/refactoring2.png" />
</p>

This page gives you an overview of the changes that are about to be performed. You can also decide to exclude certain files from the refactoring.

<p>

When you are done, press the "Finish" button. Like all Eclipse refactorings, you can undo all these changes in one click:

<p align="center"> 
<img border="0" src="http://beust.com/pics/menu-convert4.png" />
</p>

<h3><a name="eclipse-quickfixes">8 - Quick fixes</a></h3>

The TestNG Eclipse plug-in offers several quick fixes while you are editing a TestNG class (accessible with <tt>Ctrl-1</tt> on Windows/Linux and <tt>&#8984;-1</tt> on Mac OS):

<h4>Convert to JUnit</h4>

This was covered in the <a href="#eclipse-quickfix"> previous section</a>.

<h4>Pushing and pulling <tt>@Test</tt> annotations</h4>

If you have several test methods annotated with <tt>@Test</tt> and you'd like to replace them all with a single <tt>@Test</tt> annotation at the class level, choose the "Pull annotation" quick fix:

<p align="center">
<img border="0" src="http://testng.org/pictures/refactoring-pull-annotation.png" />
</p>

Reciprocally, you can move a class level <tt>@Test</tt> annotation onto all your public methods:

<p align="center">
<img border="0" src="http://testng.org/pictures/refactoring-push-annotation.png" />
</p>

<h4>Automatically importing <tt>asserts</tt></h4>

Apply a quick fix on an assert method to automatically import it:

<p align="center">
<img border="0" src="http://testng.org/pictures/quickfix-import.png" />
</p>

<!--
  Preferences and Properties
-->
<h3><a name="eclipse-preferences">9 - Preferences and Properties</a></h3>
<h4><a name="eclipse-workbench-preferences">9.1 - Workbench Preferences</a></h4>
TestNG workbench preferences:
<p align="center">
<img border="0" src="http://testng.org/pictures/preferences.png" />
</p>
<p>
The preferences here are shared among projects and launch configurations.
<ul>
<li><b>Output directory</b>: the path where to store the output including temp files, report files, etc. By default, the path is relative to each project except you check the option <b>Absolute ouput path</b> below.</li>
<li><b>Disalbe default listeners</b>: disable the default listeners when launch testng runtime</li>
<li><b>Show view when test complete</b>: active the TestNG result view when the test complete</li>
<li><b>Use Project TestNG jar</b>: It's default to be checked which means TestNG Eclipse Plugin will use the project TestNG jar (for example, the TestNG version managed with maven) when launch TestNG runtime. Otherwise, the TestNG eclipse plugin embedded TestNG version will be used.<br/>
When to check this option?
<ul>
  <li>you want it behviour as close as running outside IDE, e.g. with maven surefire plugin, since the Plugin embedded version of TestNG most likely different with the version of your project.</li>
  <li>you don't want the Plugin embedded plugin and it's dependent libs (e.g. snakeyaml, etc.) pollute your TestNG runtime classpath.</li>
</ul></li>
<li><b>Template XML file</b>: the absolute path of the template xml file used to genernate the custom test suite xml before launch</li>
<li><b>Excluded stack traces</b>: </li>
<li><b>Pre Defined Listeners</b>: </li>
</ul>
</p>

<h4><a name="eclipse-project-properties">9.2 - Project Properties</a></h4>
Project level properties:
<p align="center">
<img border="0" src="http://testng.org/pictures/project_properties.png" />
</p>
<p>
Here are properties on each project level, it will override the same properties if defined in <a class="summary" href="#eclipse-workbench-preferences">TestNG workbench preferences</a>
<ul>
<li><b>Output directory</b>: for example, in the figure above, I prefer to put the output to maven 'target' directory rather than the default one under project root</li>
<li><b>Watch testng-result.xml</b>:</li>
<li><b>Template XML file</b>: see in <a class="summary" href="#eclipse-workbench-preferences">TestNG workbench preferences</a></li>
<li><b>Use Project TestNG jar</b>: see in <a class="summary" href="#eclipse-workbench-preferences">TestNG workbench preferences</a></li>
<li><b>Pre Defined Listeners</b>: see in <a class="summary" href="#eclipse-workbench-preferences">TestNG workbench preferences</a></li>
</ul>
</p>

<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-238215-2";
urchinTracker();
</script>

</body>��������������������������������������������������������������������������������������������������������������������������testng-6.9.12/.gitignore����������������������������������������������������������������������������0000644�0001750�0001750�00000000527�12732165123�014415� 0����������������������������������������������������������������������������������������������������ustar  �eugene��������������������������eugene�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.ant-targets*
.classpath
.gitignore
.gradle
.idea
.project
.settings
/_eclipse/
/local.properties
TESTNG-*
build
eclipse-build
gradle.properties
ivy*
javadocs
kobaltBuild
lib
maven-testng-plugin-1.2.jar
nb-configuration.xml
out
src/generated
src/test/java/test/ignore
target
test-output
test-output-tests
testng.iml
z_build
.kobalt
.DS_Store

�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

rSzFfVvNez,g0ilL̄,-<]l:wwtu:\t񗮋nwVO ~apv)7#&v1^ĉ$n7RmԞ9oz=6#:}A||LAR^qb)B9meIUkM-7[eut.t]mw޻޺Ea??:Bx~qw,|؛w2?M ?|2i2|YXU[;.=?/? &U @hO< ]:]u+@D b) Wm.#?QިhFat0R^!rQ(J}*6ԯih[721>`zǼf?%&X$t];MqJ !I-)'HlFauE6%}H:j4)utr'L9|,Ve6_l99SvisU!xxyTn.˅$SEGVG^;80)ÔgzYtj y}[o궶vou}p=~A ÖǺC&<y<%؝ W onL21C)xvpfz!K˥ԯƬmnqnkj?:dyv;;3{<{i{+?v'?P?8 m`]l?ح:8 /?+1SV~tN^/̏8&n pHYs   IDATx]\kp F슉Q@`GĂb,F5jQTl**v ;hPKᄃ;of(Xv>;͛w}v-/;x<NJJ%R* rX]I`rG#ٳ5k:|$Y⢟ +++!D% @B[]Is_ZZn`-J$`IC`7\NeZŸ `UsQBcH'Cq&O. ?YQp$P(C0Vr\Ɓm  j4\O0)S-l僤_GS5Ts[3)⒜*Flız gp ײ|I&JB31Z|J(K$r$DBY ,%YR$Y(d@-@)+FLj+'MvsQc#輶E|.IK%@r*q8L ܡ,h S-\tilE&BoEzg8T;;;U'pY/ӠY#<ހ&;QsCMWזy"j5ԀPDijݛ.4xOdN*UJQwF(vvZf[ܷjyQ^fm_Ȓ k/2QB٥ #5-Ǵie -uƨ`XqMA[N{_ll,t׿){ER(,]{ӌ.GZ^ ѫS]{,((@oKw}f7߷!fbߗa@(a@Ϥq(Bv!?zX^ܹtj_ɴ8DHHy~ ;gݍZ67@NvROb-P[k^@&Ϣr酨&&k.\`q0':ѭo;ގdA ]^I-)Ű%ֈr Wvo;TQܤeTckUfF*ncW^8#=D/p8:UqCͪϽ /6BcBh I[\Ux Oheh&+˳T'iܿd0O$yeGTt@ ǁ11)AHXŮǴ4te%gG>B]|sJLDo6Ain68-B:ٹLaJ\"` Ʀd+) h1)oFU >~^9 h6'.vP.}?sY^:-Z\Yȕun8~B8;HT`SxvqvCtV\[JNM=+;-p\WVP 0,.߰,{n3Ӑs 1 z kū,#ynN[ D#-9ڠmmC'O{.NZj9FgnTʤPK:_6yI0 3tV@㥋xB-b3ӳ13sEqCP<(kBT͜Dk.HO)Vx_9$|=|7x0G1B-姵,mK2,Xha_Ӂh\B\ 9͝!tN-ᾊ$1Im !a_63A\_0i *BBoV)k;+s.*.l]uҢLj*eL%UQCx"{x#^haZ.h hzӊ_nC6W9t!h H Kj%սʑk/AO*z}hצ"/yw1|o[oX^qNo,݇ XbNqqAw0BmHCwb'XvvAS ?b*M(n{˪{%xm_b]Q> i8 Y؎!5Zqb-ӝ avS2J^ ^0#UOzjC9Y6ٳn }7L6lgGsDTIʎJǫhn e\]U xE2VMR"p=}jzbRuIP.VnlUjF\x@+,xz T3%Zչ4<=G}{T, ְ2kW'v{;_L8feɅb1f)\H2fV78'ȁD.Ėu,H%aC8lqΘt4L?L p'N` c*BV`kh.)zmխz I^ZFWUB_BB5LD_.T;-.B] ppV]ԉ#EGP4`0̧w/'Fh%[b zlYU'vE ۴iӯ_qRd3TIhY~#`X{*`ۂ\'5܂rI4 huTZ$AL),ڪcW|^H6=!]4S|T=6.p$f n o3Wr%@LMb§Rm¾kUx31Y9f͚sμ<{0#w>k ѹ`H7rX/zis\:H!NsSKCp$P{ҥE%Jp8$`0%C׸n3!_ e krs^:a?Ldߴbq :|68 ݉bxh|g;a7ӡa>5֚\SnDxĦM)ܕ2FfCE]ˀqhL@선&ε0招SE̴1hZZ شN w`+F| m>; AYsQɕo:"E 2O򆼂"RiN ף wo`]lWlyWkL׵6aXBn&rdȦ? 0l=.Mn/4JH,1:z Q1щ;fòvsOv\Sh"69:::TYԫXBLu.1WӐ܌@ kRȥ$(Ӫݜǫd`l`mYkW +n*UTYc6?yY떐51P!X; ~eW2W%D(ܡ<`.(JB+Q\ۏLE5H PcRY]L̲~F28W,j, >DZaΕBpX6Id&FDK[UFE$x:Y&HixaH@tHyHqJ@e(&&&}ҵ+<EHf׃N9-U+80k-@/a>W&ُ[sM jfJ [#66b%?q!qH{8 B_|˗W#'}'ShjMl8:XЎS!eT~ߢXgPY3b%B@Il_qɤҏ[tX,X̜<>*'9ި)_[; #9Ptaɤ]]}Qͳ̝=Y Fͳqɺ!xB k -y MM!Nqmly;q5 Esu{Vl;sk zxhy3ѧt E w%-xΪݶxqhyQZE\SLVpΝ70r6yg84?:1MnrK)9JeN;n#E~g6]ߦ}.nB#o?twv*͉2U;|K,8Avb.|`S]ռ%'߿Ba垓o0ɓ}sssmw`ĖH"zŋO>}\8gϞ,f55.IJ&,;vYj uȅBN;aY1I68/a/Z4!zS,fF}/xQstI0_YzUw1'YlK!ÅtIrOS0.\`mmm0B~u|cP{yL-.u҅a2܉-mq[4+@J8 p(*w Eqq=utysTf́ c=?aȹ&F,%— cdg\JfS.<}R*!ϰJȀEV|DB|j@rޭٹ \{YEc6vI:uԨQDijݛZbg^V[uJc'xo5b{)@zc8Ň\9'G͞ ꑜ3W8y14-v!I$ zJwMOY)KE]Oٰs*emXz'N{ ݴ|Sb旯m=T|9Jqn ?ӑ}ӨyɭRzЊPxUun/ӺQVn^r^bq?7XYT޺AaA}tMf-vߚbrn 8 + P^/5=JՏǃy~u{n8yxi$gEGPU a $ gl3ˊ×h]]\\2p6e *^aKO\6Ǵ}Av.sT3uuプLv=]EK&Q"<^M3p{{ :ٹLIfu dlܰ8)7n;6Mh.{ $PޫuE٥`WKy:qpKa1yBkqIIMTWσPu1/ ҂>=gOLܱxICBiᶰZ-)O){vcK4kUO(K/VVMǔ7Y9xiQZ i̹솜M]5Yq g^R\W_CqXCVK,VJςmEIp !637QK+ppA_xf6RJbn{)0fM˫M=|Sdat`e?dNM$9c1f%(B@%w4F؝KoסPI@ǃ'mC[Ԭ-s{6in6<w=lK%~9Pc=PV#2L;Oۂ4ɸ ;bp{1 s~iXiZkg%쵪>)k+pyJT4 zfTѴ5|^g(\vX_C5k]ĎoX+$YpQrr%,6; ^O\)xԲ?l  ꀜGz ͋*Z+_I z[a5~DYo( ^^^gdOQĺL "1铒DžĻw֋T_CY\ W^D'8:<[j2y]'8fj꾒ze~ ڽ|}Yt8 B'v^?8O8jǧO7 vK:fVٖWx_t]:Ӥ$&AIX}W٪-bUWDVq6&FQ 5P?_9ȹp5>g+8Hӓ`Uj SQlo܎+NIDAT3@pBiCL\=}Jnqq~sHcG#+bGW.$$ҮY 7OP&/m,[a唝lux7ZOΝu7fBqw/Wu1-Jꃌob@r[8 0v2_t h_pE)c8&&L0iPzCmݰ's"zks.m ~ڎ;|9xķڵ u)>xADR`;h  so3Ӵ!@G7hށU/ȸ#ZdU11}b7&&U!`]K)qAOש۬-`a'݌_mO^^`9"M}WW/Fs<=wwPp(~/fjs(@Íشs'ƍ .JqUQa}kW1Ȭ(E"=^#P0-Ae82UEfmwL]dȄv7lܬsQVxz1rFCkm=x^w{RDc= gq .Mwih/iik{QGQf;+Pv+|:K [ zٵu5s dִOV? {"2=>~Ըu˞lN9؁X c~YRI‚;4lh31c!A/B]q[P~{[fca-${DPrwvޑ;yk3;cb.\LIH໯}$$-)4%4wcT ICRim _QfÆb&Fzx 32;= {+Zs mB_tNb74t!eef[Sn?F Y%jD 7ffdhacn^躌WΕ?{%|L/ GÐ78.+Wj%'n O:s﯇y\$̆|~Zx; ICEXȁձ)ܹԫ2N lFxS{5! x ЉA0 ; "8jש 2K+$-5)$wkXG bH% 0jp&ƥ> Xm!%q]z?dŶ!IENDB`testng-6.9.12/pictures/launch.png0000755000175000017500000106311412732165123016250 0ustar eugeneeugenePNG  IHDR^ iCCPICC ProfileHWXS[R -)7Az;FHB ˢkAł+ (DTu7I];Μs? o2QyH/f|B"(@xFD(ce@usqWQps 'srYWg y:^ov@A, 8U58Y-%6ё@XTTGN%C b7vqē!Bl]ԿLbci.!rg9deЅ&  V,Ɛ;O X <^雷bFٹްf=pX>Z QF(f % Fdavh|42ge7p ss}lRx~Õ/HD[yaAܑ< ;lF(sև]/RjfYYT!Kb1cFapuyE 2#Frnؑ1kypI=NgEHcCh)7!& A:_?B |T3'g(B~^Q.ȇ/ZHF%)Y:!5;1f%}D?86d .\ ,oO DŽ.] HZ- BA7]27fBv C8W-wA EܾĬgT/g*g7"yx[q`%;bgKX#VkNJx"Y cEJe81>5@(y ;'O!sԴ<'"s|$!n#t9M8Ae7KO}齁k:"aT!wzd hfª,z6BP ցM` *punpm` aAH #j6b!ֈ#"!H$$!!eH1RlCv#ȯI,r D"Hb(UF5QCt2zh4:MEst9݂VZ,zv/A `1G L-ĊR;5w}8L<g9B|5 k:ލ_ 4L$R R> ywz CD"A4":@L'#& &6;=AF2#I,RtttK@%k~D2\JO>MF~FQ1q ̕Y+WAL0EbDqDS)K([(()(oeeeueddn="{Q[#UjJNk&][fH%hkhմsGrt9 @9"2Zkre =gȗ*߯ `RXPpR "]J1\1Kq~KϕHJJJJ{)1ݛΦ/寧*ӕ*+(تĪQ)S9@F&c-( VM84ڄU=TEUo~RceWS{OU^~^DENjjDjأѦ1)ܪyN_塕QV6]MQ ӓlahtv .=P稗QYo@_[?T~=G4 W>7R5 4*01z`L3v710aB4q40aaڙ^5Cxf;:'&9MOtۜjio^cmXjQgj'Njigi򾕒UR7֦l264?E66mlwvv+; 9;$9lwiSGg{<dwy>h w)=,ݮ]nL$]n]:, z}E?j(+zmQLs|q>q%q]_IPO%'c%NiZto01gƥ33g%?5X!).igV85=y~lq]%g))%)S]S7yxwϨɌ5[G6svNl'c/})Ll~ g_K8Ԉ]\;c5K$@$@$@rCbeH'A{ed+?ۋ~z1O7dJeE_=A.-@$@$@$@$%->}/>>TKW:\ĪHGSP}_1uu5T#ۂ}6 z2 F׏~ V<Ҟ<`L} /h_OWZ: tGwX Ѐw k?CQ=1< ']](V?Go~c8qq/%. #7诉/(d8r IHHHK>7DbU$յmsu eehH2-粲2#ucY*{úPeU׺rrr_v%50/[b յojj9~~[}l$VkY׺wSK,C,_)9|9)?-$(}Ӻ=F2@$@$@$@C kW$-]~"ֽpc;_G3a.\1:5c_vE=7^s1ꗁ_s^Kya *گf|HʍxE<sy@3!M~s4H̔1{NO.r$@$@$@$@ ێ",ŀNĽQ83ot[ԡu:wٙt~{8Smu>ܙƽ_(=;{#k }ut= @ȟ_š|jꙷM{EOž`97]ȫnwi/{=1<'ij f0o֎C~9l/LI=gS!Eŋ9]rB880 @-C#y3iprDHX<}|g Iuc޳:˲WϪ?V+iM?#twGX*r>3R z9,G\HP|!2婄]ogKD$@$@$@A@--q($is e_ha 9ÒV S.zG?pzJ憣8RcJ;͗sx,>..Aum)# W7e e0j>JLLFz>8?]ތ#(CU8$\RKbCN;/%(9(~idi7ʍ{yֹ5|v:n:\X&    0 [OO%A~vF*2*tjg[FGXH]Zgԍ3DqD~ث{#c[jF~:)뛇.1foc0إoӋu0+kN/)Y$L:\Q ___?ם Œ&on03yOK~+9skRP:mN IAڰNOgW>}OW6W|!׺.܇sngn$V6SZg~*ΥU"aToj+ /HHHHHEXTj C8kKkSԩu'pxE}g&t8;~HR,~~(k8Ρi^[SeA7)h    7U2s%O6 ?\:Gl e>8 $>w=~*S;~L ߝ[*NhTːy3~{Rˍg$ǧ9S7ӚW16 wwj|QisZu<^9Wy ?^S6z?ETw)?ZgN º7: 1ɪhb^x>4OpY %E1 wß=huwK;5jyF$+kmU~{/HHHHN{-n/2˷$_ԑLGGآ^)tuw񨯯G޽baQg8;YӼ⿝_7պz_mq(>?q'zhC,OCA$@$@$@ǒ:}⣢mTqhO6]-\;i,'衽XRWm܉olßtoa.6 $۞X*s_0u MeXZ؆+O=Xk|Ig'X9?h&RZ)]\7 gNGS!xAlcL6~i:f~mH6Im.)yW~^<Ƹj@7MSk;) x\Ҧ|99E_]7MŰb#~hw⵳~K.Pvͧ^-W~?'@@'wm.m!    pſgw:(jn[hl=M3fki^n[4Sy:z V!#{xb2Xy5 N@,?5P7P: xw*<Ӷbg-+J6~m5;_ei|>go߉r"$=TChj@aS{Cxu)Rp׽:}87$erS(* 2߼Hv 45~xx,+wMAɟ%08Z;:U$|yo?)Wv=Q_^s^d᥇ɮ9}λ J: W|m5ڿ,4ţoJPYB Ns9s3YŔXOLhiܓ|eixfY4͸Cks *c1*&4%(f> nЫ8,;Ja:7    poumASCuo },om |^ XݮݩvM)cT V[7mrN'l['mF'5Nߵ'YGU6(/[2ʒoࢳz죿|xgj@~[]0mj/޳I7O|r|E7MD~S\x2r9맜goWc]_0h1(w!.ÿ-բ]K! C(9.r9֡<`ĒK\kt6ҷh;(HHHHHk}d|YY@?roÊې|i 6sz(zHHHH>:m*ʁ0u6 w-f>ozf@':c+<\v]:no}mǛ:ŧjr '# 7Xm|` ]JIHHH@-O\\t(G0^~#*~~`|GyÂՆ'g$l7n}NgėHDSV!_"c/M~k& 6k6vuTtoYٜWyg!lk$CFZ,hy8UKH?6@6? 7qp$G=蟣O#ѻ +"~caڑ.kt%Eo@_wѕtDgVv)IHHHN71j4^~ iShnkE(jkf1E PWWЄt{ :==]CڿG,_Z;N~[ng>`7S@GD׀)#pZwWYF ?L.Ō_ e ~e%[;D[m1V8wNIhqDP3FZxSLCESQưQ˝ @; ekQu=5}eqwSr{bǍ# /mƧ_qm7iO\&ᜉqO-dcFS$PpDY.|"=B nWb;cOߋo gu[{?}+`"\JwHj{6d3w蜄CƘפGJo ^yv_VC13 @-/} v#OX+e!pkQ-#Q+M!۪UCG*+lդMm5^ÕpsVPL}rdz'W /e]∩S.p tZ I A^1]3nss[qm_v!Ķ. hR:ri#} )'~Gv:7<7|/z!nr7[/= pP5P>L+m3@ysc6혯hzx1!"K=c`m❑\{4 gM [wM\סN$k%w639:ƊHS^䉉Pج*\EY\:RbRR{ 0Ð~Bk7^m,TE[dHHHHt"y_(5]=]3Wڍ mxQ5Z83R9LT8^Ek=h3W+`Ϟ='zg}СC>|珍o`wPV'}LYPhfjŎ駜Qn럫M^ Wg~Yǰ\)7c׆wbwm moZy=֫d7uBhy+S7},"In5śvs3~_i`|H,㵚óƭu4|O~[[.& p+ӹٺAj[6c`.{{e_k}j?s_j>TР!ibmȅecF-vwv\L}ƁϫM.B}!6;e61 k0Q37_νlFF G{>1R԰DW9^Y%\66fmS];s!b+}Of#\eys[p/4q`N ߆}+Zo7MǕaPxDȜ]}C?.d?_PgxXįњYnw.eH/yRYg+Qn{IcG7Q$@$@$@$@7. q(+xit_Qc-Th͓.1?cej\~P^^RٯO0kY-F_˩ $R˒5`&z_8r)f@rqYW-|n}/?fXHHHC hRwJTtїߞ]o_yLɟhY&za }z5,2ۅGL3'/O"{%?2$.%m.qwqδoO˞wMWLf$i?{dckpq`==~o?= b ) qWg?ہw4h?8s)0}#yy7~KF1lxHa! OQi{j\18˓CVt@L1 /8YI{(Z3C$@$@$@$@$ ~hl2_ɧH|ynANV!udg*]Y eUG7MW]-:[]-ʌB~X׫DrSSqS'V*ӈj<ꊱgڑMHꝆtAFu2z6xtm @4ڀ.U@TQUD$ ӲK~?fh#PO Ȑ'(qLN x{=xʬ;mY1mMofYπ-IRA ψv]DpBz ~6=$7%}OBYVfHHHH%۱cG 6#q[vVRf&#G)/3O?zusQԊ* *ѭ-{]6Uoߎ~ V=Y:e 2aDYHHHHH "𧿵Rλ>_v+pu{)+2w~Oao+     o.,c?HHHHHZ!|h 6 5\}yK vdx9;w?R!HHHHHN>0 G?~¶[ ,|ZM9HHHHH§     K^+xa-;2|qTe5!    8~|>-oD$@$@$@$@'/@&IIh}4 EO$@$@$@$@$@$`$ C^H+HHHHHT%uOՙcIHHHHHHHHHH (DO?10HHHHHHHHHHNI?%&          UUU1S$@L,$          s_VV K't{N$@$@$@$@$@$@$@$@$@$pPy_fyW ?Myp$@$@$@$@$@$@$@$@$@$@$pJhs}rn 䤲$@$@$@$@$@$@$@$@$@$@fQU]X7/ @^*kI+?Z>GJ$@$@$@$@$@$@$@$@$@$p -!b*AcC04fIՕs QPHHHHHHHHHHN,_ [>Z_BXkwEW++FՏE$@$@$@$@$@$@$@$@$@$@$p ojow%Kuc VY5b&3 '/jX#,\ɦA5V!PE$@$@$@$@$@$@$@$@$@$@MiٴEG(4]|U<0` Z'}%k          Fp/ʽ/AE@6U hF_Vʯɟ J@;D῝HHHHHHHHHH:C@eO~˅xf|~~K_w5ƾ_%-Y1' JMA%Фo9CA+]5~IS?'~C 4cv          E _P_-U׳ex#N|ow\:)dy&          NDEo ~Bb/>~4]< @@&__}Nv"\4 iN@zwW G$&}@ky7h`rt&.#d$@$@$@$@$@$@$@$@$@$@#fc=ƀ_@$$Q!_C&_Vq#OgޮU,O$@$@$@$@$@$@$@$@$@$pZj/u^%K77*&#fi@~w,B]|E,N$@$@$@$@$@$@$@$@$@$pzjvc6Ԯa9_iz/zog]v;&HHHHHHHHHH>Wr}D7Gc/gJS_- ɯւ]3e$@$@$@$@$@$@$@$@$@$@joQaP^btb 991@&3 8ׅ#G-akq匥X]98&A ++%S@ >M8K}' II3xr3Oγ$@$@$@$@$@$@$@$pP^EzuNy`_m|joų|Mi-3m> %!-+ zLZ=X9 | xl6^c"¢gScg`, q%h4 KDoҍ{Lxuuk u/݌!Zۢ6ST*" X^']kWadoFp'bHB34&      ӂza~QY0ݲeqEmo[;1] &܅a)8I1܄ԟxmXu'*B)({y|Pl3H?\NJn⊛Mʎyڹ/ހ>O@Qa!.Xoe$w J9890 N-oVG>/Gx3^cHҿ)5!RE}_txj_úuEY+T7'y Fcvg 8`u]#Vc95\ | D,UVqAĶG##w `l&8S;znW o㈉M{ CPg3 ~4}xvּ,@z-jk«u!B}v|7]lPz}UcofWbqL7ęԗu/Az%}Eø!1{.Ϋxc$nIȿt"rS˰x=r:ze3o”9VAټOٷU&+o݌ QV,ہ߯x쩓~I'[7CZ<5DEnюl9 !G+NF^nk e ?m ?*|q۱KkMrpD\ks!ߐ`xf;6˘o~ ӽIKٕOm| ;3n:2G칏/ko%6")'r-WMq'v[M bWK/aGUS#qW!=\mĚ7a5#3p50$m;6~~ڪ9e6cKي~E:ǧc.I"ؼ{a;aR۶[Pڵp4h{=MWiw-gL*Jwl|oU|we]qgMr _i7E׬HHHHHHH )>Z'mЅ˧Sm"6[T'Њf$煡V)4blS8v\GM^%Zk$jdW ,z??TTnBuEY=7p6c xz9g{¸d{*ԓ_酅: kZϞ?鏗g N!/\TЖY݉{\K Zk[$@$@$@$@$@$@$@njj P]sWĹ^MѺ@6n jW5a9WCvʎ4bV4r}\^YW7 c^OoiHʃTQQ8nyЎ1ȕ|nypc$E>_2WB,WWqX-X#?^[~F+}35w:ޒU")%BD5m*iCKˇh;E}RBdGojj%.XbY+5*Ƣ`Ac7! i8si@qz `惞mu5kJݜt#k.$9羭pgsa_κKmw}Vu9FLñF :n"-{LVFRce<._uwz^SaLUmp.Iw|m+(}6:^+c[*|Fokc `|筻lpwia3HHHHHHHMW@,%W,_-BRL}d::/ɦf]9s1 ,uf3.?[!TKŤ?ró۪#Ы+b{эB۴SFWc{X̟[DpJ ƾݻ{ldk2Nr sWm|b߫KϚ~"bX8GsY(|%nì\K1ۭvdQk7mGy̩ T 1v7nw^x̓Xo1]U]'x*|,]<'aBE/2= PWU¥:r gEUU-bmGrw>q;(=oYsOZR@A_бȟs ??|G!fT-?wv ;[ܕn.\ 3 qGy_XXdeLʖo-Zi=[%mRW?@@>ecoa}Kh$@$@$@$@$@$@$=o@}C QY}X^P!W#*̔A=wv/`2Vo/eƂp8)GًCuΰ a5؛5)jqV߉py?!uݘHBuN}TA=p=z^YD۵D]#8gO"726lދ;'X7Zup˻(?8D?~rlww4`p'kjX*}q9dXQ:n ߤ2>El*1"r篱a?'n6_3ͫ9C9n oW?f˹bsK'ֿt|jTLl뺯ŏYpֲW'zt;\zsy.cy{F\aLC`UX9h~6PYZ*g`8K      >MMA/Q|\!jE/= zY_'&a`HMIGvHMM .-5C$kD!E5V"B3א.}jzcE,-m!ߒ?4f&2K%QE,[ VzhN()><cF@IDATCֽEFQ&y㉕+qp@%naU-\o+`^\ Kf/huW)Q\88kP,9U*|q3f#6^Rykx:3Z/,nmA^Z,wv(;Xqؐ^kuҫ!O|$O丧$vl^ ;wNJqw@ہOlmԴi_[?!X~YFL/l| 卑YƋ~Xv:xϦ}+ p<}-ƒw͔<6k!~yl+XB$@$@$@$@$@$@mP;7۹ UG-"Kz/b|22砗?ge|Ɉi"' !l m+d[IjQc#jV3?_وCAVFo˟iY,Dm=cіe^KپCB_EٖȀwzՋw%'ΑqlVnrX2UwY*]a*ݰvy7:h.FmdngrCUS dE3—X4~P _ۑqBl[IZG-ۨErEEt[[uؿ׳׊:ڲ߽c~n`Kڲ{kjxNt袍)_~\sl6n}?sc 0I^חGSrcX      h_-j*2TK6PF"'r3@~#C}>E7GX,W\DrUvT3O &&hBW9`\ i~YhЧZ{Rl7ܦvj6=eݯ8 ~%.c÷<;_k\T#7(tXUT8ͦI{pGx5%ٿMy^YYL&^{]"cH{Pqdwkws%_ɢMS'U8++NCfb=2NϰtYUR˓wa9=^W<ʖܽiYfXtw onEk{HµczZdQ+u81Kv?uУſqA|ͪߖ]g\L|9XyS>N 瑀_7}׌۞= O*GrJzfdGOXП$쉉JH$57*Ջ/"k{M~j9Gi |,ʓpE٧h)󃦽gK%K?&nbbi%ڛT2pB]HZZvBL\~B{ Ÿކk+!}z$ 9y  &/|dakjGHʾme{HYFbHΉUl=p 'C7])i :Es!ƯTV Sn 'c}Ϲ8vWC .útgiWOY5Y0ǹخ*+waGZ])|MTߞZ{:}ǡ%UтS߳DCK)IiÜτE:./r~q>%doݹOthq2g߱y(Y:9IHHHHHNF`5fUV\t"SѣGRd݌L~XŽ_ua]%~5'rhm~+$OQy- *ݘTU)H {4nvT4$y 9)YDSؗy`޾%[>O NìtSnBx_f,V{c6`7޼|9ؼI3ʼ9Q_Qm;JM|}.w㧲 EDuXեf: Bxpiwpj<ܰpc߆?xϏxU*] Ϗ?61ArO̜N^9;w?۶E3PpFwua-Fбa -h,˶aɌ~}FnO5{cS$_!O︎q?95xdxsRp"WsH.&Ϋu5WkЬ.<9$Cl#+0wcCaɒE30VAf dC5e-?G,~kYE܍S"Pw2rw'H{n,X8 lJ:^л.w&uW 3/i,^ČnikOǞᅃ5T*S Zn3wsfD?ƒքX?&Yf=aAaި(u2NÝ;gO s=E MCX<'o^/D,$eŴxt溵V+4?-ߜ"}-XeMz <n0[x͙j?WdXOk*lG?3p}!k_@$ 4n-r~=벫KuށKgȿMcE]y\r"W dwД3EĈgX ٮN_}.4X~"<5xgy\Hݳ龲 O@]44֡G*P!G+QEXĚ_}gdD,T7S,E>jV~*?ADD_X놾6>$  kn.yS?Rd% %5 āMFwGP)/ݓh< v%`[w|FwzS Hu S |낫שoFވiB|P^Gt3$3/oYKNj%"iNp܋p,`#ww `8uK.G"ClyyWWwcVwu#HtѮ^(5Wswc]g      C@J^"ף蕖3 ?M,?-%F^Bn~֕ƈbnq#&G%@-e^=,w:>@E{,"=HMR?R<=$`b߈^AC]-*}[Y9h@YTH UoE Z#)stg+DZv Cd] Gklu8q fUƪsIkicΌ`yq׻tj5sM*/P)ϲ+H9{*)1`.F NƏIYbNd:k{i7I 61-\݈wZP|l*)G*=0طiL֐?y`eſa=~+yJ{3=t=Lek୶Kw%hc]E(_+_U.iyZ\݈w;Ö¥1>veV/[fUW׏v}yMJ㾿ezxyyfO}KQT?F4֪%Yß;%V'ǖ'i1g}]^qwcܖ\VOȷy[ r'J`q{2yVʩ۸gdwc?k!.Ǐ&ߍg      ӓn[[W#aKy{lܛT_'|qˣ "ʋ]DJS}1ao] Xu~[Ҵ֠Yv YNf$Nڲ"R~G/~ɲ!pjzR{0/͡j+d!*UNRւnl.GvZO (ݳ {ԐQDgUe^=1` -|u (Le޽G}E4mA4iRoSqN3v;I$ s/;ZcgX@>} AcN;[gb?&/~Xmw J^xޞu[m}&8@)K7ˇ}Od!91Ckw8dR( +iⲩ_NY/G%%U24 3H6g~_]C'r9cFYd:1F!     8fj[ K&9Asr;>Q=)dm`6YPi^M}hnj%;ͼDjƯBtPz ƾj{5O.|@3 B}>hUhláwY4 ƴKL9'ˆĦvF D@]SFrG#r XK3fGH?SN*D$vD@ k\]S\SpG|cl(:z<>8D[X8w< To}Y0mPҁ]o~,.Gn]RaHHHHHHHsB@-j%ן(X$aع ==99_ 'A6組Doハ G]0*Fh]Tx[(on[5Iխ_6 , @\ JF97dzU}9W {da[3/:޼º.dbii+NG+}aᰯ^ )jЪU= 6|޺d,ƛBlw:(wfD!¿KW,=A-ܵd˜S@ |! :b韉}?)oY [?Qy@Fu, Ғ$$$Xd@⦦!U}dӱW` ùr 1~p;Û6c{vϰ pŌp]5c5HHHHHH?h+**╭ϡ}G#G쫙ٿ4 ~SR|'jomwU#HeD|&+!WMZϖ~ؤ.vԦ_-ŏ7O=7 cohBX(%Pq#k򿶱b_oJg/NJ?Lwf)DjF"Z<8m2|THJ\ rE#kuodroTs :E fb”M'@*rGO:A=`$@$@$@$@$@$@$@K  eA4% ៚jY |uߣ±eٯ*[qc,"^}י z );ߏTo1%-C +q/9"Y4>))a ^2jXS6ǀ`Y($BJ*BFTVꫭMu>Cy[dsޅ~[ˈ/}ҧD8#¿$@$@$@$@$@$@$@$@$@$php~WM@Mc BX1G}'$]f^9'h\ՏDl4Ÿ(.18朜È8 zN =C*A[&E-%'Oh|ڞ&YU~hW?Q\dQ QLUojNrRV|@BQKB3Gf5T$> @ض>z$@d Fvvێl ځrQevW*NwM6t%;1 0!,;sNs}OwyߺgOk|nB[+ۚX/^?}3m4t," " " " " " " " " {muWN٠ZֱZ b^_)3}e߆:$}A @@RyǕnpb\pQml0/OZ^ R qpr&D-,>-WL._k+8X׶%ocأW_=[bo#i[v4‚ޞ>mAYCE ,fGOŢ5ӎjIB6>Pv3X|g;u?z;Lp [Dw\ xg0Xm5`z^x+lf꠵[ӾqUYj`GQY!~"$"੩\m`Ֆl1mV=yLAs Pp T̪g!?_nk"䧐o[??P7f ";kl\+޴>is_6Zg(/1;ahlV֖@Z0l5/>s<ЀP)" " " " " " " " " "p5 d7 6@}7ۿkn <3l~̤lz!D|v@̮OX`K_8Cxg9? 2XtxJ_K駿)sޭXg!`g0ȀhWyŅ}\"^9_b:ƻotjK^%? {Bf?~^\ >E@D@D@D@D@D@D@D@D@D`O( /X3DZ q%}*A"Oޏ7*`Zr"Pf5)ahMtH.$|aoc  ;?̄`H! % MC\#W5JD"Cwfp^(K< u'" " " " " " " " " "p!WvӭnwX?3C}%=8@ *6Š#)d3C7펹7}6(G\?<֪Mۑޝ0vܛTs1p0?ޏoW\tѲ=oYֱW.3zsra{xWdS0?Suf"]S. 6" " " " " " " " " "p Ph?5lzMX>9h8MA m8=a&lgԬCd^٢ `@ `-<".c7[ >:?hZ Dyx1!=ѿ^IU-|su%_,A@` ̭5lwm LQs̐ Jf=ԀϿ=,2ڹ%snб5k=ddx[ϖSߴ)X|O|pG0kOxz[bG%0zedְA¦svk~?c@|TV Ox W;D@D@D@D@D@D@D@D@D@D Ы~yx@( !:|jZ$.S 76;E^]h=FD@D@D@D@D@D@D@D@D@.%o=vjuެ7,4~PKAlPw_-гK|AQTb<WǬL~^68l=4pl)<+Oc7O^30#{!0CpAjc{p9/s vG&_ng,zTz}V? ~d˖/]K{ ҷ.E1~hk[4ձްI i߳LrGt/=7 sf3@@W;Sghź̖g>Gq>`3>0`dyobИO렕wN|q@AWʛ~M{ 'AGp>Ex@E~38lk]E5hp" " " " " " " " " "p:Z-ʼ/=kKUꝮ՚5~ǰ.k8`]5/!aCN  bJ%}p^$X hb+!c דtrQiW1_lmdk_Ok` t۾{`Գ^c_POcgV?gp\!4܃Vpc*U6H ԦaI`Gt^pjM+P/DyߓAp=%i" " " " " " " " " "0&@A|8\a| ύ^ ޻ڭ}skAЦrfS(?)DwXKd`wm)󏁄}!J ֒u9;i߯ - )9S>#+>o[77XqZ>` 0@@|',Q\ d?}?nQZ@p]!#;pG>MrH/h"@1>ey5ϐ }ftk&C"8xO]wa;\:)wSʧ‡{zz |.V 0,@36ff4VֱAnKÓ5IB_|0j\@upBdE`G"6x^Xq  " " " " " " " " " ,3GIbqA =~d XֳXܖwu6(c#Q AG=3Ȇ/=?(n9Pl_7c3@>9s 2kvd2Xo>y[V7leokwz#>VCG!x@)΅=\Y|8fAߎ=.|<@ )'k\?@1-3?b>Nܸ"8}+p(Ї׫w)'aaA;jhDA\>h@pGy#0S`0;-"hrz["C-?ds0 &/qu7-~:ݲ g}IH'#(/.ڲY ֱ`mdPcg JxQ |zO< lP!cPw Ў9)Ca[ЀϒVi^w{5,;a[ϖo}o}OX-jڡދ?eϟ!,܁ ED}m}X?l3 C8Kj1-`rڣ$ D@D@D@D@D@D@D@D@D@&%wfgyFEg61h/g`͓Ĵw~ K8?9 Oyowm5?=g tSZg:假BGM!s|oVƆꆳP|4l4߷Č>%@_P$O·wnv_xN/X9RK-gNzSf @v2dVmAa OgHkܣ=sSZg?V?ϯ\}v94º;0# B`Vb5 foc&CD@D@D@D@D@D@D@D@D@&syk)} y}0H!M(S ͗a"8o)s̠?6W<M8H/'M6<@f[}]{Kj 903 1v3<{;u<9p9oUq[ *'ԫ\F6ȆՑ^@.^@/  b~$#HPcd·#Lш= . u.V(!%¾OƎYݺúZGluh_~S؟GO>c@n݁ vb5,^TТ(/>>?" &%h;qDQ$O=ύBw0ցOA[ g|Iy0@%P u3}\ 0"2SX0Y ;FVC֧/c kЧY"pcGH K \"NDg:*ww)c@6t?(Dtx2۟2;3dsq`:08Mx XP/  dk RfS(,[_AI{6\/ځVO?}MF 3 AQJVBLb?ߪID@D@D@D@D@D@D@D@D 2჈=lͼ}f%8n yjߨ JEšG&=9#8W`ݐ[Y/T}"Pcl}ֲ%,\|ǧtDn5wdf? o _pVG>C|cc:<"OuD!jćgQJ}4ՉIo qzUCHPdC AAE1,=0(IзV)j_>urzv+vPҎȣ!~ \xkC i|" " " " " " " " " " .;Y%ŠLbKưϩ6|B<C?3Q^ۿLz)ّIO˝,a ݗa9t}rv >v/8u[ Ɵtdw_;CяO!(1M!)cr$\6>Lߦj'-;Mk$g>6Or:c{L|G<,~f9p#}@/gς~>Y lٟ3O!ѭ+jXsῙu03.fxEu!s~6f&A(,'67uLa݀LP?A_^ED@D@D@D@D@D@D@D@D` S((d3.{y0ŝ;33  <~`4uYB|p?zr'>OkSmͽ!cܵ]y3ӿ>sń/<Xf{1>eh\psˏS@.$9AI*'Ի\"k[6ma[a(PNc DpFZs5Ӈg ?bO?@Ȇ%PO]ߤ M=D@D@D@D@D@D@D@D@D@ Sܢr-mݎ ^ JK^#7pc&}0|ɃN-OL. s@^KD^uxs_fFaY(O`y^ 3 B }c >B ]Ṅ*"" " " " " " " " " V#nFk>7VO lhZE~кQ3ѡ3=˰F5죖$ )+! A_ cb ޾[z^#n}>3 1z>21`d/,ރWXn֬/n&HoT#" " " " " " " " "0"k5:!{)!#72gC;ܠ?g$ǁg33`yps YgK zxb6¢~jD/:\>,x˿L:|iC/m_YY RM#PrfB.2/:aa}֬aW ]MD@D@D@D@D@D@D@D@D@\Z o9s֭wFilHpw?w?Ȟ>2#. JݐTʀ>Bh>~|a!~enJK玂"?3SXwѾ}Gu<,-ns. l( p?9 tk_f{}D Ahmo/~*!¾Pd⻭&2#ȔG;?J! SOx%pf&KI/m CԵfzڶNc覘9,bà"=3,gq` Ggz3, Ϫ}Rcab.c7fzr D@D@D@D@D@D@D@D@D@&3SuZu zA 3z*CC3g«~oI(83p()ٟ񘑌3(0O<1k$&HoU$" " " " " " " " "0^jǬB4#>2ޑ+}2UB.Y6S}0ۘnX% (lڳ3KN=b…ur(ABn39σpB7/= Bg`R5 JkS}6ݏ1OŏCć1 E@D@D@D@D@D@D@D@D@D`ĺiޥqvr= +P~!ט "72y\`?LBf!S[qa`*IzaAƍh-ͩ{| oAg"?k߇ uX[[O`G3h0r#xaon1,00=m=yw "Or?߮MD@D@D@D@D@D@D@D@D` $Ij,9~>tO,|z=7iC'ܘ2)sv8j`B\܆ {{u~yrFxf$`՝Oу*'. SgI φƆ5 A g[]k6ڰiz[⃛ eUD@D@D@D@D@D@D@D@D@?^n>x'_kyzCL9 ( fS/1w|CdQpKiz6 4[Ǿ8.sΖrߣ@!|-80_Y}x31sa5J`+-!zxn5,d|{ʹڋnu0ka&>$Ih/" " " " " " " " " {SxM^Z:<%?!O{#gey'+ gKBmB s¿@Ze߭{ yI?fcϕɘ3c̅OpN! 0goT|<"RYuEQo/OcO~Ng`y _C f';ȤL؊3 # K 2iC%ᄠ3`)<T ѤsпA,G?mJfc 1ރ{z3\ `C4Y-[IMK6;dF}|zK '҇ ff{!v|q-o|Cgf?}ߌB?u Q +C@CU|n'{C6GpH.ec- V`?9>;u{ "ӟ19(36o֬u[\VJ+.V/)" " " " " " " " " N=1;claΝ} 'kڑ_' C!GQ2G#ԧ_YE<&(??>-vEk0@Uh D!:鬽uaK60͑<TévōkUzh|\;~TSx0 sYe~38 G2GU-O0[!])fzVKj}weo[ؓJl`=/>kJ6o }rg!S߇>BeY9gBo~PNX|5@~n5 ˲Zmf~L@ahY Y0(?Hfm{ȦuF\Wn@,Cx,ڳ}r6rA:4/!s&2@>gPǹg3ӟPG0;=/X?oЯwx/ϬH + ^:V 1?^+k3uƂ;2ך`#֯T7y>nsvU閾熖mqQ ԥ%4Gtmmj%#:ȶSd#~Db4vA޽iÊ)MS@8a2څԈB `ր϶@ bJBF >c@CDCϑX>g3͎(碌׻L$&SwoXާ [Z? {b!+ZkYԀXB&>3x:33, bzAq,y=\Xů8)!~C@pEY>`294f5/Y#oZ6t?ucsyR66jNkWwb",ʛeC_ZQer+d#8 ZT'֭6B+T/$" " " " " " " " "0OQyAɟaq3!gć(  ^zA>|9+`Y1ˏ _㋏ې' V40r;ȼ4j!?]wgp|k`l5"k7g̋߱[4۞P͚6f `"z 3xף3 4xh $.lyUՅp{_?4\r ex8Ən\hq} 11P)?@b;r `PZ҂8OV:C[,A$g\`C}nO5d<ߏ_߸Rfr&+۷)ٝtƚ;9a"@pxEr>(>p ..@xߣ/P}LbQ$~z'&}(| <*D=<)Sy| p)S {{+Xp-l_ h~ p #s iE|O4Z(d3}  Q.#B <8HX[pA*g|ߍ@uqZ:;n\'̭~ym9Ņ3ڇ-6η;Pvdt]D@D@D@D@D@D@D@D@D@A)n%p4I!3XPrv8áȎ%χO|M.h G 0 :T8fk=~@J២={5a>? lFO^x u_:2'ۈL8פwdMYُ> SG +循G>m04@:؇I+A?"뙁}R h/kBhaa%f#9pK|FzY ota?A=;#:ֲ {C[\W|QGKkTƇ|^K+LfMsZ@F|4¯ SwWx." " " " " " " " " "3189~3.ݱLjcF@W ," " " " " " " " " &P%ӻ-uPrt"c? NW2y=WD@D@D@D@D@D@D@D@D@vA.o㿒!3O߼:'+\O]p[Ԧ?U(z" " " " " " " " " {8ӟ?`_@~͜WxPs\3\FE|=q-ڮ@U" " " " " " " " " "3%tQn?\Y4ϧKh\.]OL;j`1ZՃrm=Yш`=jXa$u?]D`c*Ǟ)_c;s2˯]/-" " " " " " " " "p,@o \q6ee\{}'uN ~/"Ag1ki/Z64VBk~lWwD@D@D@D@D@D@D@D@D@D@D@M3=5l VD@D@D@D@D@D@D@D@D@D@Dln#i" " " " " " " " " " "-c E@{hE@D@D@D@D@D@D@D@D@D@D`Gwģ" " " " " " " " " " "H[ߗF+" " " " " " " " " " ;#E@4Zؑ-ъ$G7E@D@D@D@D@D@D@D@D@D@D`o𿷾/VD@D@D@D@D@D@D@D@D@D@v$x7?'dwۨt_yB5D@D@D@D@D@D@D@D@D@.kS?X~ŠlK6nֱFyDO|qR$mD^\Ԉγ1#= d7YT[ҝx} 6|1x->mE8GV}0>nf}_zH+" " " " " " " " "p \D{_Gh_ b<3=.ZQ ѽڈ9Wk >TZ9گ`> ofS猀(iR(FQ.-Z_raYhYhZֱP[ߛeyb}˱g#iu-j=f pg6@g͹ :g\^kai͘ٿ=ΛFf__Yx"" " " " " " " " " e',._X8Nw){o@߷}ikVOf#t85 lFw=~ BO I@(PbA]),_:e }+Wwv7yNZ[\6 g ǟ5k[Z2,A xp Eo? `sݨ߀+>WxV95f;W:M"(_*" " " " " " " " " "p) \J4EY]Z0icF2k(gprG$yN>E]?ltv91A> 0SיCLYˏw+3mSlg!Yka絸i9,sMðTu()Ds]T6.rl?øOyG3dSG@ >PqZ~S֬6L|=l#=Kyώ]>^weLZs3;,2+4@!L#ː,(bˡAwqZGF==xoB-#[Ha{`s&*Y5Z8clh)EL p?Ly#omzIuO(c[=Fv?XxS=ff*K?b%˅{3uZ4_GdBr>Nsc!3GK,Wb\0}\6;/ۃձ5C`q-W\&R+uMlϡȚ>ס[^hZf:/r<)XudwpZe甂}fк%sgl: AGϱ0cn3ژsdyn2%F _ukπ}a'?[ 8q}f:-̘oخϟ 3)+ !;~'6g zVX}3~^u?5;rvM:Xga}O>6fnAAG3_" " " " " " " " " KನA3?;6Ω!{#< ]ϣׯ9 )q1>UlfGҹARsNgrvۖpDqd]z#OQpMͲeGPc#,[Pg>2c.0{S8M!,<y?˭½~E2.q \lx>~±;ϭ!r1o̜O0s~gAOG"|\z!Gj"l^f:6[=[ #Hֲfpn*" " " " " " " " " "p>.0ÂLo/٪-۰^&WilЇEMELs>b>m^[ bq[.p {'">=C{k~jn{)moL?E<+^mt1׽ɊG˞5K!f`TM1H3WⷾN[VZ08!23%Xk+w?f>¢^*xk_ ˨ vHf <En.&|ߥ: .3@`-bpk=߱lmCؑWj9!3^\zwW- 3V@Cku3C>j@?mfLN= P#+=n+dF'Ϳl~'9YR0l=:#c.c`گFia;#z_TL"&FCdC,U IaOiyS ^ μ>r\v0z23ckP,#[w}Rtv;F5K }MZFmfx,c"r(6fsmh39TD@D@D@D@D@D@D@D@D@D`._!] ud˱pﺝzבEr!LkaESCڄO!~ASkn7w=f=ZԷ9X贚pLeծ(l?ܐ=/{цV1AKhsX-~⏐υauxS(\ v5;05B7g `cͯ,X֛xߜ^2Ag3KږzSCxϲ>ܥ {7%qf %Mԍ/Ԟ⇰qn|?F~n׽>D@D@D@D@D@D@D@D@D@D`M[B5RZ#nZaޞ5kC䅐Mv5ͩHNתݘqo=}k8u |e =^>)N%(g\>ǝ΂n9#X6e8a8NG:ܸ@2=KfCOCs'¢ZS]BBw˶S.˵'l *YKZc ,n6! "N-Gذ<ǿ~H[8G5T+" " " " " " " "˦ٌܶ+C,rPISf02WhOiإ`W#lϛ;osFoӧ~xF:g|.[`f3ݖx~/ʜRb},w=F\?uzUʵ|=NPL`7d%|;_5(oe毃w ۟0b;~L{)bhS`(/_]?m/=koSY/'bS?1;7ֳ;_h-3ڦ._-`(zCA" " " " " " "p 4J/D|f֏ϲM&C+=`\zRx']g4ۋ+ $x|>޳cYc17 3^93#Ig -lJ'qDBą+< c΀,P'ZIw oV/pܗ rrcmƉo_[9XBfaTaphZcjջ3N6XyֆKn;|n{")z/g F͍ҵPc۞v~v]wٝ?NK{{oy|u.^{?o?l;gw-KD`7A/vu#" " " " " $˖m%z? jDL[D}dw@BF@@8#R0Uxǭ_y ]co38븜=T{z9T.i!\{~ ~i-9FF8⾧I8Df{p_ȃ|XCmbwYByDECؑ{w-~Yf"Tiy;ªvY:ro?}c/Cv e|zYv9^a7\އkn _|f/oM.YkNLE@D@D@D@D@D`}kAڼ)1MO[ax֋x<~\ŪY w~p .U)`=#g=gE]):nyb2l]FK@ų'c oϜ#9H! ev,LUS0!k#fPw]=煮yoگ}j*vG{zYoKX\ؓ=6C> zK~ܶТo>'o*nY0S{_~[Kxo˺i5.ð9/GW/?s zW٫_jG*mmby]95Թ1- K"12<4qmu{B.;u ,.>4ajy9x\-5?f?>rϼָN&V)R>F|z'mcC?1ˀ ^C EM5n'}ּ6xͪ5;b_:Cֻ%u27>f%֊x[5C?. dg3J[-mxgR,~_[g..c{*"k\J;f>^U'q~#ڞ^][wG+S烿e~ѭu5vOw>_a+}ٻ9}Oڲ_n5/OOОv./nv_;2ck#V{g{^ks!!\H]wKwĕo~+BR_+xU o4-" " " " " M?k@nT8`4.Y[n˳^x\1<§l$Yqq3)gǏ[dݲ.,qٰ62^EΌ[iT=37 {թY wSgvy31)Xw2pg{`86\_>eY"q~Sv_W;;~yk*"{o?/?B{A{퓿iW6s[-} |{X^lN7{w|pu|{p/fmX-1oʼn7>=j{%ckW~/T>lo{xD㆗s߳C7]YU, [FVkYoi MurWʗ#Oᵞsmqdc<3)J;ޑ9:=1Sﶯ>;oKO#;cv|#aY5X]Uoj*g~z+2s|pg;_G+-޿% gNanW''0O:aϝ%L4xmb-5`ܯ" " " " " " O`=޶0gy$oak.Y# 3O 6&x[MX#7f z? "DC1B|ap1/!O?kɓv}E.Ourc`lX@/l%8^I~b jBIN,F@^lK{K- *; u#@Ypdq/NyMJhw:[=n"};{L|Zb_V@/nj}{?l8fvn~&~~?jwY,o~5'co~?҃kGV_wV$3@IDATz,>~%-`?{_UuOr$y@TTTbE;wZ\hժ-q8TGz}T*B *VA" y$} -ko}:{][kKۺ#oqHYx0}\եn@X>{V-E\-Wvp'Uvn:WW F)/n~ $/"ܙƿ?K\>:>b{zpJnre>}vLLecvO[ 6~{2b܌x}pY4"^p0 Ƃf>3-cs{aNjↇYS٭Xx,Y.+u€E$~ Wl_o{Y\#T8hu c)OGq_N%W'Ih~)"("("T'dѐw 09;e~c%,29e@[V+0])'$$FRqc'2P\&M5CԌ fZ8qfL!e%@E&fJ}%YPZyY1Z¡L$yӸ5E:i]17u-ܗI#$p;?Xر,y&~;’*ǡQ@;̄@搱fOJ뮽4@hy1}SluG0.Υ}%n, s;c|ҁoo2І}qe\Ib(ft>U/^/sjw2 pfoYafjj%gwV ޘ]t[՜ekƛJyV|*?Vr Okω1LBWE@PE@PE@}DKwODe{kq38OHw$k bTcHZ)|$GcB$'"-'!pI! gd;"y4x aEK]W6uu6'ͱNBȤӖ-H-m/Kk;&Į{'}4$K\X9 /bGV $f#שEq5@L{Zީw]Wq%3;4&zV_ Ljui<7ۻw}%rQ ╏3z%ch;݉2ՉO܄?$9Wk,u_ox֋'Mm<Ӆn Êo3YKBWce56ji?=GL2fcDˠNuXF^ܲe#-Lf.~p+nYB }>m.[g(c2޶_ۖq ^O7MXk]e>)KKx7`e73+y8< =p#ukgZ -SE@PE@PE@]b>O{hCpLkb'Np7/ [N" m!+$oSB -2+93\d3VCsE@2SJ4"GO!I,fOZ>ZCb0w9WskUq>yũGA{`>+FZĪ;t~~YIdjRl {q^h_|V~>x3;!xbl&jl_cd}t%Gn}%ڑrG~LJ|I\&,>x.%A5dx{^Vl%AjڽcYQ72RLS7a&L*cL$:xmy%g/2d|Iq=.RNi:(vHڇ|6A --$ls2Ru7!4ɯq),';"Yv4ҭW4}iQFlKUji /zN^&+t*{]Wh&m:Ћ ϔWl{R6۔L- ѿ@D[:b-{+G:;*y=ssM7F[KiTIϞܕ`"_=^wECK oU߂-61X~\3o^62t^oĊ{ Vkbrt"-g۸wz\yY6~N$⤹]xXv ۱%X5 N+ ķ7i!wIm[щ'-*B~ F 6ڝ τAw OO06sgcM5_ {'.ϻocz ڠQ"("("(3#D wc.F,<@IY+}SS\޿wqV@S|RҬ [L/JdFrĔe CE$s1do )oޘQPK?ujM5xQo4er`\ji/zNi0|$pČP#M~p&?v݉ArdB@Ή8ԐUwn#֙kS?+~{ + \KK>=ҹٯ8YNoRQF_K>ډʚ&e[£SGۙ,hqy o7#M7mEK]H;Vd>))pV^nҟ}0Lվgq{Ŋ`ëkc/!oI$ ǝ37?ųKlRURޜIᗁfb%$D̺rt-sKXvw I'q~ݶ!8&m\,6=jzV,X܂Wo ?/<#Ӑ+UE@PE@PE@}Z1*WA~#>ٴ$kDv}^0Y/ O7q&&u\Q)V3BvB<77q&t:=L29 McYЙ?y4M@4# }W/`ެMyO;%L .?LLN_/@_ w*+nx<&ew=&F-*E1˾?6o%֕nył'b?WoǾ0;Rj22;fy 2hr.y͝g 3oဝ;2/16bƭ ۵a?xrތVՕa񫹗jW\{+<+xbYVVX2kqu$Zr.c6:~8Fl?V,ZeO$ E@PE@PE@P^BSYQ!믙^R94+))9mSN(=;??W!7lkhpWpSjy/UAS85 uif͉#wi(4Gg%vT_[zi9;m\ӧXxerb83@} 7BSS; M4QNܧ[ם{i]K"Ey2m 94DPE@PE@PDZKnGo<-ԚPPE@P@fEgFt3ҶuB,}%TlB.8!Eքsz9AxK;ru8y{eE.0vh1"("("(8 ("("pJ @SEE@PE@PE@PE[`L"("H3`߾ldwA5DRE@PE@PE@Pz=Os+"(@A;w? wyTE@PE@PE@PE$!~NZ"("("("("("_:,))ĭצ+"("("("("pP@PECX9"("("("0 " x߆րop87\E@PE@PE@PE`#xU#D+UE@PE!p饗3TE@PE@PE@PE@$L;iE@PE@PE@PE@PE@P@ҀTUE@PE@PE@PE@PE@PNPS4"("("("("("0pP+TPE@PE@PE@PE@PE@%;H("("("("("(%νRIE@PE@PE@PE@PE@PNPS4"("("("("("0pP+TPE@PE@PE@PE@PE@%;H("("("("("(%νRIE@PE@PE@PE@PE@PNvB(" Zjkk -pE@PE@PE@PE@PdeeaSW>':Ç FPB"552(**Bqqq_U'*'j"("("("06kO;wB@(((@aa!KIIUWE 1ZZZdgCC8;6')u35 |97*GOLP̅;> O;dm3mE"d2Nt$|~x_`^U_o$3ʊJR7^Dy'#Lj#n!}Z?qj"(BV!+߷o|>ƍץ=3&u^7n/>n84{UH_xqBYy (i0?/Hڸ2o#(`W_z>Qh?nE٥7!+Ŷ?A'K/W9 u ˼ń1Ëě   goSn0)J3S@r7,@~#zY1DNۨH ɺ.k}BRZ"(BJ(\35 ;?5d[x(w^.g&V[4 >vΕj?tra" 2N8h?<GTX f|_۵{~"ZDܶo{oYBO?KQqB{O)  Lw5Z,@KNCW?1+ٸT60A:E@Dp_wScC'ԩN}uhCzWcWKWZo}C5lC;'M"89?};bĨGPplKʔcGS>d>ik^pL8% mCJJ&\a0vqг"2Y&n{u T}> E*]Nڴ6hoگznqqx(Mq5?_>،wc7]ێB?xV8p Wr2\du*ذi17$1i!Cbߐ~OW%Nr8D%=kK C'}#܌&_/1W?~PE BF&^ S}p+3Xb ;k? _yq`a)b5T;*7e&IHfHrF}hdi 3../> Z8v{Կj @4Zκ(yo(/Sv!DnMε揙 i'ه!Mbu">8l< }I8+p+(QoNjyAM=!m}a|؜(gy,~Y `V'2^ gb֘/RSE >XX[צFdp^k?}Z`}nW}o{LOP3lSfhETO02)㱮۠-fgM!)DaaZP_ׄ$jzHGkׅ؈ K%}BJy(M)$QR%C -Ӫ @3'`8?H) ~FRj:2Re]B|yf;2fK-FŝOɭ [/8uW⋬C@-Ƒ9oEYc+ 9I ۙ;L(RGu9*FxQ_2w̒2\4< [7mC+} (:`-Eg@Fgߐ4e&V%y1mP rzSqZV3|r"ptn|= ڮ1g_ʸmԇ={_d9ȉuBuu޳ږ9f2YIp g`U ((v،o> BlxvoGfjTB6AC#y@]oFPkąGfآUzbiGIH UzC#eQrT ݽ}4uG G8He@.~$y7:RJ$;Upb??,yJ3Xq_iWlP].q>:G%]ɻ ˗ Jr~p!E4:ck Qh#=)i{9ٟ:5^p4$=I!>g%C=䵘S1*^gs_XHb44$HUm7(oipŬ ŵVR39;LbIoȐTEZcNJ|)76^~$IO!ssOAXPFH;^*|dIR3a kL0msspC(@E AZ䋟Q|(- 1鴨8ᙨ*1uq;hig,mDg4"ͻLw|vEdތ9PsdHM|ދ 1򙢢hۏu"\jw69s0vX}a:~N/5ydӮKm]ѓZS܆}š?'Ob¨3@KveE`!`4W#=I8>!d?XUE"e/抂!F`Oh[H349X5X"PV&,1R&n}wu2-x#x{?XL'/́/`⯫,'I !5C5}g4Pj*.f-3Iv-bo+/&B6(lu I$98o³o~wܬ45GȝPj%ӳ8雁aCMrcH|QK77O[_7.N&<˦"UlB ZY00R)O az9}uKyU!>%Ѥmz}H |$Y7Ï"t j#@mCǖ Ii.yE5࠭ZZq&NÔ ~l~7{B GǬ&\<oE᯻P0òEpR9.h1^@GpbiyZA7&єO*ȊeFƜCs#ytж>d4JŞ_ 4lW/<1vEBk"EG@rv* $- "I0ˉƾ=%㩠[$u'oI'i꒳}Ѫ=KO~I7ˆg\߄ևB3z-FyYǪ̇F/դY?;aPk|2 I[Uƿn3ˇNDZ"1c 4PAtgIwF8ȼ ;.Dc!4TrXgP "fIؔ!=6=;\ٟ9H>+=C~%c]4觩`IYyyY~]3ݷ;!!wu0tv2k" B UZN0UՍs?4cq#OS0m\h ͍N`ˍ]{{fA,VLLJ(-ٸWԪre%T)E"pQ2T=7 6S4~R BwӑN"64+lvzn^\3(ߊʻ&3ܵ\6\?g8>q0e}4FT8Jh! \pJ:%>D-!CGp4e(Cpt8kՀI(8М|[cao P_-L}%R\Ͼ_7B=na1AgN҈[#^_5;CO{ SiD4G<e ?@! }J4*ڷ<γTG cD^ vTe 1K6ӗ•!TBs4F;: Ce0S/, -CKAgw#ߧԩN8Y[(!)GTayop)OؽgL&(N-Y$(@ 3?(7[irP)R=CS㦝{S )db$"pؗ=qkvWV8`=+@d'$ѻdڼ < G`|x h3j['$Gna)i, M^_Êu^GPH-f \$DLzEV3VDT~^`eb4{7+7 kJ ރIg2io.)i.9oIl7yL~wOaannfjS8ǰ:E? Rky ;= q/0OaiL T|f7$8Vaݕeȧ~S78y%ϲP'i)󿱃Nߧe¸:iw,U7b ud*R$"'+#'-{﨡EwC'P]S_='V>Ja(})$1Zq8f Wգ@#ږ}RS˙,Wgi>N Gᥣqzɕ8m]1u"7krWP:G@]#\(c7M6m_м6/5& d43#_2N&4e)}Dӿ1ه`@2dFHO@FadȤc26!gk7j 67mBF"sr#ٽHI•%gI}$!倘96k!  Qkojv@.^ K$S#DY^7dRw =\%ܷL B Lm$gqb?Dhͨos,$eTyJ > y>!;nGj2QQc:#7~OFܸa\3wM1k'nlyA<[xI#J|ـFCSb?30Lxҕ{$x<Ξx]aJWSFA&؊Jeߌ=d \%:+ܙ -<g(?hsJ0j(җW NݸH2 Qc"uш͖M{ GYʻz$ZeB:Ȑ׵[}+D}c*z܈-^n+aYϡ kjn1D<$>J:/ǐtc;d>$_ld;QN^+$=BtHRaO41!$gqa9|㶹eB,0Eu\+Khk~f3vʌ~~'-&g2`M$H&_VF?v κDUk7lAMh.*ٔV=xh,3gnң2L}NeŎ'II\(TcC8B)'\~Bcw猤IʍSN{iCu `ُۛ`kJ~98=\xq=pޜlAU n@=]jw$QN2Ĥ2j|R6YI  oRG\k}n¨2Lk%5::nFCKm<:D:z_%ZFD;8`rpcyEQzSJ& RG3yNۑ-HN`4~9/ICEs22鼴>OFƮs2۞}Y\TTd㺃cϱ۞pF ?KqH|m[qkREGXX2_E`# ZOG8m1H9/Ny!(r9ds_CǢ*vN‡hǿAj\QGmˑaAS0r8r6<3pD>.S@k&&U^_9˷`'Io/^>e/SojjۻTԢHK[ƾ$O G!qFJ+eHY2a BV P%7i'Sgauex"jgh|glױ'$dMUsIzjNfddI9j_$.H qha4ɄYAU j'Mux'WN)jg߂#4HAL|'9Vg\=u#8׀LceiNSK=)5^S8kj{b.wPO;ii[<5E2VnKquЫ;c ځK19{~!V:NqGk8gjQ]wRS?^-M04|hrIlވ *q9H MOSπ߃IGMz/VrWVx9 TPɠ t׊bnKVtU%rtѝG{f9vۧ)P] }OY!f%x=N>W?Z=ZP@DL%6'|&O,7ÆfGCKwZw_Upθv^ +;U?1vo9gNH񸟟1]/U]O=ڍxqFI-nmt! K䕻6r;Nj8){>f FPu[KFD/uEZIS! o៥2 Do#,?] hpz&*Kp6g7ӵ&8LY܏|?F4=?܆e53|qÖ &yc3=J/7,L>ʤ 8[_^~[TVCt^~mcuO!8۱߱k/R1<|x/~/dLcہw6~JMp^ÌCm8Z];iϿqB; J/o;G [ g~siԘtHj,~t4F@X qP&D?= IQËh'-6F>۶XZbKd )NTY]M]msZ);{r1#x$&P/z>|_&Q A.'ܮ>QB^c3VǸ:o+w u9FBmZz^/7d |L6M)͍f*⃭٘M̢?~$rZK'caOeK11rrO Zy[@{U} m3tO F{="5ÆP ng/]vtwA.VHн$ 9g s-:9 cOмnT/ň\Kꎱ)~>]o\9GÍ4ʆ$g&lLEߗ|dz*᳉P̦n-yQP.ES(זV)8(u3dUhJD"CGk!sKK*%mcڃ8Xi&s7b ӢN&+Ks |P{p15oCLd,~fB[IoS?MO?6-mM!e9*E9fH^‘T)%L0ږTR--Q̈́]]ZlߺXCZi_|5SjNzGeْ CYvڲ)lU^ L?4 *ANPɥdpc^H}$ЋؖIlVTlqʍ:`ϊ]V pOHmɯ'&8c/_˕ 3L_7Zi%_(iYh$lE/abK¯{_h*mN 5s`PNe~k ‚iz]Bè,.؈v 2ɆO#NWt,el_a6hL)FmV@Uy(d ^KKOTQ7|ӑ?;#V^IwK^#(I&雒ai?M4rsjNdxZ>nM(Z\tl;e_Yhv&(r'L[g |/Yum]Z`a IA9{gC\z}s|q˰udzm['*s!>zq;u۪F gUg߫ uSY\I{VWEӸ乗1<#b;ٟ@#t %Z^ҮV*#܃(6Л׃͔k0aD1{n}ƌ57*\lƦ] V Oo=^ ~GdЛV\>~*}D>!c=;q({'7Nώibsꍗޟ/c֦<w<ž[!.?|SuVoZ m^> ᘄ3ԂQcTΰEA@D_~nGi<|ɈHw?-8'~ [z'hxgʶId+yF:;xGɕ̶6욢8To} Zƺi}#$>/2#)1WYo?SMpwj_]4DПOydt~Hu-}$4ai#{dRL \'PͿ3KU*0 WKn9m\,~{I?k"Z Lx5;_UށPK_%57-Uǘ[v5˚vVn\RNMm.Y/^cFl!x&^gkQ|fÔVvΙ[aݿE r)?5[˷mZun>"5/)3W|؝k>^7?k$xgZٯȓY˿oL|gfる/Cz5ߜGS( pHS0RjsLKKQ`1'((Ob},`EL;)-5C?ڽ1q7짫1ܳ)=Z|O=rmPDSsC} dC'<{KK^{Y-j2.<|jF="~ٴnMɟg_ 5@ޅ5ocQ9>FT+kMӦ(8nƣPs8ݷJjn(n7y梧>7s;'ds^2 DSЌCx$ZVW_&(c£si{)n]#?}Y/$9IM{WLhSBMF>!OJ&ڜ(eS@cƢǼRoҒPɸPMwC!G\'UO~&aDD,潄Ãg`֯q$~; z.r*q m,!\/dr9K^#Sȳ1ԛqzokLWbJ6*/#7?]_!{:KŎgq0cXg-~͚yfYNM]j'{q*F@T0g'c5᭦`m?'Nў~))O-F]%|L] !ꦠBj>ű3,&ͦt%[Nco>E>V:G?x _yETM-t/ZR><bQC]kxTqPUE#FG.Ѽ3)˘x'{{wGg%Eav7l ]yWyۭ] Ɵ0ɘP8@`ib9*\;;9*?$[]zm~\wV.5L5Rh_4-۵\$)+M!ΜjEzEȴȇ\Z\{˹Xʲ!iy~1 /8Ep=fbR`؅4.hS1eozwuUvOȶ:NRLr36 XJQ *She 5SjIw%Ms!~}-x\Yn+Mn(ҳI[%8=b!6-wm]O&ǐ3gΌO݃s_5ZVj<(?a&faX`鷮CoGڽ]!#j1T("tX鴝?\9mҟ(7V8Nh$ZqA 3'= #+χ#L>sdfݙ!fGqZD0M}`'43cw$n)>6/s/>'m3! r|JEnVMR!9◣5$ AC/rȞ gę`5Q~U׵͔7\L6 ǹ'Qβzc](sUoy#m]grbg3bHoBդhnd,<@";xnC\oFF~#JdO=2I@9Nj&"uW~ycqzcr\wr{o"\cپ߉+#ct'+/#B}+uUV}X=$k4ϩ2^rcusC=݇Y$#<벟ȿ޿D:߮_!{,{ JJ_7V-7V؛eߋK|Z}\fq"؁o;E8$]dINNzV<(Hl ܑ G(DZ^Fw *}?G9ϸO!p}w"mpZ^3evN7VeIw[lMu-^nw#iN cRq^-|ʷWbɒܳ 7{?!zr/'Rlw|zq3܆QJ>u+IJ;/a{Zog0&yzⓍAӐ g1SƨNq<)0RArṜYZJo]Z4+~dD.% ysiW bf5[cLJ5# ˤ),ìy9,m Q{fO+:G7+ϋEJ^x47QKǏOHSrBO[=k7bO-bݿb<֞xy?_['Wfw?;AޏO\uOcKVmUR{{z{;M&x2h?DӇPBhE]{s"@V*&sh&مChFg1hZo  } `չ/;/@X(}`HX|ڿ`}bJ[*VX+Rm*V ؂ Z"Yonnrrܛ;ܙ9͙3S2w/6מ=U>V6=܎V\ 8.>a:޲[r]\=nm0F_+r"FxV\BǼ#9Mr<"4^f\J˕!Of-W9℧p.yNUڵucdl|6d|e aq`ڜWӚ%b[GIwN} uAuBsOGV3+9 (YA)PPCC3hptfE9n^>j9@M;ljTؼ:a+*$z?GJ>ZۅoP HKBXXx!q}nlX +xԳaH&7I̾gb Vn9EC 0+I~#;yfs+0וrKIKut{vB{_6/_.qCҊ~Kb]Vl]7*,~.kI 9K5Ř9aO\rdJr^fao^𓇡jnRdeo0Ox^\ҧ. [m,M'+^={]3.,'O)\ੋqר>~ܜ>,jHLix0;?z6d֭^uu IN'΢T*W[/+3DO):}\DOIȣ$g|ݲs)rLđQ8IQrV(5% `0]>đouF#[FL o(>'IIϯY5/^iӆkw^~5(47ҲϿ ᴫ0t.RuVwVvz4~̓xFg8WA1=y'{DWEpJ/PʽH5l>GiSQQ\qB2 nJS"NRa.\/<^KzJJ}Yh-㟶/*XO"IT9JQ#m8;QPE $R{/G ft/.q?Ϯ<+SҺqզߟ^M=$'Bo#+?Dq묊֬\lH7АH!$yGTo&INԺغyY FI!)ETZ?:*j)DH5VqYHɒyC^!EW898#-ieBޒRn^2RG($@{8#9c3&˞{ t93m[ =2 R#Z:O, 4:f54r] sʬٿ>${HeF ʟaҋ# 37 Ƥ?J֚BȈ|9A\\MHüfzNӇ$sƐ)JI`VOVdz z8I[t;*$c4LIĴxJ9XO1Ӥ2Mz>_iTF%]>y(]_lPe˜7n}?ip2N+T}(m]O]yyIK|#Ob냣#Ϩ"G&¹#.p"!5ƇCCF鳹r ֿNaMl g\Ӈ宁t H.yJjORx~[v㑔LC/Mz,gN:Όx "ϕ;$#Nqgq2Vf~klnGss.Ti*8P3#-l"eH}׸<:8Vi5cHi sJSE pk#;yȘ\Klup°cI+eꜧIk?k&iC iI̫ԿA: @^htW_}e4l^(>TګN"(C2q`% j4],b_>ޅƲ:)άFcϨ V[G}a z{|q3IВ1cё2 2MjՙEF/yU奸䱨ɢhd !MqؿeTшlF'MsQGfbP61фzw eH/: qImn%3mH5~ʰn{%jz:|*,oWU$)M)~ U|^)LB8ZI. Kɗkpwacb@;]|=m8zG0F:b%>8Γ;9e(B{(# 9REx`5U3j8gM;hW!l\;//  Ƕw\̄պh~׸>%7Mm/ٷ٭QgXQeJRJ^{I& hmձӿCxkOsmհ#!ի6mڄ["'zPSS Л{5PEP" GL$<'Pc>\YVKJ֓@O7+0Qm"_jB~G)eek$Y)ԐqdkS@%C]pd,딼d2nPޡs+w&=}[iB_݂ἦ/<h%pH o 0NZ}HPOSiܔw|eg"3s+(ѵ`I*R;eeD"B8HBj?c~D{<[' ՚:H]|Fb E:81ƞWW߁p2:n܀s'Wq7,KøcxQw#֓Dgt+vf` D}~4=n zyد'Ka( ufv x&>4ܯ_m7M>s83!TQzȹ񔪴޶E J'оDCe9"ܑ}L$2I'{%^:Qd:\7BNANJ?j.o>= `7柠dH c5kp&X昳3RH92RGԳaLEʘhG%ݏvV+WQzg@J^:Y^ن}|Qd.[7[x`N{ת2U=بv-zc͇I"Gx6I^ӿ{IF{X3gBe#f"Hs~!SlpF\.g8H^15G̅\ j;zbI?]4Vre-:$gd~u0^jd.}TV`Nk`-fr?$pl$XYcɿ-:Wsoiv8dĿ4M={`޽fo%NP;'bsΐPGsn67v3:G2l툪@H/W~J'6>}r|( f*:5,o.)j/dཟ>~BNl^ HtX"{h>?c$HD<;}bБ;?wc/>$۱NG?[!%CR avb4/HOu1N|1ʞ @]$D+Ǩ0F$8C W=w;ELP'P>z,X`.e6ys$M+j+R;ڭڅҁXFUDcݕ$#YGZz]mVؾH6'P=եISCbUt>h U''E 횩Z+1F쌱?ŐOgG\{ӸU;ۛsx*LuKHʯ⭿oʦyInȕ_z /)}Yzsk[į|\ Iw|st=w@&$#HֻI FDDC:T#ễDt7$"r>՜rGj-R: g?'X{B>tG;pE'a86[ c>_^=NfFH+(&Bʢq%gLKIgOǃ;Kr+3W4UQQC,9s i$+"AmձӿxkOQ!~ u]G("p&1jIJ3%^)'"Z8%PL;h6*I%xΒS03džZ$5yrLzN00x٘r (ڃ[OwH+R|FVB=ieS77G3Z@HfZ۟HY܅ h4J+Kƻ&M#ɐCʾr ~E-Fh6NSg٤K7⥹B| \\@IDAT!(k9CJٷT~ih=B3 *mjgl= 8A(sOj4NP%94}K䫳5&(Uqj|Nx)K'fHD񼦂TvS*5TXoƥt>"s>?} RC\C9&ssLc` '{Uaܰ Y&-hJ 9$_ o uࣽNNj?%d}E S ~Ho+o~1e >) ؽ LZ8^k2R2;о.}:<=y^vpb{k~6= S4f&uw~]FLg~ER x嗓g?C}N7|/f^{h~uRLI92K1p0jힰ։ d\KMd v$2vLx,5:%iD޷a|= v~]("4@y✄%VIX[O#)ޒM@'r }ֿ&勷8"\e9(eYO5['ŭuRGk}Jm9s_DGI<v \9ߎFonKbm }<jִڟ4J>&EOz=}n RV~Z)^yaI;ה>sG_,a QD!*U4 k^%3LScgb1?#w Ƒpi± k.1/abor#͞SMw;IOԇkT'1I$ m.ޱa|_6(=D;$x/E(5^2yV%&QdX>oL!Np+{|'3 D):r4mW{q|(pq5}ȠS`xxUcv@M|}a͕VW!q[}"D[ƾ|_IdܫCTTV$)'bK ~ӊe-eN kϼZў=?aL]hE@81i f"!]@~wF:jӨ^A~Θx 6҇r%b7U=T2JbgIGT^J^Rvp]t3O8}2z^2nTt xQ .*GsD";AOWE6GV_\w {%{MۉhX>.dS}K%*+kP[[TU{ ),͕YFXtJ\I#i%X?."w્&݌kQ7Iǧ_!mL.wn >Z48ZRBéaɧaŁh4=gj9.4VY$?l]\zZP66/6i\AX?!Z¯Һ!Uᅣ 8Qz/j;E?ၧv}Cr?:NklXR=[yY8H^GʩdL)հapwɁWpi|Lpv2,w?zvJ/Lr%fN "Xk%+1j?/y/hHp 0?aSbݧ쉀PpM?(VIH x& "+ԋ_[tiI4pV'>kwk_ic% e\R$KlךGsiҚ_6W> jxɁ=FڟJ卶ʪVF\EӒQѻ֏b_Ts+#ͪ6WM aNmϼھgRO`Mw钥K <7p 6]P#s=g yȈpM'ro|P7.ǮAT$dۑkt|A&{/4j׽s"ޝO%K$AF$s?8O-'d`iY5n\8Rr pp*4J<^P^ 'zHLBo5-'I# ڵQ?,,_$'I"dVƖ]TC!O]"=x&xuB@)VJK)!D)9TiDDPU3-}"'; 5GZRTR8ݘ슔e?n*HϑK1[ԬqƏaز&lOTe3RvR8 e/T U֘wu>ŧXqN_/O*9F;'mv8kK󗠜}1+3*B|ue>IucN<@[|tNG'bw9|w{WYbG VcTZETn("p `euX>)СWs98Lf`ESñd+}9R F/wvIN[n3 !;{TG#+ߴC~JO$;ƣ̊'gSWM>"wʧn6y48S? \3s/俹1lyA mI3s:LWO{kQB/)ORڵDG O>HS᪃S^I%S7 55|]kt\|.}n})(,nz3-}9 @wv- '3m'Sh`ռm3^+#.$c%VL];E)?+>D 7 z벩ċtNrS7Atˋ7(@QR&; DS|eLRKTZ/)Aߕc,r|OlNWX%؞#b>#F:9u5՜ܩj0eAjGʁ]uyX95J WRqŗ6:fZtz_'IWw+A U y0yW$LNeoTDL~s,9\[5#\KTE@cB-Hax~ر7)"GEbW0(-*2p}یKtG.OMNE-)ӵylĉT:4< sƲ-k)kQ{]4uBw<w.3cgspO.L;Qt!3G=XG8!ϴ!1-}>-k!0T .θ$)^y/S\)>]ڲow<:4$f瓨ϻXpާ?Bue\ONJ@^$Rt^$tw\N?99MdIqzj:\Lټ_@72*/sIH85^xE_F4@^f/G5#YifܒaTSdK8uYmMa"% f([ !;{iU0/wc㷢:1:M%%MMƫN; pJSJu=(ٟUhP{OCb2qkP[~-d@DM_Odg/ݥ ;p[m~NE>O Mq4#`$/w+krJ7y\Ep{N!ꓩf=S>АZdoUIҿtPwROuRCt<+ͤ~TwB! ~N8ՙ(J~H]~TUIU>Ŀ8imr*@(-ROP h)y!i 49> ~( q(w"ŝ_ߑ)=ł#T}3[='rzYU%u΍S:oH.tŭQzBu@ċCD폺# 俑 1kR*"d&ҖMPw" cR!%gRX{sџ6JN{`^hgh+)"?|@QB;' N-s>4(&#9M& u̯Fc!qˑ2Rf~rj<%j,KҜx(p*oz("$p$dx 65pD{"55"("pPp#)"p <8#ucg+^Qcq\N$MWK00#rj7ГHPE@PE@PE@8~PE@PbBHͧrNvBfU<<?0`4f@yhg;@FFds?"("("("pl"yݴ֊"j%!񃝨q߯O߉kc|x.N*seuu("("("(l_?"(F@$E?D׽#6cVl*@5 $6}󠷗TCE@PE@PE@Pc%î[P[Ty!<:HG||˙0qΏ-$o D?VΟ 0P'@t("("("% KlnS,ipk渷-ä1t*>ƤDJ}7;GGGG%DՏezDߏ^??g⋟IOj~7긕!Fa("("("(GOKvժUό(Q|7j_ME<(@]x50lAGJ*ar,B^~& ;`yQ>%(UsHscѿE듐Txuضlλv2?:^(x/zպܛ-nƝ=1K,qomü aCЂWlZ *gǽ8uuWƋ\< ѾXKB3z.2D}Zj ?'vXb1LuHJNͷ\|V"6˞o\:9Exbe-X?y'ųQK͌\UE#p]>lǯE@hp۠Mڐb念_VF?ƥ4nc6beCd窅vSK0X~| nxⓧFlg$\:N  jm0j܆ vOl.E491PEvWƼP:c jG^i{7"Kaʳk1~ք]-%/7t-Hs?'p銀"("("(Za>Zm޼?Y [tO5Q_]RWk"]HNLBrR!듓y<&))\F-TLk#Y!aI3y_\`=/u~=*F_1:tʂx.M?ɢGѿ4l Q/mȋHKI/~TB4x뷏~g䦍{6=FqHaVD_w܏[:/HX- !G 5[]xb)xu tÈ5D ^WaxM!8f.۸N("("("("(B \ UD"e }ނUf: w=\>w97}@?*yHÕHu?hX]]1[]E)q,/ b#Y~1pz-F[ƍPwgx .X8}| ËSIg5roTF>~)Q;͘{użInw1u% 7h)ߝꖹض|.a~V}axHo'xtL1 1&}uIuj`*Aڻv|7~,v&!xY _ wXw垅^}"bxG>y)]VqʇKO/~_R~bv=xsHI;8l,68o R}-_6䂳 +j1`_9L*l_ww-^]ӣXa6/sώҔע\w"("("("("dm"Y#|c߿aѨƘD]R>N~ Rѵk'K?Ǽ)&gaTp`tY#}42yb->  v|x 8Vظ=0~hB펅V!gF-[G?OC.ңwh=;RimQWX@dۺGNބN)SJ+:6Nl^g)%_r5'!fW(y>7WP=n5|v)fUﳯ2q),עLIm]cϡ("("("("xVVV#\x<(jjJ⿵(!/\I)LO$U%pQ_$u4 leUELW[Csk&*:heN#NeKƛKp[ ̢Y^{{bh']q)i5V꧜ɖj9Zlб\:e]~FX3$!rmE~7l4qJAA7䥮ŴG9Q.@7W)"("("("(aF ykCqGTjD7RQW_m%j੭%a4 Q*M?,[=%kK=R392JF_w[iƹxpSڕ"JxZ>-R1L;J5?_{0/1Z~aD(\ܔ~G.Z>u?5`≏OP>) =o;lbfOm2{%Aa2cȺɣV\˞_>A-~l#^j<{9 Bb"("("("(" ѣQ듓(RIqDZj<.蛄 $iY8_OAZz {!DUU5񧨬}QZ&CAboqky\:~I}hʗQكyW2Ǎ*Ċ5wMʷ\5Jz K\ce 0Iv؆Vr_c0-eX"lE_N$ YS.5ݝ$VL;'bl`$,x}Dy[.ٍ/Pea+q_QiL/?$_kץoz]`4 s_!_ڄJXj3u"("("("("p8>5/7[HK~\\ })YHHD~ZRorzVG^ԺN:yjQ$B23'E)>?獶O2 }<މ7˿ۯ#΋tfa vs1i +읗Xr)+quae2~U,{ҐѫK] 4>~E';4{7nĭފ-qy$ o7.8+漱> ͻ{q hދs'Znh@HFbu6朦xqf^/wּxz^'D}$[Vk,߼M;W0{>ʞ~>x-F\i:_ QE@PE@PE@PE@PEਕ> @['Lqb73;"jBϋػo~þd,ϦD$'e]x_6(S̙*QS[^ˑxrrRF:\`u~7Kqd*o> "Yǝ.#Tr٭xm6l;۞pL+I>/.汭#ǤS/8KKEE%E?ܱ " z Dh-gMrcDQPhccoE1[[/[)q8J࢞h-=܆1,]/5+!k&)q13-{E@PE@PE@PE@PE@8z*zFa$HDT%+G|~ދ];`wbR]eؽc xv0 f}e5ÕLd>HLli%8+H_ Cx=[:(јh-j,NIşkD_vF,d0$(߯[ ɩDZqo1|qA^֚Gˆ<־2N;%' FWVmAٿ?U Í U'f{-?I{׿B;{BI5#HuMN .#kRw/p0Y[ׂstZӰt")kxl\7ll. ^GOVH8fdE,]=E@PE@PE@PE@PE}_s,]bo[a>6Qx~>_owQZ<%]HI4 )F?5u-"V̬T|EҵF|g8UdpEEYQbwm,oLߨ󙽶wˤʘ TTQÄ ]Q .̚d"%kNF+%$I rJ$i'sǣX -ʗO"5ֺ2сuiFy64k\QV&]7*GE=&[V!5DJ.rYG6'=2ґ:?<+"("("("D@xh[:Ҏ)T2"EH;I],.ҽ"("("("("Ŀ ||R:ҋ@=%}4ƛWQ߃,ߏ}U8J's€,!s . ;'ha^tJ; .HEGqN0@D(5N&%!n6NPE@PE@PE@P7Nh"xJ'duF" +XNC;RגCCO3Y"џyFMM.((3jj_RðeKdcuoݿE;[pʠΈ'FU(mF@$?|%30E@x[("("("(@?QojϽBn$7+Kq梴/TWq Tӻw%pΣjuVoCtȧjD#E8jz`1СHX-&wa6YhrTPEp sGr]\n0L}ed@7?7TWVص HI=#-H?}u)n0EyQ ;ɳ LJwlǾJr!#+ چg3V;`CaAn`[][=;4UPA?2V"("("("!z("p! |8ߞ^u ^xM^}9N'0a4;}k?q=08T`]slv !aIrJn< )Pm%g=xK. />pG Tc5~}]֊$y v'& 6ƶr|](yJc[nKpz("("("(@(&=SE@8HʶkXmi'Y %U{/?wA? 0Gɽ3Vs%Z']Tqm_ߛkGf98HЯ囸gB lY-ptM,g&nl}chGPE@PE@PE@P#cLGPE(@@zl`ݯ?D'^3[{oN突ҵd=)X}j"t=L<;:1ﶡ&V`wOp.?_@_;N#3hz("("("(@tրfp_])jjq{LOCr|2 ;5)"?NaQ7\; O—.Bx03l-1{@XV{ج?z;c'8dfgр/RB?f<.X Hiz("("("(@[P:AGIO}dx1e27˕$ N~`f h0 hBM4闘Uh6SltMmu^֦b/&5ȚHsmhQI*EPF`a}}y{ ;@IDAT EXhd!bB$@$@_@ٻo ~-}~elY(3tp=*6سPR;uc6Zs ;\         5%+O>AoڅzԹt9jҽ"\.BM?Vw%܅sFGe "4B͋`  iyi--*xogMx?g H 'NL"       @¿@u]hp5Ո*>UmUwťrB0c݈JP^hw4bCb*HH t4GWiG Un{h5"P#! Ⱨpu3?t*{˷ji@0P0HHHHHHHz@ R^oO[ qqc *$ C,W` ĄD#\\]~_V ӯN[;`~Jp|{9p$w 4ܘC6 ňZo FSm'w].g6a{Fwk,ߏ۱h$'0boݾS +dqC;GSo3C D63:hW?֕cCA}+~zlE((n|'h v0ˆYug!'oRYޤע z{h1F_>鄽9qV 2N yEzXdf?CG~_Ԋ3SGOÊ$O·>wi^ ^'w1D[71oJ,?_þʌ k,򧶵55!fDFj ՄYPJSGv-0B qݬY[s8wubڇ ghn| 1TnXg,C֨)->񶻱BO+b$3fGՎsb׋$䠅MȜ/`߯Xx /`YJkCfÆWV龞7?='),B~&HHHHHHHH:5zN*v5^߇*gr@oÑhNI#o?(Sni9O5?͏%ۉV3sw<bK<[ҋ ハc`m$+cC sft&ZZaXXÃt+K1u.{Upui ~0v(;wo.ruLHuhB,A ~is%W; 6D_vaCyhlhrRi+?=["N        Ҩ K ◿.Ia30<XĄ{Bm$ȓҏBB4WA9 sVrn&hf+FNUWcBO:X75sV(0#Q+BA8؊_dO)Յ<]ԔdU1vڊ20QHH丯 4;PQ9*dQDXەHKkcm)rB,~x'b|)sY.C˼wz¨*O FNjM@vz>_>b$Z:8QeGUzi5"Q7 L< ʴ_̰(\b݊'L&@$@$@$@$@$@$@$@%0 ]OٶoG]9dNSV[nksN0?uT<>qp2WO)܎=:![Pw3cARj:2$/33R!2d^(Fx 1 1ff|豻>g~xa232o{F,t; %qH7#mㅑQg0Нt╻[7z>_;vÂmÌQHYOwۻw">y1"LNܺ@$;eKq7˴=FbkZd-       \8ݭ⒧EzC\АPXMb9-W{}Xn\9\K@_Չ{qpw^njby~[{Fوz7mXDWڰticuTg6]8;9FE͇=+ *?3Vt dxڒ`߿|"A{:fe7¹Ֆ#^Ƹ(#[Xkx0#a1@.|xa&/0 ֳ}`Ql,.X5ϰ3b>@ DꦍK[-V$       KA`@ JķſuV;W7!sQPrPZS-pgv<[g?_Ζㆿjv)Գf߂abU\SteQ%~[[[}h-=9y=۱}TnG~agm&9YJZ`ǜ>V`,Bl^xִ{2k !S/N}74KeDmu) e־XK ߂ƶFTVo;*+J-Rҫ[;ٜ#:ڷ`׮]Ab!]ϙDn6VbR2CXqXf"]`C)o:NJ9#4ߌSxEZm(W~;Zזw1/| _ &d@NN:ϕ_[skg&rp2!qi/Ƚ'vdIxF)L^E7cqA311'glUå9YW7mדmK wkC3ޞy'L@}CYcHHHHHHHHCM_555Gll,Ԃ@]---߯} `l 9QUڔIqnF+CW aroh$ AI:@kFEsY )xixnRG:VɈ}r}Du6,$xbwհGrOU,HJ~GywenYdbCbF vk1#xp.F1Ƹ|x Kd<2F/gKs:]Gjܖ}veblBܛ'r0C)Xpls $p (k Ne$@$@$@$@$@$@$@:桴^ XS,bCcun w֣ խYPWֈmgqyZOYWVAv(wB g‰◑ke,Gjjz;(x,~°3&=G( ,+,EVcAVLͯk<:yV=P zDx;OIxj?\(>ھ,HwoQEkQ$)Ŋ\kPZZw6׌QZ»@=k i.;EډپW1hBBi`#       N?k!'+O"ײgΜU~n'g?ɖxԋm6BC 1ĘcpVLV\y5BݡV?/,++%+9sK rr5U E*)~V=kWaGm<"Ɉ P}b~uIH[\^ (kWkz wDp?"q̹lGĤ7ʳQW+g_yKAE\.L'Rgh~Z 1W`v>T OXұZ(g#D_Rrl((oOnBaGm8Y* . \:|9;     të|I."_!.D,bBa 9Xl> 4MuV]:5"͎(rI^#WGR "H\,˧! P:կ/_E%o袿u*_p'aiv _ XdHHHHHHPH`jzg?mjCJ5W]!~EЊwEc}Yϯ7Ҁ1h]!Vސr.Y9ExU=0H5dJ~d`C\Ɉg~Ƶb]2.{m_ q$@$@$@$@$@$p迓f466jf\3"r9P*?TU  Gxx80=%ˢ[]0)nCł_ALDMD}U-!B$_m@ihjېCMû?ՉSEcP:}H:MS:?R%H/e& M;a%^t&;w z#G Ca:fe&!P }W]̎/2߇i7CtɰVm3d+=w o^vN)ҞyfL[0BoykK^@|)0G a M-(,w(5a_HVݢ,G$@$@$@$@$@$ʤ;jYʢٳ12t[hH|P KO֮ZjmQ|1/j26oRQmpZDE#[I#nԿQY«*|FC\X-{!–6@h=ZNsVM '"ۖNÃE/('OX2y ,Wcw2D#i'=٘͑ZjϊBvلIiz0-A(w>s+*U7Fy"FZ8tZGۈg"E5ː?~U fᗳ¬;z[OY6v &TK Nܶ*s XaW=})'c@^{$H&=XHHHHHHK`wz"D&G* r؅m u 8QZ}&1Z$fJot-&Bb64mQҽڲh .4ȯ00 aVBjr}Q`GH ⵌ9S~".~`Nlhbo|9c=N}Mwgq_7k#MiBdB*R}V~=tw𭗵@&f0_ N{dU3 E2'klz ҥ6h0?kzdzz[8ڂ [W^FO]1~Q! lCHn7O%IzH 665XHHHHHH@ZUI~OxKq%=7VgԥBӅO46GD_?o.DEhӭn,xU]~HIӭA5hjj5V}ϽL&u} etw?͏7٬۽yDb FjVW M⫭e5 l_Uej(. yy2R,R:+r}7;  j']_h_<]#*zPvջ|6RMB$@$@$@$@$@$@$@1?2J Ri95;uҭTр݊| 1vX|B\Q+V2Y,jk 5D}I HֺB*i? KMꢮJR?\qsH'ߺ9Wصv&/Er`mp8!Q?[n0N8>AcFf{y'       K%>UW_5`p◖_{uBCu-vD}viW->&cz q ^[qL rŕr0I̠xdLyVPE B#:o䵺 \HPFɸ D|~,].bx`c3P[YgXu@o\1a!h3cV]% -.ָ$&䯸iCk !]߰~ٞS\ʑf%ʮl :^7F\9|wp~;fd=rѿy!?O]#KH]k8 s <}wu&+W_-V77\ɧrPhYo Io)Ͻi*F`s); $Jou""DsgO}g{Uϥ&ž| އA6#!d¢ctPqƎV|i4*2j?oՏܼQqď%|Sb=Z/KW~Dכ˼G] ~sOˑ*,ÝX{$n%@0{"Ki,yf!h|7 vlLM uxuU+>lXT̅F塷< *wG˱n<7%p{u>=sq|FHHHHHHHHr#t3).Q?D\[m4b.Wi*O_Y>ӈk{&"̰EaW1lVɉ}/~s&:ComV*a28N8ط/9 P.Ja.V%h՞֋_{ev8ڲxQ uݭ/a*d7us=]8o:Qw>}2W`έw񉻂 D{6݁5ƋY8Z rQ&&g;w.R7N0-Z=er:ЀHHHHHHH.n&]ɈfvIeL| gr_Y諫 gkʼn*PS{c! HoDL "~TN%Z` -/ !CaS"cAE{G:/s"/:ZFJPRzu2GDbg E @(7<-Z^6rGz(tȖ^Ӛü;=ul9f՚\Qket cl4*F$@$@$@$@$@$@$@$- xmX,yqŷgĽ7Ёs甘3 ,Qզ$mc =_xgW-#͡r>Cc04>qQbo(_z AewRX,ɓBY!gJhoxؑnIncDzbv`򴬰[P_5\1랑n:x܃Zȯ/>$l3Jf`֒ g"ٳzƄl3L[U,=l̂ak&ԥع&( g-]7oxjF6{hK9 e=]%;!"ꫫ&jCQxxP_kՏ 0]d#֏jSyÔ%К_(?^V*`Fčngm-m\|? _?"-&b]xYi)'DY5N U!_ƻ:0Wm#c ⩷7~B&VÒ$kv kY3l[]KFZ$@$@$@$@$@$p&#>D{fD ;J?uN15tg3|<󇆚 {-Z Oq6TjH < I+gjlP m{`70b4VK\ #JTz[5qvg~8PQ9*tXەHKzϐVFU%*)nźӿU.]SmFEzZrq(ñ:@,M7njSTdדUXO$@$@$@$@$@$0 YpA#}R(=-X P%߽jmM}iO~?!M&#$Sl r9|x^ixc/[cl>Kws'"~1=sG7a=Xa^Oay KB!c1BɈ_Q\o;0oZ J=%{ ڴ#;vㅥ 0kmOrsjes9p ÌzL_-"?tw]-Ktcn>+`Z( ^0D9k_Ǔw].~~/X)]z7Lx5PM=4j"KA >{3ɮY6-G:Cqy[ 6q@$@$X8 I*}Gm ϜձJ)\Q26cp/LM *e`x`}`L4Ǫ))Nb]3u.,&问WāiGRT+Wϖ]OEE2 r^_IHHHHH``t-yr<>A;_X-6EG<l''W棛c%Oeݏp)q㔉Ƌ`QB]A~pt4 aĜ NY\?#.d^L8y^WAGZ}k Y)q]+OoxvMTLJcL'pn5$E$@$@v`}>u[6aW`,?;ŚV(ݺ,PE_o-#?;MDZgBܑskVe/CiUlߎU(\l4XdRmW^Un#XV6PN$@$@$@$@$@$#0Lĉ嚂)v/ƍ#grn0F{,'{+cҿןvf=~Ũbwg/, ӵBeo]f9X")gߏzM 78aN5\lZ 燍l5/Q`䗡$u9e 7/> ᷼#晝.A |XO>gkQ(coDrw޿e-K0:H5'b5]Ij,eނz5x>W>4ٴ奩X^j @?O!]@dt6w}g$Vdew{~Ԓ{sNC{ OI':=S$8R\մqy}~8\$#bf?^kfED:k^C eu_ rfvN?3'^[햧Us# jQ[fHHHHHH"c߳> .~Q1 y\9䳓>+{O͓#8QU!>bdft#SLcڗɱ @p W 72V=IZZ96~|}[4> x|yJCmy)^SآHk8;"OIQhۚܮZz:ܜ<s$=_e0&zS`l(2 u_SOjGS Zچ j,* CQ|Mc_wa'9(8 "< wB5_vVY >~fq? acLHH]婆cIH0{#\~g9혃'.=:Lk/߇/4?eE87ܸ $$TWYR! #i)ƶajoY@EB$@$@$@$@$@-cf84Nv|?`Fo6oօ}vW1Wxx~-'O|C@ :xʂ1GëKgRmQŲX+F1zĜ_>aO~ُkuq`_|ڿ.BϠ3VH$huubB ].7N5Ug_Ւ_MȥuZU/wr݁e\r՝m>_g;$@$0 Xq9!WBѢuSV C?Ȝvdh; vیQw`ܹFo0c /K 6R (RɪA{JnmĨ"gGv>l[;s{K `F\(]qbb_KhaHLA1xd |_w<`i['}l>O7!U¯3%;Gxa+Ejo_)9L4^)?} :5ʋ ^gɆLׯU (&\,"m DPU0g#K!!fR$ DI/o gVNrRf5uvW}0 @BprH/xoXkm܉Q$r2C7(\Y{@6hVճ [sqSUo7 ZTٹ 铗jgM0 dcŊ1XHd`       e;鲞eTNx/}: ,m}Flcvcxiτ}k3+@}}hآ >˫ݕ;ףY-4<چp_b=2?̯_,t<о7 7"e|g[qɉ366i:׉Of\muVФV(imn4;]r!hJzk3bO{ >2 "2u)v :is$UrEorf@0%?@#zK=d2(͛"]o p>7m4/ƚyENNrdU{vd      @ T aMf}r¸.̈.bz9D6s,0K])_WWP߿p?Ϟ "C ݫp1J";[`3L:nâ,aP. ҬCnol*""0nqkwV^Վ7˗FG gH).D]GN}`AHc&äRnL͉cd<|-N_ȿCj%jkUEq[+x+xb&\N{"VfSlGFHHHHHHPbkxX8N>(0ulP=A\"9r6n܈b2\x5a7NIiu}%8wacΏv@.#`N</ s`e3(CaPD؟]3w.U8G~%y}FQWPd3uAx(     8ت~8hG@}g;0]<WMp5k+wj>'&7,5_,5}%K$o1,ՇKWrYBM-Nt8#2C_UW',/mlD^?ۗr˱Ⱦ?36f/CEveul bq\.C6"L]#0rld@;`a1qjyp|KIHHHHH.hTDYY]^ρC@}0tЁ30>i?3gwvW !p! grV^ :„p{H !p"rY,*.~d! TR jq@`ut t8ǃ7t_pޯ#< l9S˾?8kݗnj&w>n,cFQ=HlϱEXOvct6 @')^bcp1-;' 곦>s곧> ';_r6H!6 ZGpjXERFbTZ"|^5gB$@$@$@$@I4hqvСC8y$YC Cp8CA|-555>{3}FWSRX>|'{($čSeàX4xo. mmnihDHYp0edE #)Il.jD`D!T$F騭EtlT[vaI,;q #*!)ɽw3a/ե(X+DOHv9S.;/ 95>!i-{[/Rh"e AAyJXb1tX S;pD1zTUiL*$vxgY8QQvddQl@^wuX>OCLS; "`Fb      L@&V'܌6Wx!MY2@o ֪M%<\[PRgY^vK~)?۷oׄVP8oBJ w=TnsPU{4ͭm9sEfTq .hi AsރW>K :42D-+㓰T sڕw lQ.3֠|ͥMx{3PKllܿ3ꭷkNJA?2G‚(*]av" ?kiq}q)Ōv4m#Ŝx-q~ص_1yk/'wE!.rn[[oe7q`X-n/݀Lː/wߦ`Cwk1ux-CkVB;۸+g0$@$@$@$@$@$@$@k%*QQQhii.%{.b"PRKX,C}{N_ i:o 7pm/q%+yM"j"5 hῡHq3$y Uu}Q_58cqvrrrpJ-Z=IдiX'59X@$寣li!l5ًDg6׸2)Hk2v GU ZR0:f6 qcU[?%Yņ޳0w,;dK">l'^p[Zp)j^ycڎP0 }f{[OPgWϘ-ZcQmr 3y}3Z}F2gZؔE,o8+ VcyEl\\㒵%9C{wsǯ$sHjėm-⩣5Zy{77aw1&HU&y%;k{lHHHHHHP,E Ǘ-W%YUt)Q޿~k#dA$LDL}Yd_ w^kNlh.k#뱮w `Tՙ7df$3a ڀA*cJUXւƵP-*P/`Kd,o kUAZkt*`[ ]B-Dɐd&>LHBB;s} Z]r8vٲ8pK#ǣ /:?o|BFˍOϮhўFVzg(]86P)M?am.. pjVo5\1ouzin!-qQX1ͨxe<ı#_{yiG˛q_R:II?z3$h!~#X-{a5+WZ !ͥpG=X(0 'G (@ P(@ P`8t6}H\zhƌ7'vy^jы.ڢK|DKGox=oAA$LY&=!){g00v`J]/\'нHܒW }O䋯?cFػw^|JkQ跢3re(O;Ek֗F:CRi-+mGuQ ?GwFX/[ [{yE:? _;DqL/EE8kw[?aeSlSs 8]l(@ P(@ KMva} t%0z^z):8SۯeQ?d%/$vmWJbI.Yqk(g*wtoHҘJ,Wt?2=~9&[L\[!ת^j$W'"U_&>l#x+<̈́U8.73&%|{Ng*ʤ )%ؾ;[τϬ̆K&HOY[;twUQOFZ|8~6>=;(@ P(@TX(@#0$#0v|I?B˸|-)̫ZnU"9CoC?ޠ1tCA۾j]hw^&-7F]\k I0<ئ[KT^t?SfbO8͏sMD2ڽa~JJK1&s..ErjQ֧k+BPv:̜}t!f#ki wšvqG97zqh>~d]5'm@ 6/CQ(@ PPMB dA{*ϴi/|:` 3 zU_v&n: PB7gAi&8Z!3:qk_{"T&}H&u%57aشBroñypp޿mţ΅#q0=T/jͽϩ98\D|tZub#_/GhΕmC_t{o%&5-(ќ>7rdhe>Ho^yфP}IT$MьzBnwϊSQ&}8 O(@ P(@ P xX(@#Cjy/>/Wjc& | u?NAc&UWyVV!wh"{tؠԬI.SouUy{PU7 h"w|隸?|'Amk /…1{CG߱oui8"j`pI'm;"髩3BZ0&-5[aZi]ҏT㮼&_ ;nݫk!m_>&v)p^tkrp(@ P0P#=y~#<*ŀD'ܳlW3d4(Q}%6Y EF#)j˸(*?Ŕ~S8{A8~<|6z\;|.Լf,$/X/WWc:I.['(~cwϊ'ŋ޴:Tx yuǴy(jye/Pobp8u.nW7 {.w&(PL6oB9ThD-aYFW.7mdNdA5޼}6N)5"/R傉>viC?wI>INw@4yTQˌ3n2P(@ P({5F'OlI vNBUZ/~:ujG'^AP6$OVԺ*jZT _}wd2TWk 2pHvdiȵ[a T)qTwq{kj;T0j5$knw_ju͙nR@IJ&\\vTa,.c*/Z2U+uLG[;;auWI3 vݔ^KҕV7عafg`$7[VV?R0!|rCE(PˋӈFpmxq<&ҺE3D $N)FOCP`Կx'u2<(@ P(@ P@`PK>_җ,}W̴fWm]~dӴŒn5$Ȧ![^fcln2?4_o*Gc`oBJ16qGx2Wo|)@H ]J`/QZ{qM~S\/[UTעvStxOZZB(iROvX|GwɌNT]2wqr.zyn9:Ypb\dð8싔nt[ly7&=7tzZ?YRMf:+(@ P(@ A~?s8LO맢$os5A%qy 侑*04m0?wK "Y djoL<NX#~ ےw[8dTZmWt7b߱[L;WV P(@ P(@ PV=ȿu_{Z&M'UP  )v1l飻R66|o #Z^*(@ P(@ P(0|U_]U,uC!>B5)0zhKq9m5)@ P(@ P(@ aeWD0g ~l;eN^c.ۮzq;V޶qX(@ P(@ PVK P(@ P(@ P*|6(@ P(@ P(0O(@ P(@ P((S(@ P(@ PCS(@ P(@ P侉(p!i'`0vn(@ P(@ PEBkp`<(@ 14 bO(@ P(@n n tZQσS*C3S(@ P(Q@:b4;"["O`HOO2?>(@ P(@ P"Uc'(pL&ԢF(@ P(@ u=Ρ=pr_ pS0 w!͐[z4T_UlCvhhižch9[nJZBs\h,.fff-'^/Tݕ=P(@ P(00z_U#U7M*iK37X!:Ƞ)*/EH֐ |cwwupmkp~vqz#WyS% (@ P(@ P j P7֚a\ѰgWj~f]V32Ol># Ǒr"(LhӵT?}޿V25/}\V 5ؾ(!]ޞ})w4bSWvvX)ᓁFܜa'(0ơܰy(@ P(@ \0W>Jj@V#3si>/|~$o>#d=#_|bׁP]N w mtV`d=?{n.r7b+S(@ P(@ P%㚻Y/Usm?iʒqH7P(@ P(@ P@Ooc|+ft72@H=mQdneǷ9|n4Jzu7яNU 'Um\m@LJˍON5哷V<hyL P(@ P(@ PD7^}.כHsNʂ+` j 'Z(3?¢8Wb`z^k݄ܩ+dr h޷6^hzY71W{\_}R=i P(@ P(@ P7 ֟,= @/ | j d}pHпNk+1^Z~>taҟ(@ P(@ P(@ P`n׷!iO|^ Y2 'qȹ/f?[oQjqjOa/b\/O2[os,SQnf4lo(Sy P(@ P(@ PH%*d%_1ǎ4AAAő?*͏l1; FIEqS7[)y_Sn)߀;x*aE@qVM P(@ P(@ P`@As1-/l,1$aR(@ P(@ P:N'Pj.`F !Qt=Y=mOo۳(@ P(@ P(@ Zaojs/iQpd~ AAŞX[^Zp]ں;{(@ P(@ P.daW#vmwz! ` 9j6u?2LNEs>47y-V O[[ّ3f7 cdJ P(@ P(@ PV9=wD?7G<ȧ헀SڢUb%ڢV!whL"?xك:q+*S=Ğ(@ P(@ P(p*cQ~]{hO'vkXLH72`4fDF Q9@ӎ`{; &/K,&8|B~SW}8Yܽ2d>k W`ImɸϣQυ۷`Ymކ}b9Û;EP(@ P(@ P@Uߚ/\ˆL`dVx}OՁƖfmk.-µSa:z10c -{{t{x!ȾeDخƪ5Юp  ; ֯Iܛ&'FZsN%61yNYmq6|wf^nh%*H${j'kc U+`݊ٛ؄)@ P(@ P(@ P`U_Z?KF󐟓l"S4ĿM?+ %[Er JeHKq][  7_- ɋsIvcjzbM;QQ?/Y;aڹqZfۘPqMlc*DŁmXRy!(@ P(@ PΣᓓH:uyu۫ŋ4e"3g?ӊ/>`]GP$9̈́lHȂ-=SY.5(#3MpdiΞLFd\I]%ld]v|^ǎD@9M.-vZ'*T̑2AA^Ҡ~.dOLˀO.P` lٲE;ݘLө'6i|O P(@ P(=azZ?Yt#nmJ"/> gK }r$شWIcY\h 2t^۳Pʔ-S:ﴑMy~{*(@ P(@ PO`Xu bT yW^kL@7LZL Qp 2AXeD?ׯMk}*OEکj_ P(@ P(@ P 먴{j? (@ P(@ P(@ P`yvO(@ P(@ P(@0-֥(@ P(@ P(@ rӣ(@ P(@ P(@ D`X R!ӥ')Fl& P(@ P(@Xc5N PU+(^xsX|n/)Xέډ{(@ P(@ PL3?~^<(@%y;?C{kŏX{U(@ P(@ W'EY~}x[PtId$,H!(*:(g+pHZ4ƶg6_IѫsoN(@ P(@a) mmٶvA^aʐmgf4dΔ w:BE$M蘊m.)krFd2; da *зe:OXGq: _)@ P(@ P `࿓'(Qv6KXq0o&30[r`00R'E Ps }Ԅb_̿KD+Ȕ*b Eŕj[Lr]'o6.CQ=~XYBV'~*+| (@ P(@ P 'F7,2ʿYjiu{%d4x0aAo nx[ oXTS8GO'iXa ȏm&7~ R4k&vJ&C?ǒP"RY(@ P(@ PH"'WO0>mIT2>m'ܜtg ';]RyIR WH* a2}<-7~$v3Gj9?{C2Fթ PD d?28 r6E͢T":#z+GV_ž(q(@ P(@ @vpg\ HIύtAJ(`0JS,=𴞁eVJ P!>%J[{x+%O}9?w/ExLF-[>u'~)>+[Q(@ P(p?ӟSwfy Gm1T*Ҽzfb&x%5&I E -.7 Ь3@wP\\7.50"L2HW P(@ P(08|JiY4-6tdY$/7ڽ2_P#%/zm?+9%/9ӭ#aT?&߿ۧs ['nNEK>Y.߲T)|Qp:]4M[;7u}k?wܱ/չR=vYu6kb|O#PX43%Z&FϫpSץjFZ?%R(@ P(@)Aܢo4㮛.t͏)>nlKFZJj pJ4pvٟ|~E7Y#czު{FXˤr j_DPe\V 5ؾ(1O'ijM:N $p53YY'}p ˢל%Xz pzB /V{% zߙYߜfS=tՆ}'B+$Vkn^ɺ[V wv 1R(@ P(@ [#5ʈ\7o22ǂ Xҍ0J6wnO馠[>$#Ɂ d.BKd}l)c{o߃ZUnke3'G#Þ+n7bO{ ($Rm5V/gmFO.<{ڬNKj?6;>/ SlLWI _.a(@ P(@ P`X <*}2T?92?>v <>-&7v#EAd G~]nPc0$͏4cb=zz~%uŨ>fmҹ^<[<T+6-BW=Htmvn'nM:".f+& ʵ _$;:zFoՏN)!)ʒ2|r6n叟Ge_ 'e=Јiz[OO;  zϩqd=QVzkR(@ P(@HMCvLQvI$ = 0JN} g3"3Ä9QL +y7giOXr.%gm0f@|n4JzSt7яNU"ęr ;Nڸ$4rqIqf:ʭa\ JqysjƚC9u"IuTHӘ%ɖnWGkSnGNj7/+촾y̹1rxhN˵w"(T |K=gޚ׎ UyU:<ݟ'Vb֞2oN;A@IDAT׊{wi*zU\ug6pqZI $ 5gZ?id̾|UMŔ.Cd&IӢAOB\\WoG:_/6NI2%O>z@B`_IaSѴ*ۯl-K{o%l{k⹊rpa=aYUx~ [kf-ٸy|͹@{Wr`bIC=DJmx螹P|kNGiҿ|1\s j߬-FcZskpH/ ^&uʒ1⊯ȾٷK.o4"#ˎL]-*F%7FW`o~:WxK P(@ P(0~ i.7I'%}v<0!Ԅ`s3gWv/n$]z<zx㹵h- n&Kީ}z^͉ }صo ~9x}.쪪 o/[!>D⊝XSc~Gn}uqכ%[P_䘂o<4O8>u׊s L`wq8pw;cw"|pPp5?ٚ(@ P(@ -a=ˏ$wyqo(`K7!}g`߇O/3vaʱ#㒋a021-/-1GU*!j}CG.c J龹S}5$7 s w[=`ŗ6N9(.zl o8u-yJcuEoJ0cgY+ń9Sk+K0]V;/GA?pP(@ P(@ P]c),hC7]45_EzR@?dߊn$MoMꪘ@Lk{:nLWpwu>nڛ`+F|n=Q w<9oik~Aߔ莟`SIk%YB++,Ƥ~RS(@ P(@ P`3%6cLҊ>j0Fdt=}M/&'፪ƂUR~}3NJ֐(@ P(@ P(@$GatCUȝ\]3GXX(/re^>UWxx0Y~֖"Oӧ?cϱ$ϼNmDn9qߎpF㚛$_[{GIetؖCvTkd)y+kYӈV} ž~(6L/P_$I? W= Uaiy!Iw"IG4vvLh( (@ P(@ PjPhYugef`{g6'fUJ-U,&X&S,O1Ɣ<+N9^N^2d_KPߢrdh+Q萠υ;{i}X5IZl?'xxv\Ze$eQc aggqI݄YX@bD+lކS8 ,Xt/bœom6)u>"߷|\uxh&k%V|DJ~BeUG ~>|8ojn8Z,D P(@ Pz/,.>Ѐ hY^zo9a@|2`#TmWc'vU%_7MOlŦ*h-PMm̼}Mأ&lW+uT$}LՊ9rlt;-=g-JnTK0?2l''a*C*0q^Vk]< _ի9,kL.6rmN꘾*^<͏jҡF&S!ݺMJ/Гvk>ND;PP3Ŵ4dggRɝrUPyR(@ P(0Ԉ0LZ_GbC:/gZE%(}ꮎ,j]/_;-*Z],{(MҢ8Ug|݉R@,杇}ܸyTMmLԎp768 K%.v}WY$;i<8Uyh8KYڞaU8w8'V%%%(]OmwoX3s&'/2Cw9+WjV AJ%2n4?xKbq`ۣJz$,YGGa,k/z|MMM0HOO~_?,(@ P(@ P` 7TC:Tv\ h^ծoC:s?҄E[cdVqioJ:ۨmcދI[m h} o`$v/|?f?LFjtDZ'$ae a @kw$Zj9L,ȋ ަhڧ}nI{tر!f-\'px3`I.݊+GѰ}Lo{.Zwn_[keJnٲEݘRө'6i{%%AX8?Q)@ P(@ Pl16 ^>ǜ=~*MuN㤫Ao` N[Ef6bF  xE*mȒ&AH,I?L<N8FSk7귧w_?_#[szy5&/Қ=8N׻T_FZ~jlI_;эSeshmm%yݲ)(@ P(@ P8*֡*2ހo>O4jAMF̻k#պhBᨋ1.'ex33Ѳz}|xB [ 'h%H r } NIU$fòzNDYx\oW u[cx|޼J P(@ PpP@M;T˰N<*t~4σON6K d1&ہѲd0ɒL<(w{~,A~#"nAY-cڋ%1چ&~G5*#y_,>/[0>f^P Ҵg@<(@ P(@ P8C91"H~?lӾ*mv$YO LiF|3L;lu/|x>>S3ڏ@GIcDzU0ش]!)`)cpzGd# &arϓf5 *4C's'C P(@ P@:k豏t7hQTc#.y%?RTcvK6edQ5B##AFKc!{T`<:iO_jԫ!C&aі 42O$ yW (@ P(@ P(@ E`XGdp%ǿ dR_I#yCOߛ$7KN$wc9t?*E@Pu>]En +S\(:(@ P(@ P(@ -aW\Iӛ%?2Z_/[X(@ P(@ P(@ PF@_P(@ P(@ P({{oǖ(@ P(@ P(@A'HxB(@ P(@ P(@ 0{;(@ P(@ P(@ :G(@ P(@ P(@ ^۱%(@ P(@ P(@ P` 0?>(@ P(@ P(@ P ގ-)@ P(@ P(@ PNAo0ρ(@ P(@ P@!Xzp{Fiǡ)'a@ R=Պ 0UQfV_k qkNt߮{0,j.ڏw,KuuՊmA;V(@ P(@ P(;{"x(0?g˖ͻO~ |thiGpܢ*\Zz;NVU_-7unWـٷދgwFxjSuu@{qJTUmѦ݀n/][7 (@ P(@ P(@s`7~~hOBXO>d9#O|)(^<1ub<۽Ruv܆;ۅV+#|Ap$?mD.r?c;W+>(jܷ^uF(@ P(@ PΛ k*^Ubx' z{Ȳ^GHzj{$F#`mIF75&ٖDFdd^h+/\{|j}=}?v '4 32G|Xb+ht3&8*>]V#-8Q>N6f3rmv5%ä;*Z]&^<G#&Njv.Gs%i8Ôp>Lfx>yd'suIV};p&3g$ƌ+bNR(@ P(@ P(@ @HhFoyJ TF"]䌐VO F gEwY(.vjV:> o.G 76/Ou EQ-EPgO$m!F7ndeu]Z1J qqP蓴OǍ_n*KVbÊC]LrĽ'܆Vz[Q'2&P)i^t?4? ny Pw+Y&0'3N:z ~"eSU KٗЉR95I$dU;e5Cm󃘒pځ wփ|I$it(@ P(@ PxdVgWO;S:bq,Ar1Mb@FF233 {s8/]GjTJãF!#]-RTQ4gmv%FkK{h27̙P0zU&g.T7AJly֪@rѦPG=>C q IFe.TH߆zNSzحgTS';ox8/=P(@ P}'m}YTп݆K..7 'u'??_[tO.ߦYt[`xU0>]E "h$uRS'#HvyUyOjT,mT_* Ѩ9Ƭ2ɯ_~v%k-.KKoCߝ G'{0=T/Jh$W0%C9܋kb6 7@N2  ~o%&l~"gdئw8^qb?E8Y(@ Prrr <(@ P@SSS^ݭF3߯CsFЇ~([H><ۃHUPڢyzi?mǧL!i<<7<U5S<*a$zıXB1yоK;I鞕GǏ ZHj+ Uycvlܸ%#sQ1'-ر-Ox6.x=3:rù5e iXiz ;M2 (@ P(@ P@2ߚiHd8ܦ KbƅwЭ)t  *U<2Z?#L&(~Oz $]/oeƉ>x͒eԡC@f!YqXV]iX-OdKŠF\~Z2ix&/$D+j_٦U4Fm*LXI12*& CU_@P7zQ$)yb%# Q*r[!؜XƉuQYt8%`8,B\f|qyZuj"P đzNr} #XV[ FM+z{)&U÷{'/Z[4BIz& P\<?pf֫j4A5~+~J1c]҆s9 (@ P(@>PAܶ6m">]j}|Wa̘ТÓjFFEOQɤhlhQ\"gdZTt28F~如5(YO3#RMfItx3jal$ B1$]VL{^/R!k mM:sJGZDcWLsS5( dz>n)dD4aW7NYXw]9qc,5h޷y͊,֚xfIh{Fsĸ 6#qo4KXYwVbS^1-(\g}#FxrU=e }Wjڧ꨺j`(@ P(@#^Klkd K !n{Uiq0R_ 5QAy5zm$*6{hJ9zU7 TQ;+*Ol}nۤC\-~v5Yb#}y1}ۗ.9m#%꨾f>cչ#edowcғOڟبީQR!+|s'ڶp饗j%Ӌ_bvĉϡ4NmhDlS}O@| b Tl3X-p_OL0CyTDt6CYOb]@A{ث:u[B=5k}m + P(@ P_@W|k4J>߾+}!t<~(@ GZE!3R`h d4d$&Z χgG P>-xaMּ_M|l1nf(p PD P]@M3>j*/2H[B!!9ݿO؅Cc,K@=],GOr~h,XJd+xC P[S mޢbÝW^ QO,Vo*Yغj==(ſ ^<-hiGyuTZ>V|!U7cυ>w73g{|/,~V\Kr%ӧhsZ[GY=_sޚ.qow^e ;֍~|JWIĻeTbYu7]gO{Evo̾CeK,yyܵf?p״}+Ї((@ Ok}'K^΂*ْJOVPbnM}<\pUC &d b9p J@KNIUV(ߴktUӫ_w~/=_yAO]} .N)@ P` F"7ˎ\yU`mŎ- _')σ8py0ZbS}=(ܳkZ:>S7X KCOK3#+.=ͧp=u>':^/{Dst.h1Q Ԟf 2IG苪&닪 GCK:WCr"`{577"iW|gk97r>l=?|.[=ѱr;nƖTFu%|cƤ> _X{r<?{oU`@@@T| smuCiӶi>OM\tobI~3ͯۆ[>a*ZhJ0 0sgsϽs;93:m<%Ǟ?gm(*6|ghYRqP@qFmkS/`L}pbڽү;'c}EXJq)G20DzU(#ʪZ%8[g@r gxߘOO&U NY1"89WVHRk?E=ݥ;׾$K{tJ|c'>pfAۄlhl `jFwL 0& ,COygҿ}xr?'%?pB6&n!Cjֈ B#UD"K8"CZ2_'|ez sajk'"|QnHXuo0y(4Rzg&R!*EC0 -rs$<:Q?Qf#j!#5t#,*͸ϥ\>  av}L^A&S(ja֟>YX7],~GN=`I\'(-& M`vCOzcryE!,Ё z)0Eg@dX"ˮ˗Fҥr rd{.ͧ^sgwƘZ. ,m'5Bz_ /HΑhg\mc{{M=SD3@@h"6隬f8`L 5KO5=:\Gd%^Ya{fVҿc:)[f8܀bcqhw<="xq韾O`N,CϞ{eUp )C3t.+qHRedS߶MhL~X::\)E%Nw$˵MdJő [B;oqo`L]`ԓ~MVAf]NCӀ{"|0{G9)=$g5 B{_؎^\?݋g_m&̕Kbh'A9 g1MkXyb%6ʷqrSAZ;1Re;A//wcU<Կ1a)ڔPN?\Ox,Hk"5Gs[$m]fbaOhy(ZVKeU -GӬ4uG`f_lV/}V:jar-D&jO1`q. x'o*nR+of4Auǘs 6SˉkA 컵#Í6˱FaǞⱸ3E~W+&\\Խ;b U&^i O=0Q vE;8 KG">lqe<Г)t1(!Wfs ,& b&qGX@?)5yY6:^h꽘?Z}Ͽ-I2#EhٿaZ@Xmr3vDG; Єj`KwfT(eW!{ɻ$@=Gg!Cr=ᣔT/j ~;|[ݾF+:9|ln K7b.,ab9X*I0+pJ\AQ kj"+ kW[ j"+%_4?Bd.؏laxhj,S^;7EE͇Z={ X{k&+JQ^~<Q B8ܒXK>V`L(8p#"ByU@ @Bk_e V)2}}8i *"s" ?^T^crpyJF0_PH?H+a sS66g2Br[8K>Yې4-Z6{B2t/)8|I) w[f֒%9\ IF3R-8#b%_܌ϳz\b*ڂ eI/><ݷjˋJ$|eO{˭~LA,IKA5"|4vNC >L \䊧&rW*l[k,Ơ*Sզ;mg'\Zs5^s%]Co94jYqnczܱgeԌ`L :#~xǓLx`ogKƏ`B@Ĝwa _+#CG=,E^bj3kM ]V?0J~'|Z0/n|8~mL{[2P!>.x\՞#q*(Tڨ-D@w պ",Kˊe߬!6`7@)IB/q̈́CXV?eX2>t1xX~fx+0B2N 's $G;zA?BPR5*ǐ{E~;wDx( 0*Vy[1㵵%{{Kj s f =?}t:YmȩSn\ԄWg >\>GkB#5>*r*W6,0Eο'X)˸=$?~]*Z-!S+)SϬ{O{~4>M2j+Җw?DoZnY~)[$,`%GS ٿa-D-=#VЄ\mV^<6\]b@-^[o5^{8 _,E+]S˪8f` ssڨau1A,ڜ3&@{$_I{K=xtk3~mN&?`ft2]U|.Aju6.R® Ba |E [h%6ǔ6|wfܘ}ͅ,䵑4ݱSd˙jzj*ljx }=Ԗpz7rR#k0KbYkk\Rr*&wڠU Vcy-0ƄOJoػ~K!V9k;Ӝ6*S{?4{Y!5k췙_k?8`훀&Q|O ,AN>$jOLF]@IDATxH˚򷪛>LjC9 :~2i\VcOIQYYY]211Ur-x)Ue9^>4@3pnFa٥ [hBCO+mjk`2R T_õʍPiZ_?w@H(: } *l &p@π+#u#^ռpw_FVڈWqC^ d5P84Cm5mJ)Ym;kmīDdN>`Ev+?Fn~{'8[lY¸cm:84,(2PC0 ©kQ7"IqTQFgRb7'Jҡ{/c뙹R|p3,͌ͺrl{Du#:DuǘEdsm1f˷]b*/N~7`Y5͏4wK2&M"dA7Vl,z9yi.Hm1{RjW6OVI^bJŤ?*Fv9 OIiφF(182\zC$:@ ^E ;8ɵP.@?v.1e:DL0˯Vw dPJ0J(@l ijy> w3ķ u 5 TKPSYRZR^A5k㿞V\[`'0(Йx8F_jq)^(rzj,__ӄ,qrא_j2T^[O~tjL 2|s8rI\롅H?dk6)t3$n c 㪵M+?|Hj>Ml\Mՙӷk&l,zg<,`qoo黡__p羒jc( Ͷr#yU(? j1֜)1f1$;weF-9NǍ 3o}L 0&6\<-.\:ZTYmkagIm,= Ef/>xu6Ilc}Oe<ׅ@"JU"WU\XiUɉ3R>COg&!X)y"WGUSq|#6 G9.[JAL9ތ(x'V~֓!vI>PXO7@#7M7\P¯O+QZxzz뉢kפ`o isGqű]iZ@PK[v3N]4QnipD : M%ż 6YЁ,RzoF7bu B c]w!gJsp`>|{'vn{GS} ְw~9n4f/Z?m&9 lV~T[scvZl #%L5A K^ mvލ[ ŵ6r.F)L aYs,h\0chsx:Mnsu0aDAX>LHN"MNu7EZ !f3@}BV!9hqlS,Q-h7beZ̾jY cy1`lWC/cKY9mTҹ͏쟦͎6go;`LP#p[f[?xUX%L!/UP*AaxcPt蟸ӇXL 伴(ݙ30| %fEN̈́91 #枇A~4@LyuVbSKeҟ lڿ[Y/jV 8{.КBNIş7m'_ud!),K`*^ғbGK:^$Z*^C*JRbA y9G8t<9yP7]'aqHkׂ*CG[Phо$za04#>5q6~^"ns aDd<+1F .&TVcߦ¢~4 _9 NQ!d5 1h&WyFM6ƯehiH\ej֭ߊ`IĹcaǦUX`6&<49be$oNpmHX| /'y*T=g 泘(IzF9ꩵ-U*-+~-)3Xai-Sy-L-Im if U+knxBj1sm1oSP欰vͤOsڨOś3[y-RL 0&>ڿѦƒođg4 sZMlY0♿⣷[VAXF GX~* WoK-#D%#{ hnL);k?Ȥձ=z]HG!~b|}9^?NJHxD}c=T$QkciRF $&R=#zCB# :֠X@I)Fz _:{\U4ttM?j>8y;Ha*hj<;+rLK~%M)f;GLu";̑"0~oW &ˆM1+Msa4v!CyFZ&0W".Z}=*Ur7-G. GGծ7pH% ׂBl^N. _/Kkv-$#bTO"lY ޽A{1 H >܉?kPE픆[fpaLf/Ty- -a͖ K lk #[lچp?K[^ \>w`YVJ '38D _4@X\B%N^yۨj)"iD\v'pdlޕx"wG-{uƧlW^LC-u}-.2^ Zl'ޥď%aN4xrSl<ƚ\5ƨWǸ]]o[3B_݌/c"VN'%6J8j+cysq+ eߌ߿6ϋ/`L#3p&n~(ghmTtZiӶ$FMe,eAFEb;@ɕd\J9cKǂF:Goh3|@ y4 ?NnZ0 {m:XU/wώg}F9 Q?|loœގK ӟ{ }[6{m3`uyn~Rņe3v]KX4&߹eJɯF.LۋUk摅Gk咷bco6"{ 6;<#e't1t(To8&gHI5Uk?Qb{xۛT˼7vhs,[n5m =09|j9sk5\Օ^*EC|/ԑŸVz YB,9^&~ԓB؄1+}CLڥ/HDԤJf m33TrNc̔ ddm|ҵ$5fȥe<ȄJ]qdGm6"*W|dgl"dYӒt-t7 ,\}]gb̋uUɅ[M:igo_^.++kt]5/ BuhթS2?tBYIK@/SSElӯGn<)CP(m[?< {7);~WUEuU_FT4  q׬dLI\|65?--qCPMk'w8UdN8X-RU%VqF*ք|m.ǫQ&&=rI3E&;D+[#Lw5WhٵвG ZY r#NB3ee_k3^Q3fݘJѣG+uqr.4Nn_sߏ4s=]= gyo*DVUzIVWgp)QG:Z) C!fȷXAPn$]5?nQOÁ+1bDr'BIY?uWK|}op|e#DBק[4i 5bE/do!JU 3JO#M3 *? @iQ? p#,0w ܋g֫uwf,4 wE9{6Z"O/ wW.,ahAqCބ|krRi QV$e%#prrKsW*mj}!k,ey&D6Ymh4^.|m15bsDhZNhy!aaMKA`X$ ðaqJum֗ChJb綢P[!-u>bZ' wRBNףa4-Fd\-ЦЇtS&G!3rlXIK?+,-~MKˆsRdL Xwɡ$'CQgj0jn0xLǎ ߍT+;f,AY8p7eW/@ 0cPLBTW,.eEDBSe"TMSgtQ m#CMȦg7b[W z¯{ߦf`ׅ:7] 0&@XUk{4".tcC1V8NTב~iq )UG hr*QvxӲk{f4Qa5ڴTh6I5W@Y!d9 *I 0eܾaΣX|:[dyO#r< G2λ.{pF(CYh ['2KR5݊&~qiFFR$H%$$@ sTM!-dP+d`v?IQ# s$߁Z; oN%`[bua,IĭVÕ< yt{.d)3,ߔJ→+9 X,JNäW7R-o{J服(No&#6~5_ (8d~6WΊ8)u6lι#Vbl+Prڜ ?JMzg/@ &DU >W|pD F=.UɿI'W_5\*K-ט'*PDJiByy-º"<ї sB짣A Ř_-Řϡ扅k9]@GDwn@]wF5Ocėm^fA-n~@%@~]n[<3&%EouQmsi\|]vA.]>&\7-cd o7G}: O|Jڧ4&EEt%ZV_l@|>T @8j:huwc8:m ) q5xsó3G;T:m;N_._#:ԭ#1qie`ۛu A7ɍD댉hRgcK 8QV a#8/ɤxc9)V0bI:2<1b§iE9۱eX9NXE$[23>R:gSfcg'Rok׆y&FKr>%%)P"6Rcì2b HAfNfWB:a)I?hzᓗ4GSL{UI @7B#f6@[pz&ܑnf1&`L 0&&MBC!¥o]0bFK:_?cɬ$@jDx5J>= 4 GZ?jIۑp+i. rejkmJƜOqB^hNjUWOBBpO5y ~'Rp;rǐLi%?K"9%n4z+yT#i|X9z"{# 97ux?ܫUSeK{V'C|`MHMM<>y :s$LZ!&d!^1'+ճ0?M7nD_KnU⫑+r_~rЯˀ9fX$\m(0,aZ 0&`L 0&`L 0GV ?>tK/OVU&UDMըʹѯ5bsS%)BM7C~]@y >X'Iɖ(^q%&TC;^!*A -]$*Ċb+!{ ⧿9a,8M=IC"mdc\d,^8bm2֗gq٣U\Rغ?mlRDD<*S8Q XKŘ0w\E y5aU'T|B,N"呯[x1I>Bc%J [C{[Yk:V%6y<3%!s>~9EşL 0&`L 0&`L M.hf[Ut:. G}[OWPQT:`$kbZPeJkzD= BCkDWpxUӻbOB0b KWl<PO[Q;`-,Avxic_B!;{ KYd0jF{٘y~ޝoѫ*s}]GO B&掉~~ T8g;{KM!0, SS%?6X˷cZn7R3P(\x:mH*ƋA0XC;s<ئ$ )3;eQ;g&`L 0&`L 0&(Z/'.|!=x|`{}m5mK¿87ӽ:rS_!YU0Kd13Sx;ZlM+X53ayu>Ӝ׶|e*)S IM1VMl_ڇ6Cn:E`Cc3aօ?1Ǟ[B2FtVX?jؾG4byde’@ xm{VN9~Gh4~q3&`L 0&`L 0&Іx\t|c)y̙eki'w)U(p_Eޑ;#ZTUо~bb@!{?w6AaFIA>.-pB`3Q"QB=2:`'uɲIv$="VqMm,)!*"lل灼 Q;|p%ũuIQ$ FpM?8APr7}y/hsa:&`L 0&`L J$1[aq%$2Bi1K/["@^@BRƽߧC:Ig/^:>j.}yůSvMk`Yp)$eK3,-BGVzޢreL 0&`L 0&`L _׫n=wrcEH^#RP-+S$q@NaG:_A`L 0&`L 0&`L 07 '|产,]:vp'z{ ;v|`L 0&`L 0&`7+y6!pLz7RP L 0&`L 0&`L 0& V7P$w>d߱Sg)'i'3&`L 0&`L 0&M%{/)s`L 0&`L 0&`L 0&V '}\D٘`L 0&`L 0&`L&`E3&`L 0&`L 0&hioi\`L 0&`L 0&`L 0H7>fL 0&`L 0&`L 0&XD>&`L 0&`L 0&`7+o"|`L 0&`L 0&`L ⿥r}L 0&`L 0&`L 0&n"VD, 0&`L 0&`L 0&@KеtzTS:ըwlx|| 0&`L 0&`L 0&@[!p[*+ŅS(./šhy=( !Ax$>;7`L 0&`L 0&`L ~Z^ZZPSWK&qzo>.S'~fx:m %9*T[G>'Eeߪ[K[`L 0&`L 0&n=In >q Ϩ1("uzʊmq>:pG`' |uޒ)g gQev!6"nf)4 xu9ZD)o.97MÒlk`y cf-9ᠻo/-k!`L 0&`L 0&u-7 z{@ɏ_m Rkdkr4˜'TZQK(9;0,$FhL, L{76b: $A2XBZsɱ̾x, 0&`L 0&`L nK[xgJ~>J1N')MC|m֊-tO?!958?WtQf2W-* fý-umޗAǕ0&`L 0&`L 0&`C% m*.P[J=l Oꪪ'"ߏvT UmHsxͽ^u GS3fRQ)jH]ȈJ pK~?*<} %J}&xҔ٘ԙ5}EDxiC4SⅉaKD1 4.@ :X#mLTZ!:ݣlaD/Wv< 6/S}_S}A'"X)+JiCAfK! ďwOTTCDi,ѕ tۧ&DjY5mgK|bL 0&`L 0&`Lk7[["sOxIy ƒbvMrTu#FO@5(/' }7eo#x)$`7[0.<'IJuzQRD%g㕉5yxH,!H?Ϣ4s+\J1&ͅc {uIkxKyԉ 5,J8)Rb6l׹#VblP<7 $%QϊÂ3ɕ`?<SdB:{ UIL"ӯb3NHA$1a'b;/ ~zNiSr4 G) smXyŁKFGu5{%'h4VXX?H|xbM&c*)y_G%mIx>- 0&`L 0& TUU\U]:I_Rʵ[ݭ5r.^OηBntXq?(5%S[{2r#xw/:D5zou(F_Td__b_Mwڈ+a>֭΃'8d mCuA4b&F`az>Aإҟ&<"( (l&ֵ|`~zwqwM9P|`)>scì2BVx/ҿAeR( O*՚c!9z4)/+$<6ﰟҧwu[ "7FW1 p<34H_g&1j 0 e~@n^.jh5h jO/tUΑ:þM +"ƒg=8 eL 0&`L6!=S4UGF58ĄOxxt| HOȥ޻uf/O_xeLU}Q]ZT՛aL|YGKZ$k1nJb*g#e$r"xb^"fUK銊\\@li1}|e.~V}+L@2ыXf^EUm4iX)#ΞH>$l\>>׍=if5тĂ 6I&C$?ggB|D=Qn(`L 0&nWa-,YߪmDŋͫ@x[#7=;!/y|ǀ13:ҁ\UҗV M*/`0øՊjw´i . eNGÞ];&mLڦ]k:}^cJJR4t D%+:)},>r4GJs9SƜ cy2w* k'$N!.^pP[+J^NzBGz(͂cx1X&Z(db5Zb\فoV~8\=`L 0&`L 0ۏo3]PPDXaO.cu={͙_Zt0բGL _>:t-HQ@IDAT3H! sϿ] 5x=jiYyK\gE?5ڜu9Z4',禩6瀈Lg[|s|^3 iMOVsFeD9x%c`KbMN/NJ/}?L|t%AvwlœBq{ )W-ii~Vks^&O]iL::Ż{â Â'_+㝸xrؠ`Č"WmDI7ؗ2&-c} FNqja]| oEZzRAOT:J>!=L 0&`L 0&I٣5[Ԧt /\$k<[ȭz`+4eϷBZߝыٷG 'QeV7jI_zE:D\(:wȧ8u |5,6 DN5?xCjj{fUTJc!lݺ[3tB5ʝ(A_5r6oٺK!zo3{ ~RyX7g>Y OR6^%jmP6uPzoHs#55[hI-ěDwhIm|x>ݚc(b/QfE^qNX=)S{bġ9g=2.(uؤVCi|v!P]]<=v(mӵkWG?BlltA.DWe90&`L 0&@" Vj=" 6*RG5ja\k&Z3 ޾W o/EOz{r: &*,.}||5ԋV Hdv~#!`FIA,@"\+S15a6Qq}o,<+YMp-R1/0)WKF㓼-4>=EL FasS(l2"$6Ŧm|bٯ3ƢX^=) KB q7j#;^BT[iU uHV颶) x=,ڿ `ܹurHB,ɔl_3 bfbOmLaȰט|a̓DO "y' ga,֥bYR_ry 3b|Jw4"# qIѳgODGGo߾R<,, !!!!"]<".ʈL 0&`L 0&v%n |}Ovz-i-bŠ 6_hP SW_2i{{}@y!\u9—|z{Swk@Z6z,. ,1WQ g@ɥEH((JX{=ճF P!C< #gޕs=N6E.Fjg [$_"Iy VzC FLz,缇?!OAr'e T.&P!9V9MEMG ,npAXRڱڎ% ChTt/B4I/Vcrb"aM&F`&mT&O0MH唏Fk3o0vhpIV/At7YEa:c`e]ۮRqK$G47B_\5缕 ٳܹ3 nݺ!88X::vh;'2CŁ 0&`L 0&:ŕ BNJ+y*_a ##ReL4$cM]r1I&a]Ѧ7FSLRR ~Ukڟs<~F$-iC__ϽK)*@^q!i@ߖT$ō 'mk>ןf$uOgOooŘP,v[|5043a!9QZLrޚ+?Wf>QG=ROSwp q5¸} rx'Gꟷu#(uq)rA]*_l n=O ΉvlPn<1H*Yhn!D#o/yDc>V=_F1z#q"l1Lsտw/-_xkMU8H|++F:l3z~4ߡ&ۛj颥F ,N N)={~>PH2߂6Q>8e|XS ! B@!Ь~(Rbqy-I F{\,Gju}ɓݱlϧ)ipS*Il4!د%HiD#w:?P}H\>=Xp<"[gFߋ&UX[[MN"Whi<@φcCrr] ĠWىEၨ7!4Zofl yW" :vl 4WeZPءGAH@ea)r8!j`"U( UXk T%g%ok'Oɞ88qF~˧?ܨMNn=shSN!::ē5_x E+߅ĉ'йsgnUնP5~peI!B@! yyyn6#~lwoT?nL}#$w~>>>M2.ht}׵aj[5rYU/͠m`+Zкeț?"oK cx|?ߘ*~ ebS 7F)~y %cIh½+ܰo D uI& QyQUn~BhcE{d`PPs#_222H_ Ɏ;})q;f])k^3&ށ Ty %4M4{0cl6#! B@! n4%W)ǑջШ+]!p a~mZ}q-}wSHW!$+CT]a2yD-ZQrKϐ;T+$d7|(,w={E,h2.\Pt-[Tp_ğJ GdI ,Vi-4sHe^J Ы;&1\! B@!pC\)=$e|OR.7\Gc=&2c ?ꇂ,(:EGǎ0 i/=͂[Cޙ`{WȞ?gB\)-/ag)̇z+c,pa AJp^SY~ 7ZA-˹ymѼxcPoo_~@TJiq  H⧃&*R__C&rXbY@nnqfɶi\n]X_C^-PXsFh_w[q,+! B@! pEU!־vi~:?옃H+ٻ,Jƛwe \xqPzοIX9l:7>g@z ?x{̷GNӖ9# \a>0):t+Y~i*l!N y] ,ÿ7((23Qًo۟'$ ! { .UV@7{V&Up7ש SiYA6NI:~%W_HJQ..W^B)(Rp2%PRn32Qn5\v]VdMd)P}tdf"96+! B@!  @]jfS㩬Z~bAhZ1|lAןo()eLj)42,j!'?Ï(rN_ŝ]#(g q;6V=i(,ݗaLѷ{ џo,pXEOq=/)i)7$u|//5><<(?ڇ>|~&ÑB@bApp1&N&GVVVn''[])`_o W7biɋ1u-ҡ ո=9mL~ ovos 7q [,&%⥝KF,s\G!g! B@! @S8|PXYZ3*RT7i QxC$M+go[M🕺 SX?w¹% &'aX@<7 /Pm3_AϾݬ@w 9`b.JE 2AXF]nZYV daJ^i~0VQU <jX}JqTb&_NsX> $cRBx{Q:?)B@J8?o˓6}.EW/u5;+/wCz^]\Յt[CSP[[ޖQЊ:6?W/!0%sXPwwG/ÀMhöyW` md[9 ! B@! 21Fa̘1tIO͵{SM!6*RER$Z&s9#ӶT)F)M~$]MS?riliHɧ=ʻpFߤʥ9}ݻwcl,ic VY|mBxR| }@juy\GVGƠh*NB@492e^o,r_KnšC+!8@ 3Z'KU/'WCy/iq_@eiTl GX[ɛÐoD;7+}C,8nd_2ܻӖnXF 9r;PMȘ767=ݓf"eȘKB|o@ճD+]A0mt 튛E҆ሊ wH5=wA:Ӭ |i.BC.D( A9B 6Ljsf(iIE'?q ERqCFF?7 VNMS} u.jdl|[Ō^jB߄?y2RӚ>ammvl(w)z)H|Z_$F߂|!I! B@!Ќ/Xl֮]K2,[w8z{V&ܟ]j3Ki##]TFUKT#Om?$WaM-O9%31{Яw7<:})Nu۳8W%M q ]%뙀\ϯ<B$9οRlӆ$5q4iX񷢃2@b{Zl53EN/@/8y>223`h*o5B>TO{'+\ƭ! N8 H.?1H16 ]`!{-( 8}U*mժݞޞ%^U{WeOʅBN?Y1ms}_)բ&%ʏC loCZ*]޿s+V2Ы7eF˵DZDZMA1l7v/P?V6UR7iJڍCj ! B@!  !aO.Z6n)QR\&N{&;]ko~ӲѸXd6{30AMQxniHN(t,V1q\m׿z3i9ō}o~scqE bDk#ܫ\75uFSz뮻G}T9pm)gXn̛7O<0sǞ<󌲺ƪB@j\9dffM6PDz>%颿jUl]d>H/T#8s$(a^/^5VPJSޝHzoq  &.c9c.VLY0VQ]"ĸ6B@! B@\f ] 'վp ]OOLFa>ym BB{'#=%QR24j*Q2g*7Ba]B> -_f@]Hݰw]F:\/eMGūt7eOgsAe238~? fYxLʫ8xޡ?44ToLlod/*9dbve_frhVLKˁ JV,ƙi &tl]!p]0O39sm]/--UBM^}t.^6o4v8^z"ߖB6B_|o2$u܊?mP7D݉'&G>w܀N=/ GUq8YK! B@! nlyP-Zw]KLLT}Ifld2o̚ez^PjGj'|ɓk0UɊSKr +XFsg+,Twgc@ Jx!C_4Q<,x%Za8tc*>~]CD8TtwxYFXQ[!N& qb l8V1Ufwo>+f>d^xlt&P'`\VB!pظqUwnTkw̱/d^@Ϟ=Ow1ӟm>|m"(딕(^fs_i T:&T3TjGI .h`5XjD~pJIB@! B@4,<`7bcc0Y84wT(D@U}v*My Terݑ0Pqs0ܟ~gÙy, W)EvR}Q9(evl,?ʇg_=lYT N@M[f ċn_)B ?IOOX'/(F$e|m-C]d)B@! >vUNFQ{#WhZ=.]TAu'UP ~/.=gu3)Ƀᯔu9H(@!Ps#wYk"Ѻr#?aAhskj8u(7tB֎3 4A\P  Zif h]NV cpd _ se˖ʌf(X(NM1rVsl[e=`y@! B@! U"4ZO?D:Ю6o U=6{-}z86w=\8/;ƺc+IZNOFo<$/L{Ƃaa2 x?'apx Wȳ ! B@! er;;/Mj[f';w.񉊊RjMou;溡溕-%wũCx_p0 bUpU$+}C;.]V*b#ʄ3X>0̏;;7t}'l64W6 _iőѿ2 )7(Ews<B@! B`.v3t<.+'u%ȫ^^<Ӻuk_.@yoO7h.VW뿴cqMWfzI缞X?7F3tOoz9_ܷ&OXz{yR_}v;9vq_Н gNC("y#>Hrp5̢xSe_{j$߂wC0 -U#hw]uUJ&B@! B@! %X3vmc_?r ~$[5JnYiJ|#66_~eֹ׭K=J7z;=}Tx ( |<+|h[zS= (2Jسyoaa6kXSH|3=#ݧPEz EWEWu<~RoDbm߾Kp,۲h7G}3Qj#wt@gcƾ# !  $B@! I@9+O3O'QKEN|]z5[ះʛ~wWc;m;uC_={{ҡn⧺p|1K:icA8mUIpzcґ +#nYdG SqˀxD$L ǵnMyz`%,9NZ3R(ڢ ! B@! B@! yۆnk3Bm0dF|mS1Tγ0orYe}SGzweT1nDRR>;S-];uV?j0!$2WwpyRas{~JƂַ?ZßƇqkѶg>h&<_ÿ# B@! B@! B@TAyo")!chIy.M***•AA6|ڠ ք!҆":=P1)x'q*_fGA$k|:RHڤXKzPJƚ pVf'-n]V7u[ީ?^uZ'4iÂ!KR(B@! B@! DJ4To7umz{p_BD޽nԭۗC?݋47h<3!'?WҾ4pS'tlOTgA ! B@! B@! 3*_j5(/GΥKAqeP /mcܒ󀖯 l^(Pκt^Nu_;$BO7QfLB@! B@! B@!Pgt vY?ͅ㿮ݘ ;M9S NJ'RXr-B@! B@! B0?{G`ǎ~EBCCYyΟO~0F귖Ja"¼l6Lg%!!Wv% ! B@! B@! h 70C(3PN!8\Yg5k1ry=].ŸΠc[o#ڇ;Zˢ1~k-trB@! B@! B@!Шn(ៅ~wNeee8<ΞEvUYgcj8Kd'/6+!h߀ <ÿ‡}l$! B@! B@! M@ɢq3(<<`wnwbo~sps>1}}(?4 Ew'B@! B@! B@!ИD',%ot:I/P>R 2o #B@! B@! BO`;҆On$bV! B@! B@! @l'! B@! B@! B 4S{b_!p]ܹuB@! B@! ͋@ hxO,7===//uFD ! B@! B@! @$ UxYX5k.\(iVB۶mžB@! B@! B@K@&|mtO X?$` _`J! B@! B@! ߄/Ϣ<+DFFcAB@! B@! B@fJ@&zaΝ;%%%JlVZ)=L_g=8hh(윌=*sv휫ʵB@! B@! B@\*C6Gz)S(g7+b}u{y!,,ج=hؓ'8=uO֭[+}|U 𮸨r2W7 e^uOK<}EfNjpSf-bd? njS{y$I{WCrB@! B@! BDi;Zke W#'5BBih8,(6yCUV)=uO_Rm ,FDh{o.P?-]S;mhmUxeRnWQ:|}Itfߊsl@r*gۍZpےIgJGؙ T\U ǰ^UUv-+?޲ÎïWٻj"%'B@! B@! @ M [(<TVX.*GyN.JQZZjg ^^^h۶-ڴiǟ˟9Dzx3~^wy`o"бc(!Zg=u ǘ)jYllWt}Z:UmKô!;LMހOU_KzO>?6}oqٞm\1hB@! B@! BF=jr! _CU0ig'ale2kp3"飗+.WxiDZZ #-*ا^ǪPf-GԷ1nJef E1$gRH/(rD! iGW7/iTfcor%B@! B@! h6:TA߃<9'jͣ_ȴ:| aD"\]a ^(E ^j6V9rld+dEHrjA^a1@u]5l@IDATwieYZAMԡƱeV qCᖑz"q䰑3ps/TFG¿cӸX@#Jm!2X pN? E~@«W—Xuyͷ 8{!StgӘ -8VlQ_ۯk j[At>c7g/\E2\wXk@+g! B@! Bi 6sEEE@z*^|H;,Vw+ҲA(?Y)&pr/ITZȰ^6oזccU F(Fb\w!7Rm %j{'$}LJt6hYkv&C4bƽkpk"QP!H1'>9z?U᩽x~4ڜgahD'0}Hۋwbdžf7{ g q[pB)fu+vz1Q6-U5^O: '_T~cU`{f ɘ;Rp2B@! B@!t, \>[J,($O/O}J-ZQ'4r7&jG@/x7ݤx_q^1Tj?x^yha&oP OẌ́\Rpڍrm+e ;qqq8S7A]>̮4} b2;riCqF? MDG_v|Wy>jsVkq;;i"͐S1ψ VdzEj:h[), 'u|=ۤ>-ƁW6ѦUoS&,v@4_)_) GD]^u31ULmS ͉GX0$M5P ! E*cB@! 0F=/_Faa![#MmFT 7[=۫das.=ybŊf60^Mkx247 y@r|nʂDZIF"',Yصf0딅X]X0Pc苼7z6TYMP[7&Є5]-Nk`UYmP_ 5]ԁqؠjxj;,Z 3oI +`IPAM#B@4_|'#B@! 8n'`ѿ7cl/1 I:22R9Ν=sA&ZtTǿ7e ζu_/G<+Bȳ<=IF)Ğ^A>L4FOVTp FEtzwū>BQtz-SMKJ`,4fk>(dN I@78Nx}'4wp6y0 l6LʿS4blb[Ș)kuՄgXXAbBؑF'G~1 Dc 1>HƘxHZ-ag6Ip b7l }28lgܮw/m q%$uy t|_cual-q1ð)I_bx_i"jUM!pmT$ ! B@!аԈ kn_D; A?3|||$M9YRQٸ?Dh3^^JK/e5eXx-LSlIꄕ+^JKK8.b@r'o)c+1!LB@! B@4?=obo7\U$ЪU+3mZN{&j$ ׌[1ƓD—IW~O2 7uTWš=NߍC|D+AwXi cR\8Fџ:I`GE)w6L mc@vog[msᔣO1bs&,U gǫURcWYyoJM[WNflv1CxCcv覱Jw~.k:6b!ߊZNk .PPF[נc֫. 3a׮]صmνaiBm([hx?9?3<DoK ! B@! jMWm7J"-uWݒt h5!_R,I/8&B;&luʽB?mPL mfYM'om==|ghUcR(v'NGTNʅB@! J~|5|{$2/){ݦB@! B@"PrzKS6a#+]!pȼY_?Pmn=SܪwU8|JJ Yt.S/)gJE9uQY-Dla&џ'eY)i!oz ҷ 0yM(N^eڜ.MIwяy4c EkE:Y pXm,G1rhaaL"z+r?( 5ӊ<'|AEO^VVREa&J.A%#+p soA>Z|M 5-׹sM]uqF s΍j[߹~qN!J,ѣZla>8r>fpڦc{f|᝘rum@jj*;\ dJGB@! B!G:v#6{b}Ck}ayO'X9t9zG?߁.G#Хa'B߇_S$-Z;'VmB񫪪ׇY `eWSz[ ZpEQ~!h!aLz΂3X в :DO-˹y0m@:7zfzSAyTBITMn|Ǻ$! jI 77~!66*Zv2$ߋ<#!'xw/)+RM雤$! B@! z^ K( 1ٻ,Iwƛwe+=WxqPzοIX9Ȱ7>g@z z cz1gD7{+Lۇf?]'n=/MEm2\^$~"al?.mѶ-e"TӘ.>ד&e*u|RVBi8y$ҳf3p4gf(Udd~%TNe%(t Ewq\~@Qi,fKhlʸyl\_B@! W-~ ,Œ- ?Eӊq>c~|CI)gmTKMQ=%8aQ >7~4zwv\>ޞ5.Ga84w˰]s&=܅7Saxa8\,"`|W__O A=CGVEJ#' 5k۟z]qϝQb#ڇ;~pYp0ogیNjW80ulDZX,',л1&FVV2]Q#mL /ْa?KҰxTe5Sqm'bخJ_{ic o6(9L#;ϱM4ډ (aϬY/Œzpz*d+g+zsJanx3IRB2Ɨ;_ER?m!):mil"}IR׃p@8dήܤ$k>D0e݁c5Wx tݟc97ThCd<l]EhA?>˨M+S0kڪ,l?_+ 3Έ?|iUOD>kR@k(kMzzzx7`ʅ )/Sؗ=b=Kd'/M)4cBiy y?`xQ OO a䅀AcXmsܗ;)yh ,;ZEǻCxqCݦkOa=ECb3I'C8c.{ nJEƼ?_X4)DXp#u|C&ڜXuA;Faڂ7Sh@pDEF̓ǵkztYQXK& G E D\gg Z^^ A;~-Ǖ`0$ (? @S,+,,biZ ؊D k׊U"ZV- ?W-E@$ sg$$qis}ediWgr<+A@ @?_ۇ'^OY7JE^$` Toֿg{_Eꂷ0G_L7Zw=}'nꚴg7_Oq FG6[jp/.t)*7v1y_@@@ dwB+nF֔k׸Kͦ5eyغq2! \U)^wNqTa&27/i>4g:Nl&>{>(Ԏ7{< OոkL+j\g_쩺~ʍ;Js`[r <ߧONٚ8h@ ;lgMP_؇#wE}ucu?&5ύyQ , MOLOjv}nicOcA_#3g]pܻpx*?wf齔4   R49Sg77&}ImT9fنJ_nwdC5w Sm{.OO#צ9 mj_ZZ:ykEm_q&MJU6SR%:]&hÈO  ŶiW0{j/5yH. 37߿xRGH ]/؜̲?z3޳=Y~Zq!_a# Vٿ]zwīߐњrBn|E/v^?0-32E)7оFcv]j+?Ƭ)4Ҧ,;b0]^lPKG}9͟?_gO0yjޣx.C"ӆiPUG)w1fm5ک;u_5oh3j.oSmY}5J#\MW;ka &xEhX >>^Ǐב#GT[[6o۴m>l_į ފOzEڢn}Z[,k+Mo&ػݧm+v_luL{dj5mp <"4(a휨b'HoHc۰mهma D;LVݬ'߬ܫjϟ%z3vyɿ^ H@̌]jViOꦟy/&dޢiQqt#^[[EI^\c=|V~keVIzd'W='Ymg%sP[_ӫ[F{b   pn"%).)w|^ l><ǥDy'Co&RYs~W k բ/jݼufӽk:CW Nu7;ϩWڛ{7.DZm:wn7J?t?]g_Doz^s%{mzꀫ q]Iފ7|=e]ށF4~?5@ /9c6mڹ!իW;]{]O7Aͭ_x}ii8o׮)d6=zCgԗ?q<3"#}!{˿֌A&aanQW?˙e-yAzAuDL"7 _n+Ɠy^xxkgn3=S.[`O9|үL2CA^GvkV;s!D4  OѣeeeEG9χsNK x]ʦqM?Rii'2:N q@uWU^*OE7pcsاOEE1wo4a[01#Mt?Ic;Em۰)~l-F؛G); >|~A[!"Z=mbCD=\ h83qiݝ:rV-PrZEExuh[]{y- W ]i#onp93    ڷo'k3Hřp w=Agd5=m}hA~Vg@뼼ܹQ @ $'V;vРA` Qiq}Uq#U踝QkD+>7z6]uY2Ptlb8`l^Y!9$D@ @j/Qrrn,]^48Bfwi޳8M"  N@}]kN/@?x+j"Iccb_|s hbb:u\,fTeVSԱcǜ6`bDBa:ճmT gũ[ @:   Ř;;uҾ}du):H; J& @bIIIr[^)|esbDEE9b=Y nY]Gƻэ-kT@@c~ϳv|Kܵm;_tHVΝψP 5@ZEB~{{7k͙yEm@@@@]zsllsgۮ>BMPw ?lѡCa? o@@ ؙA@@hnߦpNocǎ\q#EIII|C܊ڲ~:<98uɹ(ЊN#C%@@3kϴ G@@F6=lݻzFi ؙts.1pPO@@ΝC& "  p =zv?Ajw/߿_QQQҌdfԥ*     2?&6!m{ %xfoEM@ p '__H͖:r%vNtrBm@@@'pIg!i[Q̴֭o\`~8Q @gY'!!A=zPLLsSQQ&*_]p:a?    g ДٽSH[@'O?ufK.H"{_F.#G/V^Խ[wr@@8Ow5'ԱcTV~Fg~f( ΉZ a8p>c]x hg1'""¹/0ou+!Vz Tyg^} oػl]{>vޭ(4>@@@U `]'14{&NSZVc @[3 T_*zn* >lvW=ך152WĴUEo߾"JLBQgE@@Z@Ǽ5oplzӕً@+ h h6'owYO vMc_6= S k?xyd}{ŊiVԖ<)s}\@@@ / jlحAŶwܴju[k h_U^*Ϯ*-ցt!zػmI2{@w꡴TAiM~,s -Nȑ#|?:::$A$m߶i.((.|ԽO\HZo6_'.X7$GdD@@΢@IͻD'7 {qw;3&鶫i*)zf: rz#tw){r?gհMIzeJEc;k]`]_7MX+,1i+{[P/_3<h+6mxh}Cmh&΂@h3eԭ[7'@l枸mm8uD%GbbԼN)!{G(Q|ݻW t<}Pk9&_JY_w/jUVVWC9JWkk&~}cHh/5ݽHck͕Mnw֠˻:yOi`irVZԻ{Qr}.2O?{޻N{Ak=h˫4ܕ`/Dj$ީw x䩕 0㿕> logWma UwO)[jfw.M:3YߚOT{@~my;۾ 7/Eo? gp_LƂEzrw3gz:^.`~<756?i9(?ߑ@@@B+{흚8a&Nh'j׌MK֬[Y]Oۓ<3nޠy"5Oo1m!ͬ)Sּ7m?q_*7%c2wW-0hFj7a{/UPUߴs@_G9z6x򖼬}-PZًd( GY?[3mv_WsKjm2/v6{9Ϧ3֟6n=wߣܿ<œ_C_^Dѻ6$8A  Zg#_ajnHm{S'ML-yrj=-EZS"5r?]&^H.xd7CLJ7Rgꈹ^8XE7I K t۵zXz(%16Rӧeꇫ{V-vT<[t׿IոKT]_:!X< SSbyl6xMEp  H _hōҚry7{ٴFL;kfoԔ/;~3z^:mч&lZ=z݉YCtv1_[f聾A7ieV-,k{=UOQ*4 &(@yx2 @ <111/C~i/Y{}Q m6| CeG)%shuEw4Vɝ"c7CmL17O>ZLm9D¿%tKU8Qe ՟if϶7]5ma,/TaA"_]?a'g/@@@P TirSg7kM}UN辺D׭ۭź<ٸйC]T@K<>eP_?g ^^{Y7Nu7s<%ZdO2λzozD;lf[('9у}9VR(,ƛ9T?+s=AyK)B]{zJ, (xn-[Oq"牀 ;vLݻw?k3O<f9K G*1%MiIޙ]H[f[_1 fwGO6At.A)kh٪|v'O%Z/M sO"_A7 Q|ye?zQ1]+uW}q.弪?z6)mYz C؀  5TPIQqO9{zZ>#=}԰,2{h_1gɱ:^SOtnoidyd?iپe0]^lP<4UGNuMp řn=zn-={Hd0-2 /1j(%|Q5 ǩ\;_{ 5ohˆfS΅W{<іթnH}!J8BM 7 @7ȑ#u:1mڶm 60K7Cma^X;p;v7/Yn=W׿7K% @@@ D7kj̈Q3f1q?诌ztnV¾}#H4YkLn~l]h2jqeՔA ʩgO?NxTOߩYԫKfD 34x8 ?N򦀻4\yG9d 1n_Zhol۶*ަU޻}Wi\tߩ9#RC_ʪ=~~zd*ݔ;p*e{{~G?E?U͓; E 3ij`Dy[2\ܗ}̻SD꥾Oz|U!VpF->_˖-Ӳ=w   @"%)ֆ)w|^ :&SRs79Ջ+oj]nވ:~[USsjվ^ fwtn۠e35߼:I˟yդIsw9ϑ#۷\s~ɞty3.$o\wWf{#WWޟkvE%gLӦM;c?@#zjkk?/--uڵs7칦F (--M=zPΨ/7 }@nܳ0"7Pu8Ls76f7&v@ ؀|.]:iyltgm6ŏmӶl"DD3b#."iޫzç+';݈N@\ 843zy>{G}_׼А[{gxߓ;:d 2eŀ7gVusS7dAY @@Z]-"2IoLP8ӻ42\`jTb}֠Mk?+^:/՟ HOPmMvءA9zķyEwؠmGJٶSl }9ĩ+4M]Vf83 DϺfZO׍ olxGcr3kjEW0+&ӦoXTkf&mԯ8{i¿|J?{7mm/OSjҏy{ Ei<|@@+.:*ZRl;"dY 6dm6@-`g۲sNW)))bnM3> g7o(**rf۠ۦS]Dجt1ft˦Ӷ=JsZ?h\fˡr7߫s+Q1;    p vIڻwSWW?j#j Q|6/IIeo6w6ogۅ|zAsg[Dig2_v˿hYp|| MU/CP?@@@/E\6;vքG ^VD :?DuɹY̨ʬTYYcǎ9 lΉZ7L2|Py5oֳyEz[&B@@)cnI퓙֥>v6-QٰY/@?x+j"Q.ƛ$///w.>ղ9muqqJ aRu ^⣊Q%K S͒@@@l*W=~۵k5Gs׶r ~">|X;wv>#B ^VDh}BBh9O`OI3t9M@@8vemJEwtמupg9s:&: @;9|#Go/t]f<٠4O󼨍    !@}uww5G*gm>:ts'v -D`KZH   =AE#@O jV=~   @HjQC@@@@@ ÈO     ZEi@@@@@0 #>]#     j=@@@@@(@?t     @Z@@@@@05      jQC@@@@@ ÈO     ZEi@@@@@0 #>]#     j=@@@@@(@?t     @Z@@@@@05      jQC@@@@@ ÈO     ZEi@@@@@0 #>]#     j=@@@@@(@?t     @Z@@@@@05      jQC@@@@@ ÈO     ZEi@@@@@0 DoF@@@@>՞S8N? !ܹsۤA@@wGU;'V[m+**@lߌTE@@@@B&`s0?dm!Y/୨ N8+9ZiҡC_ΉNNH   N<,;w#jQݺu0JA@uu>39 $$$Gqnu***D_ .W''@@@ĵB=o >@x >s}Ό4uy\p?Kp}:իwN!  穀w:vx p ψ %89Q @ Lǟ| /Й,cSDDD8N?66VvjϞ=VϞ=t&t   P_d-&oXJ.m%ߘ @.`{NZ{?** kΙ8P;>lߦt۔@;wt5   >s'x^Pg9;\>JQ@ >6O,k6oM{7k/؇{ݻբԚ fЊhه   Ј@_0X 5l=UOS婍WbX+1t@ ؙJOOWjj/o_wMl=7}v6msBg炀[?2|J琎tAJ M>G4Rd73f>=*"  mAxg5oplzӕً@+ h h6'owYO vMc_6= _*_=8({"͚w{.JEͶXkvSc>9Cf;|y闘#mY]UߪO7)W_o_b^35iRtߦB{t|mA3os Li[uf  @Rbbuqs>jonJXY3W(wu=93l7/hB?xԤEz|b9d'}ʷ3Wv;TQs29;7* s^   mY`?iNƤOWכ=UyiV@u39̬5.O7k"\lɘr(_U+~zZ8 <@M]E]kmr]ix{NLjoyc;^T5b=`SiaA5*3w% Z;I+wyjo?@5.۾e۶}ؾ) =.VOSOK/TD㼺CCkMJw6jݔ^bYߚ@V<|Mv+@@hީ&hĉyΞ +~͸ڤidk껕\/m=S;6^ -ʙK-N_Sۖ23;;л| +Ӻ{|1|S2f]!s|wؒ=/ѩ mذA^KT7-\9W?v3%/MiSg/Ҧ8@s%P[[,kg柭]Я+rYdb9W_?oCg){gTmܤ?P}7iٶ0C9z6;{sA@@ڐ@ǏWvvy<[!i+Gkgk}y;LH~k}gcv}0joʳ k;7w/Sd=zeOHH8gn5Aڱ@5KVzzҒUr{?jPV|廏K$w lY<8*u ޻z筿|뉇f7);^y j|*':lvM9;{gN   WTirEƩ3Lʛ5&߾_*2CJ_nwdC5w xS-Ӗ;=B}?g ^^{Y3~TIzHeYMG<,O%ٓL5;a-I?~`_~1|o*Uoi\OPޒuʟtPqC- 肆; [b y"`ǎSڌ'O:}4;_gĤ4 ;ECF ncMVѬ!J=t++;Yf6GU:q    zX[ް!|S׾*oEjk5㚅J wsm:SWRԁWku\oyIffcM2B oym[cd>hMXbR7PI-dS$ݦ5T_ԩ\PS^£.d5*.49:%)9w5û}xu>~szD@@L}{]ۇK}yvT%hŞ%ˆgCm35qԀ7o@)`|B ԛg(YgA@@CTP̄QqO9{zZ>#bݝM>Gjw јw3ЀX/ީ': &nidyd?iپe0]^lP<4UGNuMp řn=zn-={Hd0-2 /1j(%|Q5 ǩ\;_{ 5ohˆfS΅W{<іթnH}!J8ܟR8@ u!9rDݺus ۠mmǕ= Uz̦7wq^:5_>)C楺 󲶺7memwnTh޿?W=uųqqEJ+ U{\댣NE   mDz㝄eգs<wEJ4Yky[Wi(_(W)cV HIH7>JL{ ށN͒/nMjֹf@0:QzOVpA&?Q3d1[2rxlyҖOﰞ38=[=A+&[SlmJ8B;2gB mB "¤霨b'Ho6'ۆm>l۶WD]voKcOCvUš|?v7K~͓QO*M*xEzˣ67G_ wnlxW%-̽w3}ڨEkٲeZځ {   К"%Dƛ(CV>mM ))Qܧ9Ջ+oT_ "3~ݼuf32CW ~'5j_{sFsHtn۠wNg^5||[kS'ݦg^}})4B _7:ug2{Ծ:M,j2҆aM6- ãK@իW;]{]O7Aͭ_x}ii8o׮)d555:Px@iiiѣ:tpF}A'N*((PԞ Ʒ"=zr7y9]?OBor7u-yAy.T{QߚLʼU/<JWsZVֵ]Ν;!2.@@ZѣG 9TWW룏>ry;׬*"P7`6PSr;#D_U*; 7f8va>}uNwc qs0ؘͭߘ @&`]tч~ӝmAMvAi$gb~C@9.U[MſYE9ѭC?#R5oMt2DKm_nsfjSMs@@ZM!uHřp w=Am.0t5u *o~[>Zk~Fg%TK[/N[p~ JOPmMvءA9zķyEwؠmGJfG$iytl*\Gl ;uF&D$ӔsuCoDDD+>>s譹}kݑ|m6mWw]L{x~hfL>f98}-դxaWLTۛ   @u!iէςJ0V$V#c #`g۲sNW)))|7r[w 93mmөx:D()5MެAEumP~TLtCA   A܎;:)Y{}n;V%` l& @lg򗔔(99 _a7ov]׮G`/ػ(   -G ..N:mv :v ;୨ &u~-ԩs?:ڳQYMRǎs.oΑn@@@Q &&F:i߾}2ӺuG#QٰY/@?x+j"Q.ƛ$///w.>&߽oeb=I a5   @6gڵI՚bQwmۻ(矀o,Çչsg3b?+oEM@ `'$$80   pvemJEwtמupg93[@;9|#Go/t]f;٠4O󼨍    !@}uww5G*gm>:ts'v -D`KZH   =AE#@O jV=~   @HjQC@@@@@ ÈO     ZEi@@@@@0 #>]#     j=@@@@@(@?t     @Z@@@@@05      jQC@@@@@ ÈO     ZEi@@@@@0 #>]#     j=@@@@@(@?t     @Z@@@@@05      jQC@@@@Ϊw8s; @(G֦gUZRFvW*K3(;6 G    @ 0͉ ^W@IDAT@cC g}=9?rtxM0A>^KdcLx?!@@@@H0H(s @& gIfpfd}B叴[M]OkOGTAMN{ }nj)   X @r5\h歏gIvЙ//-U<ͮ0 TeRF7f{ :Uٵ'rS^l>iTkV:+2rT@~k]|.sVMo_ş6d*@ů-2mwSUPA@@@-@c_z$f׉yꬩLUd=$U %? &ߺV}sұשS)xicg鶓w=c/Ғꄞϙ:2ux;K \\/`L#]+cNN_{{ggkt)M~؇*ۿ]\ͦ9g@@@\߹7E^ = ]K3chg4_c8Qvo5ӺFNGkt8+ih??T_8G۾HU&f8Ai Ӵ`{T~v@@@@ lw"I!mNxiıhO3~B'v,=US}_4krq &q*ə_H|nirj= owv5aE@@@$o9Tƴ}uo@@@@{  #0FWǧ{ W}ozL{3TX:-sc%Ge(R+PU;A@@@㲐 A=Ow߮?]_?֜9NЖuBVm6]u/wӄdE@@@"⾝NO@ j?>a-\cJ{~}zg?1ovx OkKZ mWm    \~Z@ o-//uiv) |vX}=ta;_wSUUUkT:xy~Km ۩?,kddC@@@'P{@e BHNxhztҤWPg:>̋t=nz; OIq'ȾI0FO[t)kkGs'L^׵KӌSg>M`!@@@:#;ν' @ l}2o<8*?zb.B1f]6)JEy,(R=wzOK$5tL|p eff>')nv9w/Qg֩+:    бRw4ŗW윞1cFC8 F˖-sj>oyqw 55 *׾}f} nN[f**I7vBU*-/rj}x.    451PY_f@Hx@zhֶgV ]\G~     @@@@@:t3      @@@@@@ @7      CTV^*UWWU@@@@RRRեh(7C: (QJcff !   @GB ڻw222Խ{wɼOG@vAKK.ڵKȈv9\@@@+`6XG^:d@ODԀӝ_~п#   (?1밳$F?mGQoOKMs.   ocաjGnn@˝97#   @ X]>u#wv#,`GۧFpy@@@hUH֍9ڍ@J^ݾ<   $@2>Rܖ!$@qMMMf!    4c אgV!     ,b     )@?1 B@@@@@YF!@@@@@SbZ     @7B     $ļ/ @@@@@f o@@@@@HLy_h      ,6 !     *@@@@@%@YlB@@@@@ 1'}U     4K(     @b OB@@@@@h@jJQ@@@@H`jxͬLZ#RRR5K.Χ5u;=    tXJ~WVU:TxAo d1ǭuR~ulnN )/vclQjy@@@@@ lpO>QYYr(_znwGi /lj2Ti]:C|TyM.A*%An$@@@@@3 ؠ 8PЙ)ڥvw(=a}/ &;Nk͗a)ovm*P Ocq__o@@@@HJ;?tC&_ {nD55)yشOtz w˔~m۩qYqh%    #`"_ϑHv6h웥tλyB^y`a6jݏCAz Ei)G#ѭu4@@@@M؎ӧ(`~ݏ7 ۉ` {N./%oyoy@`*f+DHqYHD@@@@dߊ g!dhoGm/gF;soͦd9cgHMl~zɜ┓f8βL/U.mhEG,C@@@@$CC4o7off_m wǧi忂zA'm~[-fxs,ZWG;ݧ    tj;GLm**|_;SjjLUnqjẘ6o6z"Rt]4eDaTUz_z/wW~'x,? `@@@@Q k VnOp zÁz;Dڛ;t'9؀.:164}TU Řڲvs3C{\qNG-XZ'9D@faʰ+$V5 u)#a\ז,ԊuoҸMTe,+n5)MyD1s;fd18ߚԶ`3d~N@@@TXS'^.ri>?ۧm:G ܧy؉xg;I{!8W=!}4}keW #\J^}ll A8Bhʭ5lp 1GOzྜྷ_BoGZjЊm [Uxw_*k װOC߸~.Ҹ14*nڥjW^Lo. ל͵>lj*aof[2@@@C o酧գO^|X_|7~ig[α(hF ٟs{ʥ;_=ͻkt;zs 3."@0XՎWoi }̫JTGˮ#b 3>7,W<~u:+kg+8g6R߸#?|-U5Tqsږ7,ps/Ъhx!  @" 5݆}' q_,;ު}uBv'oFj/owͰ hiv0҇%5Nޢi*'ݞ{Z+>4#[s/@~  'g/u3~.?ohKƟihՆ-Z"nƻiOǔkAP[_[a~Un|f-,r KsG o 9@@@ a2z꿾p?+3T>Y1ٰ 6~߇;RTLP̌_pHE̓&o.&߼i1o&Җ{e+HNOc!3ՏeOJܸ7>=f&oM )w5`_c?5W)EU|&N~Fo@(Q?},QWةzfL?\Wݠ80]-yJ^r'o.WN5V8_1oOӘanп)TքMÿb5*Ǚ>S|^7z1ťMrT֜a| ңNmyŋ;]9C&  .PY\~|EeSߑ_wfЌu αcm~#/:8sk.|_onwkW 9d8O3\SΉR_٤ӑ3ߏۋH &oFA-:/U]Ϳ-:>рy@Pf,OA[TN'ok2f_ܜA@ 2r5̴vI];+W#MWEFU& kWJkaO }QW|]xjJp.o~6ԀW"㿭Eew9:sS̠*xmʦ'quN7{oϼM<Ι~fb-y:ٟ3mLLнiJ 2M n~P$vsѳ L *ƻж‹U,qw@@PZpϣ.]48Q>\0QϽ_]_7 {7U?豯̔>v@nHY>NaĿO\@C`njݪ?m=6`3~'t7Ɲ% a%;7omu;l>^<kzZlF}ewe_ݑųc͈y`o|^ Ϳy濴΅1I<x۞[R 6p g k ?CcA:_o2Ui}lo7Mh?[ڶwz4;jFs@@h4}hdΕ<)f^~^c͛6N4g^kRK4ЌkCz]SƔt>`0V g@]`p\~j(uu~9Ƣ"1~2=:x<=s:]78BD8vcfp{gOԽu*o33H~~4o^qiUtBCe'l]7jY rUmDƅoqPCS҃Em+٠~1)Zv#  @ d;{Ow$X96 o6$oClΎI3_ՆetC^)pLVc `8BhT5ن?kSZFg|luےUZuYhg]oN]yLk7wsGD26jϬNd\=Rꀳ5o n/5zc >CgL1\`WiINsOx;{c]3ͿQkZ"7}W֟~qM9ezZ r{ "7m;׿<1*[];"r@@@;6oG޷M,s\WCf~i|wu@@h@.]={o` F&z[oTu89<47yp`Dλ5ܯz{w!@ =kZxZc֝wݩyӎi_ƛŌn3A֌?[O$Ojc>LwLŔ]  t Ԯ]:P+T<&`oiy?6͟NcS}{g"yc敳nr4~Jk@OՓ.WP]=au oMӲ;YqT;C'kUNTu]] J@@ 9]ŻuV ]q[m@l0?}oH7yNruk㆛}es $@!1,`v}PWݲTBޥsK@@YYYU۶m3h!W?ocvkMF]=)7o n9g>G?ګ>"#t2T0t]@@@CvM6Xy򔗗'6[ @~9#Mـ9;LfpM6ƍLl ߆3     $ݻwIIVJ3|Ȍ(/{$]MfFm*_l-hN;c{ch \S%)n3D@@@@c E~322dUUU|l?^?^Zjޥ̿Lm~ڇ9iii|47Y@@@@H?<6+~;I?X2O,7ފ     6@L8 nMl3މh3Z*F@@@@@ ?\@@@@@6 fT      ͹"     m&@h@@@@@#/@țsE@@@@@LR1     G^7     6b@@@@@#o@@@@@h3mFK     yGޜ+"     fی@@@@@89WD@@@@@-#     pys     @ o3Z*F@@@@@ ?\@@@@@6 fT      ͹"     m&f5S1  P^^ݻw=:tPjMKKSnԧwWM*Of@@@@ ' @'ػo{ӔC*55U)))RQ0'|k޽ճWʓ @@@HFxh3 Hv|zJOOW p> ۠BzO}S***rd俣    wĻJ@ ` }FF=6};=PeeS_r6n *dÇajdV'CUz=Dtٚ; C   tn# +p3~v,eff6cز~=v [wcҿV&N0+tӯ5;^U՟gBviZq*[PE@@@@ !I-PQQ^]tq>}mY[].knjP|k{Bt|6^n   t6_@ Il>''I65>uںܫW<x9;zYʫ/    @ 0X@y6Hom|inЉJ+ hcх:7hx[x!xZWiOч[f J ('VU<Yfe H*Cu6i*'U9;r| dڲ]{KL[2~y\+tv}WAAF75 OY ,w2k:0Mz6hM;1   D)\ 4Io͠q[gF}NSry:~uwʓ:1/yV/Dʍe?Dc歁;':kҌڷIg2Q-8}t=[TRqӖۢqZ{{Lb-̷-ݦf;,6QZuÒҥw.%g N   @:hS#  458__=қ\w`Ι=ʩjT\7ԯ}^~t+:muK4c҃*Y8$9ʨ~TNl:A{PKVnyQMp(rdʬւYH&FCFk$w)+k=9n_r =feC@@@6 T 19H-vq⿿፺s#h…^IvZ)fz+-M[U?7jO}28s?/?Ϫεl-]G~?XFY47roۖwU D˟\'_bZ=w}zkUbfzZyZ   7F@(bisT+; &Mqސ7΂S4dt=:=Tл?G~0$37~Y r&7_SɟXǰsu# ni:[uJzǔL(d&w!:J=LwBTG OUר@M_#yU"ղ   '@, @C LrzXU =p雧eE*ڱC;O ~ivcqg'wxP9#m/أ2ldwU7gP ]ϽMۊTZR  7_fFH_M B~ouI@@@@`q6@,0sT:+ʹ>+濾A#roY6UcGKAw;^dCA}=EG bsdQ&6}:nwo]жbEr mF=vS^aZn5ir\WTLQTvg(ޤ5kh͛*sFcձOeu@FNr;m6yߋ:&@@@ _/ '@#>Dyz']rj?IsGoT~Pf]\3P6jѢEZ8i\ҺG҃ϭ~;wO[:m0"-oLKlRi*Ȍe.ˌ^ܭoJKmiVB\ݹD@'M[=nb6]{B;7r!   @vDhC.]32jZR555Nlÿ8Y_U1J-rSi&_4筀%Ғ`jk}Sï||Nź,yariEn[*Po(u$6,Wy{`«|iyQNv#& ;hپvm$    @,:m@dffTΧN&&:m-ٲ9C3A {LSui8?sIhuF^Ԅ H٩=蝴@=&ծzT=KP+}\Ty!DQjuFtE4g2;?t:~=vL86df^sz[+    Z)ŻkU/;g̘P6!e˜ϛx^+|BM_|I{niذaJOOwܑ6 [lѡC۷opUU#ed*+B!UssJG~- UTցtС&A[nӻ&'3    l^@ ݷW]iiСCF)( O>w^ `٫QɄ   $dkv;>P^=տ+8mnPH=zЧ>)9uffd2@@@;]O @dfejN>##Cv?\ ۏ)9SzS $hQRf o]3g6 #   @ ߹7EF@ 8Йo]k7%o;l؏&N4ɡj+0saeqkyn&]YSbD@@@A@/ƛm~Qۀ>@ ںBYPp/[MW6oJM˩'@@@@ '@KsrroCm [y(| -ԛӒՅB-{yNѼKP @@@hR@ml.i} [ݼ-G}VH޽{kOqe7.qN<2wFH^t<8׀13wܶ/*G%fڢn}5(/ΜB jlJ@UEʃRnnꞕJi2ɶgOa:KMZr:n;    h͍|$Z?h @inGCk5hMEqJs&_0UO_j}\7,cw.%g M􎲵O럾G7,[s~ȸ ?*_ZNCf?ɯB9il-s.ࠪX/>:_VڷI8kIC/TT"   @" 4wDmA- ƣ4f&yްV7o3-e\#*dww/g W?ˮzZőfώЗJ\?uDQ4&?j(EnxFU.   $4@Ϛv۸}K߰B W㮺Oa֮YK5ӏܬ?GֲN~ӼBOꗯE5cg7Դzδ;ڕмqC"5@@@@ 9'} I!cN"@yʓn'-M\o@M_#vήSnZv%Jﭱ߾Us/DboUwkZTS@@@C{sM@N!`5k|ʐcǎȬxׁ:.fA~0>|κl{}XߛT}w]vVރz @@@Oz"@Ҷ{Q>Ue ]l:wg[ G/B -5;n澃D@@@X dU^.;zTUnUT9uΔCu܄zқ\_QUT<u.   $dK@ ) kyqwL/9:k Ҭ3z7/m@OGG[LSk*u7a}Am? ) :uں:Wkל۔"q4lt-*-/71Y͊ 4kǫf3SC>^+c߱TSK<k[s9P]fORf{YmA    :[ǑZ@Hrz 2$G@@@u@@@@@:s/      g@@@@@$t7      @ @@@@@H;ݤ/     ^@@@@@# Hw     tzG@@@@@$@#M     w@@@@@:t7      @ @@@@@H;ݤ/     ^@@@@@# Hw     tzN/  @UTSS/4@@Hb6ot;wIW@@#)PYYrʪJU/_#Gp-@@ \]AfJeԱ:%/\BڍE1JA@ '|2tQ^<[<   @x᥃mPMʂz{7ݝK 8o;H;ȍ  A8p=H]   @ >SACt8:{6_bg8߿qC2v>kjRdoiџL)bvf3( tV;VvA@@@G W۠}t>oS9 yBi@I=?A}@HQfZQls  (j7o;O>O&@@<6mx0 p[~vgbLD@@/Bq  [39p7fRL휱S3w$ݦE6?dNqI3}gY KƶG"{D,C@h@)3L[м<-umk4o$Jv^R@h]g\{nfj5\ 5㲨iH)%'5EnP('R\V*SG"2옚\l_޶wޏnz i\h7Ўi5- w4 LS7 lKKd@[9@Γ֨?O.$A$@$@$@A;9Y۰al޵ ߌ]Y9/œ?bs߆McNYIQdڌ 6h۲p(bZ2ͯͻ@v_U*Kn @E(M_[\ierkB4͂ѹI0)-$؎m 㨼P*Տw6!  p”2?el,\":%rhdx ^0u-}?_hs#"[ FcПc^,#qV/EKsӞlĻ {#%R_Q(QlXj\s} 6+TڵL|2,G$@$@$@Uڬ# 6_w {Z$?%NMK}iHuZ`N0HH*(>};3~z퓹u*u+5Fkcz>H5;<c8\֪TY*Q$ =~oe]9-Ě2|,2f'csRRG6J%ķ7 CKC GXm(1讶 w- [ c_kg܇JmЦMSkg=VىW 7c\pS\E)˺6'ٹlHHH"_Y;}dA@w|eҕSE8R}%럔mMUgo`h* (6 H #_û3%z;7Yf180TiKm[c?tcoe=bH>5qUPhd BCpк~) qD1GԆO/xxBӋ_obFVh,);],,'om BdmN?1~< no4! ܉1>"c0c c14 fq=GH};|vs*mga\Oצ<"HHH!]6Օ*im_?V߈<;I:ET aɗ?˰gg;ٶjVu\1x'@lC$@$PiĂyzOcW7kvmY->8VىD4na%lX5x^˞ќZ-ZG|t&LpR"kUoN=Z`2 V,׹,D kxj*FVV8 .wySJ^ދyGrTd H!ڶmî]8aQ=zѾy(>zPنmF;c#ޅmU]>x)\_<1;*nF4; *1V,z j~v:.Q^+Ηdl"+a1d w!+WƠŅ9*Aѯv?=1ڕ&Oƣ\N=9WڸuGT(44J'   IWGmC^9*ڹ([]BdqOQ_&.UжRQao l 3x'`*` T0=+5οm >kkRهsGckƬaJgO°fx*k/^t&ryL(`į93>3y]y [z4.KJѺXAm5_H:i|[|103,G6}_KcI$Q/<#{4wfo< @&P">O?2.R$#HE;]W[d_OK"oB_Pud1&vnqZ!a @ee&Cva_%n#[Vi~lz$;nVعyvR O\hA,\١ٓ Ue9媧}/yۂbgc(X=p7cT #G>6kbOr0eמ==X˃](9ٗZY? Q(9o.빃*obkRu+#w\LqwqƨO ϼluȜ|5|V\o]o*]\瑩5WkX>)U6^TGdDkJUy#]0>=˩ۖ$_7]\Gƒ]| N'Mk^r$;6hd/s>C٬Th۶-w\'a+oSnnaq_M&o1G;gyyX-K$Xq±\.ڦM:>"`_x?11QkCUvh73Y jZ柵rTXa2|T?~:m*X F lu%   s_ԬE1wߝwJ\2N"+4E TbqWTy+NJMg= UAz1 x PpW#5Sj:E.GdigX۫AMr w-`D{י3lGX90^bXp<Ɗ 3ѯEm%x*{%iZXEo\&bI)x].{&lH?6{-(?#O~BmwSqu<47ʉ1o˸Q3A*mIC5㥷5E?WVy70q`cU>Εm.lޣ#8 TزWfrs-ېGDqڳжtcRa[; F,,tկCu߆G,FŇ٬0L퇰<x\O?M.V {L0i?x_91'ܓ;C!Fq0l ]K㨰j_Vsq @'\A+ŬJe^3WZQaKOO׻-٦f2xt'@w&L! du46$Xfc ڍZ}oe Wu=Ŗb%ͦWY*t Fk 5kǥuZ?7)&!v1gqU9ҬCY.*{iyKjg5j`JR`Vʹ풒Px{!(\w!Me_#[EYdSk{DX]⑖YH+LQTma<Ԝloxԇ?|(_5ύi˝xUfAOWaW5O+0]YvFu(ŢIW,LPWZM0wDMB} ƬZRS-Jx!uߟgNYbZKqgEKWr%/܏Ѵۃd:5یxd범=bʕ_kr; kw~vf?nDC鯮ME4V<_:*7n0ذ?&O96^WI:9aJU\7yz& @%Y+}â_w=(VV ' 2*n%‘C  oE7 )gaٚؗPֺ~F(p w]{W޴)mǞV/zޓwcݘRe3L,WjrDQgDoa7ޒ0˭؛6sV>vSd[Ib{fc]?W'4{%lؾisҰwӪfѫA_XqԙfS:@ƍ_\,6(/Rt'iHKۋ _1u{JQ&Dq&Zkk4&6/_vPΣRƉXֺ`h^ebC.LU.>Eecڬ,}0wV,w A2vbsR4)+mQr[-fݞ]׎OˌՋA\\bC-Mu7k~Zl{7 AX5v0Ɖ<1͊ [ڴy1kŃ|y7.s\θar st=rtZL7JoSe͏VQ9B>y+DHvB$@$ph_Gm,;Kߜ тXo<4}{H)׋^~XЂk7ð>VH{7""F})[;͓iEV˪wMGF^GYbD5킔vf8qUmZ ^n6 on)8#7݄7o}tQ;fVT\$;_뢹):i7u=+ɑ}134[}O׭pZ3)M!ڒ e o FFC`oFtRv fϛaOR kdS5rQ}!vrY|˵6w|.Cs}%DXT}F8q'O`l_WdCo.RD/U'LJ}^+ $$Kv| R?6XWICb}_[<]=]]j߉fS5MDo`J٫B*0hgEv@Kg;.q!XgJQD+9lыgb/ _'<>q 7-eSͳzơC!pGW>Jɽ`-rFv@We_k}U=$v놨𺈎R[4$䬝j åGm4|lkoݢPn4jW F<0WY=E0HHHOſ(5:JDS_Wߺ0؞kc`4)~i8!#]n7J1T]MG^>l]1/?.3;b[4 ҽ9ivBݷfK?z=7{d>F'6t/6ܝ?K9-yM*,ɫe u.H]pM7Xj.8>BJxTu+YR}˭s嚈Qಮ׹qV^ƍص"k'|~IȦc71^%=)FWKw;®CV\8<0QN"QH{P rRRP$g0 AA+cS\׶abl=TZ?ah[9ُߥr˽oSw=CmlϱOj!Ș`SMŊ?re!m=__-6jw=j9Z+ޅDKp_u20F$@$@$@1WySDNK~]R b71+9oId2 U+w R~VOXmd1BR0HH*FTt#snsߊo~n<7_r0,w+~t1Fuv提 7!f;qIx=D7SgZܪĖCO=["5D_ kCpUF*(}Gx0x=}!;R^OrTv.ش~i9gپӉUW]on<<%uZ=7tBl-tJ؃M50a.z>0Ke8k=h}]s4mͯkܒRFޟ2T7ձ` /pNۦ(54=# vʳ.p]"csС+F[;ŠGl4U j~`4Z߀͛u0L\ktfT!R<}9rnci{ńIª>zǵ1,~!ƥV6xmr/c1Fz./cB3HHHW~QˏSrJgE׼s$.}Թ Wf{fjS_CR'a& @B=nwL`\jk,5\\=`*n4;ruMP~>,lƎ}T쨎\DQ,%ŪO 8 6}R6Gqq1ۈ&Z k1ۏ{*‚#/_,ߥlQ;7qӑLzVQ/fjU7l muIr+/^\x[W­  HrX9׉Wo.}y|k)%Vw*KroQvg.Grbє_vsм3XdZZwk+k{íRYfFXG0tE% c[~D~Pkn+0uik,7nwu_$o:<28շ vwD\Y#zyVF—~s\&5CefZeax̓|^[UKth6 D” XܜjX v+^sð%(LDF˾^\-5y+6ƪ 0x41ʦ$@$@$@$PD/y.bP5O|o9?XԺ+_(RGT*];0x'pQR }v~  F`ZW}io-Zbq;s\ڴ*4wEʚ"7]Y,A}HXkfQvٖnD\gI7Ql]>UBJBUۣbJpSemZ,^}Q)T;S[-a9OJKv?S\ڛo5jK񧡊,[ C![ꚡ/VmXO,# =_YC jVƹUYF6 tk>?{ML~L> }bݰI,\k:o\^g!X|@Yں1\=5FG \"cjsGMΦַ'{o*`$@$@$@$@$6(JA6Uu8izY8:|=O}h\'o xn$@$@$@$@9Kuq\qh0fN97$@$@$@$@$p8-.~TPGe6JW:׍)MiesUIam+uc3*u*rI3 x !oP9rDC6HHHHH.P~7JoWGiqae櫲Z][}ܪ'y%RG<&6Sqſ72L'   p#5w^Ĺq0HHHHH#*ҷwMSfoԵqmG>.S⌻OIHHH ԩ#gcEeшzHHHHH$`ⷻ汓P,7@}m!BUOqB9ܭ?!E(& P sHHHH< ETTQݜB*_ԍ<$ٳ'    8 륛w(抁y4ک@IDATrW9VWE5h-Rn.zT_(W$   PAkԨ"$ !    $]%Q};QHH|"Jc(a. ?88X[8%;r ~HHHHHH'‚WнOBTΊ%IHHH\_˷  @%;|= ɶHHHHHHHHHHH P_ݓ @ PHlHHHHHHHHHH*|= ɶHHHHHHHHHHH P_ݓ @ PHlHHHHHHHHHH*|= ɶHHHHHHHHHHH P_ݓ @ PHlHHHHHHHHHH*|= ɶHHHHHHHHHHH P_ݓ @ PHlHHHHHHHHHH*|= ɶHHHHHHHHHHH P_ݓ @ PHlHHHHHHHHHH*@p%IHHT~Ϳa߱PRk82OK4" #pŅ.qQ1       8 P^TH?{jb ɧ\Np:~/]<_q$@$@$@$@$@$@$@$F~ܐ0HH*PJp8C`ƪ櫩mPm6U $@$@$@AEE%    Q  C@Q!bﯾp6T[M"Qd tE91g1(Y"l|U< Vir,\^T} }D1W\Sq,_ )濐xƺُeN}rV^-JR[M%Y%cw&U, ,rRnArgcLTgYs@h=?aΡPT   8T)HH u,O`ԭ҇HNhij Eh(3X^ʗPV]DGE凒c>|1G#R*#5qc(Pa5-"wF$:t[r,Ҭ郂#P~ K(}]VG`:1Q MӋ2~@lD"//~- ElJ<{ףPOG;d<:r-KyջGՁA< (._:[{0ke2WN5YBo۠qQ.6]KE1\:/ ժˢYmjp.QqԺ.%s^z*8&nHqs5<ER\HcMRdנ>yY8(X DmRn's+,D9dUQ__㘸"ܩ-i1a%8պ4\cHlǎ r#]T]\rE9C"<],1Һ4?F<+eK/Lڷ=̦0|02%xshԱKau*򫠾~5"j]"m.c SVK~;z*֭:嵭ڹ4S   8 P_bHbtm*. we YR51k ?=5^$2acvOtuWx$y;%Řnvږ|y~qAH]X鑢'>}GjmS0cuns19,T(a,Nיu,?{C8,US+Ex$;eY'' L!aSI-''GӞWZm,f׭c;q[ϻEI.T^g)A&VgۯJ)Uq6tƅϮWsYk2 3ӕ^&ċ_rC4Ko!~ϝLK(>rXEPOQX%tcXSGo1H c_Pڔ?v0o˽5Cd_6o^!d,ʛb3 ՛K{g3"|$ڞVHHHH⟳HH0rtI(>j_s@v)ܨ6BDDD $$$`WCz8Z1UCA5;, ;#Z)&%Ǡ- t=UY F-ytT!U;A_h)3b) r켡hc*иS/ 5l.b'bL0`Eơė :ڔkKĴڶʊ-/c!+,tsT 8F[]#h'CqGjC5ݑf#KbhK[.F 7F:шQ{18qhҴ##4wOSX;'s#e_5QMJ.hOg[ 5c۟:!D:?cyT &*(埱S̥US|0;!|v=Zxpng$@$@$@$pv#' 8(E/^n )Q4>oՕE%1zAD'0úEj(H,ԑ-.];2/w %Y/a$h6\^7ʡ4DNr&6smkH4Ծ99ζ>9 xrc6z\'?g3?Oa_љ ֖bεvYf>ʺ$W䞸&2 ' QYbE;K98V |G!661 7Y}1v2y$g%TJ눇y͑7 wo~G^Ji&u\Á][$Qd&]4?[ q׺>Yv*,b+{l?,X0~J͝Ebyymߴg&KYiOE{ qm`bK|O=ڠIK+ES[$12ϣ$&9ڽwُ֭^9|e,xF퍐/0}0m5ʖUޢGCb-;q3F$@$@$@$dDE$@$@I@)7 rs{P1(6[P=kAD֪.VA/-}%EPtRm 9#Z*%`Q!L+.վ4$`FhK!T/ẓS38%%\9lTƋazx`R5K܁x TgyP E.r]s͟gj+܃, DU +,šBrx32ReI<}7!% U֪YH=z#>'dtnb`boMSHUk:z1+ؠzlq ,㊍A,=b3:@%h&t.z*{YL~iKolF=>?g~r סU`:mܣm߭65B=ߌ{,a)P/?).DohY\JhIJ.Ծa0/yQj<-U_^)3QH1zv+n *> !Nfh~]DΔ,xf=lv~.zNy'uS,e~o34[W%"ٵ/эѩEǰ&=cf}Jn~mmc=PHDI/Pw/zXx#w9i͡;:4Pz4\ d/C8yc%Ivn(֜Xs~N{_5rZْdzv?!SThk=L'lؤֹo6\"鮀2MnX"MF*є1kJ#(XC$ C˜5dz:qDe*%E({Ph«C Cq̗/]_u ~fKOIHHH&P>GO$@$p.HmO"W;z5D]+Ipŏ,EЩ#|r7Jh'?'b\w ~MX6,mwY!.[_Q3(ۢ>~5V+%, l{='/| Qu6HN<+BQz'h-ᶖ_H\fc=! _Jb4}**K^OҮ@ _jSJ ڻt3f.nǧ܃3t_x_eADO0PŞHHHH^JF$@4ݎ߁@)C^^:2[{+Ĝu5HHU+͵m!">Wω=Bd?Y.ݰG Dc1@$s6a<*bn@]g!uv KcSTeheW.G+7pny$UgSaƿ<]_p8ovfΜZT_LP (q}:cWKJ(_-D>[zO /PD- ˏ-ѝ+1)~ g!}+F3vp4fgiJ풢\0=e#rC2m V/e֮A1Y~,g RG2Oǃzy|*6nߍݛ«4/|M5/Wȕ{ٛV eyJy?.D̹"aSBnkhDŽs~6Ny :"9$VRc2\fk 3mUzKʒEo³y廟Ju,A0'}h(ӌ7zgAPL %;sH7G)wqtvܵ09|oW<;<*AyhNmƋCz鎃RB/[8QOqdH,<>]"zVf\O^5@4)e|y#9aѿVFvx"P3s&7\dxp{B0*&[3F>>9WO%|{ct9s]aݖdĠHnO+~BzSukrroK/M|]'!z n2N%Ss=/LIڣ(4!#Bhfb@D&NIHTl x+1ǘ=a(e$kdkp4uzr- & =q|M\iW<~*ygw%ݱLBAsn6aq[n33ԦXKAa0fjxxY28*=.sPTko'ØB 68E@j|B:i]CNO9nc5y~z< ĴOfchro'ʽ-ndAok# \.=Vq&O~9gHHB̟?_]?9-ߵ]GՔe)嬨 \(ӧOk) ⡲`|PW w]MΦRXGIXqsւcHeS:Qu|R{J*}n(qi !22+\TQ\V.CLm3M; cJ !Uj'rsqx>JĬ6^צJ9Q9vySp[?ydv;2O{ T8!<:sSS7KP ϦBAHoTOҞݴ<5hw~{UJզjH<$ GL c&OBrO0 Cm<}yȂC"@쟺K ̡wcf|z6{"d-8LHHH.4T_hW% s%|K!6}BŅq _m{BҟJ 5/g>Kw3yxG*MIDԅ O"=K\Q=#*NLD$@$@$@UUJP  4_>=JD O z !{pD0W6y?NJHИ*<;x5>,wwhs\xD9b   HHHHB%ZWչPGqyL@s+x @&HHHHHHHHHHH*ȅ$@$@$@$@$@$@$@$@$@$@$T"           *B*r!( 6HHHHHHHHHHH⿊\A$@$@$@$@$@$@$@$@$@$@ @ (           ""b @ PlHHHHHHHHHH*ȅ$@$@$@M2&iӇlu Jݻ+. -KYd[]z ((7-bqXhZڂi!m$d93d&IL9Ü9u>w]w!    E@@@@@@'}r!h     @8y|OOOlD@@@"0^F;@ B2\@@@8PHnDm@n1?s!-G@@@6a?999̐-3BL@oە=    L]gꕣ @ǎ@@@@ 8!Wv#>(((?> 4@@@F$`G{A<2y dri; @z* oҫ@@@@`>޷o ?wCƙ nutt(38Ɯ   Yf3 }x @F,`1_S@@@9}t1h       OV     H.MA@@@@@ Y R@@@@@ Š)     $+@?YA#     #>4@@@@@d'+Hy@@@@@|$@G      d)     b@@@@@ @@@@@]      @<     > AS@@@@@HVG@@@@@G}t1h       OV     H.MA@@@@@ Y R@@@@@ Š)     $+@?YA#     #>4@@@@@d'+Hy@@@@@|$@G      d)     b@@@@@ @@@@@]      @<     > AS@@@@@HVG@@@@@G}t1h       OV     H.MA@@@@@ Y R@@@@@ Š)     $+@?YA#     #>4@@@@@dV@y@_gfi5    @'pŗ@@@@ #È 4 Mthu#   ` @@@@@ @@@@@@ &@?f     /@?/!'     @L̂5@@@@@2^_BN@@@@@k     d     11 @@@@@x 9@@@@@bc!     3r     ,XC@@@@@ g%@@@@@ Y     @ K       ` @@@@@ @@@@@@ &@?f     /@?/!'     @L̂5@@@@@2^_BN@@@@@k     d     11 @@@@@x 9@@@@@bc!     3r     ,XC@@@@@ g%@@@@@ Y     @ K       ` @@@@@ @@@@@@ &@?f     /@?/!'     @L̂5@@@@@2^_BN@@@@@k     d     11 @@@@@x 9@@@@@bc!     3r     ,XC@@@@@ g%@@@@@ b!   IGݲ,J ++KٲߙdUʼ6fs0\ac@@@@`:;;e ~0z>999  ηOW%=;@@@@ ~GGb OIV;Cm!9\ُ a9UmȐ +@?YA#   )EE*))IQT@o;ҿ477xC^^^AO9HrOV    @ (l$Ld^ړ!yF*O( C؇]@@@@FYzQ>#= W=T\P@@@@ ܎t.,,L"0r{{0Hz@IDATQ25~xRs&TIR    0Bn'j'eA ޳{/k9H<xmIG@@@#d'dA ޳`GsLOρזd '+Hy@@@@  T1p Rr I{n$n"   `yk|-YYJ ${mkmg?Ew{vi &jʓ:?x @@@@.ХoIo@KYUM%yۻ6윀ȼ뗖_V=v\}xd夥R}y'j41}2/a&^5ڌ   L]5i۫/C9?Ύ /7ϜfҴ t? VSSGdƼqWqc :FΒ@@@@V]Zvʙ?ؙ$6K&hҚ;:6u6Se /ϩ؜xբVO.* GjA@@@0`/I3tnAP/y-~}pZCc-WQpwm(ovA@=[>; ~[GwWX]=Y.ow 2-Nk=YATUP꿽Uh     @ dO b!tx"aO$8CK:By]η5q#ꌙg iη΄)}޼q'Y*,-Gy?HU9Ѣ@`     $p阎51Ө}{oyajU{n5prHSk޴HߞnVH3*2(; Yyef$~tzc2f괩<f~Yv/:- njEn ïס.曎֑VR4K Ou|M@n)ot[;Y?Ii*UϫRz9*    0>vieF^Cǽ}Ԑ-NY6/vfBGԲB)gk&O02m2Qtp]F39re.1s?fFOܷ}UT)ĈW>t9thSf%㟯*.ξ5L-o%Y{Zk&D]]7tb i F|   ?"UVz|:|{eZZ+mnpo@yIjԱ4?U,͍aq{z&6~ t6j;'WN< MĻ <{Ek󃉃fanxtť &WfLp-KpJgͤi1~:4?U=k ʲ)n#   d@yZ05:U['TT8):%?'q.ąr54)H O4?ELݹI~ @ЁX--uI3B*u[GEsh";Mnr- (QLzسVo&!VܢNS_>ܦ#S6+ 2zܼ"``0,F$oYkyI#n)U%o!A=lkƺ@@@@`< JT3*rfGwiюYftjϺ)2}ogу~k=yi{NFk:$Q|+ZҪ#Qѽ7LW*UMWϊИhȻL@kgzyrCլngʹcfV$3> 4@@@oESN,{_B`d&L# a[z}ڹsBnvwg)+_fU?[T~$_9RHZQ{|}&`i' T_[#9a @Iܮ1ٯ~f9جǺM~џw3cWUE~0o6Gaut3tTN+OT-5vFNlC;v Lҥ';ENTѭZu(de(`>#^z:wݹ*5Kq5}[ApJz@@@@ ؀kZ,;#X޳ӵm"{¿1GE6vaڱ%l)*I!ZOW&}Or΀z@@@@ #mе5τg=<;(_"UZ5}AYjC4e5Y=L) 'F?ԁ   $)`G:;[$A)>$N޳`t_y}NoA\FyM     0~l~s|#(*.:'?7gb'0m9c {/=Oss' E@@@@R `G;*njmooCU__j~ 0R,3ION Gyy*.*V^^/F{sI=${>Mn1F71Y}#p#xO)"  @$:/ ']9 8ӹdvhJv9HVbq6>Ak6ݧyV.fu֥ѭ_4 R;[h <\kjE#}׆)#*?cyiӯ+3[u+f$wH3"GN,,+U{ykWkoi  d)l@ygB*`1>x-3`$sc mTo8a;٬W-R;t?z^MĬwޫ\ZvN$Ncy,)ڴt;IZV=rP K׵6z_z+/ڊsdr__;M.[m5hsOhI4xb67=E<Ҩ~{՚+Ma@@@ c */MNA/XhyggT\`nsK2'UczB>'Z-0s$>84w9SkkAaLj/_q#zb8JamyL=C^{7;bDKFIGKڞtD    S >~>gL=sKG TE/fš3RŇuLr_|kRWjpn uNkݗ.Vpvsukn CF7,W2g~U|^O@@@@F&0ƁRM9Mf$ܨ6<.O 5TWФF5<%*71pHvc!TYtͮ)_bhRnޝ{tSSNb#6yM!LR9{æPSNi%yXo&u{aaPޚA`wO`*4{exk1ejMtV'`jԮwba]VEO)-ա{ezcϳriW:t7sѠrm|ݐ wxߏ~\>]SC}N,47u47;9ǭ(Vn3;_[6l}sѠ6;Wsι)nn⫺i22 `f4\ûOxsjܧ=yXsNtؕ=@@@@m1I$LK[nR=oix]RZ9.S9oml UϩŋVsfV(L>OVT+ }2X#|c~y|ZUU*Z{U]e:uU=9gjM[fVhOګ'qUcm5uU.ñ0<Z/^l,7eln˗˫VյPðs;ѫ9D2Eq-У'.?~qG.3egA/Go7ߧoL`d{zU{Ή'/㬗,6oSۺq^pimט mjN@64j'+tc- U|r]4_X6>bin? ._mu/i5Ζ!Eݬ'p"gZ1n[Gtf+>˓}:g6]܋O~rX_ކN mfRN=ukӴgӦtdzB{֫5X&U͝F\~d駟k& SŒI^QXn"c-qVw;Mq{|o'7jo{ČЏ\ΦZsM\Z-N4UWtץ6>}M^ Μۦ7N?to"ӯ_g#2ueٚ:fN$͔w@?mII;TσvlݼxNA+cadZVc֭{\=Ͻ&޹~g7    c/0Ɓ:"ˌx m}GUlGʇrpi[?>s(yo#/a\}7uTsF~6b䟻pgZ-i M;7^{c{    /L9Lck,&z3iMW^|RgDvY~"kFF;fΚlxߑ&U -ݷ#ZijhZ_M;ͨ;mlMA^4'ϭU&v!#ogԿeuC7lF?KkxL{˳+5_sM'Η1`Nz-ܯmx~9 ^!M$ fSJgkXܩ>3kT^2MM!    @͑v>l0 ) }˴n2As|¿&:a95O_Fw}b%H}?xF-ר"n2 `q㘉pd֪Oe}bGA;ͼ |>޼}UKj*PW[̹yw`8Ra&V,F+1m >[ZZP///eO|cRܕ,њަګ45oս^hyU+uC    _rGi:X<[wttI⶿ṴKfic ʦ Τʗ-5Փ5qtUl]_Y __Y;cn wґ2`s-pk`efd2؀n_Lݡ3u ' y+ϿzE[a+_ڑ3/D'wƭn!?qeSkO.rOo?:aпYy\~K {خ'Vjmig=»cj}dJ_Ntz{n ^ ? *j5Hj/4 |؉ߖiŊjivjȜMoKzw{W,ל:F-iMלjފzEe׬9sզ}gyKzvIųu٥K~@~\=Vst6?@@@@ 0c*Od2S̚@z}M: ߌZ7g_5d&O535D/od 7kgι:}#N?JfĦtGk7k/9NGԢ2sΑ ?OXlOt7u޶Lg;||5)Ћܮ%f僻o]v%Ps-h֭qP@|v97,~Pss[\m 8R}8q|$~o0.ךGiar z=t,ȋ%*1|u=򀽎v1@@@@H@Xޔ`b4U^]-n#* f)+X9^_hH/>JWUCLn` A3j ۫^ jQĖy"u^|4;|{;=3]n*Oڜ豒;~XѶ9ZOy^'qe(|;/A1c8,Vdq? w@@@@\K4sCIPKL{mԊe0=Xi WܧQqjCi{%σ%n3;lmy.﷮׊^~٬vm ,4i>UBblmk `s.{Ikn]._פ߭B l֑OE6݆VrNU99r1JS>wm]_*eZcBy[w5vAMVpVAy}NpMs@6=t5Qĭ^زz=&eo     7zkԯ7l76Q~uPsCq%*2`inl4'e5wM*ROd5TxQiWUn4Y7KX͍sJvrs-ٍ2>3F T&R^SJT^)6PoGJ/{N{BlD@@@@<.8P߻6؟gK#~oPz"(a;g&\V;>J@IO?A]    '9H9[@@@@@'@?}@@@@@ O9)"     >     \I@@@@@ O=GF@@@@@ SNJ     O92     ) rR*D@@@@@ }gϑ@@@@@HR!      >{     @ @@@@@Hsd@@@@@R.j>Pwe?@4zpT    7F@@@@@:P'E@@@@@ 0G      d)     b@@@@@ @@@@@]      @<     > AS@@@@@HVG@@@@@G}t1h       OV     H.MA@@@@@ Y R@@@@@ Š)     $+@?YA#     #>4@@@@@d'+Hy@@@@@|$@G      d)     b@@@@@ @@@@@]      @<     > AS@@@@@HVG@@@@@G}t1h       OV     H.MA@@@@@ Y R@@@@@ Š)     $+@?YA#     #>4@@@@@d'+Hy@@@@@|$@G      d)     b@@@@@ @@@@@@Gm)=== wu~we2nd,d/ (|rve@@@@@q'WW:a?ШvWPN>l:̶C  hbY9} 4yM'      Ypg Kޮ.u%rFw;#{̺} ݼ`G75ì07`)m:|y^@@@@ Mݲ+xip 1786r"L:%LZo__F;MпշiF*/7Y5TXIeN>??`V$߭PGttjamü1r y3@@@fekkBf`d{G$oGRΜ<^O-b_ 嚸] M:bJyH #a6E[ sM?K UlJ>&US&of@Rؾ)`:5YbR^q{@@@D;kʔ)0q'aA E:ru!8xRtfP=Y׾nm{tU/;"ܿ:C%1 @ԛ5|he4)|ʊL*,g2`Pw4?3`O]LA>plgs;o z@@@ &jrNA-*~5hPQQJKK}u<'EcnFQy(}y; 7mUsK>f֏PcǦ_D&ác5;TYYܬgn;pQaZZ{3L  J*#   61;SUH@eEԫ̛zGRH(Jt>ir_z'sTN(qqilo&~!g'f&ඎv}!UG"3ApLRys`2Ui ٴB'NpH.@@@@`,9M8@v-{/f\xҩϱ@:h;Ll& fR3ߎ0}l:֐k6j3\Nyz (vL3o@n߾Q` :Lqӹ`TY]   dعf%#itR޳ӽ< pt>i M^ycǠK>3ovQz}ng]a'nulHg>Ef.t -5A8= 2ys{΂ ̈́%蒅捃)7%    v3 =觶p LKߎ4=fPLkr엕8v{Ziv4M eF8 NGD3B/43Tj8h:dFwìeSNȱ9Sl07;c0     A~i=\&m51(ЌY5*Kx}lf^r(G({Om!Ȋxh99y&Ȫu۠{띀~ee7Ic=ώ?t @If~ЙNGMc"*.vR4@u2#y'7:eP/l΅N8du8M@@@@?G7߯ ۮ9:l /YEرi 藫iZ\zF}va{ e o36ʧ/2iw3?ӎ6y0?OEvf@Iq Uh&굣-@ njq:LGB߱6/v@}[ | 9&-S=?    ho{W̛mK?_Y==Y1oxK7\u|icZo|G~X]ct6mϞf}fϚjN_l0y5N ~ƴ1JM^A۴>v"`Rxǖ[.`T;sk8M:Q^a@@@@&_Ӫu8K3d[M_?H73Kqw;tjZ^i#KVPx6ϋy(!WWqc.9Ͻf&}O 竸 a>l3$f]&ySЌ*ˤo>}l<ր$oS`:lc&ok/o@@@@1h[r:r:(ֆi:{qtm1m|FrS[3HՔy('V8g@jxNL*kfk7G0Oьib(VҊ^V|no?_7~0{}_smޅM's/3gDyh%oeu_Y}߈ۃQH[p?H|/oy'77h:F##m wAG64֖G=f~3ߝ(oG]\ ӼYiiX@@@@+|ۀ䬾aM_~Yz? ޤ'oP D}v*}'Z+-:3Z GPӛԢ.ޯݥLI+)VU0_&/nkٵѠ /TtS?owD mPG;;47 p?6OɿkO?߾C&Wyͪ'L/>tUZʊJ mBȼo1@@@@ NE䎭? IDAT Uh5IA(EI^fgww[wVޭ=/ZtXg^~S߿};cӯw'Ҡ^_n|Y;v07T,?Ӛ(xgMOj:%.#۶dyay ok޳1)5<M$&qMﴺo@DIzQ&ŏn2L@%&PMߦҷ^g7I    i&)p,)Zǟay;>**} +n'_Ts԰"+w:46"z9بCvGk-={[!E?Bg^o E+z~[_|7eOdK؃hn0*t-_եnfr1 5f(';;DiFkCUnlV7Odd hv噞-gNtF 3!   d@N+oDS*}&%ϫ~暉N+&Fͺnn?o4Q*~:lw+4 O{ȗ*vP(]y>6|SWo謖h[uj /¾S^5}\m=l cG;vg2OW7KEy*-.pFqދbmDs+@@@@1&}fԌooSiGd/0Xm6bo1/_\H&*,KtݪO^fl 5zGءU}ݏ/Z`.KӬg}m=ǦC+iNa]T@ZI{M^0#x:ffISX|pgvT'oNN`RPHvlK 4X9~C@@@M"-\b ?k lqhd(J^?cd[k?O_XV-6OW^?PtKJHU>fdO OFOFW{U:7Z4Hjb990@4l7#o 2lgo'ю4w0i"N\=@@@@FO`Ҭ٦r'1=M圾Dc7ۯfݳF\ vz{DLzhD??y+v{zfkRQѥ:c'-wܫ†֪m>g?~TWUU}/JoF]#ek ~ܩ;k yOķٗ^WgPnSǗg=i׎0KtP4SGg8}M5|lzoIB| ȑ&̴+ǝثo@@@@:=+GlޝK?v\C%0MgO꽾Up\U:Cg[ڦW^Piթ_N|H$I՜>}zO_f]ҳtv_~bCuvF~pip^uF巷w~ Ų,/+)4τ"噑&#[B&O( wX@@@@R$8U7BtՓ/'XVˑߥ7ux،]oRئُ "|42@UOLrg%0hg釛ގk_[wo|=_oLaIsDcj_Ky.ZOO}slQR"T?jORkk?(iN[d:re'*L+'[+z̷\t>~^a;uJ     c-0w_9i󼤻XwЈ̛7V?ԵgP3t3&{<)R7^u:]vitcUk_O:~;a xb',t.njZu:aEF-g){жjj2ߦ/ϗ֮C&x1O9yLj3: vPۑ6u3o7/ԗ'    @@}]K8}]ϼ>1wVr'R[~gu.Wmh̩Cu]hznzM>T?zZuW-g.v2.7ơ@@啑{̃hʽ-7<&2\_l&wKϻTkQ߹2R(76P\Y-'5k:P`?nR=֢~/]vѹPb31odr݁iPC޶./ Ӎ-o.JdpqۛUz~P"k~w#Wʗ<\J}e@}0?_"8Q4<Um}^>-{шKϴ=U ]>γj\o} @ @, d<#c-(2,-4(>%s}8'~_+ Bl8kץ<\Z?å˿WwH==g4dpl>yV=Š'eeyܽ}zsoG?n,Z?2,h88YN'@ @\@4f{xY { \p)9;k+r|NW28xUNʭ=b0Λu @ @, ,//_V)?˵՞{ gע03Uѩ#Nݫz>A{"HT_}T2_O)}-L38͆攃nn=>{1=~Vy"n^2 @ @`VǏVY__/7o,nݚڹ7۫J=~<}lll7o7[8}EPI_ZTØǿeT˓?4<+?9>@&@sg@.Xɤ<Μ1a4WiVUL 4Xмe @ @UUoܸQ YOqtb'{18@f\o7Jywcϵ7w^yua&z'PEo?*ǯ@wnEA^NGnW~jx~q'ew4*_|cߛ+?jnt;i!R = 7 @ @")'9ND?T?k>/xfAAy @ @I`fz7QB,E^흪g\ߴ(FrƩ'ԏ~2f`?{åAygu L @ @ @3㿉]7b%bjEc@y{IS˿k @ @&0Iu9E>}  @ @ @@f>  @ @ %^  @ @ @ma#@ @ @N w @ @. V> @ @蔀[a  @ @ @ma#@ @ @N w @ @. V> @ @蔀[a  @ @ @ma#@ @ @N w @ @. V> @ @蔀[a  @ @ @ma#@ @ @N w @ @. V> @ @蔀[a  @ @ @ma#@ @ @N w @ @. V> @ @蔀[a  @ @ @ma#@ @ @N w @ @. V> @ @蔀[a  @ @ @ma#@ @ @N W* @ @ @6 L&6S @ @ @@2ߟ/O<)eyylllKo= @ @ @.ͭ͒Jnn 믿vrttT ܖS}z~ڼy^z[sziӶSsyigmMu1gm>uM (e4k׮lyszfkNzaM  @ @3#0#.7]=mrSs^7\\?k[9{z9yܖ?RAl@~3uZ?7=}zo21/n=5uL9Ns_sMkcF`ggPAx\g#jN9 o67<\ @ @UuoriLok7{Mgzcλ\7d|?3O.كc`IENDB`testng-6.9.12/pictures/idea-rundialog.png0000755000175000017500000017277012732165123017672 0ustar eugeneeugenePNG  IHDRqB ;iCCPICC Profilexy4{s&qS'cq̳y+C%NIm Dr-喫! yۻ޻k?{g؟g6@ pbHbx\g;@@ ( NzyoD+xĬs F"{5 dɸ5qeYGD&v, @'66>0~ӟ`М"b/@GN(?}y@jA&_ Tǰsgg" IiYyET4kji[,^dckgA+Vd#"WZ&zmLl\qMniv'%INٻwi3<}c99?=wg Ϟ-*.%.\,K~+/rU7oݪ]Ssnm]ݽ>jhl|iӳֶ/:;_vuwzw}1~dtlW>T!U X:&f -prrvq]eW\9#-INٻoii32e>}4iSʕ׮]QUuV5wݻAG 3=oxeWwOW߼}IC\Bj@YUM]cKGWOb b77w%^^>>~~3"$~Gn'O/8SX8QRrbiwn wh|iSsKk[ ߼~?26L>L  €{K3$D7@-A< hAư-\HBN<&B`D0H"JO'm&&Փs Wy%*M hYA'BA!A`P=*:L1sbbc'$\$% IJߟWMVB\̟VIEUNV=O#aZ,&WNGFF& f# %-mZۥw:9e8/uG7_m-A1+BΆF:%:,F!5>{^ObƄ6[Ŷl/ۙ;xAgd ʾt49' Sg Φ'[ZbzQtR}Y^įwݸ|3:&n`{=n*̸eq[`ۺw}v{_P0_cKO|Kפo^' T>/QHAs-+68S*4 #'t '"LdeD1JE2'vIOH_d?r y¤P(MT)KAk+'&X.$-ShBxHHIOf1jŢ%ī$b%Rfa-]nrrr &JJss2J*Ū՗iXWY@ZЭYўF.GT_opp1Iitg,.ʹksPsLtwQuMZ}G'˫gogr &~i(5kKc#9-LWĆM9[¶-il]I!:)}J*9ϒ{O\>r:Pse%(,/ʽfvjJQ vF{u\E[~o'뱏1R޲`-ጕ=wшn)[=IܵdЖmev<ݕ8Y(~_4Ƀ9AYJ/mK?O.,7K.10Xz+*4uVVNQs֣~o1\?,Yzd/Iax \0{8ӻ*āyPȎ~./r#9kVGNL$>>e1]:,1v;m IDATx{\U?;{w5Q@K--O$J$ oQV>O-G0i@S LTT=;c`]Q.%|w9gΜ΅BP(& P( Rǰ,ַ  BPd2շ  B<H$OֵjvʕmB}ƾ7&`- BYe΢z i F//~M׫T盟D/=#8{[jlos'-"| FoMF›xdL< -[ 2w)&P*?ޮ];_~FeW5)VLzoOjJzXH!1cȠ+|0nM}lT?&ZN1ww7o>QF;<YS<ϫjLVXXȲl=MzB &b4?q kZ{v;+y׺2 YKkm(yȱ=<4i w P z'~.iI F>LNؠOc```#7K$۴?<^_Q.#@MKosT闞)q1rq)xO[p%%ņ"`(iQ+e$}2ҏgeqoe=?3o4QԨXܡcJ<}v zkV.P\ ;;>9a[|䶚1ܵk={%*VZeee#k.{vvvJ^q1"mM޺[o1ܺW-#zCz2M`xK$Z!;eVV?ܷ6n;͝C^mR͘|1ծ]G=\~uv%JDm[ #ˬSPzr}oH ^T:=^u CT}}s,2ɯv|e`@/{v ?}w)7+NJ#_0]S@#쿕17 뇾ڸ-9AAUVh ^GwARiO0q陹C(UnَWwb`7VVr|FO90 ԨQ* JѱΐUh-49cA_}DL7d[EG~lBc8VY^ q"UWUXS2mR/wɜR cG'}5@ץ -}Oqc qJe{F1a#q*%.Gx @Nj%WT+YAXUrly[{a)I~АU`-2{wWbDo4Ӂ-o?l"8 @РFL _h}]aRLe}p:RYZR*`UѶݯLc""jSçM~&OV/Aj(g-MRYFϛ7qϨ>bv@ q?=@#X?6_?݂й[Mj 3';mAw,e'xܻ5} oZL۴;( * È'!ri?hF;}6;7yT 1{c*Ư۸8eѣ72?ãG W)e[[:U,X0DE\]]oOgqڨw/H2fwΖ2x{^ut[SG![Tã̋zaL6Ezxxp Yi+D_\33DT2s|K#[B !R*K8۵ιsm7r1fr -mVHձe"Y7_/5{ݮMѮNJSa%{O?+9r fM%NLPJ8T Ire^܏)nֿ}~.:׸W.8_v"£GȮ܋zxxx~,m}c%0I^^I^wC!gSɠ`\XWǎ];p(Ȇ!^:v+baL|gE`s^^^0 ~" ZȀa0L |Acx]};w߰r Ĩ?[P̸rfs@KS`X֒wa15uԚ5KCB^3{bz=;;;^o4IS[$J&xjNn|9w^08kXo<io޸IK1uK>qQjZBNZz;VO6ɝ&!V.-K.`I`T"|X/1#&A DL&d47D磈@ѝKǼiZt ^.K7Au3TrE7-3oNt'W ^奯O{\]9%oyeF{]r+Evx[TmF墲Kt7mխvz}aa΢{Z],./LlV4~_s.zFBLeYg|IW^~OPhȌ#>#&LͮTXlPղF[0_%yqThuS;x7<#1xSE9%yZkg%$/uUZ[}sOoOT'`Һ￿?vEkO)N+((x`L1]jdx⏟nrpph֬:u+((({nϭ7ek^bmO9]{8/s%C4FOg^nYbn?${pEE:@.n5 @QQQIv''֭{. <'ky>79>9K,fajI/(I~m{YorNk/%iDBNtrw'E@127&LJ a okv<;r1ݧ?y<lES+A@sy^xJiS磈@X \h\>ʹ[hNܭbXd$@MY辒DŽ^~A1|CVWu?Vpoo:3zM[,6t:K$|:zK Q.~%rFG?6WIҶY.(#KJ KsS+v>w%݆P ͛J1 O[b]@҈Hy 71GU/+3W3u[֋k׮.!g]]R|g_=L ~^6w\-|z+@g`@"q )r UzaAPTz`0TM,!T޼XGc)T*UT[Fq%/0 c}Js죯u}F ?yuƌYԮt^&%`g-vch sZmJ|2C;?szo"6t>ѐtE&˽k2iW=:rQE,CZIU< @*,ˀ1n"c%ʝ?\x šB{9wKxqHd2K.݂{*۾LY.,nsW Aƽ܅=e)/IanF \.zj S=@x}63 B^H2}\ \][_0w*J-<-{V#z~W{/p_ R} =Bv=ՙmvn;`hJ&U=Z0Rt͛lV@%swf8ܻmՋ%;eHLگ Z*rǖl}\Tjpϛl"JV>X2t.LOL]tA̴LxO~O}"w^XV&YkaTl4X;& ݈C;L&ܚ7o.|`Ic,yuJL?jd(xȽvƿ응wHc}`MY(uZzgB,nruՎR9Pꇷ]˚Tr\.T2c$woJ,Z1u N}'{Y5,~y2b=y:ΠA0c)O_,㩾ݳoqd*.6ٜce2 $f")u=dGd֎[xQyO;~g^_yﰢ#~zrw-{[T V&*qwl±/\U_(t';Xs!L&-y;դ{}n9AfM&詈JW2-FW̻ AIɭ&URCѭ5q_풗W(spVUmJpT:u* A8/w1d#,:@9uyyF#DW:8+Y]^!Tj%Pu.suRڤz gFI ;bʔ)mV|M @tphҹ zxD]sTe-w3j'Ps1[`-YuSAeL%]?uTΝHa>\][<_ݫZ-GX~GX`Y]v`Juu:w\o2eU]թ㪯 t%e-=&޲{pYjd2B\кu6A%o=Xr3dUՐ@6D]a"@>_oXܼyy̹lPu5 NI=z4//wD0 آE :e^^x1c.Lv쵕 OZƳ;snUKӞz5ճv*~'$$X.(?32fgW, [נM@ZRLɜU֞UFNtm>y?U  FQ;w8::B!ߤoѾuD"i-g) c```N̔L&suuupphy IfzS8;::ZIݻ6/[ܵe_\~'&wɰ\.ZVR= =!v:֥M'=ɩ~וB[jJЪ{aua{zyy_ & BP3gΤ9;;o߾Ak0?|}@P('_7U GNڷo3"Lrry<yx ciD!1iixXӨPo5 7Wd2RRJU:E,ܸqBT IDATR'''M&`-$4&f ,Fz7QTYL47S( NZXBȃR( Bi<,@ B4)ܝBP(S( Ԡsw BPyw BPtNP(JSݫb޼yO—) x1˗/7K^={lӦ]}BP(J_vRBUѵkݻ;99շ! BTJ~~N B45hޝBP(N B45jw믿.\@ѣGv}Y ~shۺ|ay8rUGWַu ByҩR)˲Ν#plbi+fݗJa]H ӧOPPunw 'P US/I B<̻L&L&H!ugHͽ5X+\URKDZJeNGV* A,?8X-͸7\R$-c ;u( q`rr̙/gpAP(- .0⏺1 ב4f@Br@5"jWpstw圴X&6lڳGh=4 G˛4u2Ө/`坎 cT*Glj~'LRfB7:0;a9\) By0R+ P&Wm]l?Mxo"նz HC픍sE\ w`LԈZ}"B2z\nK~Z>`6G74M^ ź,~Nr!#% ~ҍ;7Nk?w N#U BU^pҼkA's@xMuF~.ʫ) ByV6EEE{dȐ!u2?XFɂ:(5!i9ª5ϟ?_oqy%up6+,,!pvvP( By,coo3ϤZ>iuIcDmnҷ~;D٫a܏bع3bg :zef٧5$2 C+?Ii#t) +WH<,.ό^>?سzȻc +Wya^C{a܏W1?-Zd덖}fjUCA_?/ڗ@'w1}|FDXӁU+K8JAtu>nݺ9;;GoJ<[>F%$+eZ& ;5GyntYO,樾dpqqQTjzˣF*..&4o<778_9I" 'RV€HY-ډYXJ?/n2YեT܈pY\QQM!lU ;88WA1 9E/i^O=[1|尌09aM n ]1؝+hYTkF6@tۡffT9GvzdP[R(sV'A%˲gJO<4ݯ/G'}45&ryE._:sgJ^!Ӧ>hVT-![dt...NNNvvvRdڵG9rHBBN#j{{͛t:Gh̤ڐ 7-RޗVtQ6aǓ$$_`;Z@nh4n e/'DpswwwwhqV{N[I}[͜Աwfۻlds |\ra !)6@|,k"6fljW|ti?Fi){LbknuU#%nRu7Zm?:(꧓S]o_<|n"5risw9ia=zT,>K|hH.n!eEbGҢ B2lĉ^^^^^^'Nr\T\{jOED> ~9͒b@K?74d [.,4&g[% e.x 2ki ̵͢P!V<>8ʎ/l8!:¥\9U՞=z?/ B Uipw;W#Jj5q׮]Rl֬Y;t&j0sbF [~icƌsۢ 矟݂ҜzUwy*$0wm\"KۮOfM(+eض)6x}?.KU!55KΒ?-M VjZoiwM÷cP(JgBa>V2X7?앻[kWv[Mi3GQh ĭ}kmvX^Wzf3R[X̻vT*i{pYM?eX+V!|l'֡؈Y#/WޢYݼ*6ԫwJ府RH`] g"grnz,2dL_u9>;^EWak.K3@sM1_?RlժUrrx-00RT"'''wQTZU*׼<Ưl[*nk.۲:yY'2+,p_e rBc^رlXGU ϧ<7657#Gvtaz?wڅFq[6pbO y~^ʻW/x,fkYeg]=wT_K 9w:5o)H9A$3#p;R릩wGeCb)nJ_fLX>> ahhlNuj  s;dlk*n9^x^1N2D5;;;[\ @ m[/mS( 𯙫{+Bq}t|Rxܪz^hVוB|٠< B4 Wd 7OߦYM9N4˸ pH;ӿN,P( !ӘPU~#4nEYFrF9M msR&6㷜BP(IʻoܸJ2uzxOZ=0>bn^><|bK5F8m0+*jzr暏&trlޜRqG B4Fsss .mXb3_と{8EϧMgFO,T{^~>6BP(JcdժU6 y|۲-@xEps%[~h}W$-ﬤ+D0kBP(lCY3Ֆb7s.';)|E6>\H BP; +^uy748w^,㧹 ]kF)sGjܶc}4|JCP(59rdEdȔDqyUrHOĎ}ʁBbn 1 um,Жe]}g84H9OjJ*a[u.vNd꠼{50winmlW:^'(džtR?9]^lI{P`7M3 ~P( Sޝ"^;|>m!9,h|B{ly=uGJܫ)/^4@Xk`*cu 9}:BP(Lő1uǼ=ՄE89:ck}"ܷ@~U[_uB'f4?Y0w @<81Xv s_ ţP( 1Z@ݛ7?Lql,lkmv?W=CV:瘘o=5*@w| ,2p S ׳@lm-lV]}4񇬶SV>H BԒ{EzEH CsSߡKI['ǧ47&ˏm h^|O~UM;?ۙG :i`wo}<}}b) @`Axtϟ?ߵkj߸qctttnnnMvBtZ(YVF]:iU\ [>%9Rr[NVQ7BPM`xb/@hpssPfQE999R) `iDyLJVNKxڍP4 ة'  B!mBP(=NP( y 8::d#o BiƂ%K++0 ˛J>k֬{٦M;;:2BP(GKqqk̃klC@n)4t|Ii#λwڵ{NNNmBP("??rRZXX(Hāa^qGٔaBHQQQMwM B&( 2L"3xeY{˿3&5ͻE(BUƺ~`1BP( qPcF1:}v|]p$ èT*Ɂofb%a2JaT*i2;7wd%UDtBh@R( !bV70<(ŋL57ZK w$'L2]eGCOt!RCfJx/ 7.n~nw ySFߵKeFM+{\. .( .jT<]NyMSDiZ%;iSfjfiFţTɻiuvv,˂˗/vyf}3?~g|繃XzB[mmۧR.[EGy}[R*~`O7'oÃWwB7#/EE=U(+o*}6c5"d:5FU L&Baǧ@J,7死^!wt75MLcQďZl@u|L{!:i*i]?YM!*lgv H:9_XXh]T6.i[snU߸й_?y\2kպ >Nr>ǣ5S)B:5ɣׯKg,ׯ_q/8jʬ~rُ2Μq܍x_^wg ^=FM=y27,Sy'MBKQy~o{i?fÍ2yaq~,^y0^i15`5}#ӐLF:Ork+ț鶸FXX[~w\VX3cdͮ]=QO'41/lwWtj\|W^ BEQJ۷ׯߕ+WN8aPdZ0~nQuoRmo/||A~ k(Ms3k(֔yVV즛ЦttKjuVp#[얖xk3j4qw ^dwhtgTXrT yaK "Dy8^ve@"BZ˪8-NZ3R94ed7+[JJJ~(???Af4@lZyi۶U57OL5WKxīnfjpn?׆]am7oXOCmmP*4|ṍ>W=\sTF +\ӭM$ܷzvvl/ap[[o[Z|gژw//6Do03Sz`'ʖV1oNj[f`07R C^?)7& UJ]+5 ~\0;)Q'qһGՊÌ\ ^MU@rsͲ+VOTbfQ=== 9+/////ZY,=#-?-9Gu՜/Ǚk,Y}d8zQ{ôUSuE׷R'VC84Mii x|巧i{/dN:{ ˲{?DV]YGݘ_|r$0y]3fٿ2:$@^ށ}s'v Պ@;vx:)X~pꭡ?;k{[ieVKòeؖv80zyy)JJJJJKKKKK9+..y^6k֬E1 㐉P,˲ܖ_>&`0&} OI =ch䏤1?JJZ|c&;`>|rt4y1sYlZqEߨ&Ii`0䜖uj I/l\ŝ 3mdsrY䛦ۻw޽{W\)iXes{?H<^p\1 \g7 ˗g$%e:ݾxh!`H~tl\`0n1Vf"4cmU*_Om4jS1Wn7ecY:s>gOW֔_8ZA>s}]$jԺDL[𚚩 gfkBebFRX`C<`ݱٯح`Ц<|JvZgP^]}~^1߷/f~y\rLpph^,Ķ1RFjk#: c1:+CC^,n49;o ]t o>`<_$&+ʦ<1cbgJJJ4JbYCVjBVU*SRέJGuWƴG_m+> 9ƍ3^~ߚƸ`jd=zjgLz,8xX{nAHIi)wLQ~%{SJڕpld뎙+%[vu8-74;+?#mCq,Z'L66"4JbHoY,aneHb="I"Ls__wM6[l4^R>N4ѡ%wX2+]!I13#Xk|xji];b4^cjkt1yf|Vqq' n~\e[I7VpN.WjԡDl }dIjn&wGλbδx6)Y$EGGwMz#j|wK./A< ";ifYR*Ղ \E>,."x5 XW5N& v}^ri{ΛeVOSkVKURTҏkeh4EEERqkRmI@`Y}Z6vtd1|<._y$/-2}w;]η/tl$ƟOӷd\d3qbϼdHӲxAL-odȖ-Ӄ״!KdvzCmfԨQ[nݺQnuH/d?r:"{n-?rm{epw/ U+nYs~3]"{?t 0qe"tx{1Z\pvqC߽(V||+Vf7(m+y'w*ۚN᷂̝(MwXS]3oA͍fl|j/qaO^֦@3;~~wQ{zv2`9j*idZ2Mof& VLXQf[h9km`?;vlad>>t:w]}W/eoP1 #SRR>e cN>Qn֬SYmmg;[Q~[[j_|&5|nЈwo7WfVe+iCdlxVӲv[.N3YNbyrKk#ӷO3xVjX<_%MQ+GT'LX}ۻ.b2`u:m Պd&ZyM};?5ag|fK3J244ԩS~СC;v? U*2<7 ZUZz(kd$yvB5r@pzW#%e@įr۱UBw@˙'v&N]>iA#xA" ֧"%*!iY-Dy^3O,#gل/iߞx!6 0i=3<+1fSݪuZحݯ#lЩ9_ֱ˜v5x^V@.CSgc֬7n+&~BHKx7 IDAT{,bӵhʚ5k֫Wg~#FG؝4eeeeWnݤދxEbnzϞ=eeewF飸;iAX,JYf HegJMVaXZ-hۍ]d1 SZZRXVٟ3߿6z:ģnowrR9zZPt[܃+^Vg~ x5+Kݫu PsΟ^6eZ^^^Ւf3x흔9͗ ()W@d\GR7k VTf͚E8///e] K/ES2ƵQ~3,/?Nã[s @Y|<-o:}><37?Yrr,OO $R4_BIsM5qn%_?d2Fv=C[?>ὂp1{FI|n7o맶N~sn֝( T*Vqb;hN,lZZKR!Z^}G>x=g7Y}:D3ge;߈wiQ]Wլf9ٳG}=8KK\F5̪-++YZyn/y\c36`V83XJ<ƶ[3S9A@}3:b\Ecq]&7phl˦93mE*`[Ö}k(ipNfƐͽZ\ƒr&̯ˁ>>%ҐMɧ瞵k`ko|wWi։_{Cѫ>G瑄ŝ}P(JAΑ>HӱR @0#cP3)|Uj$ T@~K+0 #gYYYyyG@`?88800i .xxxjeMhٽ#wyzRP( R~je JR (tp ǃ"t*TJ-]t,,u|?Oԧ\ђ'Q0< `yOG7KRTGeY/JVRUmnԖyǯ'<׽JR! zYs  0jSNX \G ?1!l?ɵ3޿ ^e`!WeѻBm_hՏ =ɄUjZf0֊LIc_aZfHcɖV>o(J+ʈ@?b <_^^^XXxтHsss/^تU+F#E7޶;l2.wyq\yyBPTQ ʱr)XWMy(l\8GCC^ׯ/v}_y[-3߭r=>[|{x+{muok+'unia^*+GrITto*ȈWez/JRi9e1_V5˕Je Hf{{|Xto_Hk U'WNQuU/W*07^ȕ~_o> HV"*}廓ƾJ`J|[V4U2wZnK+>o*J[8%EbK.poq˗/_|e˖:~erBPJv)4G5eY(=}S\]Sso3*γV, ME4/;4T|DfVeγoaZ@]'}p]i=68YYRcuU_veٗ ƃe5!/ݯׯo96?v`شAɲYNJxj5<~\*uPnn΅&x,qSoSHy' S [ fW)0+*9ČY?cXK9ۧt'}Uб*J%Wڪ5MSV-jJ;YRI#F jaeNʕ+g'odh-WPPpȑ~-Z.ڎq ϟ7Lm۶t#T7#Sg9n]V3Μo6<@-Yn1g6qeMxlő?Z<ﻧ+r2sOԿCWT~-U5vH& ZJ`D#ZVn /=ގKQ=] z:U4 .j.X[,Q/_ܩS'CԊ( ƎݥS ֝SN0gII IQw5~zcoϏvZi[ķrĞt+b)((MLTںEקnܝ$'zkE,ڵkw.^Ȥ#t-[2 *J: 8kBNȋrwk׮effv122ywRr~h4o߾VR4ܸ;0JԻ:qqqO>~xvvvaaayyTbŊ;]`0oߟ"fdYQyם=% fڵk']lȊG [SdT!]gimU٢inr+n>nVHoI9h4^^^>-%nqwBaZ;IhNnJYQ;44%o~d&fZhHOvAɓ[ΈB#P{++QO!(=WƸ;f!. !FZuܝBHV=,2 BHSZZ*IqwB!p xB!iEkgz:B!D,uw !BH, !&ȝ 7n]Br<ۮHkcw#B*5zvC&Yo߂^J > -'0t”7M_.xeVJBiT*4ϼt] wZ lx@%ܱoު}7]W[]cݾPa=rͦ}t5!4 .{{}#0GwrDKf ז}RNqfZ 밐c58y𜙇"qpmjOoH}bи5֪jxe+@!X,M'.OlE%|0r~kߚ o3oN9C!P7ǥgzO\}FU2Say̝h1pPۭqYcЯGK3`쒭Y´AgiRd\cKO~d\0`;.~1(Oiӷby/(ExioI9vvrwzmR*`:r~&"@P8g Ҕwooc׵2y,+l%0ŸoY47xuM~hQ{zvQ첊wd<3n2Ki3wQĠ pU.!&A@~H3"rnZ)`p]!l#\8c{Y*z]=ol:o`Ϯupg~ )/5upc "2KiRletHv˽x^>[ji_6S^$M p7?ܧ_p[>6}qi O!MwgYAݥyAj&xfpw!*#ڱӿw\#Gd)=B acg/ڜې H{wtO@NW՗ҙnҡG#\MKa!~39I3"rq=;mO ~B!_ CTPPpȑ:XVQFc.]3 Rq[0g 2tcBM&3ioT7̬VaMfhtp'SU&Kd8fbxtZ'Bi:JKK-˹s碣]̼j l֬YYY;k&P.ϗ]L칯`u:]wXm9r'SX"4k怂BHcݕJeTTl8NR븻dU,VpB! ˲Va^PPpСz+=lDBH~0w7aaa3.'B6ݥ|@XXX@@d2w/fVBHX,*+V8KV}Nv'O[5~wa Fcll̻wڵM6^^^ʄBH]={gM4gۺp~-ټl2Oz;='''***&&FXVWt6E$BngQQBo«wK7{XXoKww'҈WICm[.YW*9dsq={]3UXoB!wJbYC(JJR<<K: 0LiiD^EZ/*䡃 ?TVtvyyyQQQZl!FMbNP B0 6ΕXrC6Ғ¢i|{3yCsgXnBH%Y䭂`1~~esR3rϚ5|P.!ˎm#xOiݥV+0yBH"e*`(^[,yv|i^zt@qww4 ry5BqwB!ϒF"`k9gMIodwo@qwɾ 97LBiEgGU/**!cFV9{Yh.w\يʮݝ wgYB[U1ݪ X-2v33*cqYӣΜdhQù'b ,뺃.:H#xB!RXx(D"DV9_.}j(. %SanmIkQܝBH#eDQ+d5NAE0 FŲg̚7T$.BoR1:n݆&#x),Kh|ef~}c'XI҄.l@qwlV5E%w'҈,eI/Z4ƇyD]AJU|:ȯ %B,ی4*y_K\6C7޽LQh4vQ8 !4R}4ĵZ<a>Y1eii<}j l֬-g'`hZyw8Oe3tÙݕJezӧOܞ*B!uQXXXRR"Y([uOS#w~[۽{K!Bnm+f6mڝF=n4"##5gPܝB"<ϻz~-l6jEٝBY=0LAAhݥN!w{NNFS?%B!M;g)k2fwBwo(qwW^5w>B!RF1***&&FJcߝBۨT*iy4)i.fj8B!J=ݭVիWbbbܼɍ'BY,wc&**Jպ !\Q/q8b~wB!kGP(ie9!R7Ґam'SB<_)ֻ;vͦ[='s \-)`6K s!4A .ϯ+Og ܺ>N:6qV ]vٳ̕#zٵkB=?^oܼf!h(qXS)*S;g_hJkE58sg\]/[ eɮq\Uq<8cUKWnlC!֤;˲ ~"%|WꮏPBU-xXhV;'-;{e>00Pӭ5]7mHKt雎UռiW~f.00pټizi}g&-ٚY< Y\-CYժ&k]zi7:Ltz]O<͚_>cuMURf_!9c*!ۥ>T%+>^5޿n{bqq;/_ IZ:f/m}PʨNy;t3I1gt=Y[yj 6>S5vm6,U׶,{x ,s RދT:S9uЉ]BE,3*{T$(1z 0qM{4_CnzjYժ1}K=~85cSlpzC<͚OYf:jyff~];فU9wsV ǿֿ K!=c=3z,˦6hvg-7wg [6j,)DF"o %I>563`\άABh]e B)d% 3ȲDհ,:[.W7U˪V@Jjwyk)uBcrbC̈\`\T~_!N9!:cYj6A!ڟy>m.R`c1#֙Fz蔅 )keY9!=;{|;&s\nfW@xL?ev#B׍:z缒7{lBgq޽jh4t\u3wDKҒfvgk͕GK:ڼ!'^Zi^0a!zQV "xR$\Qiiw huZɪʝ N7o3a4'ڒqͼj!22YfnvtjH‰R6=ѿKa5(ݛ:.KX+#l$=X`T2,B81 %N-}ݴx8*Ъ-[M"6 !$j=ژHإcȨYNjpVI}Άs\>Q;?%ur[1a-GСj5,˪T9rHppZfƝqfdzZ>3'R' +h h4eee%=] ߭wg{o\1ζۿ+w!4qi`2fg FXf|B!w8G|wB!w|w999QQQ111jj]ه̞=LJNBiP,Kaa믿`ٲeΒU*0ζ|ڴiuF=|}}kuf^;߽k׮mڴ=U&Bꢤٳ>kҤI~~~>օw me˖9}V; "իyyy111$h__[!rK؏< ԑKK]xCvi@[\\,_{)n43Z3n3O!44>իeeeR֣KneyEQT~opP3wf8B*eYZT*yW*( UrZj*>tc];wSj̻9A;!`,30 BsP( I+D:mZ* i5 jnfs[%BZ؅+W[BdYVdVZxAP==tه[==tjܶ}]d}Rĝ8RY;!E곤a1#"x^UC $,β읟g^j2 S9 !4Rs Bd  aǢHig=`Cx[?<XQxUB)ϲ]$os,cxv ^vllAh(qw< "nošeoB!Mah( EXXE""@bl׈*rO8?]O~:£k֝ : !4R>"|.i ̌X`3/ZAEpa)ҙ~Mϖ4Q!RXx(D"DV9_.}j(cZۘ_<B)[%;˕YZQTL[' "bYz3 OfM*k4ݝ oHD~ %BBߒ8+0;?O:&Bw/++7]tq:Bil}mzy|OyӤoDZq.ѻ[֜f͚9ϼnv'HI4˲*uwvkIWO>zwRY'Jqw)@qwB!}%푯d*w&'iچ6@B˃"t*UYCUXpeQ. vjqqu{ (‚byR@ERj 48&3iZ $tr93s@7666KU_|1}Coj4=*D4x={nY}S@HMMMOO̙s-|wA8pWwf<&9z~"1bՊήsw/¸[6<= ?ޞ;Gq :tĈ6oGKܝfCD$#e~1bDujD] :fE ;@h'$$$I>:cE)".B'M@8WUEwχ;<&幛Q.]y}NEUss0/h{' wR,NDS2l=9}Ƚd?iaFDw?v.p oԉ/z=vV8Q4߽%TbjM=_Db'PN⸞5Sr]ϯu Q/ydh{'s˦GJ'gtp{Dt`G%YfMo=,I21U$YC i-X*$!I4#R,KhG8&UNݔADZ>;י̝%yUo9v=UKnwܾdԒ,hM]ʷnY~3--͙!*HKKs:n_|InеZX]9v״zU:*U9G_%DEo s"U)r~c@FO$Uӿq;-EsFN_NJco>9gD_a3&oie6lc 6ƾ{|b >x%ƈ53De1ٵh{y΂ ~'S>tp޲9>޴wSEխ}|@޲?޳v 3&c,$En#oٴvKK&7ж\w7),{e+k>?lrp).*{?~>5nȵ7RfcgȜX@wd{9mۻk;@niD-ʼ<Q銒AN܅ϕ=逛DӞY6=wo?]Y8(u^"Xv荅#Nn2QE<_hH?bv=U.Y0^'"Yx)F&qD>>тW^>~Dz:ү&z\rը9mVy*}iw_$U{qw~wtכn T/iŒt%WOylXɲG`Dd-;&]DD<= kk\9b IU;N`<^V(j,D@deYB֘z`+zd-M$ˌzSDDB2%Qny$TEj-@dUv\Iܿ/οWd/]|Y'_"8!ޮKOT^lC#O˖m.!"hmosMXu]Pz|C'nв/{h֣.z=kd僺:;ha7j)Q鬙S)E-;øl>hdDW3.EhU팑}9TR|RWh cQ A4fD&ޖv߲Ce3' ~H3K2QGwpj CT JmbC)mZ:a[(/_A9sĵ\7_ߺLm r* o0 =ADd@ъwG~'Qz8 [۷oȐ!W}fA:;K[=21=;v,wXK-:{$[6{;uvb6-p'-3-pqK,*[uN^Y%I${رaÆ'C rV _dOz(o6^(/fݝt*5oO^ISM;@\|w%,;7_͏^yBAgDWϽ2f@m!q̙{_F.EY#nt IH=3pwRRRd9(VXaYlAPU5h9sB)#1ݸUW]u饗&%%uQ@ccW_}Yg޽fkMx`CQj;c,|}wΨC 6lXjj9.@uuu=φQ>ք6`S;yYǏonnCܵc,ʟU?>I(Vḻ&ulfY,$˲dRUUQ>,KD - f[w#1wBQKk1xMUUQEQ-d""QUUQŖ;muc>, _R7u/V.YE~1qw.,ޢkzm<|w.k:~_;qwQY<8;/ҍ Ԡv޴&bwswY6 vEQĊrj;(wdw]t߆744y0z IDATdZd}>;UhC6K[}60FRP;~eqwhć6<n W vݵ~ә{Zם]vm2FiwՇ;(t=m<|>8L=1Gkf]{JOyl6up cu#܋;>m 1bK`(V ģSc|>_0 ySNɲt!=f&۸7669r$%%y/m6>f̘]`={߿?_k3\&荻A|5]"ן_A "[&Vwgw޾ tH~C@[gK 2zeD 60~$ݣ"Gqwwָ;;qwу!΃CBE=0n6; @܈1wm:$ pa;)@@p4bC<C DF{ܝ1;csB ~h+p];;|b6G*4t<|Cvsi{\U>![9]QB!׬}[ ґ7f߿ԵefmŐޘ'x-DD-O.*={ٳ}ӧڳe%o'fx -x<=}[_+U00IthW!?]۱nsv6o} 4@s('zΣ򧯯IcA1Nce~ܳy]}Q؏;ץ)es?xheiM~Qv"b?-=&o+aaڹhgjQx]| '$IW%ɣ5,CӺ/Q&>^8mex۬b_vJsO>},{qǶDkzP""ڳrn&z?0zzR(3%|P@ow:ӜGutb~YeYVT(̷NaZnl|,Y ?3ʶrD?k)F+f:N#kŻ-??7cp:<l:'ZQZ*6I3/\AzYJe|YXp9ʲYf,tɲ,W?p(t3WWK43kg/۝N^0W/3/8knIqo7e;3]~Ǣߺ~^V""Y2 oO~x'[j/k~ɵ[?dƵS{_^xsO*)2:~)flܺqԌ)cT{t$gTYԟ!"K7ھxʔ\~EJ ^ ^Z:y;Wݱy衍~kퟖw$}qw-e.GT^Y#s 9eтW>ckU dH&=5s2c!Z03Q~m_?dDhC]=fd/,M,;tO^nGTr^lLwGom4;Y7(_?0t70OY ,Oc=עi;ڎ}<_?FU}ٯ̂}leEMRk OHV"G`G@RJDo;}'"'7ф-5ٯz~rm|$;D$ڄtc,UPVTRͼ"7Q3qn֔u5#W|t r&o_@y rJK rKJ.<t_&Dcl>8Ȧk Ѻ›,y#ڄnDdm;7[x%;ZP:ͥDOAhK|0oeSmWV 7.ξMHo͑ |f yCK2l>pS7M1&cVlmF-{JM+cɦbPr| %'cpי¤ 7lذN+¾}- V~DDtJ$#(6551dd{aZ1wgw޾&|Ar=/~ *,&(|;Sx G{|>(Zjj 7ܐzs7: F=z[:?v͵u0Fo=FZ$3bEQ^ hkjjjjj}?;}|kvIom\ y"^Мjlzm^ )*TeԥyWDQy^o6cƌ+p#+bۙIz6-w޾{$N:WE1h a}ɯ4M.9=-Ս[dEfcx{cڷm۶o߾[o5( OoZSN#ڴK*^5k:Z[d ߌ3*cMMM,yܝ۸;?%hc`DMȊrˎ+~oDY~IV SJ}oQєw8!t 9Ydfնd m}nzAg뮻u=Q|hYZI#"o}>"7CU}/Q&Y܊X]Uk JǣV+HKt]ÓXp95UC@jqmgͦ=% -rBB(lbƑU68&Wv+~p'LFG?%+^痛fSWODR.J=uޥ-OLʿMY_--(I`?2?uTuiرcZZ_nnn6ͺdfqw>u<*( L&:IMQMH'RA QWD- 1~W_EG]5!Dt7H4oVYqDH/~媑]#I߅8yzUU%!!h%xG(pV@ A|'LEUAZ>޷'rwԶ?TY APFd%3oZNDA?f1%[Ϟ-K( kJ8A;~[yvfs? qwLx>wEQlӺ*t7%v'fULԤ'z Kz @JHHMD׿~_={|Qu<[V-1wFbEQ[&~oNJTI&U"(Ola m侗ߔrRR>{P=QI#K8TՔ6zWמ֏zv3LA;Z#zi n%&&voas8S~_EUC=f;:hwEUo5$IUYTUM`Dy'.g?iZ;CϭNJ_rlwk~-]Z0u&/7*104,nGn…{o>}Od2|>>j~|h nЫW/P]ЕKU(*j"H~TA~ESeI^$3Of𢵍s=nIf6  GnS7 +~]9t{^^gΜԳ7L b74 oqwf|bbÇ/2~q>RqD:_n.)GR 3}m:4XB\/׽ WC5]Ҙ|='Oyq=#t h2t8؜&Hfpܝ,|7OAJJJEitܼobXE #mbZ ?>3#G+N9(@^[[gGo!CVeQx'6膨؝v&qw~t\޽򪪪Itf8wVkjjjzzȫFddd~X7wyb2ѣ333}>_ԝlZ !X,T"6hLEpF[a>ʵc >|ܝ w@h̷wG 6D>;Nq/j|R|>_qGnWU\1cx^A}UUK}כ\j߶ ґ7 }y]X魼Eo]݅FƳeoX-;ő-۲[=[XwD1j=sgrD0 u?{qwUUO:vM&Q_DY۴Rݎu..}nK'سI2ƈO__EƦwϚ]3Y00~Q.eNφ|Rq-u+{:mXkiw,v]Q>q.VUUEUUyiC$9$35($yقI 3xaۂZw %IZO_F-Mco=ɰ(E;'9L/{} ?E :q=ߝ3W5ܭ[=zB(Jsssrr$I<"Uk˲BeYHŪ%UDDd؈ܕK-NDt'\T_TNDDKח?ӟHVԖTWx:{1Ӯ%wjєWrx7??ef9i ɿϫE?9j*o>;G-K~1hjD_eYVTR$Yl$'%I.Lkƾu;m`({w׍kITv՝`ӗLJ1k[ߜ>Fz^^2\q+y^^4y;WߺqѤj ?yA&r Ul!( IG>z/frDwﮨgYW Dфç( fW2cL[>p&HMZD1F@}g5nS2y>ţ+kqB"q;hOĜ6& -G5:z "Tːi,d#""IJC/Nw]|vJi6cj?Ghb]}\Z|k{xW-kSzE"21RUM"5 DD̚JTAtD9ob%w;wgC=/UUEILLLLL4L猖^E֝u$~,GD֌۞;uQͯ.Y詩=EDI9s~Z7!6!#xD&Ü/hSc-j+(Ә3iTxGnIn?C#>c?cmSWnx聫mIZ5] p<¬%7eh?jdݯz|I[,w͍Ǐ'8NewN+|+#b]E3m11FԯĹYSgv֌L;]65w,)-)-!*)[Sh]K;h]MCW}Q'6Z݈jeZ6Y!N,/SǶfNK팵) os*FT:v5h價+[,=c/@cH滷۷o߰a: KOOX, ֨v_z0UTTٳnj=2:mI$} ]i5*11x qvwݻwu:l6JEY^6NZ~)EQ^()@lwECy+ΗK'">[^(F#v!Z)uAx[؉'"QiWŨwPy]׮y`g_Zw>a.km"=;YEQ4ͼE);cg=xExgy>g)-Nma;Gy?ve9|]QxXg>Drv3A$ =!1Aq 5c(3n=1'h駟>|x<4=|@hqw.WU׿5h[v]1nĮkt]3]@ Vwkx<|ܝ?bv]Ϸ,8Go] yt8߯*zZ]c;"w'"ɤB&[=Σ @L୕6nl6w|wΛnږ(G6|\޸6w:sV|Xss3:~;=6N<Ѕyi۷݅=~6; KLLLLL䏳!f3_gK ěc;|w|V#hb iwG Nsg$z|y>qwx;@,@qwqw =滣Cܝߝw;{ĝal6w:Wwm:$ pa;)@@p4bC<C DsЈIܝ1;kfG9{娯oll<ЃQ=55 555==qw30qw n{Ƴ& qwmv1wll|w];Pk]E.8wqwqe‡%_,Jdw.[o~N&55. [NytqwlժU;,'Oo:iӦO>k8p`#|>_jۇ cǎwy~3fLty󉢈;-cqw߹cX;ۧx},5\%M&w# Uwu'"UUyeff666~]tр III,gIn⚔|w]UU~7:Qv/KUݻ755ɲ|kjj޽{kUQ^} w^chM{ ҷo8p 33 v8qnNQIx hb   A&-,uuu1&4zO~eIcڱz޺/d2ETڴk?/?HHH_ed2iqWì?X58@DD+7f'Z.JOD>ojjo:4}tժ$r pĉF~D&/KGD(&%%#An.n%eWSǏ7V~A|>vO:Qwr$XΫѽ{=zh?@L~|;W^9+lj#͍䐢(*bXyu:k6Ԣk^"  zjFe0Y ATZ曱g *!zuu avwAEaL&+Bccbn֠   A|$fOfꮿ}wC|8gO|F{j2TU9Qݻ799&ϖl呉1/n֝`Ozvcxm6H1d2iag+7SG*~36⍷.mYG kH?4@-nW%Gn7 HUUu6 ~֭_~mp8|,, YzJ9ңGYyܝ׵OC}g>oÇѣj5yE>}z𦶋nWm6[ݝN{ꕜזeyEشiaZzd2V+8Çvm#oEQ-:_]vlkؖ] 1rx7w7 7z3x/\ b&cפ !h$@$@$@$( )§ <:uxz;ZB#   A4'P[\.8 ֙7 qwx;@A ޠow7 qwx;@ARU?P%)Ql-9-4~gO<Xk=ƾ}5b_#{ m֐Ȝ ׆>`k3lwBQeǎ_}^^dMw{WʟiM,$d:JE:]we=Uk=]]ٲd70WqK qvo};Θ.̈́YD9Vc'㺤v`HUSNndt7 $&&ʲ6~Qjޝ?,$1}Y9Ģi_{m`!%^|]RS3_$I!9zی2$y2l11!2SuȒa$su,˲lft:Y3*]|OXvӹݭU[A/ϚrK1>[_5eLag4Lcx޸oP}]Z{D62>F3,.ܭ[7u @eϓ%''K@DD8p-eg5eYo(kŻ-{*~Yewc6h|gәʗNi/~yoK*Ϭ{z _2LE}kpX?l//<+oݸhRUIKD$ה[vb]|uVeUU7Dr%=pG^twrƭN(2vMfɀe?ZoKd܌2fs뼜D5K.>~X;`ILDa{y"zrƭ:Ymz|Y&O' vϗU65:o-זgnQĀe?ٵOK[W4,ڡ(($յruuu'Onw}}}sssBBB|9"6ЄSJ6%"O;hBě}]7w߿kԪ.mτD'~lCV"Yh/2` oTZUfۆ _2LP:Xehb١=D;j%&~wQ鳏o;ˈ9gi;NZ;LhjyNHHlIW0y/_LS[Dp~C2"1setbJΨ$aJx`nj2,lX,'A 1}ݥ9Ì}ZM30H01Ƙ=0@"G2i} sei՜5 1f6 ${>7gq9hOs߃D^bFY63x<M(d./U;2|u>8)1|=Eb&"e5FX3n{u3oZDs6pS+5dzSDDHbD$S=19(lL[جp:}n=PYAsV1ƻ|w>z1L&dYn;ua}r3hԩD>̴JU EӮwY3yJ҄k'aCI|Tej ޮ-F`djIJ_}u>8F.v*ulnxhM.Y۝%ȫoTոXQ-h{v{jxbfx`bm D%yRYv? hj,=SYvT>SRD4kܠ%"*+Ty)+&up{PFDVҢ%ó~5KUPΨ$Jx&^dX,IIIjZ,ޛX,V5))))))!! ֣=A2g3&QƢ ~]Sy\'y/,J \:9 b5zos? _2LH킴: "YY=vte^| } cvM9mÌ,x=D󈈨lqNFԯĹYSZYfdcb*υ |f yCK2l>p(+J=%y눦d ~DHwtr3q9P:ͥDO1+hpb j JbX3KUUwyd(?~O>@S?/6+KGjby rJK rKJ. / KƸv!}tt_FU[U}c=%\}m EsތJr&%"EQN:?՝:uJɩzJNN@!dDC- { Kot9a@9΁.;gV7 qwx;@A ޠow7 qwx;@A UU1JoPߘeyb~'˲W|3DQ4L1l2DJ'{.U⾾@WRE>/))b0L&xg(~sQQViASb⯭,@ 0e%i׎cPB[nhhgS< ) eLb] m2Afa} f$ ~};$zمGP뛛+++'N8vX[[[Xyaqwܹv횝_ Aá]Ȼ  <ϷՉbWWW[[[Bq!0TP\rAeF*}fS $IDATUWWI$Y zz3C:E"SɸJBzYbZ=QNnpDبއ.C=ph$^-3"V(um9Uӽoa88N"h4}S;e}U7-dS&8V꪿-U:xMpT#!Dx  %4---1xbVsUBؠswzJ, 쌕T۱#GΟ!%fxԨr}l~ats5[owʏǿw6psoA "ˌ^w6_ȳӠLW) 5BȻ  !NcYVWcTIFuhUbu;so=?kMˣ bzgg?G]b3H]h`ͯvgr87x)kg'' yw즅pyөȦu⸫OE|b=[V+%?*S͵kNk7\/'>Gs^>{ܠU~ywZr]UU'jl^رLWUe>BzvjqCqtQNwxڶmе)a@`]x 7Oq&$D qvc IZ=!DQĩ]R+,ߍ}˥1S? ga3]a]gOLeHJQWq [ed'Tc{<ȒO^۷$ds?MH@rn# í Ztl2:*c{G2eC֬q<ۍȽ9']qĦ̳1! [bۤ3kơ]@@`X0ܘ׶i;4;u-׫CU뵵5u5ֻ5x~ʊoˋHRu]nڕcJZ]UVq`dRة!0OO0eV7)= _|~o"!T@[/ό +|Da`EB;t7=OlL.,+;$p33 mBjiEEnjx¢׊,:Lz $.K, Mm<3.lCpΰT, Lu߹"Ȇĝ/Oay(_^w^yw!)i@D;4VF8vUsNz{w+̮_"}MUPٗ@(,~̋^+fuJ4ZFg)VdF8.3}*NZlΎw @(L6Ξ*VN d~Ws4]KGDӢ׮vUO'<3/{N0g7z$dWXY~b=@W*c6kfr¶c\%i>śꎻZϊER'_* ^h~%+Xȑ^<4XYnu7cvvH=pOygME,)2__+8m+`oE(@ʀ4D6&<.? jBW 9߬+&=; >Ke&}$9¡g͗,)#B͒'YV0Vgú@K 0i|Q2ô:2?çk]z/G>h^[xx[wg@0֝zBQ6VR7[lJAN\9d-̲f~'#wgSG0@JQ*o;8BT3 bB]@@`X\b6Y/ ,K 3 j{VU36GrQ5!ږ 9op?ܱ.,ˌ1% `MAr L۱yV+oT\|#:r]O|o}ll2!eG=,*~}m/oj9@ q/|+D+#?X5j٬ Ι݀ID"ѯx%NvqK ^1'K}u^ʣ ] H+"Xsv:&#t_5;W q*LgNY%#D9jZɭinnniA_GHIENDB`testng-6.9.12/pictures/convert2.png0000644000175000017500000016066512732165123016545 0ustar eugeneeugenePNG  IHDR6`NiCCPICC ProfilexYgXͲM%Er$HHZҒsJR ""`D `}>ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx @Tȣb(CQ1ic l̲iM5(6 y*QTR~>;~}1{|w~8}wёH[(--֖^Z2KS b-/ο0lPT 60T ׮]{ ӧǍsH_`i ̪X@:-NJ 8TDW5,nD@p+k-f E9lkZ"(Z[擵v# ; @& [mgH (4"9ՅrɪX%@L9esZOQM iw~ Dܝ__ %|\3c@K^XSE;7%yc EvD.kkMD{CGCpbP.ox/%tͯR,u7=* Yⱽrq GTQjӬWO˛x(B+T[7fF*_e#;?~-32t, )(+np 0yh37Id-嬕0Dalm+FZTòcVY6]$5n@,khţrXtq6۔!buڐjzQZF<. ̶`tpG?S$t}giiھH$n jky?/ grO_F;ȳBc;8(T`uGsμ't_4٠㘹K] tw?< @PxƍdB(,ino@jj`_볥p *H=@*DD+Ne^8hJ>Xj JaAπ |X9~.MJMi-at8[50e%< |o(n1⎉S' +v%Z+{qaR^"TpedݽR)arT9s@ шzS˾[ |5˹ d5%,K}wGy8#!mM}v@U]f| 8W!(UUJ2b:vل(dNcY b@x&!~!`'WBO!0H(MCzfY ,Ъy|_w42NW\^[2XOZ*>8Ԥ c mLzFo6 jfFLm<ZV<>8ZuZ6d@hDA/,ъ3sUf]f\A.,d¹C;dBFJGBOIőLq@T1oDqOQg@Gem:u|kU( +OHMDb4m4ߙeMDom$z|M2=q~u+qhJEHV_-B*X3Q_Y)p M[z2fV0@ ?QA5Gk.e?*oR$X7d\no|?NWb)j`"Еq/:AߘT◇G9kE2Ҵo/&w]u6Miۗ4Ma ^ n)S^% }= O|\('o;|8IQ;Zad3=F5{A=NLsE0^o /庬!z%u&. G7G}Wӗ[NiˬxS~C 7ZT k'G\' dEV8iY+nfĄ,$DL{ O0mCB+#@ TZ2׊a`+-g- g*XPFF qbb" PU%s x\}Kt7޻'9¥=|4H=׎;I@O`c@L $vH$Rxj D _N+lkO7+j3?ٓLj&u#ا5T.a15j lkM58 AdIj&L-Sl <5$0lX-"J)5k O9zoػIFFu#-0)$Qr֐I 5^NݷR &S?hqʲOz(RF[v6!r%iWҲJ-AဲsyXQXZҧa2Gmx)}B7Sb@*xvR63pjD R GM5'Ch`DsDˢCQ_Ou{[ԥJg/>Y)X? uZr`f+uy@ a'箁gw0>UcAa칗.N_ē_ MB%ޝ$9a aϫupWxo'  ;wV'kU 4|{Ml5D4I5BÎFC-VSQD>@2ɼBH^؜R]|]$g3?0O-[M9iQisc&g<#)Gv_raK|q'ϛ}N&%qS\ B杹?jV[jra 5s]M]b!X76 ,$t~(ǁSGnK8P+HB`\֍ 6yLF(@_i6+`8UMSrxVXjngkVץ)*+b1|_k޵ ɰ&=ɞRO+fI,ZT4Ea.XUX hXQ~*?$WO(ȕ&e'5hSjҴ# z1:<~TlVCZYrEÜBYKrrH3Un}N҆ٱ9n|B#}EQEmRC=ܖyk1 bGUfyCpHlN$koy7ɑO\Ym]#M=s~'6`JᖋA-5B|Rfƒc3yIcVџ^_oKDuh"~{l?F^W܌IC+U(~Ae95%oI:ٛXXGUe`fXEM } j 0/Ѽ(/h&{@,CF0:; $ h!AB*j4EȒZNj* oY#3y0ph0B{6CA7 1EY}: BPSnay⸂r-rjb-Z!TFpjZ=SC&mI 4`_&@rrr<<< e"PxV@ 3>Y% ~k Rs$9у|6=^ ݾZT³T9}I UTCGA833s^V&kC*3#k#CPUH+gȠE{JYT4>Z4-9ZzaUi(ކ*6&Xy:,Y> f(adnTe&61e}k(Y?P_@8}%hğZ,@\|"u(\ 7F<ˊt#vT/Ӿt 5dZؿ{`3ǥ˒s2Z>ğcJ#& brX.^&u# % 6+3J`]!~h,`5r7{sW+nsil&VeraYq1<CiPC 3wsшfe,Zlk IDAT]H麃&B353L Heehr@0ŞZǼsh,cy*:$o8Hw2v/-a84ӴCM}һ<T*#cfH71qW2O_+aR_M϶޽I&߬:O-ۙHMڵnomyΙ{k?ƝM z{+si+^ @Ңİ Kn 1!Pĩz %|RFY PZJ !?@# r+~etxBg]x, ])%Ed:v+s8)_QKő3ykPU֦9X93<4ՈnI=AB"HNDA7k哏cu@)Tu =2NqJ8`ؕ%f,yƊbʿ;EZ>V ?lIŶ%S~BN>y51l&מNagN s=WY(?Ws4BZmwѐ--Pv?6 YW*=[v7Q,5K/|K=Q5t0aJ~t$D]:q&W)3v]\Wjz¾jkw"\|Q~- r,eKߨR[0m4`y9;tb+x', iᾋg`71\Ю@~G8hY*wpd Xx<uAn}SH:M"|v5A̬^*o6KkYsL,&5sG:tL|``c`gi<%ˋLj3e |1~*R&HOGg62!Xuz>ia%çGAct[[!KR *mTVJ~QJ۪,p_Y2bfGjׄn6,ͩQS,eY>|6}ctO~&Nܖw'oG4{ڹPpXj/5vvȁ$_m0b9x*.>a@2U/,V\ٽI탿y_(C`ر<iGm}yPE#6t>O!fy)LtTR1xM*^BM֕琤*kqeo׽ߙgGCQ/ޝgv{AҠR"`WjI, +8md1x͝K5vx)nmC )Y &{_*3x(:A,\bHxw[͉4Mɨ~$ؒi7PM)ej2aP wCwu3gNzM )36ݽ?gmH`P[D=Z8MRHäAI@r[c+ ^SWqE;sHW˫_x@E=[cAϖJ 2g'IBT}-Aѓ#[nƌ5k5GS-]; \cQpc1BŏojxaԸaiK=ml\G g]of`^r}Ϡ~m9~۷/r_-Ȓ '̊Oo߾d9t=aSݸhF<> @U ͩ-o5 Us^T3>ϟiYnPŪ Gu6'fXssrs󫩜CƝd&%\yh~_#BT/{>p1O-H?xZC5#%U)E[wЬU'^o?PМk]z}$^3%w;**l] Ղ n8lB[~AdW~S ˺WPjUh@x642z4WV1k13sB?{y} NMXeDpP xzY}%<q@ì[EY}-.T X/X, <Ҕd4ҌUj T`Dc^݂ n9jQa:ښIbPb)ydJL/6Rn$:Lڡli׹_ ڟzz΀Crp.zO&13~Rt(|oZy=N)- )qann֯n;0ykMuK{J2߼{RZL**_cGM؋Vϝ9iܸ+srw">1|bTl@o`㗝awFHGȅT/-`ft,W^>rgIW?)D1D !@rQVXngk<xbQRb2@Ip`1q)lq q%Iŀ9gXMAMgIEx'.,S͇ɥ϶_dtѴqGfhYajd"kšqi\CCU]AqE)#q3/>|b=蔰38ikWR!uA4* [84pr0ˉÍ4%`}2u&Zsnl;n'uFplFg;Ńf1力j%Wa ҢW5?nyc ď8-WL` ˄3 5Vʆ\|?}X| 2i:ź{@" V l 0BTq'#lb6-Xs oOiIQ R x@,IW\kw(Gi|jeeT231pbr Bie~"oI,Jvz­z²p#ڑUQ[_$3NK8+ G((~MME&?qeey~'x1?^....̹yй[#\jS2_~©/nTHoPF3:1-6ʻ(OrHh+LO؜REm"~"/zM qG.aa/EE`()J!.),*AW4e[eniURRc@{@^ DcKlJ#(2NVJ)º#/Pp JqYeei%~ƈv3[@š\Z)pQ(JVht2nܚ@@C.) 854ag6nx)\|- _+Tg/l^9ugԊ90X[Y\)wkk?u9[nm]TVfM+*MW,SgUVKgF*5ՠTȠ) 73voJ#p(:QJ0,TMmM癙I,>&ũX( PըM\i5gd^*5h޽(E7 .͛CKhɾHj3HӚ%'E-ۘM2/3t st4F+7bz7;^[9mJ pw_HT6jk>|i,{2m4r:r` DZ=uH|!0P%=qPQl(7c/ m`̡dW줱`}򎟕]z t:1쐫 ڳͽ ;'~zAhF}:jӢ B@ 'pAi4pe#l!4 *\mu|>y>~({6C>*A}6Hxaƹ0u׎+Q)4O%0pQτ4 63|BU3bCE3dAjUYp!C^!϶[gOW %XPbx,--}̛4tXmiEjcem¨&gUgk\nZU -oF tӣ- Gqq̋jgoES8&_k^.-50 압 njϷetM%ꙚBFr⧵ M&mLL}8Q縛#ԩ_wfvB\>1;fjDK;>i(ˀAXXw!Ԍ[.Y 8 /r'hOLtb9d, 88RPYMhJ:(TR&a+F0X0HUUH$/^̟[$X_!>m٣9.KK A,ӺYE-D >p*>IŠdbihaaԯB-d8\9z_..rAxcՃiYbYY-}]FptM]_E=SR\# ^apd?s̱={fځWE!%3> i_!T# G(v}Oߥ}7b*jL!r*Yz{ů]xᵈ?'/ez2uY}->wޑde9{s:YO0?umS/gxig`gaV RnC N  d- 5nkt5[u))Q"Jj,XNb3{)0m+aQ5&AZ/Dzݱ )o{a-Z?Z޸VɝMITpώ9g60π`hԔV Br8t1J@ݍS80c/ax`bp[V{7`4<qtl??O*r"{q ]S^{HZ܊gE i;Qzz[Cw1.0~5 m*m\-Y柋+Zə4 ֚<h.W&/&W@ʚ3gVNw"D{VzML$J<74f|h&3zƨR aoVR+ZKe[AEaVaT dZTi" h³d`e'gb׾F_冉Guf[H*X*ROzq#TÐkŒl0v3lM?c88?㥄۾ß4Z`de|)أ1ӳ^xv}<=6tk oG?N,}QgiLߟU*W^Ǎ{$wsRGܘorJ DO X+*=k9 B3\scmg>}&^Iы2/DJE!avڪͰ\/maa0xOX@xRVr^*T=> V⣹}! k͛FPKE mQ||4(*>+Y'46Yq4W~!M*GKh([xu2e1u7ftӓ:Bo%Gsjf+ڵvAlL@Zq)g" U%ڋ\_X%3M`c5,~~{]6S2  =nDCymՃF G}}䩫#(dIfv=;Z7d~+zEEʺ-ɣ ѕwV{NfH\>sM{$Dk\ْZ@HhWh.mτӳ<ϼ@i36(eIEk d< ]=]XP!02a S`1e6nzshjfdi K9{GYEHGg1)VANt `{ aY棆ڶ:Y5tjaU'bP)AH]!6 -aA?^̃%@Vi>֋)ҧX:u49͵oϣrZ;kY|?RjOtk?9+DƄ #Hb9Kvjԣ/hOu1lYe{ROթ0N4dDވO䂔Ɩ7#~{rPS~̿tWR'$sh%zQב1MPp9+:z@0uI; oBt\ѫ+qgCWO`ɥsy6uOzVy#" VkaGRc?= ffzܹn4tq5|گOk.WB$0MO%2[LcX j-Jl(u㣹&ӿr4W >k6Y\huu6Kv1> nGs򉚜V܆>3uyh1?FA?GsAX |4W棹:Q#jI5e6:N8h[WAA;>R;G@]8}֔iZr`J͕B鳻pm>KEo2\j_0#ޣV#={7 HhEZzj +B/?'@'(t[%\Y,ԪalE1ԧ{nwvrsr_cZ-{Vuޑ\^ӆO>ד6-T*re*|PrOz}AWyЪrYg`S+;t5/@}?cLE t(D|lAW= l*gͥHMX`?ꬤqFƅ?wZ~їo]7f-+hyfp^7hxkVJ {ƦCӷXMرi~hʦD 0ggK[$ӄac/~-_V[\5һ;^x-vIێ[0tϤ\Ҵ}̘oyV04]-;Ѷ{wWQ`^7 Ljfػ`'98q_%:Pw$ѩ@6&Ơ>7{%9ռ-TH={t?O:29-m4;ءJlaAXHPO}̜P (tުoX9f^uvu|8kOa:WE TeɵL$JejA)j,[w5+N֩>hv`<|* LPAK`f&+^oXS, UڤRVSh#dǞ4nkOX,К}#^(5nD0ng3:pPjh4`ߚ.@RDM^X{ڐ?'ؼޭ2f70 `\ "\Ȓc@S_Z ^!M.h$0A(%q:918ĉOO2>[=t4Wζ?.ԻyO\|u2ӜA Srk|6=&KK-sx#q`re)mЭ9KUV6kfأo.}+p49XZ"G||fC4?)/zn,Uuv]4ѸA}Y-w" I5)4eF #+r0dJP̸P!Եuպ{r'=& 0ka2Ī#*_ c6`-ZfmƮ-tFxnҢYuMb@·+103)䟗jJ„E00CLup+W `(%A맚Z^VN&:! +'(ш1k?0kצK[#)5dB*RAo1iϨG}?ހd -Ƅ '`ONܺYJuܻ֖ϳhǫ-ִ{'ݲSG{ejog1br0p6FD'Jmy^$=g ):+FxP{J<qש d;=5z 8t4po7q`tTUO cdn,挶=5]IlZ=wgƣD7~{! r++u8ImG]qKt2.Rf {v"> V`LrI9+cխ2Bk*2ikmk[ǎ(RsQ&LdaS{M]RwG"l`ȯB|h4+9 EK˳Vmjl P](h:[ |`eeÓ#{ f,  +¤w1aOQc NrU]>T}5}L Fҟ{:઎0LcgKP۶|;"h2/[yL$"{i 6ͷ]ډ4@];va56q rBFUlKv^!8fzj₌hJьŊnaXEMߏثӑ^@cyg$cb휆nzi1)Vq (["g2NIaL?Rz6z@ԊD jXuʓ.(*JS=]O90#p27iQTM)\~ՇN>=ۛQ>;Z^efx^:BKH;aNgYee׋Jg8fJ{4?V-G*/h.JGNa1`=\ז Yp _ܧVOPCÀ}J(#}A}ƞmbd 6z>Dlѯקϔ#)㺜01;.!Qm=ċ¦Е`EhV/8y ԪHk"GY±ڎ_#T[Itsjlp/=,{K;5]126J9-|!= e( (Kt\yoeW34LsУ[BXIXbͮڬ*Zier K`Y9Gwĺmu* .#v[PWpR&5 -ͥ|4tޒ./MXA Q QJQKc8*Tx Cut2q hCaa2.8(d 2# WuT^%I]In)weslyJ8ⴻݺ$_}G+C%udEy_3D]~n^cȗ-yd^C\~x'6Ytfk>n&fH~gq|GS'UӬu+ VIժؘsikM}IUqi5u ! Qp@f?kƎ7 gENԢOZ2a2Q73߽N8mLuHCYx2eq}P^bQ=ٯBbT` V?=< Vڝ߶2z.eUffsJXcĭp4GO9l=($] \?Ɔs (h B׷,2E|%Ћ4nycWk *aa(T@xQAK *Ɔ?÷P1ρow^<<)SbS0py9)(K69jA\Nnhg/7^Ĝbs}.MO*ig -={FeuYv7lڰef"VCG#w,1&@'G!00ȸ^27՞5 jNR܏%C1v5l7#o:%`&>xȯG)R Xq嚚2"m/ 4N^uݕN"K4uv'/jk _nw_WAAmT1C\l|iU+L@(ER;1"X9=BFMU?跪Q׆2*,~c֪j?_GwAI~Vp]sڊs}! ]d!HK^l淫"9wJ-S2hl442(ztQ?UP>Eaekp[Jݾb3X|<"ΘcuzP.PM=4f ׎seDa>kzmkXoJ )@G<ܵ"s)tg>%tDnBR&ǘ(ΘOw߉jCr|/_|Aڙ"ymēæ:o9ټ0 3DuG]Ζ,qe3P(C \lkR\] OW-#((2k'@!,:|,?NGԗbi' ,]=<> f2<L|c/n }oվkٻ#dDz 7;Yuk] N}NP^ĒWuud9E. &npJSlf6DzI/}ɓfx3Sg:{DЙcnLiÈ6],@;b~hXTF!t:BtgTR!LVPЖ$m2[Q0I$5-CF 5axZFCwɹ߮ qm|l]pR5Wvda\9IUˎ9;E2(V(@2VNek~ y 6?+=ƽ$M̉)$?tҎPvﰡ+tO Q>xu/AC)%8u'7\pϘ4;.7%9'vU[CЎ鼱66cy>P%(xw؝_y۹M 'ek40ŷs[KABI(Tq+ gm_`s15?fTB7auwߒҌwW:XzMOl0#UE˲E.}|/ύ:{gN>}  kmN CW\t x躩uEttJUUՒ%KzeB "@?VO <&mmm*JT3gRw?⚫5 `%҅B&W!#ojݺ%3Ky3iiձO:upA͇}Z_Icqq<>=q1`cF{3J0qŋas)7Ҋ3뷿;dStnSd^q/aGL^~R]׃pC Gx.a @ Ǐ_|dBEz81]A @ !&M4j(9 FPG! IGV A л ڈu=7A @%466F+E g IDAT#x$/a @ "F@x #@jEss1# a @5f%*wS])*"9!Sa0BxI1B*lccciɜT@6"%/ c*Hc6E'G}S/]A@@OzhVF;L*JZgk{D!uCskBgFrI5AGImw6ңLbA @ Fz^>-s @ An ,A @ $=/Fx~:,t[# a @xٗwud*%*:(kϞ%n_!k/VX[n_`T%:EIsGv4'!$)sJ*w ta}XuXyJa7*+'Ǐ9ă#dԄ]{̱gBTvKYclqW-ZV@r.͛ioe2{HMAQF@Qsf*z=^9uF5-a6󭰩I(PlN\)wb9EƍXN*U;HN-,f ߔ]N)=Q@A~xZbk͎2jwהCi߆kvP҄e. DU-|_0Oubqb󯢨;Dr#PwZY]2p@Cr.z[)ڊozրAl]uGCAiLnTt`>b)E]+\F 넫ѬܤXc44055ͦf SG+"Aٜ]PJ2Z"ޗH&; wKv{[8n+ NA^[a+/8WD3)' |[1cfA*8P8i^7ko1_yfrzT/Dm9<+%9'02#k[NϭUk>Hyl9 *?'cY/ج\ȂVBJWA/4)@t .D9 K)\ڔPwcK=`ŵwq5)18jS#wau'hayWW1't(]Ym1HY{ Chl+adqrGP_cpvJC3(z_ !n!) }2Zl;SLMzj79'DP|SzsM*SAMJ֦T* \.ommqt|K.\pyXVUU  5x' +W\xٳMMY,3hN|%5P@LR!BxE5aZ h8i (C$9-)#^ө)M/9|sBb~/CbcOw"(M!g6Đڳp&A E$o#K~Fc79{oDl9o!ܜĹ JgA86v?q;x M|1]Ӧʩ>]sͩ7ͼ* A٥@\i2B5 1?~%/"-q1NHP$6Ub Og'#'kdX2z$,·VCn\\[ ]*l07_S|/|c=BA1g B/:B[MAAIr xMRT[?;*»B|,[W OQZ\FP}x+vG0֖UegOxzO⿓h1>EqW 咲J.突hJmpE(nk3ot o߾ĉ0VSSOhmm-z{;nxNJ/^D߮ٮyCQ>zE@ܫHmuͩRMt1RNcy ٬[6tFhk.Kd!!MGv,{?rs{nm`UcV ޻7S*pK:͗jAVz xBqfE6(=Ɔ>&xE䘉lO]8 ZW#ޛ!;/SL~VvV, ^}vo':7G-zDt\˘~r'1B6Q?aj%Msu@# !sy չբ=>A ;'eD5LG˛]k9ĘE!EBZ,EԮGV "zn~w,ſAk{SQ3\Ak L ½ ~ŝkQ;n< C3wl\> r^Kd^3e}#~Vpf5;}W'RA+_4}lnsq,d2O?->l4|_@hӻX -B @ `,e]QX+ .A,Fg.S@RS/_TܸZi kyv 3m;ZTJt'eY'!0#+&{eP[.t_:)ٳ;=AWpNgU-`AY`hd)6ch0B)ؐ1jQ@X/ [/"A*ڇ(KBJ Hޘ$"m3]ZU=24p(L C]-56A lU֧@fS4@ZF_!@n]ts#ެYo̴S_}!#ik61ŤZ K:@G*:`M o9Cf+tԄ7|jTq)򣳾>jE;mĝMJ[#ds%/PYE_䕋Ţ;=:Qhur$.@tE,#jaS~BWQLiF6^%I+…Scg!/>ί4GC~NH}b<|E:|FC SRðV@񛬒 sf&0%jԘ켠\wumD Q {f ;1,,0_ŕ5BwH ؘU :IǎTYp?~#%ݝi>C#?a!xRϦ缛h*e>sՊڤ9B7t4 .v YH{ nX.…zB*Je 5.g.=!$-x~PK}5 DE{cB^p o<][@e˟D" CaB>Q8YԲv"=s,~‚<-[+iƲ5n#usji a/eP=t7z/zt҉mģs<wbބ.s- [ZӭL6Ӈ@gKl[P FS_q>Ou! g銂27yUa"!8'XHF|AaW hCZ<ߴ7V4eQrss@D ľ CxPrm⌹T_S!ޥ9xz,yq1e0>n&bۂMj1zt)&OgAKLOL+0TliJUs6s|D";F2 0D\Sޙzۈ eZQJ}y؞H&S&%Ѝ$T [hTQ1`堯X 591t8$ *TZC&5&jyTmЙ#< T7˪BhfEK?6EvU+12nKOYt^wba"=EH}}atE H##ѯE8u&}5H%K$I E~ xL.?9 =uR$)OhI-*aFD\U .cBP" /KWT[x &;Q%ӂ݊uiy%/P7,gEGjB|תÂKU@PK]ʘlGunN`s\Awu;& \tUu:XǥEkzB]h .EL&`X:K]}m"uy*;(tdj5a΍o6(& D~u)i\ajVv׮Mwvvf2 *B*~lH {4[l tzQp{$m*β%ڽ*P*]KvFF)-`ư4`u\  @]k $ֹ9!391@g0M`U wXg ״sέ΍UNy]`1` kVΨvdjZ3u zR=IudɅit! cԨQ, $ sssZ) 8j 5DA#C0 h# rF cOP+Mh#nCd m#qBA !@eŊ>ffCk#JGv 񬨺,RP64rg.3έ]]K'*ŢಫKHZYخq&A?#!A#ݞO>ٱn(4sKԄ,>u]adT3KRi E@>g4dKdZz985:QKcJ:HiAggAT;ѳj}BȯWܳgЬlaamw!xW(޲&XPYڃ6O*39ݠ".?6ҭ DxtU+ҢB&a(tq%Sp\aq_'D F; B_+=!(9q ?bk+KǎAf$NYt@́N:z'7q>hy5^/[ijґ/d˸L?}:d"0뤶/4AwjtS:A0B;NR$ge5U,6{d5{駵]R"ƍ籫$nG:h݌tRa I}1P%^` %`2\T\O1%.c27pVwa9#S#OmDOMCVa㤮 Y!4{BE$46U$)"$-̓OTt)cW`i6Yl6=k# kw!l2$D ՟ݏD?|#@qPPӗш1 zJZhEG"F UA`=y>7Mf"& FЁ,9+yqڪ^>N^v3񙿥QHk$ ׯtxem;~ iN3Wkf~VJ ^}vkn?U;]fiϟbf>̻gWM&ޗ4 p1 :Uq:2vNGz^ V!)lLQ G-+B\sMNogǤk.#ZeĔ,Ь` 5zZE-vw>ǹ\ `4+ᔳqr[鏎 I ?~񘻻;SCVQw4Q'2A @ ZE#Iz NKÿ Ng[T.xB2,qֶ3Mʶ,D…^D+@H"IZGY$AqBYxOkJ:t=>نWs],HY3[M[;zxs1%"&3T;/"pH @  LCT_/8PqhȬ,9l߄{`Ry>ώ-/;Vi􆏜 ]_gRsgeMdĕٟ럯g?DA@ n"jge_s0H/ц4ia1z=:<БU/w㘚&#EG ZfޗS<<NR]f .KHP=S~V[TL.O  l%?̓q)9-'>Z`QE!!^@KKKS olgi)SiZU7evxJòZ6)JiWSLfKaY?Yq9.8Mylb`˖-Ӥ~J%~%az Ax9[6_ܹ/~u˵3?r%Ѡr;NA "GweePnwTm;M>SD$l<\,Q֨M~W?pDDQFSe&hkDOWUɶeF`df UJaƆUeA 玞󯰢bo (ouhnҫP'U 9& ,=jqs2LC S+]E6j>.Ѫ"̙Oz Tjakg o~X|]?mc=9'] 4L&5e`c-Pq%+o*;`;f z~EI YTy;fV[V͏7cXj}GJ ̑n:/Nl0ߩ4em/~8I~?C}1pBu8? ja'wﳨ,R%/ >S )z &]˩Ӑ IDATi9as^`\#hЄW-]@jؐ6tou^1xbmk}i ;/! q.g 7}d U_ w^ # ' Oz0x܂je̚6Z@̉3XZ2ڰ'9M}!Z!{Z0Kqsw('-%pۤ ^F7_8['0amhq dwh3txA;00Pxc(.E+DoOsneL>f7ۯ^V>ej>7՜{e懯\􃄄i +$[Om ȗ;.vԗ/?t%ȗg}oZoS5鞦q9rF =iKDk[%畤N37M*c(:-tCk$ @x(_ lGOg >/f7 Xắ+_ OF>txzÓ*g?:'iTHR,2@ڰNſI/p|C?g17 EsnLΩ$ @ nx8bDO%;_Yb+J5M9ɏm/}"pC/}7tC5G2^U[N&I'@/GF^4nLzg,o/!ל7eK+{CᦔnHt4ɻPm # z0J`h}5f}4}jߓbJc-۪ pr}QRK{liSM͋ŧ%=mo3bH@-ca֖f\j&Nغ[:`7]7˴nxae[K ACm 5iWZR#I׶ ;]n;u6XcBA @ ГbDYjn_m݇^,b^;W/Kr[^翬 %lJp89" VmRҒ[K}>$a{E%~YE_ȵ}gNj BO%(N@kiM})*⦨,Ç ~H +/ů|3 wq=rF ^\rBh-?#=/oF\=SA/)xCUl}I페̲cqç>`3A1@^nZiȷľF*U>vTo;ruܜr ι¹{?|Ț_z`n7mPӹ?-)o@@1 BUk}O\ŝ3b/yѴUM+V>!@B`ҰN1֓bmcd- Ò?xX-ֽ^x?VqY`'Mj2S<~Xz|>8sÇY>/4 rɆqCL;718q69ɽXto\&r/K MqoӨ4}'{X7`a=(ZŒY_3&m$sٵd'nqڇֶ[0blK$ Lg " "m%7ov[vsL햫Vcfj4?_s2wz[(%M21YiʮT+#eW!&/"mw9ע}ѵ0[g0b5t7v8x{ =تwפ kʷǹ}C|㠈X;r$32eÒMq.n\!ƵA pKM ]"4&yh4!F2 @Oz< &'s-pN4W7TtyMЋ?aioԷ,- KBy(v 1޼5I zMhg`5O$^hzMjҡUY_q|tuvӯlm -'4PFC .,m: ҽOe\f`TP ]~5g3̪,Ykc`abtS:H$zD#dOaJ2tȮ%%!+OM@XVR VvPCs./-X3A @ ^غaϞ;EY\-$ @ G?ܓ: @;"9&4fΛskp+9I4ɎwեpqYc@=Ob`N66H:A @+DIK ?^$LP6Wׄ;im;|}KgP ٧[hZS3w@JIjXXg֩VI›gՐ*x1L WUi /QKX56U>:l/a2l; 11%e}JwXYl8"鮪r|rQ &_Lg kg`CAOTQb< D184l$"@Ĉ 7i @;-Jܣ3U:Tx' I 9 6 R@JK1O,C Q$sj:ByS"ʤHQs4:PfjdJ!K튜#~i"Lo< T3YnR,E140Дe4@ݤZ*EV-a4M В&=8~O IZ+Y/g+B_NlU"#?ƤA^[3wc/*A쏌M;IO`e;Zv~;]BuwOq'pˮ*OZFP |Qy(1E+e"Z a:úxs#ڈIᩉgs^:yGZ{g8u0e?/hi1H!+^wgNQҌʷ'hحU!C<4izO(%lp5 m16 lA!"pB~r=K])3'P 6OXˤՕXG (|1U,e pE\ (9l7A sFtjէV]Jӂ&%H߻}5kʎeܽ x ѓc&zr4 - /]kJG9ɮGFB6!͠N O݉Y%zr}a%_dDcRqa=S/a|j!Ϛ9,3!+`ȧ\#ZejN8B`R -hCNDp9ـc#Т0җ \D_wԆPٳ8NOi'=:'[<*Ά !QrJi儮8%<6!N$ ΘŮ٧U$9!!;%r疝ؕKdw 6E*c;l*k/ikcnVSB! pG3XM(1l@ :U+5恪x_@|SY \]=S6(JJyH \ Tμt)r$͞Qm_T"֬@ e:7hSu I=װ68ؽO &Рi~5ͰOV#L>5𘴵T*R̜ #>/W L _jNj[,dbbD:SU+drbZp:R9n U˂1(6˘VU>=.^hnNjVMFbSO P7/4A x"m1Lߤ 4 a0(;"-ELE\ 6 &jAV]*1,? 9²@"Ct$<n=HAN88ä57Y{^D G"F<׉pI uCŶ':yը/;/ֵjnC׆WZӉ!S5;BCrMZT">/FBXpb;F D @$ @x$_+hLhXWM ݆5b„(ŌꑺD4Wl6z:F`W4PւԵ)_ѱ% x%(6 D$'anQEs,giAQ1Bhnnva[0KH*_K-͛GTKA#*9/lHs$b窛fKy34emnU8I~?C}1pBu8?ja'wﳨ,R%/ >ShIR{Q=n.7?ZNmP4wf`s[^S}Z#ۺ(xX9',!~vnS \T!xw:"Y~F`MCi}JS#tJvOmvvA }8ɔFC{ #666IDKDgH\^]#tEAMShA1H_p[ Á_-ZC@(vQo\C;]9q֬7fکԯ搑0+a'j ^@nЗ1QGA lU֧0Bum@d ghjf3qFIEBsURkL Sa04>}5}h6f;DuS ]Esya? ျK$8r.#0mj@ Gb@ň#2'$$ү4s*?f' ׅ_)"oQ7L)xR91qAK* '>W?,gY!Lz4=l\,G$qMF@{8GTca&=k" f%Um-(-V3;g]aZ\a27ځ ,9Z8IXڵS;DHC:0mZI 5z5WyJ OJGջTqS.'!p&q8)qnHR1B@@SLCJiam o`tjU1Km K]p k ,-U/,G`0պ/ZT}..JK)Kye{z֬Ԭ9,Tvg(!'?xm\p?32k.7,xhY0e!-?螓 FԬc&X Ϋ: `ҩU0,bA@íRj^P BFGy*voKPnPaXpvȕ_ :~Nkfo/M ;f$PwK}G6-%G|2p)gٱeǪ>3~l'~*MzE+ĐxSJ j.PgԿ|/}{T!>p~[9d'xcu}7i¬u'w`s \}Tt0N,lqtDbs:QYik+OdUoӦְ z0J`h}5f}4}jј!!.O !#!dK]׋RSSn30u 9,mmAf‚=  J׉YGT$3"hA'pemAZx1ጛ,@dG=v,3nc? 跲ttn5GGަ#"[4~o54^vXr8csxxD-9)OV-P''-eua>PyY 5{ Q֕%~ CF.LLl x(C^Zf&_%#A RҴnT񦅥esd6+8/V-KfKQFC/7baeM~`9}]Kʑ\XἼ؄Zylb`˖-Ӥ~kg~ߗKx+׵w4@ #McH?ka]W"֦@ՇR 8o T{c8;gw-pQ.{`aD"JhURkI]LR鵮/aYWo7RKnTh!*<aY{Tk\f{fvپ†{O Ďӟw|vZOŇ=,xo9±` kcBlI).%. y1 y=Uvcg3 pn j4lԃm 6*8ku٥}Ac2}e.^sГuP!.zRIis 6glnP?=78|PtjgU{]z )}{ p8Mf@]e0x\ï¯K [-lO;r~=kDTy{c$k罳X鈨+=3);Só\= 8i>8=zB;ߺms K9g3pCP;Z {+Kmjk߆nAmqG)S q[KO; C8xc] lg^ 2<⍿-%|fS^+T.+6*kg'9g3/3wUQ׮hҹj"g)V2_4 nm}H&Io I%j]rWe_Á.䰘7$5SOӜ4O) p \>|_D)J~J`)x [սa)Qk=ⒶjEbZX7g3 p~Qߧz^+g3hUk.9F{r7&\^g3p= L4z2 b7^w#J Vؾ} q7;o~'$\?7[mn͸UFE-b7J^g3p#΀w#Iw-N_9`ʁlJyuyC} &ca}+%ؚa Q)~UY2Ĥ#jőȾ r߀-yO \A]Ag]KUd2/屘/~7b?qPxU]%c*+,*pZƹ$%xnҩ"nYpʏfGb{-@/\v@i4G\al=NJ#غ+ {6v}`|MتkKc{)wSrvXJBxEZc:<9Ë?; oqt1&>֕ӦuEGGAڴqPt#/:izwpUtB+~JR{fq3v/TהmT_gOWXU~⅟ h{*YCIcT;k*1x{Cns30+5K N eH`*^HS  3h'On޼yԨQZg#Ѻ˜sc dBSVg?!m׉OwSM~=]rW'c+ @8RW^Ѡ`CbNd@#7QZup%hDP'<ɳna\u-HVii#:){R_ G jV|vw]9f~/ y}+3wWe|g/~fcih܄~˝v~S%獓!CT+.ONvnm.q hȪDZe,*{P'}=[|=eS5i Ud+ XE6dҧ8y{RxW7ICD!JM_p*8 p7mꊳS>p3;٩wYU5/KeJͽ(zs`L|b\n7H=ゅ+6 3bl*a崳axg1 " /)svz@`Z T,K8qW0 Q ^Qa좋Cv"OTKyg ~=GYvX3޶t"sGTX"ib&N"-3h\0 5Rv;qYa7 :vRlP;ztwHzO?_! &Dx _ZRP*K'v,D$L``oSw8N٬7PqR|tϑP_2w025 yLBJ ;ިF̂o8'N/]aUܔXO.xiu}3ޑr]}3|kYXz*GUUҤ8XUjm3 ^e%].d絠{ٚ]qRZ;}C&g͟1i/bw'rˁbո9qϞ.H TVTzh̏ybd-P:RuÑmb6[g}{\<\M8&>c=lD=G2 K/\42sN\оO\&s!pe:vtsS}ٞw]| {GSSf"kբWS&Tޔ/Ӊ`5c ؍ UJ]NL#ݜv7j_4+: ƚ!bNu&xQQ j. ^];sun(bpZ:Q{kʧ/Tu - EҾGnQ$SWyԔ}Ȃ$|45؊][eF0{ќA+5N) 2BtGy)5u!?5/[:%Fhsɾk~0ZJ64Ų 4;%Xs/M[w΢B媢 p<ن yW'nָxYտ#v"R|آpmS ʲe\=x ]D&w2PnwxprӁǭp_^>A{!:MZz<eES~I?eK竏S;oe[ KCB'<=Fzhb!N:#GGzUWUa"#{c5*. ?[R@Ç ]4+J=9?s -myz^AcϻCA? ;ۑғE=AjPk;݉"M J=u6,6ZjTs%BY!EI;\ 8vXzz ȇزe kxxx?6dþ1DeI]gOohSU@2w.ŎFMم/][U3RuFeѼ$X(Owt xzYW%#ն۾]yCY%$KH֔ʝw>˅s$tp4~S=uYØr4gCt򂊿j7YruzY 3f<=##D۶Q31mn@/PZت0RS5lDKv)7nXïF(]F{'*=Gi7mCƣ?Vx00k 6;L┥;:%G؍CXשƚfTs N.8R/`{ùmyoNT܆D{v/Nf.vC'uOww= Pb!/?]Rxw@ /g-u]}ۂR1g6gg p><׀?1fFLrmad+5:~t}҂,_R Rk*;r ;Gwo?WCm v s*g;rHLI`=_%֒A #jg)yJ$ɠ4fSv/9)6_(&k 3agMsG{%%oGbMBWtz"sxB dy$M&w5ъzHݿb|Q8cCr9>:aa>tK0dZj,\"G&F=W {0:6vyI=3+&iF=Z԰ic>k[Z \/|]n^U89lT< _zj gsd/ݴnJMT>5N}#Ԟ/Fz@s&f IDATFxϭ4WTAh1['O+X6qsx?2Yfa;s\ۻ.T Z0G,Kn#\|xqusyK=7 #{Y4&`Vu2)se]k-gã*^6.ÍrĉT996nH>pZZ|N G>*OvdDgK>AKU5:dji]ʂժ,ˠ U*XVkZNA٘1N[x8NEC+֤2+ p+zdgIYQ(k1j`D$(j]o:Y.j3` eV=&AŚZ/'t\{mB+;(/f+FXAɿ}7o>d#~SO OXY>7?K7Ǿ>t<]<mC;KO|5xX\.ꝕЇ1`5TUbj9 p\95[n'*0hzBi|mG,{*y"c,) !0"; Yf.-5h@ z/!&kۙ/ c5xv;[en@!f"flp0ӵkW!FPCqǍx7?˶L ٤/dl{ ?@)$$G$IB0"F(T$d١ڑ߭[58irod[/{[ BPƷ&% owXfsXXn7|w)&eRq[E} WbdL*834@)=Ē{>*+xUZhh(a/-$$RVk$|l? FBRc)Vt&I]:vC*F@Υ A 39Y01Q a 1quX_=1w ( @1)k@I S@LU*@1d3z`SMb@0iLsbУ !!&jn7YOj #I[<`n=2FuN1mB?1L܍'h69)@}y0$܍"pJ 0ndAN GSXg50@ZBÞbH0  1!na&0YL,$ TVDI, Ln8Xii54Xύ`X"Q ?z <b!A󋈢w#l\~+0ʳ*ppCDLB$!ULfI bJH3zY@ %1@pBAˆ APCb v1< 4v#hCxw#{`Rmݛ Z {ʡAUjcFGYp 3NF)ߍa-,K dm,b VĬ .)n$pZuBd XQA ud!JRqRPb`g:0$S< OX16(= 6*0d'nఱ/MZn٤h#O<Ӷ- "$ߍh '#XdI%}@H0:INYd I C2a86*cI)㜄TB NXj-xr#PL:';P*Hl>0XN:7h9f.X-LJrdTb)cV0\G.UJYTIhR.iJ"T 5sZ!h1INbCiN15V YD)vIf "IJíVt̟n 4IMFkfMQM8H)\h_Qw"HIENDB`testng-6.9.12/pictures/search.png0000644000175000017500000007562012732165123016244 0ustar eugeneeugenePNG  IHDR6NiCCPICC ProfilexYgXͲM%Er$HHZҒsJR ""`D `}>ϝ癞wkzm-8 0fFa9f3Dae`AwEZ#QЛX?6_=E>08gd s0Dxp,p%TZA w=08xd YA+ BP<eAP tBm!4=fE3F0# R2 6acT8.+M< Px3%RFQ(/T(**DUQQci2jEѼhIdGۢIt":]ED36H`T1FoL&SŌc1߱X,3VݏubسFl7v;p8u9 Kǝ]ƍqx  Y  G@dBK](6)((U))=(c(s)))SSnRSPSPR*Bu%<ϏW[#b|~A@-NKDAC} L"8 9:B/aNCKcDADSJsf#-%63m,m!5Ǵttttntttmtt2/0<Rz(QH"wXFF#F_,!&&y&;hRNif0?s.s3.mO +,,kZ?xZ^-٣/s0rq8299sœVqU߸ pr-s3skqrpwq/y4x<%` E Y==*{TԖ˼toޖKmK+HKWKa1Ii,+.K-}"G3Kk[/@T8pLG᧢bE%A%W2IeFe l*$ UEpfOjj~jWoN_M9iM>M7JY--wbھڗ?HYUMCe 3Ox*v7ٟ҈ˈdTgbd`gBmbmRb2k*nj~>`|ԁfBff-+ [XK R˷V2VV.֗ڼs[׳Ϸ>(u0١hXӇҝ&>Й߹Ӆ+떛[7w#2.QK+k[O2Y\B^[gwo޿1"5-!//;(:h$X"8=x:D5tJIhMv85y9HԈ,\M=#. B:4~&A;|"ؓ$4HQ~G%K''MOiOJ=:fVN>yLXqq 3ۙYYY[٤2'Ox *斟Ğ <9WO?w_O~X(_XQDUQ4]lZzF3[%>%:eeekg=Ύk_Ȫq|y7++ UUo_PPW^UbZھ:KrNZH^9ܘ"_u:lsMڕBnodބn\iinuhi3niWkqkוֹ|L]T]];co^}gǥE'}}CwM>gptVz:2>okTsΘؽ'FOG&l'N:MN?x/ļ|EpsiYs7aoSyW бh8>~I՝_ؾ\*ŷ72k77n3j USg˝`P_(|yOp@ja,rBll텖(g=[ ԧRKQ%H(ӚйG0&10Sh5/qqr7>&JLAIJ*m'vyvhqe9}4~hYi_3/1X/oge 25oVM;gm^CmNk\N&;L=<^k3>fdrEBKZXH}hRy8OȜ(h1%qxlXbEɌ)tit)3;YN<=9דvJA39E)qgbJKn.X>r~rS j..Ծ4W@E1ě<- mF;;o^A@NhA4-5<VF<g8;Yⳝ/b_ʽ\~0z4vztlkNfnͽT/v^_[^pc'j/׿}Z{`svί @M12a_QdSSb4BtR D;@T*>%vz N2W 2">bK{B%oݐ֔9*{_`4BTPׯԊԮyW5p7_o4`h `11PTfܮ۾`C!%'ó}.5nZ$NҚLjgW{ۯ?0@?=CPŰՈ]QIZ1', EuHъ䔔T4tc|ǩeff>wxNhᓦy /,b)?CU.*Ztv|bUK54lu]6h0y5Z-P+]_-C]K4T ksO>Ob mca裱'E Iϸc/x֫㧃gf$̧{Wpa}R/>Vu}VßsB'`Qx@`u\'1J*9< ~!M9 XHb c Ss:K.YF> <:|)UwEhDel$*I.JK+8ɕVRVPQQR#KTӨҼա}W_wPo@mk+2MLLyMgVdNPYNX]Ѳ>uv,9.t3W[ N=yzx>J!Os'dAACDBS {^9\Yft]],w(ߔp(ؔ|dTc~ǵ3X2>d*:C3z2?/4B[7EŧD8#xs'ΧWVUp&bBm@KjL57_͛-­,۽o%vq~w=w{umw~Ã+ f?JJy67R;plukh2i峡/_YO從!ϱܻzj]p7=@ {Z TPmXQ_T&4D86ޔqA>XDEvH2caXG*,~@T  tz #Y fª`Y' 7JAOaIqb҅#2U 0fC Diizӎi]aah$]2`g` feae ag8 u;ǒ_@`PDɌRғ2e?ʽЫxS%:KjMZ446thu a35?jbkQnb†V. >;vLpqrs[&qyhz{xi&Sx|2#5G2EGDz9&$IvKy>~!c+k!''l{qqpIqYkйh.ՙG77q7Wސh)opu7GFzbchFyԅ%+_ؾV~X{Q5k %dUA *#Ё\Dꂦ p0\woQt(U'*u͉>TWo0l3LHp^ZEE'%҂,{*U,xy| &YW]I"Z m$nޝ=C xѐq)Y9K:<[Rv:Qb.wn)3-`,(#!L!)Uؖa^W 6r Y*g! aM-/: F&̦v ,h, mv:bY8UbZdS|~\!#CË"\bY% $eYOMyf{\)!?$%"O5CAkaQqrIHK9Jj ;?׽j۵;7j[Eۣw^̃OGtL\~zycSI1Qo-D? yo,,6xi]'X{gA~K>  }0 v .hty$ ϣ(mBM)v1}=c&[ |qp crry DM%:ii.ЖqU#E Fmτc"Ͳz-݈cwהO_\OGOXLDQHE2Z^m׍os[#[[䭮??)-_?KNvwB?N|ϼʝUH|bpev:>IA pHYs   IDATx} \TUbA Qe觵o`X9dE>O]+mb/k*d[A%TC+$"( :saϹΝ;37p9瞗{\t /G2K|;%Uԡ/^E6K%C?9^mCKWQ~<02Er*S& "{Ӿ˥&HP*̫g`K تj+BW\%-P4U e`8".FAWPd_|j"ж(i &so roO|p:ΰwא" $&ImRK#&LeN7b7+~sk |0^"[t͆B|u#5o[ޣREW@C߫t篶[Y^|[&'wXs] \CW/wy utĬιOA3HB`4/[b״3냨ˌ  YWL+ȼ˼eq%wLu3clW2/U#R"AcQ$`Hڡo&ۼTsp l߶#kA!cOm0*A= ^HxaK蚛l 6,nfC[[FYZ8·Hy8mmM1Jl!wTu`..wvj[?Oԗ'Ieۦ̗r@E8VTW?1ʒ=ꖵ3*F(g[">PIv.:T%' 8\/"t: wѩ](</a*SH6I3\ޡ>l oE oEzT~TT:iXIvt%KΕéX(f"OWg;aNEENH,sKTd Z*rFR]/]x8xuswKWѻ pl *χw}UԱ]/^E& %c?^McKWQ~>ӓ41 8lqwVԇ>cƌQ*^&yK@gEgcussXWE#j3yI^O~WzI20_!^zѯug n6U ڽ~K4}>`]t/e<4-p͚U/M@l7ݷ;FF.LQN%Xjߟ߾zÞz'Q! cȜk83jmx(Ǧֻ5IZ?QG]fY~l4%\Rri *> J^{>7C= زda[ ^Jf^K_P rRXjߘLNVqXmpR;B#FzS04 kHlv3BWyx"!C BqrIHn_Eřgz{('ƏppH7XFAuK5MR~nUEdh,[O)LF1!K^|$Y Cپdaj2w@g=4'Qhk|`*\ oJ@yH!2T\NUup}CϭW|hAռ{{3iJZuA2 8~>.=Y~_#\}w؞sd(ZX.cю ךT8@I?ceTk)[^KܢTs͚%sM6Z]~@%BLeNh>PJMr *DP1hҷ,ikۤzNځ:tE{WwҥK_mE hvWkvq[b.]9)CUofOb ;Rqm{_9*5~?9Ro/FbEn |(~Co/?fE!?Gu'7^Wsd ק|7'6xd.PߦnOdg|#~ќ?W_G=:+o?K0ŷW.L4.ї?l$@7c4c!~|KŞ()2fŔ[;WO!ŗ7JΪj58?VG{fm{6}' 4C*FI1Ggmx6 "u}*;:PG lP@мEJ#mS.Dr-K:0`ltĹP?A^^?b˫υQ^^ jxW=8kj~/޷y?y?[gy-!%Z` _ PspBCS?9yHԶpKsܐaTYkATB+4oCa3ծ~eߋ(x;[ нhDt F<:m?upv jH(]ٮTTJ$KB/;U.XjyddZ]"thʊzMs;ޒu2"nL}}I;MdjX;jKxA|Ւg]1BTqp9 g?Z'|'_+'.ޏ{ڰ'>GOLn3pI飱|۾[K<}ɜ{ U5E}dVShck$4UFnE.Z\w98ѫf]FsΝ_qA;=sj]"*eB8W}ޟA!QsњVi|z邂DMrK~ X'"TA}dm GPeIvNU^=%'CRϱ dJ=׎RN國Bx;"3k!3>dFN#tB(7M}o: z"/E"XTXN\{.\Xu-ޜ{YD€J!T} c2\T5]l/W'>X|>Jp ֙qߵRs- rcIYқ% \5,=>pvq:Bim';ӮdU; Pej"\ӕ9  v1Hu K tq(ҦT[?ODdAЗ1$rUTHL GJe)SYF=׎<aBl@}||?zvs<,ꘇxDݸ??޼9q}/ιtx@1o^s ?g@=sz?@7!eJWq9!o~aVeHs6{{Ng"]v4?~jɾiNJٙS4ח7SRmjxl"&/)O_}'^eݝa jHzbϗ}Г~uߛ뒿Z:$Rt ER|d<&fً-2nY Y=̀İPFaYPڮBX.g8.@b77rӐ qd3guȖ Eكj 1v i.:]ʞ6 u@ks{SDnSgp/?okp贚IRpV/{vbpf?ځQu۲*>hcSX5mw8F?.H+qu1P=8kW뜻Kp,o/yj 6Ǭ2q hĦk > 1kw'? qľHZz &ﴊ:2>!ûvw#ItŇSUt[ cݐ9kWmxK^.faV#:w޵pX ~O/F r"S%KFFS ؁3bH$ Jy;;;oIETٔ ߾Cx `$7vX___8tƍ-wK]CFfX=x KT4hhC2r$t bݪ(9%֦8ȓR]]uuug|Y{øUyA9LeԶjkH^PB {Td)""j2H$Tq ഥJyZ x*OkFmSc6$ y'c>N/5UOr0DG'#uVb4PV^J_~֐zZх"?y)̙3ͪ3LUB0sMd0q^(+e?4DKk6J%EIM{HvQ5ohd>M JoNw)RZcΟTKf1QG*؎P+%0=&ހG1D)Q)V$FGQo@k@K"Oɑ''u@5a鼨 |&㞋ReLoa鉹ߧ;}CVm/kem*&%˗Ur4#/pwȑhkf~-XIEL//S-˞Hٳ'gމWsT#c4PIs@tNS5Q(u2KPI Jĭ,}8Չt_cKmuY'a2i |JBdDB1PY:ߏJ"qB+?<DjA%Td6Z-Da,o,ow*.Jr-Hqo|%YRa7's%LchxH#ƸI>5vZ%O?ԋ²/ waeiܹ5;0V\ؔG>,qqwX'eijN@@贃}s?ul \*Mh$r+p͔@_,'?v@~Ӧ\zw}Jլ\`SKD%'p\SSXS(My,i⾩ukk%h?&+I[![]y/+I'<޳w`#=p ,eDO4x&l@ dx,~q:`(ssy#򖊽dQ217#a騧"fN\[[ۂS[<B7Ӆ*]vP 9ҩ"Rfh1c}#&[̋MF uۤɣ1f2feaI?*nx\(6UfW`}Hn^_Utfj:3|LW%ҙ) l֊`,knl^Hy1 ,:'2^E", IDAT1ҏKla2dvh,z%덩VñP 'kj"֫RgFwȆUKO[MGOmoE rD."3"kogh*:g%K$wf%۽dRw7HwH`n*ԋvF/|'vvM 1pr3!{{Yѽɲdx *NPFGFBUԅp$Mz^y!!6oj r 6Ndt Ct"|mRx]([K!V k)>hS@[? n .g39 DN.s ab vp98*ap'NmDEp ,Br"g 3f͚u{as/},uz S|dgö2}@蓋o|i4mq,~&z&Ei4D?S󻼧s K2]bnlx?<0WS"<{t]M I|a' tzi9=q['\U6{38"~%/Jym)t0]((&42 tƍgS@1gLO0'S~w~?R + %G%oXd$dȖ2$""44(@Ī]2L c)l* >E kOW} g6'`Ѡ%d(4 8I/B_Y7\{:Nh 6:GZ>h0$` Г#PTBrLxv VA_Kgl(JG_)q@ؘtHA-|8aqzƧ}ЌJIpؖrbZ٨Ǒc-N<[槺/vǡ &Ϻtf<=A{-lpFz~y%J G]fdƅ_ ZWyIdp$h{R%1N1J&I=27Dztha`AMCȫxK?!&vĖ2|TP6'N3G^u̪n Gy n .p;ao؅!ZE/k6?Tt!.x?'€wڭ-:8[;֪aJriV~iCR_:4 LPVN $C kl7}l^ .t=iGgW;I5֊: A.rZ<. U 0@Ч:`ЌL#;X,x;K}:yxn%3^ŋ//HC((N@m.CV5p|qyߋ$hƋ&zą-]( "x4̥>*/il ޗ 5۟QE*bk|^_1Y]l>:s;@PEU] Ι;8a 0;Y"*Iv#*>wE#gn=7 8xmSE̜ӳhLS`ލlƨPO`ꩈFer ;#P 1^_U!Mpy bHAD嚠hTr Chu$;bS>ijPl|f2؄d3+ҠepqufX)7b;(h* Ae ue$$ĨjEuYݽ^Ss抡̓$=d]YM9{J!5 6U7#2-!psAlq,^,g0>ض+^v66w={dG}tu67`ga\Wfus ѿS 8wv"jExNR;oۊ.%2QO/wZyqm Dg3HBrpU"Hģ{@6r$2q&{T4Ub&n~YN3ߜ(s<#pxlJRk*@GB`.J'f@H<ʜ9a;;ق8flv+=Hzd@*:p{ B׮CE@(Q$Pmh\%,7oZ!ݙvPx]Չƭ]? L[ӺS;rPB܊AxVξ.l=e9%*qC̀xK],z=yS++3<=\k0Ay1r(sT|WgĐCy=g-F`56v y=SnǏǽ5ybKg mkԕ"_T2i/>oڢxɲK%A2ǩҋ"=@+5 E |7| e#O ɫUacre{ %83܀4,-nvWNkɅY<$fM ~IE>D$dbgEU a8_2Z)!}]C#*\ 3eNW͊&!M{uW"NRQ=2J^2S ۣp3ꚟfa8PH8 u [sI4&RHwespFT)} ',P7f 028@+DrkP^ZNK&S$@`m)Γ2GVopNt ;ڏy[ق(Do[5CPH,wuXeJ ۞jK{=e{T&HD;:4 b1TQmOCnAn'82<>E7 j=fyC)viC0o+[[؂b+O$fВq?#6Sev/z,x/H_k u% =ψ\/ {(nP!= Qwh; / nyEhK|-y pK‹\ґپ(^1bϮ,8#*s{x * Ă3my =Z$^ tξSv? KN}StS85 xyO` aɺ^u/l >PJm'3LCkeʺ@767/jiXePi6c"ilV'b#%bLBlh${xQ|`:`),jb~~#4L z >;#+!0 BITT.shdVܕ'v.=zgܵJ 5= ).Q.=hWx[:fC|ʜT.si|e`}Cp%Ri>x뻽A Wcy{ SU *\ X2i}Nś{O_S`mu&/fSxݓūB*d(n9L/F<Dz*~ݹBxl*@ +x/sHI ;K/]*ꏦ2:Q_ӄuI3|jW !τ(imC>F- LGќZ5`F;vFm;N=Mjّz/{'0z| o\\.#\vbe}gd PU#GLTk=ґnNRW-6zQFG Xi߻MGܴ ZfX7)!4]BH.*9țLI3].Ubm9I)h@$(jg| uKگ]@]f,,=HQt\@SOoɇ h(yvF&!"|v$ p Z݆-0(k[jKtI &)ݰNա7+8jXFNҌ춊AVi]sflG$D+WXmB$S7sNCuo.%$"Ԕ.Wm/beT͑ 89  I,TKPMr(0;8Vr _fl6youmoI-} qpm742-;["̸숐S/B^!2 2oo\ 1BjwCXca^%JNKY]H^x< =6T~K!Ŵ Jg F"¾R[<0mPS0`*&n 7!rsQ/xSQoΜ9Н2̜i5 m?/'p<Ybt$xV+JhEGbr`;6uƀ"6M\$F^JYF{+( zeҦM}v/V^a{L EnDžHfQiV;=y M\r>~˰};3E{@Cx۴7 %˨3hR1483r>1zM aDc/Wԏ T1J9j$vgkk9L08ND2cAdQo 7Q@D5%xZh2;SH[LF\Y)tn[r<'gP5+)H /jHou{j 3|S\F-V7J=V- 9)"E͜(dE|R{uU(LބSCrՆ׀-HrOT s!c{[dEi}U3 yπHt [yC'*5xzK=܅n{oNyhk=8>1L[Z $Mp,@ >5 mԒ"D$[rD AS RX\Tm v8JKГ}Q1m#O-R8U>n2|r%s#<[KbSHa~Ɇj/z{Ǫ^Z?s(9쟔夗{68 ,]^/_eA+a+<[v< ǀ>EoR#GK}ܹLxG >slyVXf`u[ǒ;ؽ}-t@}v`#'|Ā#2_8reIHM&VCQI\/6ei (pfDNiG5+A"=u~pk:1 NmBN:Im]n_Z䒐g@2q "r;Q&(!\gpRC`䠊|Vp6l/Ru6|7m } CuC"_C "zxf,8$<@Y=Ćh*Bnh(5^Xbߐ;cz";M5b \HN=loJT@nd쬦4m?|::8r6TU++&"P'ߕ; mj7bJRVkrUIbŶKÊ&cy\?/nZ p ~D,)>Jh:l*p3x~Im0 VVO?_f&oJAXA7[_>zc{4~LEbxʢsC[G\/de7a#򘟡LApKYO@WviRòlflXsؽcFF5v 6* ܈ t FiGn)g++T6`Ν6)9DC]Y*9%aa <$.ҽG&H;@ŵow(H=a:u!ݜ[pݐ-Jz[en[Mp[@^~B &*̌1=%^M;=oЦP[‘e{k v=#K<,V>s~8Vܡ7&EnVPg;Fp!DMfnoh?i G}wm{M~{];:Md4;: W/_HSTTPw<^Cqf`>AyLc(7v^n ]R[9rHGwJ!&g}8{ .hD;|4vQ[ϓƎ*i]pFg%pti&kZ9Nm/y Cx @E#_t47&j;8mÃ!s ":[' {7 m|\|_L}k\ zahnmAC |c*h"7?D_Nf` n & 5-SQ݊@KE"Ԁ{s`Ay=uPNWWWPl`[$QA ק3CC"Rڥ(*o/7tT9* wD{)D72{ml'd ?Yƺ)WeD$DX?:H) NaGn9k4|`Q4pĈl;nܸ@î)Syzz7a{,h[^+n;vꃷ Tp5v&*/ɐE~ҲO%O\~oXFKD ┠x%MfJh mRF,G(+si:> i>gҐ:qeb;d^ۤx(?2Bo%/Euc9pVaBVxry!ɴ>/<&n:*bJImAZE\d4t84vRZ=h&-\Gd+Ѥ?C2P?͋Qafij}U\lɤ/ͅHSƊcMڦ҂cMؘR5V\Um >U&yEV@VŠj2'r38y?h~K.]#ANΎ7n .~3j?ꨆ+ឺB vtR@@ |yڣxw퇆`J:7N4KKS~>TB|x>P3W&e'$H8e /׌^x=Mj%H/9: ҚL8EN =ʞ0 b1` QF`))zcn7i.N.bgN.;ں6C/d3+% JBqL(<<:+móa˂3Xy`tkuOXX- )`4y)F#MY˹24 uч0iHkF8䗵n̚) 2"={Ey  [~t6\-EVKm4FF:&P dщmaF { S#!G?j >&.499ҶHF.==+h03ΐY\AdfNG"B%;O{|Ȱxȵk| ȇ0B : ~G[u- M .DCRl/'֚²:{ MNe =&Q{䟁A/@^f&%4h;} <qZgrGZCTxw nfi8?kw#2^YpC\S6>eX-&3NWkz2I}:EoƑ9xI)zLhX4 yxŦDL+Ur6QM&f' I-Wi,$ y:mlAyQup*BKMf$"t3N!Yv0+иfvKv"" k ZAAEtn l+Ral0Ki95A[M'9fLؒ-rܥ#/фY:qWTXspx?J[N(d Y&WHq|y,2t(%j&2Z/&7^R/HzK*i0GC4yR#ڬ\nsN^Y`|boD dOVBoW˰dXE{Щ$5P(o R5ڊn\y֞E<7K~8?V/2ؼѥO.hnCh ZH7P)Ac,R7 w'[vx~@->38-#-+-{+MZJitR$BnX[Zl^5 9DMtGFkimYCf'e)I~7sau#ZҽWLCrS!T:LE];d&z1>7FW3;\pA}W K|xn&H".t 3="mPt"0ͫaW%4qu'!kϊ8ΐx\=qqRHO i݃b'ИAh9G-E = #U:h` MG|dHwy}e7y~G6]^b n4TCU]\ 6DiؾΡ;۫8;q x&+`mETHw$ m HΊ]FT dx uzl+IҝY50Z͟—.?z%tNtQ=C.KA&C4fG͢zp^'\s ,Gc-@5ڊnȭ|/!ݹ*{58;V›ʡؼ:`tb鎅$i:QIDAT66BcA%wqyv=[csL .[fCtyA#fq +a 1xx~]7؁AlQs EWD/sb.AHt,aʛ*NnSP(Ģ4$dn5Aq>(GWqI7=-RC7iD '%TP\0p (EHA\$JQ-辛Q=gԊ.hȃ[t<M[i>@7N՟y3:Hwcih6JX]}{bҪ ]M-%L'w8j1*QpGo6fSFUm,dSCdH7zٱƕD BpIBZd]Tniwi} D ;Ά-!@{w Sf  xo>Z.j S"CaB%d$S_ڲ.4bd =i~\d&;6=Tuy ȡqtfFGXqզ6aS0w_jJ e< qM{֚OO#J_4&* K&CɐnL* ;4vHÓ.ʃt# ZFФ铣a3Mx%F7/F3ҭXf"x>x]^SPn9Ž==( dH&$vPhE)n{9.)|k"KrEh̹ȺX[ͺx\nwJ$IENDB`testng-6.9.12/pictures/new-1.png0000644000175000017500000022133712732165123015724 0ustar eugeneeugenePNG  IHDR]D,[xYiCCPICC ProfilexXy8To,c'=AdߗlYc`%I)*VR)$f"ٲZDJ3[zy|sous,|@?H&j`mlԯ=8kp,o0, )- 7|sORF[QC3`@0G)e[Rp9 xQ Ƒ0$Yk8ƌ]vqzRtGb%y{+M$j}^w $+0 <ïe8f?rhÉ;zV?ܢYA=r;=mo/± - ~!YF.zk P ChBnOSQibisB7cY2e8Zxo^1_~`dTAN"C3򛊴J@Ն#jE4ifi~S[DAaѐɴٺ9!kf6^v'9 dqtvlE?L &'= ':<-uYsߍP{R}\WēSiW_Ξzpܭ쌆oe'u?=7ATWs#B"bز U55j=zjLAM^\imjni+j~ûٙ%۾ץsuPpHh+̯$5c{.v\m|y{l'ON>}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP( T>Wwsp ?Ap [?r殾ݙG2Cnݍ8`98#8@2EGaGEV7Ć}ypGpz|bYoKRX=KC]d l#;o%|ͭw~tȥ$$ͮ~^;#8@6"dO[tr9˽E\d&q^;#8@ȗcIzY6\4_-ԇm;Bm#SeGpGضd#8ؒ|D!-/z$ua['6tIpGp>d"9qPu>l/NI}Tg",9u NmX96A }r-FI=[?lsW~gcuVSm󵶬rwfI^ۜem$k|:*iþBxM?lxv ^ߑLmqa~qEC_NcC]vRN me&g*kö mqmJWGpG0BR7S;2sm+6ogmrd#)d&gKqbþئ}QئOR:m'աNS}/vRC~IuTmKC?l_R8Շa[?l'ũ>Ta;)NV:Iqö%աNS}/vRC~IuTmKC?l_R8Շa[?l'ũ>TfKi'{x=SQKt1qI6Շ5 uaۦgS]=~*sV#[??J eڒjdSmV}.c]/lmm*'LڬUOx"k|.q>_8s ?>~gcKV굦^eCqm \I,#'39y}~2۪SY$IW]>5cK_w'߿?!_|[93jxm'՚ShImw m[eu0m2meYjӢZzmT/y|<qXIoNMqX?|ta|tqq0Nqq:88]88uo.voN:7Ni;7Na SӅqڎөX8m?|ta, #CZ}qviSW]ck%ڶLĮ"Q(kqlڶv KҗtqEEAMMMhm%^GpG`gG~`\JX+q: azC%.T YbJND>V2k'N8 a:׎#8#D 1T s1t-XʥIIRrEY GE*GJP_US]( ;$Uo۔.$K)WK׾mkqm'`]e֣=RlkkCss3֮X݃Xhܸ}I8|8 +g-uuuxױaD _~g}PSS.o'\z헱qp>opcؐ49#8; ro^$HJض\juG kڶ5YcEakLEmCYua86mkM}FR!agXȣxvW:G̚ǪUYX!睃Lf"I˕K.o>ۧ/$"ˣM6a-{アsi3#<<0lT-cahiiU`h҂'Î͚g&wGpvF=dޯEE"ċm[ʹM?KX[]`?r]鲤a[uHɦ$*rq.s߉vO'6Yz{p|,|ȇdċ+^Ikٲe5tP 6 wE!YrȇJfeDd=~[x!' `sc~\̓+SIcؾ_ \2(ڴ&5lL?|*vG C(٢:-eM{SkZ팣>cɕti'qPgưVJtj먹 O*!Bvmikr( TE!##ŕ+Wb]vIWuu5JKjϥDeE%wGIedRVL~Asڲ [6z3F]#c+"߱{G&uzG`A`Gc`Ævk/ӳ;#?"ED+EաW,Rcu>%]$Ve֡lkB>ӷ/Fɼk66T 6ա\F-Rn3𜳢>HHF1=`\ڲOeXJ&Q.0T|TS'(֥xqchnmĦըPa} <73?^RwvZο~F]\E#d> G]5IyGҕ-%FJt3=PV?ڶVP)tq2,:)ڮ8;'B}\M]ǕbocD* #֭Eߞ)kh//Bd߂  Wj%AyWZe_Þa̧Sˊ\JZзJn.e+^g4Ap{V ۯ":Jc~?|W~y|K1{[&rGo xt|x8)Ns63j1amK?D]lv(B(VORdYئT+JW 1*+P#\6H%rr*U\ /jo"n_$YReI9lgZԺ9 }V8"]BxgZ<MTy+vs /_hpp{Zд 8'&-r?=bGIkwoLGOg~w Fӱag;ʂ%83o2<4pi] 8Y 5,$Xd,k[eծDmS=}mmZ[['9t MCU6HL5'K;k{u2XRZx*mI >擽Vѳ@Y*oףoC#*P"g+n,$^ꛩ2ɳRa_!heU. BВB}Wқۄtտ|8q&F4V9E&,#&<*Κ0oiH^xmQ˞S8@V{q"-$[JW'CžSŞD]?#ZBY۬~Sr6e[>HGlv߼Cb![Ed3rVz5jf_b9<e%3E2ŕ.f!b^x 3:|._߄rJQ-q}d#~)_/نͩYjUf41Lb218?;Y4mk`MƜߎ{:\"Mk:l {fAֶ0q|-UynܯQiKm²+Q:0Kq-۸ߪ|AV?߹667j׎#"Ag^SRE=ۺ^ uMි*QT4>s+Dd_(SdToe,d]#a"<+OpQ1<.֮G1 2W dͲ 0CZʡ=מʋPV\ErYQ-V ءc.] W6rWv7ɗR&\3s1_f(oNWu\W8nplZwl3S&?̓Ѽ~-v;\?N'ߗv_#  N*` zOy/l-ͨgY|Haф-.ƩmEWk[]?9,} l׿F#o5`2c99D)!+~Tя]|ǢOO6YRXQ9#jȚgXw/0r=Pe\~g*/0 T#yzzyu֨QXڌ9xhk=Km6,+U9{&+wײK/##0cƌsdKJś2V\M]8ưЮ6uzQʪcQHmme%Z)٢̋JeRՏ5/UV߱wylg,$4vq #.{I)*+'ټ ke"\:/8Wp z1"o hclKJclŹ$qʼn$EBD[.[:2'ԯ[.LOṷ3nuGpv OdITguzwpԟi.ΕthIZmlr&]:@!DHcϤ]8#$p+(S/(sKQ8kqvY97JM&D&+15}B_}yqGpG WX[rkuq] 6%\ɩK8XXq~ʬ#nLx8#8VZyRKZ(WsVu$)ҋz'rXӗ}f\pɗt% ɨ]'zۦ,kg^GpG`'GEH $Yd!ZAQAu*(+3K9fGwH&cj[k)[ĶN6Ҧ{qGph5,[(,š,^â<*'ڎ?w.+Sm ]~vGpbd-r[2-EDiS52-=`iY||HjfsaQX80ێ#8# cOYµB(T^h%V9r VGhV\q0m&B)RpGpvPHH\zܻŕ֑"`Be<^u"v'+ }ĩyBHW.hXW%ZS5kGpGcDيvAҁ0)P(a׶[bQD %],k[6m6akl["ƶ^#8# p,3'[9;Z{^r8jV?XM{ bGيф!bEclu8#8@<7ȖfYlj\(fW*s9ʬzmgK}d#]Ih25d hRL^#8#l7uߖN%Dnz\[2UVAAâ,I{=]ڇFiQ[sN)ڎKxQ}\]tuXz.%!P?ٷ܂^XfêexeX-\R_[olX2<޽#8@%w+>ynXOSk4m[[+Y6u%?jBIne.:G:sƝ5 O/^{ IDAT1&2UDUmEyvDwxE`ɦzPcս"WUFVJީ#8ÿ>Z4l^͆7|1qc+X"Ghj8r?vAs$߁֔9A;I‹hزfŻioL8T\rHSw=& 1*䳯ǒ%̾o>:gO&J`ܫpڍ e9W6tZٗq'_ůN-]6Xi}H{/z| _5/H0mdL<ӦMg-d0GIk0y|:g:.OƜ|6n;Hgߺ=FQp ?GpG wg)¸7ʣB~d(.%"\<KP2ff5wȹEݑ@?kVڴۏ;cxjq]5¼{Ƃ9WbCtEB&ߥ󿋽շ܃[>{Ǥnοj-)[kȣ#^, u;VwĠ]p;b̙)yפ_ GOnQZ'N> _983g[5MY_?>WM]kg9K(4y gqP- a3B[9[n{qGpxh8ij0acƺH\(.`K3F&h }-7z+Ƕ;%6, mqm9X-)8K]שX]GR?1WNʼn;WOyx˂T&_]mu?_p&.bġ㜈󝅋Gf~n~ԁs 89, 0-h{%zh>}.8ܾNpGp5?(&wRlU&̣(:GEp8䟖o_0G-sΒ~d_/ǘ淰ƙ"MOy4I\5_ãsM./-DŽCGtv>GO9$ӈDftȡ͹75]tMM8BU']BX^ˋh8H1M$]K-T|y.0Gp>*kCTlqO>6TJ~֙8noوF67#D`s`,zj8#{?StQR"]XV4x̒%âqjӶvY]'&ʶA uVrXӟEVgvt)G᲻ǹ֠Yx/ӧ p>~t\q̙ɾw3X.~򼐮qeW AӧKWj:utyH8]:U6뮚+߇/]ʽeQNWUqpim}aeeh޲ukg`J;G4yV\kr5IQ[[+Q-BZQS|<<-hܰO9QqFq.($mY򅳵xG'~{b|ؾ^7G]?>ې7h5zDک5.kTS ]eB:h#c[k % R!aY~!P#=c+㬓[k uv}xk_7yv?G};?d䛊ZڸX/Yg\115'UIT%.Z1/J:\T.2G/hE]LkKT:Q)䶯L"0>vk۱rie dRt7i$}Gǯ_m]옥B‡])욇kGpBڻmQ> 4("^6~bgG0WMWᙿ&II.*&x͹.te\ke:+ky8#8SLh{IIH3蔇1)YLaH]Gp:蠃$֭ޮqXT,{0l=as 'ZSE}rSV%R,+\wO?-$YJ"7qiraVfN(+ jI&j'ƻ8#81۶V[ˡD SYjEQ*٭-~e}u/9z}+C&dM--]~(;Z8n2NlBBm[?kGpGH@{?b36T'+vl+d)֒Jz^tp*ڏU,,7%)![ M$XW֪KA}lYut%䬍:Δgq#8#S!N[4 oŘx5rJVR^V@V$P=,:URF,buqCu5NkQu*֧!F+]Me@b}sGpv:>.{K-]oQuM^+td-!f~3ֽEIҞcVspGة[  ˓R!TeBq9D*wb#X+MHJHv2Am衠l*Ic%$LOmklj+rᆗ~$`TפIS+L2h>9%N#8# FHW"6 r6DI\ J/h>,•J5˩rQb_5EEu-B56>eOG\ۄ8]-L.lk׎#8#@SS|Fde'֡Ǐ6ϖRҒU4xEzY9+$:y1vVlN U.N+_^Sb,6O{?d~/ t,ky%C8#D+]rVW<:,}WhEŃMe>YsE쎗]CQ+乧Ķr{EYDú<#;?)8˩ΗtiTfvRV-Οz/#8# p#}l%[yyt¼|+->r2`|҇H[[ӫ\WO %W9C-Ŭ%]vua[U}xpGp <2,Zږ);-J%/Fݼ^6hK U.9^ZO6?TOʶ͸>֦VI.2 ۚSV}ļ8#87 *7m!ْ=24W7խba\%[d׀l{}AL]3-7>c]< FTO~BmGpG`Cr%A{ `hq؈lP$vQCE}o2oxUrEh`ӻh) GMTW%>FT6ճ|藵BlIĬLM^c3M$Gpr9E *ţo0r+"X0yO4xQ*礆4[?LL3'^cs !]:d5yZYc~^;#8@O'/ڻh,E=on-yz(UV#^Bֽ\"Ebza}64?.4>cLOdm2I2M8 7:#8;$]er</no/tʊ*NJSF2'qm[#zǣ5%d4"\\-K!dʕ%oO.ܒP~6eGpGAJ|϶~"oV"Чo|HՀKlOEٷquLW*W #?Wacm4rWJM#IY{hm{8#\xt*ǛFKhq+ ْ;{?Tu&>e_(#Jq:MڨLk|&9#8;NjBm\V9SBE^ @]PkӚb}>'V:&%%k}|\8#TDe_dߖGFUaDVM7\ 6VG{*+tUF*![2d*vNҠh䛳IMN@ٺ&j;upG-W1FzTJr7suL^Ü6)$/J RBeK-6E{W(T/[RqEɫ-ҕ4$I>vou.;#8;e{ʄmmˍo)r<߹g-B~B8DpA7܈ 45QRo;!SJ8:P64-ִ>k6mHWd n}=pGqhmK`o/V~ MͧMEdP+eFY'x_׈rTVM+ uBSr[L,,2_Ȇ'_eb>xc*KعMV{¶x8#84$/{NbwfwwKZ+%T6Jnh[֯nɆTK;n~7NK"EH:P,0Yt?ÎmY>I6.@rPh&W9.#8  WQUU-+\ :޹.-+GyyEbyYZ"nX&Cb!]RZRKVZvM Um7#r1h'\ETFh ٜ:F>]&Sq9\: NʴSpGI\|XQ˾2ywaxU\$KV߱D_rU- /Jh[XT\jn)lZ KWzsU.yoU]mCQtlF.QLJA,2>%]vua[T=VVkkGpG`'G_Q6c=]Mzf!_q K,y?bT :ʶ1廒QUM`1_vxwE0 [S BQ\"Q^v-zeNyR~ V-H%a˞50a˹huClcou.;!+s Z=ewJ#8#vY.!؆LFUR\B|Rhz[KEBuP^e}$DG|Y\mBd|YyՏKڊel%dU"p>}Jt"Tlg;}Gdw)/.1|33z(4’} eMCGYW]ֺ7xցA'S7{pG؉ źk1hPSU*҅&Az.:5o/LW#}ɭMjj9V/ŕ6ZZ[Dj!BRMhjEVDJJ&QVU */Ꝼث&M?3XDeL&feki"x8#-tɾ+y-t"Ĩվ㐇"QT~-iG'ӞmeXCXVQuZk͛kWݵ-1&gUȞ1"%ċ[Թ:SqCQp؜BHW5YMVXƫ׎#8#Ё@K`1 aw/&wRyOcAs{T|EOx ( W0+Z-՚U,>"LIPW+6O6JV葦zӦ(U暭<+VQ]%d*"]vdq1H;6%?Ncr5>oOdm2I2M8 7:#8;<ս ￿sNHL=5FMjD>M| 1R|hX^U>}P^])zUWJQ>̠#;9Pb|V_R?v2l Gpj³ys=6n{+Eհ 7bz!X#V%IUr"ʊ*,m'`"߀&]ȩd5&}nr_ᢋ^.Q:ձ8.$[ۥ9N=jqoGpnKDծj6WF?j= ]uQ/CI 2w|fKwzW:bU{C&]v`N U9W׎#8N@O{"T_6TJ&N{[ˎ#8N@(Qf o;M6l݂HWd n}5 vGpvd:^mwI6l"!6>eOG\+sdG킵a;#8#6w,G!6ڬޢo}>VΗtÿɳrGp}χr=Pl9?)>Iq9\: 'هMʴSpG)o'N 6O[a;[Y =KۙbZ#O~kspGp\'$@y cdS0qZG۬5:qRzÚ+dԱWYkV\w#8#8 ?4>5y |藵p)ߢ)SMʌ5>DrKpGpvnBaшjW-^ !]d5yZYc~^;#8#+SXX]\|N쑾IWR6$ %gGpGȂ@!d>'Ӥ&dɄ.;#8#S?,/1ΣPe$BM4ٶӾvGpG:/Q*t%䬍:Δgq#8#88?h~⩷>lU %]b I>wGpGq Er S[X&{tف9pvRW_^;#8#"W5TJ&N{[ˎ#8#![5ǍHWd n}rNGpGH@ G%63M)9o8#8# Q86X%]yu3kl㾝R+_5l{ڎ#8-簲''5.:_ҕK$6[8곗ŸhpܱpS7fJ߼ۀ_4?xrn_B<˾U|GpG(sXa;wtTImMVqN?rL9[QLjqHUDN ocvX/7‘?/#8#!$zqPkx$wtA¶&hU)p)x{ςk]+^~6bH =>܈ QoOɓ1y)8S .[&pY>"wϿ_߆|"<FOL~]?pܾhs{+GpGEsSB.t ``O~Bޥ=D7o5O⒛o)\GRaY|/xz Ce,U:XbW)"s&̿{{G㹿]4o9~xo>礟wo'i _3TrGp^D {6er!KOT 61+3VGٶ%7KG xy2X|f?D'6* xㄞ'S?|,T-o~~[&@ $wOƨP%܄N?g `r6x9>,>u=,?GpGp{:l_P]4&kuVx+IkN1B&r$n:w*y|Lܣ28W>.y=&`#qPB{J5JwN~|#8#ГXNׯ[Y'4>{t%%kIPR|It6|wQ"ۧ&Gm? c\<„~)44p&6u 򵨏hO%_IwO/bR믯Iz~])xu l+.9#8@!dJ,'Ӥ&dɄ˃Ǥ;xʑ{E} S+N: yT.{įOW6Əѣ_vFݰ+å4<(cqWO¨QWtZ:Hѓ)z-EOqQGa-F8#8=@:N*$lzOx\cvUTM?6q}W%6mBJHG|7JяAi`xpGpB@8#:m$>E]k lX]SrTړj%ec,FmG `}u}v;qf\X/#8#MIC9 k:L|u"uq:pGpE kr S[X&{tف9pvRW_^;#8#"W5TJ&N{[ˎ#8#![5ǍHWd n}rNGpGH@ G%63M)9o8#8# Q86X%]yu3kl*GpGprF@yFRVV$TzdDImL[?y>>,z-YFNO(.n=pGpz6y^) =rve9"OX`ea;[^YK*$¶& R_P}_~|pDqq{ A#8#{\Ylnv8SDdDP=)v@cou.;!+s Z=ewJ1w\OǰaPSSMJWz#8#гpOPWW+WFOnfy߿O?$>9Y2DjժUXv-6{kŅ/>}|}N'אs8vkluOopd5y&beMꬬsqG+\ܜ=\-Z'^ .>''5#8+`ҥDrヒ%K`*.~:y)¬?..>IIHӤ+)YL̄3Nŋca W^vX>G8}>إln_kY'6Ӧc^wGp>z6l؀~7oM^I缯Cac2iedBuaӧO#RK0MuQ2yAyu(N.OEEsr,G#8@pޟ|M^bͶx_KP֙xR+.8&gmv5>Od;.GfUIU-cv=af+am8O\=}]|Ux ܆ /njþ%iґḱaUc{[:;VW=$9]xg^4KY:}jaUJ` q;h<8 lCW3Eָ8ocLߘ>:f#8#PhZċ5Zsy/$DkOa;Rȷ&%i}|"=>͵T=yБPS_,{MCKm :X(^aO3Ua}VFL3 GX w#rV`HA@P  CmPsG]!C%qC1rT*s sT * 2T0j_DoOc HJ^pVaCk1GoGGpG[ܯGŚdm.qq\CBUC۽MlBv9O?Rk6Q{u6{e&κg1H?_qP' +j5sq9G[NWctUd )Sli2/9%Q戔8r"Yg`hs3N=b Gǚѐ}fJGpG g⃒.%\Ŷ9%iĈYIW8뺩9q$͎N̈́S塝. ?hs1U_g đUv^?>M$?u ye##eiVH?;䆴R15u! -ô[#>wK9W黨wI 7ŷǜ7]+'K cpG'>VTQO;H%gtG-B/ S C{v\r6!f0/W|ml.ǮXbϩy{ņ9L=1wunBY4Cـ.R uէ*y#^i@TctT*+r9oIJС̜m>2pGȊ@܉|IH>FF{v g{])Z#L5mq.Yd2KzQ^"QcQfȶʑ;˓jh-SyU!PƩf7qcΘ]tGp@l^/>R\%OX2`eld.ۚ&Hƫ^5Wvm%.Y91tWqygKlyO̖|pGQ `Tʼ@ DP=)vRcou.;!+s Z=ewJ ~_5]fMtQ>nʗGpG->NPyD/{9SBe-$:0z=c?<^^GpG`G {6 hce~0bLYfH.ci?^;#8΍@9,qC7ūAu!+]d5yZYc~YT ?lk[ܒwYpGpGPVurJ..>IIHӤ+)YL̄c'Aµ6K7"YT^GpG`@_U1w-?lLRԓdie[2gµ?h»`Qg\YAsGpG`;BnWRRv|T:s<$l1.G-.U*VB48#8= rW[e S,+]%Dԧ l %]qD)NYu)q.>^ }_;$ϕ#8#}"w<y}?ru8 mYYwe!N^:8]R/ַ7]q#8#|<;9|Y.k,P?u>albI'i'e}UU#8#8!x[l\j|Au 4M$۷[]dO̷ۡεѰn5;ϫiyvoK>^xo>[.8#ldqrl V$MvӭIJK,5> ɲuy%l9cdPpXix.^z{OpG-B/ ƇN|[y܄t:Ʌm鵚b;pbԩ߿XOPoqhX߀֯Ǟ ƭ-5c1sUx~LL"߯[W^| û p@ގ#8|y(6'f"9ߕ.@rPh&W9ˢEpxf(GP~>ǜO_tS+ ;vݢa=pѥf&u(FDOzAȳhr<\Ltɱ1nJK_E/eN^GpISA?)>Iq9\: 'هMʴS㥩 q 7Vt-{mmxѼC9 5c0Ax2Zx9fM,!/jނ܈S%o{ǕS:1e ]Ͽ>i(y8漿mm0km-Oĵ#8@ʜy?Njvua[cU϶ծzŊ|cǎ/:fa}Gƒ7Щ~7,bbZjj:mO~s~&2^0 w.Acw{Қݘ,ab? x.K#sU-rǴ?T56 8#|r8ԫ-hiuKlBV a[zʪضl >r cN6 c2IS'^|=_tG}z;՗`r;I̸N<=dp1 SS9r*θ+z 8 j]Y-Oe:.6{@xaدx8#s!?$>9!YŸsL'S7 IDATw]^^O>_~yŎLEҀpF\J:V$rp^M5X:xһG|2Yzk 0v0.ruK1 ]U5kеGpSX, 'ʅ.g {z/kc'g}KUJ@ (%pE7[g+jyL6snIZ'}evR3ԧCd<5[-1~{8XUjԡqlt=C7nrrrٮ2kg 9ΠಲAs̕`S<85CS`f^Z1`amAJ@ (%>Q?Y'pŝqYv'*.4c͇X֒?K$}joNt/42iˋDϫO>|JJJ¼y&?~ 9ظ٘E%1c2#|VXbkcWM[%P_ 闘m-dArq)쾌ҏ@~T*%PmIė[$}% |&7gX\*%PJ qMpLBu%* rqqG69V8GQPJ@ (%$7?XpK]8+QwYo5QPJ@ (%`2RSp6X;sޢK.L7)7%codz][%PJ@ b q]^#7Ҧ}%PJ@ -mk_/Ee[֞piw_ hu< $a~'Ol% #3֤qJ@ (%. ?/6*;G=<&ηŵdTV~ %?d TbՔH햅^YY薞uFľӑ[6P!Y&'[:/PJ@ (w QhF/}.W1wҜiM=iTWWcڵk׮ypW-Ǽƀ|u}n'`UXy Ꞃ`$Wo^GC2_hCr$Ӳ1`P(_UJ@ (%bpRs>MfX ƌE{AysNcg?ں:l۶ ˗/Ç[SgL>ueٿC]ɟisQV4mv<:#F0bKgQPJ@ (%`n}gi!H_x'']r٧1(gSЧy6V^iӦ!77AĦ1uV-Kfl't*Fr՚&/u4ipۂNXXNhJYsO7 ƬOT$dNF%PJ /!nk7bDYٕr[yFo';l;ؼ&L@߾}# $DWٚRϼ="1|&%Wǫ'gbd&Iw.A |D)q)1q8uõ6V`lv""WՑPJ@ (/[SHa$#OEYIJ0٧x.smZ<׈Asdda*OXZpF8I_&Wuu5֮] ?/j/1Z y7OjϚHz^J@ (%'EMOH!Toc3tϛ\,6H6vi+**l2޽ϟw]^3rI9] G+ g͸">N,eS7!#KPeط[@ tQ,2)WJ@ (%\zK-p[ck Ⱦn{^:l۶ ˗/Ç[.SgL>ueUwXM#Oopٵ#ebT8w 39jd WM߀>S{WGP HԤPJ@ H"S=v)v/ȉ|趸Ÿ@;cm?իWcڴim34SjyĘ]2`=T,|56:n#>.S߀A1?+_ŭ[RflowJpagzD+۱?J@ (%@Tɉ(bdg?%X&snYIٳ'&L}FQ07bEWٚRϼ="1|)`J`>EnYfzǓ][WeM/ᦼLuyժPJ@ [sH*n7\m"+\,OϹ&qv 7x# ;X+XGwdQٚ?f'{vUmك >ce<`WɕrgbD(r~#&CS^J@ (%)b_YH[tٓ{+\^:ӯ̙Ç .ZO5u\FUy|W2`Wfd``tVta NܡE8@ոciGD~N-30tã C !x%PJ m)_OdAPYݗq2]ae#hSK˭3+XE~^bsD^$Y5HK#aՀ=]=Z)Xbn $50&5,T$ԮPJ@ (%_!SZ#?QEi(}r,Zg=DT8W?s颒ȘL Gp%قAٌ:),(lLo%() ›PJ@ ۸&8ƞ8_|9܄>ɱ"bZ)I[OcѼ<:_0yxHD!޻/bР [7W<_Klx7OL<PXgx#4oI&ބ=X)'[<[}544`ɒ%ew,!+h޷hSAB 4Z}E7Lq+z #pS[Cm/֗`PJ@ ("'}DZI\ {̹l쳟yܦmuu5֮] z PAAv9 {Q~yuм| /a g_~FeᎷ1{@=?7 57`(GC~U]y~d7Gth.-;cAib%wv" >WC% s1`ǐ"ZPJ íOdg/ki|iK$=l(Xlvލϻ.Wk^Ӄ+OJϡg8z^Q>oƕ_qb]g{YH랃q#*)#QR>R2*Xѝ%< DaH,AdvK 0tV(aj펜!cQzdP>ל΅Nͪ^Z:x̓XU8ӻud 0 ^.) :ñV[|8n\܈)u9 N OƾChdq˚ pYkNFxe[O?㘑1Y@PJ@KH;;]nY >{;j\WWm۶a8|p˹)x睷N[MS}^Lǥa=X_}[wA}n̸ص^9ڱ'x f.3Ʊ'e\aR2x|cju ,:RƳqh(Jõ#31k~Yh za>qn *y\z e^=ʜ7Kq]8jl0 +v :K㐙#䛁z 3W`襃~_=lX9޵o̷O|t-x]fcn.J@ (7[SHaN9.Z'"/9qdr(_ڨ/×86Xz5M\b圔iV-Kflǜ]`L_ ~0I :PfK#{75~K_pϦCq3Ĺϡ`jḺfo?#18훞Cd,^Tc}vUݧoÐWR5ӬjG9>y89gz%a`Ĭxb|ϥDa"e0K"-ċ%DӣJ=kڣW:r 8X]DSzdi{fBFmOQJ@ (</=A's}hs\<>Js>}"mϞ=1a7bڀ/DWٚRϼ="1|3,{ sd4IqdIRRTMCYߚE}υ#Mc2{rQY5aV9>ddSDf޴(-01݊/-G@;) Sܹ΋ЇWi杳.tHgn1낦{1)FH6mi6F0A+aPJsG@j _YH[oy(Nbe1^}Z+qDv 7x# ; ֑\ %/[!s#)&`g5wcC͙P#6_inł´8Y2G9Ii0^\Tkb5hHN sCOrG3 &oYQ iSR]W`_vf_w I1.94pI2P7 W~cs2PI Ds1ȗMNjCay]߸?rX_%HDȜh;'36{-*}rq)쾌ڧ_/Ι3Çw\8t9k8#x .Rߒ=t!R>83 5F*hsedjZZ1UH5tf> qL#Bk>0%O5? Keweٝk s<{|ݲ!x\d1}d}ܷ҇[jQ߹"5vˢLF٨lrxIII7os's3U(- /*+ )%j8{/ŚƄqMOc@?97-nK&1/8Qspo7|2+&.{j 1WvpR?,T<&a+i_ͮS Ξmt槴w]V (%"5x")8}vKí-7JlmmTNyIQV|6ԛdN>~.!iJ@ (%L HKk'jkI{z8^ڴPJ@ (7Z#Vۚmm%"cm2wPJ@ (?/v+&IqDq:PJ@ (%@R22_]#cݵkr91]դPJ@ (Xgx%H!e<_m{ܥloSax'[?w ~J{v<:׼Vݝ k `b?}HZJ@ (%$?Nc|r[b);cm㊊ Q_x0 gb>o#`/T|e~1֩o,C{%xVT̕(#[B_uڱ#JqM,&c;0|.(9`!PJ@ x5sg+j9銶Ss>s'Қjc՘6mrss R/xiLU#< m#\)γ05O`PFwLzr2ܺ o6`7ǐ|Hl0_M*!=WV (%p! 5;BXe|/cokU,ƫOyGDk0a1Um6Bt)E#bs+럲i4qO3t'݇Az;1CXώȫ7ozWh. `nK (%@"CD[Kض] Sv_vw)=]:#̃*[!kS.;Yy~w"2cl8*o 75͛VsFm1lA];J@ (%@K|)5$rO- lܜcs{K^3g;']:.<>n&=<NgoC7n-7]Zc;zգPJ@ !?m4]1~jI[An6.N&-u3331n8Ĝ@oG&6tt][pq܀P&?% iYiX6ev6e|EtPJ@ p?XPyڳs9q87BCހk>۞y~"gPZFQIgL-K (%hWnZg11q[tɂ.MmQy|iiw+eEi}p5)%PJ7^ Rs>{{9W3 {Lse|ndK (%P~ 9dqucƷ׋r&1v 9MFx!5\{ネ'58y`+~@LZRQJ@ (%y%` /v{c-ړ.!٧E1(g{Da1hhh%KPYL-{w,!+XB y->WᴯIbn}٠=%PJ//!4=v)v9r[b\Ovر?quu5֮] z PAAv9Ǟ {Q~ =?A y7\6m!.X\i}vmm6,_nV1y>>ue~ KCr/Lp̼S{W3|'sUX=kNa|Ԧ2\6Kn+7%jG (%O@j J6|/{{"_/FЫXYWʏf}Ǐի1m46:xiLU#<1bk#q׳Moƒq ˤnѣPtn5H]ۗk01ݱ{ŇPJ@ (%`$?dN4_bƶť2Nb={b„ ۷oĚZs,֔"1Ofqź)+ ɗ!Xeø_?P4;"2*GpT6Rķp1(%?.9n^L(}r,Zx;uoÆ Cǎ[sޅ5O!-"N0;)݇1iX.4tNNgamW~x #k"od1(ݮlF}{C:VJ@ (%papl6☄$*܄>q9?ZLB>?^䓮ۑ?u\!sD'\͐QKw<{6gd~לEMˬܱ㻝s@0v[јĿ4vPJ@ |/Z֦&cl_q+ yn6dWL\L79991> 4 $Fhkl2;wF{# !5 )I Rz21!@ (%O0i8/"1z蒅 ]`ll4iRR͛Biq6~V/*t2&JJK &o5R (%@,]ېq~yjKtym7I~V}PbUEjPJ@ (%XMH+?r9]v6@~TvPJ@ (% X,;G]^Gۤ88(%PJ  Qh/}.ˑ1ڏWt5ˊӘ.jRJ@ (%o3}s6^gR{>ɮPJ@ (%pRs>iXƌo p7aXml*%PJ ^lx{.HK[D^ >-b@i># , <<$k1pii z(^J@ (%X[;DNo';yX׸>YC6_W:8GUD|i_x*J9UP8y@VL鐌nYY2n0ļH/%P_(I0-F{9='5YSKbFm?c,^~g\=ɿ!ȿ^Ծ_b{4o2Bo׵Y'`)x)s”BA1n\n>T>ƕ 5;o :\ꗣ׬?=j'-o‰=GZe=->%PO^zv?x7\m"']&bx}Ε6|kK_ r?>[K_ȥ\|RzE>B~3M ddjƙW|A\R>uNRxaٔs<E[]EH`bV`bׇ'1$Ez3/ΉmK (%@@j H6|/{{[.be1^}*+?&:<߹8x`/r:3 yS>FU/u32v}#Ζߍ?@yڅs7`z4֜>H7;Bqb7n5F(_p=JTZNؿ}VND6RJ@ (%&9/TBe1v_%B<ν]1cu iSl1dv{̩Xkh+o_pP]f 1݌F.B9y3JB@^zupN;]gLl= S:=KgkɊ\>ivEёPJ@ \K(G[E(QE(}r,Z?_W1rHwSѣ]_.]0'IBt)Eۛ:g=_Fi(.&N87y̡W9(9q~sGhv?8 r嘼"g K,pr tm=|GE I5)%NMhBc”׋nBI8Z-&n._t?:GΈ.竺 5#!aKf[4hrpnpo8}am`c>o96(jC_ k ˜C;̿ E[qt.sERPJ%kn[>e ]~l^XIII&LdvIWٚ?uZ GqsOpV/z8ZӋp]F;[rD痎. 0L,\\B@e #|Wȕ{"NoBd%Y1x.`WQPJ@ \0ܴoNj ckzD6snIZQعO-js?Ļ^߫:PX&qeybB6'ў18q .9aC0ajZC$!4]AKK ݷdᇣ&!Ŭ9aLu*%4 d^Oeweٝ֫={37wdsE9gcTb t66G\gPZfQIezJ|ˇě;JqmiIBFw+ң#%P/[tRkyjJtEeLBISD}PJ@ (%D Gipηc"B"^Gۤ8b1(%PJ  Qh/}.ˑ1ڏWt5ˊӘ.jRJ@ (%o3}s^ٛ+}œ=u՜響9(%P8QHxI7=!5"v=UH֊.yen>WCH?K (%h%[OxS<ث~Η~_/F$ܐS=l WpɹfPJ@ /!=v)v9r[b\Ovر3;&;KEPQ̅szwMob%P [SHadYGh12޳EzM, }97F|SMշl#nT$XxbW,1 yF74"9 I}|w916xlZ:="wRC#v6FSp{Qv y漃15@ (%@ؚCN?z#|&"Mr++moYxڈ#Zs/F뚎U~<Տ-g-,OS_ ޹3R:?G|}v>F<=W/%PN@j Ť_YH[EW>ugQ`[lﻅ<>:Uog1Nū4\ҿ+~o]D#́_1c{xdl\&VǺ'PֹN;R{gᱫb+S5Z >Qk4|d>G:?%+|?urY7sj1^׎]DOv'AB=0NGxr'r H (%@,m~/1cZtɂRL}'/>vWc.6+mﯢt*?РLt,+\v/~3zdNjkP-ٯv7}iw/Ǧ۾+6;->)hxg1Wp*3Ѻחй9^=Pz3ǜQ~ 0xw ]l(ߐڿ3j"ҁPJ@ (RPǵ mrsOe]3S. ]7{Hpɗ}CFuWk_R UFLqNާx݈'I|a9=kj2Kx{x4?A7 Ә{iI#:rJKGa/`ǎտÎ*1~Ot2R.@㘩񊑙ݭ:zd2N%JZZJ@ (%|?<mܲmJqŴ%* rqqG69V$GLv|[/\.chו,7fOz|._-ʢ׍tW\z)ݿ߾tǏ/1v{8XUjxsr,~?igyisC'\z}^$|3 8\4e>i;񪉍ftԈcP)r$'|}Xm-"#r}g/.s:}4%&+_$ofv&UJ@ ( o4\vqg\fNPusc&YnF>OcMv;lH/GvqstOm\c#:@^B1;j[p.Wrp0{׭^jjPJ *?makoӔeAta%PY?Yvd\?Rs>MhXƌϛǼi,|kPJ@ (x zBj>dznrEwZ+Oc.Pکv G (%P@KH;-ktDD~|Ϟǎ:VJ@ (%8.Z'rO/9qdr(_ڨ/×8W1r=C\{ネPJ@ (/=AŹ.F)=kyE! W~Uljm9ELKr+ 4RTCẦӯK0lS\ObO.;: ˀ_.}N`˦ a \k]zY*.kĬPRvTol%/Vwc΍( iCμ@6URuw2\H8K%Pq?.9q.2۶mqk[t}}yTRR #kvHu ,:RƳqh( -{"Z`УswaB` t(ݐ#93wݯ#GT0CAcc ~9|v-o7~2gi/{Wb͌GPNeן]+Ppv|7M܂g@eU0Co]ҽGPSsV x}0Ec3PJ@ `t $TD_/f⤏lrpΏjy6V^iӦ!7Cr_!MֲUȦKflǜ-;t%ϕӁ[G[)̸v9)`F_gsxuMa[z?wף!^arЭϕ&V-J9303w!rƔySX\R3&t=g64l\n] 0c6|4[=FÞ\f `&LyyvoUh!ƌeXp^b!P1Qys9q87BCހk>jy+9&L}FU0] U3og=_Lڱ $o9 L**–#ܜ2q܂,Z&N=}Y5;vμ{m@y^c׭tΙcǗat^曓[ c{8ӄIĒ5ͽYEiكTcBh@E f`ᦗpS^9{]L2 uz%w'GpMN((#p~"-pzsPJ@ Dp!5DZn)cc'b Η&6ۨ:uᄏ࢘`I: \o 0b.\\ihf?;?}J#"p2u(< (0qwum[g21h 냴1s)xh;f޳x|x}9%2]O8G+~j<6œUwr80`mnj ͱSE_5j 9&Cf}5ʛgpzRl\)zl`x~gـU'ѐt)ȼeQ}zpP (%Z+8C2jKtym 'WK[׋sѱcG9lSȟ:-#<>Ǎ WrfOD 7흏IW vE7{&wgcqdJ̺Wt/׀ΙNϟ6.f/OoēYww}t#&cd5O:.~%՜dM^(5 ʂr\’ 䎘a\^f?7ܧ8^mjsWUu6+9MFzNC=q!''͞ Z,#F{Ɛ z.ɓ!3"NkPSЍQI Ajꑜ"8t,xL~V& e_n6>.}&%%a޼yɉf?Sl\l1)Er%oDI)m/6ɮPJ@ (%pRs>iXƌo p7aXml*%PJ ^lx{.HK[DK. =l(LJ@ (%hC^Ci9{S_e&"h瓝}6_/Z)^9_d9Fx!u\{ネPJ@ () ~g!mn^6;DNMU,ƫOzG[ӷdJXjr]A"K~jֻhӛ{>؊ws`HW}@,'[SPJ@ (2eɗ~i듮MG*2NKk׮<:{E%UA 1/1 }]{_x]#V E9⼕85P3ŖYơ;_յtJmB{}+%PK(G='HTtQxZ.Jm8?5ILEE|Mx6lѓr^JOD<#;"M!(2} cU5qb&_+Pf@KEGy"OPJ@ (%`фD_ÛrJn6.N&9fΏ۶mßgL0} #mwޢ*_Ǔ֢rr#kKQ:Ie#boaʥ}:*%P /Z^EؾDEW̉l^XVKzjL6 M<4N٪ctN6edt Ν:lOnFL,[9'saSJ@ (%|p(5DZn)cc ]`llrRoJzU0'QBt)Es+럊zznZ3Oœv_`bwբGη1E*[S`nK1 WiLmڏV ɺs7Ɣ#Y-U7dQͿG:\SgÐjcJ@ (%bi [ī_lv+hr x!鳋ǜnmff&ƍk|h@Hp6WWEgxg#JGby@kAnFƎP:=h>r+%P.x8]LR[Ki('~Kb2*QC0ogc~+%PJ[SHa|-F{]! }ʡ|iS _~XmPJ@ (/6/=ATb+j]bx}Ε6|V (%P~ HM#ClwmEbe1^}*+?&q6gd =X{E?O:KdNwId"¤ɱkbMP]]kk<8ߋK{-@c^h} c@>> \mni0/IߓzP]PJ@ \۸%]}ݎs'z&l\M] 9?ZLB ,[ w]稅QH)W8Cѵp}ߌ+*ĺ5> $aߪ)P GtUl,⧝ }ab\ VnD,:A+\BeEJ=Oo-i羍h7-c5ʭ5|z's- VPJ@ (`M-OvC㸮DO." ټ擱^1 m6Ƅ зoȹ0x<1zS xV8usU-(Ɛ;~.E_DZwl? >^WañĪYwbge I;o/x}( 9޵+E=`j+z]7[`l>~`.n9ɓJnPJ@ | i .Zj cR,pk=no% `6ٶFvXz5M&1uV-Kflǜ]ͻ F7|Tet#I੗pu|Fesd 5~0eײ5xd^<<=3G3F Ya0̞~h+.'d!~=ptংt9fL?J@ (%>b ._n牫m/$b8^ڼ߳gOדڀ9Bt)Eۣ"b#` W55s Ȉ܄uGy]~ubDVY8&e8LƸ[nAV}=&N=JKĒ5ͽYEqAnp9*%hXMH+Uյ՟QX i&MԩnF 6 ;vl1MNBlSȟ~K̽O'GCjAr˺,GyG7x؉i-ð`9&jʛWR](JAba4J|[|c-[gb԰l!po`^ؐk7UPJ X{};G]4ۆlciϯlvOgWӱRΘ':VYp},aX<}j& 0+e\ 0zt/sOVfϞCQ2,&UO0:<b;usMiqyc򱨳4v'{$̛7g?Sl\l̵J*cbD_i϶m-ѨXgc~+%PJ[SHa|-F{]! }ʡ|iS _~XmPJ@ (/6/=ATb+j]bx}Ε6|V (%P~ HM#Clwm-x PPJ@ (%bHDȜh/m-dAPYݗq2_J@ (%h+~%2u$*dA\m>9q' MMXlV (%P6Xe\,!c9?Dp{ȍpi_ (%Pnbi 7!F|5}JtEe5P (%Pbi [ī_e|1WtyMmgtPJ@ (8ī+FedI,GHk?^.+r>OcI (%P JC9+yxEIMcC/s'^J@ (%KMOHUeW 9 " D FZ -iv=Χ8tSFDEI* QX% RPW5{[osν>@j=[^G1?M6Ots%ҟ[AX|I! B@@%A?9>z'K^ :]!B@"Pޏᢝ)14!] z-B@6DNGWz?;M?1ak3s%B@ *9A7ߗt r:kgB@! "9EǽN}x4*MOcBڕPP!  ?|M]ˠIL}.B@A!Жx^k&=~I'}~1mǾ$B@!0hr>:^œ/M(| >oMu9 ! B#%ANB~r=~IWA9_?[ʑ_! @ 5c,^rcmўj ĕ+s|%B@!hyM\精/9U8">B@! !-rsܘ}"]qM+i=a% ! B@W1eJJ׭hwMNB@! z@W^9 >~:>z3#M=.B@! Z#@Q*/՗k%{%]m:+m'ur ! B-9>9g̏vӸ%]~\hsVC IDAT>3_R! "Dheɒ.?1H9ANd! B`chxJi5~HWn6q~b?17e ! B Sxc?NSOAA6rڌ\I! B`F'J-z%!]uqvO_v?9@WrB@! q "9X[tq%J\1~I! B@Dx}^KN*'x)ǯOB@! r4q\>7fkߠHWd sZOXB@! ( -"蕿ac}wٽRu+c>]!B@Wxa|y+̈aSϤ%B@g <:K%?Z^IWNJD}{\>jB@! h@Oxu4ncdI:W"ڜ,̗B@! @D>Q3?ڹqc.}u mN51B@!  %.9sZMҕ``O̍qB@! h@{Ęyu9>C8x:jP}н6c1WR! ذ( D|}~HW@,'\zI ! B-Sj|ޗ/X_WAddJ:&T] B@!Ѐ@?uߊ t DzB@! m%ft q'cyKR! F ?裬%k^܄r>NvY_B@! <9P$'WρStO+B@!r\xN<Ƣ%7&]~`@\IR>z̧_R! &^|5|.SEJ+#^+|ӇfL5S*cIB@! dx}-rwT0|}xf}u4Ni9sFs9Ǧ)ZS ! pf t7&nG%ct |͚Vrќiv-GWUíJ$B@<H kC+z~?b>{%]~:k`='dcs gشilkmD7"LB@Q"GxF3m3 ֔@nnK+Wź:W"ڨ+urOhCikl4lih [9ֆG[OO! B#Eu#sxh7 ݘ?YΕ6'Knc=k%6PZE| ! B`=Oȇq{_e~h9ANGB@! (Ǩjmc=~bnB@! @"#|̫EQzm䰵B@! @O ZMKCd9yzu3OR! m"W^'\}Rt&'S1R}J((B@VeФOOO&>KB@! h??c_B@! 49Ae/aN_t&qr>&ńB@! 'D?z}Z ~r\ԟ-/B@ Ds 1e/hO5cJc>B@! 4 &sYߗ*UZNR_{t! B@h9FS}n־A8ɦ@紞B@!P@[D+{%]Vb}&'C! = +z~?YWSYæIK!  (xuK~ֵ6ƕ6:b|ՄB@!3Giɒ.?uD9Ys+/)B@^|?g~s2X}]dI$ڜCkb2B@!0@J1\s<%洚f?+7x8X?c㲅B@!)<1r|~Qtqb)'uԠ{9lmbB@!a#P@%?FS=8YN^gy̓B@! @[k\%tVGW']! 9ExToP+Ni9'D! B@h_ⰱ>ƻ^IWXB@! @+低X.~5! B@E '<:n1@+mN zK ! BW"(ܸ1{_>Y:6' ! B@ ~ O9 f0N0X'Ƹl! B@A r =bǼ_!]i y5>F[+)B@lPETd?n NGY}^g=$B@!)r5>u՗|/+IWi~2%*׮B@! h@ko_MDd|t! B@ _3yK81o<%)B@A#Q5~IWnB9'cyn⬯QL! (rJK'JRB@! 9Ad<`cQkT.?0V _)K=/)B@@`k>}ɩ"]/aIB@! @&nk4l銓lZ}N +Q! E8l.WUn%},Gkr2B@! Q019ޟ{%]=uc~m̟,PJD?B@! 'J~G;7.s|ץOtA z?t&&C! D?E;SbNiCr31.[! ms1.~H/v~b^G f,J ! 6%>Trho43/uzY$qa|Fa x>cݺuԄB@!Pi>OhZF2>Ĺv}>x1H,S2bЫO#)9&cyJ(YwBr ! B 9 $(}=tcrE |ϥOR! 9r\yS0({ɍE{I+WүϥB@! @DW05q T p∗r0 ! B @5sc tI6>(B@M"^K6x+*u^>59B@! ^y(꽒:όzN6L\B@! hyFs3T_򳮕t4Dчï&B@^G1?M6Ots%ҟ[AX|I! B@@%A?9>z'K^ :]!B@"Pޏᢝ)14!] z-B@6DNGWz?;M?1ak3s%B@ *9A7ߗt r:kgB@! "9EǽN}x4*MOcBڕPP!  ?|M]ˠIL}.B@A!Жx^k&=} ʼnI[1o>{ed^y];wns['?/cXn] MD`ڴie镜19gv %#OF12::jX̘1ðLձRHO D |!ʕ+nz{1]LŅd…FnsΝ4z'߼.]vO)myҥ!nc^dɼ?``=n6{l͚5S13YfV[me;찃LgIE¦buթ8f%AN:ؽωFD%>O$_?=IS| _`,Wسvަ㠹lq%S6444Pt}N;4 /x|뮻ڂ :33| /?9;}toy,b-!-%Hꈃa:QԱU# Iu(#т 6u,H^'7u+6kh=c.7mˎ6^4fΜiڏww^˃4 '.FFF}nExynb m=g >Kwj6xtA@9L`uvo/C]qag?[ ~n˓lr =u6֖/_nK8.\wؠ><ŶAy,7D>קty cQ/$zrX+$Pt!-$dhXGrWW`?9*N+_ZM?g,{_f[m"^b|QDOpy6gΜc ^j.]X7c /_n8e;ĦWhđ$ߴ¾α-Mxa|ߵk/^;2ۇy^];nͮE;W I? }>cOƹ=+7 xefY_&'Ns\,\Y30la$忹-gǼ\o|ve+ivcOE 楻c3 /[n-U`7W/.zh;.>,=Ȏy~K̞sNsExddz>}[o՞g7>>vҷoc3zh]gCb2cQ\w0_좿޾2_SƯ7 {dze⤵ [,0wz6;=Z:[lƯ>LKߒgK;C.Ns^k'>yV]O1uժ鼳vgr?)9 f_gnc'6j?ɶ[k77=.70y{})|^J&tzNɶBʯ^d"^>u"nw~EN`B=g| t2a 9 _JyӫC*n&ڝ_L&ilm~ Skׁ N86veaGPw&靎=hW/NjrKi;+kMv{\pu!5?Kt2kֆY'?^֤CұjV%]z=X6qrÏδ6mMރwV ; ۊҺwe cTI`bw}$ӫwFFGlN[3h6>X'>ؾ+mj#;_m+7JѴMuJ>бਭ^ZCC3Nj?O+͛9)9 [bo/eIf̚ckg +^~lp7uӌx9./M<)MʽJYJJt'mW贈\xr n㷳qwgGvtg]v6{↚O?-1Ǯ6cRk0̯ b &-9m γ~o7h;ka-;Ž9x%чnsrh'7sGƤue8ގepwu%*pH[t1tX9vbBҋXiPb2>GG]:u}6߿k[/2[:Êaklupْm'p]ݻ}^x̡9ͧT[fo_zeK쥶O/-Y6t?IU/ѧ~;Hٍ\b7_3"JY^-y¶[WVY>` >k=_Ԏ~N56l^= ;7g;-lM߳fH6 IDAT֗7RK_{{~ث j/󯵙^by'}㯵MRx[fUd$ 0P7dISvK[~Nr׺C67׍ښ`}u1*߷'vV_}a:/-`{Ջٜagvڏ/"r N8xos3 zC= mә?>c~m̟,PJD??Z]|o7{^koOcn X$藩g%??noضP{˖"~݃Gγ_t mw0K]ܾͶ~ݳ\? Ͷ]7ɡuzlݖ tx䂋4pPFE9mY6/}/Gm[+̎y6#/~oiYmO>~b{ux]tvawή^zv96vj76{nK9g{7ߝiϓwM_!{ߒ^c2#3UwWIIi9g9O>h;lxoOc[xlWU7.`AQsJ02g{m-Sc;?M+:vʏڅWڮľlwvMsOg\bZ^ϼ>=/]hwd}=o±L:-!ƺ8fЁ->,Jbư=U4u[=;}=y{GlEzod]CU3j{݂?]liϻ.OkAcOO, n~쮟}.ͽwֹ6hQ@vi88뽯K잎ؼ_9AN?RUV'Q {-?Xg1 @xwv~dO{[{kvN˭=G7|]oeoĖnOڃ?Ru6֭HG`Kwֿt8 ߒp]enًv&)?4H,[`xCϙ?fLjsgHrzufF:cAKg-}"O˯oy]vQE 쇯_QKvslEz]Җq_<.C _mbcewo-٨z&:k;sGKZjvNmdOwUSh"`#p;n" xv; ux|rm2c/zkl4G9γ`l_;n3m%iO3oN20!lu"O>gSv‚ȝϒ9_ϱ{?^[M 0*7g;Ga#HwևW[:%B}ml?]K.t!vxt4O+v>Ŷ϶ cZo;\/l 67=mspx ,5Ālښ.x Jso3+5=}1_O9>?u?`Mo!cewIsJZ; TжIw~$?t\113.y;μ~Oyc3_};/3V8t k0 _U N;lk._\x}[wc -}הJF1Zո} I#ܰl1F?$A^ctI:9y֭HOVR-w{l_m;]lmI5f|m'#PigO08r+.&"RGڍf6oǥۮssY̎g s Ic;6s㶤P}q{@D[/ʖy#ͣ6+} M&oy/wN7Ol/N/۟x1#C` .&~p0&ҕHPzIdfpNǏY f{ t]=^}ζ ^},h4wؑ'AKx֮8>|ʇ/]g3s}攽C_<%ux [a}02[ew^yO/}hoN Utwf/$u?^m~D86pAA/f}wھz ‘Uv˯io]6{Ö٥_x11Ý.0k&=u8p3uzύmwNIy\SMz_챑Ν.~~ȋ9)ExcVu*5^;w}]w:*ovi?}NzbZGG"*'?@a~c ç zctuuzYϼI.F{U\/:Lwp`sՕ,!-E{\@pA,p`ڦK׾g?{k3.;\jwCq~N&1.Fӣ+α˿$߶v.wP{o}/fW4L?c7ga/줷`OV8QW<*J@`Dx]fq];߾מf.0x5]+/TՕŚMw-^=gDl;? Oooζc.Nj7W} a{13{{k{]WٗJ= 0?6:w|':oOn'vy-~zDG:nRI q^y kK`yJc}8~ӒVFPZK?JO;?*jɳ8wzȨcCuġӎr He~k1VƬڝ_aOس~>HM/-7wnzE NtWJ?'^;tMifdz85VYmFcYsm L_@@^~a)_-uPװ}g:ve+KKtRNK:q`?ymV=n-Μ[=l5U";tS@҂/ȥ͐.vmأ~9hݧ9i_Z86Hz9;=IwF.léUPs?ጤ;xi[`}~}wXWgYm޻=mю&=e!I0's^QnvrB$sASzܒc~Uʳ&Qyx'O=]_um/WϹ7ٕOs~,|E"\]f:>mu]5*'3һ*[wƂ1lb ħQ` 0j]gݑntgsӧ]MM>>Gj= yOIή/'zV {ގ*l' w[v~]tEO`JPf.\le6I̴^0:Ϸ*gVOZtp %hcag=0s?W?A/aNjc(v #' c>uoln~ꗷy{s;!wO\a8H/ O|-׆!pţ-w5ԉq0qMu>O8QCa*l>\+W߲%GksodsqB置s=kV=lwtuњ!H A?|;GqgiC`?b^a;Gf:M~<6Y}uD9}M#Gxࣟz_dq/~H~d&{z$^Lߟ==1~lK`$_`A9>~sDX/wxea<k{f P[ i 3XPx[sl{۶h;/jeHwN6{-{VEb?Xy<Rm|Wbiw3Epg -W\a]vYH؏~lAS3Xn"!!ux(>,G^GNnI1?\ц$:}hOIuJ,\?ʁӅaϾ"@{Gomط[ fWۏνv~3{GTr@] V$$ `ĻB Y Y`V ށNOveb-m2NJGJ.דlxo6.je/o;SN6 <J믓@!Ip!:b$VÆN)4^5He?+G"Ɋ@tqEo]umvɕ7Xq*t۝HUR<ئ ;gYTwEd Hyd8boOA"x/5\8@@Fw"FË޵c7$/c gjx- $&M<քPw|c~wtd1˨hO=-ژ׫iLE@F7a"c~!ܟ{6^crlwAs><..R#0cDˏB;h>&Q1+n>@=RB:)p۔'k4ճHWd sd*S^Izjg L~pb5i~yԦ[D+1e1a/yJXv/sQB@! < QЏ1꽒:όzN6L\B@! hyFs3T_򳮕t4Dчï&B@^G1?M6Ots%ҟ[AX|I! B@r'J~G;7s|ץOtA z?t91ǘB@! :3JK<9NsYҕbq} ǂ<2sB@! 6ppo%GxncyORWkz?;MO${>?Uc.mI! B@Tp?~w}w}}.>~H6'ۓ,y\X҅B@!0{,O;]S;qn1SJB(%]3DN:k|KB@!"p7ڙg9v+ใߣG2XKGؘ=_)~~2^G+ ]M!  \?No[ne" 'Juyn{+N߆czr'Z>eKB@! 60r?b\Gw`\ /a.BmIWWQ28Q1Xn~A|.$aй$U ! ؐX|;\ \W'+re08Z?o˿.ئkK+~.ՄB@ A?ҩ3.7Cڵ2|t@(Þbi#6$r?ؐ6s=B@! jr-ߟe4-#p GCd mH z,Svԫ H `c TlE9G|lIl1q).?[PyF6..>rb PQ]L ? PŴh㉘QO6@yXOk8sƫu!c{%]0D>rа DhiA> œ6POjG!hS?hẉ,,,,,,,,,,,,,,,,,,,,,,,,,,,, 8 ?uK0F}̃DD5R<}h 3ak#A~ }yy>hi3J*!Cgm!};OHhp~ Ÿ^5^gkUQ_zxjQWG}35_xFk^_55^Ϩ|ƣz}xx}<^5^gkUQ_zxjQWu _y$$C\:}G:H/hܝ\'0`uL봽zn \a.'P̃qH,8b=rX|ڔ_?(Ȍo7X#J-_<Տ.8nY8^7J/Ook?ZLqڐᏹQJ`O?ڝ_2rxѣ|L $O~Gċ:$ه'a~x9^Wq1?~8~x-5 ~4  b)XJ˃Kԡ:ws:/W~Ⱥq1ǂS">}.k1y?}kj PJy%(TwWwvV~qRwW+T?S/`OrѠБKo*^d9̋9sEzI,xu NRE5y?Vv pf|>M1O1usv1R@"VXΎ>Q  i+чLb,gG(?贈C&|h1uHtZ v!>:J$:-b6}Qcн̅Dc^ԫ`z%]V@qE8iJA||NG>el$ yA- n1cωq8>8\T/>hs~_}>1?>hskXg4R"ަ/aV0\]>ڐlvd'q$9^GS"18~w>IDATG_7m9~ʔV$7 b4Տc+zG@m<h9 "/ TÂnj蓏GtH)kGsDMrOwXW:%& r:c)SZYıY/ɗEOY׸)/#PeUٯCT(xxJzZۯ 2^u\N;'g u},+?c>c!vh/8kYH5ITMs`sw(Dxw~`z$^BGC> <ʎ>NWSwtSEFI_@#Yzi-G>x8H Mc@ 4~ K JBqby/%uZoWjܜOyrX|R_#۟;Vrq+Wtkܜj|Z.7r9xEƭ\n7^ѭrsq+Wtke>$4P⺎?Dm cØhC0P$Bq8A@L >Plse1>t¦5q~U" }5^iGE{[Ǐ?폗t>~076\㵟>J}6}ަZ4/沎~H쓱V-1J L u2V)T'S ᘨƀ1'uL>}X$6 sh:~t]xv\~ڔ 9vI(1|h웲e[lKXN9mGԑVd~f_Ij$ 5 @f-㔨1{i~z9bsu}Lb?' bSI0{&uLg:r6Fنtax0xt4I18uư$L)@u9$6Vyq>Fٱ:}Fc>ʺXO&č;aT~#u1?}>ps:ak|sO%cƜ땘;+ *(~2A|| +NRR|l$:F?rPGk!}ޏơR9mE?/:tߣ=zu>c 㔞dGc/|ؗCcw{%]*̃6bIh'WH(mpLhAn?O-jT?O?uxz?pLs6u$Q̅-XCREI?:C?oϫ՛H:DOSĄI@@r(G>$*G`#c?,hQ:_zt! B`p䮿џ 6}%fkus<~ 3>&HXbI\2 @~!q\<uĐ|֖>h~^C~xuGOGxT?cul k;{>yx?RWUٌ-ے. w胍l1H,{caH/Bh} CS§&B@L=SbD$Gmy:|36s(}1&l,hrx+-b!$D>q2y?%# 6d-t@8C!cOԩ ! OGu{G>K>`A\?pv\7seWU ᄘKq,tJ3uoϥ6r/| k9 W| 6r>'rFn_h3ܚ;Vr^\sy%z̃-C>sG14d'c|EXIƾcGO"ʓD/H'H^G.k I  胟:Bco]u9u1wè.&Gbhyrl)Ʌ~ч\q}J}u9u1wè.&Gbh+cK{”󱿒w}#1k KI>ӣ6IwhIOX yq`Ӈ;rb..uńuH]L??8rяTV砖 %s CcN^%\3}kź D2c ~H|YGcrѼNH?.Ƽ;aT~#u1?$:c٨Cr)ges~ٖ# Ęmꔨ%t4_ٕcC 1(;_3'Ƽ]9RɯmԄU.._+9?rGF; lARgm/#z\|-cPWGGOvynI: ;Iz 1M-7Ǹ4Oiq?ģ=z}vN!Θy:=`Ohx1fCݏ5\́uرhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh|a8(} #QKh>'gWIO\+胱^$s}'@>@g9>i߶&5^gI71kx5^ocx&kTǸ:Mxq_uƛzS7I_:}oMu3$}כ5^gI71kx5^ocx&kTǸ:Mxq_=ע$duڽJ΅uKz. 2GD&$9G.?hS6%УMQ~h1B@!tC̭d9E~H6PF?mȘc].#1umN.JC>4\\!Ѽi}˞~51WMĤo"&x]Nu aAy\Sv2v/8>΄`#W}:6uϋ _žJy ! As61ucD!_::&Qg#y^OY?cQǜ:[~¯UO7:~t<ǹ9<>#1,2[̋ 6hշ5xcv~ٌE?:ls>g`92|6 /Io]C9&1~u4DŽ_3Fu¯؆/MK.7Ø%Si]䦫hg]Ni),B@<069muEBӦO/]! xz!+i?z2I/cW:߇t! B@m/uj{*IdǞl}+$B@<,Il}_<qN}"! B)E)!W5~&g:B@! 8O+5>-iB@! B@! B@! B@! B@!džN0IENDB`testng-6.9.12/pictures/groups.png0000755000175000017500000015432312732165123016317 0ustar eugeneeugenePNG  IHDRYiCCPICC ProfilexXy8To,c'=AdߗlYc`%I)*VR)$f"ٲZDJ3[zy|sous,|@?H&j`mlԯ=8kp,o0, )- 7|sORF[QC3`@0G)e[Rp9 xQ Ƒ0$Yk8ƌ]vqzRtGb%y{+M$j}^w $+0 <ïe8f?rhÉ;zV?ܢYA=r;=mo/± - ~!YF.zk P ChBnOSQibisB7cY2e8Zxo^1_~`dTAN"C3򛊴J@Ն#jE4ifi~S[DAaѐɴٺ9!kf6^v'9 dqtvlE?L &'= ':<-uYsߍP{R}\WēSiW_Ξzpܭ쌆oe'u?=7ATWs#B"bز U55j=zjLAM^\imjni+j~ûٙ%۾ץsuPpHh+̯$5c{.v\m|y{l'ON>}7}_TggJ/~&BŋK=?WRW}7fˀH*FA ϣhj [= ]L 9l0k_}yf?B˂B5"bKQRyKq2+H**N+5)g>b*}ȸZ50u' =̓ZZS:zOIc7M>{hfcIr6;k`aaʼnri8(W;󘗁~?~"84F &4> />qTbd(Ѯc<..|=>+J_ISSWQ1^tcԭwbfޗΕyp0ODX#l!O1g {) SRXn)SwIH=3FƟ[R_85K4/ԷƶzyGWM^>ꁔA!ahdlUkbcOƫ'g~Ș̜X9? _gqs__-(~(Ի|qtM|i 11Aa2" ɉ|">QwT}ܳ* [6fC,W''_ 5Vb8zƒc)i.鎃gpr2E˫T(P$(q(T:,wJ5<hs Zz]:XS , 1Ff&,&Wl4/[Y Yg'(lٶ%8su<dW)yE|d~y_{z| Da}*&LBÁynbd/ەkW>:P>hb:6O+t|ԍ-Lfb^4X7g^Xo' QBDMCCyND,'#{ĥ#q $JHɽV(}f@vz=l܉gʋJs+k͟=e}T|5ݪCkw|v8a5qo?BϤ~M7?z/XX Y_w0oIn ;P+0DD oHud(9CYQ]p a*A &jn`~ElZd:vLz=1 3L6~6l~`Zqt2Vc'Ј-W +#@PJE|tĶ$Fj4O&V6SЄ_,R;O8\}ESBvNA+c!gX-r-|3/w8&D|uSr?%B F 4>%tz,Ǟ0 [|HԞKu6-7'3\nOfme߻ϖ{Cr#bB2+*UeˮW|Xz[KN>|`0qTUϛ1w:G&ݦN[}ʙ"8k4=ւ‡X][z/_++U"ɫk^k777\6766ǶTm-llP/Q a4v_ܓ Vbb <H6o-8Bv[G7ƺ a/MIưƇ``cF,~~;=.Er Y" `?2^붐B̭` Ph7"O;6gbp7Y?@ xw &}<^ ڑ#e?ZRc^莎/uϑ`[ہ++}mYxG^ofnt; ûѠx/M8y %Eɣ4ZRXHP("Tqa0YӵSLjC0 !)kf&L:TzK5ŋrN&[ccX0 CC 3EFɉH.#rIHQ$|ߧ],_V!`|#0/:c_i&k8J+uӵq۾.O_( W~~v޿(bs>nm8,U_X.e' SXmT۝mjڰ%g?b3>_}*gL:Q8k>ח}ܾ̈́~ߵua}ʢ+䆀!`=G'm\?k㶙w۾׷sulI'ϕm&2ձh<%-2^>徟ڲk~+k~+k~+k~+k~+k~+k~+k~+k~+k~+kV{,Ovi~X;]fO+W8kӥN"EGT:4NMX8[ e&7?agjNk}}]XՅ}NQ5tun[OWnLi T_tj7_Jߏ"8}֔k[k_r}}Xߕt,:HOGSU,26ګ_\թ3Ϳ+_f?aK龋vOjs缴ĵt*sk͸񵯵?vܷ~dۻ}mkjۦmչ29q֮\mYkQ=nq(nt|S00YT00#U,;6OQQU,*Fm*L^(g~Z6eޯ]۰v,JG9KXIm_qem\B:ۏkSDŽԖu\cjkWG0=mXTuM-1ǡh~F9%Jޯ2_}jYۺ0;S;o)V2yCՎwIYm\] +W?֢TʣVG0?vQm |\y\چQ>ԳdOzKxR7~vuwenzV~W;_}8*ski&mj^k_er:,Qu.pGTk?bG{&3yg{5Ӣʴ^a5e*ov`[W _j>}mVc_Vu6I5)`WO[CծLl_?`ɓzTYYtb!`( g|ɹ7|COtuPQ$Zm6֯Kh8c&2wRʵ/C/~􀦦&_dR7!`@~~>JJJΘ1y:9\J(}o̭u)٬|@ISk ĩ6^jJʗGy䤼l٢cXm!`tA D">c| (y\W%(V[iv)S[իΕSdK~`&϶6klfY1 C0b _)F@O5*(J6~K&ݢ}f^ej%\n{T҂ WG_GSm-FIU>qI4EEEt19n]]~ml޼md лwo^OwyYۣXun U٫ ?N< ~qs0!`"˼K8Y VNfgkOU#^u*rڎKPrum(ϟ'#ׂ} /κrο7dH[b֮]-ms\#K鋥KwAyrT@y%ݰu+eV5 Æ 㩎X<=gY((a@hmmŚ~lmY'MǤCKg.hhX-c_Ii*_Xޣƀ2~b8ɡdKԶ֮t1c[eoJ'ݕ/EnvA09e. ͢$SzSwbX^7t?D}֙h[އO<ؐtI\Ge˂c8p 6 \>XefB; ਘ//>2C{a{-Mux?Ec0Op\Qc<5o?ƥ'doܹ`6z!\yɷ qh'\~$ZTۜe𯈼ƒ?6?O%]m6 uheo6䫉뤴VӆrNDk>۝G΅cL 3 .E7 Ec (@ ˻%ʅk--iKMVjڵ1mz {wPq OA#%ޖvL>\KPV^eߊ$bdw0 W]'N<{h^"wt; [n{7㎿,Lyi?xB\}LuU8j2~.m55 $zgnXCY}_;n{,x.|?&mϹ4aeso~gOJl:: 7/> <,~p#'a9ɹy'C&xcǿZU ?zu/pQA1_ S7_vr%b?@ \5,:yPk/.EI7ITSmV:i.Hc=8)k[kv+^k1ե%, 9j-MVC=UuɖzǭJjߞQQQ| y5ki+@SM Y7W nd:g/'{BNOo .1!}qrn@}{yտ;=%,%pY}|omM-8Gf}xookF{&\ґ{{_pGC g௚00{&|~qqqaѰ)_!9{8Z!hXB,yw\͸k!պ~ހqqC_D<$/8h{b;yʝXȃ# ]w"]i ִT{۫g"o6Yk8-i2Z Uy˕ڥEP݄TF?d[PXTO~t2!Bk9bYy hlBi^ dYG$ڨd˚jH,/BE-/ eE(/ >Bck r:6Kb2+!P|N\~X*<3kNN{}. lKe#pWQ[>c3xq͞$L >tY?Ot݀꽏^?yl ھU,Ĝ/EMh˸wWb #Q!ob|;3~G}+o+zNw58dH 6̒C g(0 E۔\!cůoSN[_>|Qk@Q5mkq3PX)E} _H7$mnru*O۴ "q1A hO س9|_8jXzp"Fkx{WΘ48lY_geR਎)>fkߊ}"1>3w~xIIW ;,O'|xDΒߍR;õ8l$˨U\8VUI$Y:޲ATjo%v;B? V \ Qؾ6ӸɻKJ;rf\._x;+iog> ~ _~X9W'N CY1r@!o_S"הiEvGm]Yp> G;nrlڱ[j8,;4]Y'\C][O>B xIAWJemx߶r$Ϟ$'"D7=7cyEgr9Bd^l>)~9;J{˖AkJ1rD `k]w*Ħ2Ggip[ErE۲tЈ5A\raO._/֭'&/Ts\__]GE:=bDr`,!' |' m뽴I~սq"_q |aEڕi[0~P fSjðyB("x 0O=${^K6: ZT߿?֭[0BD塤˶/9-}r>Ge[/¡G"?aTW$VIzqq">xZ"kO=oO4`yfO|3S`*FM1;Gr1|gJk—p|j'F$&WyC&ږV߳^ַ)fϻ ''>lkƢ\Vn삡7Ĺ?7T}Ǐ X^y0a\vS>ΟXL{( Vռ!JX֊$ls1+G@Խ3D2wk uh _::˟[:_oܜ1kh5 %}$4C 7(0+|٪۴ v XgT2!_M5AY+͢},;@4!l=N9YN=!u\,erKY9ѾϞ1 6XpRexiC[L4ᤃ~06Ȫi m~uV.ވ=' Dl›èf`XݲͰ`'wN&&r}ѸPO.F=}\~у/> ~{n<MI ԋ?K~~-^8Kpg;kph^nOuy7C{\u[{w+W;_vrKQxWŸƟԎSn%SIwm[_,PrB\y&y~CՖk-矇_~.YO_+{7̗U>.9ɩ%Ƿ%Cߋog6PS#9U¥6fg2-n[eZS1:*m3;1O[W϶{POxPΚ2~P;F}HYx=[T!ЂoN[)7ȬZ Ur@DE$ 0ɕv\)-/8> 9h+kwUb}kM[bX%u*WHgX&C@T(mڀ箥 Ckۂ@Pнvxea}Q/\YYQMrA~C9Q#a{XQ@n0W{g oaho(/h1rQ^ZRIصlCkA v(%P<;j [P$w,H,~oeҾD_=Ck*x k_&/_=@~,GJލK۾`jd%B0 +SC1M0,䞅*dӡ'ɛ?"SS9aЈ%7YmKNUx|ѰbӧYB-#>(5ɑmOyuܚ+S4Uƺ0@XQ[m$ elCTuԇJSҥLY;gI[Hl}p=R/-VW!OX녈WR(IU0+MWêri/3Drn?8?0!ewȜr MܱmBs=Glޔ 6wS? ]lyɶ IDATk,k!pyM9ɗħ$Z$LFJcp`ƣ\mrZ6 C0EzTOێQy.fB=- i2q FcՆ!`@:(OXxŕvIjCNq}R%7%T51֤Uӆ:+!`@&(G۬YTv%W)˗Kk~PLVgMJ~jۍ2ж[o!`B@y'Zݢ}u6*׾[Sm>:v:u ԩC}Q;;ZmhhiGlB oi!}Lc!c P$壪Q N6`1TQOkն[:x77am}+lNmY1 CI .ޅPQ m,5 u?DIj߯}{֏EFWIRbueXmS.vȻT\\Ռ7Ƽ]!`;cKw+m=M9)9\Zwe_}E2)KT>aEs}jy<ռV6/'ZJ6Nw34!`@|۾&ʷUMQ?OXp %V^ekل7Ά|@nR.LÝʴvcvk/O;sۯO~o6D/{w7?W;ĭފHƋٮ̯}*O\'\TNK"Bm?^SSlй+b/..Ogmm]U_k>y4r|CX.gLI*Ýun_c^Z.Uzx ½}AW◕'t%]kƄh[7׺oA-5C~!Ld7Æ È#ѹW:?nI%%%eT 5?3V9EkpUE9mG\Q8N]&nqQm7Yڸ\_6PoZ >an(ě( G$;K|~,q/1}X#04io!#@2-%ڊ l޼9 ᢢ@GA{.XgYxD?W(Ymth)Ӛr֧,dBD/s':ڦcj/ub}|\T3ppZ!߾ʖM^-M.UX1 CHJ$U,Qկ1O;EQZC~]^R\ɶfJ|݁&a}g퇍Jj/*I8C t'~=L:Ԥ^6 C؆adxkeCe\myg Wm]uTmp\m}n~z"D~rnma|#A~1;񒳀nxL:mQU*:Y- R0OC0v"\bgXfMpSs*WLwtP}_:Mzm+ѻc]"q'R\cO ~-D<< 'wSFw7IʹkSFf`\ M˗/Ǜo zy73~fNhޔ5~xի(h{KƫDyT[}YںڙoZ;hu' &:AJyI=&bzvd3Jqz{ҵxg!`t"1hРN '}VteNc%29t59&&֧NX'Y|1y:cŊ)ɗA OUҍ(JTWn[ڎ43YKK\y4tJǐTr水e(KӾ&}Ի i, C0vH.+_%_}/â5CGㆥgqt=%_?`X"*ڝ4WyV[o_W}Ź瞛r3 CGJ2Z+*RN[Y+GՆq ezNQM\;?>[ .q2WI2jӮ kƌ6m=Xgy&ш=xc0!`:XK+*9+V=L)&׸|eK>㱄&5!f{tHP&k0J:/snj hK 淯`cXƋ|Wl\r!`;-%*v(.dIL#)jF^Tܤd^؞u-y" )Uꨘs .ՇH'%Pg?1W~ӶaC-j$y@K60Yb,!X(%bdYT}+Io\>0. H̏ӣ>O;PBb}ANT9;LŽ$p[|s1r@5[aʒX`7^bE)V։Ext2.촵!`; ;9iâu?G$TQ}]2lΕd|`ܡ޵?w})]k,E 'MbY{ wex.8/?8 |"v!L^y![Ҁ:zڥ9 2g|!hK5ߙ{aΛk3rdN!`%]%ZVk%_mgRE.6.td{U(dPa62fyʂ$W*Ne#;bgc&≅°]BWN8BRq2L B(([F}x)V}ْ;HT"ڦڅŋzKA4{8<l|9l >)/ܡs$_k}C0 4H?2$NܔeKnTܤdnsCO-X]րO]7uԼc:{aOD*궵`n3/ؒkb MMMغu+pEEE!Nuu53>Y8p'*xNkӭ+M7IwK'tWn)̥<9DN#O"8idwV=S̃v ;|<0o.^Zy\＀ۅ@+ϨZ] 81Tv"hgb!!occ#]O< //F,U0f)|bP :} V!A]u۩&ALȗ5I:g:o}r`\-[߰lmsŜc'[/01ߘPQd6.ԥ8sqa\. \6rkq,f-o3.q|`~Ø ;΄wxXe=Z<0 7`.A"4XX8:>$|Ѿ֌Om>eLM}w`71mWy+OL0&mo ({;5@-G9gju5μ)|u jZOFm-X#1-!d' 9wn}amC0>zH+V5?mMoxQU)Gb䣸p e \Dp34B*W;M}թ,:$f 6&ۏbKA+(sfriu 99jkJ7q0 _^lUWe 񖡦w)z*(-*@^ñ+0t 8p{rVKK׹}w9G`Β@!`WiCQb|P׆]QUe;F{ꅂv|Xrlq(8|uTƾ>`g` Cy]jqqp'j`󱱱/-NU+GV%<MO rM.I/BL__uA@#y ^veVn]C0 vo/Ƙ*+@7M~"Y"9 Xn -٭o=(a?*Pl֮,tԿO& $qQ:ͺ- C>硲0X 桠  Er<螧I=(QCRenƗQ&/钯LS&gyzcƌ6m=< nO[b!h"[{[)ǔ C+9 ,t~kMvwm|MFʴv'2Uqo))+#ά!`l'dK 7OVzy s#sE|{ICrX/ߧ:Luv3yho ⒨:\&﫝Osj0ЇOSb!Sho N/ne oOqbolig<0ۤ&lw5 *ҤwBF yBw5(So f>ms䆀!`@ ON+ *IN;/WA5xr2'%ȔO:qS杋sɹIR&uFPP?E[PsOpWH>24!`aѶ˹e&愐rd%D,`9\>b`|]ɆM$Lq?ݍ*&QG8taL,Y80 |KEBf C0f.}LbBVrY=_䲃os8*FG0R9:qDh'se~\u;Rv5[8E5Zž8Oa\knЦ4 C@M-|Zd}$?+"'l3eI0#$7W+_?IMOֵ[.e;ݕo*]2qJ{(zafo0 C vF~ nʣgERCl%Olgg(wtk|Mҷ W[ t{]i)P9]w!`d| ?)kXHH+܋qnv[?Z$궷y蟉}%epMΙk_ \- MS- NjVrĵ-!U0 ] 3 lc;s4\o\H<Ê!`vƛf^*^^-R./ mIـ.dT2V!` H86X˵BYts0n/Il'8|930u+_ip^veV]d35-3E CC')W|spȹv5"A 0Qd[ve]|%_7)7@hP'iҩoV5ږYAgN!`lW^n(+rl%\g#&[rssǐTr&e(KӾ&}Ի ijR0+0 폀<ƊSeVo3dR2JyGkFjǍJ35_&ʴv'2WyƵ [un)@!h!4 C#Fn~mR'EC"zxI)A-QOUGdKQĪLkߕQՎ O;Fq RǻROxvp͂>sa]cݢGp|,$@ʧqA|k]07>..3]2پpŒmƆ!`|X֦Vhh--X@mS;6!5kL>h@]]kQf>lO;D%m0hҾ-e]M\wm)aNb6_т5uX)}hym2mDrrȑ(O58CC~\qb7\t-n?!yϘ4:r~0 C`C@7!%عyB,qQCcchj~%rf\lW&&a27fN $# ,nmwK*$ꨒRG`uQ疂ØUq 1)q3mNpxɑeO w Yҷȅ#ƌ) p"Li7\uEz!"C๗oĿVnūKjhn؂[Ѱuv]6./gŜ(wӉwmsuA1$};-lʖr=}dJsnǴ:4% Dc0?ބE%aO`|Cb_׈Bnah0 B>x&a*"ץ%m(;rSM<#- C7n(, By3>lޥLMf~.}P 7uK g屒45`?_U {m|Ѿ֌Om>eLM}w`71mWy+OٶL.34 C`#=—x d[چ-(,* mݖO8h>BQQQ!|}ѾK vӮ3!ߴf 6&;mBۖpX0 ~&橃Wc xyU>h|m݌y1qX3C fyU:sUq9oM:Ҷ%%ܾ;Ѵ7CC0 pqq1F^k,7[5551gE-[]]9zLUYKT 42p5iWmy=tKJ<2Y?T g!`z $DKoVa?*Ki2yԿO& $qQ:ͪ閂 cڍ|z50 pHJ$\[g%\.s60~ O|`ĵuz78;Uo)/6L[S!?!`(hDfJlr+ ʴv'8eTtK=9;}W8g!`|ñ)%ֵkGg .q2WI2j3s Py8Ib-܍1'LĄpHыbƆ!`|8DG'׸|eK>㱄&5!fK$2\$|0[\(HB(ZQf$Rqx~UP)V& WHf:C0>"%RVeQi6Mo<[ 7iWm7I }jwK[lII_w5_/O! FSU9R.OO6l"a2?N|T+_v~Ewh-Iv2؊!`+TuN=W'dt̟cq\m):E˕s>jC0  a:rG u,rQ a]:Ӟh.D<$ׅĕƺh)ر(0 C`".fE6ڹ"t~ڹRPuVZYmXe!`vImʘ2!_$`?$_R0WhZC0vh|Ѿ֜o>veT2!_71݁Ĵ~_Q<6 ض236 C`gDkĹNaߵSyupm~|k!`!+\Ήjj N&+T$|w'曵̶:s4 C`W@@l東.W'ɨNek[sZۖ9ӂ!3!Is)&#tɗ*F&ʴ:Ͻg]Rg!`; a?*V?]Y&ШtM IZmtUm[ f9!!1/չ\涉m|a24|݄6R0 =>t^1dup;6>uL%3/萏 /Kd=Gs4 C  ե uĪji&2V=?-?[6^{ C(|}&}ul 砥9k*Ɲ[4<|=G9!14L)ֵkGgK%Q N4IW~_4~Fu+dKґc CxwZfY8eznBL+]Yf'=<ޘ9 1`b0 "S\M-m|fԄig?С"M:].4`RQG:Em)p٨%{; 'M:X~)}&V,e{ wY*lLSqi^E!GD҉2l *t̍)#-رAyx#ƠeAށEXS9\u~9 xljp>w,vZ10a hԛۂ!9/4_ _?lDd~-w`^jMR&p-p rcUn]4\3b`xoĪ…ie>%eRI {528$[: ێV''ӥs0!`@G\oC/:\oTBDkD|'an)XX*ۑYKZ*vFifh@?./cvQMv7$};-l`ș!`?Z$SALx/ktt0^Z R0hZ,C0vX|Ѿ֜o>veT2!_71݁Ĵ~_Q}A<)QX=K0@_1EDޔw1q`f\3{SS%%1O>d{$nj 9O}u}mz9t:!`0Dq ?U~mN60~ OwӾ&}Ի ikf }= ҽ7hkkg~,GA~^J "wbo9o5f/Kģ2uKk_G7·''[}SnGcOoM.3}3zEhJqu#pPkk%y| sҹC1gr%x~<!"5gՎC ե uĪji&2V=K|B <Gg>XN&*'?ܵ }c?zY߽ф۟K}Я1kDcy_\zm!N;uڂ;e샓ÿXb}b# jI.evu3*mO^XGM䆀!`ÙP;([&i7jXuPiM2Qq䢂|TCq1JʫpEȩ+*HM]L3}`UAWe _=Ɲ0]5Oڿ!`ls^ldQaFZcx;HiߵSY5O;WYQsދa0p8u*S5xcS>TKU%RЂ{; W=ՊO|_K}lZYoΨ샓(O68 eu%w Q' U>wlf90ʫ/W^ހq=Lyixl!"dIq/kh%_wTtT03'>E[0 R?x]VS-%[9;<p0VVJB؊?r-QxXCgG6[ϖcvnă691wU+V%キO;torrz u)3x&4m?؄Z0 ]G6r0 _?t&'WP +#ZFuؿw}oeQH?z ڱbT5cQpG GO:TȅMD<,^΀`~VAo;cm->1؉ILsx`R<.QҞ2!`;G0R9`{N Ɇ\?)Gj1_z\BeY.nI㾥MrhF*^. c^<_7 CA0#߆:_54"ߨ܉0I.iO4Oנ5lȣ#CL? ouܘk]yTSnUg=C0 \!rR63J'ɨNek[sZף\\풤ӧOrc.EE$I7 10><=cI94ƏfZC0v5|90cFpu6c,f0ɘ8b' C0`1VW=ZwwѤ44t]ͦnݺXw%8*Y7OkQn9a"&܀ϖ Wޱ-=3_u+f%-a`:tÍ L gd:C0v8<:6/wo5Y8eznBLAP?{o Uu t+ `D@24&($f\h53`2;F4D,Q[L[$& *($ B V?o:f=p9{=׋7_9$!ܚ!`@"@ޡPqz4P,)7/s^a#4(N|$G[|rLtYkD'7V佭V8C,zE&_UvӉ}ۛ9 C(MsP}l~7&VJ%>}y/l4>T L IDAT"[{xFYNn"wl[ݒ9ׅ!`q?|Na.:sXK\bW7iu^D~BTSSjQ՞Ӥ]lէv\`LL5SςnZ>Lj\(f/7 X52cTn ,MFU+#cɮLqKɒ+wcVWlؤ!`@iPNxiMWkwi&ӹ!_-$Z~mYfMDIo`CMU&˥n4Vv7fp4_H:efΔLUT)MSoz}@57HNifop7wƻ+s]b!P, RGG+v:rB^ 1d~)=cen! ӭ[74iRrRAhս"sJGV"Z)l!\v槙0 C]!$3`dC1wʯ6w̘12bO~ËOzHY0 C`WD ?B1p#?1W~|&wyivį/hGA8{:,0 C`7B ?4h^һTuN^W~Gi'o=\[`i> `!K @$&Z 9d L)[MƋ/)7ݼH^d;vȹKt:&܆!`/>ЦĞi~cZGoWP+|0oĨ3߷鏫:=܅T$_vx̿C~*0裲tGw%S%!`# mJzueN;jy?M|.Wޮ۞v+E >~ֵb]S,)-0 C hΉK:R/w"4A?mڢ|XRuw\}TyzC5mwxlϑꡇIyUhI`%\R0;Lƻw2e{R["(0T?ׂKI N\O1`Sg~I%N;w.ee#dOf_XD翥wrߗ]V -)( O̞AWPʬVK Odoٰ\.ܿqWr\ykE3j8ڰ ޼s6-eheFm~wl-8ysqi?>'qr6eZM4n=ku)ڏrQfĩ2h ^-wv?'%"_%'쒂d[Rpó3}+?hlMK.ic%qsgΛ'܇ Y-eҧ V%ϓK'Z6$ >|2KeݦrU+rܻqvF=IX1mvk2\2nZfOT.XSLB!`8&?agz+ַI{UܠN?>.j=**ϿA~䵧|o$=M ݰ,ۯܭhӗ;EQΖU^ztw'&'SrG[bx Vo_)o3-27˔}#n%¾K?J47TKvrzyn%É2d2 e-,1.I'~sSǻ5C0H8<Ř,>C>OK~g9qڔq~W+v^ݤנPҽGLƏ"?:ҐN(`,dGȗCΖ2snᄾy8ٯ~-/Uö`X^x%YL>,;2E~80{:ٲfrJmi`U'K-]Tʔ_ȵ~JOLV5^-Clh4C0vU;g|+mh"QꝤm8ܭʮ{gkzPi0x\]=i#쒂'Xpò/q#*%^7e)Ij1(t9n2 G;ߍP]" _,߸8w u5#Q˳je[urԼq3VFr W˨ _oy7[|?$k!` 8>nzruNOA XYC%>}yM[ ?)3.و _##K |r;BS5zf`Mej";intSMnݗ÷ڿfΒȕbA,[X!_eFJje1y!2u$W>XpV NwyU| 7#^t C`Fs ~9P.kdGzI _ʅO]IAo!~]ǎm]w}*5aIAΑwliz,lwK cM|Ϛ)7gܲnΫG] Mt.Z4i][].N2Q~*+5ԆK.O/pW|NwAmuunyĖ#en@(e]KzvPO!:U#ݒwkE%qpYhIaE۱nE#squtPZ{ttC0xBDJk*)dɆv$ Uϖ,:+4 CÄ/(KMG/w'iS~OmIDx,h@b"G~bh0nBzGP_k!`!B ?4h^$뼸z7$<Λ`{?u\M߾}_tPxb !`(5j}C}!Q/:$Q\`~>mhB{;p 2uT9ꨣ}'妛nK`n'ܭOJ?.oJ| ,h@ mJ'T\߆Vig=1 z`=1m?%m&UUUe˖ĭ{Q.j2iکV(,=~r]"|;X\Hl!3)K"3C6e!G;uzbZGwc9XRGVhK*n6H5{跢lWyg͹RfG>f! @ќ)t 9mk 1mmkqvQ/xnt+$mQ&ҹʌ%"qw:+{gTTnY'b#rY7=҄e dܒI!`@ARr'8M=M%$wj!Hh֛]Rp<d8F;^~eI%cQ_"3*n9X>"5cɬVȣo<ݒ-hti.?2߭CP qK.pKUN +1"i3 CH?>'qq4X|1( 43/9iΘW~G]z ᤆr _RwlވeztRE;Jwyj5h͢H?ˬ~,f!`@DŽ>tu&V iWOJw%(䋣Z~g7on|~mn-O-)22`@psU^[=&-:!`c[r|m=zK#_mi tC󒂵nI`́raȡ$jC 7K7D̖E2U.#]VNEzeIC0 w(Q'ukߩ&Vϥ.Ԥ@mBD_X?|Y6Y'Zo䩯%7 W[-+d {3i!cP7E\ICYD/A421NRЇo3XRߖ5kDTo 6[1K E?z#\!Mu X?`0 CG |o6C f#|]i&;ׇryq9A?=cݒ d:;lIAe` ݙn!D I.8pgnk$>ۭ|nj##F(7F~gϞY:0 C])y T 'O6#!Om0N%ǞNnց!`n/(K @'ijtutC0 C $E3TG$9:1mFK^mI6!C0TCO%kuN^*M;I?Ϸ&XcWXR0oreSVC!`t&JMZokN/$?ꯐ~|ڔm̛pKcC0 By6%" :l+r'A|['JM\w6/M0 Cy6%y 3 a|;~N!cG`h9rxl`|x7eOHtjfŲ=}L~ke[rК!`@ hΉ=#_]ҹib:Whh匟u䒂 ,xeXyfcieCϪF9ivFzT4i ftG;TfX M'ɲ_I}gHcr˖u뮒RI_:W8wѸX!`@GsR1\_JNpz2:K. I`/3.j5F|}Hq eS+S@ [) ZBЭ!(%{Pi[hq6\yxg4,Shk,k!`?>'qq|X|1( 43/9iΘW~3fj9@,2LkY;PzV1zVn!eύ'M>Y_4Ns~80"o,xToy¬e C0D 1!Bg9J`rWOJw%(]-'K cۼbhu#3M=M2qjnLpԌ1<!E cSi:@ci_;uIq~ 'cl%7oFS.)8)e VȄARrˤRvfv/3pYdK}wC:&ϬS&\Jn9w -wxT`]BWt4 CHyUqzR|k/&BI؏o_%CV" ^*( kZؼ/2ኅtwmLI|s;pή|4jBy)e s!S C0|B7sP}l>i!6!&A42-ɧcfO-;{I`["킃c0 C8B\&.9>6C f#ŒoI_ʅO`s!aA Hu.}q8!ڜXu=i'ܐ%`ɠ C)y jB'ڑ1,0 C(#pW*ŘJofGt?ޏ'ڶ`"<4 C`OF ?B1p#?1W4~"߸ $u^S.`[!`@;H?I:/^"ߴ|;o:%m&)/@Ҽ3_lux!`JMZokP_H~_ibA$ ϧM;p1]rIbvj C0ڋ3)ѿ7Pur}Z!\aQgoW[Rp?kpsYĭ=y2yh>Իb!`Cڔ%ҙY6e!G;uzbZGwc9$;eI-d<7;S۲UYҀ>}29~ƫتMr|/G6eclk! hut$ߤ 1m-:nߒ{nYAzEFI670 C`!@ќTd /%r'8q=M% ;ȶV.lƭo0 C`'!I~ 8}X;ߤA:'"zX\?Eo.)!#(c.]"â3ˁO%NO<'Os^DUX!`@8&?a^ [դ=4ة'ZM3>'eʘ>qɬj?fyJ1[derv.桴C0E cSi:D?owFMG\O8)}%;kIA!W?(mdrInr_<dxVi-si!`tJ' 5ϒrb%_D;Im [>2֊,YeQ~ن!`@SG9Iz>6X D9@O8IC-f0 CSH$RK_dVN\mΟj\A@ѓ[Mzjg!`t!"՜s(7idC;%YT̖, 6+2 CÄ/(KMG/w'iS~K`(ik, L[t%f!PI49"-)ig7!#~^볳N_Rp˖-%St.%ZfOUI7>e]8[Ə.I,WkH]m!`$柴l\}\~/&:]`&Lp,ԔeD|n̹XCYsJ6 0 C Rփzj[-|v[)۪/(^%.[&;Q%ᨴG#e|xprL8i6NsӶ!M #X!`@['qDXA:'"zX\?E555c۠dc75Jદ7Jr eK1Tsw 3.%W*d6/ƊHd퓥;M+,d@2! }M׾[GYʛ*n`nߟTk5B.)2ijC>OK~g9qڔq~ IDATWQK F(jw|;r#Z1p1.">& C PbqzQ,)7/^; M>Jߦ`K _i4Z3-CP!{0`۱cG"A q |tq:'IKD(H'}÷ `Tg?*QdC#U$d\ 14q)t||rb7ͤv¯§ro! @"$^!٠3F_2 Hu.}qC!ڜXu=i'ܐ%`ɠ C(  T/IV$hhB.$Z: )y YZJ|i H. 7 SN:*'|Rn(|i[qK v֛!`;)O) ; $:M/(K2-d0jɆbXmۢg-%H`Y0 PI\qD[Fбђ#i>st.)Ց?IOV!mhX/)O[\RpNJMsڈ@(`IX!`< #\A dH@E/I?q00 /Gq D3^{|= mJ i _A |ߦ?^ .O] iK %_,wϾGVfMjStonN)ᄇzt2r{) 劊t/b #FD۹>Ц$/a|;~N!crA8'I䛭%=Kj]_%-rV[(遳!`VO>i_|Q6n/.ze/.߿z衑{t5_gNIPJMӶђ\#_|J"YRNnEǍų_rX #ߒ>#3Cؙ`ȑ#}eٲeiӦq: QnѣGGČS?R/wדa>ԙ_rLǶ%~V&3.)x巣%/."HĒUcdAH*tk.$c^ fL(e׋L"]rL=No-`N;ciCJ^ pAPBjgI~S 8EX|1(:/|NZ3VHmK p4_$+,9S2UXC%n~> 80 Gh:9J'1!/:Jĩ2`MZՓ҃; L0>.)Xǩc=V,X O'I&~',)X^鈷y\78q4 C`A 隚t=/&टqbLs֣)?~aܴwFMG\O")}%3&R?5{@s+;lIBв\C0Z+.}7@D CaQ,)7/^; M>Jߦ(uL%;W0D@/$6+,sLیSMwsP}l~az- Qz߷5C0 =/v+'?$Ns+r>+u,.W6BɓA&7sp~}(>%c!`;~ӟFy~ׄ\6NΥ/k䶕WK'$1$^R0SA6eOBv,P'.*Tȸk@G!#Zl=c/|VrbuM 0.ioɆv$+Tv reRQG/5Uer+Sڅe[\j<ך!`{ 8(G?y+/~G@|J_k`bivD;X_RwI j;Ԕ}eͦI윩r%ECYsJ5 0 ] M){j~x/ي[%7#i>st,,b2KuVӟ$'6ku,Qǧ+*Nq`ᄤJ"7ƞ|Ǫ;尊2“dƭKv$hd|jq8xNXrGڸzqdHf;r!'!@җ$gqFt`g|9$CIzZq:'O/yl3wf\ԶA}$Xb!P,JMZoWsNŅӦ&T?iV%5#WO^<հ\=ee^[dKIrSrw*%֗!`@_w(7Pur}Z!'A|['FM\|qJy,)ذTʖ9JWkw`%HFjpKi!`E! mJ:ue!䛺S'uۡs ;ȷK fjVLM:P622wo we6zV>v6T:Q CP @ќ)) |[OӶђ[R^|r]Pt-CxX.}h^;4G6;%]guf;uEK wpPyƍ%q+>FќTpח| cʝ`LIG'M1!Й_  Æ j3Pjg|] Ú"r>1v9ʴAIyIkuƼxv%۷Vm!!Їr謣>oDҒ ةKIq1=N:ז,6+0 C`OC cSi:@?owFMG\O8)}-A`Y!`{"Jc|+%CR$}oo0 C(MsP}l~GD(H'}÷ `ApY!`oEϟw֭V8c~Vow.q<~5oro?Pn6[,t`N\t^\NЏww^R0S4 C`7Gċݘ4i,\P}JfN{;EK䶕٥8'77I-ڷ.)X[!`8i!aq駟. `M"RIJ:|)ן?Ў|~?w%۵Vl.nMO}SrAEC#N$`J_\#7XC1xи;|Kz%ae2l]@eY쒂/EK N2Fgt^Dz!`(3׾SN9+P&G(.|XSO/Hdubf~|q甤e[wgd}}[3K# )os"nܪqIm.),[}xʭ!!vp=:qnE{h㡤z=z{QIy.; ̒Fݳ]뎆ۅ!k"jA)$OMx뀽 Pjz[CBs(.t0?6e4RvwYRpܳvZU}ߒ+nJ C`" a5qGs>ЦD|Bym jm=u6q_wXRNnEǍų_r:Ў| z-0ve@񨶮.wԋˣ i_}vckQj_iU|tAIq1Ϡ]UQ&nҷgX/gk!`{8ռWUWU_@KO19K9~ӒmN6eq=<(+ܣWHrw!TeWo!4 CwU]{C0 C @(0N~Ci+|u'mM;|O C0 F㑧1JJADɆv$10 ChG4UtrG04;ن!`@$E WTO'6kutC0 C $CIz̸z|N 0 C?DЬo+U'ۭ:~>m@ C0 v# mJ IT鼐 _A'z`=QmtC0 CP|MI^B!y׷O- !ԝD=1;1M!`B9'N/՘Q?$_Dh~LzGC3 C0:b)˝d6u4 C0:|NSǹh)ӒoҠqɰ^3׏ C0 bqL8Zg2ַIKq;u#Xa!`@ǀӜu h?Ϗ֧%_v`.)Ώz=<, C0 "@ޡDqzX&)/k/jbe>J=a\& C0 b9MsP}l~7&VJ%>}yY3 C0"9X\am/rY'%_=HDs榭yg!`HrIoh>|ŒpPܐOi!`!4a<t?_IZ)ן?Ў|~?f!`ܕJ2 _&fGtS~70 C!H󑟣c |Irdubf~n!`!x(^Wsx)(B !_tI|ڔф:ϳtS2drrSGUܰW!敷>5F&0&3Ylׯ_/ZJz-ٶmΚn1nnd}!CI'$}ȸ#&]~K'eK} wĘ{=c,>=>=J_>Цİ|Bym jz0G?u_c |޵9I$O$rd~dIگyJ^x _}tptOo!`ޑħ {Pl"9䒌o (婧?^>h9W^tW_~Z?1#SLb;&s$4Tw8*8{ZglWϮs,g=>l۶-BscC1M29w=j$Yڐ$ZG.$bx} E.^ $\-KF !*ʆ#HW #{reokL4pt{뭷J}}{rtiN}qT/m9Gťh ޫe5Cs=#/̜9Sz;-/잣45mOj9CSNi<7oY!i[-"p&+]ō'~yL䫏I$`$$E $GI+UN7 }3住,oO?5:ŧ_?;\wck{<WeKVy?ɴS9ʙq+~"kyWۧiD)Sx+]La;jwZ |oʓkc>UXGwlwG#ҝ3gq0Z/?r+U|^eٷH u{}{[auVv;uG{O0|3d~0'|NBǩʴ/- Z+]sGI'erаAOh.Yɽ{?u3&R "y罍z-wLhd:yG4 QS]+EK3WN򗭺kC:տ?Ul:rVhEKCCkzcɗ%ix/ٯ^!J}dۥW&ֵ):>l[\1#YUݿ{l $m/v yrӋȏh) o5$k76J#L6%GK%>8:F:cڇӒ ةKIq1=N__|]wGL&wz~b~Axw<'1i 1wYswޑOTrom{tGwĻuh~TTGEѣO^'z^96w(1B4:j4%K~Gw>-7o*ݕxŵ{E0>bR>}:䉐C`]]EqսYDoG9Zn S9Xξ_#sO_P˺ȟRjRaA8ڭqW=cY*Uyҳ{;H{Y諁.%;K!*dmC'ܹ]mYU#o2o#r5eGtfb%8g';c䎄wk 5vz㦻9Iz>6g:$|:Ijm$^tq{{z:z '*GT4T,HN$7&/H $A.J]Y8# =ݜwγRyνw=M҈B]O6Ge?8])T)GG?BqyȷZ(7 -|L:0\n'P.|:/.'߳GOBmrwq6Zw׫OM;⎿$4O}xF8Y]]0~IBG?!w塥ɘAKwOc@n{ɬ'KnT7CN9׷Ue/|Kr;xG8X%[ۜnEÛ87ظx A[lBܾg]&u9~4X'O||OUrFEoi@)g~ ?#T?.+wFÉw5;-o.8ov~L$RK_,m+'6/|s8EOZI27c~I%kkd/}d߾W=kpMF S;, (Q[7?!<_I'~*?84k}R Y_~ƽA "T;(ZN&OZqL>doyew'>E|yLѮ}A&{ m>/%7:{:WPjwlmht0+;)gp;id/OoCפ~/ePn}@h({|uot F#^\ZQ#7F(m3D)jj¥ _D ~Jb>yvrE/8/|x䛛3[&G|b2(9xƭ#3?zVVV"Ҿw[#`R3J~)/~d/Ȩ.qg}Z>5Y'ۻE]#f|fl'ݹo}I?y᎚3Z5v$^H~7ma 9ܕ{dw] ~orڑUw\uN~7{ǢU{鲦h?zW>]>sursM; ݶNl@^}5IC }%՝G?u_F\^t9:` ;!UEr,oW?z>;{?o[)MϻZesGrGwLk@"yfy"N8Q 枣BA4;e6ȆV;jU4ԹTKu;(vG㙪T7+Q+̵;w?lp7脻xW^-=PtoѣG;_\pFA! |v'* 6DIڽ.{ nU wPkV%| եns,%~2 GNhC7ĩ}9?yi;M}(MgD]$腡 _*j%r)t8/jx[!cFG"#ݏ~]?F?v$bʫ{Kby#fܝOiލ(N:`%ԁ-0.T;VL:7K޸]+vbjS֩5ћ㮹rYm O? ˮFْ?q .swzEf}Q1:7cǎVFvZtg)Ps3活z񫅍7Fl'pB-0.|gg?Jz]#ݫWѯxzOmu&Y{堚mӱA͌&QD6B*;~:{٫}:} {qyqK?j?^Pֹ'Gw§a@3Nn>we86ޅFNA7׮]+/Ns3F 6̖l믿.=/Ncy䑹lQ*+[.`ekeeC#gklq__~/zw7Q|,0ӿ;toa43mʸS 6IO$j+)?E|9wQ2GB p㋗Ë"'_?s"B ׯ_/+W+VD .XZ<oh)Ç]#k\oG*ذaC&a;qp+ua ,9`'%8A/M RCNL.GI$c-Awʑ'jXVɟ-ɝn?zc{R4EW5pTWMs C`"p.ƟYڣk#/ ou*HWS6Xg-< 2q~_QX$%=ŃYR@\cƑq6, 8}dCec]|EF};"7*A ovdFGV G;q `GsR1)˝d6uwHtm 7wCPin sN|YX#GҠqpgQg,!`"Їqz+d.oU| vFIqV50 C(8O19K9~OKėN]RzIyXf!`ECtMR^0^;}zM!`Xj919Izhb7nM>JY}֠01k!`@, xq)Sx)˚W6Rğl@=}~>l?f!T8Ռ#^;_Ms"l?Pr n~ I38@:~= C0>xy9s"}rD Cs B!ez?\NFׅ!`@Os3Dmqx9l$cϸIXB'|C ?tØ C0 /r/W璳 Fߡ?9;Fzg=w~!`bpjGmE>nnHwu-t|~ B7Mǜ(s9IژuH㰭!`|V2 4ׄlYL !>6%ut `s鰱Y: z?f!`F`rݶmOǍ1:mIFcIzXS3?'1q,ࣞ4瑴!K ]M@2}C>v(7c/C!_G;1ߗܐϯ Pn|e(7hrC>2uC!} :ڡܐ |~Pn|_rC>v(7c/C!_G;1ߗܐϯ>hZB86~ >CPYsG hiqm#5\x|ѩODőI,Z!WM2%2Ċ>4g ~ء]sbKIY}$b#I1{tH#AbC52Nk 8GP8sYXBQq9Hj>?? h36c6;ja=ܺF,ql׺g'+>(g~@@?gEu\vs_ӆ4觭s9ԳLcC-Swj1Va| uA'R:W'~Cg)Q7-_6+PV߂g?{@k5i;wg`lnxG yDgo>hc u / n@q9o$L0ϡ_K5F?A7|HIk> yVoE^?< 6A"F$ɾ|>GcߴkKjOi+|ѹ&BF;z0 KM1.= bQDh-)ƼgH()f~@ 9yD?~xncKc/u̥GD2.i]QOobG*¤ #>sˆ\Q-bDoOc|Ar5 5G1[} Ą2 49VE 93:?<hh]!}]i^RAC 1ꑣ=JA 'I\1G3G2t@t cO)CG#ICܡ3]7}c18$sqz_?/ӂ_#ɾ ?9ȶ6prMAgt4|$G4%_NR?!88AHjs!N"O72ec6~胎cYOa>B4 ?5iϟ쎯>lmӯ%u.>Æ1Y%s >|*$}/Nͩ9>԰ ڈk;9hZmE>km'#շ~>~N矏mH6xϧO<F.SsiCu~hZ)%_t]f1LߵAG.6`c1f" g߈ÇzO\h}1qGŪ6g cA6u"c?>Cx0jϟ]2%;|~3%O'#o:ں?ԠO}xb6[ZeG#NNOTCb$Qj??ِL]ZqLHQzı!k5Ɛ_l}Ӈշ<6_Ǟ?|o+3E#@Roa l/?u78Ǭ2ډ2 b>N鼸O8t!lJzP`sH\Hl!7ΦB_}p^" ?{gzb|6z93'R`~؏:΁6Kli7/Io"@OI8l같 q I~š![h_NX}g}Su?x,t͍~p i36%96t8 \mF?dy KZE|SDZ%we>Xc,Nje |4z)ϔyiV'3zNtKϮc t }9EuHlh6 >6kE("aQG)rS2q(9Q1>  2,G|3dÇң`ƵtC0 A@GN΀D\OIHhq6cQRs_c|s1 :&q= }&SP8b\ C:1L!`t,HIx&G u\.:mv|9&Eq2ru-t'tn~?+B-h9?Oq4Z׾(!`t|I7}_,"hy^GZ<ؓ_?|c?}DGrQ"WPqc0R7%_t)1I!$|<Q }~_\u-ӄV26%qϣMWGGyqϣMWGGyqϣMWGGyqϣMWGGyqϣMWGGyqϣMWGGyqϣMWGGyqϣMWGGyqϣMWGGkIDATyqϣMWGGyqRA%kٌAHRPGuA/9cGϺ<|u!:!Ff}&M2EsQ(?O2/\9SPXH)Xgϟ ERt]uOL;&1Ɠ$b$ʥuk>.ZŐ/;`|9}z#G-6+Ls Y=Mc=s}8v\~o3/NWG̋~o6⤟quͼ8v\~o3/NWG̋~o6⤟quͼ8v\~o3/NWG̋~>mH8q+t7/QC.`ѦDaF cֳz" 0^@XI'`б1t4ʐƾ _5N`h?r}h\tϞ?׎9ZSޑL1ũsD1çQøO?|>-5"߼f:%C eNsY`=jd!Mq+TZ} b|k՞?#~d1JC]K}}kSy9چm }m鬥)kӒ1֖͜(9r,K[gϟ<{|^?>an;Cs9PZAJp8v&ybcܳ[E󜳉kQm?/7s  8ejfZqZ+7b$sM=I8z6q'm!NC8iGq&M=I8z6q'm!NC8iGq&M=I8z6q'm!NM{i'Nάa5OT^Ԙc%VY RCOZtA{͹fɹ\Aou9J3=o~}q>?֜7vƬƚ]{=Zֺ{@S=0u쯰穒#֍yW=<U'o*tgݯJ>+݊1UN+ѽOUUN+^n*W_~"ܬ^S93v=4w3{T̻7PDIKnuAϮYM?zn8iY8'NC8iGq&M=I8z6q'm!NC8iGq&M=I8z6q'm!NC8iGq&M=֪z%N矄9ZCjF]54 DOνqV+i3>ԋY?~mfyour?755go 4&_m?Qwҧkg~ v% %ahegnU_ͯϛ>iJh?o~|'I{Ԙcs}&7Yq/W:.MC#s5ĩ+բJV\k~|n~xVI8Wf^v)&f+޾S M 4&89VJSΩ$gG_;ϋ,KyO忪Zߥs=k~o]gS' _/Gqxz8r ɞ;ͳ 4&~xٙ#9xd6N 4&owWiJORwuG=@hM{&pr`;㻣M:a_TQhM |^=,_?WS71LPU8ej/=4淌hbZ~B~:?^}e@ ^9Оgt&ON[?9>[hM 4&@hM 4&@hM 4&@hM <& 5ƙEuIENDB`testng-6.9.12/pictures/idea-output.png0000755000175000017500000014205112732165123017233 0ustar eugeneeugenePNG  IHDRd6J ;iCCPICC Profilexy4{s&qS'cq̳y+C%NIm Dr-喫! yۻ޻k?{g؟g6@ pbHbx\g;@@ ( NzyoD+xĬs F"{5 dɸ5qeYGD&v, @'66>0~ӟ`М"b/@GN(?}y@jA&_ Tǰsgg" IiYyET4kji[,^dckgA+Vd#"WZ&zmLl\qMniv'%INٻwi3<}c99?=wg Ϟ-*.%.\,K~+/rU7oݪ]Ssnm]ݽ>jhl|iӳֶ/:;_vuwzw}1~dtlW>T!U X:&f -prrvq]eW\9#-INٻoii32e>}4iSʕ׮]QUuV5wݻAG 3=oxeWwOW߼}IC\Bj@YUM]cKGWOb b77w%^^>>~~3"$~Gn'O/8SX8QRrbiwn wh|iSsKk[ ߼~?26L>L  €{K3$D7@-A< hAư-\HBN<&B`D0H"JO'm&&Փs Wy%*M hYA'BA!A`P=*:L1sbbc'$\$% IJߟWMVB\̟VIEUNV=O#aZ,&WNGFF& f# %-mZۥw:9e8/uG7_m-A1+BΆF:%:,F!5>{^ObƄ6[Ŷl/ۙ;xAgd ʾt49' Sg Φ'[ZbzQtR}Y^įwݸ|3:&n`{=n*̸eq[`ۺw}v{_P0_cKO|Kפo^' T>/QHAs-+68S*4 #'t '"LdeD1JE2'vIOH_d?r y¤P(MT)KAk+'&X.$-ShBxHHIOf1jŢ%ī$b%Rfa-]nrrr &JJss2J*Ū՗iXWY@ZЭYўF.GT_opp1Iitg,.ʹksPsLtwQuMZ}G'˫gogr &~i(5kKc#9-LWĆM9[¶-il]I!:)}J*9ϒ{O\>r:Pse%(,/ʽfvjJQ vF{u\E[~o'뱏1R޲`-ጕ=wшn)[=IܵdЖmev<ݕ8Y(~_4Ƀ9AYJ/mK?O.,7K.10Xz+*4uVVNQs֣~o1\?,Yzd/Iax \0{8ӻ*āyPȎ~./r#9kVGNL$>>e1]:,1v;m IDATxy\Sg7ـMA **ZV-VlUch8UmeZv::ҎЎ8Vwm jBUP 7q!HB\p}INγޛ_~8EQ8_XBQ D(@IJlccV5 ԕ+W2f%R@Q D(+oF`JKKەT*' D(@Q d2JKKA @ Xqq&i^w@ p?q^@ pB,{@ @O!+@ ...@ H @ Y$<̬|^׽ AB./X-UUUu{C t|q@ h;i=P G hzF6hQ>rGVwng70zxvն li|_+9OK.Z&u#m0%{ccXlZfक˿~'5[gV_b709rv׼uͭ2?`Ͳ~wflGvV¿?,͂igR&GP{DHDHDHDhUȿt;Ȗڶ[> ~3oyH/"Z&-r/3=FH%]K5_o֌Fa0OOfWw_ Ͳ,FbHEa)`0.+~5꡿O?ǡUɝr ]X;3 \FUޜtQ=oF:ڮ:;W ];⛷t35#ƙj'B"$B"$B"$B[B3s4|zi-icy%zoeTj]a0LhkJȕٓaw rlY|eISXYẙjb1X/^38k3 ;Cg_Μ9SXdW#Xnz.YOi\M#fғ6۰5ž{Īw|:ste-!!!-a;}O* -@9[e2/&4/x}O\07us'H}FuҲf^9bOY3p~'>Y%m]{1n}T͎vZ;b~ճ2%즫7\B[;o{wԥ}/M k.%66g/\4MӶf*l*ì'4.48@ {R@ 칾o:qЦEg+`ؔ%poڳT3X|L:"$B"$B"$B"%4? !caUx3ó7iY{/oHP_6ꭽg"`̧מJŃѲ!ujZ74 ϗ#Gzz|olǗujQSqUQon46>|⍸4݀?;:Uk|:꭬SɞO,}x׶=3+(E?L.uwp];ʹ۶ܪE3 q̻4|G nXk,+n}o B"$B"$B"$B[v4,2}OnHg&c̪6gjtCije5y?Ve\ndV͚IiQv*Ѽ%S`[`[nf[⩶~A)3^ q-YL2a,T:wPPo z]Tkg6htO#W^3 ұouuW)E7\XykúsVf@YJ`9Cz i{g}f)>u$_XcݥSVwe5,ks:m^?9׮:a8 1cr̥7Wڞv4k57o!!!iȲMw'>cGxsHaU"EVF0?\bl"X0̎tOލc;>)I߯6*;`5ЁjmӨȕ{fXZ6쿼7q6r$ mcC3މ>Y;ݫx4"-`dNY/xH҇>~a6n6\Lr~;ÚO@./[Bԭב 5id 쮦#o'muC:aqz\tOP @ i#-4ͱ>o,ٲp0+Pױ#b`ј./xN{J'n|rQmgnNfi7`P}Uzc70 c G}!dYohcf3?{1/kn`z{.Áb_f˕5Wv^!y^^3foQknA#ҨK JLq׮:trתO?,r  8%~淬VMDHDHDHhYd&c#[ߤH fDZ,kUر s 1O[u޽}Ƅ1e6@e{uѓkPqnt/W^xҥы^Ɛ]&9P|~ȕF,}lB|}e)k36/Z cX LۺuYrO矍aT&y]>k7f;f>aR>×6 `DJ ͅF,3,s,t ˲vii#οbYKu=5:!!!ih24*3՗ΞdGhI۫(I}}rrM lLS5MI_V4 KUS5J5u KKݺY_;Mڃm"Ξs5uܗAFK[5ۖ6=Gͨ*aX9qMÂv\6'럌]"XI kClkN aTU}PWǰ0_}y$7ю@rk.["$B"$B"$B"%1?I)F`?~L|x|ڛSJVOU/,;r.}SO9?\r]%@ byfc/^oXFABA!/ga{@ $R4h05RyY JJ@ <-@ʾ@ }@ G@ n=@ £ YY$@ ,) HtGj#h4jUVrN 8NUH 8HCCCIIɽ@ 'wg1444<1.Eҥw1ɌoG2ʗw/Z zR 4M "744p%.t.J/ᡤ ,jk[L^ z->VwMbJ{KEfv'junA&?EFimZJj`<\{"]jK5E@` Z"aem۶ruuW ??]q&77wƍ3f "ᣫV9=b\|}|77=&14lcOXZFkS.N/~{gi2)1'oic\836%E%$";F^ڧO&#ЅLLWWFh4{݋y%%%wU>3BeQ'p&X(\!Z R_ Q}2ӒFˁ2iw_ `2>SI[ۧmKMl ݱzF̓,A-/VruZ9Sx̜"[xgNoMmv>JQ***=gi,5"D_~}-+`Y793{>zhSSX,="$׌ l2h~޽d2q;BG?qIo9ݡ Z1 Dkb1WO 9Ci,~\TVgۑ N˭`EB'*t/JܲN@Y,XuWUjal8i`@_{"'ȚMTAr[9_|}}b/(d2z@l)ם9&E,zT -Z75ߣ:^n2 i-!ep$BRpB(XT]g DGay5ƻèE7EH'FFޮ9 Xbj} @eL^[+**()**0`:,9VSS-_>} `D% ~7j䠱x]ǾՒ[r zo/}+FH$rvvtr1qWCתS(z5JB])UA Шd2@)K)LQx{,́RAژ"gi!$ V;tUzj۠h/h\Aill5cFMӜm4y|B7lzGJl8:YjW[JV7JC-:9㌧3bh;wN!L&H$rqq1܃L آg|rBG0至pw &W?͇MF,(1Q (՜F>gČO}D /ݚ*9rAr&^kDJ"fs0??0ӧnjN,>BX,njj`2BaCօiuOl^"ª3^Ov :K:>,9ҩL(#_y5?)a=-Җ>q~iSKmn>w$D4i'MEۊ:FWY_`Jp0fHj5rt#OǫFG,ϛ1:hknj o/FFFxW'O}GN[ ;,η){zzup5o珞u_C-=uS}3 +.rrrjjj"+6,9(tOwa\''8l< E*Nʹ)1 q%%6inDLJH%iHXuB=(5רiS>z%6MIf13VP.]fK䭍VPpǝ (o1Y$<||ʢzϢ_qj[=dgLPs*\UVuU&Lwsj׎yleH*HիQ)18X(5MG`UbdΫ/~%\#&LBW׬L{9i47*||=px O_A5l{ iE[R[Lh4]!o;&XV~FXYk"H$555,KED낺d2ۅ,Er(jĔ?}oMNoǭ丕7UД4,)gC;%[WPds$V(iZ$bbq_cH@$nˁBX, !񟊄P2X0h0\1~`?.`x蚟w'dĐNJۃivx+wJny?  2%C#݌}Mrp:+^K$ppŪ##۱_> ͝JZg8Cx(ig7 [,*tn#o6ؿç_1ڥs'}sVN"˥E]PTngТQ+e d2t:VKӴ)NCy+WTWW3 òe% xD(eTUUT*)D9mQhb4ڦk~B9 BT(B!8RJ(y5 Rש}I37iܚP(ASK 9?{I$Pȵ(P|ؿaܬfdZ.wDήbRPy¾C'ǯ{U}}Tmk4_F#>(@بjך.>{UBWw'37[ۂҥKOh4uuuR388xСݻwX/7gAAk||| D"SN[~.opX, H/[j־3/叾_Hw9+!Xpm=x~iP聂>'UJ [Ir#/Bw?_(w8  YY~wMF?n<=B(p=^7ˍco 0~ IDATiK)-P- UaO?3P(l껆[ LL߻NNzVZ,Ƣkn񾺣Q1LFݽ),, isVBWgrԩ`0bV[VV~{8s~EEEuuuϞ=d2:MoTQ w_) Vo&|c^{}G͒y0)Fq!.y[lX9GB rat/h񣰣KVZ풝?M/0v_7cB6.9X6,+ƍX,K! ~%E"GD"@dSS~ʈq#+jbEZIaWsQD(D"T**++oܸѽHݻ  &Z%???<<Ֆ87LgΜ-˝e2D"Ν;uL&{gۯjU*'''~mսl.`2JKK:YcWձ,\f:nnO0u.n.4Ùj4u }SRFw{߾}/ {Rjoοlܸ^wH$ gϞ} "၃__е>JرcV?D h( 5FDhcpPk 6'_d%^eワ$:oSY U['])/~>7N *i v%0lC"kL\B yk7,DԌ_v1cH/m{L#-EyP(4,tz' b;*Z,SKQ "$$`0F6SCtڇDz [ERL&JSw @BG}h׶˗vYm?qIo9ݡ Z1 Dkb1WO i)L}auVIാ&/L9E9'ܸ]ES(N|@u1gt7v#i}˜X5$hw413fnjf^[;3ةqxn ;7 cMϯF^[Z1n85@\.7n} ^ҟPW c-z{P>4j "'bݿz")oo9P*miP iѼcz%Rs(m6 ՈÿV8[Fnӣ5ywu `0X&3oaqv@x8G݈|X 1(2/ꘟӍG*&'';sğ7w+T\TyġoNuus5"CIܥ}¨iЃvo){; 8@RYŁ;99ݙ@PRRGXغ( +++br-QM&B;@QW4vџ7$aDAtގZ;:9noqݿMᮮC`(YdډC-O`ּ*ssYst%eլHJ:䍰!_%E7NE%zGÖ7uzw y6jS )-rB >W'-/;`4ʺ@ <<ɉډ' KE(fq]N$- ]ݞ|&vm@>I[,4}}a1CP7Le֊19kWo2W[S {9rXr̠ ŭ U*}6l$vU}&q]'gNx{n}_ZFί!+ Ug-T*ROY`\a!@xi?00P 466544y$ o/b}}/aNn,EKHt:]Ƽhr{a{'D'$D$)ѕNHNxp߼h>c}PTN^MQ&@ybÎ}ʌL\>٪+7ӂ^BDBtD"MNN.je^X8KK<{CDs@Ʉm'ya5|"#Sv];~T_eddؗB>y~k.v[agXdy:yEEOAQԆձlZ:PsfʵP@>KK57m](*!evEPT¼mh\.vlstEً)*z B&oVW*pܙǚ*MYv97D !:>>>"H$ ڂv?[l D~86];z##qع9y>wIIՙʉr鲟 NhƲO }p9 =Z:L98p(sSt/!I3֚J yPA}4հ@Irh2HZ⊊[2tE r+8cg/+sNT@C兟p0//,赊;w%nе̍:.QfرF;g~Bձ+9k>_$[5oJPmiSP|h_j̮J-뭌jjTY ˃NKz?vf[{Ugk|"8\rsߑe4[JU6neÒ/h [}E]̩ӆk8@=ǝdvN1;("]2G#`M>SvWm}M YW,>}FFt<,›4m:`4Leà1%tSF[ EK?oE,$`M 6d//H<t|y*7Z6N:#ӿIGXlގu ,aaRj6v_7.XgZ)Z, ܇ߩP!n3ZF~2؆6Svh8n*')]帛ac(ի}h24MY4u_|uZ][dh]V̥#gT\tuwNtE g(6ΤHUQ맆T'LxS72:]Em57:idujNWS h**ZǰXF]V[ FSͷ }I;_ `YFe-P[өuLHb [LѱНy9&Q9iɒ%k_0`4V#LͨKٰlMmFAZZV #FHem|au*h45M5:OȜ1E+EVwP1btj~Jk(lߐ]c*7 ^r5}VGdrtl@ nO̊GVTTpgi,vԴC"Rܘ~P|u_q;|a}a2G̍R- JQ MQ5wglkW{<bSURUN|dž|6:D`|wbK<Fjv`%0s7EQG䅴ɋ2>Z IgtgŨM )+RcE#_qr z)2b?U [ҴxzԘP;&u㗺WbVTKc9_:>;BUUU999D cnmuETXY3fRg2eo@,(\?֡QYn40($&YbK,-_)F=ճmk&#E9`LѾ ?\Zv!KQ222JJJu*--U(xSǏ;6???44~ ??W^"˗/[ޱ:Zfe:L.޹ #I:RVC.Ji!k'aXRke-t&VVe:^7h7w lNg9ћ@ <8p; @,Su…C4=jԨH$PȲl}}=EQFի m>D[cx1h+J[D"UK> PSL5$8 Wx@D+ڠ 剨~{/)0F$bꆢBl^Fsj6P-5q vL "Rt_0gxT["an6΢},CIuc,EYQs{{H*TjzR"uڤi//w{yun)s':8T`GobD`lll5c6|h"˲ ӳ[n^^^wtK||[~nnnv8O-;jpBjR(ppQ=zrn1 @w<)L}f|VYjJYjp>` V$.yXu 9RE%UIm(3ץ5qcgrU*Jn1p%zCaӧO357#yob=QKa{aHp7@[} 5B&I PΔFtݹ["h(H'FFYf,vZen;пAu|p<?"##̲leeD"Dϼ̶HI-ƍ[r}W'ԕXEK8;A& rв)LQx{,́RAژ"gi!?j94w>m:dpI<6:h:LeIaa¢.<+~DPE%~2Æm>w++^AQT5jlIጌNS)͞(V개Ouy|il YE}Sܹayرcǎuvvo0Թy6ձCOH@9OǒPMiy5$n 9iԘonL)n6bXed/G{źW 6/o=eg;\j%~Jrz-ΆYbq,,T|by9"#N>K,zV{qRg+5?ř[348OFM&#@J,M&^V_Gߔ}СC}|| :ԾrĨQY 7*7g7b;"RgpM4p4-JjmEj,/b0%yj3U9KN(S+*TUV!FWY^ֳ .2[=5"::S+]>Jr.Њ(M#J IDATrRwqBttDkRelNHذ̀ ѻ u6FdxDK8OZV:lmDi5s|%ދ-^@QaƕC2j#ub9N>cG̎3p8-!@ I֚Ŏ?aV]0fBa\\Mqqq^wlثzjms C@ʹ) UH,/f%mIPޡ?@5&CFyNJK1KҰ*C4]ޱKsZVGȻ-lWjn莩J 4y|}P9$ Wm~;gn=@?&(rr֝~yi9hgkF+(2Q:erJX#Vv"f)ֺՆXji^[2zݪ9Olopɽhlu)ˁ{ؚOͿ(;ۺ@ l`Foܸ{s 'b~>y>{ׯ_޽;WS Ac]9å PB>mds)DAsƍjd29O3~!8LXiԧ!K}5[| CWծN6+wz%w aVTG?^dN+"GV<꤅/X ^r[k0ooD.^ a)Cod^9h , BR>?dv2X<ᔝD̝p֭6dTD}ͱ:;盞/sF_ώJN[ۼq};x V-7"qbk94!*DeGp0u!@ ؀DzliiiAAVz?""–;UF.t7Hdݻy<`~k*8ͩt-wowr;~g8f贒^jnaIԭ[#zO0h؍] pR ZrHk)?Js'Qsll'bvF [MmeDvfJrg+adA-Q~3wybk p}@jo9 |gϲ,l>%l0oܸ1d޻G$yE>>7 EQ^^ѳd+NvNq`Ncz"+ >$g)TTVf<URTZz YZWeʨ(Hک7hϹV3scf_lsַ΍[׶{ܝ5Y 8k׮9rɓ˩SN:wĉȑ#ի.]:x`uuhkn&<_~e777>_yyy\.J2rCS믿 m'rXI̪լetzZ~ ѯ>ZCVUameD4Old{Dϼ|ӎuAIlm5Ў744H$X,H"4M ~`<<<̹\T*-[`,Mk놄$h B[X \A%06uЮO+Uط8~S݆Uçc@gh': k vPMZUHB?.@.G89ssr_ͳ8S,WN5L^Y+d}*ZWÜ+dkBq]påz_|__{ DnGtf!MXir'vӓ珌4=44dZm6ϟ7o󽽽B\.ZhiOHV[sկBgʝ  GpcN}}}F D"l믇HRG.Bvn~׆&8sy|gO|[=x,wUr_NHvbNh@vxž>T*H͛'ك3gΜ;wb,ZH6vay[y~wݵkЯd:XdKUtEټ){~TkҤ]_Y{˖-; /:Zz^O P䈸EN#Nt*V*p_y:7U2U&[L&ӥKbH$r|{Ξ=8fa22.(oT ǕWocg컇q0tXy\0Ρ3mw nHR#o ^)&]e%QTnՉ:u[2˥"szܦbAn uYQ8([HC<[** F­Ȉ`7oH$bwb,XNӣv~t;6)0v__lYKCס WG:,9tCqy Vk<|g:S2Օ ʜSUb}?99DFTE(*ӥYrs FO iwTm۽3i5@ "v,J###.]Ͼbג%K.^x,6Ƶo_rU /E 67}y`I,EF Bވ0vHs;EfG_Y>.)2NKw;5F&嶎^NLM*ܩ(U G뵵OVBfb$5KԍyӔݯ',unn螣lt.@Bo "Shk.{S r")ZҨoIQ].H"IH**P@-*Tw7LlTl޺MbpnhC;/m6ˡ Q}/sepTǮp^ِ*\ifjjU.rKRr4 Un.)wE,Ico|? 5& Ì}AAA>>>vBP h6w~ȊLz2aw_rJER+s(s7M۔OckLy׋>٪6[͔\rz)2K2*aSRKkFF*Pd7jcaΔ$Y]F%itNk*hgڴJ aƬU%=mڪ*aLm QS[5Ѝj "@FaL@c6`NԔW#(*JU젡>qʪ1wG.ȩ7Pk]]k{S7MJMAMӎf1s$Q9wg%_F6%3Vhj4J(m7(,21|rXmZ%FZ%6wW6r79:Chs+2%;;G)ڦ0sN?{(W@0g򁜓.qnW aܨ~NCk)] ÎĘ {43Qe![^{ٳ}}}:ٳϟ7 e<;ΞlRn0ʛt,*xbVZ>gM~Y;3]g [a.o 7(ղ ЦWہ$>):ux>>\ ~_qVVF8K"V 1Qk*u4?X]WH%kT-\DfZ/*U.ʘ&>k K8mm ikTVg>z%:g9;(9`$b_rJm.+soXQ}H!"cֽTƎ߿O;9}m+YdUzmdjGVh,rK>pCxF8Bv!pOXNEEﱺ%?YX5NO8+?0w@kbmV(D6nlKѮmc=ڍs@ %xyGo5wík}wMF}k˱FF8Kx \Fsnu$˜O}?o @_B{w hwU -x<n++۟$]CW^<:71/$o c&;:V˘FfsұtpϚΟ8KVwzhko;Fw3 g1x=8G0 C(O'pĚM{vOQ8.;m==;~>}̮634(a+[1j3c΅bD^RbߪUNS&ܞW*RdxtT!`Uʳf̢+XQ/UPj3oֿ9( ]u:PECc%9yI\NNh@¡.@9ju\,H)rלA[1ڏ(R@ HswSEN |^q+>l^\46|Uon,d/r6X#,_*9\eQKE$8F[,; RDHxgޫjc& Yt?0Pݻʤ.ak3& mei.|ö4wT9l}uKՙ2$Smg0l(WZ0{G{q_|WJR_-HnB8d^y_4B@`ZV3+ =qzcvޓ'ޗ߾w~;Gm=}wwV_YyYt 5h_ -?wYf"~}&xb .g. Bz{@/M n-s ,x###)Ec:441r\#yw1?>\Zŗ^?8 >+[K~wp]?E+E|lB_7S'_d2X/L$n̖E\H"T4<_؀ي'}C|pU.EkgkYʚ%䧯oE}}U-z-y2\~E<|GE:EQpzqMމcyeZ:zڮw|:}䩰RC]mm$EQI;δM y܍[+]W>"9p~((Ϣ@ αkCk`l  M~gʥ߬Vt(0h;NG3m͛#忓"@ jR_YEZYt>׾b5Pϙ5$W)MVo[(նZ`ӭm{`ԷdaRū@'Ybg sgq%kuM̓uFN+ՀfJ}dNh{w44T/+6:XZ uavay˃@ n)fKd؉&Лp1y9 TU8YصwF5P]:Q ZcW r2oYQRȸ[&^_/韪sȪzE拠-Mg}PiRU"?.1WY(ھADi=ֽ\ $x<#^$[ۢlsώ7OQȗ<KLR}6⌵9b2&,: c8}._ ٢Kj?Toӛ!+et[C9U )'€RTurp#s 1/^r%(պ]O= aVD< 8! zs"UBnj8#3 @!\SFlz+mE+o-FDaVfBJK0Z2-% N>H["<@i`sq1wmsff/_ *D ? 0\ t ϧ(ON['xc8DC-*TԤʝ*RЀagRx{=к-u`iT=lcSA$0LU׍6T]͹:橥M4^h7Œ_7#&µ[jtpɍNhR¹ͳȟ(|9+s9[sW!fHl-|}J@ nQ%2cE>ɳ̑},6shsOC:^zs kˠ̣cgebH,0"BSSI#ś;חyXliysڮRez|OxߕlzD>6O٥Z!>>PWW]kȢ6d&oThW >1Pll"YvU'*C*sE3gk>:Bq[ӃV[vfSpo1 w=ti7'<܇<p1<$f]N:x=KboڼyDy}/b*bFk=J,+c"j2z 5 ,o,H@7BQ -B{Dc﫾x6{t%{ֲtd׆pS|BjSD oh?,V(ɮacQ޶wM M~b]:Rć )QqSG fM\ #tS.IPI ,M!4Q̵!gYY)c @U.*4YtZ>;)~y\lV w^_~Z{ZhK,W#tl.6VG]hN֔11P40E/I[;3*`-`\ Q4j Kp@6'Ck s-,"@ nb,zqEEͻ=SޯG σz-ckfk.MGg+i"nGԊJsʙp X;k-&@q[[|fl&rh ]wJ PԲIǠmVˋ@`Jբw6Րkgà p2\"|>ddYʄ,}Z/YFS< x8/׆y83U-{Qsu R" Q&;; a |WoTFY-(z}"jb*4\d&H]Ӵ DhWj]e icwKNNOP[zp 1x(gC<@ D*Ϣ;'DzL`wD__j/bFmK'Iܞ]j`u6B0PsĔ/(?E"bϺ^`}b^6`Z)cwevBh um_,0tO*ާִQDޙPT, O?jc 噊< Ś q4e7f)`v6ͳ8=@ d\qũ&PҥKsYsssDD4 l~{  a1 G{^] #&|1)|u/R@ P(<<<8Mg>ddMHV(W~`?XTf"4K^5b's@p X:W!y9ɟ~X4ۗYqGg;Yd~IE@ 8򇰟lŢctBv64[lsY&&fdddppMt0 "d|>[$fpr-,adH g.\pB3{644HE788(cYI" ɳH PEQԗ_~9yf&"_}Ղ b$i%1\0xj|ɃQ˼s2azfgq a@ d|///{{{{yyyyy###ZT:*8&f,N/K;\2}Z>KC[C+Zӯ,- eo]ck|]+)#\xe9?ch@ |x<__A6#<=nnjj2K,qM3=Q-pڜ޵BQ $r|& v[CB\dѥRΨ蹬J5LV= \CggqFyo'@ <ja6-ˉ'CCCcהMțFFFxOCF퐟]H$:t6R*.0P@(Q]_18Z%RؑH} :"Zv]+(?\J I!)Vp{c0vlX,Eu] ,p$fq˗?& __ +B˗/W dŖ @axqNJ?Kߩ[(S4"`f6߁|SuaWfʎb-T=,޽.;Pj/hݖ_H[K˶\4?pQcSCڢ 2x0<t0u3>?76XW"Qv}k/YX Hxݩ#iK{]V}5PgdIjv=g"|ߙ+mԑ]Z<@ ,Ȣ6d&nڨHW {"zbMy=8%=`霊DEhq/)7ٺޚ0%OY.7'W7 -$I H@ I!)v@Uqlr OOOpY ?GlEg+v%3s0\Ǽpx=&j /S0Zq/%"}|@2&&(sZH?pnk" Ƃ(tSn!"$J;6g3@7NWQji-KGvm 7+Z6H[L b" ښ쪞 X!m@ Ŧ~'?u(ߏS+#E͚0rGG\ ߓ&AX&p!sCirtSkCkgq6Rǧ~* `6价BRH ݅1ar­{- U# EQC6Ǖ|>Mæ"殮ocd /3zg8Ŵma^_b/:Jv|%FF4ܹ1ieOLs @mUj6 hMQqsgJS LK%"GE@yEJoڴ yȵ!7sX{'k\ 9yGVTQڐ:=z~je/j.t+.%%js+i@;)wF%jʜ2'FZϞAK m,F KYzxBc`̥)HVln@݅:=M ˑ}? YLvկi oѵZF 6v445{ +=tSnz(gCr*g$ց61ɳ8\&};j i1E%$n.\p`b,Pc)3^JQ~ENŞu!?= 9m." SBe4D4 GXf`jTOi{I3ɡrX~63Ry@5:b0i,(N 1oRB}<@ 8D"H$7oH$BS |V9cxxfl6vZ 興,Nx ݋//tƴGRIfzI$s/ hѢo L&s/%HQsg aHnEZpJ8:PBK 0;ЮteE/LG=1`c Yz;8=3V/ b00###WV4 Dc{SNۂl ,W]Ʀc®bzë1v@ =![xxxO?~z<;J}7>|8eUtaׅO2gEP|SqbFZ&C\Fɨ$ZXUKuw@ |>;Ng MAq$f?;csƦ囊zIx{[nev{HZe7*(*RJ=Hz]mٛeee*uY^n*{)ʭlE%2R(J%um$EQuSyT.uW令/zFOrR%@ K³@###n#a6]J| wRG*){.Y=j-InkMHRjKW̵=zEM%;0?'_8iWz;`oO.A[6=>|fjjU.rKRr!ne׃ [Gp9]x<_oٺs*@ n/'䘊p#l6ۅ .\~f⡡!v+ b# LpA R,' 0a_v_> _|_(G)dԽ' vUǙoS>(4*֘f+[4PE^#hFqoǁ7WC|_.?,B@u K퟼TN5Xn@ neH"7>;le6?^?44ZZV٬jR91i14v%|WO[ݺ$Js;]?kkOR<}l l2ZwۺH[퀱:;SCag^9]!W`F6}==H[.ܷnÆC_ƍ@ 7%$fq\76w-GT I\.?I{_;E.(*8^۟DQTAZb"cYjkؙ>zoڽ%)H(4NoM|}}АbX,Vb|'F1((ȑU{G9`qUӖJwby"9$.'xcX }P_ @rEQ_2$>D9ju\,H%鱡Jr*ocw;S Vʚ8Ǜ!.,$\* bW|X*O*r٠-GQ@ G@ I?{?ywC~wS" /ӱ[D;KYO[db @[uĬaB\ [T@(}H}FM=}.8Kx<<{hhh4zxx:.###_|CCCϟ?su"Xw1fX ʘh%v2E"bMP᫶Y;4ilgl/Ѵcu0L̆0Dq6ao.E^26^̔ZhC\P!Jit^ lP(?>EQշ:hpV۲?=é&:6AIdRnL(T~zXe\n$Һ]]+Ԣ@ߩ[TER -`nؙ9)O}[j^D!q[ӞYP`0;wd2/Yd…vf ͪMlP$&DI%"D-H$TI\t)rqi8]Rps|gU7[ LYM@DwqҥK|||bҥKᆬK~^^^SEN;@ XH8'{O w'ws^ʻ{=/(翴R0֠s.ʘWG )Ql&MRE&0atar) '[MPTUo߰2.Y@e9ԑB(EǬ{D|PI K+qc ]pz{{,Z("c IDAT"BP}݁r\$3>˛%Lkhh-v@@ LɰSMdg Z6x'Oy_^h*l&@Qk`F9 Af;c6gǾ5[mǞ6}y8 fIXloYyS9| 0N<㱟]q?f '<<(ؔ~E/_jPd2V3^nR6m\Fmճ2ny' tōUύev|S{#zgyۢ/|T嫒2#p޶,SrM̊MGUӛv눇SMdgq[=z22tѼUhy6alً F]X_o5ZߢkWW7![2Wm6<@G|/(Q[IzᝅHOP[zpZE;m4zt[(r c(6֬>Uyj\M"ZaTC/H$~>S7 LS'ԮWrcѥRTd]6ͧ՜";#)ՖmREEV:[wov}a.? 7+W7а ZBif54h0Ȼevpkms c6 {l_徲4VN}uo5s& ;o^TȝR;Rm_V\ {=ޗQ <[L ;Gq2}}}VU^NI=h߶[:)WYإ V7"T$&ʥb_xQbbJQUM0PKs}U;0z >D:4 X(,Pc)3^JQ~ENŞu!5E~9YVr5{h +YJ}D` HUܹ[s ϕֶI9fԜWr# \vr*<_U[ |v5/ZCX[2wڸ:J'v?y l EgR#*=ƄaoǬ,-TT00iv~"i0A*0}99 ˒dKN8jZG^'P(a-& ѕxQ?-G %ga^KD$c3%""07h bb[ŨOG/?Ѱwl◷,{{a4-;Nqg84ͽm@=aAb{בF6-l24Svd']D-}}>׋^㘌.W)U[|M9}±VuC_vKʢЋn.yynnnr nb>;Eo GJBFĝ1w|A^j8.^Гsnߖn˔" FzzvC[WﱻTv=dfa/;~NC 2_#a.͕bLyhγ{Z"dB||xÕ Վݜq@=&n]e21m|#K,>P} jRU]&|P( ^^^0 tAAA6cҥ$fpf"c5rx'+.5t H6uHVz&itSDw"FU,y#~7gy;jcL JF.rDjǚ^ {|%0 >aFFFFFFG`/p?cJ@ \/|rϺk;@ "K;ᦃ;d8t,=)擟?xۂKL[Ix1;R)gT 3')z\0TbT,mhL͌(64@ 7 좐;dA[V<88X,#7ꆂ9~`l|(bg*oMHhg)K?|`C(Fs@Vy >f\f+*]ƦnUS"QO}Cֽ]:&?\J I!)V!g[>?88(@awE$f}y`I?P !ZcFc=w T*nؕX (5yiwK: Z+VҲ-?W-/oTPtEhC 0L}4DMbfa "g",uY@y獴`fz}rnlf9)74i!9{oCG쓼 ckJ|)ɅZ <HڸFZZl^z|Cm`floߌO2mgR̢bGGP8mYo{|sk I 1 $ A0@l#(ZK*=bO-V=y%J{TP\%\EH.{ݙٙCn&|v=<37w6b#6F@[eEQ$\"0$#IQ,9NVT{G3`KJk~A 4 ,6yTstw齒W.ܒ#Ty37.޿dµo=syPvaoOjW}?iFuK} 3ۊȴZfɚ-eTT?]7k/UJ?:|grttg5&V])ﲽc8_BXt2Ă i늒VfmVoWM3M_]v"k/6xn(Z;(_];ͩWK2wx$!jLnd)cFءCP{IXh 5$8]qx7ܒ:f̘˗/Mg̲,qĠHȠk5qUH &z!Ph#g`hP| 1`S+וEkɱw<';>75`\x{Ɏ59.}Z,}vW'^]P7C.SIuµ egWTTYq'ۯW|X[6h̳B.RSܥ{ v/8nڂ|}.}^] [^^/$w<rvSGg=fޮ mYXAx{'R5e{cq˸nYć'6Eqx7e|24n<ɶ6bt|S{^βdqJqZ[[d~ý>ԩR.sB|x\P}Y*{\[KJp6EuNkH{zH#+wز*q̱TXmn WJ[9բyO8=µ.\ckCgcY!)z\6 q}]-;d+wv=nkmrP5+s̳g;m]zX4{mENwF?ɀ~Иy]N Ks|ݾVpq:BQԹs  8p !!!)).KEQM&nONNN+}ggrMvd7ϊxv ?Ngi@5oܟNyN=FK>b0AdHCYu843bo`U_Q"v51j2?*k/}>W\#ztuWD#M*)A78n Äw߷0ubcNf=5}h|xI/XobVDr[x#{ 81yovmXheٛ4? /9;$S-nZVu1 ,Zr/8޷x߆$=)j@pn;e4h,>onYҳs<.fyV˴9ΖVpq˭u> |ʢr}6Zz",Bכ," #7}ͦ{[bń㸰<đb_W~IB'~xg/#;*~F{vK/QnwF@c.ZrLLCa'ҫ*~[+ Yu2"je#sh4y7 gpJr<> 3&998JtmhaB},Qw1/AjN(v)+X*[Zk k诀VlLLL8^͖1B//C' k)t  aYļ#?Y{Y͸PeF食|,2d=2ݑo s'8 W? Uf@G)AWEAVw%%%eeen∕=gΜ趘HyhyBo͞`&f9@?Jx'ⓁEAdD+|Nܹsaʔ)˲QFC#C~BGA[Шgsss999 DnEEd(z/kCв  BgΜOQThm ],|QS j[CQ1ϋnN1O:ySk>{l훋r{WX!&:$n~B=)" #}4mܸqzU"Ls1h{Cś.a\Úd-˪O~^jm\CQmo7\n_UJxl0p}5rX8tK䊷}+RЧO>cƌoK.]`ԩS{[14(" #eRv(/  bY6u<ϧ\ 9 4_ff0, EQGLoUo,+5nyf.EQG_&yy.,} wX]bHtWz +GvDz㙹E]@?⣓){M_6Ԓg68׎ltQFu{ 7{Ej_AAGm&IrիWI9/n.c$hY|hLMQ~S~}E4g|1́B{%\ rkq)TUA*Vm|zӲ I5^8* b7Maڣ ɀa )aތgn ׾U'xco,|H([ҷt~m"[8gx~VL'7BGA[EQΟ?_RRR\\|ȑ/:ҥ7)YNղ`_{m6ػW~R<۟ki͕\5yXȿ;V]Z!M[϶]Es./udܻ|[~[੊{m0_SmIDATpzC;>75`Or/c9Kݽw_tBWdX!c{ xU{Qphkqc(jDih4|>bK'wv;Y w^PER]i4M Am7n¤8!˲t; ȭ5$˲de!+N~kKV%KmmmoOw*q!hZ }ȕIȠ4,K1;=^o d+>Y Bζ}2/NzVn=BhBԄ[s_}+`"’kZ ܵ>BŰͥë茵E;KoztE])ԏB^HMꆆjO4THQ%n2t'bRd2EEEqG$:Ad$Az`(|>Qnjcue@E*dUUϟ??HSE[3>i dlK^ GGy`y`aY6͔ |VǍ܌E?ħǦkͻW|<2s@6|PbBX%+ru;`~QM芡y>]vhMG^hy۩CfS)N,0e1Xg}V^^j8qѣM&$ A ò,7449srJ|  #=fY7.(/_y>33S_ںҕ~L8̳?L>s[l |mnLo{^CWj[올P0GoŃI%Ù*/Իr&͙IV!/Ayɠfkv^C abOz͏~ *`1T|S󕕲,,gߒ6}-K:Hޡ uW#1.\8q0&iҤIXIGYi&fH8R^^z[ZZl6j5  r+Óu#$I'OZn&$IJH6]Ȼ8#87ZS# ^M55do햁3ZkyUy&11VҴ]v~BEy<f;{lII6mvݍVd2 Q1eڽ-_ f777K󼮡" j-fzfEܹs&L|5؁ѣ_Gg]VUW=c#+XClq5&&s.9`oGX3{C_Kg1Ԥ'kkkZ766c!ފr(jmmMII1&yYK2,&f4(@$DeA䖅($MY@e C[[d1dWUUyɲv}>_?U@{mЅw# ~ȿ4>(9R7L;u}d%xz_ cB{ z4M=z4T _]hA$ #zli(,K¢"! ÏP"ɛA`0H(TnΝ9sq<;>0L\iAn/KŰ<S=`0y dYr;(;E]}H&'VLTAne,d!Vh8}nO6X E>,"ÉRzqWпŗ4M4X]]]ZZw %I2e &}1Բ:BQ(,$:/ѿH,*0 }y]P/B>M&MVVVF< /jZZÇO:G%i=-4: JD El6?XWAcD-DY|NlC4MΞ2e Dɲ?e }Dh)tI<#%#uDߡ|$œ9st'i://̙3eee ̞=h4uSև%:^__CAa Q $8@O<9T(*lUҷȲu2u>?t) ən2(),"q%$ 1AQI,>NzH EQ ߿#G\}(eee'Ox<&L?~<)5\AdXTsH_0ԩSf.껯iZȡo޽{IsI~"q)/i%آ"7z_ B}aah>qDMM͙3g|>$I6&ϲhNLLt:#::ZW[{ CwX"DSlkk!###>>G#H-dgQJdbZ]PB6Mb#uGrEFp; %w1L(E;tݴQ 7> E{+//WUjFGGO8qd(I +#CtCCÙ3g\.Wmm$I$b s_qD{`Az@K?3fĉnj 3fLBʌ ndgQE=xS/y…'N0 k2&Mp8jOuPv=͒iqqql6J"poԡQ ;(*)|E֏c! pr|>x`lY$;zP@\VUՆ@ p8L&d2D"ʇ^BLun5Eh6m6QqIuhBMFEٕ$TE@@FEE QFu5>Ey< ={]?6v766FGG[Vd0DQ j{ GfOuiķ/f3EQ 477KDIweCz/dQSSz 2 ao!dPPP` hi>yR3, HA3?F23CH cfRF/243v[%h4+(J  A0#xԡQ h6nܸfGqLy :4M[,ݮ8>x^kjj=kt,k0<FT#롩&#=IF4QI!R\X{'SEbr( rUCfȲܳ83 9CtzzzTTԧ~Ƿ0$˲ .kرDYS.SD8t-AFv)$WUUO CDYԆF)>M8؇QPP&g8ґTvE4X]]]ZZ@L$M2XjY$Ò$cN EQ(,MII!ʢ~7DQ # `0+ E\§iڤIʈ4>|ԩSyyy$w ٞiZN$IDw$)l9ȍg(BGAd0`ELvG i://̙3eee ̞=h4u3ҟ/N~%?ʊ:a(UAd0`")e1t@Z(JHH?9rʕ܌A XVVvI3a„Ǔ 7C0ԛ] AA`}Iv 0YYY4M8q̙3>O$] SX5щNpDGG$CGY!P }Ad0UEj\^h n577zu[\e$~FbpG4=kC:  ,-`̘1'N ×BGEA ̲.^hj@%͞ L֛=AAd2$r   CtYd@@@@u^AA5!0;  rP#,"  ݛ<  H-  H" #UUɍyݡҦ mMq(l ( y睚7J{#* ƍ~]((0FL ȰGQɓ'gggGEE3l4GJ_D FUտ/ ,Ye)4MSe޽`pѢE% šlE@4M妦\YcCRRRIII0y>R`(\(@@ . M4MEafi}@UU0( M{(\(@@ h!ϢZvc )MӼ^l8`xG`$4|CQ QO93^b!uPP'*Adx#˲dbYV4-Ҭ '<_wxo߻tU+НwRΛգܑ9.˲&I^ 2QUUQa9).PP`H J4`%iVCU+VD"x1:<;+@1mJ~gDEQ$V(eYڅB@轀֎>u݀ 2< .h4@  JQVy:Ip￷U=aㆍ~rws%ia#0nraA5Ġ4M[,6!!fO A*bkk+˲^WY: ].WZCI o{qGE]޼?8dW. r<.{_mQfE,˲," 'YwGC((CM  ʲ,qdy_Cmg>~`FUM: UWY1 IyWO2k;rrf'O21t@Mh$yMXU (({-y[4"2|4i8iZb; @Lݏa%22`(1e__ː[;`0!I5@@$AiWI`44 ]Ec&)9b8eӂwpCFO}5^= O<ۻk~ blS5GpЋf ËyA`PQqGJR4\,ڦ{9 yMէŤiΨ+ɌIna?eYQBS~ E!1 r@" qyݍQ`ENϞX0D Sc}>?,%?=orC%.d$iΠ* Mjmms@'եDGG3 ӏHdկh {W :!b`0 [[[/^4n8,"2@" e[ZZ m s+ \L5%vE4%99GG" Mx|?H[qs㧁 2H^ A;vlqqM C(xرFa" UUO8xmeeeݰ755:u… ӧO谈 EA=`ٳmmm$݀<" #F|0IENDB`testng-6.9.12/pictures/testNG-exec.png0000644000175000017500000012511312732165123017116 0ustar eugeneeugenePNG  IHDRO%CWiCCPICC ProfilexYgT˲ّ9nr$MNE69猀$HN " A7}ff%bHH0+m#`3RKtѲ0}@⇺WAd<am[0}$:"ƨ0 Cb_%cc "1LG{zp`h<|"XF,00Xx&I$z? X7<$ ׯn)}D]c!|@AGa! r33{[ YDhbA^!6|t`Lkc^QE*>0p/i;Ա"p hp$ d|P*@5Mn^0o`|a!D@\?$ @J:@V yCAP$tJҡ-zBih  =!D(!17"8(BT!^b 1XDl"ɈF#:Hs# LD! U&dr9\Bn0(:%ǩ!(JDeJPuvT?jGhQ G{gtz =`1E!㇉d`.a1=Q fŲ`EjXs,=-6bacg[$$\$2$$$A$H H%yN2GKJMOBjNAKEz,.  Y2YYwd<'ɋ[OoSRPP8SDR\xMp8G\wEIG)AIL,l|NLEJOEBGU@JjZZHH]J}zzFƜ&&#yZ,ij3tH:^::w+tf1z?t r 1 w,ƛ;LLZLLLMLϙ~01k2{21731YXY.tLXEX-YYY.ѳd{Î`abgf¾aQqcSӏ3.:/W=/x>_ǯrsrGrWrs93Kƫśǻgw ?)! A;ŝ8wB8! P*a%aK#"yRgQQ_Kbh1e * q q-(i F S˒|%%H6>%%MFD]T,NV_6ISvMNTS\<9> a M |eJJJJIʷUT"Tn^S?"xȕ#3jn}MۣBG#R:ӵ˱Or`uut::8n:9;:;u?&x,#V;ǩ]\͉UM7[۪{Gǂg眗W׼wOϒo_sZ@@[AAA1!!gCBUBCWÌj¡cIP(Ҩh'"sqqWQ}'O$NJLxN'͞48YLԩS)v)]9N<=sLYʳag'Ω8:{~8U68u?#qTzA^{L̢̃ ^ʳ1A5.6?*+($+,*2),+.+)+.m.c/K-qr ˾_UTW TTc?_2xUj} kMzڠک:zkײ ΍#uw67U636Ȗ/7\o4ת_emtmiP{ljOTC-[}]]mݵoaum,z{{~PG*n=Vz10DISm u(t\y / /FǏpzju7Qovߞ|~6I=Y}S Swu|v}fSӟq eo//|q2t+ײeV4Wگή|XgYݐ۴|=-m=^O]Ba_{$"V p0Y@ 9@ #/ȋ(=4}5&!E.͓P,~RS+Ҹ^bgJ`a%a#q}TtGOg>_7YBenq`eU꧵oYAon;۫ٻ?up١| i*E[b1\_Rc2Ir6 J % ZƘ֛.aY%}mco+`".$.Y@D[hؚ% ĺdԦt̶U9+- CB%Myle)GdVKQW֨ f^-׋ӷ3P4d1%|03542s57PbZo,ׁ&Jc.g'cb=Nz{կz@+|3E#gp+!<19)S})/OϟyKjqhIڅЬLBO~IPZ1MLMY̥򁊵J*3WnaUpYVwqK䍊[uu#xpϯ|վ<ͣCOzvxvmh/qWR=u}ԇ鑏۟f>"趔uto-]~/3*!|ȓ(T  $ "}DVN@3ԣRUӡ7gg$21QFdZp t  "<"-#bpL$I$%$ۥ^HIɜ+o&^!HaWV~7y̅;wss7JsKJW/V].vMMad=5ߚOD6qkԝyݯxOGG+_<.=u]SF3Ǿ|]h9 Q(vp=ĺjM 2@ig~ )\"@0JB (s X ^H ¡,X  nAJ#]{o(a5Db11kXS 6Rq:87#'0EPRSIQR[R ٢=CGMWBOʠ0_D2a`DZ7rq|<ՍwFq78{;| BB+"Abb.%3XsFrr -YJA&*ªh#]jښ,Zڝ:-zW/ sMM3YL2^8z6юho (rم8U(-[*(dz=?uRJtz8\bRҏS?N'ŜNeMPʜ*__]]N╙k;)ozEt܊>u^_F@!֧^F_g0:bs.xqqrMhC>+jk.5 |( AH$BeP7BLITC!+(j *MvBcJT$T8S.%!K~ENAYKuz6N yE9B&s '+;Ev3rǜi\&x* bW^a  .RB$B·E E$$%jIs(+(.*M*