pax_global_header00006660000000000000000000000064132072442700014513gustar00rootroot0000000000000052 comment=489e20235989ddc97fdd793af31ac803972454f1 Base-1.9.1/000077500000000000000000000000001320724427000123755ustar00rootroot00000000000000Base-1.9.1/.gitignore000066400000000000000000000000341320724427000143620ustar00rootroot00000000000000vendor run-tests-tmp extractBase-1.9.1/.travis.yml000066400000000000000000000003131320724427000145030ustar00rootroot00000000000000language: php php: - 5.6 - 7.0 - 7.1 - 7.2 - nightly matrix: allow_failures: - php: nightly before_script: - composer self-update - composer update script: - vendor/bin/phpunit Base-1.9.1/CREDITS000066400000000000000000000003451320724427000134170ustar00rootroot00000000000000CREDITS ======= eZ Components team ------------------ - Sergey Alexeev - Sebastian Bergmann - Jan Borsodi - Raymond Bosman - Frederik Holljen - Kore Nordmann - Derick Rethans - Vadym Savchuk - Tobias Schlitt - Alexandru Stanoi Base-1.9.1/ChangeLog000066400000000000000000000310631320724427000141520ustar00rootroot000000000000001.9.1 - Tuesday 11 November 2017 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - PHP 7.2 support, which deprecates __autoload and "Object" is now a keyword. 1.9 - Friday 12 September 2014 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Adjusted source headers of Base to Apache license. - Updated: Moving copyright information to NOTICE files. - Use ezc_autoload() instead of __autoload(). (tests) - Use assertInternalType() instead of assertType() where appropriate. (tests) - Use assertInstanceOf() instead of assertType(). (tests) - Fixed #ZETACOMP-39: ezcBaseOptions implements Iterator. - Fixed #ZETACOMP-59: ezcBaseFileFindRecursiveTest::testRecursive1|2|4() now work. - Fixed #ZETACOMP-33: Many dead links (404). - Remove custom test runner. - Fix ezcBaseTest. - Added composer.json and test dependencies. - Added Travis configuration. 1.8 - Monday 21 December 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #15896: Autoload not working for all lowercase class names. 1.7 - Monday 29 June 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No changes 1.7rc1 - Monday 22 June 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an issue with the PEAR reader as sometimes the returned structure is different. 1.7beta1 - Monday 08 June 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Made sure that we (try) to load the PEAR Registry class so that PEAR doesn't have to be in autoload. 1.7alpha1 - Tuesday 26 May 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added 'SunOS' to the list of Unices to make finding binaries work on Solaris as well. - Implemented issue #13718: Include metadata about installed components that can be queried to figure out required PHP versions, dependencies and component versions. 1.6.1 - Monday 09 February 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #14402: Auto detection of external programs (binaries) does not throw warnings anymore. 1.6 - Monday 05 January 2009 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added a workaround for a segfault in call_user_func() in PHP 5.2.x. 1.6rc1 - Monday 15 December 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Implemented issue #12542: Refactored the ezcBaseFile::findRecursive() method into the ezcBase::walkRecursive() method so that you can setup your own callbacks to "do things". The findRecursive() method is now implemented through this. - Fixed issue #14091: Incorrect documentation for ezcBaseConfigurationInitializer. 1.6beta1 - Monday 01 December 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the exception class ezcBaseFunctionalityNotSupportedException. 1.5.2 - Monday 06 October 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an issue in ezcBaseFile::removeRecursive, where the parent directory could not be written to. We now make sure nothing is deleted until we're sure everything can be deleted. 1.5.1 - Monday 04 August 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #13370: Infinitive loop in ezcBaseFile::calculateRelativePath(). - Implemented issue #11865: Different development modes. 1.5 - Monday 16 June 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No changes. 1.5rc1 - Tuesday 10 June 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No changes 1.5beta1 - Tuesday 27 May 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBasePersistable interface that can be used to ensure that the object implementing this interface can be used with PersistentObject and Search. 1.5alpha2 - Tuesday 13 May 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed a bug in ezcBaseFile::findRecursive that prevented you from passing an empty array to collect statistics. - Changed ezcBase::getInstallationPath() so that it always returns a trailing directory separator. 1.5alpha1 - Monday 07 April 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Implemented issue #8529: Added a by-reference argument to ezcBaseFile::findRecursive that returns statistsics (count and total size) of all files that are returned by this function. - Implemented issue #11506: Added the static method ezcBase::getInstallationPath(). - Implemented issue #12694: replace reflection test for class type with spl function. 1.4.1 - Monday 14 January 2008 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #11448: ezc_bootsrap.php uses relative paths. - Fixed issue #12316: Numbers in own component prefix not possible. - Fixed issue #12329: ezcBaseFeatures::findExecutableInPath's return value does not include the extension to the executable at the end on Windows. - Added an optional argument to the ezcBaseValueException constructor to allow the exception to be used for non-property/setting type violations as well. 1.4 - Monday 17 December 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No changes. 1.4rc1 - Wednesday 05 December 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No changes. 1.4beta1 - Wednesday 28 November 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No changes. 1.4alpha2 - Monday 29 October 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBaseFile::copyRecursive() method, to recursively copy files or directories - Fixed issue #11540: Problems with ezcFile::findRecursive and ezcFile::calculateRelativePath on systems where DIRECTORY_SEPERATOR is not //. 1.4alpha1 - Tuesday 18 September 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBaseFile class, which was moved from the File component. - Added the ezcBaseFile::isAbsolutePath() method, which returns whether a path is absolute or relative. 1.3.1 - Monday 30 July 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #11057: The ezcBaseConfigurationInitializer inteface is not enforced for callback classes. 1.3 - Monday 02 July 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Documentation fixes and updates. 1.3rc1 - Monday 25 June 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Documentation fixes and updates. 1.3beta2 - Thursday 31 May 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #10704: Autoload fails on class not found. The exception is now off by default, but can be turned on through the "debug" property of the ezcBaseAutoloadOptions class. This option class can be set with ezcBase::setOptions(). 1.3beta1 - Monday 07 May 2007 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #8433: ezcBase::getRepositoryDirectories() problems. - Fixed issue #10583: ezcBaseOptions misses __isset(). - Fixed issue #10666: ezc_bootstrap.php fails on Windows. - Implemented issue #9569: Add "autoload.php" as 3rd fallback autoload file to search for. - Implemented issue #9988: Implement component preloading for better opcode cache performance. - Added exception class ezcBaseExtensionNotFoundException to be thrown when an extension is required but is not found. - Changed the ezcBaseInit::fetchConfig() method to return the value that was returned from the callback function. 1.2 - Monday 18 December 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #9658: Checking if $_ENV['PATH'] is set before using it in ezcBaseFeatures. - Fixed issue #9780: ezcBaseFeatures throws notice about non-existing array key "PATH". - Fixed issue #9819: Let all components deal with the ezcBaseAutoloadException properly. - Fixed the exception name for 'ezcBaseDoubleClassRepositoryPrefix' - it was missing "Exception". - Implemented issue #9811: If a file for a class can not be found through autoloading, we now throw the ezcBaseAutoloadException which makes debugging easier. - Added the static method ezcBaseFeatures::findExecutableInPath() that searches the path for the given executable. - Added the static method ezcBaseFeatures::os() that returns a sanitized version of the current OS' name. 1.2beta2 - Monday 20 November 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed issue #8507: Two autoload directories with the same basepath don't work. - Fixed issue #9390: Classes in external repositories that map to the same autoload filename of an internal component were added to the external autoload cache array as well. 1.2beta1 - Tuesday 24 October 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBaseFeatures class to check whether the current PHP installation and environment provides features that can be used in the components. - Added the ezcBaseInit class that assists you by setting up on-demand configurations for objects (most notable useful for singleton classes). - Implemented FR #8508: Display search paths for the autoload files in case of a missing class. - Implemented FR #8753: Added the 'Base/ezc_bootstrap.php' file which sets up the autoload environment for you to facilitate an easier way of starting to use the eZ components. 1.1.1 - Monday 28 August 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBaseStruct class from which all structs in all components should inherit from. 1.1 - Friday 09 June 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed bug #8434: ezcBase autoload system does not handle classes without a prefix. - Fixed bug #8435: ezcBase::addClassRepository assumes the ezc way of structuring files. From now on the path specifying the autoload directory is *not* relative to the repository directory anymore. 1.1rc1 - Monday 29 May 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed bug #8252: Autoloading for external repositories only works for the first such class. 1.1beta2 - Tuesday 09 May 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added support for external class repositories. You can now add a class repository to the autoload mechanism by using the addClassRepository() method. - Added a method to return all configured class repositories. - Added the REMOVE constant to the ezcBaseFileException. - Added the ezcBaseOptions class that serves as base class for all option classes in the components. 1.1beta1 - Wednesday 19 April 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Changed the way how files are included when the SVN checkout of the eZ components was used. This does not affect normal use of the components. - Fixed class descriptions for the exceptions in the documentation. 1.0 - Monday 30 January 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added HTML escaping of exception messages so that they show up correctly in a browser. The original message is stored in the originalMessage property in the exception object. 1.0rc1 - Monday 16 January 2006 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBaseException that all exceptions in the components library should descent from. - Added generic File and IO exceptions that all other components can use instead of having to reimplement them. - Added ezcBase::checkDependency() method that allows components to specify dependencies on either a PHP version or a PHP extension. 1.0beta2 - Wednesday 21 December 2005 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Added the ezcBasePropertyException that can be used by components to signal that an property was assigned a value which it does not allows. 1.0beta1 - Tuesday 22 November 2005 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Initial release of this package. Base-1.9.1/DESCRIPTION000066400000000000000000000002001320724427000140730ustar00rootroot00000000000000The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package. Base-1.9.1/LICENSE.txt000066400000000000000000000267071320724427000142340ustar00rootroot00000000000000Zeta Components Copyright 2011-2015 The Zeta Components development group Apache Zeta Components Copyright 2010-2011 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). Originally developed by eZ Systems as eZ Components Copyright 2005-2010 eZ Systems AS (http://ez.no) ----- 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. Base-1.9.1/composer.json000066400000000000000000000020651320724427000151220ustar00rootroot00000000000000{ "authors": [ { "name": "Sergey Alexeev" }, { "name": "Sebastian Bergmann" }, { "name": "Jan Borsodi" }, { "name": "Raymond Bosman" }, { "name": "Frederik Holljen" }, { "name": "Kore Nordmann" }, { "name": "Derick Rethans" }, { "name": "Vadym Savchuk" }, { "name": "Tobias Schlitt" }, { "name": "Alexandru Stanoi" } ], "autoload": { "classmap": [ "src" ] }, "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", "homepage": "https://github.com/zetacomponents", "license": "Apache-2.0", "name": "zetacomponents/base", "type": "library", "require-dev": { "phpunit/phpunit": "~5.7", "zetacomponents/unit-test": "*" } } Base-1.9.1/design/000077500000000000000000000000001320724427000136465ustar00rootroot00000000000000Base-1.9.1/design/class_diagram.png000066400000000000000000007105231320724427000171550ustar00rootroot00000000000000PNG  IHDR|bKGD IDATxy|MWd4s S|%Um5I[EiiS\T!⪡U&14*1D( R "|srN"C~>^{>k >{-0 DDDDDDDDD$#_(Y&""""""""re"""""""""w(Y&""""""""re"""""""""w(Y&""""""""re"""""""""w(Y&""""""""re"""""""""w(Y&""""""""rݻ;G"""<@ 0Ƚ@n+VDDDDDbdeh0DӫW/{!"""""Y&""""""""r,Akh2) %DȃXDDDDD(,Ck<شFY&""""""""re"""""""""w(Y&""""""""re"`Hʕiڴ)ӦM#==ޡ}F2ի޽#FвeKRSSG,?-0,>\x+WRvmɓG, gggz!tŋXhe"RdgΜԭ[WWWիY?5Ųr[nTV <==5jׯ_/T< .\:iѢUTɉU+uV%&&TT ___>#^jΛ<0 {!r988F``cɿ۷Ӿ}{]fu͍UV`Qn+]ҥ-[p!onݲO}vʖ-k~^ܹ͛Ӹqc:d.ONNUVڼHڷoo.ۻw/mڴ!995c׮]ck Frr2#11 RSSٲe 5|GE7  Xg`3aÆy$::prr2cĈFiƫju޽{ WE9pORQFYaƾ}%&&QLr7770Z]gF͚5e5ob),,Zc|ث'D֮] !Cl۷/6lȵ$zIff&ڵcʔ)7mA0 N:U `߾}[>}0HKK(S/y{{cϟ7ǼHpw"2-Dg\ߟӧOҥKqtt8qxgX*++k׮qaf͚Exx8޽ Z]Iٳgw6=z4}!::hvM6tЁb_&""""""%C2)4[_MDD˗orVuL]+WQT)*U?xxx0eFŚ5k/_ѣ9ydݻ7+VdҤI~,X dÆ ԯ_(Hk"Rh(^js~. 888d5jgYq1b[l1ӣGNΜ9Chh(AAA4h'N0tP1fDDDDDDd)Y&"Ν; t]zz:=z 55>;Zz7n0mrΜ9$$$0aرmYYY6۪[.}!$$GuVsΛ<%D^z%v)33|DDX>ҹsgƎg?<!!!Vppp^zѢEzh5^u׫W ;o""""""R,B4h+VdǎKٳtl€xqrrbk"##5k?8-!>+goyfz^3,2339y$1#Gw1[.p;oq-y76m˗_nݺqFRRR$..@d77ۺ888fNd̙3Y|9aꫯҠA4ibDDDDDD%D!d~Wm۶[[(d`ZZƍk׮йsgƎˊ+(]t'""""""5Drg,ZsDze1cF_us%za.ٳ'.]bvLDDDDDDSL%''g+дiSڷo׭ӪU+siӦjQL06mرcƘ1c3fǨQ,DIjj*3f̠cǎ4k֌:_aўXZnMppE4h>,mڴaʔ)j"lYlO=իW7רQÜ|MNN.EDDDDDH.L;v@<<ի3zh6mdڌ 9|… ̙3)U27矓l<0`IIIj*3f *iIMMߪÆ ҥ=]DDDDDDr'D"b]ѢE^d qƄ{n"""hҤ {!22*c䖇Wfǎe˖Ua 2;v裏Zc*3RL. )3fqy'=z47o6ٻw/5bݺu||lnݺѣG퍳3>>>0Rxꩧ $66z}ѣG~<۸q#'OA8::R~}Ə`j'kUȑ#[. k׮wJZA|Qv"0zYk"ԩS:uxĉL8sU'x¢'_5 6v 0}9qm ;;<ݻws!ׯo}kΞ= @ǎm?~U)I *e.\8v,Ș\~z/'Sؗe"XďԩSIHHN:lOOO޽E=S2(gRɾė_;88X\4e/5V,ELL ߟƍ`yaܹy^_fMN>́xg\k.BCC\2899QNN>>,]{똞2g;rn|\,ew*i#<3g1ꈈ}2<%YoyfΞ=kѤnݺeZ"**>>#Gk?ѣG߿|vl&bLcLL Ɍ?2e0a?~<={?d/_ʕ+s:w;~-{f֭~cȑԬY*ȑ#t| ÇVZ8::@r %00wwwPZbT~窤dڵL2l߾ݪ۷S\9^|{q""hX͙3֬YCZ;vԉзo_;G W^rC,|MjԨAXX,,, www8EDDDDD~,J.㉌… \pHƏ;=ˠA6mZ_DDDDDDK2{(00Pk㉈JܡdZL+Vl0DVXaDDDDDO@2;֬YÚ5kؑe"aADDDDDDDJݻww"RL"""<,:֭#Қe"""""R,#,,@{!"N^.]G沞={tRϟϠA8991}t{!o;|QL%''3w\6o˗Z*[+W΢?+8rTZVZ1h ʔ)cwef͚ŶmHKKu֌=ȱgTBBBظq#;UV_o߾X{ٲe3v,K,4nܘѣGə3gǏSNDEEeGêzYa&Rڥ<,EΧNԩS'Ndĉ'LJ>O>$?`ذa$$$Xcso9Mql@pY\;|qW\&TGDHSLDDTJcYYYVeSN%!!:uвeK<=={L 4DIgNٟspp0aTGDDDDDD~dH.bbb4nܘ os5kri83$]ta޼yܸqޡHnaÆ4mڔ OeLŲeh۶m1ETc,"""zL$EIl޼gdqnݺeZ"**>ΖGߟ^{~GҿvLL޽{uV_͎;pnnnԭ[^x޽{[<mRy˯_~#GX>Mdʕ+yWy&Czz֚[Ç77 bcƌ֭[m6=ʲe|W7++[wyTovs!>>~IHH`ժU<_~iqͤIHIIGl޼GOxx8^^^;w?EoxNJӧOn:~g-i#zgٿp.g,͚5#22#G~zڶmKzz:Cʕ+w"""+%DDggѳgO{#"Kre Ę1cՕ'|ɓ'ӻwoYdI߿ӧЯ_?:vh>NFF 'Nv899SO_fzzzZ|~a2dS>777\\\hҤ }p{L_'''xg9s&`gq[v;vӧЧObsȐ!4hЀrCjܶG&w5jԈ 퍳3^^^|s|mP <<}G}"k""""-[̯ꫯs]D?99Cr-Zh#,رڍ=XwV4 8y?cԮ]ݝӧO믿O?;?UEַo_ڴiSl}>Ve-цIa]vѢ~sNl8LEDD;(%DDDD8~8M6ͳӧs=7fΝ;k8s >h˙h?~ŋI׮]Yz/±caQoРA9~vߟ6mкukcrruuF<tڕ͛[/jVv-ц-w?$In+'J慩|r֮]Kٲe;w.+V P/s*U*Tjժٳ:uźgk׮7Kҥ ˗g̙/\`^nݺ,Z:uEMgWqRmdW{]rl/_QyyP)Y&rG^GAED.]ׯssB!?ĉqpp?+>RRRHMM-pwӯ_?fϞͮ]e 6 /Lڵ\2^^^6f׶m[ڶm˯Ν;!&&SNqY&Nܹsc*VIYqdP{gصkP]cǽ}gH| $,,a䋒e"h ㉍e˖ƍ1l0^x<8|0ǎ׷8¶az֬Ysn}ì,Jf͚tڕ]yfg+EIqtEw 6f۷o 4k 2<)" J-[$>>YfZ7vZyZlIhh|ʔ)9rvuMra"""eǎ_VZy.`iN:Y>t-Z|u ;oEQ}tՆaX% syꩧppp0ݺu9s5ǽ}i 3kdн{w{ "$EkxbG޽>|8 6d|Z GGGnfӦM,^ 2m4Ą-zbɒ%\jժѻwoʖ-ˁ裏^׭[_dƌ5k̙3L2wyʕ+sI+sr իK3gC aܸqʉ'2e SF*> :jL2~zڶmKVV΅w0l0yԩCbb"SLaԬY3_?ފ,#,,@{!"5cz!sN:wlUg„ 4j|lJP9r{,׶M׫W &3{lfϞmQ'$88fvW_305B w}ӧ9x 5k`lڴǏ[$Lz!Feq\y+賠.67nݻ2dĉw}ᇼ{|ߘ3ge˖s,xy]x5j;"C8jժ}ݺu'''ʗ/ϳ>… gϞ-pݺucҥlْ *쌧'Ḻ-j׮M?>'O8ߣGMFFpqq\r4oޜaÆ4kʕ+ʕ+8p ^^^與}ᆪVZtފCqYqGSNE)SGGGN sΌ3ɉ5jЫW/֮]wVJ͏#+WiӦL6t{Z 0f~<ό3݋yY _T''''*W̓O>9uT n[XXYYYoqk{|@RR͓)nɝU/I"1=Yfg-uu҅LO`at,"%ӓӧӱcGqHHAAAvh ?O?4[l(z\vԉo|\q}/>1o<^{b^sάX%Vq4lؐ]vQb+sgb@ХK3/{9sdw營_'+{={=@%"""R@aX|222x"+Wvٳ7n87ni&<<olڴ:oڵkjr0 n޼Ʌ ={6e˖e|W5OƑ Zj9r';T)%D!..ڂqvn̜9#F0|pf̘ٙz.]xb-Zd . ׯ纳֭[IIIy ~m3իWM6DFF2rH `ܸq5`fΜ ܹsU9::RfMX|9~SL$rKd{!&&۷)7n]vݝ5kҹsgƎKZZZ#"""RΜ9C[y^zqaZ)bbb֭ժUOOOF 3< Υ3}tZhA*Uprrjժ+lݺf{八+*Uח>WڼfbJnɲغO2e >>>?+WZ+HG׮]l߂~/&NXϜ9/e˖CGӦMۛ$r/7z7pwwٙ~/﫢FaksεMnj31cF&t=z0ٓK2| dDDDDi߾=׮]3]xpV^ͪU Sҥ-.\[oŭ[e'OO?eÆ l߾=_;f~K%''ӪU+bcc-/_LTT֭#22ۛݻ6mڐl. 66X,X]x衇2oZL2]k׮͍֭[:o(U o߾DFFׂ*~Kz7on]AEQ 2_[?7QQQ67Wck׮?~CpAQ:o=Y&RLLpҺukRSS1c;vYftЁ/: .]bر<u ֭[s)222b|7++?+W);XOۛ~Tٵk͚50 >ck Frr2#11 RSSٲe 5|GE7WWWZnMbb"8y$-[uもoG&[a笠}YJA8L gCagbb""))>,_߸qDoX|HZZ*Gƍ߿_|1ױ]a~dH.Ld && РA~$''9pB~W" :b{WҧO{IKKcL6W8[A^~=[Ojj*6l(XEDDD뫯ҥK=?///hڴ)w%))Yfή]1bsƍ̞=zs=ҥKNGGGUFn8|ƍݻI&ٳH-~N:,\hfΜEQ8NQw>jՎTGDDDĞL!C<߷o_<їDϞ=̤]vL2Ml.Ca:u}(?}4acuXeJ/b>a?\VfJ}w㼒ev2}J2)S{'rMZwU{Q8[l빼)S-Z0o<6nh:S1;'''쿨,.kb>޸q#'Of͚DԩQQQt @ѣ7mڔ#G2rbWQ,nѣ6WE{2-g f׿N>K.x' _Wk׮]̚5pٽ{ep{]xݻ;lwӇh 6mСCڷoosiq̛l߾dʗ/ORR;v+kw *%% *ܓ~=777j׮O?M>}x,^&NSr77k ?`Z s}^%!!___6 (6o%Dr騩S2uTĉ8q"ūٳgر~L?=6[/(Jʕ+/_ުTGDDDĞ/]z_5/_oʕ+[1vY\zGRT)S5jk֬1[|9GɓjwTXI&_X` ,ӓ 6P~}fo6nHΝ̼v2==3QS$ {/gnk@j %66:wO?]cMQbZT~I~AdH1[1? ٷvtt$33'aι %VMc-U-rSEDrRlY]իWXbMHHw%KШQ\HNNnF)Sزe,<<ܼpyÆ ֭գjժ<4hf[??ٳg駟駟8v'N`С濗2oٙek׮sZ87) ~ȩ0^YB/^L-سgƍO>XLOQ&%%)L2\Kiܸ1 , ::~Νv9s ~]iWG%66bCYupp0 RRR̿I⎳*UpE~+d#"7|_|a%4i!ܹؕ_~9ץӣGRSS0aBOxzzrh޼yqm%:X̙À,e%/++/7֭K>}ӧp{ :=PygB [0X~=e˖JտIQnnݺeIߒ-y <3fΝ;[$.ލQFDGGk.;5?3-/.o?1c8rn|lۮ];&Mľ}$..I&Ykz ͚5qI(8[A~G8sU;2S{z饗̴:hܹՎz9~ :em/zh_ξV?sWV6w8/ċ/ȅ ҥKnWW<+lr"_9+c۷/r-nݝ,}]gX'p-Mf3saFXXX&#F0|}}uakVu}}} ___dK.?͛779b{ O>V㏭Vv\8jǖPWZe .g…f͚|%.aaaFr_WΝ;'N0N8atG{>}`"+ȿ7Ν3*VhF6mݻwiii͛...~5|?qs1߸x񢑒b~5c͛7'N&M2\\\ Xd4.^hdffqqq믿nqϜ9cfԨQ`<Ɔ ׯ7o4:dknݺirWHH7cw/_+V7o4nܸQ9>ݼy_Hm۶`8;;۶mW~808,YbͽKRRnFv7n0nݺߊ>700 >00mp%֬YCڵyz*QQQT^ݢiC[ _v-[p%ʖ-V;񤧧3o<֭[_5kƇ~H6m,OKK/`ƍǸq̏̚匫̫C~NII_Ga޼y׏Dt Lݙt0XtBff&ӧO`ذac)L> '!!!9)7QQQt5קXKh>c߾}w#{f ͚5c͸ k߾}-~7oYwܸq,[DV\I.]?5mԼK_Njbǎt޲+<\pZjΜ9Cݺu󼦰?-̜enʕ+ŋv/l%5LV{QRqw-Z`Ԯ]GZ^e׮]\zEoKqŴZXXLed ɩ?9sš5k;?N:1`k,(Y&bJcǎ駟qF.^H2ex1b+Wܜr}vLBtt4ԯ_^z1bJ¸NӦMy7ͯfeh"ONBB< :W^yŋo /qF5III||7:u7oR^=jժi޲+yY]SO>پ};7nܠF/*UAmۖ`z!u oI(?^1Tr IDATDǡC!33q1a„{>g2i$;~w~aƍGϞ=^2?%liiitޝ{#G0uT~'""",~s*JIn,%DDAKi7Ly.]?e""ӧ `xIsAqOĈ܍e"@eРA\:u*111DDDW}'$$g}a >zѰa{<ؔ,y@Kk""F(ә1cm۶5{ /?\OHw""""ݻӽ{w{!f\B@@, +Wf;F&""""=Y&"""r|2K.eRV-:vH-,ꥤb vիW\2< ݺuئޔ6m .رc8;;ӬY3^uSWYYYX;wDݺuyiӦE[ٿ0=~xM~ElmܹBTT7oNժU&**:PlقRLDDD>ѣk.;{,3g$++VZʸq8wڵk9t&Mzp\~7nqF à"##3339vǎ#--5 B*UJdܶرt4ibuI&:t;w^DDD%Dٻr|çĆ|g1rmfÚ9-a Y s K2>u]u])ۭ~_wz{_kHY!DQ]m߾wbooϴihР/DFF*A;vpu6mvvv\tUVq5mưa궱aʔ)4jԈH"##ߔ`/7*İ~z0`,2mImmmYx15k,qj?N^{{{˄B/ ;!Sҕ;kkk{=%ĉiٲ% ._~%FlJ 22*MMM䧟~tܙ}ҷo_?`e|2P ,JuLUF!B,BT[? d988S*W^^rlѬYDٲe o6D7iDrE;nmݻ5'ꘪB!>$X&PZWtDOG_Eը>m8;;Ӷm[~wϹs c׮] >\ef+mhq^]sw1ς9B17 _ R !ԅJAQ5jԈ[nq5%ߖ6VVVܸqgҶm[ٳg,UuԡgϞٓK.qQoΆ JZj瓕y5r[듖FFFW;tMV)!6mZ]Л˄wyGr QHLTy:w&003fPn]BBBqƬ\N:q 6m\tбcG۞:u*L0ݻӬY3nݺhJ'%%E/9c߾}曤)},͸ݼysҸyFP͛J!B}IL!xL}6mڨ}~W˵ݏ?ݻ8px6nXք?+?͛DFFZCe:t(-[:sB!aeeŌ3J,WNƍǸq-+*_Yq5O055e„ L0[[۵jբDFFPٳ 2SSbB!(Ls !]2rb'$$(dz}v^u>|5'̋}:|06mɉL>S4#++y1x`ݝs)|aaa]cvҒT`τBQ2!tж???UXjUXXzu4i§~ʰa*K ZbxyyqyvY2l0ټy3ywχZj-镞)SL᫯b8p>  Kߔjբe˖?B.MQIII=KKK~'W=G$//777RRRCO{=&6D2!H^^֭ݝ.]н{wƎuwLVZ+]taYǏ+e ?8::j}ѦYfܻwO}4i=zɉ7ߐV?d''' W^+VЫW/VXapiii̟?^zѥK<==ٳgqsQfMƌ@LLrhǏW^J ԩ 8::FFFA}BQz[fذa5 Ebb"3f >>{VZnoСCŖUmbggeϚ*m'|̙3Yj'Nn Q2!tP9<#FYflݺӧO3fZlIhhRח`sNNNԩS<|PyPy1&M"))I)B@@O׷ط_%r 5R]rn",,_iiiJ/2|>>ddd(Lo^gϞ=xxx!D 3*ӿ>)=`swˎ;ܹb`l۶ݻ,?<eEӆJڐjժL!DU#3˄(AdGFFK3∉alٲE)i&xW ~#<<ώ;/P}hr-Z@.]s7o`>|#Gw۰aiiinݚHbbbxڮ!!!ٱj* j3$$ׯcccC@@qqq2aÆ_%J888hUSB!0dVZ56lȴi]=zzv>|XEpa`jju IMM%00{&D&3˄(x!!!$''ӣGݻ%K`ccb.\ȠAbРAzM9ǏW>Đϙ3gؽ{7.\J94O>DIsΜ9̙3Gk;>>>bnnի1777(vСsUT,nCAxx8;v`̘1TVM.Unaۢ:MRԃ?~<ʱ[nJ||<  $X&D۷/NNNl߾D֬YæM2e%T8PMYW%7e8s ޞ6mhS$#F 22l֭[m/RjժIJ$aTu)xvvAnnnEwC!/SN1w\RSSNK퍽=W^eɒ%JZAP2m\]]լY3.\K/?8p@ lܸ7n`kkŋiٲ%Nb%֭i׮;vLmǏڵk888(Rʳb,ҥKٲe`Ypp04i҄E@RRŋi^}7m˄$9˄!!!??? ?YBBV f=~077jA$Ռ;wա׮]Sr=8Crr T6lH׮] oaɒ%ԯ_+WPQȑ#ŋ]V (oɥKꫯXhZ̙3|Wmrty.\`ڵ\p&MЯ_?Co% nիA1R} !-///*B_>|~oooo߿{W_Ϫyyy1rSUZӇos}͹>N:jρESu蛚(ՒvکWUJϒ6Dғ`0$XŒ%KXt)K.U;WAg̘1믜 so\}+(˗ <Per%ܹr\WZWsN ʊjT>|/TP0d?|^]ҌݝoСCپ};Fબ*5+III۷ 63XfccÕ+W8qߕ'NPfFq-ݻB҆Q< Qy ~b˫KbnnG}G}Tl}ҷo_&W[.K,zhWek[m&Clذ쳔,,,Ԏ{tktQvmF?7nܠI&@'N0qD-IL啖yyy\~]yЦMjöm %%Ec%!f,Y_|A۶m9w_~eז&-GӦMԩСvvvO]wQf)Gd-ZD֭IJJR fł $X&Pݻw'33ٳgӷo_ԩիWrWT///~'BBB5kPZcB!.啖RUԬYSm=zɊ+Xbڌ0Cyzzo>Ν;_~JGҦ >>e˖hVں 75ϵk7nڹMjӇ d7L!DRXt)zsμ;$$$РA޺<ժU cRRRHIIaǎ,\BQ+Wh=J@@ӧOgȑxyy1k,"""UP,[e˖]&u QUE0UZ WWWׯO5hٲ9#F###͕Ig ͜9&M`ddTbJ5j`iiI^i߾r?dԫWccc7o^1~~~ < `ll̛oɜ9sJ֐֣G5j_EÆ ٳg];ϧUVcll=cƌ?y]ݺu dȐ!XYYaddÇ'((HIo~affFll9I"D嗔PPj aĈZ?g'//0v˗y1/]ta„ XYYUtKʱcǀ7ÇBCC9rg 77WYZPs-[Վ_r :KKK-ZDÆ i`(o|fΜ7ZzzEaooR͐LMJJ F6&n:ٶmZڐA1qD&LP=/#G+q}ddBU^#FT@eU5$((,ڶm'撜LPP/_&44S[٬Z}bii @>}Xr%>>>2V"rZ QI!JGa !Bh1d RL>͛cdd ̘1ǏWdl۶tM\\\BuU9-$m#3˄B!JݻpqMI~]xcvv6[n%..t4ho;ZgUΝ;ܽ{uZ9z(?3/_ѣG4hЀN:1|pLMMV1<|(^}UeY(nܦM8p k6 5kM6i)DձcG&O7|)Sl@!2!Beee1|O˗@Ya999|\tI9vm"##ps̡z'{xx… ݻ7:tEԨ\XXjؽ{7>Tpjc>LvvZrps)9"I(yHK!*7%a$X&EDDBT-ٵk'VVVL6 ;;;Ο?ʕ+IOOW+sN.]D-xwiڴ)7oϏSNqzMxxl.>}`ff͛پ};۷of͚+tܙ޽{+aꉊ`„ уjժq.\lRZ}`ggq2,B!De%2!k۶mGE!^`=N||<-[uL4%K 򍩖RSL> 66V 4ggg9yI]> IDAT$III={ӧO?3o*:CǠ򰩎iOBTu<)EDDTy,:zw*'BҒeYjܸ18wrܹse---y&WHJJbϞ= 6Lj[Ii/ׯ+}`mmMNNIII)hGĉt҅ׯvZWk CIKK͛A1U`yOq\uFn*B!ʐ˄B! Կ:č73gNe OΙ|677޽{L>KKKV^MΝquueǎDGGц %/u\|k֐1tЁ.^H֭^x;{τJeBgĈTt7"2!B-Ufjj… %!!Llmm0`ԬYS)kffƢEغu+ܹs333:t(M6Uʎ;PQ{zzkg.]_M4 LMMgرrq=zңG8< ,N:.?Vh?ח-[СCiٲ%۷> Qv0aΘqMhժUbî]7nvҒTpB!'2!#sȑ#XYYӵkWիǟIdd$|駬_^mʦh(==+Vƍl|8V`τƍvvvPzu,--ӧ˖-SZnͰa $00Çk$B?XkLM'|Bll,<~'Ob _}c~<~7oɰa8yd9N|Kw^֭ӦMBތ ؿ?w‚^z{QNXUk7YϏ3gbmmiРT!׮]ݝ&M}v222 SNj^7n#aaa5J* C߿Σ,=bFJJZQPxFӣG|2=zO?H_Ռ2YQuHL2vZ%Wʭ[ |@A dܸqܸqC)Ç54S]t]6Ǐ/qԩS:u*o-K~~>|iFǏ4iIIIʱ8}4jA#Z .fggʼn'شi 3]222֭]v% _~}*ebbbc?3Zx;;;Ϟ={лB!Э,9+K3j333֬YÚ5kXvmdbbBVX|9^^^?;wR瀮7o&00ɓ'W`Da S2yffϞÇ9r}J7r lmmٰaqqqq: ){4iL U#&&ٳgeZHNׯ{Ȉw}WMHJJW_%44~pڷoO||<;vШСC\8͛lڴI)Lrr2M4! 8ŋ= ?('$$( iWΎÇ_0rH4ʩeoP0A>1U!B4ϟO^ҥ ٳGkLVZ+]taYǏ+ebW}w5ᅬ [ LJS˲e޽;zbݺuܻwooouFϞ=Y``=?[nՋ瓖_CuE&OLnݻ7_}YYYc}(I͚53f gO{YVs_|{ٙs璙uɂ ӧNNN 6(/yyy[wwwtB;vz_ij'3˄(/!??3gΰ{n.\E̒С}ӧOWאFFF>W^孷vZx1'''Ϫ/vکU7o>u1]UpKӓ-[3Gɓ't҅5 OOOКLuLUFQTTofEwC! ذxb8us%55UlYsU,Y̪4hZ3KE@RRSf}wi6oLffݺu,]-[uV7n̆ Ә9[ ЩS'Μ9ܹsJӯf͚pB^z% JE{o~hذ!r4^A}ŋiٲ%Nbc-7l@ZZ[fXXX|r~Gt KU&ҥKٲe,we* Q_f}-[3g`kk?iӦFnUp P-۶m[_Α#Gt3vXڴi?FFFG߾}qrr_e$&&f6mĔ)S-9ˋ гgOHAfhžf*n`M ÃPN>,U-mm̪c6Sy|PB< Ymfy;w.ӦMS+_Yv5BifϞ=-Z0b֭[ǣGVf5 ???evPr5ʬYhڴ)#G$ +KsK6l؀ZHrڴjՊQFĒ%Kر2UښWsNeGz./m1nCVʔG?0/2U˄(cqqqӇdeH(XRذaCf,Y_|A۶m9w_~F]ҥ :t3SҥKLMM9<}Gk׮z*innnܸqٳgB-$#Uѷ\qƏ޽{q~~~̜9S9׳gO3gf͢E_lڴ7$U/YhZԩS,Y~)ez-ZD֭IJJ⫯givժU#??k׮)o i8?Ov_rW^֭[\zU#(z`7BbÆ / ///?o YRtƼYޥU_XYFP). dbb>W~>+{\RuqJy(qfUMY_߅!}wZ$X&DѣQQQ̟?_g쌧'ܹs{~)A C,]K.iM۳gO-ZT_ˋ%KtR.]V[P}VZ,X'2 l̘1믜C6l,Һuks5ƍViӦjJ; ;ܹӠvK2zh""" [׮]9x Oj梾9!'NKEwEԟ-.]"11Ν;+5ʖfV}a]PV Q <ʊ!+eʣ^z?\x֭[}}gZ$X&{'Kll,OsVӐP &<<_~˗/SZ5P{zqSF Õexyy)[$:t`Ȑ!lٲo___ԩC@@ׯ*>N4_~Y.,XѣG~&LPUn]_s5w޼jKAK;ƙ3gzjnݺlAmH%]s׏+VѣRNxRL!YTTTEwx7t_}2̙3 Um{iW#wCj}fBI.ty.\`ڵ\p&MVVǸ Y)Swڕ0,YBYr%?jΐDVvT-K_(sZj0b󩴻UU|4k֌[j_nl۶Mƍ 4'2a„gȑ#iE?JpL5TeB/{{{/_ߠYҕQio{bԨQ\rE5jԠe˖J³UG5FFF+3 L9s&M4H[0}tڴikצwެYZ 7}Ȑ!XYYaddÇW H%uF5bѬ[Nj!X_~ӬY3 ͛e><ƭZ)3x`4h1o(ˣFH߾}[.5kt ݝӪU+166ޞ1c+뇙S}ae$3^L/̲o([lƍu&=vӧOWr;\R|r,TeW\Q/,55]vHZZ5jॗ^SN[j;WPќuB}Xr%>>>K?ug .jժ… >}*eǎ\R+Y&BŐ!C2dHEw0}t7o&&&8880c ?^]Tm6rζm*gBT^f⣏>SSSW5(˵UdfB!򈈈ȑ#ܾ}5jдiSzI޽fgguVHOOAxxx([ʩ~^zܹswRn]r%sQ~g._̣GhР:ubᘚ{>cx!QQQ4lP9naaA6mbԮ]۠-z2ӻe5 r+?Y&BaPnJJJ dggsy;vڥ?g۷dҥؖ .$$$3gΐkP7|lڷoQOȑ#]!YeBȑ#9B/x{{ꫯKLL ׯ'::sN.]D-xwiڴ)7oϏSNqzMxxl.>}`ff͛پ};۷of͚+tܙ޽{+tգe8azAjոp .رc^4R7,B!(o,!xOVxxx8dffO?qu:wL߾}۷Zٸ8 ߘǔ)SX3$''sI8{,Of޼yj &??dbccz*O 33ض ˗ѨGuLUF!`B!F͚5kHLL$11-[oӿLLLr)))NE]v͠v찳cРAm6""" ?yݻwINN8_l޽{Zs񼉈.!D;SЛ˄@l!DS?Х,c]"`W IDAT۶mٿ?Ν#,,]v1|peaIK5zhYṉ5kFDD@rr27SN/G{cVP(1U!7<) _!!!#UXhhT:uٳ'={ҥK=z۷a%Xfii͛7Yz5aggGRR{aذao޼ hN -^sss_ FFFZ5d '-- ׯv.##C)#DvB˄B! 4uTRSS0aݻwYfܺu 5xչsgmƿ/ƏOf͸>vbǎiӆ 3III̤O>X[[CRRAAAJ;*Q9q]t]V9իZCмysҸyFPLk޼~!*CrʊBTzݺucڴi HL!@ Ϗ׳~zs[V+sy>Sr&&&xyy)͹wӧOҒիWӹsg\]]ٱcDGGkOO뉉___:._L^k:t@BB/^T/^cǎ:Uѵkת\.!x"""ݻ Q;wW^yT:::P]*9z(NNNCQ)Sr>}022"::ZYظqc:v숛ŘEuVsfff8880tP6m;v,^cϞ=\t ###4i...[رc⣏>%͢ReB}ٳg‚=z0ydݹ /T|FF~~~߿;w`aaA^xSN3Z}pV^ʢW^x{{km;,,N:)r Ǐ#aaa5uBTz[fذaʋÇk$B?]i=233={6GQ;~INS֯_k{|*`l۶`ُ?{g7h@IAZI?(Ja QF6o ٳ9|0G 66֠ 9%$$(INNI&?666\x urcٸq#7n֖ 6.\h888hSSB!xTt"66 iذ!FFF0uT&Mē'OXfMEwկ_?j׮ÇIKKZ&==LMMۗETV2Lbz)zӧЬY35o\B!ċ&--+Wr!gJz/S333g޽ܾ} z-&L1δ;w`ԨQj1 :t(jJ)=T=zvE52d&M޽{|PfMwάY]fҥݻcccuƴiӰx~ɓ'111O>̘1Cm>X:u.Oxx8;wdر]vgâbAEWt%QQKKK![\[ " qc#l ++1(vQTl(Z(wof|[9s}98PNUm6mi֬i&>Lrr2XZZ2d"M:2A(#=bܹ$$$S(eR4ݱM6J۶m {\M_˟  ߓ'O~IۤcAA%L(66.]zLj՘4iҶYz5AAA[lA*) %&&___LLLJܮS*o>Xp!P>.LuN@@!!!888ٕ]^^^uֱsNyNNƒ1cԶ}vM8yJOC$$$ƽ{*I5jĒ%K_>[nLJ09ikZfaҒ6mpE~whܹs-Z ]M4Gu&/׮]5999޽{ G?kE˄ ePF"""vJO^rssGGGBAFF<\ann۷SN9)fi4lؐ7oD(..N:up}RSSS>S a„ ӧ!wy5;myKѮ];ܘ5kGsssU@dɒ% :PI~zzz|R뇭%IBӦMۛ/^*7n6m<_ٺuk.\W_}EXX\WI쌅cƌLJ4yI2 3|p.^RbiTYI5vXUVٳgqMz聝R=G?4-Lӻwon޼fZZԮ]'O~Nrr2*HA;w2=z`|rZlI||߿ORRJP,))I>F}G PTڵS9Ν; Sҥ)K.)MMpmѮ 5`\]e.ѣر//BG?4-LԨQwwwL"\\\)۷/}U)f͚8;;\d{4=WVKTV {{{nݻw夲w%&&S#PΝ^Ԯz'@>}qVb4oޜ9]F~={d,\ggg6mJJJ ڵ kkki=:wLv툎3gҹsgTµk駟K.JyJV\)Gll4h6})uBbaaA]FvTɖE ݻwqqqa4mڔ?P VPyH"DL 3a<̌cVrAx[uڕ]Vv3A 5f~n߾C:88pq.]J*̝;W]ʕ;l08pL>7nRGϞ=Y| &p1ܹt %ejj-[dԨQ.mXS] ÉbjE&L;*y^Ys.]8qqqq*u4-Be9A0,YINN&$$%KPTAM.GؘM61x`jժ>͚5Xʟwz`oozzz#ę?> 4@OOONP;wdٴjՊURZ5>6l/fRJ#GR^=W_|۷o/2HIyyyѵkWWǏ[?ʣ] =zPNRRR055gϞҮaÆxb7o!XZZҥK =<_~TZSNiZʦ(.K ttt^B^-_Tr?cƌ]ABE~$''3h ߩR oooonҴ :S2yJnPVƌYRO<}4?cY4FxtڕYfUv3Jfoo/  {dffB߾}^:IIIxzzжmJn Ex]z;w ,o@"##+  Z8p *X^ر##FԮ][e%Ax[4-UQ[Jf)  _СCܺulׯOΝXAAPn0E3MQ&ޯ    Y&TvA(#  IAIyDLСCߨ (yA ׵kW1KAA`P*߯f#FG2AAAJ6\ZWW>9s&UT֕j:6oތ3O>-:AAMs7*W Beϯw>XV.\`ݺu8991|֮]KLLLe7KAA#e000~ >]vsJn T?gΜ233Y`ϟ?& YhvvvannΰapssHAAAK,KJJbʔ)XXX`ddcƌ!>>^:::tyF{g!ٳSN$''~{ԩS}}}֭˧~ՖȴiӰȈZjѾ}{.]JJJssѫW/]6&** {QmcmmvȈ͛?ЬY3qnl۶2zhy_|Çٶm[%LAvUmwڂ?]tޞVBKVէ:vH>}prrx0`yyyEǠA&::LDE_͛ǼyĊB`٩Shݺ57o?:Ӿ}{BCC.X;v`cc=zDNN7oӓݻu.\yJҥ ԩSaժU*#?~̲eO͍L8::Bjj*/,\P򨿸UF FşoT޽;+ڪ֖L>OA_q)7Ο?Ç8p u!uϢm۶ddd(ݟÇ" aʭ-T5)HPa~ꊗVVVTR6oٳIMMeEŋprr^͋/5j7nqЭ[7v GN==={=Fݻwqqq/T:GZtΝtcccԩ߬`իWceeC:\VP K.TZ?͛7pY^ٱc=e˖qI>s|||T):uJȆ}}}?ߟH裏"$$uxyyG&MXvV+(M֦ӧO?ܻw__RۨQ#8s *}k.޽KÆ ٱclڴI)WkrƌCժUپ}RR[n9s-ZC&# Byy2|*5o]]]4h WK~VgΜQ;^==y$UTPF IDATO?-T&D,Ϝ9Sɓ'9"55/\ǪUK#0f̘r5 [nivB˗߾}BvhwvÆ 8p ~~~VZP({,MJe[ǎF $(j4 V… 9t'o&M`ll,b?~,?r4k ===4i’%KXj[~zLLLꗗ/__J\\\֭[#JROz}-tuuUVЮ];ʣ~MW͚5ڵkr;==/RZ5QF*hܸ1  =zŋի;wfر>|XmM꾻j"77@m>bmR<|777zInpww';;w{tt4zbڴi%j69"}KMMUW\MS駟Bgҷo_jԨU֧yyyx{{3l0:wLݙ8q7u2==O?>3TkD *~ )Yǩ!2e oʊݻw_JئMWp a^^iiidz~z%22R%w͛7|2QQQDFF ĉ s5lؐO>Agahh(_ʶjժ0RP޽{|ԬYP{)՞?u>l>}{ァyCv%jFwizYr---K}+ߺukڶmRVyԯ;v,{e۶mrY^|IΝ@'O/CIۤcAAx=edd0yd@W\UX)EDqqq[]]D( gff&t^-$JLL wÇ@HH*AM)egguH uS999KFFFy={ƤIyMʽ얩SǬ,G^^P$QQQ>|X*%Ua2MG+vܖ-[F+ݤKtKKZ֖Fj*\\\"{U@QY&+VW&?ؾ};۷oҒÇӤIV*Uhu{Iڮ?(Nq9?Ѷn{{{[)&n6`\F*`S^kzLMM>|8q))RX.T+eȑATf͢k׮ AЊ'X-Z>T:6WWW,--IJJ]N1tPΟ?_wWfzzz*)h4^y 6dŊ4k֌]_4iZvO!366VN\YO;wV9FJbffٳgaaa*2)EIHHHMNQ"͞M6\x]FGGsZhA˖-T t]kkkrrr Ã{,۹s'7oޤA,_-ZϢE~:۷oW֨Q#,YBٺu+>>>2MS`PZ6 S6i#M/!!ٳg:ݼ<=ߟѣGsM7o΢Eغu+\vв>s~wёf͚p ̙JoBŪ_>~QIH 8|UJ&ZҺ͛''?yғ#zQJ V1Hӡ .rlyԯ7nݻgϢK.]KuCmp o@+P)m%:AЖ6<{ Һuk9EJ%I)===ڶmUiԫ.免Jp,;V!tiYXj_?ƍG||<&&&L4IүH4IQ'yHʴI>FӧOjJԽ۴i#,,,8q"'N^/4hGJoBҥ {ݝZj?@Æ +JϞ=پ}; .ٙM/voo=fBCC~:7ndڵEŋ$&&qFiР+Q{%+Wd4oޜXyҖ[aYl[ի*זW\{!CBA6mU>$%%Œcw8#i7]0%%IQiYZZӧO'))qV!S^LQDvj0zzzҾ}{KsK"$E @޽9viiiѣG^w钼_ 9sXt)DDDqF/rƒ4`$I~ť3)HRaʕ+ӧtFŀҥKREٳ'111lݺU%X?5j$'׆4G;t˸qT?ƍD\\JuKoAGGBQh0]3qD9¥KϔƮ ?ΥK;vҾ*U0wRխ+&M"<</|64OOOڴWbjjҶ-[2jԨR[crQ^*WA:jy֯?~ 6m6}fϞM5`֬Y*7EΝ;޽e˖aׯ_g|ԭ[+Wɮ]?~,˾ <<<1bȈ+W4߿TVQWNzz:AAA :^:>>>lٲ0>|(8m4'T%u|q"GHbffFΝ7n<$xyy)gJ[CCC6mڵk9z(|,\_ԯ8^/@ݕ׏5kp)ƏԩST^>}hF!r o;Lx4lؐ7npEyz/kffFRR(v0m4oޜqƱ}vi߾Ҋ۸qc^JttҀXcrҤ5Ѧ 6͛*T"\tIa%aÆGpp0F"88@%pUVѣر//Beܾ}:u$o+I{ԩIMMUU!Re‚e 4;;;=Eay) .]Td~)Z޴iS6lɓYjdQҹsg\\\ԖIyJ 2e 7ndƍJ.Z={ȹs簰^W&!!}ѠA)mUsqF!o+ܼea7uMLL7o+]]]UVZiD«ak֬)rjժ74A5^rF?$ժUޞ[r]4hԩSUV-ҨmZD}ƍZJNQr?ڥQwܑG2i$9ݻwٴi0_zիWYb˗/M6\r+VYvm|8xxx+j69*&)J$tA^ڵkkNbY2dwŅҴiS@y$XA=z˗/e˖~)HRa2'GTZ;2ƍZHӦMYjdffҤIƌFFFedd666L0Ai.edd?@BBFFFtؑ9s駟ҴiSƏm711!<<OOOu9994nܘ!C`{R[EٶmӧOԩSxR!oL?͛S&Laff2uTx7fJLcƌ_~΄&E6lfff8pȲo:u* >\դMG͟۹M6rEңGXfU]zMiNmRsTMR7|pXz5_R)E&L;*Luyw1ܹ> m)HRቦ5k֭[s٤paOSPn ӧxB^vW]ruwV IƏυ "55#G駟nl f͚se233!11N%PV~4^7n̡Cx999*| Nׯ4k֌A=ؘ%KBrr2Ʉdɒ" Pq166fӦM 3s璞Η_~35"77H+Yt)6l(q?~CjridF⧟~~cʕ*]]]a͚5|GܸqoƎKbb"^Թ>G 2+WҴiSYp!9x}0`_5m۶ܹsL47nb y.TwE,N5~?cƌ)b7_Ax}(MTGΔ)S}6VVV޽===ׯ_! Eyyy֖H7or͛7|2QQQDFF\WWW&NHxx84lؐO>Agahh(_~Z*Ϟ=#==5kj))).ޡCUrگ.5.Je[jՀW2?m n fޤ@,9cAVlB@@5j 88ڵk3`6tuuUҨQ#VZJ{Օ7ojT5kdŊDGG}voߎ%W,I5k֌hܹ/Y2nIunbb%PhpFddd_JJ M[L߼sU>m?D_~4oޜ>}pu>իWr k;M  ""X0ժU#--F;$$$0{lttt-4WjHOOٳgZQ'''VZEXX-͛3b7nLݺuiѢ͚5S[Ν;w8z(O\v7n0gBBBפmӇh I9> WiDZZ45jBjj*!+-m B޴@'l}ו/Ϻ?~̙3ga֭jٲe >>>9sǏ\puYv|1TWnkkky$˜;w.}GGG|}}i A]䵨y7ob^N8VmnnNddk^^ԯ_TWf,Z;;;077gذan߿?*? }\tI~gϞjqqqиq_Z2@Hʟ5n8㽼?ָqcttt|9*JoVVV̜9,_֨(Hvv6ӧO/tD˗xzz0|p}:::@ZR(|ԛ66*ȻDݽfY{nMl_yr}xmennnAvv6=MɬYprrԩS}:FFFl۶ WWW]t!99=z IBCC5jW\{|g>}*#ҤuAAA撝]hӧOF1l0&>>aÆqqV̙3 -CS^AN#uGy›rvƍo^ۢTh rYիҥ 5ksN,X-[?QmQgK,)UGh@KʣG9}4ϟ?Ғ (d֭9rԭ[0ydyկO~ Qt̞={ҥKѻwo̙#_<6mÇINNKKK СCѣr[.=z`ƌTZU>ԩAAA9sFi4ũcǎjԔEeffǩR 端H>&==M6q1?~LݺuիSLQIZc֯_ω'x9z}~ٳ:P^=yᅬ5{aܸqrmA( 4;;;=60a>#e˖>oJ/8ٴiS6lɓYjVR:sθ-@ޘٙ)SqF6nܨtEسg;wN}7@߾}UhР׿~׶ 9x ,`ڵrzu={6J `ԩ*O}UoߞǏ+U*:o~~~1`GF m6*M~](RxTȲFH1kkktuu_%O>ͩS055e 4SSS077g̙L6/_aÆroOy &OLhh(iiiplMƎ;w999$''Ü9s4"SSʣRSSٷouֱeܹCNNƲbŊbݸq# ,<{\߿Ϟ={к:t@WWW%ӧѡcǎ*UJff&O<ߟgϞ1i$v̓ɓ̔MOOёRSS_~a…*dff^dkkKff&5Bi 8iذ!ԬY>}paOt7ё'N0`jժ!͛7g儅ij7f:t͛7+/ٱc}FFFлwo~g-[ƢEW9$&&&7вeKʊ .7!?W\kkkLLLӣVZt 777YfM2x5X[[O&Mprr"66V m߿?ժUC__oE?h ;v,fffcffppJr MT3^A(4Ȳ":tzR$<`Æ 9sgϞѸqcƏEQ'Rq)oԨQ( 7o]**ԍt???OYb-Z 66777>|t/|ᇸbiiIRRDEEСC iԨK,~lݺMPPk׮ښBCC`޽3кw 4 4bcc:u*NҺLLLh޼9 <~:u#R [YӧO ̌׳g];w͛4hЀ˗ӢE Yhׯ_g̘1]vq]6lȊ+h֬,^X3gТE }Ҷ3gΨЬYB(ӧ%[ntMc 餩3~xƍ6Y͚5qwwW:Ym +++#Ju֜;wNc7n̡C+[lɮ]4nOqׯ%6)}EYP#xyy?ȑ#6mxzzrI ޽;jgΜÃ#G`hhH׮]5ku-UO!5-mi_U!^`Ya$6i4I\\֭CWrOGu;x-[$(('OiɩS3 AZU|||g֭ˣU jԨIJ؛-~޴i'Q~^IJJm۶J۵kr;w͏?Hxx8>>>s=|}}Kծ4ԴLMﻴm&׼8s gϞ姟~j6}VŎ;Dr}&`YZuj2?hf͚'&WB899aaaAժUYp!ϟҨcccK@y-===@%+8Z@p1sBFFFS#JS4 1mՀ$J:BKb``Pd}СC,^6mڐņ 8p +իW@Æ ;v,~m}nӦ!22R~oSVWҼ~Km*6}}5Q7VڦIrsAA^_FOӧOJqqqiӦ+վxWWW5j<]AU|[[[ hݺ<*|X3gΜai0M|||8z(;v` TEc:88ʗ\  bdddPZZkLTӧ9tΖPkuɓ'tB ۹sg.^իWܹsʛB!w̜9%KKnn.1SL! @QSGP[!)hX95X;=Lc̓34˔kref͚űc3e)c%*DKdeЩ$Fjua~#F;wj^m21Obgyh (//ȑ#81ܹs+Whvca̘1h46l@YY{0fs-?XOݔF4AӍPZ~~>端vojr{y*o6kmJB{OeeeBB4ДN-g*m 'gi1׼v~2VBt*$]v7?>,[l!%%QFWQQUSäMV17S$4|ל>}Z놄{n y]v̚5K}@qq1~~~8;;Q"88(bbbyN;P^^^lٲH'=?~`κ( -5sNΞ=Pt],((;vp 5_ȑ#ņ FVVzQJ$' !e2f@sl;=x ղݰXaXɮ ݕ kh唘KrEn޼{gFQbС 4_233)--|̜9\ sʠ)*fJD@[[[uָhG*ّH@@X[[coo::g\]]֭[f???"##۷/666FHHK,s퍭-666#.^Ftܙ$ؿ?7o $$z^Ț5kHOOoԩSXYYرcu:*hO>ݻws:wSO=K/bnJS\\{ڵkՋ "##uFɲe_ԹD>|8eee̟?ooo8szdW_}EJJޛ!*007ZBqO3eG֭IOOWu֍'x`e>oAnn.o#44Tg2ei,Cs͆257ܹs)//';;;wлwo8u[Ψ2SJUb v_JDD۶mӹ+EsdU ?CQQGEhUVƍu_|}} #44k*G"|lIVVV^W\111lذs$''c(f̘7n˗/7x:T߳[GB4ӧ\7Q'XB Wn^0 Ym gjDo޼ytޝ[r)nݺE׮]:t(899Y.3x`Yt), iXB!$Jb=fԨQlذ^xPms̘1I&i&/_Nv횬AVOIgF469]tI&w?WF1~!h|}}e1AHX!WD1~!hƍǸq, ! U&ɼR4,!B!B!Y&'r!ĽҥK5os닓[lt 'NO>w]![B!D˄@NBܻ xu?C_'++"ۈjkűn:*++0a 8)B4bҢX~B\Me{]VV]7Xh8;;… Y~=MM!G!jmLD~^h9*++-݅F+'>>^}b VX!BIII\t^xA-8q"9III[wBܻBf_,-Ds"?B4cw_Xr%999\v={/2j(zdzsN\B.]x'y嗱S) iiiƒO۶my駙9suUQQA||<ѦM3f :://O:>>9sΪUth3T^}vii)iii 2'''ߏF!--I&ѱcG^!DG!Z/ݻ˗zǙ>}!Bh?@=/((( $$wwwRSSseHܹѣvSNɓj/ʁHLL}: իܼy/ """c͚5j۷os9׍ZxTgʜmȶm(++S9OOO8@ff&cǎ5OBB92Ϟ=+P'ot7BԠz2Nzj._L`Ϟ= 11QfN<+߿\\\(,,$99Y=z ##L]322gϞ=̟?u`yyyzcz"''7|]S999OJRG4d#uknLN|N8A>}tjmz}h{7שUVtԉ`2!ybɶ>h~c׮]L:gϚ| scܹ̙3+VpС]S;4 M6{hx뭷:… u.ȟ?Z #\G=P9s&m۶%77> &͛78e*cېb9ɔ2B!Y,.uO][ mjLJ{yyy8p/Gyׯ駟|7Xh8;;₟ .ƍ MʪA߯U]6mjmۛ[ɀy&+WdԨQ|F_STn{ IDAT!|oVoᔲB!Ľ.նa׮]̚5 ooo<==2e k׮UMԶә={6gϖpj,:CVpuuE'%%q%^xlĉ\t&h~򈏏b  @ܘv T% ^ٹ^CBBk֬!88bccu=ej{3 ܹ3zx6L#w#Knm !Ų81}tΝKvv6ܺu|-[Ƙ1cؽ{ww."[DFFO2tP4VVVƊ+aС=+WD!),,$<<zh VZCeL<7;6m^^^xxxϳtRLSS Eii)>=zX]V1/(++#22ÇMll,}1d~4 iii ZK'6lK.ŋܼyS$ **|'::'xnjFaÆ ѻwoQilvpp`ƍܸq'OS6Զu̙3zU곽S!ݚ^D@B-%մ)""}+°aԩ Y|/i^[^]kZwׯʹsԲǏ`nbڴi=zT-+**"11 n1VXXsM ***qqqYFm9‘#G~zob>ct.^HZZ%%%F g\vSrIkri߾5Fu9}4a{?>RSS)//g޼yl۶2<==ӓرcq&Oy^RfΝ={V=Rѽ{w2cELLނ֠Aԯ(..ggg6o\5`ٲe,[ 缾maÆEAAN?װ>B"2B"# ٻw/8::ѣqtt^{5MƝ;wXrkaRRR8w...$&&~uk׮ѣ ;;ۨ{c͚5 4i &PYYI߾}uw9~87oޤK.xyyR2ʢ]v >W^yE/m/\]FϞ=yull26mڄ3g4jkפI Ւմzy^^? TE',\ӧ߾};PHӫW//^/[l7ży޽;PuDobb"%%%۷ڵkpI߿kٳJ;֭[ )`^{5vIxx5Fj9gԩf 0IKKʕ+J e6d>Kǖ-[t7釋 QQQuԩS,kRӢr|||j7Fakkjo}jCquuN =taaa&7B JKKgΝ\r.]O/cggSK~~>m۶駟f̙jԕ1si̙3wwwVZSGe$ˌmkGbHt&`ޭbP5W> .++cƍ&%%E6 jB"##sG6؇>|A^~e@v+G)M?S$>I_+ڧ͜9%KKnn.1SL! vz˗/3k,; pu1ujU dڔ… zSGGGK/X_wI_ߴ)eJ!DW_}EJJx3AAAR4FPRZZZc`CC !jb2`۷oebbbXnU{ڂ pss̙3DEE|}}u>AP>5ѣGceeő#G 3i˙ĉ| 8cǎh"Ο?g}+bRWߟ~.]D1ƒJ^Xb[($"JTgjdUuSkÃݻw_raV\ڵkyWk}{=;Fn_> Ǐ7Nmj[kDD髡GS4 }fKfkkŋ1c&M`ӦM,_<-soѣ,ZHM_Q="G,^]@bb"vRˌ4OSՋ: kj[@BX|` ݶfmm͝;wfέbPY6d~a"""g׮]bmݻs"""jLP,Gx] ׭[7~'>̣>>|X3gΜa:IM^݂tQvի Ann.oڟLӺuZuti:c=+5jҹsg.^իWo+V/B<&<`ժUTVVsϩW۪fΜ7-//7i,{-| cڵ+`|2ٳg ٣sXl&[`WakkK||<>>>w}nwww5H 쌵5j'cskkkoϏH틍 666’%Kjm{ܹx{{ckk > ֺuꃱ1;vHRRǏ kkk8q":[9&#G}s&fggcgg3<B!D5i 6J ECW33Huuн:'&s !DM,` ݶ6tP w}GHHC]v|'2l0{͵쭷7ߤO>;OaHKKcҥDEEq}|r֭׿Ȗ-[(,,?fŊl2GGG"##uʊҥN=gfٵ^ooorCojz#f\Wfj;v$**`}eQP{C}0t?:ub޼yp51eL}ck{2TޡCHHH%ϟСC`%BعAc0G(..fƍ;"bbb}߆ږ9&_, &**?~BBBؽ{mMmk͛-g ? ,ˈ#x뭷tBmزe z PQ5߿?!!!:e}9N6'OשK/lښ 0uTÇ0`Æ #++8Ç퍝gΜw!DCW_.QLVB< ٹs'gϞKUQjEFF˖-cٲe]޷e$hݺ5qݺu'P*>SvťKС bڴi<j9sGqE-NYtN:;VCܹs)//';;;wлwo8u[ΤŲ PYYɮ]Rm6;wLRRqqq߿7oSO=Uc~a̪U9r$˖-#;;_|Ql2ΨQذa7 :EB4-/fƌL4 M6|r{ƍٸq!;7PW|'޽+Wйsgz)^zz0vNW<͐YfѪU+o΍7h4,ZHMc}j[@BXUHG-?ǪUHHH`ƍ:[|}} #44Ԥ)r)))[))))bGEEiiilݺSNq-vСC \{=h4L8=,9 \Ͽh Mb9°y}Y& 4Mw GGG̙c,ܛm۶ۗ>www~W6oln5Zx%,س#//O_]卩R籡MTwڵZW٪[LT !Bh05թnu)// OiWbbbؾ};666.]\xvɕ+Wҥ O>$/2vvvj ̤6mƘ1ctPiom`l3g9wdddLϞ=|uw6m aٳGͫUΪULz]~V\INN׮]gϞ⋌5JsWC?^N-wt֍~Ç裏̙֫3gؼymhΝ;sE^JΝuzZG!B,LTTVVr.] >v}]6o͛7)))a˖-L2εkט:u*9 \xTBCC)++S駟rYn߾MYYG&%%Ť5]Ell,1aΝ;7|SgϞ= >(y~:*}PLy] 櫯/YgT[CK{J)}7S < P^^Α#G֫;b*ǹsW\?D0m4AuPP~jS,uB!bf}[bb"'>>"n|3p@T7֨ꔭ!C0rH233楗^Wٿ?p֮]Yf 'OU\\\(,,$99Y+ؿ?{a[4ի999Ҿ}{zbO]v̚5KT=z4Æ @J)B!2!jU}k[ꧺiF=խ:SݱVOuزeKlmm#Ο?OOOڴi?LDDt Pvܩm߾=Po?yyyjcJ uk`N~`߾}@ÇӡCIkrZ{wve޽̝;ݻӾ}{"""_W6t 1ƾrje4e2-p}ѺukY=;;; kkk"99Y'*lΜ9bmmͭ[9r$۷';;[٩nB!&9˄05f5޽{@6mj/C`JӟĘ1c)))/ w_SPP̙3quuc(xK.ŋܼy{F&^N-w̛7ٳgӯ_?ڵkGVpvvϏu9 ,L9}4!!! an V\\l޼ko;vfJ GGG߿?&LPsNΞ=˔)Stv],88($MX )_d@F5EֺWS^ɓ'}vyuj~U6, ~&¦טI[jE@@ֆ!hS!B4Y& j;-)OuˠA?~>LhӦ nnn3___PVVFBB۷o_K.<쳄bccӏ}*--%--!Cֹh41i$:v8$B!,B˄BqWc͚5۷os9PcݺuiӦqQnQQGV5o۶2<==dff2v߻B!{6L!B222XbgϞ=̟?u֙\oڵ=zzT[8p `ӦMn}Ք[m۶у@{Fȑ#۷/}ۛx@Naa!8qǏm66JOO'779Ax5 ^ޔI۷oϵkHIIɓxyym߾(\\\ի/ח-[mv z\Ϟ=u!BC˄˽dee=ax7kʕ+䐓?Ltt^O?o`$..uQYYɄ pwwg3gdrss?fʔ)Ю];={ڟb9ɔ2B!h9dwZW )2335j}YSt[***t+**oڵk>nܸEXp!7nܰth4vUٺu+ 07orJF_|arZۻvZ[YYk)uB!D!eB@ԸunȜ9s8vXAII G)ϧ{IQIII\t^xA-8q".]"))ɂ=doo Y`JJJ537o[s\zU9L#B!ZY,Œ._Ldd$O>$C%((LleeeXѣYr%nRh) u~CMר^<.,,$<<zhVbXDG5R}{9<<vpp???ټy3Æ #++O4즅B!]G"˄0Ν; ߿x%ڵk9z(=|3p@8M Nh4 2#G5/RGdddÔ)Sصk^={{{ˉ'r Pe?=k֬ɓ㕐 $''u?3Ο?OnXz:?u[#_~zQʪG RY"GYu~~~DFFҷo_lll͍,Ybr=;;; kkk"99Y'*lΜ9bmmF9ۓlxgqDB!%Hdicc=z}1zhGeee ׀X`;wTv  hA3f\ה=qP(X]Ϟ=u!✏OW֧=gfٵ[Cquu:t05V!BX&(ky[w85M nWl+p}YD~moowG%))IgL)7DR9`re.\)[[Eu2tQRBܛꫯHIIa޼y@U$N!B2b,@նURq$Tg(}]YhDGG&6ԾүIi'6t @۶m|ibam -)U}Zf*d(?RV} 5 i,[[[/^̌34i6mbk½B!A˄0nݺO?qahÇuvv̙3l޼gggo߾L4dMHHHuCBBؽ{7z9oڵkǬY燳37oڶ~zƎ˟gj*##e˖l2HR._ؐ`vٳgՓ6ݻw) bǎ8q_~Y-9rB)c;l0(((ЋQִB!B|Y& j%>>>Zn;o&PMQaggGbb"8;;cmm=^^^$''D3͙3WWWk/mРA?;wfߟN:acc'-PԻwonǎIJJb899amm'N$99Yg < z5elGIֻNvv6vvvjĠB!B{Ue]ٰhHII! cs***bѸi&__4̪UHHH`ƍU'uFhh{(J``zC&ϻB!AlLNYY;;;Μ9û #} >Nnn.O!B2!x"//O﹃Ǻu먬d„ 3p@ T%PڮX<#Ba S!-FVV7nh"qvv???.\ȍ7B|}}4h!BXD %DKҒ";F0$%%q%^xlĉ|$%%n shtYK_Z B!EbB@@!T;TTTOff&EEEi777ƌNݲ2ؾ};+]tg%44?(--%--!Cֹh41i$:vw-B!v S!ǧ~ٳg}6eee9r~ޭ[6mW… ܾ}"9s&m6{ӓ2233~iU*ʊ۷oGGG"##r /:t`JJJƍL<:ȤI(**?׮]c}EuJQ ֵ*1D JԈK԰bd7j(2TTh쉱E F1H(" :yy̹r{iҤ &&&@zzzYy뭷Vua„ <~X>jCNr{ܹhWN׮]Yn]B!x2!BTV\ݻEuVeM8{,m۶e4mڔ+W`bccٵk "..NrHZj-221yd?hҤ W/3sqƍs~6mĉ:uZj3==^zi}=p.i%W^ܹsG9ڵkyyKyAtt4<|ӧ{B񲑙eB'''%@%96777,X78Z]L2իWsE}.^ի2e eCianL>ӧNB#˃9 ><<{A\\vR:t `ooM4aݻqΟ?kvvvZ}D˙3gx ~)'NȈsΑƼyؽ{{a߾}<}H|2K,w%KG.]8}4OtޝJUfqd-Z/F@@jZyI߿OիBQHLTFF7n ""ÇPݹsHT*z[JEddӧ d̙̘1+W_a !:u*&&&DGGl2 JY:vUܴyf%5޽ &MGT>V]v2uT gwԯ-Z`ff̙3۶zj~mqqqQFhPyf:t@*Uhݺ2CmӦMegIZr%͛7̌iӦ XXXtRIIIa„ j~B!^6,ŕz99∌dӦM8;;G}ē'O(S(;;ׯ_1ԓ'Oݙ3gswBLr+зo_ܹsi߾=^~c_a;>z55.E&(V^;vTΝ0mӦuj=o߾Zϻw1.\I&J/5k@bbbYڶm|meePhŋcff_ʂ HKK+8!e$2!y,K011e˖,[ {{{Cʚ3>uBBtҥc(RRR>|IJJN !ċ777ٸqR|ҥJkkk gYd^\\Qvmfffzۍt|*%~5I/,{qd,PDù~:*nݺ)K8򗿰v"C!xYHL2_ݟ/2qDwN>}Xpaf9UZ___;ZZZ+W͍]2`V^MFFtSN=ԩ׮]S40MAl(:w\,Y;ҥKs~)}Ņ9s®1[lSNԫWOioРNNNlٲTc!*qrrbѼys큜}z s3ܹ×_~ǏWj>knBN}&)zMGN<\o #44._*XjĉGq=)/ґdϏXy;vК1Q:t\j95Əφ qܼyJԩSΦq899qUg \~Ν;ӨQ#SN*1'N```7Y#ƌ͛uYYY$''رca=]v222ؿR`8\ƁHKKE<...qn95j-GtU]Ύ|||ҥ |ט*5ewBwww @nHJJ҉A믗`ܸqĐǕ䬧gǼxyyq)ř3gb``@޽,Kt_MbGcM IDAT``5kHMM}oО&BT,Add$G~(94D߿mڴgҶm[ˆ!<<:$7x` g74yxxh[ZZҲeKΟ?}6.\YfJ,mܸK.ѰaCT*'O$88.^믹~:5bÆ =rgϦM6TZ뜷py '9?>B6m"**(nɓuvd޽>ŋ"}o!&&9EѽJׯ7пVJÆ 9s&4cjԨATTSN֖*U`eeŠA*_Z1֗_~I&MR<#88LMM155m۶a?ΚweΝeseW!Q.Bhڴ򵥥%Px1޼n߾ /9 ݻ7QQQ5 @ }sk:Ѵi!^ML8ŋxb&MT?S8q={b 6mJ׮]Ybe6VHH(˟ k``GvFl߾޽{SfMeʔ)szjGGGe˔jGGGu?:33SvwwEӧ?=Վ?P5Qys߄x;P)~xyy癙}GTVTxlP9sFVէOV^{M_sj̙1bZV͛ZxPO2&''R~O%55իWrbBQ8I Q σfyټyN2JaiiIϞ=Y~=-ZꟻF{7oS UV^:!!! :zaddDzd ÃZjall[oE@@yssq?~ zY!(gϞq=޽˥Ktg>s-Z?L0???u5vX6m<,4n333 BDDn>#""͙2e iiiE䎯Vfz1c2ySSSΦSN2sL&O h[0agΜa߾}ܿH,--y7J={Sͱ ((Zͅ /<<͛7ӡCTB֭Y~=6mRZXXtRIIIa„ j~bBQ8ue000 44///iڵsN6l9h ;vlG(SXXL_MJJb N8Azz,~;GIDD?|߱c֮ЖZ;\bkk7>?f׮]l޼`ddDN7n֩7oޤFrOmee600Pw]j*uJJJpttT}}}߾}j@䤴i޿kPZ&%%)sotu[mee644TYfj@[(z-Z˗ Oll>Rj33RBC !*GGG&NŋYx1&M¨W\Yb\-={$::._Ǚ8q"u-iժzҢE HHH(8['==SN)KLݻ|mccØ1c ݻtڕ:u*~0uT^JZZ'O͛+߻ N"++dfΜ{V6m֬YCjj*۷}@N-BQ8Y)tÓ3tЊArн{ㅥU닧'[.k .A400>`ҤIT*eg8p 6mbȑ9RSNi՘5kd%%;DEEakk޼yEΝ;Q9K,Ѻ3qD&N7E'p2L!Ķmƶm*: !Ŷm۸zjEB/Q(DYFFXYYM`6j(j֬Ihh(kʕ 6jժajjJΝٺu+W^-N (u 4ɓ 65kbll#۶mӪZ~5j **SbkkK*UbРADGGӱcG888`jj)m۶ߟ 6B2!0EeUb꯲%cccn߾]ժUZ*V˯f͚lٲEkgliDFFТE e `ggo %WV--[Ʋe ;zhF]fBLeB!BJ!55Ǐ駟0cƌ H!HeB7;w0%$K B^~١C|}}+.!/-I  2CB '::gggA_ܹC^ꫯRE>!(>Cr> !xu>}@n݊ZfذaӡCMQ ׮]BT,),De_qh!>c<<|͛ aĉB!x$Y& 2Dj ̔dY9$ҢYt)~-UTaС?s1VJ=5kժUSΑFpp0?N:ocرČ3gڵܾ}+Vp /^?sq2xBMRR7o֖7vZ-Z=;vAlذ ;i&Ξ=K۶m={6M6ʕ+,XXvŠAjҤ *J ?iժ̙3c3^dd$Zҹ^M[dd$˄B!^!wBT?oo") ѣܹsHT*z[JEdd$w)xJJ̙31c+W$>>999i= ky+5>}ٳĄ#FC`122I&̟?{㣵\~ vQjU3gαNB!x52!^`%Ψ{.˗/g޽|׼666Đ*;;ׯϭ[=(ܳ\͕6m|ի=ŋu4*+WбcGvRw]54m>B! 3˄(}3-^$VVV̘1ÇILLjOHH 55.]<8J"RRR Ȅ(qqqZ!g>yV |ѣG:mgt.R9^5h!B!*/Y&D&((rMVJӦM8pN-ҖwY6WVV.sm<߲e K.%!!|MN3kK.DDDI(:w̮]tLMM%((ÇsԩC޽7nZ}ܹêU8z(O۷K.jevYTTj:zevk߾J#G0{lڴi]缲%_R,XXXR###,--ٳ'ׯ/-333pssf͚TR{{{>S@YqsuuܜǏyq,,,YmB! 5˄(#SNO>!::h֬YѣTW]`C&L+WV& %;w&$$( ULׯh8?wqЮ];}s(%ъniiә>}zƂMLΝvMԩSU\~ 9S!BT~2Lg}o>ΝKIOOg׏;v(ǖdWXZZ… .7~FFFV|]Np۷Ąh233Qfd&޼J\'DգGؾ};>$;;~O>П@/QFѠAX[[S؅B!Ef Q,--qss͍g߳a.]N-[2b֯_ς pttTfANGVceb+1>^kf||<}iԨ.]ԩSZYh-zVZ7633cL2#Fk.VX1!BQy2!Yiii4o{{{@{Vqvil,/,̘1chذ!#((HZjsNpfeHH@z KHH ++eWŴ~mS⧟~>9'D5k,ONV055kkk UO#'Nd,^I&{vB!dfedԨQ,X@﬇|}}9r䈲K[nywiUwkkkv]` fff̛7???my׀UDD˗/gZ3JK}s}FÇzӦFƍ|||9WWWDWqmn8z(III:ejllLPPԪU cccz-t+; !B!(-ua  Uf}.^ k׮%88;wj7h ;vlG(#,, oooe_MJ]! Nf !^YB!Bf%;W7B!/ IDATI !^iwd_| 4 99EQ^=fϞ])ͱ -- sY& h~۷oҠA~W^]ygׯ 8uo߾2(˜J$fllL:upvv -?ߊNtt4β+"dyڵ}̞=ɓ'sa&NX8y\t={၇VC`I&̟?Aw^eթS' e̘1$&&IΝK}=9NB!(>Y& ?ZӺukeH'NPUO?iU7`n|/oE8}4̜93frJ+4&~: ˭cǎܸq:u*&&&DGGl2 J"==]իWpssӚ I]xcjfs{5i$5kFbb"M4zJsݻw$Ӵi!Bd/Gj=oӦ PpL|oO}pBMofܹݛ]Z*;vL'\gQ7[n1o<|M>|8{'Jx{{o0h ?W^ɉ*clٲN:Q^=_ prrb˖-ފʯgϞ@NHHH`…%>qrrbѼys큜[^z9uΝ;dzgϸs_~%NNNZ?YU%0:tJ͛7ף/Ƣsx5m] Q!e&(#lܸQyIbb"<~XYfݼyJERRzԨQ ru]FF?u ݻsaN8 /_&-- jԨ,[3f .]RHNN&,,XT*Z1,]TKn˖-#446m0nܸ2 "==;vM@@?fر1Νc7?:t… {y޽˨Q}ŋ̝;gϞ1`|-{ҽ{wuJᆪo߾JMG8p4#7bcc9x .^oԨQ>|W2zh7nVs/XEh"}}}9r h355eڴiZjq]ݱ֙MZX=..Tϟ9~)UTaxzz2oBϟ׳gR_}y8&I9sLs){RF <<<ظq#QQQʙ3gV2 @N2/;;;>B@֬Y5kV}K憛[絴dL>~}՚YY|g|g:(ד_E9Zjxyyiذ!ki||<~~~B!BOf QFN ,[aÆRHOOꧩOԜrrrR-/^,p34ݻk<׼O?i9 '[ǎqDJ^aaa@N-{x M6U$rģwQQiE֪Uоy8澕fPY'>>>(Ex]vUwлLӦ#x5 bmmLU!B$˄(@ j۷/cܹoߞtV^M~رcrZ.p̼Ejٲ%;wle\Aɲ,.\ewy-Ye^^^VYvmcbg-ȩS{XY8$%%)Kr0Ĩ>vܼ͛y]v1|LMM+:.,--ϵEUСC$$$;h}e9m۶InݺqQtf$%%=F!"?s!DE2dH!2!ݩR \t YF3j(*u?R8~xef3Xjddd(7&gggTBVV,^:!!!|W9r;wPvm_-j׮.Y133#((@;ƣGhҤ >>>̝;7icmmM׮]1b/Q,yj׮MHH͛7K=of͚Ž{J}.}222zѧO&MkV&cB_d'eiΜ9:uJy~ڇ~ѣGj>c:\zW7߰pB^2uVj5Æ ޞ:h,!";;CLL ۶m~ܼC+dǾ}矉ȷyotqƕ3߿O||}G_ǯIE(eBOhh_!y<Њ5Rd3K.ѣGZ4I7N:)kfڵӵkWz{Ν;ubHKKcʕѵkW ի {''';Pxzz$r_~jժNMMe˖-tԉz)}4h[l!555ߘB<W\aܸq4nٳz+..!CPn]iڴ):U.]JOOgٲeуڵkSJԩC9r]pӬY3LLLY&|'ܿ_1Žow]/?E?{}*=+ پ}k2eB!(УG3f .]Rڒ #66JU(lܸQyIbb"ޝxH!b&iגnډЈ"֪[*- QDhBS""ZJREId7ϝdlzEs䙙3RRRԍW2228qޛ݄eʕXXPbW^y~|GziE{߾}Ү];cڵĉ߿6!#<<}i_vZ 6o]|O?Nj UǩShܸ^zrr2zqCܹÞ={ػw/W=/Э[7/s2228y$'O$ H}YxQՕU{n>swJ*tdq3g ‚ɓ'3vXBCC;]oIF- 4*/>>> x{{=qbŊ {zf͚ _@W^:2{l2@_ ]xQUWREXP4sMvEQUV)Yd(_~9Y.s,III1(5'E EV xw巺>|ό38rw%++#qs IDATG0}t>;ͩSXr%3gdŊDGGu(nܸ@_yn޼ivӧOrDFF3x`IOOw5x`... 0< ~zXԺ޽ @ iӴyB-mlS=>vXo3tPի-;O?EQ vEQ_9{^+WP-[`g^xx#,((H^BQϸio=[(~]YaURxy-~WLDXX rlll;v,]vgDFFf~G*Udg(uǎx)--yၝ̝;[āB-߸9a={M6>|;wriVZE`` SLQx):_0dF͛7駟?~1ScUԺAv5Ӧ ,iSjoVA]Ǐʕ+4lؐoKKK/Yr U_rrrHJJ"..͛7Ӯ];?n E;{,'NϹ˝3goDDD&кuF~۷ޮ1nNNNKLչ>ǎQF4lQ)JIIֶT-~W2Y&c,::={`kk^ڵkӧOڴiÐ!Cسge~znݺb:t(~-ׯ7͜xs՝MV~oLckknnnq6l؀:YfggիWٵkYk.6nHy饗3uשSD߿O:uݿ_#7'7|CHHիWgΝԪU K,,,Y&ڵ]v899h"fϞtpp0s۬'/GF|'jLׯ@@@ 4`ԯ_(iӇ%K??@VVV~]Үtpp(zK܆)rrrXf mۖN:[o ib h۶-cժUzMbsNFi2(uڵ>|8}A9>?Ctڕs|Vrr2˖-_M6___Us3nb*7YV\k;fqa^}4Q^2!̰rJ6nܨə3g8s )))j &N. G;ʕ+ޖui:ug{:tu}ڵ tCtt4&~mo$[18qi&LHOOg |Gjj*ڵ3hWv8qWW!רQ8x ׮]c̘1z [/fztk=Ç~AUJkժݻwqwwN{TX`6nܨw /;rG۷',,X!@&B rI~gz]2d|G۠A}lqY &ݝ2''gGGGz-z-Q ~=`֡Clmmٻw/o>UFΝ<*';;uЯ_Qha;vb """8r*88XH\\͚5c?~Zh' DEE_@8=ܺuѣGY|9coo͛7 ̳6n˗qppߟ'>>sرcǎS?L~Uq>>l۶MvӢݫW/VJxxAñGfBk& PBN3g$&&Fe???cTP]%~M#MzZ;@իG  6 ~mVbEzABB7o֭[tڕʕ+ykWjΘܹs9{, 6o߾EQǞB}=W<=Jp'JQod^Zqqqѻ_a˞l|Q^F tM9~DR%00P=ްaCP&M$&&*YYYJll2b\@zzٳ@iҤ~JffrW^ 4Hf_~~~ ԯ__իW{W^][*ÇL͛JhhҳgOP*U3Ǔ}B)؋vGGk߾}Jv+~~~JZZ^ytŠ>]}U4MK.)Fqss3(/%%E/o^kնm[E(Fk۶|999fc֭F^u=|Р?$e+Mjjҷo_O?U>S_~l߾]ͧ o~A=_y8g>qm~]+&.-{s/եVAQ{6kӌ/ kkk,X@hh( $$$ʂ RJY7O!>}͘1cxT5jԠG߿I&tR3f aaaݛ5kbeeEƍ9tP^*WLz2d{믿;>n86l@-\2tޝ|G̛7xJ֖>6m5+VaÆ:u '''z ;n٩k^z% t9_^{jժQbE59c+3Ю];,X@||< 0gnՏS{lmmqss͍88 UqUvڕo1cȞ={X~=;vaÆy.\&0vR ?Bޞ+W'::?):uꐘS r !F0yd.] )S  !x<8;;)fmV;v,/} #G2rHFa4U5ǧft~BcNc޽F3fE}̭!$f߿?...l۶T5jnJۛsΑ͝;w/qqqaĉj^ʨk׮i͛7_'55cDzyfOHLL$00qƑkF- ںpBbccԩS]^;7WWW|||!++-Z[AQ<իehtl !ӓe˖l2ZB!F2!0j(|||Xx1/;J`>|J*xyyתUwvM=|~ ___]Kt.ͭvڌ=Z/iӦ <8ߺs\vMR :۷',,XUyuB!B!DnL33|7nVVV4hЀѣGlll;;;,--ՕP3gKKK222t+++/^/;vf͚XXXPV-:uꄯ/K,1/:tbŊԭ[#Gf[WY~=o&uҒu2tP-qիUV%<<ܠplllѣGB!B!reBIg+?̘13f䙯gϞN:ѩSBF|X̶5j0k,f͚gyK/8VV OOOqܸqh&L@ժU,C!B!(,B<Fݻ R'낂3Uo֭zqB!d`mm͂ 6mcKhh(˗//B<{nB!O,B<14 'OfҥL2 B_qla.B!D&˄(L {yzzYou(Q:t(f!2!ۺu+ *QnʀʺB$f$i,B!ʹ Y)ʥ *uyB'L !B!(V3S$2!߰a/!`% [!#13%$$˔2!X>BwuK,ĉdffԩSM/߼y@"##ILLRJD !=)(iLV3B;w.'OT}vw%,,`W .0n8RRRԴ Ο?ٵk~~~ԭ[8u+W$88EQ>>ڲaƍGΝ4i!!!dddu;v &M6MG!e*fY֝;3--[)Dɒ2!)WC_RJ4oޜ9spAۡ]DHH7DEEQ?#>>>8;;ciiIY`{)P}={gӦML:bcc䯿*:ϟ?zBU!2֭[_ [&D0B7nмysW^y7o]$22իW3f<==Rڵk-'>>P6i҄&M0zh222`ݺu,Y>X{.јd4m!?dժU;vP^=FI>}6f-[%&&ʕ+ӽ{wO~\Xbajn:fΜ3k֬1I-q8xD&˄BPAP'''ٳ'mڴܹӧOj*2eKQǎ㣏>*~KN!2!Bx+&&,bbbXhhՖ ۶m#55F Ke.]GqΝ;Gvv6w/Ņ'yQ£*%K'##p{=z_|D.m6B<- 3=z{GGGV7QQQ|wj>sbvΚ5 GGG*WKJJR4Vg^U)6rB!4j(<ȵkoɵ [/fzZl>|J*xyyתUwvK.1M6ӦNپ}{ˆ @ll,PF! sbv6h@-:󢝜*)6L!FoЪ^:ׯ7ߤnݺXZZRn]J@@a̟?ƍcee 4`|j>KKKlmmquu% @̙3qppҒ 5}ڴi\WWW`aaL4M6QVbW^TZp~cccC=;!x徥=Pxy]m={w^ϟOIOOgժUdL*ӍW{ Jp,B!DjԨY5kVyM}1frI]̘13f䙯gϞ6mЦM|*:U'~~~ܸqJh&L`Z!D{g~:4md>{{{\Btt4[VӋS͍88 5+@~ PuNc;6ԩSD߿ooSpHV !BQFsagggpkBѾ}{.]Jbb"|gdbv4VXhWEqeB&˄B!J5 , 44 eM#x[ԩSK `ܸqjQFȍ73f mڴa̘1ܼy옝F`tԉm Nӯ_jYXo兇5jʊv1o<-q8eB!%OOϲnBgooO 0: X,LSuX[[3{lfϞo[p !+˄B!B)&L!B!cťD-[>miӦ1bBCCY|L !B!"_q8)-,B!ʹaÆ1lذnBQ`%q8@&˄BrL%U֭˺ B!(g$B}# IDAT!B!OV !؛oYMD@B!(V2Y&Bs2 ʫ *uyB'L !B!(V3S$eB!B!B?YY&Bbu-,Y‰'ӓSL/ ϟ_Twqq **9SrAWHHiFb !;r]BEQL,B!D;w.'OT}vw%,,챙2G^}8u+W$88EQ۷Tڵklj'ؿ?,~ !DyUؖiii>}ӧrJ^}Rhahڴ)M4~ѣtdǏ@KmI P S!yڸq#/_"""ޞxԼ?H"##Yz5cƌӓ*U]rҒl233Tt5_n 4Pokk }/)[֭c̙8;;f͚468K PQ2YVou3swwge݌}ANgϞiӆÇsNN>ͪU dʔ)"Y΃<^F ޽˭[ppp08MwrB emiӌO!T)));?CM;wɣm|roF/'Ɍ3F ~ %%%߲ Bhh(G6xޢQ貵|}}INNV' 37s7TL=%VXQMBr˫Pr ѴnZMήH憛qqq8p 6뫾Qիڵˬׯݻw=zq 6|lPN>u;P;]!dAAA'ФIΜ9ܹsu^^ݸs̡A\z5.vh6B?~|Ă xgߟC86mƍ |'8;;sϟo?ͯߓ'Or54iBӦM ]VWWtqq!33={xbMNMiҤ qqq̛7O:yBsAcdM&˞})&!DEU^1M6%..EбcG߿?7n`ӇFqu@EW.]ۛYfѨQ#ݻG`` 6mŅ5kVW)µkpttGDEEvZ,--yר]6w|7km^|EzիW 9sx饗G6mZe|zc ]UfNÇ׻=jժ|;wPNuƸq7pwwbŊH^x:vȨQ|6667p!nݺEjhٲ%'NԻ}r̙|W$&&< _c~.]Djj*6664k :uXW^|3rH6cccC=Bsbfh,>cQBRZ5vJÆ qww`LQMk1!w_*Vc{aoeeE~ d޽ <{o7e*,7TL=$BiҡF̚5YfSX_eƌ̘1#|={4z% bРA֕W{FU'~~~ܸqCݨƍDGG3a B${tOW_UO>mq!uQv>-)))¬`^˜>>|G˜? {naHV/\@˖-_~έ=s+TL !B|8z;oK105p@N8g}`4e*h|OcwT* &]!P 8h4LSN:ep\+4o_!wxzzu3ծ]%$$35e^ cmmٳ={v&fj.eiiɾ}WвÂ4v~At%(YY&X999$%%ŋ:t(iiieݬBscƌas%$11~coOq1c?< ;;g}LTҼ>m !lu mFRR999JW^y[(TF#((HMB,O+LwQQQ|ǜ>}իWꛔtm<<<~:>,cƌՕKKK_޽{Yv-flڴ KK2iﯿ ڵkҥ j|qOysaS/o+Bӧ۶m3VZzq( *#eUbEy^{5jժ';vxb&f͚iݺ5k֬1߾~L2=z0x`?NPP#G,feeЭ[7*TPfvB!0k,ٻw/;<쳴mۖcRnݲnx$#e7Xjaaaܾ}5kҶm[LBÆ )+*3gΰvZ"##INNΎ>}0uTo޼9n28Cؿ?/^$99իӢE ƏO֭ ιr | ǎ#!!*UH=z@_~0j׮ͪU L̬Y;w.e.]bܹs:uо}{LBz ӍƤ\2Zbʔ)xq5_*>>+V?3ӧO[nfǪ#G0i$._L۶m믁=rY\ҏG~-Oրysqqq]//|ۛd…@֬YٳgiԨ .䥗^‚8>N:ŪU>'0dƏYYY>}-7, wytw̙3WW\aҥOf߾}0(ߧsΌ;Mٳv+W%1IIIL>]m{g/^dѢEER;?W\a޽۫}z< (s 0sgZƞGOnSNi@ *(JA!0oΝ;L<ooo\2 >>>=d,ԩS|7No{͛7믿?OŊiժ_~%[4hӨQ#\\\:u*''NdȐ!zܹe˖hR VVVhтe˖p9sbccG NNNTX*UкukV\ O?Tqy& jƍҦMV^MFT5bմiӆi&ꫬ^F5[V'N}:tԉ{OcnE!66/ҨQ#5ȑ#&ynʕ+3#Fꫯbgg@F hθi4'>ѣG0aL0H>l2ޗ_~@5s8pd,--4iR^ꫯ<((טc]]kz=3>M6;v0\pӧOsi5Y[!&O̬Y8uNMk׎nݺѵkW*U7glllHJJ"%%ի|ML;999i'rrrjօ l[I~4σz||SRc+kMQg=gL<$y=BdPt|޽jժn:jԨa'55(ڊ*- lmmiٲ%-[իWgvZ5ݻYd ׯ_/Pz\R 𝐐wttdƍ yę3gt-Z(z8J&lllHKK3zrھjې[^`}xkJIVA5E=A%F(OvZjř3g/d΀֭TV$׶|PE`ٱ}xc(ܵ񐞞N.]Mq\N8}`ժUΝ;ȵkטN!JJIl#eBٳg9y$;w.y>dڴiE#.. .h222W.֭[srr ၇dܸqzr[߾}'((1c}myޛGGGbccSNDGGJ3QQQ9s;1y999@vY) ǣ4ZcLXlQQQl???5kƅ 0a?;5kawȑ#9pF"))m۶QV-/`tPkhݺ5k֬1Y_|y.\… ɲKre6lHPP-Z 22h E9?]t!##M61ydVX!e7`<==˺Brj%Q&˄sΜ={:ڽ{7;w_M_hΝW^L2%:ڴiC\\!!!e.\w888,ܔЏ5`}HOOW'f:uč76 㱶͛ӡC=ʿo++믱{ީS'bccYv-:tЛ믿}F-I={$** ???:t7ɧ( |smmmw111 h}#(J&x\鿹c\֘{=B<>pU^KKK*VܰaCŮ]兯/:t 22iӦ9[Ƿ~?OuhXB}… {z\}ڵf!:ubռzep}|}}9{, `ҤIL4ɬ1q3h ]&(1%6Yf\>|8իW_eќ>}7.̜9S=租~bӦM4nܘKzذ! IDATaXYYm6.]۷IKK#""wyx3~:_}/`ԨQq{{{ч۷oŋ9s:ynׯSNѣͅ tW3n .VZѻwo6m&== ._ӿoL78l0UFdd$&M">>L4iǏn%iȐ!<쳄3uT">>ɓ''9sÇ\v hV{yb۷l233M8?*L*ܿK!ŋ/SB*T~}>>>_"22M RGYcâ:ڇA`-ذD XP#FA%$.y,nh"#(h0 "H QD sEvܟ3ά[fgmcchol0uYNj/PB۷ԩSy9^B?dfP;|3'NеkW2_~%m///.]D:u ^[ɲRJ||Z4hȑ#^CYՋ.]δiOرcٱc7oٳQFq^5xwԺml3j(n޼ٳ> k/WK.eر8phoeeҥK{ݼTH`Ϟ=ٳG 2e>/ܺu^zi7w\Mft<< ɓ';vz,뮬W?Le7sS] !^۹i$S갲ʶeg)wVݛ?[MHHӦMc̛7g"!ċ?^>LPP.\ɓ'ԨQVZѥKɅzfVVV.]&Magׁ3//;5Q&MٳKWY&hт;vУGlmmhѢ4k֌uѯ_?ѣ7n>XbXZZRJ>sʊw};f͛u޽Yx1XYYammMӦMYz5&LPs_5jUV`(P+2l0vء3al)ؽ{7s͍ebaaFޣO>l߾]gLѺukoLٲe)Pe˖O>am6m6lȎ;OتUOǎvSԩS͛7ӦM/%gۤXLy,Z777 .L(W\a cmS֘RjT:;uС餤h:u*ΝQF\p/"uܼyt֑ͬ)%2;ͬdɒ <ǏΔ)Sx+"9 !!q1i$%99gҥK9~ }{.;}:*T`piȟUJ*\~+Vп4 [lo߾/^B333ԄYoJ ͖0a-[QFѴiS/?C`` zlg3'%%q /_NXXeʔ!00mUY<}=zЮ];5=ҥK9x 7o6O}_zD2!DUUT͛z/B!DfԨQSNмys$%%#<<<(Z(ׯҒuQhQ 8)SRQq 6l%,^… 7ĉiРo>ʊƍ$h=bŊhԁW-.{َ?Npp0666]N:accCcر9TVXᾕ4 5j`ҥ888p}oߞa\fݻO>ܻw5kKL2X&u?& 7od…@ BO9qǏG`nn 1W~} 6 ///uRJxyyqF w}Gʕ ))I+baaF [pFE2eh4S}lĈx{{D)X kӓu֙xBAbbb9s&ZŅo>l xyyѹsg\\\ԩ+V 99Y-P] @ٲeҫW/FE7N&Mر#K,ɓ'ZRRRtZbʕ@FĩSҬY3ZlɬY9?))9sЬY3Zj̙3щظ͸5kF֭?>O>5szMC}}111_Z8{7RCK:/V+VЙ}!C2dHu 񶊏gذaܹsG=v%NS699#GLJϳ|r Qvmڴ2EaСZǞu7"3˄VZ޽kmP\9:v͛1bD~)5ȅ թSPquu"q!44UVa"##]6Re2!D(WӧOg޽\p˗/w}gҲ!o:u/_`{=8zh>E()eYW]+_MFݺuɉӧ\w̛7 (@ʕ\YeU@ c1X^=uIHfTV +++5OaRRSNbŊh4 z+ԭ[W-y0Ĕ&OL h4꬟Wߔ6~5M ˙_N2/ԩSUַs^q&MD (\0ӦM#""_UzĢ\# ҽ{w"""Քo*VS^A)22L!BJS6p-Zкdɒl߾ŋӢE .B^nݺC 3n߾ @Ν^իUlYܹCTT+W[&==xc2:%gBݻ:ש^w楐UTQn&MhV$f^jJ\W f<4wMS)K,B-q+ׯ[y&EJg~.1?9sFXX?C o߾,XP- @ѢEuSʼL2L!BlmmYjƍ_>Ӳe|Rr |fff:5WP5}Vʠʼn' p-[CdHvBFrey6Urr~vqYZZV?RvJQz̔rҖykfvx~S˜Xڵkݻ9s +VСCl٢r,7;9%3˄B!+N:jn_2qD`ٔ/_>#Bs5}S֖[n}vlmm룏>b׮]ѡC5'B/==wwwu٦7o̙3ZW9sF+={Vk ӧxcy׋qnyZM/'m|\~SNi%ח3/w믿z*9>X+FΝܹ3x.\`񄅅ѴiSwﮞ ̛7gϒٳg7o̝;WmӧO3o<><˘6)}}aHRRϟg\r{{{lJ|9i˼x۷2ԩSpΝS6/Wv}]x1$&&h"DK.]pvv_~!!!jժh|S*ˮ3S\47̲T5B!g(W"oԮ]+VPV-Vݻ/B7S~سg7o#۲9rgҿ ,Ȅ %K$66]bkkہ)GŵkDlْJkIؠA8toVwTTPAXniGGGzꕧq9e/g}eVX1.\5bJ|9i˼xΧ1Hu(/Be]^ :? e0ggg!VSK.ez!^?YeVP!VZ9vO>>;w]EDDp!\“'O(RiFzϞ==Fcʾ7oRR%ٳgPn]ڷo!B!AkgٲeDFF>|/99˗u%""\]]3f -Zr/^ߟot&NHJQF>D*ٓfB$9ʄ#e0sLIMMe̘1UέZ0 .Lnhܸ1K&..?N8cǎ51Dh׮eʔM6,[%KnfBW0BQ&',ze|HMMVZannܥK8v|W۫/^777իĉ9vڵ!#6֭[C:k.nJ޽1:!Or !۞lͯJ !myvm,&y7n$$$`ooOΝqss*͛9y$=dɒ4nܘ=zPpa28xb֭[˗Ņrz2 =|???N:Ebb"˗K.|Ze f=ܞ={6/bŊ̚5 ȘMeBCCdɒ4oޜnݺi}@8t;w(ˬxtԉ 6pD~'~74 Ջ%Jݘ2Ϯ]]6666jҥKSV-vEN(R.B![n} ',F{1SNvm/_NZZ-Z !!3fp\LL ;wܹs|:KfϞ͓'OHJJb3|pb|)3gQݸqC({֭#>>RJ3̙õk2'00+W0m4u9:ذa/^Թ2<ȹsXhdfĘ'$$Dׯs_9w'Nm۶>~!e\r@M!!dLm۶m<|*U0n8J,/ 00PL Ν;-[qQre]oֻ$Ύ1cPT) ɓ`YdYرG˗/l2bcc_/_Z}v]FjOPweժU;wÇӺuk.]::y޸q3gRF _βe˸wAAA8cNP?>}ʕ+PJ !ċ133{ܜbŊQzuwرc_\ڒQQQZsO?ɓsm o^ՁwE9|0W^%>>E@۶m6lݰ_Dv}񪷫Еy%B䥼H${ygϞZewԩS <[[[ , `ٲe1,,,^:~)'OԉcСbeeEǎR>|Z##G4ZYuQkbhh(}*Uܜw}Wt 88X- EA}GAڵ#F{cNW7nY)ǔ2B!r_ZZ=ɓL4>$frr27n̓zΣGگDƌCڵo8u/PF/jҺo%YcNWǏIS!xqYTy?~μy)Bӭ]ڵk_ݯ_7oߞGbiiI۷/NNN,YSNYx1;w|) eFϏ}wB7:,ex~r -ȩ2ϸzz@UvLOOWҬ-/5k'<',,L-UǠ_@3&iw\};*r_Bgii;Cn(U-[,;<;KfŊر.\&LѣTR͛7ӠAmllhӦ mڴaرtܙ3e,YOQ !yCa E IDAT)3Fҧlٲ\tIrL2y]%1P_6oӧ=̔ߦMԲJ_`7o$((@#իWnGFFd טsڿ(;rܧ˼kB.nݺéP[[[맾geffG)S+++T7n ovqf,]777J*Kݝ#Gޕ+W9r$UVEPD 6lȜ9s .3֭O>)RDɩP׸t +++ʕ+>})3p@lmmZj|w_xUVammuʲjذ:lٲe\~]fL2Ջ,vvӦoѪU+ *Dɒ%ܹ<BdLMfbbbHJJLJ={2n8\FXj/_&55˗/zj V^quu2^rE~)[X1hf$UfˋB[.?DGGOÆ ٵk,TuѤI~bbbxׯ_g…St%{I\\M6?'88XRSSyvUVرC~ ?r5y1Nb4h@'햚ʆ %aRSSn Sܹ'''|}}{.Ϟ=ݻ[ p<)k.X~=ѤpUƏς ƶf9rd0ԯ_!C2ǐ!Cx")))؍"sI8|0s>%JpeF̀سgݻwWu[[[ݻӧӧO޽{f EcooOtt4ӦMS뎎) _Shcoo˗2e {fh4hV#FBBB֭cԨQӇѣG~z>}op3*U0m4ٳRJ/cNWd2NNNrT!r[ll,ݻw'.. &p>}Jhh(Æ #99}JOOo޼yq#F 55#Gr 9vUV,\0G񦥥/C 8uj$$$HXX...3w\s&L@\\~)W\!99>#7ovسgԬYSBҸqcb޽9jQ%mXtt4{ӧt҅ϓҥ SgL)t}ӧOի.]"))I݉:ky2K?6 {`pPjԩ4i҄0p;w&))s}}ϋϐ!C裏8~89r*Ulx՛(!!q1i$u:99gҥKlgu e GGG5mdz=ɓDEEQre;ț,_I&1qD8sL~֐23?~u˜9s&&MJxrJի?*UҒ͛;@_^u.,PeʔGxzzP+iӦ*TFCƍٳZ(-jժXZZRP!Zh~^ضm[ZǕyˋ'OвeKUVVVԪU@ZlÇY|y\˔~y1:t`ӦMT^+++ׯϮ]S%FQz|kԨChܸ1GGG~WZlǏYrQeF`` M6p| 'Nh5/^}G{|ڴi8qe2k,ɓ' Ã'O0eΝ;#~senݺul_ڵkf@DDy^ӧO1cݻw;;;vӵc.[˼|||:t(׮] (( &6g̘1-[6Gn_Giii333~^?L`` ^^^j޺{={oB&LҥKlٲ%?9 FdYf !**JonHjժEF :z1͛|ܹSkS r)=DvrYmڴaҥ9NfffZK`r ...37772>|-ܼy *ݺu{+++(YÛ~ݻwӾ}{ݻ#z-C aaa8p@om۶2W@HMMջI!)))XZZR@RRRJQoƍM2s9j׮uN||<֘k-517;333/6DA2 SEƆ 6c3aŊ4jԈ~&O>}$&&sNJ.sNll,:t‚ݻw*ub ֮]ˎ;btt4;wÃѣGse7L!!3iٓ}Ҹs+Vt)={ƍ7uK..]Z+Ɏ;(SLKEU$՛_.ùy&UVeƍ:+ԕY:Ⱥ355B>}ؿ?:(_ۙ1cڵVnfSN 44SB*T $99YqFhѢ@@ŊHJJژ&()y?RK=i?]x0P~… 7Ɏj>@q%eNhVZUX"Eݝۍ}̙3iժ...ߟ};wŅN:b >|Nkl߾ȘŪo 25koݝ&MбcG,YAR_JJ -͍VZ,?~ԩSi֬-[d֬YZ9+󓒒3g͚5UV̜9xի=f͚Ѻukϟ3)'mkB Njj'YرڵkשShժ(--+WҵkW\\\pssc:3=rشi5z.+Wggg6m$^@ƾ}XzNbŊMvZ@ʕ% 2fϟON$_|&_bBS/TnPhQmۦ3 P?LFzsssJ(+TXfԩ:ADk׮eڵTR}=Ξ[v-FQR/^\l`굌'C,rppԩSDFF⒣@U~}3ByOM^Q= 6;w.]`fȑ#vۍLJϳ|lgN*K+6mjL"E:tֱ'O0tPf&ҊE^z5l޼Y_YennάY_p:Ȯ]8s 6lel\#FulBZZӦMLk]Snݺ.~)Mkɒ%ũQ˗/WC$sq9渃i{7}+۷OV1Y&HC aРAT\F9eʔM6,ZEX5?-GGGz͚5kXf }1:B &=қ?󌮬.^g}6l0:"L4 |Rӻwo_N51cl۶`)֭[0dvǏyLƴ[dd$[Wxx:*+}K/st̔ MVʬ*Lchm۶FﴶyfK>sZy%J0rr˜=~~~ܹs;;;||| eժUz?oذHj׮?'O$ NPP2s`oooT\~{{{5Foooz<ϟgƍ8qBٴ` (-[ a;vLǏl2BCCΎw; WŊ $$$!C9m^P_TRz_,M?uoߦf͚)qU\KuˋP;'@mCBBYι1;2X&H渻`֯_ϦM>|8666^2e 7ndѢE:W^6www&OɓСC"RjeM<ݛ̙CΝ R )$%%+;"\/_2d:w5-R4ۛ?Sݐy8Smݺu@ؔOJy2k !!AڦjUP.'OjkOy2SfEe5l0 (ʕ+s<>>_2MϔNJc/,E˺Mqeaڴiԭ[KKK>}u PrefϞ ]KY"o}1֫WOv!s<==VVVVjN$NJŊh4&===quuҒu32ɓPFIy)mkb(ѿ_Ufj\ MG@@>{DDDlSE;@ƠZVlJwdL!%qܹs+033Q`ĉ={Vݹ*;-[[cffrN)KJ2J(96 RTT 333.\se"ƶ[jj:#Bٹ%f)K\ '?X.4/^ U2tdP7Q'U2vXi߾sӡC5j:*oFXjj* .YBd/yc"ܺu  hwrr){m:w5ljl(eufL߀ݻwuSzuK2*T`Y֯_@k)qe_YΙߗ)mkҦM/ΡCԁbmmWǣh cҥ L΋v/W)eDޑ2!BFM }Ç1b ‚ySn]|}}sQh4YS?Cݻ73)RRR~:se7N_y}: 6L+12?P\9,,,]6ׯgƌjþ j֬ŋi׮XZZRN݋=gr)9]ƌ~Qfe3}t ,իWi޼9 jժ,]e˖sd=TľhضmjBPV-mۆFO2L)TX1)Q{~h4j֬͛o heeΝ;?~={dyO@@f͚h4իǞ={(W۶mIo/rMMe_hzPwݾ}[DD%>Xo֎[bzz:M;;; cirfm%ܤl8}4z,/z66V׮]133c۶mJͭ+FΝחAj*/YٌE\嘡 [D0R;!xmڵ+TҡCΜ9… ٿ?.\I&2dժUc@ʕׯ&M2j7aF-M4aРA:3^>S4 K.ŋh4}Ə;ժUc\RBRX1BCCYp!۶mƍ<{J*ѥKLB2eLjGDRԙtӷo_&MĶmx%J̙ٙCpp04hЀ3f&j͚55`(Wz_N8uܿ2eжm[<==&_6kOSu$7-YYf ۷gذaZq9e/-ZTRIJetvyCpZUVB!xKK[&OL ؽ{77n 99wy Fٲe;D!LÆ =z4/`̘1899sTo,B!B177o߾yu$>?B!B! ,B!B!2!B!B!?Y&B? 6ׯ0h2X&Bڸq; !B Bd S!B!BOf !⭶l2Y)3}/xz!!~M,B![m2+[o{.??:g"o,B!B!2!B!B!?Y)B!^ȟI_ I&CI쬷FbŊww^)1GDD[}ܜŋS~}FAժU"##8p eʔaΝF.]bժU899p9Hr !Bѣ/K@N>}4˗/&==^z@_zBW[III\|Yfamm|x!&<ܻw5kcdB^V&Nŋ9׃9L2ȘՕW>C)BHH111zr1 ,--ޗdB!+aŊ*UY8VZšCxKUV >kkktӦM,YgϢhhӦ ǏPB@UVo>J*t҅?XZP^j'N+Wۢشi5lٲjr̦M0`E5#"&&e˖qq>}J*U8p SN_7fܿҥKG1l0ïϓ}9Wq=-[FHH)))|GL8WWWXrziv_c|=GӧjJmscTXǏm p ,H3f F뱄`ߏ͚5cܸq.]B N@@۷og:uر:t蠾= iN'3/s=[r !Bbcc4h/W^e̙ҩS'n}KBB33WWWٷolGꊏgذaܹsG=v%6Ɍ9HXTT>>>?˗gݐtbccoU>z?e)'g\\C Vٳxy&Jҹӓ'NW0ydr .d@ծ]8s 6lXb@R̀ThvPdmSS'=[r,B!xE[ رc|'|}}~:7vvv\zk\bŊ!C8|zˋP;'?3+,+W&$$/2CBBYucJ!īϏ;w`ggZJ vsI_>݂- y|LWdAUhB%v%*vڢPb j%ھTRVbMR{"DVDGi&3IfFbc2{kΜsգuر[[[hQZɊ+d߿?L'ל8WZ\d ϟ7ǏsiN @ ߬_fiEDD0w\"## L2ܸqիWx{{SV-~79իWZ*ժU3=jSS=[}O:˄B!a)cy!""?///\\\?~<0?5kbooOZt/vmP1cQwRRn[0֯_M`` F?DӫW/=yƜ={wOF˗#x̹խ[ &sNBBBTTPɓ'}vcN:,XoN{`ܸqT^{{{ FRߧnݺ|'֙ӻwoN:AO> *LHH07vX6l=5kԍܱBvTM-O=[}Oa !BS7nrNU^z:u[vKzz.mĈL2(o߿?AAA899?2{.uYi}j׮[o_|ݻIJJ͍$vڅ+[%sZz̋{rt !Ba"yB0C>zZj?{e˖-?~ zj fҺ'Y*SJLMM54ǭDڴmW!,*Μ''NO>L>wwwZhaq<~`;?tJ9qj'4uqzyڷoի駟֭?zXd77Ǝ˘r}2 S!"z嗁GD)ScǎkFnnntRV\I>}HJJbΜ9zEmvicO^Ӧ[hZxzzpqܶmtke|XC*Uݻ7J)BBB[vdґ#G8qA^/MeNvg||?8GW_5۩S'lllزe Wb}2/r}2LXիWvBˋ[; ! QF]ٳgBbŘ;w.ׯSKY|9!!!L:jժq)O@&M̮C\~cҶm[*V~íիxyye[;wetܙ7o2c Xݕ+W֭[\rvJ%;^˖-pӧOgԩTRӧOmhт˗3~xƌCŊwWfժUh"Ν;~:K,aۺukΞ=g}ԩSUgΜ>3륩̉f…駟RfMΞ=˴i,iL6MwO8AHH޴J-///ի{s[.*TgN{ddfyqϖ{_2aU&=z^ ((0k!x׏;wGve|"[>}ؽ{7W^=%K }!$$3f|@˸^]N`۶mYټys6mW_}W_}`15jľ}7XH;*’"BggϞ\|}fo߾ݻ8zꥷɉ#Gޛspvvilܾg˽/4L/(%| ʴS3%Jl2ZjE"Ejժ̜9m)Re˖ѵkWJ*-JG,_\9:uĤIR 888M߾}2e.ѣ)[,93rH)Z(4lؐ'Z|nݺ5...8pJ˖-n!D̒%KXbQR%>S@ )WWWBCC [[[tx21纥Un]vJZZ_|E:88pBCRiӦFz4q.Y@qppe˖P>ks̡qQT){=-Zg͛7Dܻwŋ3GVLOfl>T+ ٳ'k(;HY&DY?-bҥl޼eO>ֱcG̀xQHt_0f~n޼I)S [nM"2'bBLa&YL! >}?Ƙ1c'mWӦMh4;VZʕ+W9s&uԱrBr]Y&YL'Fos|n9ggg&Oݻ7[neܹ899Y9:!ڶmƍ /:.,L&BQ2tPfϞ aò]pY3///~'.]Djj*/2 4`*U! Ƚ/HgB!S`WPP+W ..No~ Yfヽ=4o\.Ė-[݆LB_:t(իWhѢ4oޜqƱ{nQ\0a5j͍eZ\<ݹB!B!22Q ?1}ر#2ѣ?uL>]o СC C)ťK̎])oɓ'/_RuꫯtOOOڶmKXXn[QJqu]fccìYcԨQ߿Ͼ}>}:o&+Wf&Cf͚5h?c !ٳYn[~=FbԨQ@ª{2ȑ#iժ 6^ZoY{_rb߾}l;z(gݺu(֭*UvVT!,h;v,K#..P&MDͭs(\Ӓ{o$#DqqzK}w_"Ee hjy_B(V 6$,,O>$Ǝoݺux{{M@@};wΝ;F۷/6m|r:wLjոxnӶ[FŊUVL0~[n1`RRR8qIdb>Ys'ϻ}M'N$00ʔ)CN0aHg!xbcc-?~<TR;v ::[ҷo_߿_N8QñaTV-:/?  {\x*U0qD.]ʖ-[8w\eo\rPOJp#F08&s]1)R"""leUb4o^;!zVHeٲeܾ}ݻz۷Yl#B<(^8˗/}/^[[[ʔ)IKKc…Z{o%0EÑ#G8tmڴ1ywFO?% ˼;vx5jaxiӦO2ZuzmΜ93-_<666 hذA%ַo_Lb4̴Ihܸ^ f.٘mF=MB̟?W#4 'N>=U 55`VX7x7o$44#Fx_h4F% 6Dd!xL&jVf%j…yܿY(L IDAT5kcnݺExx8 @3k,֯_F!))m۶cRRRHNNdϜ9m۶BRR۷ozˤX!%%D{7r*9i97o/ܿ_nk׮eƌ&hN[%''ӿnJbb"ό?ޠ\oY& CRhQZj8;;cgg}G\rznd*/?L޽\2...*T777ׯϔ)S8w/[~… cgg+brqApww?0p,3=MB1GGG/֭}OOO5k7իWk׮fhN[if'ywY&B@@@Nb׮]X9s>$xxxpmۆu(Q[nH%%&&!rMlӦ ۷o',,mRxq2YhJ)y]GY2e|2ǎ~ǎ89=zW_}Uq=}Y2|8իWŅ… opB>s@)Re˖ѵkWJ*-JG,_\}n3g7ΎRJ{h"4.s2vyZscuǴj ggg^:ӧOub[Τi+,YB``ae-[dʽ7QOBO!<<={@^kٳ'aaaF ! .6nѢE,]͛7SlY:v0`#y7666dgƈGO'bedB!O>.]ZC|XXNBޛɚeB!O!Srӳmɓ>|8{`̝֭;`B!{/,B!2tPfϞ a B!D{o$e"_ڰaC/ 6ХKk!(fd!!c۽C<?Y&]Z;!B!BL+ң.B!Bk2DDD0w\k!7?vB!B!!,իWe(/lذ{{{k!xF6l@ǎ9V?%Kyֹt|iAziУGdL!e7ofC!&eB!xf0⹢vBaB@!B!BBF ={ʕ+ݶ~ziBB d2!5ѱcGlْ!B!B=Y&6m7n$))t.]Ĕ)SSNקOJ.MXX.-,, `۲eCB!B2\˓rccci۶-7ndƌ̘1Co; :%%&M}[o/BBwիWY&8qŋ2@VD 8%Kp=|}}x^v?'ßѶ/r\O!B! XY&f/~=zGqI7n̯Jhh(ŊcŊ$%%{F>}HJJb帻u +tM#ʕ+s94 Ǐnٳx">>>DGGCG\\AY… 7o^.B!B?Y&fZ~=k֬vQZ5/_իuyx Fɾ}hܸ1{?䭷ʵ:͛GŊqvvfȑܽ{W},^_6m7|cP+saܾ}!CҥK4B!BHY&f:<*TЭfcc'NkFTTժU3x@DnPF 麴 ״iSfϞ3;v࣏>^#$$FcB!BQIgȗ2vK^xgʘlMaI֣yM@{{{ݻw넆ҨQ#W^yEt B!BQY;!2jܸne4|={˗/S\7n'N^z>|O>/2}̭+Vɓ߿~[e4;_~>|3g2j(s%&!B!oddBw ((#Gcnݺ o.ݻ/iܸ1iӦ|޽[G; ܹsa=z0x`ϣGayo!99ZjQV-@B!BE!BXXX !,Šg4L8@<<<ԩ&L`Æ 8;;?0RRR9s&ѣԩSD4 < 11,믥L!cǎaVdt般e˸}6ݻwץу5kְl2SEİaXh7wfѸ쌛8;;SH)3otڕwyڇsU9S~}FtB.]B!H:˄0Qzz:K,aǎܼy{{{С;v˫hXt);wΝ;,Y6m0`;2Krr2k׮^z*UJtvZzM"EQ s,Y7n0|ƌÇYj`jԨ34g !DniHB!盧L͟?+W?z'Np ]Bjj*:uJ͛)T(/h46lhaÆİc:wG'r |M6GԩSΠS5-[ۑ J)k xN5 ZBE2!Li&͛=b̘1u:V^ͩSQƍۛ+WBLL [ncǎNzAVj6YVԪUXλː!C3gNNNzΜ9Å x"/^^уBfBKeBlY& SK5\\\>aaa\x͛H``^;wB2eP'Ocǎl߾=FgϞ\rʗ/G...|nݚr֬YC5ty~GJ,ɵk3f IIIꫯRV-^{5ׯO&Mځ&k !,(ˉa&BxL1)SETT| '((HoիW0Zm=w0)MG`` գgϞ̙3`wy˗p%8qqqq]O?[[[ԩCӦMi֬M4a&LCB!DA#e@}1cM6A?uۗG^_>[fժU8991rH]^zS:u}4jxiM4Ƀ#Z%f͚5O]#F_~!!!m۶믳j*6lHR ",,;wBBš#Ie0RJʭ[ظq# 111X;Le>^B! ,vJԩS'&MD*Upppooo˔)St\]] %((lmmqssy,_\oTѣ)[,кuk\\\8pA Օ-[gF;7|åK8}4ƍ?L1cjZ~-RWDDjժ舧'$ΜXsLOޞ_~Ν;j*V\i娄B,,^Cq!֭['W1j(mFtt4wfkժ[l!::_~… ıcǸ~.9vz%V<7TG}Į]HHH`d۷i۶-M4̙3TgΜQSNUEQj֬z k)u*,,,MAט+777rrrR?>f|9;;_|5N:FjԨ֭el666j۶mzFʗ/nݺkf s3;Ɵvmo[n% x'B2\˓׳ɓٺu+7o͛lݺɓ'y#SDVŋi֬'O䣏>Zj8;;@ʕ0aXb۷EY;l!{.$''3rHΟ?σdd0zKY_+a}K.1x`ҥK~|||8z(3g4)t/6nH̘1#GPzu"""h4E PJ1m4}FIrr2󤦦hسgժUzKhXn>sAeZ'Miϟĉ$&&_X|l/!x&I'=r7O^FFíNjHFYye5p@TҥUPP:y0X}Vdɒ^UPAUYFegggjΜ9I&xV(QBmVٳhyΝSVA-ZTխ[WM}sx3.](@ :h| P*U26śYHHGʎ92ZN?6fDZ֍Ȕk}Bرc ,Wof P...zNNN 0z͍Wd䨖fq۰>K!ctP/6fɱ{ ~=wX:˄U=ӼI:?cONR5(/u!~Gl4ӧkРA P'N4)ޔuC~!˺ .vܙ屛z|(7ݹsG*UJt_vM+;;;cr6΂aśYFn޼itɓ'իeS˗Wjݺzvuq߾}&Ǖӵ^{Mmٲ7ǏͨbŊ P 4PWVW^ͶK͔2)!ctPgΜ1fɱ{ ~='eºLWYfgBBȑ#ՃTdd0`*T*ZqFjʋ/*GGG`u%߯|||vrd4uad<ƍS^PF(ՠA(}Ο?RSSFQ{QժUS2dS۳,oUVM*""B?j޽[m۶zܾ}[-ZT/gΜQ>TGU-[TFҞ(WJ7oСW>TC P$-9άL)ꫯ:U˖-&OlRݙ-M)VXetUGݽ{`޽{&ǕݵVTAAA PnnnF˹pںu0ajٲz饗l2cT}UAfiϓSOY?ʱ{ ~='eºLWYfߧLy"OɸoNi-`w6rԩ w.=zHٙ… +@%&&=fSh;Y[h-Zdng2i;,1͛m flmmԪUTĩSX`4lؐhTbŋ9y$111DGGs17~Idd$更oߞv햹ܔb1H+\0|fti|}}o4͍{LѢE-Stsfgv,=ŋgJ8|*Udrz|||8rM6&Bh4|dۛcǎOF{wU.(@"KbK.(*WBQDKE?Bn KZLTLD1 4l"9132 uu993e?ג'<رnnnRJ?Q2255Ō30c /#GܹsbUT鯪AMMM#??_{B(REDT$%%0a „ гgOuQodggWݏ?0ȑ#hѢL\@&MThjjyppp@pp0.]lxzzJ;p,,,`aaQF믿FDDo>}::[[[q۟]vaܸqDjj׭&յ5jpۜZ]2Qp_EEEr.oMS^^ʌ"U#GĀo6͛W-1Q6lM F!}HHHرc| ߿? @f_RR444`ffR{ GԩSeoܸQŋfff7dqpp٦uS*r@CCvɿ2+rA˽qqqRb_SvʎMU'D kQeTױYņ k֬-KXX&MÇĉveS]:9III޽;:t+US$^̐$tMRTn.VѣG#:::tL;???ǽ{|~~~ŋCŕ+Wa 2DvPqq:L%)V )R-YoɓsN~9ݫPߤ^#Fkװ~zDDD 33xd %K@OOOsz'1k,aӦMu{aѩS'L6 ;vqqܻw/_F/mڴu*eS:@PPΝH?h׮QQQXj"##w}+V~ٳgT_DD5MCj:0Q%.^͛7; "W,xY,^ѭ[7<ڵkaeehb׮](..F\\lllGѣaeeK..Ν;޽;,]_| ?7nʕ+##"/梢"|8LMMKܽ{+!շx QƚeDD$ePR|̙BYfSNɴ-o"_/\ >\h޼+W_}%ȴzzz0yrK޽[M  ~AqeРAR<{LXt`ii) BǎE ?u+=.U(;!UclZZ0k,Hv*(tނ_6l`dd$5:w, ƍط0m4͛J &4nX|M޿ɓ' yܹaĉ ->X%'DZ0?;wVwT)ID$O}KCoQz-X;wɓNdQaÆQw(DDDDDDDu'ˈM6;"""""":eD Pqq1ЩS'YNdQC`hӦ <<<Q2ݻwy7n樈O[Qs6m7xcƌ#>>ZZZpvv ""Z2ݻ077߼y3m6|gj SwDTS!8YFSN]t ɓ'M6jpu@DDDDDTc8YF`ĈRۼw^,[ ?"`ĉV󎈪"88NNNT2(55;v֤IlذSNUNNN58eT 8YF_͕,)S`ǎp%#OR.^͛7; "g>sWa)LSQ{.Bf6oތڵ#WFDJ ǃR{.abbիWqf͛3\t8"RW(+NR >>^͑@R Zݾ}]tQիQ8YFܼy/^ \;wZBϞ=1qDΎeDDDV-4xUlݺ 4i:w j^',#j`$0Ϟ='ϟӧcʕj\Ο?_~_x+V`022;˗/Gxx8t~""z=qٹs'BCC۷ׯ_WSDD GuDLO"BI҂cLdX:u ƍSiDDTwD~VVVT-~WyI?FPP##z}޽YYYġCp|rۿ?ɨ(\t ;wDFF:زe qxzz8t$^Xjb\yyyAӦM[xJWt,QQQ]/&iCDDTWЬY3\~}Uw8D*Q4)''8s 2e {rJ<{m@daff&Ն4NT̄uAEӜrss' 55Ul"00P$ϟ O?XE:R6n܈I eWeLO"3f@DDGI5kV9::ĉd888k׮/|}}ڊ_+ڮVK^)SrJ8p@hO>رcaddcǎ)|l>}py$%%Ɍ1)) W8F""jҥ Sh1|oddR՝$]ӓZZBPP CCCk׮X~zK[d }}}[nXnfϞ ߚcǎ7~mBWW>}:VZ%OvţG!~?R6ŋZZZ =vС000@ddLhҤ ؉ŕeD$bPaڵh޼96oތ0o^]vaڵꫯ`ii7obݺuT[a0zh#F@N]&5t+LMM3gW^9s&/OT+C޽@6(YQPwYo>&N͛3|055Ńܹ &GiǓ'Oرc^zgЧODŽ ;;[OOO?/,,DLL bbb pHY\Vw999Ia ,#jǣgϞ℔=lmmOѼys޽ ´ipi";;D- t};?&Gi]t]ob͚5Xf ~gqر#acc141Bݻزe 'ˈ\8| ""Z4L.,, ~ :::pvv۷Ol;`,XϟG߾}q9|4hR}hkkvCb˖-ԩ`ӧO_\v܉{ׯo.s&M6n܈[ǘ;w.A{NDDL0&LPwDTM0TĕeD ܝ;wR-ZHLLھvZDDD &&U};#~ݲeK%$RRR{:_~2̙3q):u +VϟJ'"I"""jX8YF+]խIgtOёi;yd :F@@???]sQhTBNDT󎈪"885A)N5pfff}6߿:(IW ˖-Cbb"z聸8,]6mRԩnܸ .`ذa[h3f`ƌO?c…,SP߾}ʂֳgOuP%cƌ/D';"N5p1|}}-[ o&233̙33g`ӦM۷/Μ9Aȑ#1`%:w\nYYYo'ՇL˗ {E޽qUɴ@jj*mX[[iWźeDDD 'ˈ8OOO>|.]>===|7gϞa044޽{ݻwHLLDѦM<~]tAp 000PŋO?իSL۷zxx`Μ9pwwԾR.^(>HQLC"""eD \fp%^?3ѴiS.'v 333%[l+^^^x ׯV^ݻ+Ν;OOO:>>9d[e3vmtE]h[Ǘf͚nnnرJ.{T5,,L,}ѫW/keD-Z`ӦMRdžG߇ $$DiӦaڴi'OɓC&bmoڴ)mۆm۶Uv̙9sf}Մ˗Rc4ۢEpz5W]gϞEll, SSSQիغu+8A0i$t666*deccǏ; ""z/!!}v١>>>2tyuPJ߷bdddW^ŏ?իW+u^/^`Ŋ?~<cǎ}}*TwDT7Y[[֭[b*%QCT]]짺b … pB>HI;455pR&LLL/_c,)S xj 'ˈH.+++5E Ou(IYd /^-[ڵkU>/Iמѣ} 6)))pwwG߾}1p@[/^:'Ozj 8X|9q )nǖ-[0j(#GĶmPXX(sGaʕ4hzɓ'Qބcӧ1g8::W^裏'cŊׯ O<(3fyСR+]?qF? 44=z@۶mڵ=BCC82a\]t>_.'jHj+է*TGL![IO(.. 3g"==]<~C^^^իWaڢ]v̄/ڶme˖ 1g?edd 00IIIغu+45K&SJiKII7^z#GV9۷# @j[ff&BCC-H%DF\\ѤI}(3Tv+s}@Vm^y<==q%%%$$EEEc@``WWk`{zz"** .]Ν;@+ؾ};c޽̘+S=.OQQnݺ лwoq"נ?!22R7t\QQQ]&&iCDTqeZ,JLTNBFFttt`aaѣGc̘1Rmhݺ5O?T#T6UP8"1Uӧduptt; *2e {=MDD`ڵ066cƌ'Ϲ/,Y"KUTpA[믿Ν;ʴB=򂻻;Ξ=sC1W{\ZyﵦMO>WȳtRf͚PTILIhifffRm;NQ?; Jmݺ{%3<5J)))5%++ ,[d 5<ʌ2hiie˖ìYy@k Oǎů5k&ӧO@P$$m;NQS<|o!*סC[l=^|'N'J,[ HKKڵk41c >>^eT^?iF $&&M*FޱP}~~~DAA6l{{{?qxRSS+d䳮h"99˗/W_!)) /_ĕ+Wk7hРr2cVʮAEׯ2Tڴ4}m5nKDT*"TLGRԐ!CЫW/;wGױm6۷3b*4G1pqqӧqm̞=[>tP=8>>999񁁁V^ mmm`ʔ)Xr%8CCCL>ΝCBB\\\ӨQ#,X@~ƌ@BB>#fvttġCo[hObر022±c'N2$''KӧOjӥK kI*3fuPȻ~ӧΟ?$J퓬l|6":+ˈBָ~ TӦM1j(`Ϟ=puuEvv66n(;v 2ZI4ȑ#{2cHgJcJ $?_AWW?~tuuѭ[7[NL|(n{`oo/j QǕeDT!z 7nPw(DruuP*_~ݻʢtaff&C޽{eh$sƎ+:c׏#pqq!\ʌQRKH^apQYh׮m022IO%"8YFD277G&MXVHcǎ7~mBWW>}:VZ%S&**T"y*3F2ャG"##8z(|||ШQ#uGDTmX*ݻ?yF¨Q*m״iS,\ .ݐ!C0dȐI^?Xv zclܸ1tq5sQbggwww͛'S🈨dUE^_8~8)5DDT1'''899; "2"5BBB 444S5rJT&NC IJ_|S=͛73$NQ㭷Rw8DT͘RCDDDD/NQwMMM\veJeRCDDDDTeDT&M Q  ""Z2"R Qsa>|XaQ-d){ؽ{ ""5 ;"""RNBlllボ;R';"Z;"?}UwDMu@DA`*ffjj &; "G&LSSSup; "uAD*2"R5kׯ/d T߾}y bHi+ˈHa666HHHPwDDDDDDD5+ˈHaVVV|àZƚ=DDDDDԐpfmm@z ZZZjkQu5۷oK.RƝ={Gō7~ ѣ_Ut+Sq*Bzu\!&&ЫW/A52"R5򐒒jDT+ IDAT~a2"kѢE8||xzzҥKR@x{{Q=Vr8^[&MBΝaccЈp֭[7hii,#""Rϫ;ZK.m۶;w.f͚ѣG8tك/?#wp[&Q_/^+0~xƎ˗#<<j ѥK'""*^8Rŋ-[b׮]9r$Zl ---9sիWضmåPPP?~ɓ'ۦLǏ#((HQM2"R]0ꍬ,l޼/^ċ/`aaiӦaٲeW # Ѻuk >~)tuuH׭RMLL 6n܈_~ژ8q"̙ϟcptttЯ_?xxxq9N>p$''[#a``PcccǎNmI ~m999Ǚ3gn ٳѤIk7"!!zzz4hϟƍCq!G B_,^;wFU兓'Ob1b~1h P^Gm6DEE!77fff6mT]z{EcEo׭[ϣQFׯΝVZUx}sNNBCCѣG_v`ooPL:GqbmmͿ)(//~)>|(nKNN'J+,,Ĝ9spMq[FF[BSSĐ 6HM011AxxgAA?MMM\}vH+33իkt>};ƍO>ږO>Rq 662/nnnxx-~' CBBc={}*Ǎ7"''@UxzzիذalmmѮ];dffm۶2>}ۦ^ȑ#7 ///DFF(;|0,5!Z2c>y$ sԩS7n\MDu 0H)666?SuBDDTÇ066F`` /wRd߾}y&y bccqQҫu^uҥK3gZZZ駟ٳg.\ ~%/QQQtv $EM>>Q':u]]]899,[ :tN *d,.._waJVoIXJW^<⊪3gSSS pttD˖-/_mۢ_~JME&ݱ:NNN'ʕ+XXX[n8q=V+++<|.]*wƍ1cu놀qJVTݻw_~p hjjb̘1*M&V)Jx]-9Pc}I2Yωdׅ>NՐݻ~Te!-- ǎQmY%5ZhRE󋊊]cc>|8N8`1-[_\\;v@|$1߿k׮gϞb{SUի .>VXZZ͛غu+.\(W&7xxhhhȬSte77nHfr (3VZ!33ϟ?y¦$]'oQÚeDDDDD5du!)) EEEHLLĺud@I dz O}:N:|7n>}Ec@I]!!!AW:7^QXX(էc+Ou߸8R'!33ذaBIÇŋHMMR&W_!)) /_ĕ+WfAʽ.ʌYr*I3.M&RH=5\|Yaժ={Ta߿ӧWv8w"QFX`}-S;FFF8vXMdĉd888XvΝ;w ֿ|WRp8s RTf}m?FVѩ26y*etW6|||0e\RΘ1HHHG}$v֬Y׎8t[|ƩMR֥K (3>}HJJ@W"8YxbP'մj[nŅ  sss[VU&MgϞǏѸqcbΜ9رvp-(U-YEEEīWЩS'޽{ǁPcc-[bϞ= _ܻwիƍ'3a_ Ν;q9 %O[3f 駟S'DTY8x Q\\{aժU UkHcڵCpp-88FFF2iDz`ffD:b2"FWy-0{l5EVXaׇ L:pQl޼5RstDT8Y@DuLMM믿޽{(,,o޽{O?E۶mbiHc̛7O?>8Y@.V&"K455 &Xa`2""""""""2""""""""2"233BkODDDDD '˨АB-ЫW/@ݡ*qihh@[[-Zsu[+$/~@׮]Q*./^{Uz_{"\|_^DT?[x._˗/#<<gϞCW^ٳg#<<111h֬Cu1{x5\v =~;4kODT]c={TwD",zCWaa!233qA曈ڵkʎK!==hӦ W_;'}$#ȑ#QPPiӦKDDDDDDǕeTo7qЪU+{_ЪLKK Ƙ9s&z- 0aaaSwh m_bÆ pssݻw'NTwDTIa da055쌛7omJ~||<&L6m@WWDnnJ1K8gdd+((MЯ_?j hݺ5>C;wNܹ9scǎCaggUVٳgrQ)W^/ XZZBGGmڴITn,puu tuuabbӧΝ;r+{KVSI٘$HKK7n#G"..ܹn߾ i^[HOOweq{NUEppU|_,e/… BӦM2F Ǐ9F^/}}}v}w\HTT@xwggg Ʀ!;vLXаc̄jn9xoYUwÆ rӓ& 򋠯/ƍ UIE)Uc*}_O4IAx뭷ޝUU<]9`jɩP ˛`8SڽMCh-55n `zJKHie@ ޽pxBT}"} =,rXYY)ӦMS~GƍJBB2n8ZiРr;788Xp? J͚5@4i?+m*2gc5QTTʆ gggP̜9SN:)T|%11Q޽(ݺuۧG ?^%//Oo;*WdW~eJ:u@5k^F֭+'NP<==@iРremK.)uUKIMMUn޼*^^^ 4jHtXVOTxǕ,(J``( .48ڞ9 )Ҷm[m,NK>٫.}_r1* DQY5,{Й3XpQM6F3fm 0!:r6㨤f@clRo`ۏ?Jڵkժʵk IMMUI+Li]q=?m+**Rʂ ruбO>JQQQcrss~k8-+WZuǕQ!De~*UenU? ~SO[޽l2N'ƾ0/ʴiӔiӦ)f{>B9"9˄F}Joatqعsgbȑҿ.\sի;/?BΜ9CPPv=WQ~TfbǎqU6oތ7i_M^^nnnqss#//\B ͋/`2K!..+++PӧO'%%E[_>}n-55+++ZjeQk׮yԜIG6_bdVZaeeeMKN}])..74ȭV~eEEE,Zkn_d,...맕ۏeQIJגL.ܼy3>Pegĉmۖ_~BDz䳷gA{!JQQQ?'''"""HHH ,,LoƊjݺuL\\]t!))[Mg9t&M $$5jqF0a ۃ1:tO>/L{ IDAT>… 8;;f|Zr-[i&\`g`/kfzu>իqԙXի%((bmyTŚ5k̤cǎlڴ+ae)L~N>ʕ+IHH ""͛s>2mNСq2v)(\}IϟW4hJ~Ç+7nP٣L0ASlllGjlٲE'|R~5k*o+Jnn{nSN ̝;Wo̘oݺOʻᆱ)n:m{۶m@yו PIMMUFPΞ=J;w*ׯ_Wnݺ?~\߿(CPݩ]uiJ2 (Æ SN:ܼyS_|QG}TqㆶϯԫWO///ĉ͛7'N(^^^ Ԯ][_,DzD= )7o޴8&S]Q'(YYYFu[n)/^Tnݪxxx(bkk۷Ϥc%%?{սKW. >quu5韢(ʈ#WWW%11QzJֽp^_UquuUƏoCY+ﵲ\~X9qWYx2tPUtWv[jCRR^+oO:Oe}+(3<[uw*~~~d􅷷ꪤNm4V^V=S_ÊueE>^zIquuU233 T\]]#4Li޼9 2ݻwYb]t/X+ծ];VXqXp! .ԫ׽{w*Sa7NqL0+WrJs!&&#GТE ~ml©S08G͵/{sT|'8p@^y-9zEĉ+o֬[lVZZ_W:t([lj֬ITT-[Dzw^)bQL>|8Ǐn/,[.}K+J䳷g~{!Ξ= `{pTΝ(3EYO6U%Rrټeff2m4N:eM)1^|ǏӺukm7/.^w*/Uh`9mz*g֒2%0p1qvv֖  /sN^u?g߾}K4l;;;{1yA;Y&ZbĈر?zǏϚ5kҥ 5k֤~<|,X@K&C t{{{lllh۶-oG50ccc 6TCe޽t:lllhݺ53f<w}ǨQpttGGGƌѣG4h^}KјH^|Eԩ _-r@l M6͍yq̙ S%?{k !ݦ.!+r0O,JCZj֬iں,^SN̨Q;wͶU[c>&Kgkkܙ7f=zTm%͜0%m~I=g5Lcm6sI.U!|2Lpqq1Șk׮Yt^z|1p?nw2fƌctѣ3kР|s LoO<[*%=9r;v,7Di>iժ;v쨴LwIVVVTY1L9%9?{ս~O?4ޠ#gϞe۶m8::0˥>'""Fm/,,枷ٙt;|fSv|r!ѣGs:vɓ'Y|9?#<¯,VVV(Bnnԙ~T'NЛ=>ٹs&MAVVM4ۦ> t#3˄ ťyH !$/ .$55B?n|ˬYHKK+WG鴤uyٽ@AAiiizu^[ˢ>&88BN8= WZE?/xyyW_O:uh+~7prrɉ._2/4iBdd$ԫW[[[:tEN6!CРApss3zXR͜9cggGƍ>|8aaae3vZ8@ݺuYBR wD+{Qw-ZpUXj'!Ҿ"** TɥK8p NNNlݺҏ_z(˗/'66EQ>|8...t)B!BdL3۷ڝƍ̙3!C7gfÆ 0BQNmتr}i/^ȺuHLL$##[[[׿s1bׯcdUae]Iә|%Vdd$/_fĈZȑ#|2UB!4oU=?0rH8wriUf*VW5̘1ӧl2;v#BGfj~cŊsuZjŘ1c0`^سgW\iӦۗ &Pn]:Chh()))ԬYSj cΝ\t [[[ڴi ;V배0O V*N;sO?VYft:bbb=z43B!2g]U,{cՌ>\}Y|MZnMaa!N> --˗`{Ͻ 3Y&W2vXK 9s AAAl۶Mwu^{5֯_oFaa!DGG3n8 =qD'++7m_|9~)Ν֭[qq}]L?44Al1_5yyylsss#//;wB!#3|))){`ccCZxꩧU=#,ƚ5k̤cǎlڴ+[v-4oޜɉ3gΰzjclْM6?|}ӦM,[O`` d;[&>>;sСCej!BT<ݻ7rM:wfҤIӭ[7^~e,Yw#UVMݻ7*7oP|fBӱ}v NG``LXltޝb w&OLϞ=ׯ .ƍf@eNN|ߴ~ иqc233 E$''gϞr2Vy&ϧgϞۗ sSג~۷/&M*6eUCNNA,Bqe(;l9]7c Zhܾp5k^=uk֬Y<tܙ3gog&OO@@vL___"""ֶ׮]ׯEzz: 2!CQ3զۘӧOKkժ^!BT@:XV\Ixx>Đ݌[|9k׮ܺuǏsqrss-'ѣGYx1]vYfddd3g[PPI8yVv%"""HMMeX[ߣ8q"YYYqFK۩@HOOIIIDDDPvmb7n&LW^gϞ<ޱoMh"mEA~~>۷oرc[ԵLY%qU IIIܹ[BQM2Qm\xOWpp{zJ8%iF{^DkeSNf͚$&&ÇA~~S2\zhN2L#Bs58p|,9t| 24ufz1|rss s璛˼y_~3׭[ɓ'yljѥKغuAL1ߘW^!88fƏs=믿N\\ :s3x t:,^~rj+=hgj]KUAexG_9s ;v, ǎgUO1Wӓ'O{n֬YChhESɭP\ gΜ1gjiҤ deeѤImrB!ڶmnР/33iӦq)}Kx:u*'11DV\?>>>ԪU͹9e>iݺ5Ϲs4)m'ܝuЁ:GAAW&,,ŋ_yuK.?ޢ)$dUa!3DѣG,YBFF,^N%pwwn߽LII.\@^>:?<ڵk `|VzQXFyfnܸAzz:!!!عեgϞ58ZfN!B͒wxbN:3Fbܹԫ`1ý_REV N˗ 1vX iF-~0%jB<,dLT*M4!%%_~={jrcҢE .\?ݺuߟ/ҢE -ׄ9ԋzMݵ)]v` 8cz~!zbذa4lv;:Жjp\̒C!B[@KDDSN5(,,^Yv-cǎ%;; kY|Qgo۶`099$bNNN+TY*kNAYrI0ʌͰS?z(>EuF?+ %ɪ!ăD˄Q"GYiM4!22ի-:t`ѢE 0@W^="##6lԨQFի d oooxǰΎ6mzӧOyԨQ㎉\MƐ!ChРvvv1gmvzUnݺ fB!FBB1{l\͡elxK9rhtBDD]ve9rDcl{>}(**ʕ+|Gt:&Mdv,n@9r$p{ ̙3puό3?L_azHMMG ֳܾnejB<$gV?iРRրr5_Yy<<<0jOn*)6v:uCxx8.\y<ǎcĉB!D "((`{ZZnnn;`BBB _JΆ/JKNN&''yQvm,X cȑ̝;XիGFz*8::m6ػw/)))5JصjbڴifSoϞ=;w`+ѣψ54Ζ-[C{ΦMpss+7Ocǎ >ܢ>=zo>RSS >Y x2!scǎYfDEEieQQQ8::\ !Uƌ3fၽ=vvvtԉ 2am ~# @[D@@/_t[.H5_>^ڢFn@x7Y|9/;;;\\\xϴd` Uhh(={ƌêU3nejB<̬;eh|}}䢥ߛNw&-u|>h[|M6lСCYtiw^xPXYYBa*}"5ڔkasMV"<<͛7j4h'NdܸqU_u!O%2!L<%KdL"eB!ɪ!@r T,Q6S%B!*{{{͛Ǜoѣغu+K.VZUBT,B!BaY x`B!BTsVmTA eB!B!B,{HYYYUuB!B!Վ =dzI\\\U!gB!,B! 6lֶB!=$e[a!D$Bbl޼B!=$e)EQ:!QqBp2!B!6lXU gϞUUB!ц ذaCU!mذsUuB 2;}4۷kC IDAT穬HLL[nrG\! ɉ(&e[oo>y*+ƣG|rbccQÇB.]*t\!B!a"0m߾}<73gC '''={67nܨB!B,Ft:>#KTH._̈##G~z"##kjСAjZG!OәQT/e|2UB&3PvNwN_ڵ~:QQQΐ!C2d^]v[f޼y 4۷,ۼ1~EԩSر#Gpr5Oe˖iժ^!BT&&PRRRY&?Ic!<2X&S2|ILLdʕCZzΝqΜ9sc2&33iӦq)m9mz*ы9L#BȡCg")"*ĉ ??7R\\̬Ycǎ%33S̙3QTTM>yHOO222&))m0$B2LrŲvAPP;w&??+V0`6nܨջ@ӝfmݍYx1NٙQF1w\L:9m0M-S!j\v88-ooV.-"ZlɦMߠ=k֬!33;i&+@DD`zʌkגN͉ !!p8s W6;>Ic!<2LT+OOON<ݻYf ڝ=GGGΞ=˶m۴dU1##""hԨBll&MAVVM4ۦQ-].BYߦu?\m75}CERDTZh/dggk<3zffvC5kO>$;wf̙ٳɓ'BQY& ///t:9yyyklmmz}n_0QTTĕ+W裏tL4IΨR5ޭ;OBB1{l\`39ml߾=gϞ58ZB!Dh۶AcLƌØ1cxwnq>uTj֬Ibb">|8y+*c@6m7hŋʹpp{zJ\'i,BGfjcرBHH޶]jػw/)))5J^Z6mQF\zoooٶm]yپ};AAA;-- 777=zo>RSSbHMMW^f[!eS|c=f =mڴSN 6Lݺuc޽lٲ+Vn:LR[h7 ʬgaI"DLOX!0Ff EҼ ;;;ڴiխ[|||pttFԯ_wwwV^ws4oޜ5j{Wјgƌxxx`oo:ub…L03}ic]^>Ձ[./mB!ĽS2}ԩS j]cǒMhhWrss<4G1T;W$-BMYQB!3Dd<#88h}uMmc:u!<< .мyscǎ1qD'D !zJHH'==]{&Nиqcp 0v믿̥t߼y3ҥKѣGbbbXd 4lؐK3ۃtp9-Xi`y:vɓ'Yp!` ۓٳg $BY&`ر4k֌(,** GGGeB!~ ͍QF?hҀBBBݻ7ݻwגN`?CzŰahذ{WiҤ )))S{*zC fөƎK-pt .^H-]G)+J4B!df0KE3^{Ӝ2Ԋg޼y曌=[tRjժU !ʸf1c8p"ڵkǨQ #66777!..N{3z,1m4ٵk7n@1g^z%פI"##Y|9 Ӷm[ׯVo|ddd2^zDFF'w^\B&MׯǏ|8p1cm4B!dL+'Ofɒ%L2BwBQqe .75}œA<{{{ ,n+M*c(APLOX!( O|||: !Bjoر|DEEipB!H2!B!CHMcuV.]ĥKغu+͓4B񐓙eB!BBa !B!ZB!Di2X6lXU B!BQHβL-:thU!fСhѢB!B< dfCgϞٳB!B!dL!B2[a!(B!0O\\\U =UB'9ʄa&B!YeB!BǧBX@˄B!(gWa ++AQ S!B!B2!B!B!Ga !Bqt:s | [nĉ\~{}Ez:Juiڷoot[\\tMr !D%2!B!}#//@:WBJJ ^5Vz}|8...tҥ "B,B!B7f͚šCppp`ܹܹÇuV~:׿8~xUZ)gƍ̙3!C舓̞=7n("eB!BTNӖ<8pƍzjHƍQNNNL4"VXQU\|#Fhe#GDFFVadBqeB!Beyyyw^jժŋ/Ȕ)SYVglذ4iڴ)L<ڵkP\\LXX;wҥKҦM4hP /ƆaÆ1i$Xh֖޽{@:ů 33KrAnܸA6m3f 3gsή]iڴ)/ƍNm6F6>EQxsrr cϞ=\rMҷo_&L@ݺu (&&PRRRY&?> ,KNNСC2B`B!fPsUVV9oM֭g?p{@ȑ#tؑ;vGh"(:)**8]Ɛ!CHNN6:R@ڵk>>>ܼy3gҲeKj֬ѣUĩ*͚5'|[[[vٳ bٵkPF Znͼy?jԨ^jctYg}hѢ5kfeggNƍٵkn]v@޽njԨQz39}4p{@VZBa>Y)B!]ֶm[u LMƩS UE{=uTϟObb"\|||Uo^{]ra6mٳgxꩧt`si43gh8<.]uF+Bnn^ .йsgj|/^48Nɾ_>gfcc8p}r!0a6gNT`Wy^ `4'ZBa>Y&B!p%ŕWqŋ9uΌ5sgPÃ;vDΝgŊ 07܆(t,KT@cJXSߌ9q}Ϗr] 5[[[_y/۳Ĭ`NTw祖Y!idfB!U,115jۗOOON<ݻYf w=q:;;O?3hۿ{c:::rYmۆc饗ؾ};QQQ 0ƍm/..fժU(7m ǎg;vL\NNNt֍xRSSٿ?=^^6sf&MAVVM4ۦ.-].t2L!Bj"!!{t|Ѯ];\\\PU /… IMMǏpBcO,--"\G}N@н{wv;w$''[nq NJbb"=zВcp;wXJJ hˢ~ח_~??r޽{IIIaԨQzjժŴiBBBx駟%ӇwyGoرcٳgΝӞljѢAzꅃ/_Yo%m3QF\zoooٶm=z`߾}|ZlB!,#3˄B!c95c <<<ΎN:pB&L@ll,caggmڴϏW-=aaaxzzҰaCl;)JDfLh,ŸBm"H)dX6اaP&2nCѐJ"eI{>?3wݺG}9{;}?ZZĪUjذ! ###hjjسg f͚a߾}бcG4hׯqF5jݻwc̘1044& 1n8ٳ(e...Rqm,χ 455QPP4h4hhѰaC~v!iNB!ЀP(I奤`ذa066FxxSر8rLLL9|pL6 ^^^jǍOif!B!Dj())'Oo_}kXyxxO?P(ӄB!$,#B!#b޽;Fx4mڔl(OOO+WDxx8RRRp\R1TB!B!Zp!pI|8KQؘ1c]BH%T`x ({9BCC !j mmmuWʌ=g! ,#RLfBԋoB!2RRSS駟VWA!eeeʮJ/-ظq#PXXWWW| ˗/q?B4X֫W/0j(|_~5NyFFFꫯW_a̘1ܹs޺u !!!qnܸJsN,\ (mܸq?{n̜9S%U=uW&'|#G۷O͵R#%s瑓GGjjhkkCxx8.\M>zDE455allI&hPBH푛˗uʙ3g0}tCŦMSRR;v666ĉ^ VVV(**† `ggرooo }Ŋ+p=G /_ |$g֭prr ???iiiXj[[[,]TNѣG9s&z~aڵ_gu+++ÇGIIXϟ?YYY8puCCC~O?VVV8pwO1 IDAT+B!S`ٳg0uTAWWFFF?~<޽+s _1zhl:::hݺ5/^lܣG+?? мyshiiE2dΟ?/3bhӦ tuuѤIxc77vq۹-_:O֮]]˗8t6EUw;͟g aÆ/SSSL<>TY]5GeQlے0aA[[m۶Ŗ-[*߁SB!5ŋq ݻwE!>>(**Bjj*8um۶ vQXX\ܾ}?#BٰaBBBLڵ ǎ!""fq[ϜxyyĉDaa!-UL>{ūWPXXaΜ9RIdeeaҤIGFF p)iӦ!..Ç+owiرxot&ͅTEDDDC!X% B& _>;~1}g)s߯egg̿<111 /333Y׮]ˬ;v1qqqQFeӪU+~g 4`m۶6 V~}Sf_(R~yJ>Wvbؘ1c4E˭vۮرcy:}JRtI?+(۶Ǐ3===Ǭ]V%%~)r>>RS2WW20PXeL ͍=~沍72@k~޽{3@BCCY~~>gӇ v%VPPrrrXhh(lذa֋K7n{۹s'֖yzzO|o1@'waح[XAAv!Wufٻw0j(deeaܹx! ///UjcLf~]._ 0O?3w\deeaʔ)x! sΡCx)~JGWWxԬ{!99})sEG)gի6hnGe!n߾ RΝ \v >|ݻw1baܸqx >|ÇqFxxxgEyرc>ƍ0`@}QrEU*k&&6m kkklڴ ꮪB䙭^uyH=^'1;YdXXX@OOSLP '** W^EpIlٲf}2^  Azz:Fx݆ŋm۶с+ҿ077.>h=ϝ;AN]bҥRuYԄV\ 8qDf{{{cǎ|yK,QIy .gs֫"7ƨQ\t @,[nA__]vܿ`nn.GV!nS5k#sܹsΉeZZZ [`ض 9ի2gDܫ^zlRy32<|` 4K_>ӥILLd1lqug1???/blܸ`[l:FROnh>.W:.~lllXaaض֯_?^ZeuQ4]=;^2m[z5),,d666UY*r>V[{ݻuWWn|HMhfٿ*zyp޼y͋1N>lmm={@Mϗ^\\zlw^^Ծ۷oʓlWNNN =zٟ1&6>~BjYoenrqPTTAaڵb۹ecee>srLMM oر#cx%~_b+SE3Eկ_窺ܪnGeӧO@KK|A\ ,Xx8ghРsNDFF癣{Uq̛7O---,ZHf,UtN LbfwAARSSq!|gJѵdz:xWE*\pÆ wLMM+V\f8y$/_Ν;#??~~~pttÇnz@zr$?3fbV'0d^:ʖ٤͚5ȑ#q $&&"::лwo2e.fBHB\j##r++8L:O>E6m@SSSlG;wV~8KJJwb-\vI;w ..W\͛7e퍉'"66JaÆaСbT7ssstBFmmڴ)XU_yLQܪMRnU2se (] (}DWUuQ۷o1c >|*^m\p ~SBJ͛7G߾}o>!˗AAAhڴ)ҿK"~NNNprrݻwqݻ9rd)?~[n{[nIiddgϞرc,)quk*)Oq!_~vBHH5jGEqw6l|E^zhҤ lmm! ddffbbZl ggg:u &Mۿ +4nB!W3ߣq {=|wѡC2BvveTdXv- ڵѣѪU+h۷/^$1#Fq\x/^ăc̙3Z~舍7pqq hLUs3EpTuUݎοZul29ʼWi733##͚5lTE!::C(MMMEpp0p %w^L<|Zrr2֯_DGGC___2nܸR`oo/ Pĉ8y$1tP~իWѯ_?~0 pu\~{˗'۫T&׍L8q/_˗KmOJJ-<<>>R;x ,>k,rí&7qDmofX:\j_@J`ӹIKKcXF4eMVF3lذal ԪJYYue kӦX}-WTVÆ <2kkk(`FFF 2Ueڶn:ݛIϒmuȺ^Z)Tu-KtYi:5I*իWL H]Ƣ@ `...23+++ >ŋʊܹID'jWuŋq ׯr cgϞeSNe:::LKKݸq?ѣ ԩS1%KTΜ9:v+VS?޿?M6 1cKMMeEEE,11]p?{?i߾=`٬ݾ} 4`GTծ@YXX0߿c-QF eRYy穰z2L[[]pAl?eUu;$.UMqƱ$vu֯_?*e1~WȘrUe&:h7h vMv=6zh֬Y3~hLޞ={2,%%E;w0[ne{֪U+=)9۵kW@{< &ihhȼS"XQm۶e ۿ?{y(o1XsZ`G޽@ `,##d6m4&]#''}3@O没CiׯgÆ cyyyU]"'>!V2;~8+Ol@m`` ?Hecc#D g///cwٲeCc222X<Ą=}R&.Q^y7)^yR9O 6ylnX֫W/:[B!B!B=I!BH-˗/iQB!DT>XvE?^BcLU R nܸm۶`aرD.]]5B!Ve!T`YA!<,[ FK.Ehh(\CB!0 !)!U+44V`ee2wލׯ_oƍ?w̙3.BH]CeB333=Z =z4zj*YYYٳg-ZSNEÆ JJJ@[[[3.߁Э[7~)pQFNB!߿/B,(JOOe.\(w;71tl۶ عs'w^U2#Gď?#GήObSu(`}!!!!u ~*AVz||<Ν;AN;w7[={E J IDAT/֠AdggC("995jF%Ruhժ>BQU^h֬fϞpܹsGUA_~ALL ޾}-ZH;DEE~2djY(.!u-#j9rDUU^| tLW_}x6g|2._ L4 _>߻w@fL2.ۇB!3޾}_/^D^^Zn & [nn.7oޠE*gC纬Gtuuannש9ܹsllkpvvV&IEse7UO>͛7Vra!8prr޽3g`޽Q7oTdddybsBB_ / Pfqߏw/Dpp0\tqqq ~/ʊ 0ǎNZ#,, 1114i+˗/ajj{}ay~hݺ5:wvX>ׯ_Ѿ}{tA9UV"pg K-11бcG߿K.]s!''xmVT>XbE7\̞= ,@tt4޽{$$$`pvv]Mo=`͚5HHH@QQvZ@޽}aeeC!77m۶%@[[ߏ[ٳgRqiB!D~6X&:%Hdd TmmmtK.722@%455aaa+Wle$%% (c…033.?*33]{{{cǎ|{,YRaފ#)o /@Vuss{<% t5 28\0\8{13%V`;'!!8x{{ypq8::(RWTGҥK044Ċ++W𳬳h"ܾ}JQSI.|cll/| 033˗/1i$X[[cҤIx|ܾn:Ɔ!/JyϞ==&K#Bbjc1.)G"s̼=z$w999r ~gx{{#33Sj%"ynݚx qSn$deQ?g"33ę3gаaC 4H鼁8H0\NELp z1 [n֭[EEEb7ԥYf?>N8{:ŋf͚aϞ=b3ԍߢA󃟟X[oTAFapyyׯL_+tkii!$$Eajj޽{i@M7oFtt4&L V^tt46lBǣ˔ ]VR}$egg[E1ppp@6m@2_26_^$ۢUQ:::6lߏ'Obر8y$ 0b,eVJyKV0\NELp !\֭ҿSZE7'{JXbbbVZa„ 5ɻMew ȑ#ajj?/^BXXLMMnc2C9رcCvϜ9P$%%!??-Z=fΜ)3"Xv-.\3f̐)%oCY6oތp899aΜ9M5jܸ1.\ V/%Bȿj2SSS<~nB[nIkddgϞرcRRU[uQq> 0ƐoWd$SSS$''beML]\\  qQ;G+U.||| tȑ#z*B!!oʞ_~B;vc7?P BM͵#Bj6vZ$&&o۷/ Ѥ$#-- [lOݍ/,OII ?իWiӦJ~!99֭S_ 46QTT;wয়~XE133CnDDDڵ+,,,*$yJR$(.!/`eg1QUh,nݺaРA&L""ݻo߾E(1Tnʣ]Ǐs1݊7-- Y7?/FLL .]~ A/EܿEPPLLLKs9P(n8oj7===\HIIAJJ ñrrC]B!b5rfq)<}#!!A.Z1w\MݻwpqqxGVltPG4f=°yfl޼dޕΜ99h ;i#G"..6lؔ[֬YuI (ʊA'zٳgsʫgϞpʦ`mWP+((\ |wrN:aڴiRDc166~1Çĉ/^,X?NYwΆP(Drr21jԨrcۣYf󡭭"DFFvvv WSS>/KTTcwN<ի ?۩S'`̙8wf̘PC___۷oE ~3gĦMf*B!Q`Yywm۶!** ٰ/_.vAްaCa׮]8w^~ }}}tӧOG6m}ϟ۷#55c@iM?&L 6`ܹW"##+++,[ V/ttt[̙3A>}ӧO{"eoo͛#-- ͚5g"oQH0\yQ0\B>>K6loիʬXU puČ33 > YEɓabbt~b,ܪ6mBjj*aXYYA/d.@iLbxzz@*Ι"A׮]xzz"""YYY(,,ĝ;w0g\|={O-66HJJҥKtˊ^(,,ĵk߿˔?~<:ߟOo!BdarO<'O| lll%vEQ0\B>.,.b L6 9r$>s-2qDDFF"!!CWt.d.@B+x5LMMѽ{w.>n:̘1?Ty}ի7lj'|rPtAj/ǏWLyϡ(MMMx{{cɈŭ[йsgZFNǏ;WBj`Yz(X)R"!98=WeYER׮]1fڴiOOO׏߯ ( >FY@@\\\bf)LfͰo>Ɠ'Okkk9Rj0(]i(..F۶m'O Th1;w_Lf̙ULyϡN:aĈ ?vA !$$DU b=zPw!J`,$"88ǏJN!z|l[{ ;v@`` 9"1m4xyyIͲJ^ihh@(7BCC\#BHm֣G~!h5rf!Bz8~8B!4-|/eW@%48FH-FeB!)np믴?eH .U6XFw!zBe7B!T>XfffѣG:[B!^BhB!|W^ի%B!_˗/B!qBQZ BHE{\pRnܸm۶`aرD.]PSB!UY̲ʚB 8r䈺A!p<,[ FK.Ehh(BZT`!UXXHejt' dҪmvލׯ_oƍ?w̙3X;B!zT`!WRpi?>,--c@nn.7oޠE^"yriVj-#GV3!,++inn./^K.'$$ !!AAAX|9u[yAe%իW éSm6tԩjI&rE!^zaFbaa ~vq]|F֭3Yqqqgn +++ĉXn<ɛg||c111K՟K2B!u^ٷ꠲ҥK044Ċ++W <<ƢEpjqUֹ󯘘߿ŢEWM58q}_$AE=R BCCquWC^أ5kʕ+'NmР@("$$5jTܿ`nn.UVbB!ufՔG.^h4k {`llo 4~tuuѮ];/p1zT ¤*j̄T-nQ 7y9I=3g~\|/_?&MWWWԯ__X~= ;;;,\b`ݺuD-*U E1g @+Oehkkވ,S~*IKKq_K!&&hժ&LGGrϋSaB!u<3+1Vn5Ο?G֭[1k,HEECCd5Ҹ}!F /^Ӓd(T6)heϞ=G__'OKɓ̧"88qqq s6lǜ]v|qqԫW+V;~^~~>N87ob000P^ӦMCFFÇQRRqEy*cC>MӗU,L4 /_9urrrZ{x-̣G|rcذa2zjSaB!3###<{ ǎQ NNN{.Μ9{ח[h7oTdddyb۸ tB!.1˄B!^xccc!662g~2 ƕ+W.]L;}&&& q߾}HNN _@ѣGسg1?p%L>n:hjjÈԩSQQQRsccccccz TL4 @ʠyX<:h֬<}v/_{ۢUY޽{[taaaˆ#AAAe"u B(,^pA~?yRɊ[TSl!LܫgϞpuuU2$VA W1`,Xʣ`޼y7o=\C@iܤ$#-- [lΰ¡Cm@{efqnW)T}V'Bj,S$*Ͻ:ummmtK.ʷL555>:Yuܹ3?ٳR,^m۶\]]>|7͡ www޽<ԩ?[Ht0Dz-\fffgdffەTVqq1@KIOv?퍎;%KHU_x`AA||XbETlJJJsabRE{U,Xc֭yf$VZ!!!nnnѣ ܹs}=<<d ҵkWlڴ)ŅY=i(U_.wުB!Farw+tыNeŋHII}c=F׹sg}:zJ*;qBnݚY4$kkk߹GEWU^s *,AOӗUn.N:'^]BLA QUbI~6oތ'NG>}TV|f͚s=V!nSoeB\T_A2֭ Gro_k׮]V]OuB7ֻj4WSiːW/:5T'O [0˺ܟ:E]!"RJёP,m۶[;Ǐ{$uqppPoR&mM6% kג)ӄԾB!E re ?#gΜgQ9sFmm 2$:tZKQVVի)//gذaD3/^Km`J_ju S_n~KII xyyM!.BVV'O*lv8??̅ ҥ"RDX4T$ݻm۶STTD֭bƌ2ij"muۍWuĆ֤?]c:6۷ogԨQh(|}}r ۷olCݼrڼWʹ\d g̙9I b3w\B6m0a{'BԏY_Y޽xb233)--ٳ,^Xmm ݛ=zoLrr22k,۷/ɚH222(--%##Cc]sxq)"##%u/cαU?d֬Ym۶Zc6˺?T?'Oo{Om]_EtRrss)**>]-O]!"¢!RcwAii$|'[8q[nQZZJnn.[laɒ%޿L/vÆ \r5v֬YJ_^^Yt)]v51j36+\| 222g,CqE@9FRRܸq>cR INN6x`ooϢEعs'999sN-ZUNA!5ȕeǏ端ŋW688L5+dz hӦɒ%KxWB;Cu<((}qe5uPꪳuG.]3fL˘sl EU)_Z.ϐsY0a{j)TLU4ˤ /ԩS|1} "22%K§Ywo߾z/L-mL\0\{PQ<7,,񝝝NٟKa{5fϞ}u&~E^^ .]bȐ!zW&6cdcc/֭x{{sQn޼ɴiڤMۆCGGG~iNUL6l޼9#B!ie0|||h֬.]R>S74>ŅСCvѣ} kjZ[~)ǪNMX`AAA,^-[qڌ_| 6_MRRVVVZUWC/c<5 HB!idСC,YYYj]M%+!(;v`ԨQhHɸ˗/ T٬_pΝ?MOqwwg5{ɤMll,s8)cgԨQ=zT {L6ƣOǎҥK:b:ldzcKwC!ANYYY@@@ ZKs0wPERR:5{So߾hUfh%+ޞ ¶m5j_ڥfl'''^ ̝;wxǙ0a?lݺU䖡={6VVVpmY`C vl+44+WBSRo׬Yz*M6GL>]|Mzѣٺu+˖-#&&ǨQjS˜>ƣL8Q9I6Lbb B hTnL ?^-[Bq}oWfڵرC+uxȑ0e9~x"EYFWW;K6*h>B4h'deB!=JRkoȑ˭h5 !:,۶m[]Z!+LRk綾^eB!}&d&]!$uX!8f,T;!BEry:vh\¦MHKK#77[[[ 0c`9Uv}]bb"iiixxx"!f,;r˗/7nBHۄBX›o,RL:u[qq1ϟڵkd.uN:ELL [n1cƓO>i !=;|B ضm| !˖-^z@ZZG':u"''3N8aD!n߾͂ M68;;}vW!GuVLV6!DJHH`BwLNhޣESOGd-jݺu\zcǪƍ͛Yn3f̰`RgeB!%4j]' WVVFll,`kkKeȑj&*oWdRRRӓ^{֭[֐Ʋo>_N֭fڴi4kLgo>:~GGG~W]N)\]]c /вeKoߎn|2~~~mۖ/BKZZQQQ|0zhO͛7y9tߟsҴiӪ*U^mٲ(222hܸ1>,f޾}EGGsNFYg˖-S6GywwwlB`` >BK&˄B<==eU]kİqFqII gϞٳ"g׮]ӧٴiN|C޺uɓ'.77ӉI&Z"??bƌʔ){L6_|OOOx lmm2fܡC߿k>o߮>^f m۶e۶m;wN=7wʊ V9&cpM9eeemGO׮]6m_5G}>}HOO'99QFBq?3{ͲU>~fϞ}aҤIlڴzCy/Ν;;C ה1|p9yd}t2\˿BqS&hVXc8taaalݺ*Zǎ#..ggg5IҔ7n$++mDZcXv-\p}]kef.c/6l`ԩ 0W^yDնǏI&:R&맵=33͛7sQO%K?'55URa.ڵc2i$}}XBLMMs:Q)mB}B8z 222#""//zMҥ ;wȑ#:W5?~ڷoO=GR0͑#Gf$ xKwbVy'hҤ n">>,߿V} SWu֍pfΜujWV [ntޝyꫯo>N0;;ji}||}ϙ3ghڴİ0qի?7oڵ 00Xu̝;W]9~xiEBB\RkrY髦G}TBڻVUѣGqrrb…$''sqvIpp0n⭷ٳ{WBY2cǎj_ ??X:H!)GB^yy?H2̚5ƍG}>XTTTzxxh=V./&*&4=S\rEg$MuLΝ fݻiӦqE>C̈́ hܸ1֭ѣܹs޽{cc&cǎ5o'СjՆ1 0}wS$$$5~wnܸ&Mi#,6YV߷Uȑ#>|GGG֯_qttggg^}UOΝ;wXj{~իW'(((ԯpttdԨQ:uL>ƍ!砶4kUB<@yy9WzNy*$F!̧,vx{{ӻwo&L@rrIBVX#ݻ7ÇgժUZ_04_i```Inj+„ l2 /QQQܺuKrR>C̛͛7OOO… )((yo'DDDX2_.\`ƌxzz2h /^ɐsl> 6;wIe_~%WЌɓ'VkUzjݻ7_Yߝϳ!)GR?O!8880b֮]ƍ "//(2ѡ… U3##CS_bR[gggN>VyܦM*RCƯ7p%@w(00;;;nѣGo߾&Ւx iJ@V"lS!9YVPP)SHJJ"//{͛Ӷӧa\BII 9991k֬ +VVCiӦLD c͚5ڵ$''STTD~~>wfҥ:W#))I&i<0_!!!STT͛7ϵrkڧ>ʭ;wԺP&rjSLL k֬˔PXXٳgywR繦B;B2 _O߾} `ݖYjt X닻;}<㸹+Zl T|߹}6YYY,Y{dffRZZʩS*VVIFFdddxb@jʔ ˗/=qLJ~ȅ (..֭[:t9s0p@c>CW_ѢEP?{ O>DݮFLjRij*vdY||< jOllޕ_6mܹs<$$$pqy'IOOgΝU&\~mGSjSWIF5%z gUE޽;?3wI._LΝҥLm*AycggLiܸ1%JdS$4nXM\f9iUпR_39ɔ~UNmR Ǔ?'N;٦,)GBcUСCO-;󩏐 XQݿQ???"""ԩvvvѡCyvgߟ͛cggG>}X`Anj8q"W[G̐> ֭c899ammƍcZɌU m۶X[[%1 ?믿NLL ^^^㣳ݐ+<<,;VJUcC> ig9Rs˸kPKKKzU Y|2={O}}}ٳ'?Q㕀!N\~ yiF'L!D4ȕe...㏜9sgyFݮ\5ԦM.]Į]LJ2dIII3tPWȗ3l0Mggg.^ӧիAU壪$#sX~~~_0f h_JBӈ#8w{eÆ DEEօv IDATSQUVrM4#I9~ܸq .;wj i?~@9Ddd$K,щgG]}rA233u-)GBO8#G3g@ń!*өqjH̙3ٿ?3f̠yqF=J>}̙34mԠ_֭!!!: EqvvPCQFIRR#G0<K_ʭ['++ ///~+ptt$%%Plmm)--%%%'''u1㕀q71XQSMA^5,L!DݰʲR퉍eĈh+њ_5kF\\ikkkbZ+q%@$ƍyڵ+M4iӦ 4UV,m6Gb+ɨ2cαz/^^^jՊ?GGGueLB8ϒr$)5}~aHH˄ hܸ1֭*i޹s޽{ԭ,ݷo;v֖!C E\Liz/dqƤGU|}}S?/=͛79rĘJB! WAVDDֶZn7x7x}V* Z cW톞cCY{#je~a M^o,)GBԍתKìmFu!8::2j(T'jZU  bŴlR"1(ƞr5.(xxxp Μ9êUشi3gάF؋/Ȇ /&)) +++u"LSuWVB!4КeWHQVVO?Q q#!,W֧z( z/*غu+Gʊ}N:Hyy9i=i׮]:I'N ==]mkyP& m52%deڵlܸ 򈊊5xxxJff&bZIƌW OQT4IB!A,:t(}:R-[dڴiuKR}e.]Jdd$-Z`$&&¿/vHyt¹s xxwԩgϞCg}Fyy9ݻwEɤMll,sd3w\q6mħ~;W6<('wQ]___ cС<@!+PQѣj-uΌoǎҥK:b"mVG!B[dܹsquueϞ=OӻwoLuX{f )GBԣ_~222xL4%Ðĉٶm`\= .$$$m۶1j(u1(///oNttZ&@ 10!+Pq^z*...<3Z3^ Xٱc;vt7BQdhד./Dݩ3UV[;FQQ= 4Hm|\~VZ1h N7#** #?|'jGVo5վB!ĽAN !"YCC>4pڵkGu"ʜ9s3gvCCQ`ooOXXaaa.BVMVmiC++*Gtw^{ OOOKwCaY_!ru,jGV>۶mSoBcl۶˗/[B2!м͍Ç[7 XUBU. d|8!qrr͛t_!Bu0YIbbw+Bܕ iIJJÞCHB!0B!fqy:vh݁/0Ҧ.{'&&I!Dcɲ#G0~xsV!-!7|Zl2nq)bbbغu+3777|IKwM!V/kBQbB9x𠥻ݾ} O6mcl۶ {{{ P!mB!1r+uk۶mR׭K(֭ի;V6n86o̺u1c{'B!eB! K^z^zYw2bccINN&''[[[:t耯/#GTU5Vy855%KknZ絆'66}quZn7ӦMYf:%44777~k˜}vZRRRhݺ5C aʔ)U;իWWۏׯrJ<۷f޼y:ٲe ={I#Ζ-[ iBad7nLv?~<Æ `;feeEy' v:w'N䡇bXYYUٶ ___rrrG>!=B~鉧!ZbbbظqgrY L}g׮]ӧٴiFu'O&++K}]nn. G&ME~~O}ߘ}3}tΝ;!..LbbbtK264i궯_5G>}Nrr2F2!3U0܃|M~ ,\Pj03yd._\'ҥ ;w~ȑ#ն=~8999o߾&R(vΜ9b N>mn QhԨ?H}Dm߾+Vp1:DXX[n5yGa;v8r 6m2ƍʢm۶q1֮]3.\`:m߾=׺8x q]ߘ}oڴsOILL'$==;wV;|dgg† 8vi @ΝuS)mBX} +nܸAtt4III| 0.gTC/eeeh"N:Ś5kjaQFc_e_@ET_B[bb =M&ʪ+'NФInݺE||N0AF}j;%%HɰE1rHtn4dl`޼yt=z_]h׮~}Q6B!,bewC!TGGGBCCIJJᄈtw VVVmۖzcr:;裏HMMڵk:u7bСC< VZsBBheBԭ;vX wYfoFZZ| &M" xzxxh=~'_LjFؽ{wO=W\ٯ2SComm͝;w())Vg?EEEj;c0b}pIcCeQ7M7n[L٦BaY 6k׮7{f„ $''sծ+V0bzYjjGUJKKhԨsWqUϟׯNy|I>}I~:4h}at4)Wn޼\aa!?uo鉷7\vMmgooϰaøsZ/R|||/!iYYWϏ޽{ӿ^~e_,[aÆ /@TTn .0c <==4h/ZPl~~s#B(jnXvCDDݻwUV1tP>s}]Mac}ͻ @oWcVǐWy@wf}rrrosOaMsߕQ~wޕm~BQmL2Ej7UƔ(//ƍ,[ @]Vmq^~e~WRc*#5(ŋhժsaaa=zJHHsj3QHLLdΝ|P&(jjZS 熄EEE|甕HX!իWIOOV9WC ;p6sKrpp`Ĉ1sαw^6l@TT3QFSPP&O[8u_Ljŋ9}VکRU)` C߾}{nܸAJJ :Pn 2tmڴҥKڵVŅ,N<},33SmV͛:ߑ{; ! reY||< jXi4쬪&e5;={d$''cmmԩSM:.TL_ p!s2UbӘU)--ww:m~w9|zH!h;t@'Ore:wL.]>USS ՚R8]vl߾T&MsP7|OAAZ+Z-EgjGBP%g}Faa!?8nnnZlwmXdI}̤SN T0PQ+##R222Xx1qEK̀'CsO?~;wpU6o̚5kxzl=w|Ǹkݑa,?rQ[[[zuY kkk`'@RR}橧bʕ:W9nŸxxx謤2HkO@iu4?9wLkggg5Ev!JPPK,[NҭLVEGGӯ_?FM-ܯ#xxx0uTrssҥ cƌ1mPPdgg3i$<<<4iW\UhWeϏÇ5#GAII 1C W^ :e˖Q\\ /ט}裏 իO?`5*&Lcǎ2m4<<< SN:m _ul3dRR!Dka*WV*0`gU/yyy+\t!C-Ƙ*Q+\l*#5(5ĉ;|0͚5SW !z,%:% e+xiJΚ888`Xx1-[Tor\kkkJKK *ew$ciLRMƮ 0OC1|p6mĞ={3f {졸_|Qk^}|||9sUVi&fΜit} jB߿¼4/3KyeȠq<̚5 {{{u?ׯ_gʕDdd$K,љWWOu:Er -[Y߾}9x :ǖBBTWwRvS +!P+..N+rp ښnݺRm3\2rH[99s~+L/֭[Ǔz?^^^8::Bhh(ZȘJ!z駙1cK.`̙~BQ,+2bZh nnnk/J΀ڴi5xyy~zU5mkkkуѣGsckggǪU [[[OTTfϞ?͛7Ύ>}`ߟ-[bggs=W_L'6668991qDV^]e3///ZjN90|TϏ:uꄝvvvtЁ`~*_=z4NNNX[[ĸqX~As+#ƌC\\EEEUצ IDAT___ϴGrMF5`x%E܋I$_a-[Ʋe7n# *VEDDhmuZ -YUњD̙39sl7Pj+_mghqךOC tL}joµPr>(jH1Y}m\)+L 1TM!(8cla3 Byٰa_~%$%%aee `x%E!BA,߿Z*//2~'uNMW䅸#nBB4 ...www?>l ?y)..֩sfx%E!BAކL޳g?<ݛ)Sh]aBHX!*s+p_&%% ^x) 15*BIz*...<3Z3^ A0~xƏon!52+++tW]%4!j>?c+Vw^ 0`XԤlݺe˖/d͚5߿WҴiSzy}jՊuñc(**#88AfϞ)))ܾ}www,X!C ꫟666$&&Tܒگ_?}R,66???bƌwDGGsa&N AHLLtw^zY B5*Rn ?~Zpc!~<+Lzj֮]ˎ;BPFIHHSLp>*+VfwF^|ڶm{$ WWW@EѠh+˄B!!((ݻw&K0ѣ-!]L&DŽ{dB!YJ믿N`` ;wd" " !LQRger%N!.$~"B!a2WWW^z%sV!D WIB!0'<==4nB! رIuwwjN(6]m_HZZrB>Y ! IBQ|Mpz9N]Oݾ} O6mcl۶ {{:=B&ˤvBԯ,Ck۶my➱n:^رcmƍcͬ[3fXwB!,&˄BK:3BK)++#66drrrC2rH]U*oWdRRRӓ^{֭[֐Ʋo>_N֭fڴi4kLgo>:~cTuNlBTT4nܘg}YfU,::;w2bf͚E~~>[lgϞ899yٲe <&]!ݫANZSٹs'~-nݢSNx{{+?ꀾxM=!eV_)&+HڡbbbظqgrY Lk.HJJlڴ ޺uɓ'.77ӉI&Z"??_kRƯOHH7oTSVVFxx}tڕiӦ_SXXH>}tӇt5j- 'j0==## ∈2Y\\V a^Gaeж}vVX;%%%$%%dnjdֳgO;ϟϕ+Wشimݸq#YYYmۖwyΝ;s9,X X~~۷oO\\vvv{1ƯOvXh?0k׮%..,"!!۳b u"055Ν;Fٖ*eBqt9qɓ=z'''.\Hrr2ǏgΝs-z-Ξ=k^߿kC;vmT.&}']RLzm6?nn4H$L||F!b+▷#GpaY~2qggg^}U4iªUXj|َ-1uGҘ[\t7RjRΚ5~4O4i<&C뱲 _~1mvv6ݻwjSOpck:>H"PCbQShCBk(ڢ#5gQ%AƖXCIPs"g\;ɽ/]8)y~kJ,iݔ{ŸPq[nQ@㵛7oX-bf#""ϗrfDBM:ud=vOr̶[t߾}L<ד-[6ٳ'ofܹggg֭ˠAș3U|Ֆb,\-[?~4io-L- P['w~+Wrqbbbȟ??գW^58cqfbǎܿ &b"""&oooؾ};| f,]޽{[,狏$yld7%-361k&f$5^Νɓ-voLے;*O<Ysƍq 9Ç9x cƌqƩkjt5f"""x!;:uxWϟ3Z(UYS7bӶt\/Òe(Ni{B urrBnMj2ҥK₿?7Cx⸺ҩS'L%?=Tt˖-ʔ)%J`ȑlܸcFJ|;w/_M61m4Ə>>f?Y4H阶>sk_NΝܹ39+V0=*Vhv ӳJHdE^Oҍoyi.ebg|7T\{` MI2|pʕ+ ...,Y@>3c\~hӦ /...ԬYaÆ%yɓ'Svmeˆ;wfܹV26w,Z???<<%J"ʨ⫉ʕ`)TNNNS^=ThVI̭{x{{憋 *T`رt7)+ϟO6mȓ'...[F/!XэW?-[W? Ulwd[HM崐N` ԩ{Ң/J(ݺu0[N4hP>m۶p{ꅫq(ϛ7۷s GÆ ֭[]뇣#[lxzz2l04ib6n̚5+W5L݃,Xm۸v9sJ*Ӭ~j 8k.(]4;vٳ̟?+VPfM٪qL:]vѹsgԩ!H&pTBCCСQ7""1z%͝; fNŭZG41$$Y!!!-"iN/"YJfNjH%V\^++dԩXTLDҋjd-,KC u*~F@:$ODDD2,#"""|Kdُ?""b#͌I=Ǵ>U7GD$\R""""""O(jifH CHn2!DDDDDDDD2eO>aǎ?U>x 3gdŊӮ];ʔ)CJ2>>Cy))-""":@.-ڵkor5-ZgzfիW={6wݻ+tܙMblݺ7n?~4h@ɕ+1˗3yd"""puuQFטu#ϟ͛|2Δ,Y-[ҪU+c%{xx3`ʔ)ܹs$dm{JםԹX|9ժUS`A<==Y|9:u"w=,Mݼy_nl;uÇ'..-Zp]{=Μ9cr ߿`rav=zpmbbbXj="((3gW_ccc__wM&OLTTY*-ۚhj֬iZ͚5ٿ?7ouv$""YGTruuxtЁf͚epT'҃*Y IDAT爈d 2ŋsuʗ/իٹs'Ƹ3gPHٻw/ .pœ:u/ŋg޽]m6իW0c Ν;2d+V(!D޽QFu'uݻw⸦m1""|9q#FԚYy0`3fСCX&~GHbȑ#AAAgJrQbEy:t([n8A(V,;wfƭ[hӦ ]֦;v숋K]58+b6FDDmSL6ol,_dI&Gv}`7)\cɓ5kp}Μ9øqR}mZ[״-5;EDMV.]Jdd$OQR%o#GXl{1f;7'''VZݻ޽;;w4)afhi&ձy jժѸqc6oތݺu3k9lmc̖f;=UMu҅|Aͩ]6aaaf?PX1.^H׮]k׮\tbŊ.L\S̛ĸYgklٲѲeKܹcoٳ۷oӪU+R;K֭[)[,4ij1{$hNzS5z2fYf)\0cƌIq /A4hP㒪fm^Yrnnn 2XBx[ڹs̉? .ŋ)RxۡCѣ/|""YAIS'z$lb~BVǦT,)ϼ;,^ӠA6n܈Ş;Æ # cǒ'Oׯo6ƞs(&>>'?3oooؾ};| f,]޽{'Y#,署爈d=tL  1!!!*T;frt""PB[.Ս_leO… ݻ9r;w74뺘+WN:_2fVj6ڞsڈ6IMj#"""d2bꏤ#Gdڵ\|˗/vZFI3;<LaIljƍL6 OOOZL֭#00E:{"Ep-ϟsڈ6Iَ5iyO6lHn,Ϙi͟?___Wi{*UcŊL43g}S#3gw^bbb(U4lׯ_?ٲe ӓaÆѤIb%[lq-J:uII{ڸqcNʮ]ܹq,cf """"""""2 @xxկS/1WWW/Nh֬YFl/i!,,}兟_SD' 0DD;JdA7'N`Ĉʕ7|3CR<̙3Ybk׎2ePRM$ՒjHH\(Qo6;w5K4Z8}t:D/_9x`t7OD$+SLDD$ H<͛L:7dɒg&Y3߿ϰahӦ חO?+W1dGq:ġCشi!!! DD[Js%#y2`6nȱc2;,eѢE\v}]-[ƢEիW&F'z!=Ç3gIf6HFQy}Wxzzh}xzze>>>xzzyf~zIzyL8h:u* 4`ԩ6!EGG3c |||Q-Z`>7o2i$*T`ٳ'ƶ˗/̑#G9s&pucS>|8qqqh¦3׭[G߾}yWYnnnnfksYݩY&}L2Vwi̙Þ={qVZݛW^yb\;w>̙3ԨQ[Zg:Y%af̘ٳgɟ??uԡgϞVLNF=Ke""+T?СCY[[nёݻw#Gx7ȑ#˖-`Ȑ!޽={0o<ve'OLHH%J`ƌV6͸Zj4nܘ͛7Dn.]H^{5BCC駟 RJ߿kc/^)_f;^z5[fӦMܺur͛Gv잽 Iĉ{Ѷm[ 8_E\\۷oCI|||Xlϟ'66(=ʴihѢY"%eԨQ˗~'L3j'OC\ʕ+i֬߷ cHFSLDDi L֖ fjOܹs-[Ï?/YV~}P|y6mĴi?~<wM1ɓ';fͲ: '''*W̬Y,G32eD%9r$Ku 8bŊ#G?MXӱcG\\\M ¸umڴ!<<,Pzț7/[l!66xܲe ԭ[(^L3*LcD_ѻwoݻG׮]ٺu+|״k׎Xk1{ `>vX.\ ((8ٱc˗/xDFF#̝;GRti8z(ǎcժUT\xfϞmν{h߾=[n~ѣRT)O-ѣgFr1>>Aqmc6s\2Vرc|w4jԈпn޼i?裏QF|?~oF͇~ȟi5sαi&>LPPo$HݳJ?F]ǏwMLL }5dhJ5Hm޼WWWzꅳ3=8Yh$j_NΝܹ39+V̙3_R gN||mQ_Hn*T]7peҥKsiclK#FÃ+&L&M2bY#=z0{5ѣ{K}Zou=yV %־$YRD$y{{s!/^̽{]6kf̛7wK0|بs81ݫW/ 9x c͚5iذ! 4-u_?{F#Gꫯ&ORMK6brN_S3M,RmyoO""O3, ht2%jժ`,MWž{?~O?~ΝۡCk؜9slޣH"ܺu盽fJqqqӦMӓ={cM6qD\BLL &L(5kp}Μ9øqle˖xzz_Mҥr uȃ^rSkTyR0q+V`Æ ̙ /X1JMqwwJ*L2>w2aq6l^zԫWݻ3k,~$&nݚ9sp|2VW^x{{s'oOaÆԨQx2Q&L˵6Wwk>`m)ꟘZGJuƜ9sk׮5,Y&M/'OJ*EÆ ooo.]Ğ={gϞ=H?}{R߿x<+lV?0I꾛>IZΜ9sQQQI5}V&)]-f2Yd,Jey{{ ,K0qIooopqqB ;ݻgآbŊL.[gUR???⌢x@pp0*T'''ݩW_~̩|h"ɝ;7`4mׯ_?ڴi / 5kdذa6 )W...BIDATPdIeQIIXע=۸qcraή]ȕ+U$)n]|ܿ}ҨQqĉug͚<yfG۶miԨGY=V…iӦ ƍ7YB.I'g46:tS<1rӄc+#|Mcǎ4n8.&^^^DFFFժU^;qM4H"ܹ 23L^CLLnݺ\xoҥKcmhjۓ7ngΜy|,_QF}АЂ e&qqq̛7~^n]9¼y]YGCӲw[jE>z옩yVZjf<MfKdֳ(Y&"""ϕ ,HHH-$$B Y<(Xǎɝ;7?3>|}'|Ygɒ%+W'uC_3qD_ٻw/}@1… ̚5X `^paqBqI `${/-Zw4u ĉ27|ۓڵkK.套^bԨQ& .̚5kزeoG}ӧShQڶmkС9sd߾}|:uXN:|O?[u3%;∍R _~9sX"## .\??cˌg)"4LDDD+nnn9?uڵL>ٳgrtKL:޽{gQGeavƌ:?<+¨Q׿Ŝ9s,gW\٬yEB:\&֮];Zli|ݽ{w 1K$d9wF>ԩSf7^zl6jjerin߾?~H!gΜ7>SUfQklƌ|lذl{7oƶ 2eo SL1f^㧟~O>fוgЈ#߿?֭3۞7o^ΝKΜ9SIN3DDDSjUzĉ8q"{NрHBcmۖB -[6rMڵYx1:t0yѶm[-[ƛo;Δ,YjI /2͛7gѢEK۷oĉ)_<...ʕZj`g$lBCC}r_|@RȞ=;NNN/^[$oOb\z;ZԡU\~jsM?O(Z(ݺucӦMV;6lؐuѪU+<<>>>Whh(:tm,">Lf$:+spp`ʔ)Fm%K}->5 ?I?,Y ҵkLLDp,/%DDDDDDDDDK2R7Ly\2Cy\mfv""""F2yev""Ee""?,N5DDDDDDDDDK3DD$KS2̥f"""QLDD4(ddIQ&"_~/ d3fDi*UDDR2+>A6e|||2;  J$A̋%Kfv""I2LRLDDDDDDDD俴 SDDDDD8wS}o%""+o?1ED٠e"""""„ 4hS}رcҥK O|\y6(Y&"""""?Icbb1c(P5jӉy㋈H֧d/Y7oҴiSc[ӦMy&k֬DDie"""""ỴGXr%{?$[l+VӰaC111Z{rMC:uhݺ5f><γo>;Ξ=M3N>m?Yz5'O$((GǴYlbkL,_իWm~:6m޽{'}ݻwCJ,SR%~W[oeuȳG2,`Сk<|;w`[#1n:N>Mҥ֭ŊҥK̟?_m۶ѰaCR=̞:ƍxWCvel3c櫯">>3gΰk.~w9@tttsgϞp1m3痒e"""""YLΝ={6ìXwyf͚j|2@ϟ?1Ys-Əϙ3g,^Ov_{VkƈK2;$1Sf͚TXuV~7/_ywe)%R1Y̙3g(X ժUhѢ*Ux^{j66y~)Y&""""ʕS~}N>;}oXx*P.]b֬Y(PੈɚÇa}_|ׯŋ/hZTT1FDDoiFDDDDD2L>}cPxq^yeoӦMٳ~$M\tܦm1""2,UV̟? `ʗ/o68qsuu% ݝ۷oS@f͚.1Y;oΝ;9s&3gδ8ٳgT}*UΩSb8uUVED٣e"""""O ,,,C4jԈ>W_}ggg)Z(ZwƸ9r0zh5kFptt$W\TV/lU.]ёtytB͚5ɞ=;Δ*U}Ҷm[6mڔ\cZȞ=;?E?39rf͚v_<[S)""""ppp`ʔ)PdIٰb V^͌3ڵk|ѺuLWɒ%Yp!]vDD2ynlْ~zc)P͛7DDie"""""/]QK>?>ٳӻwoƎK-ضm׿puuDDidBase-1.9.1/docs/repos/Me/myclass2.php000066400000000000000000000001441320724427000172630ustar00rootroot00000000000000Base-1.9.1/docs/repos/You/000077500000000000000000000000001320724427000152315ustar00rootroot00000000000000Base-1.9.1/docs/repos/You/yourclass1.php000066400000000000000000000001501320724427000200430ustar00rootroot00000000000000Base-1.9.1/docs/repos/You/yourclass2.php000066400000000000000000000001501320724427000200440ustar00rootroot00000000000000Base-1.9.1/docs/repos/autoloads/000077500000000000000000000000001320724427000164505ustar00rootroot00000000000000Base-1.9.1/docs/repos/autoloads/my_autoload.php000066400000000000000000000001711320724427000214750ustar00rootroot00000000000000 'Me/myclass1.php', 'erMyClass2' => 'Me/myclass2.php', ); ?> Base-1.9.1/docs/repos/autoloads/your_autoload.php000066400000000000000000000002161320724427000220460ustar00rootroot00000000000000 'You/yourclass1.php', 'erYourClass2' => 'You/yourclass2.php', ); ?> Base-1.9.1/docs/tutorial.txt000066400000000000000000000212071320724427000157330ustar00rootroot00000000000000eZ Components - Base ~~~~~~~~~~~~~~~~~~~~ .. contents:: Table of Contents Introduction ============ The Base component provides the basic functionality, such as autoloading, that all eZ Components need to function properly. The Base component needs to be loaded specifically. Base can also autoload external class repositories from outside the eZ Components. Aside from the autoload functionality, the Base component also contains a number of generic Exception classes that all inherit from the ezcBaseException class. Installation ============ The installation and configuration of the eZ Components environment is described in a separate article. Please refer to the `Components Introduction`_ for instructions on installation and configuration of the eZ Components library and the Base component. .. _Components Introduction: ../../../../zetacomponents/documentation/install.html Usage ===== Debugging --------- By default the ezcBase component's autoload mechanism will not throw an exception when an autoload class can not be found. In some cases (during development) it is useful to have an exception with detailed information about which autoload files were searched for, and in which directories. ezcBase supports an option that enables this behavior:: debug = true; ezcBase::setOptions( $options ); ?> **Warning**: Exceptions are ignored when they are thrown from an autoload() handler in PHP. In order to see the exception message that is thrown when a class can not be found, you need to catch the exception *in* the autoload() handler. Your autoload() function could then look like:: function __autoload( $className ) { try { ezcBase::autoload( $className ); } catch ( Exception $e ) { echo $e->getMessage(); } } Preloading ---------- The default autoload policy of the eZ Components is to load every class file on demand only. It is also possible to load all classes of one component at the same time, when one of the component's classes is requested for the first time. You can change this behavior with the "preload" option that is available through the ezcBaseAutoloadOptions option class. You can turn preloading on with:: preload = true; ezcBase::setOptions( $options ); ?> Please note that preloading will *not* be done for Exception classes. Adding class repositories located outside eZ Components to autoload system -------------------------------------------------------------------------- It can be useful to add repositories of user-defined classes to the eZ Components autoload system. The ezcBase::addClassRepository() method can be used to perform this task. You need to arrange the desired external classes in a class repository. That is, make sure that classes and corresponding \*_autoload.php files are named and placed according to the explanations below. After they are in the proper structure, you can call addClassRepository() with the proper parameters before you use the external classes. External classes will then be loaded by autoload system. ezcBase::addClassRepository() takes two arguments: - $basePath is the base path for the whole class repository. - $autoloadDirPath is the path where autoload files for this repository are found. The paths in the autoload files are *not* relative to the package directory as specified by the $basePath argument. In other words, class definition files will only be searched for in the location $autoloadDirPath. Consider the following example: - There is a class repository stored in the directory "./repos". - Autoload files for this repository are stored in "./repos/autoloads". - There are two components in this repository: "Me" and "You". - The "Me" component has the classes "erMyClass1" and "erMyClass2". - The "You" component has the classes "erYourClass1" and "erYourClass2". In this case, you need to create the following files in "./repos/autoloads". Note that the prefix to _autoload.php ("my" and "your") in the filename is the first part of the classname (excluding the lowercase classname prefix - "er"). Content of my_autoload.php: .. include:: repos/autoloads/my_autoload.php :literal: Content of your_autoload.php: .. include:: repos/autoloads/your_autoload.php :literal: The directory structure for the external repository is then: :: ./repos/autoloads/my_autoload.php ./repos/autoloads/your_autoload.php ./repos/Me/myclass1.php ./repos/Me/myclass2.php ./repos/You/yourclass1.php ./repos/You/yourclass2.php To use this repository with the autoload mechanism, use the following code: .. include:: tutorial_example_01.php :literal: The above code will output: :: Class 'erMyClass2' Class 'erYourClass1' Lazy initialization ------------------- Lazy initialization is a mechanism to load and configure a component, only when it is really used in your application. This mechanism saves time for parsing the classes and configuration, when the component is not used at all during one request. The implementation in ezcBaseInit may be reused by other applications and components, like the following example will show. .. include:: tutorial_lazy_initialization.php :literal: The example shows a random class implementing the singleton pattern, which may be some database connection handler, or anything similar in your case. The getInstance() method shows a typical PHP 5 implementation except the additional line 14, which checks, if a configuration callback was provided earlier and configures the newly created instance. If no configuration callback was provided, nothing will happen. The customKey is used to receive the right callback from ezcBaseInit and needs to be known by the user, who wants to define a configuration callback for your class. In line 32 the class used to configure your instance on creation is defined. The first parameter is the key used earlier in the getInstance method, to reference the right class, and the second parameter is the name of your configuration class. The configuration class beginning in line 22 just needs to implement the ezcBaseConfigurationInitializer interface, which defines one method: configureObject(). This method will be called with the object to configure as a single parameter. In the example, a new public property on the customSingleton instance is created, which will be echo'd later to show the success of the configuration. The configuration itself will not happen before the actual instance is created in line 35 performing the static call on customSingleton::getInstance(). The var_dump() in the following line shows, that the property value is set and contains the earlier set value (int) 42. File Operations --------------- Finding files recursively ````````````````````````` This example shows how to use the ezcBaseFile::findRecursive() method: .. include:: tutorial_example_02.php :literal: The code in this example searches for files in the ``/dat/dev/ezcomponents`` directory. It will only include files that match *all* patterns in the $includeFilters array (the second parameter). Files that match *any* of the patterns in the $excludeFilters array (the third parameter) will not be returned. In other words, the code above searches for files in the ``dat/dev/ezcomponents`` directory, which are in the ``src/`` directory and end with ``_autoload.php``, except for files that are in the ``/autoload/`` directory. Removing directories recursively ```````````````````````````````` This example shows how to use the ezcBaseFile::removeRecursive() method: .. include:: tutorial_example_03.php :literal: This code simply removes the directory ``/dat/dev/ezcomponents/trash`` and all of its files and sub-directories. **Warning: Use this function with care, as it has the potential to erase everything that the current user has access to.** Overloading the callback ```````````````````````` The ezcBaseFile::findRecursive() method internally uses the ezcBaseFile::walkRecursive() method to do the actual recursing. The callback method ezcBaseFile::findRecursiveCallback() is then responsible for collecting the data. In case you want to do additional things, such as printing progress, you can either call walkRecursive() yourself with a callback function of your choice, or overload the ezcBaseFile class and provide a new findRecursiveCallback() method. The code below uses ezcBaseFile::walkRecursive() directly in order to display dots for when ever it finds a new directory: .. include:: tutorial_example_04.php :literal: .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79 Base-1.9.1/docs/tutorial_autoload.php000066400000000000000000000007571320724427000176020ustar00rootroot00000000000000 Base-1.9.1/docs/tutorial_example_01.php000066400000000000000000000003271320724427000177160ustar00rootroot00000000000000toString(); $yourVar1 = new erYourClass1(); $yourVar1->toString(); ?> Base-1.9.1/docs/tutorial_example_02.php000066400000000000000000000002751320724427000177210ustar00rootroot00000000000000 Base-1.9.1/docs/tutorial_example_03.php000066400000000000000000000001531320724427000177150ustar00rootroot00000000000000 Base-1.9.1/docs/tutorial_example_04.php000066400000000000000000000026201320724427000177170ustar00rootroot00000000000000elements[] = $sourceDir . DIRECTORY_SEPARATOR . $fileName; $context->count++; $context->size += $fileInfo['size']; } static public function findRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array() ) { // create the context, and then start walking over the array $context = new ezcBaseFileFindContext; ezcBaseFile::walkRecursive( $sourceDir, $includeFilters, $excludeFilters, array( 'myProgressFinder', 'findRecursiveCallback' ), $context ); // collect the statistics (which we don't do anything with in this example) $statistics['size'] = $context->size; $statistics['count'] = $context->count; // return the found and pattern-matched files sort( $context->elements ); return $context->elements; } } $files = myProgressFinder::findRecursive( dirname( __FILE__ ) ); var_dump( $files ); ?> Base-1.9.1/docs/tutorial_lazy_initialization.php000066400000000000000000000016221320724427000220500ustar00rootroot00000000000000value = 42; } } // Register for lazy initilization ezcBaseInit::setCallback( 'customKey', 'customSingletonConfiguration' ); // Configure on first initilization $object = customSingleton::getInstance(); var_dump( $object->value ); ?> Base-1.9.1/phpunit.xml.dist000066400000000000000000000005771320724427000155610ustar00rootroot00000000000000 ./tests ./src Base-1.9.1/review-1.5.txt000066400000000000000000000020741320724427000147430ustar00rootroot00000000000000Review Alexandru 2008-05-08 =========================== [X] Regarding feature request #8529 (a du -s implementation). The documentation for ezcBaseFile::findRecursive() says that you can supply an empty array as the 4th argument to get the statistics. If I pass for example $stats which I initialized with array() before, then I get notices: "Undefined index: count in /home/as/dev/ezcomponents/trunk/Base/src/file.php on line 139", and the same notice for index "size". Also the documentation does not mention that you need to pass a variable and not a value - if I pass array() as the 4th argument I get the error "Cannot pass parameter 4 by reference" If I pass $stats which I initialize with null, false or empty string before, then the function works. Also all the file recursive tests fail on Windows (slash issues mostly). [X] Regarding feature request #11506 (method ezcBase::getInstallationPath()). On Linux it returns the path without any slash at the end, but on Windows (Vista) it adds a Windows slash at the end. Base-1.9.1/src/000077500000000000000000000000001320724427000131645ustar00rootroot00000000000000Base-1.9.1/src/base.php000066400000000000000000000547331320724427000146230ustar00rootroot00000000000000array) */ protected static $repositoryDirs = array(); /** * This variable stores all the elements from the autoload arrays. When a * new autoload file is loaded, their files are added to this array. * * @var array(string=>string) */ protected static $autoloadArray = array(); /** * This variable stores all the elements from the autoload arrays for * external repositories. When a new autoload file is loaded, their files * are added to this array. * * @var array(string=>string) */ protected static $externalAutoloadArray = array(); /** * Options for the ezcBase class. * * @var ezcBaseOptions */ static private $options; /** * Associates an option object with this static class. * * @param ezcBaseAutoloadOptions $options */ static public function setOptions( ezcBaseAutoloadOptions $options ) { self::$options = $options; } /** * Tries to autoload the given className. If the className could be found * this method returns true, otherwise false. * * This class caches the requested class names (including the ones who * failed to load). * * @param string $className The name of the class that should be loaded. * * @return bool */ public static function autoload( $className ) { ezcBase::setPackageDir(); // Check whether the classname is already in the cached autoloadArray. if ( array_key_exists( $className, ezcBase::$autoloadArray ) ) { // Is it registered as 'unloadable'? if ( ezcBase::$autoloadArray[$className] == false ) { return false; } ezcBase::loadFile( ezcBase::$autoloadArray[$className] ); return true; } // Check whether the classname is already in the cached autoloadArray // for external repositories. if ( array_key_exists( $className, ezcBase::$externalAutoloadArray ) ) { // Is it registered as 'unloadable'? if ( ezcBase::$externalAutoloadArray[$className] == false ) { return false; } ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] ); return true; } // Not cached, so load the autoload from the package. // Matches the first and optionally the second 'word' from the classname. $fileNames = array(); if ( preg_match( "/^([a-z0-9]*)([A-Z][a-z0-9]*)?([A-Z][a-z0-9]*)?/", $className, $matches ) !== false ) { $autoloadFile = ""; // Try to match with both names, if available. switch ( sizeof( $matches ) ) { case 4: // check for x_y_autoload.php $autoloadFile = strtolower( "{$matches[2]}_{$matches[3]}_autoload.php" ); $fileNames[] = $autoloadFile; if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) { return true; } // break intentionally missing. case 3: // check for x_autoload.php $autoloadFile = strtolower( "{$matches[2]}_autoload.php" ); $fileNames[] = $autoloadFile; if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) { return true; } // break intentionally missing. case 2: // check for autoload.php $autoloadFile = 'autoload.php'; $fileNames[] = $autoloadFile; if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) ) { return true; } break; } // Maybe there is another autoload available. // Register this classname as false. ezcBase::$autoloadArray[$className] = false; } $path = ezcBase::$packageDir . 'autoload/'; $realPath = realpath( $path ); if ( $realPath == '' ) { // Can not be tested, because if this happens, then the autoload // environment has not been set-up correctly. trigger_error( "Couldn't find autoload directory '$path'", E_USER_ERROR ); } $dirs = self::getRepositoryDirectories(); if ( ezcBase::$options && ezcBase::$options->debug ) { throw new ezcBaseAutoloadException( $className, $fileNames, $dirs ); } return false; } /** * Sets the current working directory to $directory. * * @param string $directory */ public static function setWorkingDirectory( $directory ) { self::$libraryMode = 'custom'; self::$currentWorkingDirectory = $directory; } /** * Figures out the base path of the Zeta Components installation. * * It stores the path that it finds in a static member variable. The path * depends on the installation method of the Zeta Components. The SVN version * has a different path than the PEAR installed version. */ protected static function setPackageDir() { if ( ezcBase::$packageDir !== null ) { return; } // Get the path to the components. $baseDir = dirname( __FILE__ ); switch ( ezcBase::$libraryMode ) { case "custom": ezcBase::$packageDir = self::$currentWorkingDirectory . '/'; break; case "devel": case "tarball": ezcBase::$packageDir = $baseDir. "/../../"; break; case "pear"; ezcBase::$packageDir = $baseDir. "/../"; break; } } /** * Tries to load the autoload array and, if loaded correctly, includes the class. * * @param string $fileName Name of the autoload file. * @param string $className Name of the class that should be autoloaded. * @param string $prefix The prefix of the class repository. * * @return bool True is returned when the file is correctly loaded. * Otherwise false is returned. */ protected static function requireFile( $fileName, $className, $prefix ) { $autoloadDir = ezcBase::$packageDir . "autoload/"; // We need the full path to the fileName. The method file_exists() doesn't // automatically check the (php.ini) library paths. Therefore: // file_exists( "ezc/autoload/$fileName" ) doesn't work. if ( $prefix === 'ezc' && file_exists( "$autoloadDir$fileName" ) ) { $array = require( "$autoloadDir$fileName" ); if ( is_array( $array) && array_key_exists( $className, $array ) ) { // Add the array to the cache, and include the requested file. ezcBase::$autoloadArray = array_merge( ezcBase::$autoloadArray, $array ); if ( ezcBase::$options !== null && ezcBase::$options->preload && !preg_match( '/Exception$/', $className ) ) { foreach ( $array as $loadClassName => $file ) { if ( $loadClassName !== 'ezcBase' && !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false ) && !preg_match( '/Exception$/', $loadClassName ) /*&& !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false )*/ ) { ezcBase::loadFile( ezcBase::$autoloadArray[$loadClassName] ); } } } else { ezcBase::loadFile( ezcBase::$autoloadArray[$className] ); } return true; } } // It is not in components autoload/ dir. // try to search in additional dirs. foreach ( ezcBase::$repositoryDirs as $repositoryPrefix => $extraDir ) { if ( gettype( $repositoryPrefix ) === 'string' && $repositoryPrefix !== $prefix ) { continue; } if ( file_exists( $extraDir['autoloadDirPath'] . '/' . $fileName ) ) { $array = array(); $originalArray = require( $extraDir['autoloadDirPath'] . '/' . $fileName ); // Building paths. // Resulting path to class definition file consists of: // path to extra directory with autoload file + // basePath provided for current extra directory + // path to class definition file stored in autoload file. foreach ( $originalArray as $class => $classPath ) { $array[$class] = $extraDir['basePath'] . '/' . $classPath; } if ( is_array( $array ) && array_key_exists( $className, $array ) ) { // Add the array to the cache, and include the requested file. ezcBase::$externalAutoloadArray = array_merge( ezcBase::$externalAutoloadArray, $array ); ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] ); return true; } } } // Nothing found :-(. return false; } /** * Loads, require(), the given file name. If we are in development mode, * "/src/" is inserted into the path. * * @param string $file The name of the file that should be loaded. */ protected static function loadFile( $file ) { switch ( ezcBase::$libraryMode ) { case "devel": case "tarball": list( $first, $second ) = explode( '/', $file, 2 ); $file = $first . "/src/" . $second; break; case "custom": list( $first, $second ) = explode( '/', $file, 2 ); // Add the "src/" after the package name. if ( $first == 'Base' || $first == 'UnitTest' ) { list( $first, $second ) = explode( '/', $file, 2 ); $file = $first . "/src/" . $second; } else { list( $first, $second, $third ) = explode( '/', $file, 3 ); $file = $first . '/' . $second . "/src/" . $third; } break; case "pear": /* do nothing, it's already correct */ break; } if ( file_exists( ezcBase::$packageDir . $file ) ) { require( ezcBase::$packageDir . $file ); } else { // Can not be tested, because if this happens, then one of the // components has a broken autoload file. throw new ezcBaseFileNotFoundException( ezcBase::$packageDir.$file ); } } /** * Loads, require(), the given file name from an external package. * * @param string $file The name of the file that should be loaded. */ protected static function loadExternalFile( $file ) { if ( file_exists( $file ) ) { require( $file ); } else { throw new ezcBaseFileNotFoundException( $file ); } } /** * Checks for dependencies on PHP versions or extensions * * The function as called by the $component component checks for the $type * dependency. The dependency $type is compared against the $value. The * function aborts the script if the dependency is not matched. * * @param string $component * @param int $type * @param mixed $value */ public static function checkDependency( $component, $type, $value ) { switch ( $type ) { case self::DEP_PHP_EXTENSION: if ( extension_loaded( $value ) ) { return; } else { // Can not be tested as it would abort the PHP script. die( "\nThe {$component} component depends on the default PHP extension '{$value}', which is not loaded.\n" ); } break; case self::DEP_PHP_VERSION: $phpVersion = phpversion(); if ( version_compare( $phpVersion, $value, '>=' ) ) { return; } else { // Can not be tested as it would abort the PHP script. die( "\nThe {$component} component depends on the PHP version '{$value}', but the current version is '{$phpVersion}'.\n" ); } break; } } /** * Return the list of directories that contain class repositories. * * The path to the eZ components directory is always included in the result * array. Each element in the returned array has the format of: * packageDirectory => ezcBaseRepositoryDirectory * * @return array(string=>ezcBaseRepositoryDirectory) */ public static function getRepositoryDirectories() { $autoloadDirs = array(); ezcBase::setPackageDir(); $repositoryDir = self::$currentWorkingDirectory ? self::$currentWorkingDirectory : ( realpath( dirname( __FILE__ ) . '/../../' ) ); $autoloadDirs['ezc'] = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_INTERNAL, $repositoryDir, $repositoryDir . "/autoload" ); foreach ( ezcBase::$repositoryDirs as $extraDirKey => $extraDirArray ) { $repositoryDirectory = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_EXTERNAL, realpath( $extraDirArray['basePath'] ), realpath( $extraDirArray['autoloadDirPath'] ) ); $autoloadDirs[$extraDirKey] = $repositoryDirectory; } return $autoloadDirs; } /** * Adds an additional class repository. * * Used for adding class repositoryies outside the eZ components to be * loaded by the autoload system. * * This function takes two arguments: $basePath is the base path for the * whole class repository and $autoloadDirPath the path where autoload * files for this repository are found. The paths in the autoload files are * relative to the package directory as specified by the $basePath * argument. I.e. class definition file will be searched at location * $basePath + path to the class definition file as stored in the autoload * file. * * addClassRepository() should be called somewhere in code before external classes * are used. * * Example: * Take the following facts: *
    *
  • there is a class repository stored in the directory "./repos"
  • *
  • autoload files for that repository are stored in "./repos/autoloads"
  • *
  • there are two components in this repository: "Me" and "You"
  • *
  • the "Me" component has the classes "erMyClass1" and "erMyClass2"
  • *
  • the "You" component has the classes "erYourClass1" and "erYourClass2"
  • *
* * In this case you would need to create the following files in * "./repos/autoloads". Please note that the part before _autoload.php in * the filename is the first part of the classname, not considering * the all lower-case letter prefix. * * "my_autoload.php": * * 'Me/myclass1.php', * 'erMyClass2' => 'Me/myclass2.php', * ); * ?> * * * "your_autoload.php": * * 'You/yourclass1.php', * 'erYourClass2' => 'You/yourclass2.php', * ); * ?> * * * The directory structure for the external repository is then: * * ./repos/autoloads/my_autoload.php * ./repos/autoloads/you_autoload.php * ./repos/Me/myclass1.php * ./repos/Me/myclass2.php * ./repos/You/yourclass1.php * ./repos/You/yourclass2.php * * * To use this repository with the autoload mechanism you have to use the * following code: * * * * * @throws ezcBaseFileNotFoundException if $autoloadDirPath or $basePath do not exist. * @param string $basePath * @param string $autoloadDirPath * @param string $prefix */ public static function addClassRepository( $basePath, $autoloadDirPath = null, $prefix = null ) { // check if base path exists if ( !is_dir( $basePath ) ) { throw new ezcBaseFileNotFoundException( $basePath, 'base directory' ); } // calculate autoload path if it wasn't given if ( is_null( $autoloadDirPath ) ) { $autoloadDirPath = $basePath . '/autoload'; } // check if autoload dir exists if ( !is_dir( $autoloadDirPath ) ) { throw new ezcBaseFileNotFoundException( $autoloadDirPath, 'autoload directory' ); } // add info to $repositoryDirs if ( $prefix === null ) { $array = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath ); // add info to the list of extra dirs ezcBase::$repositoryDirs[] = $array; } else { if ( array_key_exists( $prefix, ezcBase::$repositoryDirs ) ) { throw new ezcBaseDoubleClassRepositoryPrefixException( $prefix, $basePath, $autoloadDirPath ); } // add info to the list of extra dirs, and use the prefix to identify the new repository. ezcBase::$repositoryDirs[$prefix] = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath ); } } /** * Returns the base path of the Zeta Components installation * * This method returns the base path, including a trailing directory * separator. * * @return string */ public static function getInstallationPath() { self::setPackageDir(); $path = realpath( self::$packageDir ); if ( substr( $path, -1 ) !== DIRECTORY_SEPARATOR ) { $path .= DIRECTORY_SEPARATOR; } return $path; } /** * Sets the development mode to the one specified. * * @param int $runMode */ public static function setRunMode( $runMode ) { if ( !in_array( $runMode, array( ezcBase::MODE_PRODUCTION, ezcBase::MODE_DEVELOPMENT ) ) ) { throw new ezcBaseValueException( 'runMode', $runMode, 'ezcBase::MODE_PRODUCTION or ezcBase::MODE_DEVELOPMENT' ); } self::$runMode = $runMode; } /** * Returns the current development mode. * * @return int */ public static function getRunMode() { return self::$runMode; } /** * Returns true when we are in development mode. * * @return bool */ public static function inDevMode() { return self::$runMode == ezcBase::MODE_DEVELOPMENT; } /** * Returns the installation method * * Possible return values are 'custom', 'devel', 'tarball' and 'pear'. Only * 'tarball' and 'pear' are returned for user-installed versions. * * @return string */ public static function getInstallMethod() { return self::$libraryMode; } } ?> Base-1.9.1/src/base_autoload.php000066400000000000000000000075161320724427000165100ustar00rootroot00000000000000 'Base/exceptions/exception.php', 'ezcBaseFileException' => 'Base/exceptions/file_exception.php', 'ezcBaseAutoloadException' => 'Base/exceptions/autoload.php', 'ezcBaseDoubleClassRepositoryPrefixException' => 'Base/exceptions/double_class_repository_prefix.php', 'ezcBaseExtensionNotFoundException' => 'Base/exceptions/extension_not_found.php', 'ezcBaseFileIoException' => 'Base/exceptions/file_io.php', 'ezcBaseFileNotFoundException' => 'Base/exceptions/file_not_found.php', 'ezcBaseFilePermissionException' => 'Base/exceptions/file_permission.php', 'ezcBaseFunctionalityNotSupportedException' => 'Base/exceptions/functionality_not_supported.php', 'ezcBaseInitCallbackConfiguredException' => 'Base/exceptions/init_callback_configured.php', 'ezcBaseInitInvalidCallbackClassException' => 'Base/exceptions/invalid_callback_class.php', 'ezcBaseInvalidParentClassException' => 'Base/exceptions/invalid_parent_class.php', 'ezcBasePropertyNotFoundException' => 'Base/exceptions/property_not_found.php', 'ezcBasePropertyPermissionException' => 'Base/exceptions/property_permission.php', 'ezcBaseSettingNotFoundException' => 'Base/exceptions/setting_not_found.php', 'ezcBaseSettingValueException' => 'Base/exceptions/setting_value.php', 'ezcBaseValueException' => 'Base/exceptions/value.php', 'ezcBaseWhateverException' => 'Base/exceptions/whatever.php', 'ezcBaseOptions' => 'Base/options.php', 'ezcBaseStruct' => 'Base/struct.php', 'ezcBase' => 'Base/base.php', 'ezcBaseAutoloadOptions' => 'Base/options/autoload.php', 'ezcBaseConfigurationInitializer' => 'Base/interfaces/configuration_initializer.php', 'ezcBaseExportable' => 'Base/interfaces/exportable.php', 'ezcBaseFeatures' => 'Base/features.php', 'ezcBaseFile' => 'Base/file.php', 'ezcBaseFileFindContext' => 'Base/structs/file_find_context.php', 'ezcBaseInit' => 'Base/init.php', 'ezcBaseMetaData' => 'Base/metadata.php', 'ezcBaseMetaDataPearReader' => 'Base/metadata/pear.php', 'ezcBaseMetaDataTarballReader' => 'Base/metadata/tarball.php', 'ezcBasePersistable' => 'Base/interfaces/persistable.php', 'ezcBaseRepositoryDirectory' => 'Base/structs/repository_directory.php', ); ?> Base-1.9.1/src/exceptions/000077500000000000000000000000001320724427000153455ustar00rootroot00000000000000Base-1.9.1/src/exceptions/autoload.php000066400000000000000000000035671320724427000177010ustar00rootroot00000000000000autoloadPath ); } parent::__construct( "Could not find a class to file mapping for '{$className}'. Searched for ". implode( ', ', $files ) . " in: " . implode( ', ', $paths ) ); } } ?> Base-1.9.1/src/exceptions/double_class_repository_prefix.php000066400000000000000000000035261320724427000243770ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/exception.php000066400000000000000000000032521320724427000200560ustar00rootroot00000000000000originalMessage = $message; if ( php_sapi_name() == 'cli' ) { parent::__construct( $message ); } else { parent::__construct( htmlspecialchars( $message ) ); } } } ?> Base-1.9.1/src/exceptions/extension_not_found.php000066400000000000000000000034661320724427000221560ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/file_exception.php000066400000000000000000000024551320724427000210610ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/file_io.php000066400000000000000000000043251320724427000174700ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/file_not_found.php000066400000000000000000000035121320724427000210510ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/file_permission.php000066400000000000000000000056521320724427000212550ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/functionality_not_supported.php000066400000000000000000000030761320724427000237410ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/init_callback_configured.php000066400000000000000000000032571320724427000230510ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/invalid_callback_class.php000066400000000000000000000031371320724427000225110ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/invalid_parent_class.php000066400000000000000000000031051320724427000222410ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/property_not_found.php000066400000000000000000000027711320724427000220240ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/property_permission.php000066400000000000000000000035461320724427000222220ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/setting_not_found.php000066400000000000000000000031241320724427000216060ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/setting_value.php000066400000000000000000000041331320724427000207300ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/value.php000066400000000000000000000043061320724427000171750ustar00rootroot00000000000000 Base-1.9.1/src/exceptions/whatever.php000066400000000000000000000040131320724427000177010ustar00rootroot00000000000000 Base-1.9.1/src/ezc_bootstrap.php000066400000000000000000000032661320724427000165620ustar00rootroot00000000000000 Base-1.9.1/src/features.php000066400000000000000000000272451320724427000155250ustar00rootroot00000000000000 * * * * @package Base * @version //autogentag// */ class ezcBaseFeatures { /** * Used to store the path of the ImageMagick convert utility. * * It is initialized in the {@link getImageConvertExecutable()} function. * * @var string */ private static $imageConvert = null; /** * Used to store the path of the ImageMagick identify utility. * * It is initialized in the {@link getImageIdentifyExecutable()} function. * * @var string */ private static $imageIdentify = null; /** * Used to store the operating system. * * It is initialized in the {@link os()} function. * * @var string */ private static $os = null; /** * Determines if hardlinks are supported. * * @return bool */ public static function supportsLink() { return function_exists( 'link' ); } /** * Determines if symlinks are supported. * * @return bool */ public static function supportsSymLink() { return function_exists( 'symlink' ); } /** * Determines if posix uids are supported. * * @return bool */ public static function supportsUserId() { return function_exists( 'posix_getpwuid' ); } /** * Determines if the ImageMagick convert utility is installed. * * @return bool */ public static function hasImageConvert() { return !is_null( self::getImageConvertExecutable() ); } /** * Returns the path to the ImageMagick convert utility. * * On Linux, Unix,... it will return something like: /usr/bin/convert * On Windows it will return something like: C:\Windows\System32\convert.exe * * @return string */ public static function getImageConvertExecutable() { if ( !is_null( self::$imageConvert ) ) { return self::$imageConvert; } return ( self::$imageConvert = self::findExecutableInPath( 'convert' ) ); } /** * Determines if the ImageMagick identify utility is installed. * * @return bool */ public static function hasImageIdentify() { return !is_null( self::getImageIdentifyExecutable() ); } /** * Returns the path to the ImageMagick identify utility. * * On Linux, Unix,... it will return something like: /usr/bin/identify * On Windows it will return something like: C:\Windows\System32\identify.exe * * @return string */ public static function getImageIdentifyExecutable() { if ( !is_null( self::$imageIdentify ) ) { return self::$imageIdentify; } return ( self::$imageIdentify = self::findExecutableInPath( 'identify' ) ); } /** * Determines if the specified extension is loaded. * * If $version is specified, the specified extension will be tested also * against the version of the loaded extension. * * Examples: * * hasExtensionSupport( 'gzip' ); * * will return true if gzip extension is loaded. * * * hasExtensionSupport( 'pdo_mysql', '1.0.2' ); * * will return true if pdo_mysql extension is loaded and its version is at least 1.0.2. * * @param string $extension * @param string $version * @return bool */ public static function hasExtensionSupport( $extension, $version = null ) { if ( is_null( $version ) ) { return extension_loaded( $extension ); } return extension_loaded( $extension ) && version_compare( phpversion( $extension ), $version, ">=" ) ; } /** * Determines if the specified function is available. * * Examples: * * ezcBaseFeatures::hasFunction( 'imagepstext' ); * * will return true if support for Type 1 fonts is available with your GD * extension. * * @param string $functionName * @return bool */ public static function hasFunction( $functionName ) { return function_exists( $functionName ); } /** * Returns if a given class exists. * Checks for a given class name and returns if this class exists or not. * Catches the ezcBaseAutoloadException and returns false, if it was thrown. * * @param string $className The class to check for. * @param bool $autoload True to use __autoload(), otherwise false. * @return bool True if the class exists. Otherwise false. */ public static function classExists( $className, $autoload = true ) { try { if ( class_exists( $className, $autoload ) ) { return true; } return false; } catch ( ezcBaseAutoloadException $e ) { return false; } } /** * Returns the operating system on which PHP is running. * * This method returns a sanitized form of the OS name, example * return values are "Windows", "Mac", "Linux" and "FreeBSD". In * all other cases it returns the value of the internal PHP constant * PHP_OS. * * @return string */ public static function os() { if ( is_null( self::$os ) ) { $uname = php_uname( 's' ); if ( substr( $uname, 0, 7 ) == 'Windows' ) { self::$os = 'Windows'; } elseif ( substr( $uname, 0, 3 ) == 'Mac' ) { self::$os = 'Mac'; } elseif ( strtolower( $uname ) == 'linux' ) { self::$os = 'Linux'; } elseif ( strtolower( substr( $uname, 0, 7 ) ) == 'freebsd' ) { self::$os = 'FreeBSD'; } else { self::$os = PHP_OS; } } return self::$os; } /** * Returns the path of the specified executable, if it can be found in the system's path. * * It scans the PATH enviroment variable based on the OS to find the * $fileName. For Windows, the path is with \, not /. If $fileName is not * found, it returns null. * * @todo consider using getenv( 'PATH' ) instead of $_ENV['PATH'] * (but that won't work under IIS) * * @param string $fileName * @return string */ public static function findExecutableInPath( $fileName ) { if ( array_key_exists( 'PATH', $_ENV ) ) { $envPath = trim( $_ENV['PATH'] ); } else if ( ( $envPath = getenv( 'PATH' ) ) !== false ) { $envPath = trim( $envPath ); } if ( is_string( $envPath ) && strlen( trim( $envPath ) ) == 0 ) { $envPath = false; } switch ( self::os() ) { case 'Unix': case 'FreeBSD': case 'Mac': case 'MacOS': case 'Darwin': case 'Linux': case 'SunOS': if ( $envPath ) { $dirs = explode( ':', $envPath ); foreach ( $dirs as $dir ) { // The @-operator is used here mainly to avoid // open_basedir warnings. If open_basedir (or any other // circumstance) prevents the desired file from being // accessed, it is fine for file_exists() to return // false, since it is useless for use then, anyway. if ( file_exists( "{$dir}/{$fileName}" ) ) { return "{$dir}/{$fileName}"; } } } // The @-operator is used here mainly to avoid open_basedir // warnings. If open_basedir (or any other circumstance) // prevents the desired file from being accessed, it is fine // for file_exists() to return false, since it is useless for // use then, anyway. elseif ( @file_exists( "./{$fileName}" ) ) { return $fileName; } break; case 'Windows': if ( $envPath ) { $dirs = explode( ';', $envPath ); foreach ( $dirs as $dir ) { // The @-operator is used here mainly to avoid // open_basedir warnings. If open_basedir (or any other // circumstance) prevents the desired file from being // accessed, it is fine for file_exists() to return // false, since it is useless for use then, anyway. if ( @file_exists( "{$dir}\\{$fileName}.exe" ) ) { return "{$dir}\\{$fileName}.exe"; } } } // The @-operator is used here mainly to avoid open_basedir // warnings. If open_basedir (or any other circumstance) // prevents the desired file from being accessed, it is fine // for file_exists() to return false, since it is useless for // use then, anyway. elseif ( @file_exists( "{$fileName}.exe" ) ) { return "{$fileName}.exe"; } break; } return null; } /** * Reset the cached information. * * @return void * @access private * @ignore */ public static function reset() { self::$imageIdentify = null; self::$imageConvert = null; self::$os = null; } } ?> Base-1.9.1/src/file.php000066400000000000000000000441371320724427000146250ustar00rootroot00000000000000 * * * * @package Base * @version //autogentag// * @mainclass */ class ezcBaseFile { /** * This is the callback used by findRecursive to collect data. * * This callback method works together with walkRecursive() and is called * for every file/and or directory. The $context is a callback specific * container in which data can be stored and shared between the different * calls to the callback function. The walkRecursive() function also passes * in the full absolute directory in $sourceDir, the filename in $fileName * and file information (such as size, modes, types) as an array as * returned by PHP's stat() in the $fileInfo parameter. * * @param ezcBaseFileFindContext $context * @param string $sourceDir * @param string $fileName * @param array(stat) $fileInfo */ static protected function findRecursiveCallback( ezcBaseFileFindContext $context, $sourceDir, $fileName, $fileInfo ) { // ignore if we have a directory if ( $fileInfo['mode'] & 0x4000 ) { return; } // update the statistics $context->elements[] = $sourceDir . DIRECTORY_SEPARATOR . $fileName; $context->count++; $context->size += $fileInfo['size']; } /** * Walks files and directories recursively on a file system * * This method walks over a directory and calls a callback from every file * and directory it finds. You can use $includeFilters to include only * specific files, and $excludeFilters to exclude certain files from being * returned. The function will always go into subdirectories even if the * entry would not have passed the filters. * * The callback is passed in the $callback parameter, and the * $callbackContext will be send to the callback function/method as * parameter so that you can store data in there that persists with all the * calls and recursive calls to this method. It's up to the callback method * to do something useful with this. The callback function's parameters are * in order: * *
    *
  • ezcBaseFileFindContext $context
  • *
  • string $sourceDir
  • *
  • string $fileName
  • *
  • array(stat) $fileInfo
  • *
* * See {@see findRecursiveCallback()} for an example of a callback function. * * Filters are regular expressions and are therefore required to have * starting and ending delimiters. The Perl Compatible syntax is used as * regular expression language. * * @param string $sourceDir * @param array(string) $includeFilters * @param array(string) $excludeFilters * @param callback $callback * @param mixed $callbackContext * * @throws ezcBaseFileNotFoundException if the $sourceDir directory is not * a directory or does not exist. * @throws ezcBaseFilePermissionException if the $sourceDir directory could * not be opened for reading. * @return array */ static public function walkRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array(), $callback, &$callbackContext ) { if ( !is_dir( $sourceDir ) ) { throw new ezcBaseFileNotFoundException( $sourceDir, 'directory' ); } $elements = array(); $d = @dir( $sourceDir ); if ( !$d ) { throw new ezcBaseFilePermissionException( $sourceDir, ezcBaseFileException::READ ); } while ( ( $entry = $d->read() ) !== false ) { if ( $entry == '.' || $entry == '..' ) { continue; } $fileInfo = @stat( $sourceDir . DIRECTORY_SEPARATOR . $entry ); if ( !$fileInfo ) { $fileInfo = array( 'size' => 0, 'mode' => 0 ); } if ( $fileInfo['mode'] & 0x4000 ) { // We need to ignore the Permission exceptions here as it can // be normal that a directory can not be accessed. We only need // the exception if the top directory could not be read. try { call_user_func_array( $callback, array( $callbackContext, $sourceDir, $entry, $fileInfo ) ); $subList = self::walkRecursive( $sourceDir . DIRECTORY_SEPARATOR . $entry, $includeFilters, $excludeFilters, $callback, $callbackContext ); $elements = array_merge( $elements, $subList ); } catch ( ezcBaseFilePermissionException $e ) { } } else { // By default a file is included in the return list $ok = true; // Iterate over the $includeFilters and prohibit the file from // being returned when atleast one of them does not match foreach ( $includeFilters as $filter ) { if ( !preg_match( $filter, $sourceDir . DIRECTORY_SEPARATOR . $entry ) ) { $ok = false; break; } } // Iterate over the $excludeFilters and prohibit the file from // being returns when atleast one of them matches foreach ( $excludeFilters as $filter ) { if ( preg_match( $filter, $sourceDir . DIRECTORY_SEPARATOR . $entry ) ) { $ok = false; break; } } // If everything's allright, call the callback and add the // entry to the elements array if ( $ok ) { call_user_func( $callback, $callbackContext, $sourceDir, $entry, $fileInfo ); $elements[] = $sourceDir . DIRECTORY_SEPARATOR . $entry; } } } sort( $elements ); return $elements; } /** * Finds files recursively on a file system * * With this method you can scan the file system for files. You can use * $includeFilters to include only specific files, and $excludeFilters to * exclude certain files from being returned. The function will always go * into subdirectories even if the entry would not have passed the filters. * It uses the {@see walkRecursive()} method to do the actually recursion. * * Filters are regular expressions and are therefore required to have * starting and ending delimiters. The Perl Compatible syntax is used as * regular expression language. * * If you pass an empty array to the $statistics argument, the function * will in details about the number of files found into the 'count' array * element, and the total filesize in the 'size' array element. Because this * argument is passed by reference, you *have* to pass a variable and you * can not pass a constant value such as "array()". * * @param string $sourceDir * @param array(string) $includeFilters * @param array(string) $excludeFilters * @param array() $statistics * * @throws ezcBaseFileNotFoundException if the $sourceDir directory is not * a directory or does not exist. * @throws ezcBaseFilePermissionException if the $sourceDir directory could * not be opened for reading. * @return array */ static public function findRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array(), &$statistics = null ) { // init statistics array if ( !is_array( $statistics ) || !array_key_exists( 'size', $statistics ) || !array_key_exists( 'count', $statistics ) ) { $statistics['size'] = 0; $statistics['count'] = 0; } // create the context, and then start walking over the array $context = new ezcBaseFileFindContext; self::walkRecursive( $sourceDir, $includeFilters, $excludeFilters, array( 'ezcBaseFile', 'findRecursiveCallback' ), $context ); // collect the statistics $statistics['size'] = $context->size; $statistics['count'] = $context->count; // return the found and pattern-matched files sort( $context->elements ); return $context->elements; } /** * Removes files and directories recursively from a file system * * This method recursively removes the $directory and all its contents. * You should be extremely careful with this method as it has the * potential to erase everything that the current user has access to. * * @param string $directory */ static public function removeRecursive( $directory ) { $sourceDir = realpath( $directory ); if ( !$sourceDir ) { throw new ezcBaseFileNotFoundException( $directory, 'directory' ); } $d = @dir( $sourceDir ); if ( !$d ) { throw new ezcBaseFilePermissionException( $directory, ezcBaseFileException::READ ); } // check if we can remove the dir $parentDir = realpath( $directory . DIRECTORY_SEPARATOR . '..' ); if ( !is_writable( $parentDir ) ) { throw new ezcBaseFilePermissionException( $parentDir, ezcBaseFileException::WRITE ); } // loop over contents while ( ( $entry = $d->read() ) !== false ) { if ( $entry == '.' || $entry == '..' ) { continue; } if ( is_dir( $sourceDir . DIRECTORY_SEPARATOR . $entry ) ) { self::removeRecursive( $sourceDir . DIRECTORY_SEPARATOR . $entry ); } else { if ( @unlink( $sourceDir . DIRECTORY_SEPARATOR . $entry ) === false ) { throw new ezcBaseFilePermissionException( $directory . DIRECTORY_SEPARATOR . $entry, ezcBaseFileException::REMOVE ); } } } $d->close(); rmdir( $sourceDir ); } /** * Recursively copy a file or directory. * * Recursively copy a file or directory in $source to the given * destination. If a depth is given, the operation will stop, if the given * recursion depth is reached. A depth of -1 means no limit, while a depth * of 0 means, that only the current file or directory will be copied, * without any recursion. * * You may optionally define modes used to create files and directories. * * @throws ezcBaseFileNotFoundException * If the $sourceDir directory is not a directory or does not exist. * @throws ezcBaseFilePermissionException * If the $sourceDir directory could not be opened for reading, or the * destination is not writeable. * * @param string $source * @param string $destination * @param int $depth * @param int $dirMode * @param int $fileMode * @return void */ static public function copyRecursive( $source, $destination, $depth = -1, $dirMode = 0775, $fileMode = 0664 ) { // Check if source file exists at all. if ( !is_file( $source ) && !is_dir( $source ) ) { throw new ezcBaseFileNotFoundException( $source ); } // Destination file should NOT exist if ( is_file( $destination ) || is_dir( $destination ) ) { throw new ezcBaseFilePermissionException( $destination, ezcBaseFileException::WRITE ); } // Skip non readable files in source directory if ( !is_readable( $source ) ) { return; } // Copy if ( is_dir( $source ) ) { mkdir( $destination ); // To ignore umask, umask() should not be changed with // multithreaded servers... chmod( $destination, $dirMode ); } elseif ( is_file( $source ) ) { copy( $source, $destination ); chmod( $destination, $fileMode ); } if ( ( $depth === 0 ) || ( !is_dir( $source ) ) ) { // Do not recurse (any more) return; } // Recurse $dh = opendir( $source ); while ( ( $file = readdir( $dh ) ) !== false ) { if ( ( $file === '.' ) || ( $file === '..' ) ) { continue; } self::copyRecursive( $source . '/' . $file, $destination . '/' . $file, $depth - 1, $dirMode, $fileMode ); } } /** * Calculates the relative path of the file/directory '$path' to a given * $base path. * * $path and $base should be fully absolute paths. This function returns the * answer of "How do I go from $base to $path". If the $path and $base are * the same path, the function returns '.'. This method does not touch the * filesystem. * * @param string $path * @param string $base * @return string */ static public function calculateRelativePath( $path, $base ) { // Sanitize the paths to use the correct directory separator for the platform $path = strtr( $path, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR ); $base = strtr( $base, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR ); $base = explode( DIRECTORY_SEPARATOR, $base ); $path = explode( DIRECTORY_SEPARATOR, $path ); // If the paths are the same we return if ( $base === $path ) { return '.'; } $result = ''; $pathPart = array_shift( $path ); $basePart = array_shift( $base ); while ( $pathPart == $basePart ) { $pathPart = array_shift( $path ); $basePart = array_shift( $base ); } if ( $pathPart != null ) { array_unshift( $path, $pathPart ); } if ( $basePart != null ) { array_unshift( $base, $basePart ); } $result = str_repeat( '..' . DIRECTORY_SEPARATOR, count( $base ) ); // prevent a trailing DIRECTORY_SEPARATOR in case there is only a .. if ( count( $path ) == 0 ) { $result = substr( $result, 0, -strlen( DIRECTORY_SEPARATOR ) ); } $result .= join( DIRECTORY_SEPARATOR, $path ); return $result; } /** * Returns whether the passed $path is an absolute path, giving the current $os. * * With the $os parameter you can tell this function to use the semantics * for a different operating system to determine whether a path is * absolute. The $os argument defaults to the OS that the script is running * on. * * @param string $path * @param string $os * @return bool */ public static function isAbsolutePath( $path, $os = null ) { if ( $os === null ) { $os = ezcBaseFeatures::os(); } // Stream wrapper like phar can also be considered absolute paths if ( preg_match( '(^[a-z]{3,}://)S', $path ) ) { return true; } switch ( $os ) { case 'Windows': // Sanitize the paths to use the correct directory separator for the platform $path = strtr( $path, '\\/', '\\\\' ); // Absolute paths with drive letter: X:\ if ( preg_match( '@^[A-Z]:\\\\@i', $path ) ) { return true; } // Absolute paths with network paths: \\server\share\ if ( preg_match( '@^\\\\\\\\[A-Z]+\\\\[^\\\\]@i', $path ) ) { return true; } break; case 'Mac': case 'Linux': case 'FreeBSD': default: // Sanitize the paths to use the correct directory separator for the platform $path = strtr( $path, '\\/', '//' ); if ( $path[0] == '/' ) { return true; } } return false; } } ?> Base-1.9.1/src/init.php000066400000000000000000000115261320724427000146450ustar00rootroot00000000000000 * * * * You will also need to configure which callback class to call. This you do * with the ezcBaseInit::setCallback() method. The following examples sets the * callback classname for the configuration identifier * 'ezcInitConfigurationManager' to 'cfgConfigurationManager': * * * * * * The class 'cfgConfigurationManager' is required to implement the * ezcBaseConfigurationInitializer interface, which defines only one method: * configureObject(). An example on how to implement such a class could be: * * * init( 'ezcConfigurationIniReader', 'settings', array( 'useComments' => true ) ); * } * } * ?> * * * Of course the implementation of this callback class is up to the application * developer that uses the component (in this example the Configuration * component's class ezcConfigurationManager). * * @package Base * @version //autogentag// */ class ezcBaseInit { /** * Contains the callback where the identifier is the key of the array, and the classname to callback to the value. * * @var array(string=>string) */ static private $callbackMap = array(); /** * Adds the classname $callbackClassname as callback for the identifier $identifier. * * @param string $identifier * @param string $callbackClassname */ public static function setCallback( $identifier, $callbackClassname ) { if ( array_key_exists( $identifier, self::$callbackMap ) ) { throw new ezcBaseInitCallbackConfiguredException( $identifier, self::$callbackMap[$identifier] ); } else { // Check if the passed classname actually exists if ( !ezcBaseFeatures::classExists( $callbackClassname, true ) ) { throw new ezcBaseInitInvalidCallbackClassException( $callbackClassname ); } // Check if the passed classname actually implements the interface. if ( !in_array( 'ezcBaseConfigurationInitializer', class_implements( $callbackClassname ) ) ) { throw new ezcBaseInitInvalidCallbackClassException( $callbackClassname ); } self::$callbackMap[$identifier] = $callbackClassname; } } /** * Uses the configured callback belonging to $identifier to configure the $object. * * The method will return the return value of the callback method, or null * in case there was no callback set for the specified $identifier. * * @param string $identifier * @param object $object * @return mixed */ public static function fetchConfig( $identifier, $object ) { if ( isset( self::$callbackMap[$identifier] ) ) { $callbackClassname = self::$callbackMap[$identifier]; return call_user_func( array( $callbackClassname, 'configureObject' ), $object ); } return null; } } ?> Base-1.9.1/src/interfaces/000077500000000000000000000000001320724427000153075ustar00rootroot00000000000000Base-1.9.1/src/interfaces/configuration_initializer.php000066400000000000000000000032131320724427000232710ustar00rootroot00000000000000 Base-1.9.1/src/interfaces/exportable.php000066400000000000000000000032471320724427000201730ustar00rootroot00000000000000 Base-1.9.1/src/interfaces/persistable.php000066400000000000000000000033731320724427000203430ustar00rootroot00000000000000mixed) */ public function getState(); /** * Accepts an array containing data for one or more of the class' properties. * * @param array $properties */ public function setState( array $properties ); } ?> Base-1.9.1/src/metadata.php000066400000000000000000000102771320724427000154640ustar00rootroot00000000000000reader = new ezcBaseMetaDataTarballReader; break; case 'pear': $this->reader = new ezcBaseMetaDataPearReader; break; default: throw new ezcBaseMetaDataReaderException( "Unknown install method '$installMethod'." ); break; } } /** * Returns the version string for the installed eZ Components bundle. * * A version string such as "2008.2.2" is returned. * * @return string */ public function getBundleVersion() { return $this->reader->getBundleVersion(); } /** * Returns a PHP version string that describes the required PHP version for * this installed eZ Components bundle. * * @return string */ public function getRequiredPhpVersion() { return $this->reader->getRequiredPhpVersion(); } /** * Returns whether $componentName is installed * * If installed with PEAR, it checks the PEAR registry whether the * component is there. In case the tarball installation method is used, it * will return true for every component that exists (because all of them * are then available). * * @return bool */ public function isComponentInstalled( $componentName ) { return $this->reader->isComponentInstalled( $componentName ); } /** * Returns the version string of the available $componentName or false when * the component is not installed. * * @return string */ public function getComponentVersion( $componentName ) { return $this->reader->getComponentVersion( $componentName ); } /** * Returns a list of components that $componentName depends on. * * If $componentName is left empty, all installed components are returned. * * The returned array has as keys the component names, and as values the * version of the components. * * @return array(string=>string). */ public function getComponentDependencies( $componentName = null ) { if ( $componentName === null ) { return $this->reader->getComponentDependencies(); } else { return $this->reader->getComponentDependencies( $componentName ); } } } ?> Base-1.9.1/src/metadata/000077500000000000000000000000001320724427000147445ustar00rootroot00000000000000Base-1.9.1/src/metadata/pear.php000066400000000000000000000110241320724427000164020ustar00rootroot00000000000000registry = new PEAR_Registry; } /** * Returns the version string for the installed eZ Components bundle. * * A version string such as "2008.2.2" is returned. * * @return string */ public function getBundleVersion() { @$packageInfo = $this->registry->packageInfo( 'ezcomponents', null, 'components.ez.no' ); return $packageInfo['version']['release']; } /** * Returns a PHP version string that describes the required PHP version for * this installed eZ Components bundle. * * @return string */ public function getRequiredPhpVersion() { @$packageInfo = $this->registry->packageInfo( 'ezcomponents', null, 'components.ez.no' ); if ( array_key_exists( 'required', $packageInfo['dependencies'] ) ) { return $packageInfo['dependencies']['required']['php']['min']; } return $packageInfo['dependencies']['php']['min']; } /** * Returns whether $componentName is installed * * Checks the PEAR registry whether the component is there. * * @return bool */ public function isComponentInstalled( $componentName ) { @$packageInfo = $this->registry->packageInfo( $componentName, null, 'components.ez.no' ); return is_array( $packageInfo ); } /** * Returns the version string of the available $componentName or false when * the component is not installed. * * @return string */ public function getComponentVersion( $componentName ) { @$packageInfo = $this->registry->packageInfo( $componentName, null, 'components.ez.no' ); $release = $packageInfo['version']['release']; return $release === null ? false : $release; } /** * Returns a list of components that $componentName depends on. * * If $componentName is left empty, all installed components are returned. * * The returned array has as keys the component names, and as values the * version of the components. * * @return array(string=>string). */ public function getComponentDependencies( $componentName = 'ezcomponents' ) { @$packageInfo = $this->registry->packageInfo( $componentName, 'dependencies', 'components.ez.no' ); if ( isset( $packageInfo['required']['package'] ) ) { $deps = array(); if ( isset( $packageInfo['required']['package']['name'] ) ) { $deps[$packageInfo['required']['package']['name']] = $packageInfo['required']['package']['min']; } else { foreach ( $packageInfo['required']['package'] as $package ) { $deps[$package['name']] = $package['min']; } } return $deps; } return array(); } } ?> Base-1.9.1/src/metadata/tarball.php000066400000000000000000000114211320724427000170750ustar00rootroot00000000000000xml = simplexml_load_file( $filename ); } /** * Returns the version string for the installed eZ Components bundle. * * A version string such as "2008.2.2" is returned. * * @return string */ public function getBundleVersion() { return (string) $this->xml->version; } /** * Returns a PHP version string that describes the required PHP version for * this installed eZ Components bundle. * * @return string */ public function getRequiredPhpVersion() { return (string) $this->xml->deps->php; } /** * Returns whether $componentName is installed * * Returns true for every component that exists (because all of them are * then available). * * @return bool */ public function isComponentInstalled( $componentName ) { $root = $this->xml->deps->packages->package; foreach ( $root as $package ) { if ( (string) $package['name'] == $componentName ) { return true; } } return false; } /** * Returns the version string of the available $componentName or false when * the component is not installed. * * @return string */ public function getComponentVersion( $componentName ) { $root = $this->xml->deps->packages->package; foreach ( $root as $package ) { if ( (string) $package['name'] == $componentName ) { return (string) $package['version']; } } return false; } /** * Returns a list of components that $componentName depends on. * * If $componentName is left empty, all installed components are returned. * * The returned array has as keys the component names, and as values the * version of the components. It returns null of the $componentName * is not found. * * @return array(string=>string). */ public function getComponentDependencies( $componentName = null ) { $baseVersion = false; $root = $this->xml->deps->packages; $found = $componentName === null ? true : false; // in case $componentName != null, we loop through all the components // in the file, and figure out the new root that we can list dependency // packages from. foreach ( $root->package as $package ) { if ( (string) $package['name'] == 'Base' ) { $baseVersion = $package['version']; } if ( !$found && (string) $package['name'] == $componentName ) { $root = $package->deps; $found = true; } } if ( !$found ) { return null; } // We always add the Base dependency even though it's not in the dependency file. $deps = array(); $deps['Base'] = (string) $baseVersion; if ( !isset( $root->package ) ) { return $deps; } foreach ( $root->package as $package ) { $deps[(string) $package['name']] = (string) $package['version']; } return $deps; } } ?> Base-1.9.1/src/options.php000066400000000000000000000157601320724427000154010ustar00rootroot00000000000000mixed) */ protected $properties; /** * Construct a new options object. * Options are constructed from an option array by default. The constructor * automatically passes the given options to the __set() method to set them * in the class. * * @throws ezcBasePropertyNotFoundException * If trying to access a non existent property. * @throws ezcBaseValueException * If the value for a property is out of range. * @param array(string=>mixed) $options The initial options to set. */ public function __construct( array $options = array() ) { foreach ( $options as $option => $value ) { $this->__set( $option, $value ); } } /** * Merge an array into the actual options object. * This method merges an array of new options into the actual options object. * * @throws ezcBasePropertyNotFoundException * If trying to access a non existent property. * @throws ezcBaseValueException * If the value for a property is out of range. * @param array(string=>mixed) $newOptions The new options. */ public function merge( array $newOptions ) { foreach ( $newOptions as $key => $value ) { $this->__set( $key, $value ); } } /** * Property get access. * Simply returns a given option. * * @throws ezcBasePropertyNotFoundException * If a the value for the property options is not an instance of * @param string $propertyName The name of the option to get. * @return mixed The option value. * @ignore * * @throws ezcBasePropertyNotFoundException * if the given property does not exist. * @throws ezcBasePropertyPermissionException * if the property to be set is a write-only property. */ public function __get( $propertyName ) { if ( $this->__isset( $propertyName ) === true ) { return $this->properties[$propertyName]; } throw new ezcBasePropertyNotFoundException( $propertyName ); } /** * Sets an option. * This method is called when an option is set. * * @param string $propertyName The name of the option to set. * @param mixed $propertyValue The option value. * @ignore * * @throws ezcBasePropertyNotFoundException * if the given property does not exist. * @throws ezcBaseValueException * if the value to be assigned to a property is invalid. * @throws ezcBasePropertyPermissionException * if the property to be set is a read-only property. */ abstract public function __set( $propertyName, $propertyValue ); /** * Returns if a option exists. * * @param string $propertyName Option name to check for. * @return bool Whether the option exists. * @ignore */ public function __isset( $propertyName ) { return array_key_exists( $propertyName, $this->properties ); } /** * Returns if an option exists. * Allows isset() using ArrayAccess. * * @param string $propertyName The name of the option to get. * @return bool Whether the option exists. */ public function offsetExists( $propertyName ) { return $this->__isset( $propertyName ); } /** * Returns an option value. * Get an option value by ArrayAccess. * * @throws ezcBasePropertyNotFoundException * If $propertyName is not a key in the $properties array. * @param string $propertyName The name of the option to get. * @return mixed The option value. */ public function offsetGet( $propertyName ) { return $this->__get( $propertyName ); } /** * Set an option. * Sets an option using ArrayAccess. * * @throws ezcBasePropertyNotFoundException * If $propertyName is not a key in the $properties array. * @throws ezcBaseValueException * If the value for a property is out of range. * @param string $propertyName The name of the option to set. * @param mixed $propertyValue The value for the option. */ public function offsetSet( $propertyName, $propertyValue ) { $this->__set( $propertyName, $propertyValue ); } /** * Unset an option. * Unsets an option using ArrayAccess. * * @throws ezcBasePropertyNotFoundException * If $propertyName is not a key in the $properties array. * @throws ezcBaseValueException * If a the value for a property is out of range. * @param string $propertyName The name of the option to unset. */ public function offsetUnset( $propertyName ) { $this->__set( $propertyName, null ); } /** * Return the current element. * * @return void */ public function current() { return current( $this->properties ); } /** * Return the key of the current element. * * @return void */ public function key() { return key( $this->properties ); } /** * Move forward to next element. * * @return void */ public function next() { return next( $this->properties ); } /** * Rewind the Iterator to the first element. * * @return void */ public function rewind() { reset( $this->properties ); } /** * Check if there is a current element after calls to {@link rewind()} or * {@link next()}. * * @return void */ public function valid() { $key = key( $this->properties ); if( $key !== null && $key !== false) { return true; } return false; } } ?>Base-1.9.1/src/options/000077500000000000000000000000001320724427000146575ustar00rootroot00000000000000Base-1.9.1/src/options/autoload.php000066400000000000000000000060021320724427000171760ustar00rootroot00000000000000mixed) $options */ public function __construct( array $options = array() ) { $this->preload = false; $this->debug = false; parent::__construct( $options ); } /** * Sets the option $name to $value. * * @throws ezcBasePropertyNotFoundException * if the property $name is not defined * @throws ezcBaseValueException * if $value is not correct for the property $name * @param string $name * @param mixed $value * @ignore */ public function __set( $name, $value ) { switch ( $name ) { case 'debug': case 'preload': if ( !is_bool( $value ) ) { throw new ezcBaseValueException( $name, $value, 'bool' ); } $this->properties[$name] = $value; break; default: throw new ezcBasePropertyNotFoundException( $name ); } } } ?> Base-1.9.1/src/struct.php000066400000000000000000000030771320724427000152300ustar00rootroot00000000000000 Base-1.9.1/src/structs/000077500000000000000000000000001320724427000146735ustar00rootroot00000000000000Base-1.9.1/src/structs/file_find_context.php000066400000000000000000000046651320724427000211020ustar00rootroot00000000000000elements = $elements; $this->count = $count; $this->size = $size; } /** * Returns a new instance of this class with the data specified by $array. * * $array contains all the data members of this class in the form: * array('member_name'=>value). * * __set_state makes this class exportable with var_export. * var_export() generates code, that calls this method when it * is parsed with PHP. * * @param array(string=>mixed) $array * @return ezcBaseFileFindContext */ static public function __set_state( array $array ) { return new ezcBaseFileFindContext( $array['elements'], $array['count'], $array['size'] ); } } ?> Base-1.9.1/src/structs/repository_directory.php000066400000000000000000000054271320724427000217170ustar00rootroot00000000000000type = $type; $this->basePath = $basePath; $this->autoloadPath = $autoloadPath; } /** * Returns a new instance of this class with the data specified by $array. * * $array contains all the data members of this class in the form: * array('member_name'=>value). * * __set_state makes this class exportable with var_export. * var_export() generates code, that calls this method when it * is parsed with PHP. * * @param array(string=>mixed) $array * @return ezcBaseRepositoryDirectory */ static public function __set_state( array $array ) { return new ezcBaseRepositoryDirectory( $array['type'], $array['basePath'], $array['autoloadPath'] ); } } ?> Base-1.9.1/tests/000077500000000000000000000000001320724427000135375ustar00rootroot00000000000000Base-1.9.1/tests/autoload/000077500000000000000000000000001320724427000153475ustar00rootroot00000000000000Base-1.9.1/tests/autoload/autoload.php000066400000000000000000000000261320724427000176660ustar00rootroot00000000000000fail( "Expected exception not thrown." ); } catch ( ezcBaseInitInvalidCallbackClassException $e ) { $this->assertEquals( "Class 'classDoesNotExist' does not exist, or does not implement the 'ezcBaseConfigurationInitializer' interface.", $e->getMessage() ); } } public function testCallbackWithClassThatDoesNotImplementTheInterface() { try { ezcBaseInit::setCallback( 'testBaseInit', 'ezcBaseFeatures' ); $this->fail( "Expected exception not thrown." ); } catch ( ezcBaseInitInvalidCallbackClassException $e ) { $this->assertEquals( "Class 'ezcBaseFeatures' does not exist, or does not implement the 'ezcBaseConfigurationInitializer' interface.", $e->getMessage() ); } } public function testCallback1() { $obj = testBaseInitClass::getInstance(); $this->assertEquals( false, $obj->configured ); } public function testCallback2() { ezcBaseInit::setCallback( 'testBaseInit', 'testBaseInitCallback' ); $obj = testBaseInitClass::getInstance(); $this->assertEquals( true, $obj->configured ); } public function testCallback3() { try { ezcBaseInit::setCallback( 'testBaseInit', 'testBaseInitCallback' ); $this->fail( "Expected exception not thrown." ); } catch ( ezcBaseInitCallbackConfiguredException $e ) { $this->assertEquals( "The 'testBaseInit' is already configured with callback class 'testBaseInitCallback'.", $e->getMessage() ); } } public static function suite() { return new PHPUnit_Framework_TestSuite("ezcBaseInitTest"); } } ?> Base-1.9.1/tests/base_options_test.php000066400000000000000000000112541320724427000177770ustar00rootroot00000000000000properties; } catch ( ezcBasePropertyNotFoundException $e ) { return; } $this->fail( "ezcBasePropertyNotFoundException not thrown on access to forbidden property \$properties" ); } public function testGetOffsetAccessFailure() { $opt = new ezcBaseTestOptions(); try { echo $opt["properties"]; } catch ( ezcBasePropertyNotFoundException $e ) { return; } $this->fail( "ezcBasePropertyNotFoundException not thrown on access to forbidden property \$properties" ); } public function testSetOffsetAccessFailure() { $opt = new ezcBaseTestOptions(); try { $opt["properties"] = "foo"; } catch ( ezcBasePropertyNotFoundException $e ) { return; } $this->fail( "ezcBasePropertyNotFoundException not thrown on access to forbidden property \$properties" ); } public function testConstructorWithParameters() { $options = new ezcBaseTestOptions( array( 'foo' => 'xxx' ) ); $this->assertEquals( 'xxx', $options->foo ); } public function testMerge() { $options = new ezcBaseTestOptions(); $this->assertEquals( 'bar', $options->foo ); $options->merge( array( 'foo' => 'xxx' ) ); $this->assertEquals( 'xxx', $options->foo ); } public function testOffsetExists() { $options = new ezcBaseTestOptions(); $this->assertEquals( true, $options->offsetExists( 'foo' ) ); $this->assertEquals( false, $options->offsetExists( 'bar' ) ); } public function testOffsetSet() { $options = new ezcBaseTestOptions(); $this->assertEquals( 'bar', $options->foo ); $options->offsetSet( 'foo', 'xxx' ); $this->assertEquals( 'xxx', $options->foo ); } public function testOffsetUnset() { $options = new ezcBaseTestOptions(); $this->assertEquals( 'bar', $options->foo ); $options->offsetUnset( 'foo' ); $this->assertEquals( null, $options->foo ); $this->assertEquals( true, $options->offsetExists( 'foo' ) ); } public function testAutoloadOptions() { $options = new ezcBaseAutoloadOptions(); try { $options->no_such_property = 'value'; $this->fail( 'Expected exception was not thrown.' ); } catch ( ezcBasePropertyNotFoundException $e ) { $this->assertEquals( "No such property name 'no_such_property'.", $e->getMessage() ); } try { $options->preload = 'wrong value'; $this->fail( 'Expected exception was not thrown.' ); } catch ( ezcBaseValueException $e ) { $this->assertEquals( "The value 'wrong value' that you were trying to assign to setting 'preload' is invalid. Allowed values are: bool.", $e->getMessage() ); } } public function testIterator() { $options = new ezcBaseTestOptions(); $expectedArray = array( "foo" => "bar", "baz" => "blah" ); $resultArray = array(); foreach( $options as $key => $option ) { $resultArray[$key] = $option; } $this->assertEquals( $expectedArray, $resultArray ); } } ?>Base-1.9.1/tests/base_test.php000066400000000000000000000440711320724427000162270ustar00rootroot00000000000000assertEquals( "The setting 'broken' is not a valid configuration setting.", $e->getMessage() ); } } public function testConfigExceptionOutOfRange1() { try { throw new ezcBaseSettingValueException( 'broken', 42 ); } catch ( ezcBaseSettingValueException $e ) { $this->assertEquals( "The value '42' that you were trying to assign to setting 'broken' is invalid.", $e->getMessage() ); } } public function testConfigExceptionOutOfRange2() { try { throw new ezcBaseSettingValueException( 'broken', 42, "int, 40 - 48" ); } catch ( ezcBaseSettingValueException $e ) { $this->assertEquals( "The value '42' that you were trying to assign to setting 'broken' is invalid. Allowed values are: int, 40 - 48", $e->getMessage() ); } } public function testConfigExceptionOutOfRange3() { try { throw new ezcBaseSettingValueException( 'broken', array(1, 1, 3, 4, 5), 'int' ); } catch ( ezcBaseSettingValueException $e ) { $this->assertEquals( "The value 'a:5:{i:0;i:1;i:1;i:1;i:2;i:3;i:3;i:4;i:4;i:5;}' that you were trying to assign to setting 'broken' is invalid. Allowed values are: int", $e->getMessage() ); } } public function testFileIoException1() { try { throw new ezcBaseFileIoException( 'testfile.php', ezcBaseFileException::READ ); } catch ( ezcBaseFileIoException $e ) { $this->assertEquals( "An error occurred while reading from 'testfile.php'.", $e->getMessage() ); } } public function testFileIoException2() { try { throw new ezcBaseFileIoException( 'testfile.php', ezcBaseFileException::WRITE ); } catch ( ezcBaseFileIoException $e ) { $this->assertEquals( "An error occurred while writing to 'testfile.php'.", $e->getMessage() ); } } public function testFileIoException3() { try { throw new ezcBaseFileIoException( 'testfile.php', ezcBaseFileException::WRITE, "Extra extra" ); } catch ( ezcBaseFileIoException $e ) { $this->assertEquals( "An error occurred while writing to 'testfile.php'. (Extra extra)", $e->getMessage() ); } } public function testFileNotFoundException1() { try { throw new ezcBaseFileNotFoundException( 'testfile.php' ); } catch ( ezcBaseFileNotFoundException $e ) { $this->assertEquals( "The file 'testfile.php' could not be found.", $e->getMessage() ); } } public function testFileNotFoundException2() { try { throw new ezcBaseFileNotFoundException( 'testfile.php', 'INI' ); } catch ( ezcBaseFileNotFoundException $e ) { $this->assertEquals( "The INI file 'testfile.php' could not be found.", $e->getMessage() ); } } public function testFileNotFoundException3() { try { throw new ezcBaseFileNotFoundException( 'testfile.php', 'INI', "Extra extra" ); } catch ( ezcBaseFileNotFoundException $e ) { $this->assertEquals( "The INI file 'testfile.php' could not be found. (Extra extra)", $e->getMessage() ); } } public function testFilePermissionException1() { try { throw new ezcBaseFilePermissionException( 'testfile.php', ezcBaseFileException::READ ); } catch ( ezcBaseFilePermissionException $e ) { $this->assertEquals( "The file 'testfile.php' can not be opened for reading.", $e->getMessage() ); } } public function testFilePermissionException2() { try { throw new ezcBaseFilePermissionException( 'testfile.php', ezcBaseFileException::WRITE ); } catch ( ezcBaseFileException $e ) { $this->assertEquals( "The file 'testfile.php' can not be opened for writing.", $e->getMessage() ); } } public function testFilePermissionException3() { try { throw new ezcBaseFilePermissionException( 'testfile.php', ezcBaseFileException::EXECUTE ); } catch ( ezcBaseException $e ) { $this->assertEquals( "The file 'testfile.php' can not be executed.", $e->getMessage() ); } } public function testFilePermissionException4() { try { throw new ezcBaseFilePermissionException( 'testfile.php', ezcBaseFilePermissionException::CHANGE, "Extra extra" ); } catch ( ezcBaseException $e ) { $this->assertEquals( "The permissions for 'testfile.php' can not be changed. (Extra extra)", $e->getMessage() ); } } public function testFilePermissionException5() { try { throw new ezcBaseFilePermissionException( 'testfile.php', ezcBaseFilePermissionException::READ | ezcBaseFilePermissionException::WRITE, "Extra extra" ); } catch ( ezcBaseException $e ) { $this->assertEquals( "The file 'testfile.php' can not be opened for reading and writing. (Extra extra)", $e->getMessage() ); } } public function testFilePermissionException6() { try { throw new ezcBaseFilePermissionException( 'testfile.php', ezcBaseFilePermissionException::REMOVE, "Extra extra" ); } catch ( ezcBaseException $e ) { $this->assertEquals( "The file 'testfile.php' can not be removed. (Extra extra)", $e->getMessage() ); } } public function testPropertyNotFoundException() { try { throw new ezcBasePropertyNotFoundException( 'broken' ); } catch ( ezcBasePropertyNotFoundException $e ) { $this->assertEquals( "No such property name 'broken'.", $e->getMessage() ); } } public function testPropertyPermissionException1() { try { throw new ezcBasePropertyPermissionException( 'broken', ezcBasePropertyPermissionException::READ ); } catch ( ezcBaseException $e ) { $this->assertEquals( "The property 'broken' is read-only.", $e->getMessage() ); } } public function testPropertyPermissionException2() { try { throw new ezcBasePropertyPermissionException( 'broken', ezcBasePropertyPermissionException::WRITE ); } catch ( ezcBaseException $e ) { $this->assertEquals( "The property 'broken' is write-only.", $e->getMessage() ); } } public function testBaseValue1() { try { throw new ezcBaseValueException( 'broken', array( 42 ) ); } catch ( ezcBaseValueException $e ) { $this->assertEquals( "The value 'a:1:{i:0;i:42;}' that you were trying to assign to setting 'broken' is invalid.", $e->getMessage() ); } } public function testBaseValue2() { try { throw new ezcBaseValueException( 'broken', "string", "strings" ); } catch ( ezcBaseValueException $e ) { $this->assertEquals( "The value 'string' that you were trying to assign to setting 'broken' is invalid. Allowed values are: strings.", $e->getMessage() ); $this->assertEquals( "The value 'string' that you were trying to assign to setting 'broken' is invalid. Allowed values are: strings.", $e->originalMessage ); } } public function testExtraDirNotFoundException() { try { ezcBase::addClassRepository( 'wrongDir' ); } catch ( ezcBaseFileNotFoundException $e ) { $this->assertEquals( "The base directory file 'wrongDir' could not be found.", $e->getMessage() ); } } public function testExtraDirBaseNotFoundException() { try { ezcBase::addClassRepository( '.', './wrongAutoloadDir' ); } catch ( ezcBaseFileNotFoundException $e ) { $this->assertEquals( "The autoload directory file './wrongAutoloadDir' could not be found.", $e->getMessage() ); } } public function testBaseAddAndGetAutoloadDirs1() { ezcBase::addClassRepository( __DIR__ ); $resultArray = ezcBase::getRepositoryDirectories(); if ( count( $resultArray ) != 2 ) { $this->fail( "Duplicating or missing extra autoload dirs while adding." ); } if ( !isset( $resultArray['ezc'] ) ) { $this->fail( "No packageDir found in result of getRepositoryDirectories()" ); } if ( !isset( $resultArray[0] ) || $resultArray[0]->basePath != __DIR__ ) { $this->fail( "Extra base dir '{$resultArray[0]->basePath}' is added incorrectly" ); } if ( !isset( $resultArray[0] ) || $resultArray[0]->autoloadPath != __DIR__ . '/autoload' ) { $this->fail( "Extra autoload dir '{$resultArray[0]->autoloadPath}' is added incorrectly" ); } } // this test is sorta obsolete, but we keep it around for good measure public function testBaseAddAndGetAutoloadDirs2() { ezcBase::addClassRepository( __DIR__, __DIR__ . '/autoload' ); ezcBase::addClassRepository( __DIR__ . '/test_repository', __DIR__ . '/test_repository/autoload_files' ); ezcBase::addClassRepository( __DIR__ . '/test_repository', __DIR__ . '/test_repository/autoload_files' ); $resultArray = ezcBase::getRepositoryDirectories(); if ( count( $resultArray ) != 5 ) { $this->fail( "Duplicating or missing extra autoload dirs while adding." ); } if ( !isset( $resultArray['ezc'] ) ) { $this->fail( "No packageDir found in result of getRepositoryDirectories()" ); } if ( !isset( $resultArray[2] ) || $resultArray[2]->autoloadPath != __DIR__ . '/test_repository/autoload_files' ) { $this->fail( "Extra autoload dir '{$resultArray[2]->autoloadPath}' is added incorrectly" ); } self::assertEquals( true, class_exists( 'trBasetestClass', true ) ); self::assertEquals( true, class_exists( 'trBasetestClass2', true ) ); try { self::assertEquals( false, class_exists( 'trBasetestClass3', true ) ); self::fail( 'The expected exception was not thrown.' ); } catch ( ezcBaseAutoloadException $e ) { self::assertStringStartsWith( "Could not find a class to file mapping for 'trBasetestClass3'. Searched for basetest_class3_autoload.php, basetest_autoload.php, autoload.php in:", $e->getMessage()); } self::assertEquals( true, class_exists( 'trBasetestLongClass', true ) ); try { class_exists( 'trBasetestClass4', true ); self::fail( 'The expected exception was not thrown.' ); } catch ( ezcBaseFileNotFoundException $e ) { self::assertEquals( "The file '" . __DIR__ . "/test_repository/TestClasses/base_test_class_number_four.php' could not be found.", $e->getMessage() ); } } public function testBaseAddAndGetAutoloadDirs3() { ezcBase::addClassRepository( __DIR__ . '/extra_repository', null, 'ext' ); $resultArray = ezcBase::getRepositoryDirectories(); self::assertEquals( true, array_key_exists( 'ezc', $resultArray ) ); self::assertEquals( true, array_key_exists( 'ext', $resultArray ) ); //self::assertEquals( true, class_exists( 'extTranslationTest', true ) ); //self::assertEquals( true, class_exists( 'ezcTranslationTsBackend', true ) ); } public function testBaseAddAndGetAutoloadDirs4() { ezcBase::addClassRepository( __DIR__ . '/test_repository', __DIR__ . '/test_repository/autoload_files', 'tr' ); try { ezcBase::addClassRepository( __DIR__ . '/test_repository', __DIR__ . '/test_repository/autoload_files', 'tr' ); } catch ( ezcBaseDoubleClassRepositoryPrefixException $e ) { self::assertEquals( "The class repository in '" . __DIR__ . "/test_repository' (with autoload dir '" . __DIR__ . "/test_repository/autoload_files') can not be added because another class repository already uses the prefix 'tr'.", $e->getMessage() ); } $resultArray = ezcBase::getRepositoryDirectories(); self::assertEquals( 7, count( $resultArray ) ); self::assertEquals( true, array_key_exists( 'ezc', $resultArray ) ); self::assertEquals( true, array_key_exists( 'tr', $resultArray ) ); self::assertEquals( __DIR__ . '/test_repository', $resultArray['tr']->basePath ); self::assertEquals( __DIR__ . '/test_repository/autoload_files', $resultArray['tr']->autoloadPath ); } public function testNoPrefixAutoload() { ezcBase::addClassRepository( __DIR__ . '/test_repository', __DIR__ . '/test_repository/autoload_files' ); ezc_autoload( 'Objet' ); if ( !class_exists( 'Objet' ) ) { $this->fail( "Autoload does not handle classes with no prefix" ); } } public function testNoPrefixAutoload2() { ezcBase::addClassRepository( __DIR__ . '/issue15896' ); ezc_autoload( 'ab' ); } public function testCheckDependencyExtension() { ezcBase::checkDependency( 'Tester', ezcBase::DEP_PHP_EXTENSION, 'standard' ); } public function testCheckDependencyVersion() { ezcBase::checkDependency( 'Tester', ezcBase::DEP_PHP_VERSION, '5.1.1' ); } public function testInvalidClass() { $this->setExpectedException( 'ezcBaseAutoloadException', "Could not find a class to file mapping for 'ezcNoSuchClass'. Searched for no_such_autoload.php, no_autoload.php, autoload.php in:" ); self::assertEquals( false, class_exists( 'ezcNoSuchClass', true ) ); } public function testDebug() { try { class_exists( 'ezcTestingOne' ); self::fail( "There should have been an exception" ); } catch ( ezcBaseAutoloadException $e ) { } } public function testNoDebug() { try { $options = new ezcBaseAutoloadOptions; $options->debug = false; ezcBase::setOptions( $options ); class_exists( 'ezcTestingOne' ); } catch ( Exception $e ) { self::fail( "There should not have been an exception. Found one: " . $e->getMessage() ); } } public function testGetInstallationPath() { $this->markTestSkipped( 'What should behavior be in a composer installed environment?' ); $path = ezcBase::getInstallationPath(); $pathParts = explode( DIRECTORY_SEPARATOR, $path ); self::assertEquals( array( 'trunk', '' ), array_splice( $pathParts, -2 ) ); self::assertEquals( DIRECTORY_SEPARATOR, substr( $path, -1 ) ); } public function testSetInvalidRunMode() { try { ezcBase::setRunMode( -3 ); self::fail( "Expected exception not thrown." ); } catch ( ezcBaseValueException $e ) { self::assertEquals( "The value '-3' that you were trying to assign to setting 'runMode' is invalid. Allowed values are: ezcBase::MODE_PRODUCTION or ezcBase::MODE_DEVELOPMENT.", $e->getMessage() ); } } public function testSetGetRunMode() { self::assertEquals( ezcBase::MODE_DEVELOPMENT, ezcBase::getRunMode() ); self::assertEquals( true, ezcBase::inDevMode() ); ezcBase::setRunMode( ezcBase::MODE_PRODUCTION ); self::assertEquals( ezcBase::MODE_PRODUCTION, ezcBase::getRunMode() ); self::assertEquals( false, ezcBase::inDevMode() ); ezcBase::setRunMode( ezcBase::MODE_DEVELOPMENT ); self::assertEquals( ezcBase::MODE_DEVELOPMENT, ezcBase::getRunMode() ); self::assertEquals( true, ezcBase::inDevMode() ); } public function testGetInstallMethod() { self::assertEquals( 'custom', ezcBase::getInstallMethod() ); } public function setup() { $options = new ezcBaseAutoloadOptions; $options->debug = true; ezcBase::setOptions( $options ); } public function teardown() { $options = new ezcBaseAutoloadOptions; $options->debug = true; ezcBase::setOptions( $options ); } public static function suite() { return new PHPUnit_Framework_TestSuite("ezcBaseTest"); } } ?> Base-1.9.1/tests/bootstrap.php000066400000000000000000000007731320724427000162740ustar00rootroot00000000000000getComponentVersion( 'Base' ), "\n"; echo $md->getComponentVersion( 'Archive' ), "\n"; echo $md->getComponentVersion( 'Blah' ), "\n"; echo $md->getComponentVersion( 'Configuration' ), "\n"; echo $md->isComponentInstalled( 'Base' ) ? "true" : "false", "\n"; echo $md->isComponentInstalled( 'Archive' ) ? "true" : "false", "\n"; echo $md->isComponentInstalled( 'Blah' ) ? "true" : "false", "\n"; echo $md->isComponentInstalled( 'Configuration' ) ? "true" : "false", "\n"; ?> Base-1.9.1/tests/extra_repository/000077500000000000000000000000001320724427000171615ustar00rootroot00000000000000Base-1.9.1/tests/extra_repository/Translation/000077500000000000000000000000001320724427000214575ustar00rootroot00000000000000Base-1.9.1/tests/extra_repository/Translation/test.php000066400000000000000000000000461320724427000231470ustar00rootroot00000000000000 Base-1.9.1/tests/extra_repository/autoload/000077500000000000000000000000001320724427000207715ustar00rootroot00000000000000Base-1.9.1/tests/extra_repository/autoload/translation_autoload.php000066400000000000000000000001161320724427000257260ustar00rootroot00000000000000 'Translation/test.php', ); ?> Base-1.9.1/tests/features_unix_test.php000066400000000000000000000122051320724427000201700ustar00rootroot00000000000000markTestSkipped( 'Unix tests' ); } } public function testSupportsLink() { $this->assertEquals( true, ezcBaseFeatures::supportsLink() ); } public function testSupportsSymLink() { $this->assertEquals( true, ezcBaseFeatures::supportsSymLink() ); } public function testSupportsUserId() { $this->assertEquals( true, ezcBaseFeatures::supportsUserId() ); } /* // Need to find a way to make this test work, as setting global enviroment variables // is not working (putenv( "PATH=" ) doesn't unset $_ENV["PATH"]) // One solution would be to use in the ezcBaseFeatures::getPath(): // getenv( 'PATH' ) instead of $_ENV['PATH'] (but that won't work under IIS). public function testHasImageIdentifyNoPath() { $envPath = getenv( 'PATH' ); putenv( "PATH=" ); $this->assertEquals( false, ezcBaseFeatures::hasImageIdentify() ); putenv( "PATH={$envPath}" ); } */ public function testHasImageConvert() { $this->assertEquals( true, ezcBaseFeatures::hasImageConvert() ); } public function testGetImageConvertExecutable() { $this->assertEquals( '/usr/bin/convert', ezcBaseFeatures::getImageConvertExecutable() ); } public function testGetImageIdentifyExecutable() { $this->assertEquals( '/usr/bin/identify', ezcBaseFeatures::getImageIdentifyExecutable() ); } public function testHasImageIdentify() { $this->assertEquals( true, ezcBaseFeatures::hasImageIdentify() ); } public function testHasExtensionSupport1() { $this->assertEquals( true, ezcBaseFeatures::hasExtensionSupport( 'standard' ) ); } public function testHasExtensionSupportNotFound1() { $this->assertEquals( false, ezcBaseFeatures::hasExtensionSupport( 'non_existent_extension' ) ); try { throw new ezcBaseExtensionNotFoundException( 'non_existent_extension', null, 'This is just a test.' ); } catch ( ezcBaseExtensionNotFoundException $e ) { $this->assertEquals( "The extension 'non_existent_extension' could not be found. This is just a test.", $e->getMessage() ); } } public function testHasExtensionSupportNotFound2() { $this->assertEquals( false, ezcBaseFeatures::hasExtensionSupport( 'non_existent_extension' ) ); try { throw new ezcBaseExtensionNotFoundException( 'non_existent_extension', '1.2', 'This is just a test.' ); } catch ( ezcBaseExtensionNotFoundException $e ) { $this->assertEquals( "The extension 'non_existent_extension' with version '1.2' could not be found. This is just a test.", $e->getMessage() ); } } public function testHasFunction1() { $this->assertEquals( true, ezcBaseFeatures::hasFunction( 'function_exists' ) ); } public function testHasFunction2() { $this->assertEquals( false, ezcBaseFeatures::hasFunction( 'non_existent_function_in_php' ) ); } public function testHasExtensionSupport2() { $this->assertEquals( true, ezcBaseFeatures::hasExtensionSupport( 'date', '5.1.0' ) ); } public function testClassExists() { $this->assertEquals( true, ezcBaseFeatures::classExists( 'Exception', false ) ); } public function testClassExistsAutoload() { $this->assertEquals( true, ezcBaseFeatures::classExists( 'ezcBaseFeatures' ) ); } public function testClassExistsNotFound() { $this->assertEquals( false, ezcBaseFeatures::classExists( 'ezcBaseNonExistingClass', false ) ); } public function testClassExistsNotFoundAutoload() { $this->assertEquals( false, ezcBaseFeatures::classExists( 'ezcBaseNonExistingClass' ) ); } public static function suite() { return new PHPUnit_Framework_TestSuite(__CLASS__); } } ?> Base-1.9.1/tests/features_windows_test.php000066400000000000000000000120711320724427000207000ustar00rootroot00000000000000markTestSkipped( 'Windows tests' ); } } public function testSupportsLink() { $this->assertFalse( ezcBaseFeatures::supportsLink() ); } public function testSupportsSymLink() { $this->assertFalse( ezcBaseFeatures::supportsSymLink() ); } public function testSupportsUserId() { $this->assertFalse( ezcBaseFeatures::supportsUserId() ); } /* // Need to find a way to make this test work, as setting global enviroment variables // is not working (putenv( "PATH=" ) doesn't unset $_ENV["PATH"]) // One solution would be to use in the ezcBaseFeatures::getPath(): // getenv( 'PATH' ) instead of $_ENV['PATH'] (but that won't work under IIS). public function testHasImageIdentifyNoPath() { $envPath = getenv( 'PATH' ); putenv( "PATH=" ); $this->assertEquals( false, ezcBaseFeatures::hasImageIdentify() ); putenv( "PATH={$envPath}" ); } */ public function testHasImageConvert() { $this->assertTrue( ezcBaseFeatures::hasImageConvert() ); } public function testGetImageConvertExecutable() { $this->assertNotNull( ezcBaseFeatures::getImageConvertExecutable() ); } public function testGetImageIdentifyExecutable() { $this->assertNotNull( ezcBaseFeatures::getImageIdentifyExecutable() ); } public function testHasImageIdentify() { $this->assertTrue( ezcBaseFeatures::hasImageIdentify() ); } public function testHasExtensionSupport1() { $this->assertTrue( ezcBaseFeatures::hasExtensionSupport( 'standard' ) ); } public function testHasExtensionSupportNotFound1() { $this->assertEquals( false, ezcBaseFeatures::hasExtensionSupport( 'non_existent_extension' ) ); try { throw new ezcBaseExtensionNotFoundException( 'non_existent_extension', null, 'This is just a test.' ); } catch ( ezcBaseExtensionNotFoundException $e ) { $this->assertEquals( "The extension 'non_existent_extension' could not be found. This is just a test.", $e->getMessage() ); } } public function testHasExtensionSupportNotFound2() { $this->assertEquals( false, ezcBaseFeatures::hasExtensionSupport( 'non_existent_extension' ) ); try { throw new ezcBaseExtensionNotFoundException( 'non_existent_extension', '1.2', 'This is just a test.' ); } catch ( ezcBaseExtensionNotFoundException $e ) { $this->assertEquals( "The extension 'non_existent_extension' with version '1.2' could not be found. This is just a test.", $e->getMessage() ); } } public function testHasFunction1() { $this->assertEquals( true, ezcBaseFeatures::hasFunction( 'function_exists' ) ); } public function testHasFunction2() { $this->assertEquals( false, ezcBaseFeatures::hasFunction( 'non_existent_function_in_php' ) ); } public function testHasExtensionSupport2() { $this->assertEquals( true, ezcBaseFeatures::hasExtensionSupport( 'date', '5.1.0' ) ); } public function testClassExists() { $this->assertEquals( true, ezcBaseFeatures::classExists( 'Exception', false ) ); } public function testClassExistsAutoload() { $this->assertEquals( true, ezcBaseFeatures::classExists( 'ezcBaseFeatures' ) ); } public function testClassExistsNotFound() { $this->assertEquals( false, ezcBaseFeatures::classExists( 'ezcBaseNonExistingClass', false ) ); } public function testClassExistsNotFoundAutoload() { $this->assertEquals( false, ezcBaseFeatures::classExists( 'ezcBaseNonExistingClass' ) ); } public static function suite() { return new PHPUnit_Framework_TestSuite( __CLASS__ ); } } ?> Base-1.9.1/tests/file_calculate_relative_path_test.php000066400000000000000000000125231320724427000231550ustar00rootroot00000000000000 Base-1.9.1/tests/file_copy_recursive_test.php000066400000000000000000000174631320724427000213620ustar00rootroot00000000000000tempDir = $this->createTempDir( __CLASS__ ); mkdir( $this->tempDir . '/dir1' ); mkdir( $this->tempDir . '/dir2' ); mkdir( $this->tempDir . '/dir2/dir1' ); mkdir( $this->tempDir . '/dir2/dir1/dir1' ); mkdir( $this->tempDir . '/dir2/dir2' ); mkdir( $this->tempDir . '/dir4' ); mkdir( $this->tempDir . '/dir5' ); mkdir( $this->tempDir . '/dir6' ); mkdir( $this->tempDir . '/dir7' ); mkdir( $this->tempDir . '/dir7/0' ); file_put_contents( $this->tempDir . '/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir1/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir1/.file3.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir1/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir1/dir1/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir2/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir4/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir4/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir5/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir5/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir6/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir6/file2.txt', 'test' ); chmod( $this->tempDir . '/dir4/file1.txt', 0 ); chmod( $this->tempDir . '/dir5', 0 ); chmod( $this->tempDir . '/dir6', 0400 ); } protected function tearDown() { chmod( $this->tempDir . '/dir5', 0700 ); chmod( $this->tempDir . '/dir6', 0700 ); $this->removeTempDir(); } public function testRecursiveCopyEmptyDir() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir1', $this->tempDir . '/dest' ); $this->assertEquals( count( ezcBaseFile::findRecursive( $this->tempDir . '/dir1' ) ), count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) ); $this->assertSame( 0775, fileperms( $this->tempDir . '/dest' ) & 0777, 'Directory mode should equal 0775.' ); } public function testRecursiveCopyFile() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir1/file1.txt', $this->tempDir . '/dest' ); $this->assertTrue( is_file( $this->tempDir . '/dest' ) ); $this->assertSame( 0664, fileperms( $this->tempDir . '/dest' ) & 0777, 'File mode should equal 0664.' ); } public function testRecursiveCopyEmptyDirMode() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir1', $this->tempDir . '/dest', -1, 0777, 0777 ); $this->assertEquals( count( ezcBaseFile::findRecursive( $this->tempDir . '/dir1' ) ), count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) ); $this->assertSame( 0777, fileperms( $this->tempDir . '/dest' ) & 0777, 'Directory mode should equal 0777.' ); } public function testRecursiveCopyFileMode() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir1/file1.txt', $this->tempDir . '/dest', -1, 0777, 0777 ); $this->assertTrue( is_file( $this->tempDir . '/dest' ) ); $this->assertSame( 0777, fileperms( $this->tempDir . '/dest' ) & 0777, 'File mode should equal 0777.' ); } public function testRecursiveCopyFullDir() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir2', $this->tempDir . '/dest' ); $this->assertEquals( count( ezcBaseFile::findRecursive( $this->tempDir . '/dir2' ) ), count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) ); } public function testRecursiveCopyFullDirDepthZero() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir2', $this->tempDir . '/dest', 0 ); $this->assertEquals( 0, count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) ); $this->assertTrue( is_dir( $this->tempDir . '/dest' ) ); } public function testRecursiveCopyFullDirLimitedDepth() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir2', $this->tempDir . '/dest', 2 ); $this->assertEquals( 3, count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) ); } public function testRecursiveCopyFailureNotExisting() { try { ezcBaseFile::copyRecursive( $this->tempDir . '/not_existing', $this->tempDir . '/dest' ); } catch ( ezcBaseFileNotFoundException $e ) { return; } $this->fail( 'Expected ezcBaseFileNotFoundException.' ); } public function testRecursiveCopyFailureNotReadable() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir5', $this->tempDir . '/dest' ); $this->assertFalse( is_dir( $this->tempDir . '/dest' ) ); $this->assertFalse( is_file( $this->tempDir . '/dest' ) ); } public function testRecursiveCopyFailureNotWriteable() { try { ezcBaseFile::copyRecursive( $this->tempDir . '/dir2', $this->tempDir . '/dir4' ); } catch ( ezcBaseFilePermissionException $e ) { return; } $this->fail( 'Expected ezcBaseFilePermissionException.' ); } public static function suite() { return new PHPUnit_Framework_TestSuite( __CLASS__ ); } public function testRecursiveCopyDirCalled0() { ezcBaseFile::copyRecursive( $this->tempDir . '/dir7', $this->tempDir . '/dest' ); $this->assertEquals( count( ezcBaseFile::findRecursive( $this->tempDir . '/dir7' ) ), count( ezcBaseFile::findRecursive( $this->tempDir . '/dest' ) ) ); $this->assertTrue( is_dir( $this->tempDir . '/dest/0' ) ); } } ?> Base-1.9.1/tests/file_find_recursive_test.php000066400000000000000000000156401320724427000213230ustar00rootroot00000000000000 'src/base.php', 1 => 'src/base_autoload.php', 2 => 'src/exceptions/autoload.php', 3 => 'src/exceptions/double_class_repository_prefix.php', 4 => 'src/exceptions/exception.php', 5 => 'src/exceptions/extension_not_found.php', 6 => 'src/exceptions/file_exception.php', 7 => 'src/exceptions/file_io.php', 8 => 'src/exceptions/file_not_found.php', 9 => 'src/exceptions/file_permission.php', 10 => 'src/exceptions/functionality_not_supported.php', 11 => 'src/exceptions/init_callback_configured.php', 12 => 'src/exceptions/invalid_callback_class.php', 13 => 'src/exceptions/invalid_parent_class.php', 14 => 'src/exceptions/property_not_found.php', 15 => 'src/exceptions/property_permission.php', 16 => 'src/exceptions/setting_not_found.php', 17 => 'src/exceptions/setting_value.php', 18 => 'src/exceptions/value.php', 19 => 'src/exceptions/whatever.php', 20 => 'src/ezc_bootstrap.php', 21 => 'src/features.php', 22 => 'src/file.php', 23 => 'src/init.php', 24 => 'src/interfaces/configuration_initializer.php', 25 => 'src/interfaces/exportable.php', 26 => 'src/interfaces/persistable.php', 27 => 'src/metadata.php', 28 => 'src/metadata/pear.php', 29 => 'src/metadata/tarball.php', 30 => 'src/options.php', 31 => 'src/options/autoload.php', 32 => 'src/struct.php', 33 => 'src/structs/file_find_context.php', 34 => 'src/structs/repository_directory.php', ); $files = ezcBaseFile::findRecursive( "src", array(), array( '@/docs/@', '@svn@', '@\.swp$@', '@git@' ), $stats ); self::assertEquals( $expected, $files ); self::assertEquals( array( 'size' => 133978, 'count' => 35 ), $stats ); } public function testRecursive2() { $expected = array( 0 => 'vendor/zetacomponents/unit-test/CREDITS', 1 => 'vendor/zetacomponents/unit-test/ChangeLog', 2 => 'vendor/zetacomponents/unit-test/NOTICE', 3 => 'vendor/zetacomponents/unit-test/composer.json', 4 => 'vendor/zetacomponents/unit-test/design/class_diagram.png', 5 => 'vendor/zetacomponents/unit-test/src/constraint/image.php', 6 => 'vendor/zetacomponents/unit-test/src/regression_suite.php', 7 => 'vendor/zetacomponents/unit-test/src/regression_test.php', 8 => 'vendor/zetacomponents/unit-test/src/test/case.php', 9 => 'vendor/zetacomponents/unit-test/src/test/image_case.php', 10 => 'vendor/zetacomponents/unit-test/src/test_autoload.php', ); self::assertEquals( $expected, ezcBaseFile::findRecursive( "vendor/zetacomponents/unit-test", array( '@^vendor/zetacomponents/unit-test/@' ), array( '@/docs/@', '@\.git@', '@\.swp$@' ), $stats ) ); self::assertEquals( array( 'size' => 191012, 'count' => 11 ), $stats ); } public function testRecursive3() { $expected = array ( 0 => 'vendor/zetacomponents/unit-test/design/class_diagram.png', ); self::assertEquals( $expected, ezcBaseFile::findRecursive( "vendor/zetacomponents/unit-test", array( '@\.png$@' ), array( '@\.svn@' ), $stats ) ); self::assertEquals( array( 'size' => 166066, 'count' => 1 ), $stats ); } public function testRecursive4() { $expected = array ( 0 => 'vendor/zetacomponents/unit-test/design/class_diagram.png', ); self::assertEquals( $expected, ezcBaseFile::findRecursive( "vendor/zetacomponents/unit-test", array( '@/design/@' ), array( '@\.svn@' ), $stats ) ); self::assertEquals( array( 'size' => 166066, 'count' => 1 ), $stats ); } public function testRecursive5() { $expected = array ( 0 => 'vendor/zetacomponents/unit-test/design/class_diagram.png', 1 => 'vendor/zetacomponents/unit-test/src/constraint/image.php', 2 => 'vendor/zetacomponents/unit-test/src/regression_suite.php', 3 => 'vendor/zetacomponents/unit-test/src/regression_test.php', 4 => 'vendor/zetacomponents/unit-test/src/test/case.php', 5 => 'vendor/zetacomponents/unit-test/src/test/image_case.php', 6 => 'vendor/zetacomponents/unit-test/src/test_autoload.php', ); self::assertEquals( $expected, ezcBaseFile::findRecursive( "vendor/zetacomponents/unit-test", array( '@\.(php|png)$@' ), array( '@/docs/@', '@\.svn@' ) ) ); } public function testRecursive6() { $expected = array(); self::assertEquals( $expected, ezcBaseFile::findRecursive( "vendor/zetacomponents/unit-test", array( '@xxx@' ) ) ); } public function testNonExistingDirectory() { $expected = array(); try { ezcBaseFile::findRecursive( "NotHere", array( '@xxx@' ) ); } catch ( ezcBaseFileNotFoundException $e ) { self::assertEquals( "The directory file 'NotHere' could not be found.", $e->getMessage() ); } } public function testStatsEmptyArray() { $expected = array ( 0 => 'vendor/zetacomponents/unit-test/design/class_diagram.png', ); $stats = array(); self::assertEquals( $expected, ezcBaseFile::findRecursive( "vendor/zetacomponents/unit-test", array( '@/design/@' ), array( '@\.svn@' ), $stats ) ); self::assertEquals( array( 'size' => 166066, 'count' => 1 ), $stats ); } public static function suite() { return new PHPUnit_Framework_TestSuite( "ezcBaseFileFindRecursiveTest" ); } } ?> Base-1.9.1/tests/file_is_absolute_path.php000066400000000000000000000413201320724427000205740ustar00rootroot00000000000000 Base-1.9.1/tests/file_remove_recursive_test.php000066400000000000000000000156151320724427000217020ustar00rootroot00000000000000tempDir = $this->createTempDir( 'ezcBaseFileRemoveFileRecursiveTest' ); mkdir( $this->tempDir . '/dir1' ); mkdir( $this->tempDir . '/dir2' ); mkdir( $this->tempDir . '/dir2/dir1' ); mkdir( $this->tempDir . '/dir2/dir1/dir1' ); mkdir( $this->tempDir . '/dir2/dir2' ); mkdir( $this->tempDir . '/dir4' ); mkdir( $this->tempDir . '/dir5' ); mkdir( $this->tempDir . '/dir6' ); mkdir( $this->tempDir . '/dir7' ); mkdir( $this->tempDir . '/dir7/dir1' ); mkdir( $this->tempDir . '/dir8' ); mkdir( $this->tempDir . '/dir8/dir1' ); mkdir( $this->tempDir . '/dir8/dir1/dir1' ); file_put_contents( $this->tempDir . '/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir1/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir1/.file3.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir1/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir1/dir1/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir2/dir2/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir4/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir4/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir5/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir5/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir6/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir6/file2.txt', 'test' ); file_put_contents( $this->tempDir . '/dir7/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir8/dir1/file1.txt', 'test' ); file_put_contents( $this->tempDir . '/dir8/dir1/dir1/file1.txt', 'test' ); chmod( $this->tempDir . '/dir4/file1.txt', 0 ); chmod( $this->tempDir . '/dir5', 0 ); chmod( $this->tempDir . '/dir6', 0400 ); chmod( $this->tempDir . '/dir7', 0500 ); chmod( $this->tempDir . '/dir8/dir1', 0500 ); } protected function tearDown() { chmod( $this->tempDir . '/dir5', 0700 ); chmod( $this->tempDir . '/dir6', 0700 ); chmod( $this->tempDir . '/dir7', 0700 ); chmod( $this->tempDir . '/dir8/dir1', 0700 ); $this->removeTempDir(); } public function testRecursive1() { self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); ezcBaseFile::removeRecursive( $this->tempDir . '/dir1' ); self::assertEquals( 12, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); ezcBaseFile::removeRecursive( $this->tempDir . '/dir2' ); self::assertEquals( 7, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); } public function testRecursive2() { self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); try { ezcBaseFile::removeRecursive( $this->tempDir . '/dir3' ); } catch ( ezcBaseFileNotFoundException $e ) { self::assertEquals( "The directory file '{$this->tempDir}/dir3' could not be found.", $e->getMessage() ); } self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); } public function testRecursive3() { self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); try { ezcBaseFile::removeRecursive( $this->tempDir . '/dir4' ); } catch ( ezcBaseFilePermissionException $e ) { self::assertEquals( "The file '{$this->tempDir}/dir5' can not be opened for reading.", $e->getMessage() ); } self::assertEquals( 13, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); } public function testRecursive4() { self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); try { ezcBaseFile::removeRecursive( $this->tempDir . '/dir5' ); } catch ( ezcBaseFilePermissionException $e ) { self::assertEquals( "The file '{$this->tempDir}/dir5' can not be opened for reading.", $e->getMessage() ); } self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); } public function testRecursive5() { self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); try { ezcBaseFile::removeRecursive( $this->tempDir . '/dir6' ); } catch ( ezcBaseFilePermissionException $e ) { // Make no asumption on which file is tried to be removed first self::assertEquals( 1, preg_match( "(The file '{$this->tempDir}/dir6/file[12].txt' can not be removed.)", $e->getMessage() ) ); } self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); } public function testRecursiveNotWritableParent() { self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); try { ezcBaseFile::removeRecursive( $this->tempDir . '/dir7/dir1' ); } catch ( ezcBaseFilePermissionException $e ) { self::assertEquals( "The file '{$this->tempDir}/dir7' can not be opened for writing.", $e->getMessage() ); } self::assertEquals( 15, count( ezcBaseFile::findRecursive( $this->tempDir ) ) ); } public static function suite() { return new PHPUnit_Framework_TestSuite( "ezcBaseFileRemoveRecursiveTest" ); } } ?> Base-1.9.1/tests/init/000077500000000000000000000000001320724427000145025ustar00rootroot00000000000000Base-1.9.1/tests/init/base_init_callback.php000066400000000000000000000023511320724427000207650ustar00rootroot00000000000000configured = true; } } ?> Base-1.9.1/tests/init/base_init_class.php000066400000000000000000000026201320724427000203350ustar00rootroot00000000000000 Base-1.9.1/tests/issue15896/000077500000000000000000000000001320724427000153045ustar00rootroot00000000000000Base-1.9.1/tests/issue15896/ab.php000066400000000000000000000000301320724427000163700ustar00rootroot00000000000000 Base-1.9.1/tests/issue15896/autoload/000077500000000000000000000000001320724427000171145ustar00rootroot00000000000000Base-1.9.1/tests/issue15896/autoload/autoload.php000066400000000000000000000000651320724427000214360ustar00rootroot00000000000000 'ab.php' ); ?> Base-1.9.1/tests/metadata_pear_test.php000066400000000000000000000070421320724427000201010ustar00rootroot00000000000000markTestSkipped('Only work when Zeta Components is installed as pear package.'); } public static function testConstruct() { $r = new ezcBaseMetaData( 'pear' ); self::assertInstanceOf( 'ezcBaseMetaData', $r ); self::assertInstanceOf( 'ezcBaseMetaDataPearReader', self::readAttribute( $r, 'reader' ) ); } public static function testGetBundleVersion() { $r = new ezcBaseMetaData( 'pear' ); $release = $r->getBundleVersion(); self::assertInternalType( 'string', $release ); self::assertRegexp( '@[0-9]{4}\.[0-9](\.[0-9])?@', $release ); } public static function testIsComponentInstalled() { $r = new ezcBaseMetaData( 'pear' ); self::assertTrue( $r->isComponentInstalled( 'Base' ) ); self::assertFalse( $r->isComponentInstalled( 'DefinitelyNot' ) ); } public static function testGetComponentVersion() { $r = new ezcBaseMetaData( 'pear' ); $release = $r->getComponentVersion( 'Base' ); self::assertInternalType( 'string', $release ); self::assertRegexp( '@[0-9]\.[0-9](\.[0-9])?@', $release ); self::assertFalse( $r->getComponentVersion( 'DefinitelyNot' ) ); } public static function testGetComponentDependencies1() { $r = new ezcBaseMetaData( 'pear' ); $deps = array_keys( $r->getComponentDependencies() ); self::assertContains( 'Base', $deps ); self::assertContains( 'Cache', $deps ); self::assertContains( 'Webdav', $deps ); self::assertNotContains( 'Random', $deps ); } public static function testGetComponentDependencies2() { $r = new ezcBaseMetaData( 'pear' ); self::assertSame( array(), $r->getComponentDependencies( 'Base' ) ); self::assertSame( array( 'Base' ), array_keys( $r->getComponentDependencies( 'Template' ) ) ); } public static function testGetComponentDependencies3() { $r = new ezcBaseMetaData( 'pear' ); self::assertContains( 'Base', array_keys( $r->getComponentDependencies( 'TemplateTranslationTiein' ) ) ); self::assertContains( 'Template', array_keys( $r->getComponentDependencies( 'TemplateTranslationTiein' ) ) ); self::assertContains( 'Translation', array_keys( $r->getComponentDependencies( 'TemplateTranslationTiein' ) ) ); } public static function suite() { return new PHPUnit_Framework_TestSuite( 'ezcBaseMetaDataPearTest' ); } } ?> Base-1.9.1/tests/struct_test.php000066400000000000000000000045071320724427000166410ustar00rootroot00000000000000no_such_property = 'value'; $this->fail( 'Expected exception was not thrown.' ); } catch ( ezcBasePropertyNotFoundException $e ) { $this->assertEquals( "No such property name 'no_such_property'.", $e->getMessage() ); } try { $value = $struct->no_such_property; $this->fail( 'Expected exception was not thrown.' ); } catch ( ezcBasePropertyNotFoundException $e ) { $this->assertEquals( "No such property name 'no_such_property'.", $e->getMessage() ); } } public function testBaseRepositoryDirectorySetState() { $dir = ezcBaseRepositoryDirectory::__set_state( array( 'type' => ezcBaseRepositoryDirectory::TYPE_EXTERNAL, 'basePath' => '/tmp', 'autoloadPath' => '/tmp/autoload' ) ); $this->assertEquals( ezcBaseRepositoryDirectory::TYPE_EXTERNAL, $dir->type ); $this->assertEquals( '/tmp', $dir->basePath ); $this->assertEquals( '/tmp/autoload', $dir->autoloadPath ); } public static function suite() { return new PHPUnit_Framework_TestSuite( "ezcBaseStructTest" ); } } ?> Base-1.9.1/tests/test_options.php000066400000000000000000000006661320724427000170120ustar00rootroot00000000000000 "bar", "baz" => "blah" ); public function __set( $propertyName, $propertyValue ) { if ( $this->__isset( $propertyName ) ) { $this->properties[$propertyName] = $propertyValue; } else { throw new ezcBasePropertyNotFoundException( $propertyName ); } } } ?>Base-1.9.1/tests/test_repository/000077500000000000000000000000001320724427000170155ustar00rootroot00000000000000Base-1.9.1/tests/test_repository/TestClasses/000077500000000000000000000000001320724427000212525ustar00rootroot00000000000000Base-1.9.1/tests/test_repository/TestClasses/base_test_class.php000066400000000000000000000000431320724427000251160ustar00rootroot00000000000000 Base-1.9.1/tests/test_repository/TestClasses/base_test_class_number_two.php000066400000000000000000000000441320724427000273600ustar00rootroot00000000000000 Base-1.9.1/tests/test_repository/TestClasses/base_test_long_class.php000066400000000000000000000000471320724427000261410ustar00rootroot00000000000000 Base-1.9.1/tests/test_repository/autoload_files/000077500000000000000000000000001320724427000220075ustar00rootroot00000000000000Base-1.9.1/tests/test_repository/autoload_files/basetest_autoload.php000066400000000000000000000003361320724427000262240ustar00rootroot00000000000000 'TestClasses/base_test_class.php', 'trBasetestClass2' => 'TestClasses/base_test_class_number_two.php', 'trBasetestClass4' => 'TestClasses/base_test_class_number_four.php', ); ?> Base-1.9.1/tests/test_repository/autoload_files/basetest_long_autoload.php000066400000000000000000000001341320724427000272370ustar00rootroot00000000000000 'TestClasses/base_test_long_class.php', ); ?> Base-1.9.1/tests/test_repository/autoload_files/objet_autoload.php000066400000000000000000000000731320724427000255130ustar00rootroot00000000000000 'object/object.php', ); ?> Base-1.9.1/tests/test_repository/object/000077500000000000000000000000001320724427000202635ustar00rootroot00000000000000Base-1.9.1/tests/test_repository/object/object.php000066400000000000000000000001251320724427000222400ustar00rootroot00000000000000