diff --git a/.gitignore b/.gitignore index 440b0331b..d7a87ccdd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,8 @@ !.git* !.vagrant-puppet/* -# Exclude enabled modules -config/enabledModules/ - # Exclude application log files var/log/* + +# Exclude symlink you need for packaging +/debian diff --git a/application/clicommands/WebCommand.php b/application/clicommands/WebCommand.php index 5d9b20c64..12ed9e1a4 100644 --- a/application/clicommands/WebCommand.php +++ b/application/clicommands/WebCommand.php @@ -47,7 +47,7 @@ class WebCommand extends Command readlink('/proc/self/exe'), $socket, $basedir, - ICINGA_LIBDIR . '/Icinga/Application/webrouter.php' + Icinga::app()->getLibraryDir('/Icinga/Application/webrouter.php') ); // TODO: Store webserver log, switch uid, log index.php includes, pid file diff --git a/application/controllers/AuthenticationController.php b/application/controllers/AuthenticationController.php index 27a9ae93b..b0d93ddf0 100644 --- a/application/controllers/AuthenticationController.php +++ b/application/controllers/AuthenticationController.php @@ -6,7 +6,7 @@ use Icinga\Authentication\Backend\AutoLoginBackend; use Icinga\Web\Controller\ActionController; -use Icinga\Form\Authentication\LoginForm; +use Icinga\Forms\Authentication\LoginForm; use Icinga\Authentication\AuthChain; use Icinga\Application\Config; use Icinga\Application\Logger; diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index a681c4255..11d011bc0 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -8,11 +8,11 @@ use Icinga\Application\Modules\Module; use Icinga\Web\Widget; use Icinga\Application\Icinga; use Icinga\Application\Config; -use Icinga\Form\Config\GeneralConfigForm; -use Icinga\Form\Config\AuthenticationBackendReorderForm; -use Icinga\Form\Config\AuthenticationBackendConfigForm; -use Icinga\Form\Config\ResourceConfigForm; -use Icinga\Form\ConfirmRemovalForm; +use Icinga\Forms\Config\GeneralConfigForm; +use Icinga\Forms\Config\AuthenticationBackendReorderForm; +use Icinga\Forms\Config\AuthenticationBackendConfigForm; +use Icinga\Forms\Config\ResourceConfigForm; +use Icinga\Forms\ConfirmRemovalForm; use Icinga\Data\ResourceFactory; diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 51435d727..d357231ca 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -8,7 +8,7 @@ use Icinga\Exception\ConfigurationError; use Icinga\Exception\IcingaException; use Icinga\Exception\NotReadableError; use Icinga\File\Ini\IniWriter; -use Icinga\Form\Dashboard\AddUrlForm; +use Icinga\Forms\Dashboard\AddUrlForm; use Icinga\Web\Controller\ActionController; use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; diff --git a/application/controllers/PreferenceController.php b/application/controllers/PreferenceController.php index 442c27ba8..378a5aa34 100644 --- a/application/controllers/PreferenceController.php +++ b/application/controllers/PreferenceController.php @@ -6,7 +6,7 @@ use Icinga\Web\Controller\BasePreferenceController; use Icinga\Web\Url; use Icinga\Web\Widget\Tab; use Icinga\Application\Config; -use Icinga\Form\PreferenceForm; +use Icinga\Forms\PreferenceForm; use Icinga\Exception\ConfigurationError; use Icinga\User\Preferences\PreferencesStore; diff --git a/application/forms/Authentication/LoginForm.php b/application/forms/Authentication/LoginForm.php index a48fc5afe..41107be18 100644 --- a/application/forms/Authentication/LoginForm.php +++ b/application/forms/Authentication/LoginForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Authentication; +namespace Icinga\Forms\Authentication; use Icinga\Web\Form; use Icinga\Web\Url; diff --git a/application/forms/Config/Authentication/AutologinBackendForm.php b/application/forms/Config/Authentication/AutologinBackendForm.php index 0a53de6bd..1725ea3c9 100644 --- a/application/forms/Config/Authentication/AutologinBackendForm.php +++ b/application/forms/Config/Authentication/AutologinBackendForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Zend_Validate_Callback; use Icinga\Web\Form; diff --git a/application/forms/Config/Authentication/DbBackendForm.php b/application/forms/Config/Authentication/DbBackendForm.php index 0ffaa2a1e..4cf015db8 100644 --- a/application/forms/Config/Authentication/DbBackendForm.php +++ b/application/forms/Config/Authentication/DbBackendForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Exception; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Request; use Icinga\Data\ResourceFactory; use Icinga\Authentication\Backend\DbUserBackend; @@ -89,7 +88,7 @@ class DbBackendForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (false === static::isValidAuthenticationBackend($this)) { return false; diff --git a/application/forms/Config/Authentication/LdapBackendForm.php b/application/forms/Config/Authentication/LdapBackendForm.php index 84298e3c6..3e5c2b305 100644 --- a/application/forms/Config/Authentication/LdapBackendForm.php +++ b/application/forms/Config/Authentication/LdapBackendForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Authentication; +namespace Icinga\Forms\Config\Authentication; use Exception; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Request; use Icinga\Data\ResourceFactory; use Icinga\Exception\AuthenticationException; use Icinga\Authentication\Backend\LdapUserBackend; @@ -119,7 +118,7 @@ class LdapBackendForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (false === static::isValidAuthenticationBackend($this)) { return false; diff --git a/application/forms/Config/AuthenticationBackendConfigForm.php b/application/forms/Config/AuthenticationBackendConfigForm.php index 33e0b1a3a..c21ccf8f2 100644 --- a/application/forms/Config/AuthenticationBackendConfigForm.php +++ b/application/forms/Config/AuthenticationBackendConfigForm.php @@ -2,19 +2,18 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; use Icinga\Web\Notification; use Icinga\Application\Config; use Icinga\Application\Platform; use Icinga\Data\ResourceFactory; use Icinga\Exception\ConfigurationError; -use Icinga\Form\Config\Authentication\DbBackendForm; -use Icinga\Form\Config\Authentication\LdapBackendForm; -use Icinga\Form\Config\Authentication\AutologinBackendForm; +use Icinga\Forms\Config\Authentication\DbBackendForm; +use Icinga\Forms\Config\Authentication\LdapBackendForm; +use Icinga\Forms\Config\Authentication\AutologinBackendForm; class AuthenticationBackendConfigForm extends ConfigForm { @@ -192,7 +191,7 @@ class AuthenticationBackendConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { $backendForm = $this->getBackendForm($this->getElement('type')->getValue()); @@ -202,7 +201,7 @@ class AuthenticationBackendConfigForm extends ConfigForm } } - $authBackend = $request->getQuery('auth_backend'); + $authBackend = $this->request->getQuery('auth_backend'); try { if ($authBackend === null) { // create new backend $this->add($this->getValues()); @@ -230,9 +229,9 @@ class AuthenticationBackendConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $authBackend = $request->getQuery('auth_backend'); + $authBackend = $this->request->getQuery('auth_backend'); if ($authBackend !== null) { if ($authBackend === '') { throw new ConfigurationError(t('Authentication backend name missing')); diff --git a/application/forms/Config/AuthenticationBackendReorderForm.php b/application/forms/Config/AuthenticationBackendReorderForm.php index 3b5e70866..07200827a 100644 --- a/application/forms/Config/AuthenticationBackendReorderForm.php +++ b/application/forms/Config/AuthenticationBackendReorderForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; class AuthenticationBackendReorderForm extends ConfigForm { @@ -30,17 +29,26 @@ class AuthenticationBackendReorderForm extends ConfigForm return $this->config->keys(); } + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + // This adds just a dummy element to be able to utilize Form::getValue as part of onSuccess() + $this->addElement('hidden', 'backend_newpos'); + } + /** * Update the authentication backend order and save the configuration * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - $formData = $this->getRequestData($request); - if (isset($formData['backend_newpos'])) { + $newPosData = $this->getValue('backend_newpos'); + if ($newPosData) { $configForm = $this->getConfigForm(); - list($backendName, $position) = explode('|', $formData['backend_newpos'], 2); + list($backendName, $position) = explode('|', $newPosData, 2); try { if ($configForm->move($backendName, $position)->save()) { diff --git a/application/forms/Config/General/ApplicationConfigForm.php b/application/forms/Config/General/ApplicationConfigForm.php index bc236ae81..df8531250 100644 --- a/application/forms/Config/General/ApplicationConfigForm.php +++ b/application/forms/Config/General/ApplicationConfigForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\General; +namespace Icinga\Forms\Config\General; use DateTimeZone; use Icinga\Application\Icinga; diff --git a/application/forms/Config/General/LoggingConfigForm.php b/application/forms/Config/General/LoggingConfigForm.php index bddb648cd..deed06011 100644 --- a/application/forms/Config/General/LoggingConfigForm.php +++ b/application/forms/Config/General/LoggingConfigForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\General; +namespace Icinga\Forms\Config\General; use Icinga\Application\Icinga; use Icinga\Application\Logger; diff --git a/application/forms/Config/GeneralConfigForm.php b/application/forms/Config/GeneralConfigForm.php index 0b55704c2..2cb72e3a1 100644 --- a/application/forms/Config/GeneralConfigForm.php +++ b/application/forms/Config/GeneralConfigForm.php @@ -2,13 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; -use Icinga\Form\Config\General\LoggingConfigForm; -use Icinga\Form\Config\General\ApplicationConfigForm; +use Icinga\Forms\ConfigForm; +use Icinga\Forms\Config\General\LoggingConfigForm; +use Icinga\Forms\Config\General\ApplicationConfigForm; /** * Form class for application-wide and logging specific settings @@ -38,7 +37,7 @@ class GeneralConfigForm extends ConfigForm /** * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { $sections = array(); foreach ($this->getValues() as $sectionAndPropertyName => $value) { @@ -62,7 +61,7 @@ class GeneralConfigForm extends ConfigForm /** * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { $values = array(); foreach ($this->config as $section => $properties) { diff --git a/application/forms/Config/Resource/DbResourceForm.php b/application/forms/Config/Resource/DbResourceForm.php index 4c0ce7740..b1d54c704 100644 --- a/application/forms/Config/Resource/DbResourceForm.php +++ b/application/forms/Config/Resource/DbResourceForm.php @@ -2,13 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Form\Element\Number; use Icinga\Data\ResourceFactory; use Icinga\Application\Platform; @@ -68,14 +66,13 @@ class DbResourceForm extends Form ) ); $this->addElement( - new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Port'), - 'description' => t('The port to use'), - 'value' => 3306 - ) + 'number', + 'port', + array( + 'required' => true, + 'label' => t('Port'), + 'description' => t('The port to use'), + 'value' => 3306 ) ); $this->addElement( @@ -115,7 +112,7 @@ class DbResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (false === static::isValidResource($this)) { return false; diff --git a/application/forms/Config/Resource/FileResourceForm.php b/application/forms/Config/Resource/FileResourceForm.php index 2814e9a72..8e2920313 100644 --- a/application/forms/Config/Resource/FileResourceForm.php +++ b/application/forms/Config/Resource/FileResourceForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Icinga\Web\Form; use Icinga\Web\Form\Validator\ReadablePathValidator; diff --git a/application/forms/Config/Resource/LdapResourceForm.php b/application/forms/Config/Resource/LdapResourceForm.php index cd482a7fb..6c29a09d6 100644 --- a/application/forms/Config/Resource/LdapResourceForm.php +++ b/application/forms/Config/Resource/LdapResourceForm.php @@ -2,13 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Request; -use Icinga\Web\Form\Element\Number; use Icinga\Data\ResourceFactory; /** @@ -49,14 +47,13 @@ class LdapResourceForm extends Form ) ); $this->addElement( - new Number( - array( - 'required' => true, - 'name' => 'port', - 'label' => t('Port'), - 'description' => t('The port of the LDAP server to use for authentication'), - 'value' => 389 - ) + 'number', + 'port', + array( + 'required' => true, + 'label' => t('Port'), + 'description' => t('The port of the LDAP server to use for authentication'), + 'value' => 389 ) ); $this->addElement( @@ -96,7 +93,7 @@ class LdapResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (false === static::isValidResource($this)) { return false; diff --git a/application/forms/Config/Resource/LivestatusResourceForm.php b/application/forms/Config/Resource/LivestatusResourceForm.php index 27925e370..e4dae844b 100644 --- a/application/forms/Config/Resource/LivestatusResourceForm.php +++ b/application/forms/Config/Resource/LivestatusResourceForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config\Resource; +namespace Icinga\Forms\Config\Resource; use Exception; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Request; use Icinga\Application\Icinga; use Icinga\Data\ResourceFactory; @@ -57,7 +56,7 @@ class LivestatusResourceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (false === static::isValidResource($this)) { return false; diff --git a/application/forms/Config/ResourceConfigForm.php b/application/forms/Config/ResourceConfigForm.php index a269885cf..d5faca1cd 100644 --- a/application/forms/Config/ResourceConfigForm.php +++ b/application/forms/Config/ResourceConfigForm.php @@ -2,16 +2,15 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Config; +namespace Icinga\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; -use Icinga\Form\Config\Resource\DbResourceForm; -use Icinga\Form\Config\Resource\FileResourceForm; -use Icinga\Form\Config\Resource\LdapResourceForm; -use Icinga\Form\Config\Resource\LivestatusResourceForm; +use Icinga\Forms\ConfigForm; +use Icinga\Forms\Config\Resource\DbResourceForm; +use Icinga\Forms\Config\Resource\FileResourceForm; +use Icinga\Forms\Config\Resource\LdapResourceForm; +use Icinga\Forms\Config\Resource\LivestatusResourceForm; use Icinga\Application\Platform; use Icinga\Exception\ConfigurationError; @@ -128,7 +127,7 @@ class ResourceConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) { $resourceForm = $this->getResourceForm($this->getElement('type')->getValue()); @@ -138,7 +137,7 @@ class ResourceConfigForm extends ConfigForm } } - $resource = $request->getQuery('resource'); + $resource = $this->request->getQuery('resource'); try { if ($resource === null) { // create new resource $this->add($this->getValues()); @@ -166,9 +165,9 @@ class ResourceConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $resource = $request->getQuery('resource'); + $resource = $this->request->getQuery('resource'); if ($resource !== null) { if ($resource === '') { throw new ConfigurationError(t('Resource name missing')); diff --git a/application/forms/ConfigForm.php b/application/forms/ConfigForm.php index d1f2ed1dd..fcf674cad 100644 --- a/application/forms/ConfigForm.php +++ b/application/forms/ConfigForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Exception; use Icinga\Web\Form; diff --git a/application/forms/ConfirmRemovalForm.php b/application/forms/ConfirmRemovalForm.php index 86a2eb02a..02d7263df 100644 --- a/application/forms/ConfirmRemovalForm.php +++ b/application/forms/ConfirmRemovalForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Icinga\Web\Form; diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php index 564ff3d7a..7f5a217d1 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/AddUrlForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form\Dashboard; +namespace Icinga\Forms\Dashboard; use Icinga\Application\Config; use Icinga\Web\Widget\Dashboard; diff --git a/application/forms/LdapDiscoveryForm.php b/application/forms/LdapDiscoveryForm.php index 88f30f2c1..9e5af79ac 100644 --- a/application/forms/LdapDiscoveryForm.php +++ b/application/forms/LdapDiscoveryForm.php @@ -1,13 +1,12 @@ addElement( - new Note( - 'additional_description', - array( - 'value' => t('No Ldap servers found on this domain.' - . ' You can try to specify host and port and try again, or just skip this step and ' - . 'configure the server manually.' - ) + 'note', + 'additional_description', + array( + 'value' => t('No Ldap servers found on this domain.' + . ' You can try to specify host and port and try again, or just skip this step and ' + . 'configure the server manually.' ) ) ); diff --git a/application/forms/PreferenceForm.php b/application/forms/PreferenceForm.php index 926d7a529..e3cfdf319 100644 --- a/application/forms/PreferenceForm.php +++ b/application/forms/PreferenceForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Form; +namespace Icinga\Forms; use Exception; use DateTimeZone; @@ -12,10 +12,8 @@ use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; use Icinga\Util\TimezoneDetect; use Icinga\Util\Translator; -use Icinga\Web\Controller\ControllerTabCollector; use Icinga\Web\Form; use Icinga\Web\Notification; -use Icinga\Web\Request; use Icinga\Web\Session; /** @@ -86,7 +84,7 @@ class PreferenceForm extends Form * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { $this->preferences = new Preferences($this->store->load()); @@ -122,7 +120,7 @@ class PreferenceForm extends Form * * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { $auth = Manager::getInstance(); $values = $auth->getUser()->getPreferences()->get('icingaweb'); @@ -237,7 +235,7 @@ class PreferenceForm extends Form if ($detect->success()) { return $detect->getTimezoneName(); } else { - return date_default_timezone_get(); + return @date_default_timezone_get(); } } diff --git a/doc/container_component.md b/doc/container_component.md deleted file mode 100644 index ed505f81b..000000000 --- a/doc/container_component.md +++ /dev/null @@ -1,198 +0,0 @@ -# The Container Component (app/container) - -The container component is the most basic building block for icingaweb. Even when displaying an empty controller, -you always have at least two containers in your viewport which are implicitly created: The main and the detail container. - -Container handle the following tasks: - -* Updating the url part responsible for the container -* Handling Url changes like they occur when the browser history is used by synchronizing their content with the - associated Url part -* Informing subcomponents about changes in the container - - -## The Container Api - -You can find the sourcecode for containers along with jsdoc comments at *./public/js/icinga/components/container.js*. -Here we will discuss the most important calls and their synopsis: - -### Accessing Containers: - -The container component returns a 'Container' object which allows you to access responsible containers for dom nodes via -the following methods: - -* using `new Container($myDomNodes)` which returns a stateless container object wrapping the container responsible for - the first node in $myDomNodes -* using `Container.getMainContainer()` or `Container.getDetailContainer()` which remove the main or detail container - (this one is stateful with a few notes, read on) - -**Note:** `new Container($('#icingamain')) != Container.getMainContainer()`, but -`(new Container($('#icingamain'))).containerDom == Container.getMainContainer().containerDom` - -** Example #1 getting the container responsible for a dom node ** - -**HTML** - -
-
- Some kind of node -
-
-
- Some other kind of node -

- Insert your lorem ipsum here -

-
-
-
- -**JS**: - - require(['jquery', 'app/container'], function($, Container) { - var firstContainer = new Container($('.myNode')); // firstContainer wraps '#icingamain' - var mainContainer = Container.getMainContainer(); // also wraps '#icingamain' - var secondContainer = new Container($('.myNode p')); // #somecontainer is wrapped by secondContainer - - firstContainer.someProperty = 'What a nice property!'; - mainContainer.someState = 'I have some state'; - console.log(firstContainer.someProperty); // return 'What a nice property' - console.log(main.someProperty); // return 'undefined' - console.log(Container.getMainContainer().someState) // return 'I have some state' when page hasn't been refreshed - }); - -## Containers And The Browser Url - -As noted before (and indicated by the `getMainContainer()` and `getDetailContainer()` function), the main and detail -container have a special role. Considering the following Url: - - http://my.monitoringhost.org/icingaweb/monitoring/list/host?page=4&detail=%2Fmonitoring%2Fshow%2Fhost%3Fhost%3Dlocalhost - -This URL displays the 4th page of your host list in the main container (monitoring/list/host?page=4) and the host information -for localhost in the detail container (monitoring/show/host?host=localhost). When you split this Url up in logical pieces -it looks like this: - - http://my.monitoringhost.org/icingaweb/monitoring/list/host?page=4&detail=%2Fmonitoring%2Fshow%2Fhost%3Fhost%3Dlocalhost - \___________ _______________________/\_________ ______________/ \_ ____/\________________ _______________________/ - \/ \/ \/ \/ - 1. Base URL 2.Main container URL and Query 3.Detail param 4. Encoded detail URL and params - -1. **Base URL** : I don't think this needs much explanation. -2. **Main container URL and query** : This is the *normal* part of your Url and denotes the controller route that is - being displayed in your main container -3. **Detail parameter**: This parameter will be ignored by the main container and used for rendering the detail container, - if omitted there's simple no detail view to be displayed -4 **Encoded detail URL**: The value of the "detail" parameter is the Url (without the base Url) that returns the content - of the detail area - - -### Updating A Container's Url - -If you want your container to display content from a different Url, you can use the *replaceDomFromUrl()* on your -Container object: - -**Example #2 Updating A Containers URL** - -**HTML:** - -
-
-
-
-
-
- -**JS:** - - // this loads the page with the new main container - require(['jquery', 'app/container'], function($, Container) { - new Container('#mainSub').replaceDomFormUrl('/another/url'); - } - - // this loads the page with the new detail container - require(['jquery', 'app/container'], function($, Container) { - new Container('#detailSub').replaceDomFormUrl('/another/url'); - } - - // this does NOT work: - require(['jquery', 'app/container'], function($, Container) { - Container.getMainContainer().replaceDomFormUrl('/another/url'); - // will never be reached due to a reload - Container.getMainContainer().replaceDomFormUrl('/another/url2'); - } - - // this loads the page with both main and detail changed (this is rarely needed and should be avoided) - require(['icinga', 'jquery', 'app/container'], function('Icinga', $, Container) { - // it's better to use this: - var mainContainer = Container.getMainContainer(); - var detailContainer = Container.getDetailContainer(); - - mainContainer.updateContainerHref('/another/url'); // first update the main container href - detailContainer.updateContainerHref('/another/url2'); // update the detail href - - var url = mainContainer.getContainerHref(detailContainer.getContainerHref()); // fetch the new url - Icinga.replaceBodyFromUrl(url); // and update manual - } - -This results in the URL changing to './another/url?detail=%2Fanother%2Fdetail%2Furl. -The advantage of using a Container instance with the subelements (i.e. '\#mainSub') over calling getMain/DetailContainer -directly is that you don't need to know in what container your view is displayed - when you move 'mainSub' into the -detail container, the detail container would be updated afterwards. - -**NOTE**: You should read the '...' section in order to understand why you shouldn't do it like in this example - -### How container refresh states are handled - -If you refresh containers content (load url or replace dom), the container displaya a loading -mask as default behaviour. To disable this mask and handle it yourself, you can register own events: - -**Example #3 Load indicator events** - - require(['icinga', 'jquery', 'app/container'], function('Icinga', $, Container) { - var mainContainer = Container.getMainContainer(); - - // Detach the default behaviour from container - mainContainer.removeDefaultLoadIndicator(); - - var showFunction = function() { - console.log('container is loading'); - }; - - var hideFunction = function() { - console.log('container content refreshed'); - }; - - // Install new handlers - mainContainer.registerOnShowLoadIndicator(showFunction); - mainContainer.registerOnHideLoadIndicator(hideFunction); - }; - -**Example #4 Use this for your components** - -Please have a look into [components documentation](components.md) for detailed information about components. - - define(['components/app/container', 'jquery', 'logging', 'URIjs/URI', 'URIjs/URITemplate'], - function(Container, $, logger, URI) { - "use strict"; - - /** - * Master/Detail grid component handling history, link behaviour, selection (@TODO 3788) and updates of - * grids - * - * @param {HTMLElement} The outer element to apply the behaviour on - */ - return function(gridDomNode) { - /** - * Constructor method for this component - */ - this.construct = function(target) { - // Container object for the component - this.container = new Container(target); - - // Detach default handlers - this.container.removeDefaultLoadIndicator(); - }; - - this.construct(gridDomNode); - }; - }; \ No newline at end of file diff --git a/icingaweb2.spec b/icingaweb2.spec index db0929f7b..9d9e11345 100644 --- a/icingaweb2.spec +++ b/icingaweb2.spec @@ -31,7 +31,7 @@ %define prefixdir %{_datadir}/%{name} %define usermodparam -a -G %define logdir %{_localstatedir}/log/%{name} -%define docdir %{sharedir}/log +%define docdir %{sharedir}/doc %if "%{_vendor}" == "suse" %define phpname php5 @@ -179,7 +179,8 @@ install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{ap %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/enabledModules -%{__cp} -r application doc library modules public %{buildroot}/%{sharedir}/ +# make sure to install local icingacli for setup wizard token generation & webserver config +%{__cp} -r application doc library modules public bin %{buildroot}/%{sharedir}/ ## config # authentication is db only @@ -194,8 +195,8 @@ install -D -m0644 packages/rpm/etc/%{name}/modules/monitoring/instances.ini %{bu ln -s %{sharedir}/modules/monitoring %{buildroot}/%{_sysconfdir}/%{name}/enabledModules/monitoring ## config -# install icingacli -install -D -m0755 packages/rpm/usr/bin/icingacli %{buildroot}/usr/bin/icingacli +# symlink icingacli +ln -sf %{buildroot}/%{sharedir}/bin/icingacli %{buildroot}/usr/bin/icingacli %pre # Add apacheuser in the icingacmd group diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index b61a3e3e8..1844486cb 100644 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -13,7 +13,6 @@ use Icinga\Exception\NotReadableError; use Icinga\Application\Logger; use Icinga\Util\DateTimeFactory; use Icinga\Util\Translator; -use Icinga\Util\TimezoneDetect; use Icinga\Exception\IcingaException; /** @@ -139,7 +138,6 @@ abstract class ApplicationBootstrap $this->configDir = $canonical ? $canonical : $configDir; $this->setupAutoloader(); - $this->setupZendAutoloader(); set_include_path( implode( @@ -277,6 +275,18 @@ abstract class ApplicationBootstrap return $this->getDirWithSubDir($this->configDir, $subDir); } + /** + * Get the Icinga library directory + * + * @param string $subDir Optional sub directory to get + * + * @return string + */ + public function getLibraryDir($subDir = null) + { + return $this->getDirWithSubDir($this->libDir, $subDir); + } + /** * Get the path to the bootstrapping directory * @@ -323,7 +333,7 @@ abstract class ApplicationBootstrap /** * Register the Zend Autoloader * - * @return self + * @return $this */ protected function setupZendAutoloader() { @@ -331,17 +341,12 @@ abstract class ApplicationBootstrap \Zend_Loader_Autoloader::getInstance(); - // Unfortunately this is needed to get the Zend Plugin loader working: - set_include_path( - implode( - PATH_SEPARATOR, - array($this->libDir, get_include_path()) - ) + \Zend_Paginator::addScrollingStylePrefixPath( + 'Icinga_Web_Paginator_ScrollingStyle_', $this->libDir . '/Icinga/Web/Paginator/ScrollingStyle' ); return $this; } - /** * Setup module manager * diff --git a/library/Icinga/Application/EmbeddedWeb.php b/library/Icinga/Application/EmbeddedWeb.php index 0dd8b5d5c..7ba2ba73e 100644 --- a/library/Icinga/Application/EmbeddedWeb.php +++ b/library/Icinga/Application/EmbeddedWeb.php @@ -27,7 +27,9 @@ class EmbeddedWeb extends ApplicationBootstrap */ protected function bootstrap() { - return $this->loadConfig() + return $this + ->setupZendAutoloader() + ->loadConfig() ->setupErrorHandling() ->setupTimezone() ->setupModuleManager() diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 461cec59a..443a39e32 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -763,7 +763,7 @@ class Module $this->app->getLoader()->registerNamespace('Icinga\\Module\\' . $moduleName, $moduleLibraryDir); if (is_dir($this->getFormDir())) { $this->app->getLoader()->registerNamespace( - 'Icinga\\Module\\' . $moduleName. '\\Form', + 'Icinga\\Module\\' . $moduleName. '\\Forms', $this->getFormDir() ); } diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php index 06a37267d..f227df247 100644 --- a/library/Icinga/Application/Web.php +++ b/library/Icinga/Application/Web.php @@ -90,6 +90,7 @@ class Web extends ApplicationBootstrap protected function bootstrap() { return $this + ->setupZendAutoloader() ->setupLogging() ->setupErrorHandling() ->loadConfig() @@ -326,14 +327,14 @@ class Web extends ApplicationBootstrap } /** - * Setup an autoloader namespace for Icinga\Form + * Setup an autoloader namespace for Icinga\Forms * * @return self */ private function setupFormNamespace() { $this->getLoader()->registerNamespace( - 'Icinga\\Form', + 'Icinga\\Forms', $this->getApplicationDir('forms') ); return $this; diff --git a/library/Icinga/Cli/Loader.php b/library/Icinga/Cli/Loader.php index f0aa95499..655ef7c18 100644 --- a/library/Icinga/Cli/Loader.php +++ b/library/Icinga/Cli/Loader.php @@ -66,7 +66,7 @@ class Loader public function __construct(App $app) { $this->app = $app; - $this->coreAppDir = $app->getBaseDir('clicommands'); + $this->coreAppDir = $app->getApplicationDir('clicommands'); } /** diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index f315c264e..20484c33e 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -11,6 +11,7 @@ use Zend_View_Interface; use Icinga\Application\Icinga; use Icinga\Web\Form\Decorator\NoScriptApply; use Icinga\Web\Form\Element\CsrfCounterMeasure; +use Icinga\Web\Form\FormElement; /** * Base class for forms providing CSRF protection, confirmation logic and auto submission @@ -36,6 +37,13 @@ class Form extends Zend_Form */ protected $created = false; + /** + * The request associated with this form + * + * @var Request + */ + protected $request; + /** * The callback to call instead of Form::onSuccess() * @@ -111,7 +119,7 @@ class Form extends Zend_Form * Create a new form * * Accepts an additional option `onSuccess' which is a callback that is called instead of this - * form's method. It is called using the following signature: (Request $request, Form $form). + * form's method. It is called using the following signature: (Form $form). * * @see Zend_Form::__construct() * @@ -355,11 +363,9 @@ class Form extends Zend_Form * * Intended to be implemented by concrete form classes. The base implementation returns always FALSE. * - * @param Request $request The valid request used to process this form - * * @return null|bool Return FALSE in case no redirect should take place */ - public function onSuccess(Request $request) + public function onSuccess() { return false; } @@ -368,10 +374,8 @@ class Form extends Zend_Form * Perform actions when no form dependent data was sent * * Intended to be implemented by concrete form classes. - * - * @param Request $request The current request */ - public function onRequest(Request $request) + public function onRequest() { } @@ -437,8 +441,8 @@ class Form extends Zend_Form * `disableLoadDefaultDecorators' option to any other value than `true'. For loading custom element decorators use * the 'decorators' option. * - * @param string $type String element type - * @param string $name The name of the element to add + * @param string $type The type of the element + * @param string $name The name of the element * @param mixed $options The options for the element * * @return Zend_Form_Element @@ -460,7 +464,9 @@ class Form extends Zend_Form $options = array('decorators' => static::$defaultElementDecorators); } - $el = parent::createElement($type, $name, $options); + if (($el = $this->createIcingaFormElement($type, $name, $options)) === null) { + $el = parent::createElement($type, $name, $options); + } if ($el && $el->getAttrib('autosubmit')) { $noScript = new NoScriptApply(); // Non-JS environments @@ -549,15 +555,17 @@ class Form extends Zend_Form { if ($request === null) { $request = $this->getRequest(); + } else { + $this->request = $request; } - $formData = $this->getRequestData($request); + $formData = $this->getRequestData(); if ($this->getUidDisabled() || $this->wasSent($formData)) { $this->populate($formData); // Necessary to get isSubmitted() to work if (! $this->getSubmitLabel() || $this->isSubmitted()) { if ($this->isValid($formData) - && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $request, $this)) - || ($this->onSuccess === null && false !== $this->onSuccess($request)))) { + && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this)) + || ($this->onSuccess === null && false !== $this->onSuccess()))) { $this->getResponse()->redirectAndExit($this->getRedirectUrl()); } } else { @@ -565,7 +573,7 @@ class Form extends Zend_Form $this->isValidPartial($formData); } } else { - $this->onRequest($request); + $this->onRequest(); } return $request; @@ -691,29 +699,19 @@ class Form extends Zend_Form } /** - * Return the request data based on this form's request method + * Return the request associated with this form * - * @param Request $request The request to fetch the data from - * - * @return array - */ - public function getRequestData(Request $request) - { - if (strtolower($request->getMethod()) === $this->getMethod()) { - return $request->{'get' . ($request->isPost() ? 'Post' : 'Query')}(); - } - - return array(); - } - - /** - * Return the current request + * Returns the global request if none has been set for this form yet. * * @return Request */ public function getRequest() { - return Icinga::app()->getFrontController()->getRequest(); + if ($this->request === null) { + $this->request = Icinga::app()->getFrontController()->getRequest(); + } + + return $this->request; } /** @@ -726,6 +724,39 @@ class Form extends Zend_Form return Icinga::app()->getFrontController()->getResponse(); } + /** + * Return the request data based on this form's request method + * + * @return array + */ + protected function getRequestData() + { + if (strtolower($this->request->getMethod()) === $this->getMethod()) { + return $this->request->{'get' . ($this->request->isPost() ? 'Post' : 'Query')}(); + } + + return array(); + } + + /** + * Create a new element located in the Icinga Web 2 library + * + * @param string $type The type of the element + * @param string $name The name of the element + * @param mixed $options The options for the element + * + * @return NULL|FormElement NULL in case the element is not found in the Icinga Web 2 library + * + * @see Form::$defaultElementDecorators For Icinga Web 2's default element decorators. + */ + protected function createIcingaFormElement($type, $name, $options = null) + { + $className = 'Icinga\\Web\\Form\\Element\\' . ucfirst($type); + if (class_exists($className)) { + return new $className($name, $options); + } + } + /** * Render this form * diff --git a/library/Icinga/Web/Form/Element/Button.php b/library/Icinga/Web/Form/Element/Button.php index 00da28d10..1c5499373 100644 --- a/library/Icinga/Web/Form/Element/Button.php +++ b/library/Icinga/Web/Form/Element/Button.php @@ -4,14 +4,14 @@ namespace Icinga\Web\Form\Element; -use Zend_Form_Element; use Icinga\Web\Request; use Icinga\Application\Icinga; +use Icinga\Web\Form\FormElement; /** * A button */ -class Button extends Zend_Form_Element +class Button extends FormElement { /** * Use formButton view helper by default diff --git a/library/Icinga/Web/Form/Element/Note.php b/library/Icinga/Web/Form/Element/Note.php index fa003a2cf..37bc127e9 100644 --- a/library/Icinga/Web/Form/Element/Note.php +++ b/library/Icinga/Web/Form/Element/Note.php @@ -4,12 +4,12 @@ namespace Icinga\Web\Form\Element; -use Zend_Form_Element; +use Icinga\Web\Form\FormElement; /** * A note */ -class Note extends Zend_Form_Element +class Note extends FormElement { /** * Form view helper to use for rendering diff --git a/library/Icinga/Web/JavaScript.php b/library/Icinga/Web/JavaScript.php index 0b64a394b..9fa687042 100644 --- a/library/Icinga/Web/JavaScript.php +++ b/library/Icinga/Web/JavaScript.php @@ -118,7 +118,7 @@ class JavaScript } if ($minified) { - require_once 'IcingaVendor/JShrink/Minifier.php'; + require_once 'JShrink/Minifier.php'; $out .= Minifier::minify($js, array('flaggedComments' => false)); } else { $out .= $js; diff --git a/library/Icinga/Web/LessCompiler.php b/library/Icinga/Web/LessCompiler.php index 16514cf6d..791fdbab0 100644 --- a/library/Icinga/Web/LessCompiler.php +++ b/library/Icinga/Web/LessCompiler.php @@ -41,7 +41,7 @@ class LessCompiler */ public function __construct() { - require_once 'IcingaVendor/lessphp/lessc.inc.php'; + require_once 'lessphp/lessc.inc.php'; $this->lessc = new lessc(); $this->lessc->setVariables( diff --git a/library/Icinga/Web/Widget/Chart/InlinePie.php b/library/Icinga/Web/Widget/Chart/InlinePie.php index d22923131..3ff97b2df 100644 --- a/library/Icinga/Web/Widget/Chart/InlinePie.php +++ b/library/Icinga/Web/Widget/Chart/InlinePie.php @@ -73,28 +73,28 @@ EOD; * * @var int The value in px */ - private $width = 28; + private $width = 16; /** * The height of the rendered chart * * @var int The value in px */ - private $height = 28; + private $height = 16; /** * PieChart border width * * @var float */ - private $borderWidth = 0; + private $borderWidth = 1; /** * The color of the border * * @var string */ - private $borderColor = '#888'; + private $borderColor = '#fff'; /** * The title of the chart diff --git a/library/Icinga/Web/Wizard.php b/library/Icinga/Web/Wizard.php index 424b46b2c..2cc4abe5a 100644 --- a/library/Icinga/Web/Wizard.php +++ b/library/Icinga/Web/Wizard.php @@ -8,7 +8,6 @@ use LogicException; use InvalidArgumentException; use Icinga\Web\Session\SessionNamespace; use Icinga\Web\Form\Decorator\ElementDoubler; -use Icinga\Web\Form\Element\Button; /** * Container and controller for form based wizards @@ -208,7 +207,7 @@ class Wizard } $this->setupPage($page, $request); - $requestData = $page->getRequestData($request); + $requestData = $this->getRequestData($page, $request); if ($page->wasSent($requestData)) { if (($requestedPage = $this->getRequestedPage($requestData)) !== null) { $isValid = false; @@ -239,6 +238,23 @@ class Wizard return $request; } + /** + * Return the request data based on given form's request method + * + * @param Form $page The page to fetch the data for + * @param Request $request The request to fetch the data from + * + * @return array + */ + protected function getRequestData(Form $page, Request $request) + { + if (strtolower($request->getMethod()) === $page->getMethod()) { + return $request->{'get' . ($request->isPost() ? 'Post' : 'Query')}(); + } + + return array(); + } + /** * Return the name of the requested page * @@ -270,7 +286,7 @@ class Wizard $request = $currentPage->getRequest(); } - $requestData = $currentPage->getRequestData($request); + $requestData = $this->getRequestData($currentPage, $request); if (isset($requestData[static::BTN_NEXT])) { return static::FORWARD; } elseif (isset($requestData[static::BTN_PREV])) { @@ -427,60 +443,55 @@ class Wizard $index = array_search($page, $pages, true); if ($index === 0) { $page->addElement( - new Button( - static::BTN_NEXT, - array( - 'type' => 'submit', - 'value' => $pages[1]->getName(), - 'label' => t('Next'), - 'decorators' => array('ViewHelper') - ) + 'button', + static::BTN_NEXT, + array( + 'type' => 'submit', + 'value' => $pages[1]->getName(), + 'label' => t('Next'), + 'decorators' => array('ViewHelper') ) ); } elseif ($index < count($pages) - 1) { $page->addElement( - new Button( - static::BTN_PREV, - array( - 'type' => 'submit', - 'value' => $pages[$index - 1]->getName(), - 'label' => t('Back'), - 'decorators' => array('ViewHelper') - ) + 'button', + static::BTN_PREV, + array( + 'type' => 'submit', + 'value' => $pages[$index - 1]->getName(), + 'label' => t('Back'), + 'decorators' => array('ViewHelper') ) ); $page->addElement( - new Button( - static::BTN_NEXT, - array( - 'type' => 'submit', - 'value' => $pages[$index + 1]->getName(), - 'label' => t('Next'), - 'decorators' => array('ViewHelper') - ) + 'button', + static::BTN_NEXT, + array( + 'type' => 'submit', + 'value' => $pages[$index + 1]->getName(), + 'label' => t('Next'), + 'decorators' => array('ViewHelper') ) ); } else { $page->addElement( - new Button( - static::BTN_PREV, - array( - 'type' => 'submit', - 'value' => $pages[$index - 1]->getName(), - 'label' => t('Back'), - 'decorators' => array('ViewHelper') - ) + 'button', + static::BTN_PREV, + array( + 'type' => 'submit', + 'value' => $pages[$index - 1]->getName(), + 'label' => t('Back'), + 'decorators' => array('ViewHelper') ) ); $page->addElement( - new Button( - static::BTN_NEXT, - array( - 'type' => 'submit', - 'value' => $page->getName(), - 'label' => t('Finish'), - 'decorators' => array('ViewHelper') - ) + 'button', + static::BTN_NEXT, + array( + 'type' => 'submit', + 'value' => $page->getName(), + 'label' => t('Finish'), + 'decorators' => array('ViewHelper') ) ); } diff --git a/library/IcingaVendor/JShrink/SOURCE b/library/IcingaVendor/JShrink/SOURCE deleted file mode 100644 index 721d70182..000000000 --- a/library/IcingaVendor/JShrink/SOURCE +++ /dev/null @@ -1 +0,0 @@ -https://github.com/tedivm/JShrink/releases/tag/v1.0.0 diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/CREDITS b/library/IcingaVendor/htmlpurifier-4.6.0-lite/CREDITS deleted file mode 100644 index 7921b45af..000000000 --- a/library/IcingaVendor/htmlpurifier-4.6.0-lite/CREDITS +++ /dev/null @@ -1,9 +0,0 @@ - -CREDITS - -Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks -to the DevNetwork Community for their help (see docs/ref-devnetwork.html for -more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake -for letting me package his fantastic XSS cheatsheet for a smoketest. - - vim: et sw=4 sts=4 diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/INSTALL b/library/IcingaVendor/htmlpurifier-4.6.0-lite/INSTALL deleted file mode 100644 index 677c04aa0..000000000 --- a/library/IcingaVendor/htmlpurifier-4.6.0-lite/INSTALL +++ /dev/null @@ -1,374 +0,0 @@ - -Install - How to install HTML Purifier - -HTML Purifier is designed to run out of the box, so actually using the -library is extremely easy. (Although... if you were looking for a -step-by-step installation GUI, you've downloaded the wrong software!) - -While the impatient can get going immediately with some of the sample -code at the bottom of this library, it's well worth reading this entire -document--most of the other documentation assumes that you are familiar -with these contents. - - ---------------------------------------------------------------------------- -1. Compatibility - -HTML Purifier is PHP 5 only, and is actively tested from PHP 5.0.5 and -up. It has no core dependencies with other libraries. PHP -4 support was deprecated on December 31, 2007 with HTML Purifier 3.0.0. -HTML Purifier is not compatible with zend.ze1_compatibility_mode. - -These optional extensions can enhance the capabilities of HTML Purifier: - - * iconv : Converts text to and from non-UTF-8 encodings - * bcmath : Used for unit conversion and imagecrash protection - * tidy : Used for pretty-printing HTML - -These optional libraries can enhance the capabilities of HTML Purifier: - - * CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks - * Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA - ---------------------------------------------------------------------------- -2. Reconnaissance - -A big plus of HTML Purifier is its inerrant support of standards, so -your web-pages should be standards-compliant. (They should also use -semantic markup, but that's another issue altogether, one HTML Purifier -cannot fix without reading your mind.) - -HTML Purifier can process these doctypes: - -* XHTML 1.0 Transitional (default) -* XHTML 1.0 Strict -* HTML 4.01 Transitional -* HTML 4.01 Strict -* XHTML 1.1 - -...and these character encodings: - -* UTF-8 (default) -* Any encoding iconv supports (with crippled internationalization support) - -These defaults reflect what my choices would be if I were authoring an -HTML document, however, what you choose depends on the nature of your -codebase. If you don't know what doctype you are using, you can determine -the doctype from this identifier at the top of your source code: - - - -...and the character encoding from this code: - - - -If the character encoding declaration is missing, STOP NOW, and -read 'docs/enduser-utf8.html' (web accessible at -http://htmlpurifier.org/docs/enduser-utf8.html). In fact, even if it is -present, read this document anyway, as many websites specify their -document's character encoding incorrectly. - - ---------------------------------------------------------------------------- -3. Including the library - -The procedure is quite simple: - - require_once '/path/to/library/HTMLPurifier.auto.php'; - -This will setup an autoloader, so the library's files are only included -when you use them. - -Only the contents in the library/ folder are necessary, so you can remove -everything else when using HTML Purifier in a production environment. - -If you installed HTML Purifier via PEAR, all you need to do is: - - require_once 'HTMLPurifier.auto.php'; - -Please note that the usual PEAR practice of including just the classes you -want will not work with HTML Purifier's autoloading scheme. - -Advanced users, read on; other users can skip to section 4. - -Autoload compatibility ----------------------- - - HTML Purifier attempts to be as smart as possible when registering an - autoloader, but there are some cases where you will need to change - your own code to accomodate HTML Purifier. These are those cases: - - PHP VERSION IS LESS THAN 5.1.2, AND YOU'VE DEFINED __autoload - Because spl_autoload_register() doesn't exist in early versions - of PHP 5, HTML Purifier has no way of adding itself to the autoload - stack. Modify your __autoload function to test - HTMLPurifier_Bootstrap::autoload($class) - - For example, suppose your autoload function looks like this: - - function __autoload($class) { - require str_replace('_', '/', $class) . '.php'; - return true; - } - - A modified version with HTML Purifier would look like this: - - function __autoload($class) { - if (HTMLPurifier_Bootstrap::autoload($class)) return true; - require str_replace('_', '/', $class) . '.php'; - return true; - } - - Note that there *is* some custom behavior in our autoloader; the - original autoloader in our example would work for 99% of the time, - but would fail when including language files. - - AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED - spl_autoload_register() has the curious behavior of disabling - the existing __autoload() handler. Users need to explicitly - spl_autoload_register('__autoload'). Because we use SPL when it - is available, __autoload() will ALWAYS be disabled. If __autoload() - is declared before HTML Purifier is loaded, this is not a problem: - HTML Purifier will register the function for you. But if it is - declared afterwards, it will mysteriously not work. This - snippet of code (after your autoloader is defined) will fix it: - - spl_autoload_register('__autoload') - - Users should also be on guard if they use a version of PHP previous - to 5.1.2 without an autoloader--HTML Purifier will define __autoload() - for you, which can collide with an autoloader that was added by *you* - later. - - -For better performance ----------------------- - - Opcode caches, which greatly speed up PHP initialization for scripts - with large amounts of code (HTML Purifier included), don't like - autoloaders. We offer an include file that includes all of HTML Purifier's - files in one go in an opcode cache friendly manner: - - // If /path/to/library isn't already in your include path, uncomment - // the below line: - // require '/path/to/library/HTMLPurifier.path.php'; - - require 'HTMLPurifier.includes.php'; - - Optional components still need to be included--you'll know if you try to - use a feature and you get a class doesn't exists error! The autoloader - can be used in conjunction with this approach to catch classes that are - missing. Simply add this afterwards: - - require 'HTMLPurifier.autoload.php'; - -Standalone version ------------------- - - HTML Purifier has a standalone distribution; you can also generate - a standalone file from the full version by running the script - maintenance/generate-standalone.php . The standalone version has the - benefit of having most of its code in one file, so parsing is much - faster and the library is easier to manage. - - If HTMLPurifier.standalone.php exists in the library directory, you - can use it like this: - - require '/path/to/HTMLPurifier.standalone.php'; - - This is equivalent to including HTMLPurifier.includes.php, except that - the contents of standalone/ will be added to your path. To override this - behavior, specify a new HTMLPURIFIER_PREFIX where standalone files can - be found (usually, this will be one directory up, the "true" library - directory in full distributions). Don't forget to set your path too! - - The autoloader can be added to the end to ensure the classes are - loaded when necessary; otherwise you can manually include them. - To use the autoloader, use this: - - require 'HTMLPurifier.autoload.php'; - -For advanced users ------------------- - - HTMLPurifier.auto.php performs a number of operations that can be done - individually. These are: - - HTMLPurifier.path.php - Puts /path/to/library in the include path. For high performance, - this should be done in php.ini. - - HTMLPurifier.autoload.php - Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class). - - You can do these operations by yourself--in fact, you must modify your own - autoload handler if you are using a version of PHP earlier than PHP 5.1.2 - (See "Autoload compatibility" above). - - ---------------------------------------------------------------------------- -4. Configuration - -HTML Purifier is designed to run out-of-the-box, but occasionally HTML -Purifier needs to be told what to do. If you answer no to any of these -questions, read on; otherwise, you can skip to the next section (or, if you're -into configuring things just for the heck of it, skip to 4.3). - -* Am I using UTF-8? -* Am I using XHTML 1.0 Transitional? - -If you answered no to any of these questions, instantiate a configuration -object and read on: - - $config = HTMLPurifier_Config::createDefault(); - - -4.1. Setting a different character encoding - -You really shouldn't use any other encoding except UTF-8, especially if you -plan to support multilingual websites (read section three for more details). -However, switching to UTF-8 is not always immediately feasible, so we can -adapt. - -HTML Purifier uses iconv to support other character encodings, as such, -any encoding that iconv supports -HTML Purifier supports with this code: - - $config->set('Core.Encoding', /* put your encoding here */); - -An example usage for Latin-1 websites (the most common encoding for English -websites): - - $config->set('Core.Encoding', 'ISO-8859-1'); - -Note that HTML Purifier's support for non-Unicode encodings is crippled by the -fact that any character not supported by that encoding will be silently -dropped, EVEN if it is ampersand escaped. If you want to work around -this, you are welcome to read docs/enduser-utf8.html for a fix, -but please be cognizant of the issues the "solution" creates (for this -reason, I do not include the solution in this document). - - -4.2. Setting a different doctype - -For those of you using HTML 4.01 Transitional, you can disable -XHTML output like this: - - $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); - -Other supported doctypes include: - - * HTML 4.01 Strict - * HTML 4.01 Transitional - * XHTML 1.0 Strict - * XHTML 1.0 Transitional - * XHTML 1.1 - - -4.3. Other settings - -There are more configuration directives which can be read about -here: They're a bit boring, -but they can help out for those of you who like to exert maximum control over -your code. Some of the more interesting ones are configurable at the -demo and are well worth looking into -for your own system. - -For example, you can fine tune allowed elements and attributes, convert -relative URLs to absolute ones, and even autoparagraph input text! These -are, respectively, %HTML.Allowed, %URI.MakeAbsolute and %URI.Base, and -%AutoFormat.AutoParagraph. The %Namespace.Directive naming convention -translates to: - - $config->set('Namespace.Directive', $value); - -E.g. - - $config->set('HTML.Allowed', 'p,b,a[href],i'); - $config->set('URI.Base', 'http://www.example.com'); - $config->set('URI.MakeAbsolute', true); - $config->set('AutoFormat.AutoParagraph', true); - - ---------------------------------------------------------------------------- -5. Caching - -HTML Purifier generates some cache files (generally one or two) to speed up -its execution. For maximum performance, make sure that -library/HTMLPurifier/DefinitionCache/Serializer is writeable by the webserver. - -If you are in the library/ folder of HTML Purifier, you can set the -appropriate permissions using: - - chmod -R 0755 HTMLPurifier/DefinitionCache/Serializer - -If the above command doesn't work, you may need to assign write permissions -to all. This may be necessary if your webserver runs as nobody, but is -not recommended since it means any other user can write files in the -directory. Use: - - chmod -R 0777 HTMLPurifier/DefinitionCache/Serializer - -You can also chmod files via your FTP client; this option -is usually accessible by right clicking the corresponding directory and -then selecting "chmod" or "file permissions". - -Starting with 2.0.1, HTML Purifier will generate friendly error messages -that will tell you exactly what you have to chmod the directory to, if in doubt, -follow its advice. - -If you are unable or unwilling to give write permissions to the cache -directory, you can either disable the cache (and suffer a performance -hit): - - $config->set('Core.DefinitionCache', null); - -Or move the cache directory somewhere else (no trailing slash): - - $config->set('Cache.SerializerPath', '/home/user/absolute/path'); - - ---------------------------------------------------------------------------- -6. Using the code - -The interface is mind-numbingly simple: - - $purifier = new HTMLPurifier($config); - $clean_html = $purifier->purify( $dirty_html ); - -That's it! For more examples, check out docs/examples/ (they aren't very -different though). Also, docs/enduser-slow.html gives advice on what to -do if HTML Purifier is slowing down your application. - - ---------------------------------------------------------------------------- -7. Quick install - -First, make sure library/HTMLPurifier/DefinitionCache/Serializer is -writable by the webserver (see Section 5: Caching above for details). -If your website is in UTF-8 and XHTML Transitional, use this code: - -purify($dirty_html); -?> - -If your website is in a different encoding or doctype, use this code: - -set('Core.Encoding', 'ISO-8859-1'); // replace with your encoding - $config->set('HTML.Doctype', 'HTML 4.01 Transitional'); // replace with your doctype - $purifier = new HTMLPurifier($config); - - $clean_html = $purifier->purify($dirty_html); -?> - - vim: et sw=4 sts=4 diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/NEWS b/library/IcingaVendor/htmlpurifier-4.6.0-lite/NEWS deleted file mode 100644 index 90a054620..000000000 --- a/library/IcingaVendor/htmlpurifier-4.6.0-lite/NEWS +++ /dev/null @@ -1,1078 +0,0 @@ -NEWS ( CHANGELOG and HISTORY ) HTMLPurifier -||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| - -= KEY ==================== - # Breaks back-compat - ! Feature - - Bugfix - + Sub-comment - . Internal change -========================== - -4.6.0, released 2013-11-30 -# Secure URI munge hashing algorithm has changed to hash_hmac("sha256", $url, $secret). - Please update any verification scripts you may have. -# URI parsing algorithm was made more strict, so only prefixes which - looks like schemes will actually be schemes. Thanks - Michael Gusev for fixing. -# %Core.EscapeInvalidChildren is no longer supported, and no longer does - anything. -! New directive %Core.AllowHostnameUnderscore which allows underscores - in hostnames. -- Eliminate quadratic behavior in DOMLex by using a proper queue. - Thanks Ole Laursen for noticing this. -- Rewritten MakeWellFormed/FixNesting implementation eliminates quadratic - behavior in the rest of the purificaiton pipeline. Thanks Chedburn - Networks for sponsoring this work. -- Made Linkify URL parser a bit less permissive, so that non-breaking - spaces and commas are not included as part of URL. Thanks nAS for fixing. -- Fix some bad interactions with %HTML.Allowed and injectors. Thanks - David Hirtz for reporting. -- Fix infinite loop in DirectLex. Thanks Ashar Javed (@soaj1664ashar) - for reporting. - -4.5.0, released 2013-02-17 -# Fix bug where stacked attribute transforms clobber each other; - this also means it's no longer possible to override attribute - transforms in later modules. No internal code was using this - but this may break some clients. -# We now use SHA-1 to identify cached definitions, instead of MD5. -! Support display:inline-block -! Support for more white-space CSS values. -! Permit underscores in font families -! Support for page-break-* CSS3 properties when proprietary properties - are enabled. -! New directive %Core.DisableExcludes; can be set to 'true' to turn off - SGML excludes checking. If HTML Purifier is removing too much text - and you don't care about full standards compliance, try setting this to - 'true'. -- Use prepend for SPL autoloading on PHP 5.3 and later. -- Fix bug with nofollow transform when pre-existing rel exists. -- Fix bug where background:url() always gets lower-cased - (but not background-image:url()) -- Fix bug with non lower-case color names in HTML -- Fix bug where data URI validation doesn't remove temporary files. - Thanks Javier Marín Ros for reporting. -- Don't remove certain empty tags on RemoveEmpty. - -4.4.0, released 2012-01-18 -# Removed PEARSax3 handler. -# URI.Munge now munges URIs inside the same host that go from https - to http. Reported by Neike Taika-Tessaro. -# Core.EscapeNonASCIICharacters now always transforms entities to - entities, even if target encoding is UTF-8. -# Tighten up selector validation in ExtractStyleBlocks. - Non-syntactically valid selectors are now rejected, along with - some of the more obscure ones such as attribute selectors, the - :lang pseudoselector, and anything not in CSS2.1. Furthermore, - ID and class selectors now work properly with the relevant - configuration attributes. Also, mute errors when parsing CSS - with CSS Tidy. Reported by Mario Heiderich and Norman Hippert. -! Added support for 'scope' attribute on tables. -! Added %HTML.TargetBlank, which adds target="blank" to all outgoing links. -! Properly handle sub-lists directly nested inside of lists in - a standards compliant way, by moving them into the preceding
  • -! Added %HTML.AllowedComments and %HTML.AllowedCommentsRegexp for - limited allowed comments in untrusted situations. -! Implement iframes, and allow them to be used in untrusted mode with - %HTML.SafeIframe and %URI.SafeIframeRegexp. Thanks Bradley M. Froehle - for submitting an initial version of the patch. -! The Forms module now works properly for transitional doctypes. -! Added support for internationalized domain names. You need the PEAR - Net_IDNA2 module to be in your path; if it is installed, ensure the - class can be loaded and then set %Core.EnableIDNA to true. -- Color keywords are now case insensitive. Thanks Yzmir Ramirez - for reporting. -- Explicitly initialize anonModule variable to null. -- Do not duplicate nofollow if already present. Thanks 178 - for reporting. -- Do not add nofollow if hostname matches our current host. Thanks 178 - for reporting, and Neike Taika-Tessaro for helping diagnose. -- Do not unset parser variable; this fixes intermittent serialization - problems. Thanks Neike Taika-Tessaro for reporting, bill - <10010tiger@gmail.com> for diagnosing. -- Fix iconv truncation bug, where non-UTF-8 target encodings see - output truncated after around 8000 characters. Thanks Jörg Ludwig - for reporting. -- Fix broken table content model for XHTML1.1 (and also earlier - versions, although the W3C validator doesn't catch those violations). - Thanks GlitchMr for reporting. - -4.3.0, released 2011-03-27 -# Fixed broken caching of customized raw definitions, but requires an - API change. The old API still works but will emit a warning, - see http://htmlpurifier.org/docs/enduser-customize.html#optimized - for how to upgrade your code. -# Protect against Internet Explorer innerHTML behavior by specially - treating attributes with backticks but no angled brackets, quotes or - spaces. This constitutes a slight semantic change, which can be - reverted using %Output.FixInnerHTML. Reported by Neike Taika-Tessaro - and Mario Heiderich. -# Protect against cssText/innerHTML by restricting allowed characters - used in fonts further than mandated by the specification and encoding - some extra special characters in URLs. Reported by Neike - Taika-Tessaro and Mario Heiderich. -! Added %HTML.Nofollow to add rel="nofollow" to external links. -! More types of SPL autoloaders allowed on later versions of PHP. -! Implementations for position, top, left, right, bottom, z-index - when %CSS.Trusted is on. -! Add %Cache.SerializerPermissions option for custom serializer - directory/file permissions -! Fix longstanding bug in Flash support for non-IE browsers, and - allow more wmode attributes. -! Add %CSS.AllowedFonts to restrict permissible font names. -- Switch to an iterative traversal of the DOM, which prevents us - from running out of stack space for deeply nested documents. - Thanks Maxim Krizhanovsky for contributing a patch. -- Make removal of conditional IE comments ungreedy; thanks Bernd - for reporting. -- Escape CDATA before removing Internet Explorer comments. -- Fix removal of id attributes under certain conditions by ensuring - armor attributes are preserved when recreating tags. -- Check if schema.ser was corrupted. -- Check if zend.ze1_compatibility_mode is on, and error out if it is. - This safety check is only done for HTMLPurifier.auto.php; if you - are using standalone or the specialized includes files, you're - expected to know what you're doing. -- Stop repeatedly writing the cache file after I'm done customizing a - raw definition. Reported by ajh. -- Switch to using require_once in the Bootstrap to work around bad - interaction with Zend Debugger and APC. Reported by Antonio Parraga. -- Fix URI handling when hostname is missing but scheme is present. - Reported by Neike Taika-Tessaro. -- Fix missing numeric entities on DirectLex; thanks Neike Taika-Tessaro - for reporting. -- Fix harmless notice from indexing into empty string. Thanks Matthijs - Kooijman for reporting. -- Don't autoclose no parent elements are able to support the element - that triggered the autoclose. In particular fixes strange behavior - of stray
  • tags. Thanks pkuliga@gmail.com for reporting and - Neike Taika-Tessaro for debugging assistance. - -4.2.0, released 2010-09-15 -! Added %Core.RemoveProcessingInstructions, which lets you remove - statements. -! Added %URI.DisableResources functionality; the directive originally - did nothing. Thanks David Rothstein for reporting. -! Add documentation about configuration directive types. -! Add %CSS.ForbiddenProperties configuration directive. -! Add %HTML.FlashAllowFullScreen to permit embedded Flash objects - to utilize full-screen mode. -! Add optional support for the file URI scheme, enable - by explicitly setting %URI.AllowedSchemes. -! Add %Core.NormalizeNewlines options to allow turning off newline - normalization. -- Fix improper handling of Internet Explorer conditional comments - by parser. Thanks zmonteca for reporting. -- Fix missing attributes bug when running on Mac Snow Leopard and APC. - Thanks sidepodcast for the fix. -- Warn if an element is allowed, but an attribute it requires is - not allowed. - -4.1.1, released 2010-05-31 -- Fix undefined index warnings in maintenance scripts. -- Fix bug in DirectLex for parsing elements with a single attribute - with entities. -- Rewrite CSS output logic for font-family and url(). Thanks Mario - Heiderich for reporting and Takeshi - Terada for suggesting the fix. -- Emit an error for CollectErrors if a body is extracted -- Fix bug where in background-position for center keyword handling. -- Fix infinite loop when a wrapper element is inserted in a context - where it's not allowed. Thanks Lars for reporting. -- Remove +x bit and shebang from index.php; only supported mode is to - explicitly call it with php. -- Make test script less chatty when log_errors is on. - -4.1.0, released 2010-04-26 -! Support proprietary height attribute on table element -! Support YouTube slideshows that contain /cp/ in their URL. -! Support for data: URI scheme; not enabled by default, add it using - %URI.AllowedSchemes -! Support flashvars when using %HTML.SafeObject and %HTML.SafeEmbed. -! Support for Internet Explorer compatibility with %HTML.SafeObject - using %Output.FlashCompat. -! Handle
        properly, by inserting the necessary
      1. tag. -- Always quote the insides of url(...) in CSS. - -4.0.0, released 2009-07-07 -# APIs for ConfigSchema subsystem have substantially changed. See - docs/dev-config-bcbreaks.txt for details; in essence, anything that - had both namespace and directive now have a single unified key. -# Some configuration directives were renamed, specifically: - %AutoFormatParam.PurifierLinkifyDocURL -> %AutoFormat.PurifierLinkify.DocURL - %FilterParam.ExtractStyleBlocksEscaping -> %Filter.ExtractStyleBlocks.Escaping - %FilterParam.ExtractStyleBlocksScope -> %Filter.ExtractStyleBlocks.Scope - %FilterParam.ExtractStyleBlocksTidyImpl -> %Filter.ExtractStyleBlocks.TidyImpl - As usual, the old directive names will still work, but will throw E_NOTICE - errors. -# The allowed values for class have been relaxed to allow all of CDATA for - doctypes that are not XHTML 1.1 or XHTML 2.0. For old behavior, set - %Attr.ClassUseCDATA to false. -# Instead of appending the content model to an old content model, a blank - element will replace the old content model. You can use #SUPER to get - the old content model. -! More robust support for name="" and id="" -! HTMLPurifier_Config::inherit($config) allows you to inherit one - configuration, and have changes to that configuration be propagated - to all of its children. -! Implement %HTML.Attr.Name.UseCDATA, which relaxes validation rules on - the name attribute when set. Use with care. Thanks Ian Cook for - sponsoring. -! Implement %AutoFormat.RemoveEmpty.RemoveNbsp, which removes empty - tags that contain non-breaking spaces as well other whitespace. You - can also modify which tags should have   maintained with - %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions. -! Implement %Attr.AllowedClasses, which allows administrators to restrict - classes users can use to a specified finite set of classes, and - %Attr.ForbiddenClasses, which is the logical inverse. -! You can now maintain your own configuration schema directories by - creating a config-schema.php file or passing an extra argument. Check - docs/dev-config-schema.html for more details. -! Added HTMLPurifier_Config->serialize() method, which lets you save away - your configuration in a compact serial file, which you can unserialize - and use directly without having to go through the overhead of setup. -- Fix bug where URIDefinition would not get cleared if it's directives got - changed. -- Fix fatal error in HTMLPurifier_Encoder on certain platforms (probably NetBSD 5.0) -- Fix bug in Linkify autoformatter involving http://foo -- Make %URI.Munge not apply to links that have the same host as your host. -- Prevent stray tag from truncating output, if a second - is present. -. Created script maintenance/rename-config.php for renaming a configuration - directive while maintaining its alias. This script does not change source code. -. Implement namespace locking for definition construction, to prevent - bugs where a directive is used for definition construction but is not - used to construct the cache hash. - -3.3.0, released 2009-02-16 -! Implement CSS property 'overflow' when %CSS.AllowTricky is true. -! Implement generic property list classess -- Fix bug with testEncodingSupportsASCII() algorithm when iconv() implementation - does not do the "right thing" with characters not supported in the output - set. -- Spellcheck UTF-8: The Secret To Character Encoding -- Fix improper removal of the contents of elements with only whitespace. Thanks - Eric Wald for reporting. -- Fix broken test suite in versions of PHP without spl_autoload_register() -- Fix degenerate case with YouTube filter involving double hyphens. - Thanks Pierre Attar for reporting. -- Fix YouTube rendering problem on certain versions of Firefox. -- Fix CSSDefinition Printer problems with decorators -- Add text parameter to unit tests, forces text output -. Add verbose mode to command line test runner, use (--verbose) -. Turn on unit tests for UnitConverter -. Fix missing version number in configuration %Attr.DefaultImageAlt (added 3.2.0) -. Fix newline errors that caused spurious failures when CRLF HTML Purifier was - tested on Linux. -. Removed trailing whitespace from all text files, see - remote-trailing-whitespace.php maintenance script. -. Convert configuration to use property list backend. - -3.2.0, released 2008-10-31 -# Using %Core.CollectErrors forces line number/column tracking on, whereas - previously you could theoretically turn it off. -# HTMLPurifier_Injector->notifyEnd() is formally deprecated. Please - use handleEnd() instead. -! %Output.AttrSort for when you need your attributes in alphabetical order to - deal with a bug in FCKEditor. Requested by frank farmer. -! Enable HTML comments when %HTML.Trusted is on. Requested by Waldo Jaquith. -! Proper support for name attribute. It is now allowed and equivalent to the id - attribute in a and img tags, and is only converted to id when %HTML.TidyLevel - is heavy (for all doctypes). -! %AutoFormat.RemoveEmpty to remove some empty tags from documents. Please don't - use on hand-written HTML. -! Add error-cases for unsupported elements in MakeWellFormed. This enables - the strategy to be used, standalone, on untrusted input. -! %Core.AggressivelyFixLt is on by default. This causes more sensible - processing of left angled brackets in smileys and other whatnot. -! Test scripts now have a 'type' parameter, which lets you say 'htmlpurifier', - 'phpt', 'vtest', etc. in order to only execute those tests. This supercedes - the --only-phpt parameter, although for backwards-compatibility the flag - will still work. -! AutoParagraph auto-formatter will now preserve double-newlines upon output. - Users who are not performing inbound filtering, this may seem a little - useless, but as a bonus, the test suite and handling of edge cases is also - improved. -! Experimental implementation of forms for %HTML.Trusted -! Track column numbers when maintain line numbers is on -! Proprietary 'background' attribute on table-related elements converted into - corresponding CSS. Thanks Fusemail for sponsoring this feature! -! Add forward(), forwardUntilEndToken(), backward() and current() to Injector - supertype. -! HTMLPurifier_Injector->handleEnd() permits modification to end tokens. The - time of operation varies slightly from notifyEnd() as *all* end tokens are - processed by the injector before they are subject to the well-formedness rules. -! %Attr.DefaultImageAlt allows overriding default behavior of setting alt to - basename of image when not present. -! %AutoFormat.DisplayLinkURI neuters tags into plain text URLs. -- Fix two bugs in %URI.MakeAbsolute; one involving empty paths in base URLs, - the other involving an undefined $is_folder error. -- Throw error when %Core.Encoding is set to a spurious value. Previously, - this errored silently and returned false. -- Redirected stderr to stdout for flush error output. -- %URI.DisableExternal will now use the host in %URI.Base if %URI.Host is not - available. -- Do not re-munge URL if the output URL has the same host as the input URL. - Requested by Chris. -- Fix error in documentation regarding %Filter.ExtractStyleBlocks -- Prevent ]]> from triggering %Core.ConvertDocumentToFragment -- Fix bug with inline elements in blockquotes conflicting with strict doctype -- Detect if HTML support is disabled for DOM by checking for loadHTML() method. -- Fix bug where dots and double-dots in absolute URLs without hostname were - not collapsed by URIFilter_MakeAbsolute. -- Fix bug with anonymous modules operating on SafeEmbed or SafeObject elements - by reordering their addition. -- Will now throw exception on many error conditions during lexer creation; also - throw an exception when MaintainLineNumbers is true, but a non-tracksLineNumbers - is being used. -- Detect if domxml extension is loaded, and use DirectLEx accordingly. -- Improve handling of big numbers with floating point arithmetic in UnitConverter. - Reported by David Morton. -. Strategy_MakeWellFormed now operates in-place, saving memory and allowing - for more interesting filter-backtracking -. New HTMLPurifier_Injector->rewind() functionality, allows injectors to rewind - index to reprocess tokens. -. StringHashParser now allows for multiline sections with "empty" content; - previously the section would remain undefined. -. Added --quick option to multitest.php, which tests only the most recent - release for each series. -. Added --distro option to multitest.php, which accepts either 'normal' or - 'standalone'. This supercedes --exclude-normal and --exclude-standalone - -3.1.1, released 2008-06-19 -# %URI.Munge now, by default, does not munge resources (for example, ) - In order to enable this again, please set %URI.MungeResources to true. -! More robust imagecrash protection with height/width CSS with %CSS.MaxImgLength, - and height/width HTML with %HTML.MaxImgLength. -! %URI.MungeSecretKey for secure URI munging. Thanks Chris - for sponsoring this feature. Check out the corresponding documentation - for details. (Att Nightly testers: The API for this feature changed before - the general release. Namely, rename your directives %URI.SecureMungeSecretKey => - %URI.MungeSecretKey and and %URI.SecureMunge => %URI.Munge) -! Implemented post URI filtering. Set member variable $post to true to set - a URIFilter as such. -! Allow modules to define injectors via $info_injector. Injectors are - automatically disabled if injector's needed elements are not found. -! Support for "safe" objects added, use %HTML.SafeObject and %HTML.SafeEmbed. - Thanks Chris for sponsoring. If you've been using ad hoc code from the - forums, PLEASE use this instead. -! Added substitutions for %e, %n, %a and %p in %URI.Munge (in order, - embedded, tag name, attribute name, CSS property name). See %URI.Munge - for more details. Requested by Jochem Blok. -- Disable percent height/width attributes for img. -- AttrValidator operations are now atomic; updates to attributes are not - manifest in token until end of operations. This prevents naughty internal - code from directly modifying CurrentToken when they're not supposed to. - This semantics change was requested by frank farmer. -- Percent encoding checks enabled for URI query and fragment -- Fix stray backslashes in font-family; CSS Unicode character escapes are - now properly resolved (although *only* in font-family). Thanks Takeshi Terada - for reporting. -- Improve parseCDATA algorithm to take into account newline normalization -- Account for browser confusion between Yen character and backslash in - Shift_JIS encoding. This fix generalizes to any other encoding which is not - a strict superset of printable ASCII. Thanks Takeshi Terada for reporting. -- Fix missing configuration parameter in Generator calls. Thanks vs for the - partial patch. -- Improved adherence to Unicode by checking for non-character codepoints. - Thanks Geoffrey Sneddon for reporting. This may result in degraded - performance for extremely large inputs. -- Allow CSS property-value pair ''text-decoration: none''. Thanks Jochem Blok - for reporting. -. Added HTMLPurifier_UnitConverter and HTMLPurifier_Length for convenient - handling of CSS-style lengths. HTMLPurifier_AttrDef_CSS_Length now uses - this class. -. API of HTMLPurifier_AttrDef_CSS_Length changed from __construct($disable_negative) - to __construct($min, $max). __construct(true) is equivalent to - __construct('0'). -. Added HTMLPurifier_AttrDef_Switch class -. Rename HTMLPurifier_HTMLModule_Tidy->construct() to setup() and bubble method - up inheritance hierarchy to HTMLPurifier_HTMLModule. All HTMLModules - get this called with the configuration object. All modules now - use this rather than __construct(), although legacy code using constructors - will still work--the new format, however, lets modules access the - configuration object for HTML namespace dependant tweaks. -. AttrDef_HTML_Pixels now takes a single construction parameter, pixels. -. ConfigSchema data-structure heavily optimized; on average it uses a third - the memory it did previously. The interface has changed accordingly, - consult changes to HTMLPurifier_Config for details. -. Variable parsing types now are magic integers instead of strings -. Added benchmark for ConfigSchema -. HTMLPurifier_Generator requires $config and $context parameters. If you - don't know what they should be, use HTMLPurifier_Config::createDefault() - and new HTMLPurifier_Context(). -. Printers now properly distinguish between output configuration, and - target configuration. This is not applicable to scripts using - the Printers for HTML Purifier related tasks. -. HTML/CSS Printers must be primed with prepareGenerator($gen_config), otherwise - fatal errors will ensue. -. URIFilter->prepare can return false in order to abort loading of the filter -. Factory for AttrDef_URI implemented, URI#embedded to indicate URI that embeds - an external resource. -. %URI.Munge functionality factored out into a post-filter class. -. Added CurrentCSSProperty context variable during CSS validation - -3.1.0, released 2008-05-18 -# Unnecessary references to objects (vestiges of PHP4) removed from method - signatures. The following methods do not need references when assigning from - them and will result in E_STRICT errors if you try: - + HTMLPurifier_Config->get*Definition() [* = HTML, CSS] - + HTMLPurifier_ConfigSchema::instance() - + HTMLPurifier_DefinitionCacheFactory::instance() - + HTMLPurifier_DefinitionCacheFactory->create() - + HTMLPurifier_DoctypeRegistry->register() - + HTMLPurifier_DoctypeRegistry->get() - + HTMLPurifier_HTMLModule->addElement() - + HTMLPurifier_HTMLModule->addBlankElement() - + HTMLPurifier_LanguageFactory::instance() -# Printer_ConfigForm's get*() functions were static-ified -# %HTML.ForbiddenAttributes requires attribute declarations to be in the - form of tag@attr, NOT tag.attr (which will throw an error and won't do - anything). This is for forwards compatibility with XML; you'd do best - to migrate an %HTML.AllowedAttributes directives to this syntax too. -! Allow index to be false for config from form creation -! Added HTMLPurifier::VERSION constant -! Commas, not dashes, used for serializer IDs. This change is forwards-compatible - and allows for version numbers like "3.1.0-dev". -! %HTML.Allowed deals gracefully with whitespace anywhere, anytime! -! HTML Purifier's URI handling is a lot more robust, with much stricter - validation checks and better percent encoding handling. Thanks Gareth Heyes - for indicating security vulnerabilities from lax percent encoding. -! Bootstrap autoloader deals more robustly with classes that don't exist, - preventing class_exists($class, true) from barfing. -- InterchangeBuilder now alphabetizes its lists -- Validation error in configdoc output fixed -- Iconv and other encoding errors muted even with custom error handlers that - do not honor error_reporting -- Add protection against imagecrash attack with CSS height/width -- HTMLPurifier::instance() created for consistency, is equivalent to getInstance() -- Fixed and revamped broken ConfigForm smoketest -- Bug with bool/null fields in Printer_ConfigForm fixed -- Bug with global forbidden attributes fixed -- Improved error messages for allowed and forbidden HTML elements and attributes -- Missing (or null) in configdoc documentation restored -- If DOM throws and exception during parsing with PH5P (occurs in newer versions - of DOM), HTML Purifier punts to DirectLex -- Fatal error with unserialization of ScriptRequired -- Created directories are now chmod'ed properly -- Fixed bug with fallback languages in LanguageFactory -- Standalone testing setup properly with autoload -. Out-of-date documentation revised -. UTF-8 encoding check optimization as suggested by Diego -. HTMLPurifier_Error removed in favor of exceptions -. More copy() function removed; should use clone instead -. More extensive unit tests for HTMLDefinition -. assertPurification moved to central harness -. HTMLPurifier_Generator accepts $config and $context parameters during - instantiation, not runtime -. Double-quotes outside of attribute values are now unescaped - -3.1.0rc1, released 2008-04-22 -# Autoload support added. Internal require_once's removed in favor of an - explicit require list or autoloading. To use HTML Purifier, - you must now either use HTMLPurifier.auto.php - or HTMLPurifier.includes.php; setting the include path and including - HTMLPurifier.php is insufficient--in such cases include HTMLPurifier.autoload.php - as well to register our autoload handler (or modify your autoload function - to check HTMLPurifier_Bootstrap::getPath($class)). You can also use - HTMLPurifier.safe-includes.php for a less performance friendly but more - user-friendly library load. -# HTMLPurifier_ConfigSchema static functions are officially deprecated. Schema - information is stored in the ConfigSchema directory, and the - maintenance/generate-schema-cache.php generates the schema.ser file, which - is now instantiated. Support for userland schema changes coming soon! -# HTMLPurifier_Config will now throw E_USER_NOTICE when you use a directive - alias; to get rid of these errors just modify your configuration to use - the new directive name. -# HTMLPurifier->addFilter is deprecated; built-in filters can now be - enabled using %Filter.$filter_name or by setting your own filters using - %Filter.Custom -# Directive-level safety properties superceded in favor of module-level - safety. Internal method HTMLModule->addElement() has changed, although - the externally visible HTMLDefinition->addElement has *not* changed. -! Extra utility classes for testing and non-library operations can - be found in extras/. Specifically, these are FSTools and ConfigDoc. - You may find a use for these in your own project, but right now they - are highly experimental and volatile. -! Integration with PHPT allows for automated smoketests -! Limited support for proprietary HTML elements, namely , sponsored - by Chris. You can enable them with %HTML.Proprietary if your client - demands them. -! Support for !important CSS cascade modifier. By default, this will be stripped - from CSS, but you can enable it using %CSS.AllowImportant -! Support for display and visibility CSS properties added, set %CSS.AllowTricky - to true to use them. -! HTML Purifier now has its own Exception hierarchy under HTMLPurifier_Exception. - Developer error (not enduser error) can cause these to be triggered. -! Experimental kses() wrapper introduced with HTMLPurifier.kses.php -! Finally %CSS.AllowedProperties for tweaking allowed CSS properties without - mucking around with HTMLPurifier_CSSDefinition -! ConfigDoc output has been enhanced with version and deprecation info. -! %HTML.ForbiddenAttributes and %HTML.ForbiddenElements implemented. -- Autoclose now operates iteratively, i.e.
        now has - both span tags closed. -- Various HTMLPurifier_Config convenience functions now accept another parameter - $schema which defines what HTMLPurifier_ConfigSchema to use besides the - global default. -- Fix bug with trusted script handling in libxml versions later than 2.6.28. -- Fix bug in ExtractStyleBlocks with comments in style tags -- Fix bug in comment parsing for DirectLex -- Flush output now displayed when in command line mode for unit tester -- Fix bug with rgb(0, 1, 2) color syntax with spaces inside shorthand syntax -- HTMLPurifier_HTMLDefinition->addAttribute can now be called multiple times - on the same element without emitting errors. -- Fixed fatal error in PH5P lexer with invalid tag names -. Plugins now get their own changelogs according to project conventions. -. Convert tokens to use instanceof, reducing memory footprint and - improving comparison speed. -. Dry runs now supported in SimpleTest; testing facilities improved -. Bootstrap class added for handling autoloading functionality -. Implemented recursive glob at FSTools->globr -. ConfigSchema now has instance methods for all corresponding define* - static methods. -. A couple of new historical maintenance scripts were added. -. HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php split into two files -. tests/index.php can now be run from any directory. -. HTMLPurifier_Token subclasses split into seperate files -. HTMLPURIFIER_PREFIX now is defined in Bootstrap.php, NOT HTMLPurifier.php -. HTMLPURIFIER_PREFIX can now be defined outside of HTML Purifier -. New --php=php flag added, allows PHP executable to be specified (command - line only!) -. htmlpurifier_add_test() preferred method to translate test files in to - classes, because it handles PHPT files too. -. Debugger class is deprecated and will be removed soon. -. Command line argument parsing for testing scripts revamped, now --opt value - format is supported. -. Smoketests now cleanup after magic quotes -. Generator now can output comments (however, comments are still stripped - from HTML Purifier output) -. HTMLPurifier_ConfigSchema->validate() deprecated in favor of - HTMLPurifier_VarParser->parse() -. Integers auto-cast into float type by VarParser. -. HTMLPURIFIER_STRICT removed; no validation is performed on runtime, only - during cache generation -. Reordered script calls in maintenance/flush.php -. Command line scripts now honor exit codes -. When --flush fails in unit testers, abort tests and print message -. Improved documentation in docs/dev-flush.html about the maintenance scripts -. copy() methods removed in favor of clone keyword - -3.0.0, released 2008-01-06 -# HTML Purifier is PHP 5 only! The 2.1.x branch will be maintained - until PHP 4 is completely deprecated, but no new features will be added - to it. - + Visibility declarations added - + Constructor methods renamed to __construct() - + PHP4 reference cruft removed (in progress) -! CSS properties are now case-insensitive -! DefinitionCacheFactory now can register new implementations -! New HTMLPurifier_Filter_ExtractStyleBlocks for extracting #isU', array($this, 'styleCallback'), $html); + $style_blocks = $this->_styleMatches; + $this->_styleMatches = array(); // reset + $context->register('StyleBlocks', $style_blocks); // $context must not be reused + if ($this->_tidy) { + foreach ($style_blocks as &$style) { + $style = $this->cleanCSS($style, $config, $context); + } + } + return $html; + } + + /** + * Takes CSS (the stuff found in in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/Filter/YouTube.php b/library/vendor/HTMLPurifier/HTMLPurifier/Filter/YouTube.php new file mode 100644 index 000000000..411519ad6 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,65 @@ +]+>.+?' . + 'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; + $pre_replace = '\1'; + return preg_replace($pre_regex, $pre_replace, $html); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + $post_regex = '#((?:v|cp)/[A-Za-z0-9\-_=]+)#'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + /** + * @param $url + * @return string + */ + protected function armorUrl($url) + { + return str_replace('--', '--', $url); + } + + /** + * @param array $matches + * @return string + */ + protected function postFilterCallback($matches) + { + $url = $this->armorUrl($matches[1]); + return '' . + '' . + '' . + ''; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/Generator.php b/library/vendor/HTMLPurifier/HTMLPurifier/Generator.php new file mode 100644 index 000000000..6fb568714 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/Generator.php @@ -0,0 +1,286 @@ + tags. + * @type bool + */ + private $_scriptFix = false; + + /** + * Cache of HTMLDefinition during HTML output to determine whether or + * not attributes should be minimized. + * @type HTMLPurifier_HTMLDefinition + */ + private $_def; + + /** + * Cache of %Output.SortAttr. + * @type bool + */ + private $_sortAttr; + + /** + * Cache of %Output.FlashCompat. + * @type bool + */ + private $_flashCompat; + + /** + * Cache of %Output.FixInnerHTML. + * @type bool + */ + private $_innerHTMLFix; + + /** + * Stack for keeping track of object information when outputting IE + * compatibility code. + * @type array + */ + private $_flashStack = array(); + + /** + * Configuration for the generator + * @type HTMLPurifier_Config + */ + protected $config; + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + public function __construct($config, $context) + { + $this->config = $config; + $this->_scriptFix = $config->get('Output.CommentScriptContents'); + $this->_innerHTMLFix = $config->get('Output.FixInnerHTML'); + $this->_sortAttr = $config->get('Output.SortAttr'); + $this->_flashCompat = $config->get('Output.FlashCompat'); + $this->_def = $config->getHTMLDefinition(); + $this->_xhtml = $this->_def->doctype->xml; + } + + /** + * Generates HTML from an array of tokens. + * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token + * @return string Generated HTML + */ + public function generateFromTokens($tokens) + { + if (!$tokens) { + return ''; + } + + // Basic algorithm + $html = ''; + for ($i = 0, $size = count($tokens); $i < $size; $i++) { + if ($this->_scriptFix && $tokens[$i]->name === 'script' + && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { + // script special case + // the contents of the script block must be ONE token + // for this to work. + $html .= $this->generateFromToken($tokens[$i++]); + $html .= $this->generateScriptFromToken($tokens[$i++]); + } + $html .= $this->generateFromToken($tokens[$i]); + } + + // Tidy cleanup + if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) { + $tidy = new Tidy; + $tidy->parseString( + $html, + array( + 'indent'=> true, + 'output-xhtml' => $this->_xhtml, + 'show-body-only' => true, + 'indent-spaces' => 2, + 'wrap' => 68, + ), + 'utf8' + ); + $tidy->cleanRepair(); + $html = (string) $tidy; // explicit cast necessary + } + + // Normalize newlines to system defined value + if ($this->config->get('Core.NormalizeNewlines')) { + $nl = $this->config->get('Output.Newline'); + if ($nl === null) { + $nl = PHP_EOL; + } + if ($nl !== "\n") { + $html = str_replace("\n", $nl, $html); + } + } + return $html; + } + + /** + * Generates HTML from a single token. + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string Generated HTML + */ + public function generateFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token) { + trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING); + return ''; + + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $attr = $this->generateAttributes($token->attr, $token->name); + if ($this->_flashCompat) { + if ($token->name == "object") { + $flash = new stdclass(); + $flash->attr = $token->attr; + $flash->param = array(); + $this->_flashStack[] = $flash; + } + } + return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_End) { + $_extra = ''; + if ($this->_flashCompat) { + if ($token->name == "object" && !empty($this->_flashStack)) { + // doesn't do anything for now + } + } + return $_extra . 'name . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + if ($this->_flashCompat && $token->name == "param" && !empty($this->_flashStack)) { + $this->_flashStack[count($this->_flashStack)-1]->param[$token->attr['name']] = $token->attr['value']; + } + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . + ( $this->_xhtml ? ' /': '' ) //
        v.
        + . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Text) { + return $this->escape($token->data, ENT_NOQUOTES); + + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + return ''; + } else { + return ''; + + } + } + + /** + * Special case processor for the contents of script tags + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string + * @warning This runs into problems if there's already a literal + * --> somewhere inside the script contents. + */ + public function generateScriptFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token_Text) { + return $this->generateFromToken($token); + } + // Thanks + $data = preg_replace('#//\s*$#', '', $token->data); + return ''; + } + + /** + * Generates attribute declarations from attribute array. + * @note This does not include the leading or trailing space. + * @param array $assoc_array_of_attributes Attribute array + * @param string $element Name of element attributes are for, used to check + * attribute minimization. + * @return string Generated HTML fragment for insertion. + */ + public function generateAttributes($assoc_array_of_attributes, $element = '') + { + $html = ''; + if ($this->_sortAttr) { + ksort($assoc_array_of_attributes); + } + foreach ($assoc_array_of_attributes as $key => $value) { + if (!$this->_xhtml) { + // Remove namespaced attributes + if (strpos($key, ':') !== false) { + continue; + } + // Check if we should minimize the attribute: val="val" -> val + if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) { + $html .= $key . ' '; + continue; + } + } + // Workaround for Internet Explorer innerHTML bug. + // Essentially, Internet Explorer, when calculating + // innerHTML, omits quotes if there are no instances of + // angled brackets, quotes or spaces. However, when parsing + // HTML (for example, when you assign to innerHTML), it + // treats backticks as quotes. Thus, + // `` + // becomes + // `` + // becomes + // + // Fortunately, all we need to do is trigger an appropriate + // quoting style, which we do by adding an extra space. + // This also is consistent with the W3C spec, which states + // that user agents may ignore leading or trailing + // whitespace (in fact, most don't, at least for attributes + // like alt, but an extra space at the end is barely + // noticeable). Still, we have a configuration knob for + // this, since this transformation is not necesary if you + // don't process user input with innerHTML or you don't plan + // on supporting Internet Explorer. + if ($this->_innerHTMLFix) { + if (strpos($value, '`') !== false) { + // check if correct quoting style would not already be + // triggered + if (strcspn($value, '"\' <>') === strlen($value)) { + // protect! + $value .= ' '; + } + } + } + $html .= $key.'="'.$this->escape($value).'" '; + } + return rtrim($html); + } + + /** + * Escapes raw text data. + * @todo This really ought to be protected, but until we have a facility + * for properly generating HTML here w/o using tokens, it stays + * public. + * @param string $string String data to escape for HTML. + * @param int $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is + * permissible for non-attribute output. + * @return string escaped data. + */ + public function escape($string, $quote = null) + { + // Workaround for APC bug on Mac Leopard reported by sidepodcast + // http://htmlpurifier.org/phorum/read.php?3,4823,4846 + if ($quote === null) { + $quote = ENT_COMPAT; + } + return htmlspecialchars($string, $quote, 'UTF-8'); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLDefinition.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLDefinition.php new file mode 100644 index 000000000..9b7b334dd --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLDefinition.php @@ -0,0 +1,493 @@ +getAnonymousModule(); + if (!isset($module->info[$element_name])) { + $element = $module->addBlankElement($element_name); + } else { + $element = $module->info[$element_name]; + } + $element->attr[$attr_name] = $def; + } + + /** + * Adds a custom element to your HTML definition + * @see HTMLPurifier_HTMLModule::addElement() for detailed + * parameter and return value descriptions. + */ + public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array()) + { + $module = $this->getAnonymousModule(); + // assume that if the user is calling this, the element + // is safe. This may not be a good idea + $element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes); + return $element; + } + + /** + * Adds a blank element to your HTML definition, for overriding + * existing behavior + * @param string $element_name + * @return HTMLPurifier_ElementDef + * @see HTMLPurifier_HTMLModule::addBlankElement() for detailed + * parameter and return value descriptions. + */ + public function addBlankElement($element_name) + { + $module = $this->getAnonymousModule(); + $element = $module->addBlankElement($element_name); + return $element; + } + + /** + * Retrieves a reference to the anonymous module, so you can + * bust out advanced features without having to make your own + * module. + * @return HTMLPurifier_HTMLModule + */ + public function getAnonymousModule() + { + if (!$this->_anonModule) { + $this->_anonModule = new HTMLPurifier_HTMLModule(); + $this->_anonModule->name = 'Anonymous'; + } + return $this->_anonModule; + } + + private $_anonModule = null; + + // PUBLIC BUT INTERNAL VARIABLES -------------------------------------- + + /** + * @type string + */ + public $type = 'HTML'; + + /** + * @type HTMLPurifier_HTMLModuleManager + */ + public $manager; + + /** + * Performs low-cost, preliminary initialization. + */ + public function __construct() + { + $this->manager = new HTMLPurifier_HTMLModuleManager(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetup($config) + { + $this->processModules($config); + $this->setupConfigStuff($config); + unset($this->manager); + + // cleanup some of the element definitions + foreach ($this->info as $k => $v) { + unset($this->info[$k]->content_model); + unset($this->info[$k]->content_model_type); + } + } + + /** + * Extract out the information from the manager + * @param HTMLPurifier_Config $config + */ + protected function processModules($config) + { + if ($this->_anonModule) { + // for user specific changes + // this is late-loaded so we don't have to deal with PHP4 + // reference wonky-ness + $this->manager->addModule($this->_anonModule); + unset($this->_anonModule); + } + + $this->manager->setup($config); + $this->doctype = $this->manager->doctype; + + foreach ($this->manager->modules as $module) { + foreach ($module->info_tag_transform as $k => $v) { + if ($v === false) { + unset($this->info_tag_transform[$k]); + } else { + $this->info_tag_transform[$k] = $v; + } + } + foreach ($module->info_attr_transform_pre as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_pre[$k]); + } else { + $this->info_attr_transform_pre[$k] = $v; + } + } + foreach ($module->info_attr_transform_post as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_post[$k]); + } else { + $this->info_attr_transform_post[$k] = $v; + } + } + foreach ($module->info_injector as $k => $v) { + if ($v === false) { + unset($this->info_injector[$k]); + } else { + $this->info_injector[$k] = $v; + } + } + } + $this->info = $this->manager->getElements(); + $this->info_content_sets = $this->manager->contentSets->lookup; + } + + /** + * Sets up stuff based on config. We need a better way of doing this. + * @param HTMLPurifier_Config $config + */ + protected function setupConfigStuff($config) + { + $block_wrapper = $config->get('HTML.BlockWrapper'); + if (isset($this->info_content_sets['Block'][$block_wrapper])) { + $this->info_block_wrapper = $block_wrapper; + } else { + trigger_error( + 'Cannot use non-block element as block wrapper', + E_USER_ERROR + ); + } + + $parent = $config->get('HTML.Parent'); + $def = $this->manager->getElement($parent, true); + if ($def) { + $this->info_parent = $parent; + $this->info_parent_def = $def; + } else { + trigger_error( + 'Cannot use unrecognized element as parent', + E_USER_ERROR + ); + $this->info_parent_def = $this->manager->getElement($this->info_parent, true); + } + + // support template text + $support = "(for information on implementing this, see the support forums) "; + + // setup allowed elements ----------------------------------------- + + $allowed_elements = $config->get('HTML.AllowedElements'); + $allowed_attributes = $config->get('HTML.AllowedAttributes'); // retrieve early + + if (!is_array($allowed_elements) && !is_array($allowed_attributes)) { + $allowed = $config->get('HTML.Allowed'); + if (is_string($allowed)) { + list($allowed_elements, $allowed_attributes) = $this->parseTinyMCEAllowedList($allowed); + } + } + + if (is_array($allowed_elements)) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_elements[$name])) { + unset($this->info[$name]); + } + unset($allowed_elements[$name]); + } + // emit errors + foreach ($allowed_elements as $element => $d) { + $element = htmlspecialchars($element); // PHP doesn't escape errors, be careful! + trigger_error("Element '$element' is not supported $support", E_USER_WARNING); + } + } + + // setup allowed attributes --------------------------------------- + + $allowed_attributes_mutable = $allowed_attributes; // by copy! + if (is_array($allowed_attributes)) { + // This actually doesn't do anything, since we went away from + // global attributes. It's possible that userland code uses + // it, but HTMLModuleManager doesn't! + foreach ($this->info_global_attr as $attr => $x) { + $keys = array($attr, "*@$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + unset($this->info_global_attr[$attr]); + } + } + + foreach ($this->info as $tag => $info) { + foreach ($info->attr as $attr => $x) { + $keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + if ($this->info[$tag]->attr[$attr]->required) { + trigger_error( + "Required attribute '$attr' in element '$tag' " . + "was not allowed, which means '$tag' will not be allowed either", + E_USER_WARNING + ); + } + unset($this->info[$tag]->attr[$attr]); + } + } + } + // emit errors + foreach ($allowed_attributes_mutable as $elattr => $d) { + $bits = preg_split('/[.@]/', $elattr, 2); + $c = count($bits); + switch ($c) { + case 2: + if ($bits[0] !== '*') { + $element = htmlspecialchars($bits[0]); + $attribute = htmlspecialchars($bits[1]); + if (!isset($this->info[$element])) { + trigger_error( + "Cannot allow attribute '$attribute' if element " . + "'$element' is not allowed/supported $support" + ); + } else { + trigger_error( + "Attribute '$attribute' in element '$element' not supported $support", + E_USER_WARNING + ); + } + break; + } + // otherwise fall through + case 1: + $attribute = htmlspecialchars($bits[0]); + trigger_error( + "Global attribute '$attribute' is not ". + "supported in any elements $support", + E_USER_WARNING + ); + break; + } + } + } + + // setup forbidden elements --------------------------------------- + + $forbidden_elements = $config->get('HTML.ForbiddenElements'); + $forbidden_attributes = $config->get('HTML.ForbiddenAttributes'); + + foreach ($this->info as $tag => $info) { + if (isset($forbidden_elements[$tag])) { + unset($this->info[$tag]); + continue; + } + foreach ($info->attr as $attr => $x) { + if (isset($forbidden_attributes["$tag@$attr"]) || + isset($forbidden_attributes["*@$attr"]) || + isset($forbidden_attributes[$attr]) + ) { + unset($this->info[$tag]->attr[$attr]); + continue; + } elseif (isset($forbidden_attributes["$tag.$attr"])) { // this segment might get removed eventually + // $tag.$attr are not user supplied, so no worries! + trigger_error( + "Error with $tag.$attr: tag.attr syntax not supported for " . + "HTML.ForbiddenAttributes; use tag@attr instead", + E_USER_WARNING + ); + } + } + } + foreach ($forbidden_attributes as $key => $v) { + if (strlen($key) < 2) { + continue; + } + if ($key[0] != '*') { + continue; + } + if ($key[1] == '.') { + trigger_error( + "Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", + E_USER_WARNING + ); + } + } + + // setup injectors ----------------------------------------------------- + foreach ($this->info_injector as $i => $injector) { + if ($injector->checkNeeded($config) !== false) { + // remove injector that does not have it's required + // elements/attributes present, and is thus not needed. + unset($this->info_injector[$i]); + } + } + } + + /** + * Parses a TinyMCE-flavored Allowed Elements and Attributes list into + * separate lists for processing. Format is element[attr1|attr2],element2... + * @warning Although it's largely drawn from TinyMCE's implementation, + * it is different, and you'll probably have to modify your lists + * @param array $list String list to parse + * @return array + * @todo Give this its own class, probably static interface + */ + public function parseTinyMCEAllowedList($list) + { + $list = str_replace(array(' ', "\t"), '', $list); + + $elements = array(); + $attributes = array(); + + $chunks = preg_split('/(,|[\n\r]+)/', $list); + foreach ($chunks as $chunk) { + if (empty($chunk)) { + continue; + } + // remove TinyMCE element control characters + if (!strpos($chunk, '[')) { + $element = $chunk; + $attr = false; + } else { + list($element, $attr) = explode('[', $chunk); + } + if ($element !== '*') { + $elements[$element] = true; + } + if (!$attr) { + continue; + } + $attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ] + $attr = explode('|', $attr); + foreach ($attr as $key) { + $attributes["$element.$key"] = true; + } + } + return array($elements, $attributes); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule.php new file mode 100644 index 000000000..bb3a9230b --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule.php @@ -0,0 +1,284 @@ +info, since the object's data is only info, + * with extra behavior associated with it. + * @type array + */ + public $attr_collections = array(); + + /** + * Associative array of deprecated tag name to HTMLPurifier_TagTransform. + * @type array + */ + public $info_tag_transform = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed before validation. + * @type array + */ + public $info_attr_transform_pre = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed after validation. + * @type array + */ + public $info_attr_transform_post = array(); + + /** + * List of HTMLPurifier_Injector to be performed during well-formedness fixing. + * An injector will only be invoked if all of it's pre-requisites are met; + * if an injector fails setup, there will be no error; it will simply be + * silently disabled. + * @type array + */ + public $info_injector = array(); + + /** + * Boolean flag that indicates whether or not getChildDef is implemented. + * For optimization reasons: may save a call to a function. Be sure + * to set it if you do implement getChildDef(), otherwise it will have + * no effect! + * @type bool + */ + public $defines_child_def = false; + + /** + * Boolean flag whether or not this module is safe. If it is not safe, all + * of its members are unsafe. Modules are safe by default (this might be + * slightly dangerous, but it doesn't make much sense to force HTML Purifier, + * which is based off of safe HTML, to explicitly say, "This is safe," even + * though there are modules which are "unsafe") + * + * @type bool + * @note Previously, safety could be applied at an element level granularity. + * We've removed this ability, so in order to add "unsafe" elements + * or attributes, a dedicated module with this property set to false + * must be used. + */ + public $safe = true; + + /** + * Retrieves a proper HTMLPurifier_ChildDef subclass based on + * content_model and content_model_type member variables of + * the HTMLPurifier_ElementDef class. There is a similar function + * in HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef subclass + */ + public function getChildDef($def) + { + return false; + } + + // -- Convenience ----------------------------------------------------- + + /** + * Convenience function that sets up a new element + * @param string $element Name of element to add + * @param string|bool $type What content set should element be registered to? + * Set as false to skip this step. + * @param string $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @param array $attr_includes What attribute collections to register to + * element? + * @param array $attr What unique attributes does the element define? + * @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters. + * @return HTMLPurifier_ElementDef Created element definition object, so you + * can set advanced parameters + */ + public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) + { + $this->elements[] = $element; + // parse content_model + list($content_model_type, $content_model) = $this->parseContents($contents); + // merge in attribute inclusions + $this->mergeInAttrIncludes($attr, $attr_includes); + // add element to content sets + if ($type) { + $this->addElementToContentSet($element, $type); + } + // create element + $this->info[$element] = HTMLPurifier_ElementDef::create( + $content_model, + $content_model_type, + $attr + ); + // literal object $contents means direct child manipulation + if (!is_string($contents)) { + $this->info[$element]->child = $contents; + } + return $this->info[$element]; + } + + /** + * Convenience function that creates a totally blank, non-standalone + * element. + * @param string $element Name of element to create + * @return HTMLPurifier_ElementDef Created element + */ + public function addBlankElement($element) + { + if (!isset($this->info[$element])) { + $this->elements[] = $element; + $this->info[$element] = new HTMLPurifier_ElementDef(); + $this->info[$element]->standalone = false; + } else { + trigger_error("Definition for $element already exists in module, cannot redefine"); + } + return $this->info[$element]; + } + + /** + * Convenience function that registers an element to a content set + * @param string $element Element to register + * @param string $type Name content set (warning: case sensitive, usually upper-case + * first letter) + */ + public function addElementToContentSet($element, $type) + { + if (!isset($this->content_sets[$type])) { + $this->content_sets[$type] = ''; + } else { + $this->content_sets[$type] .= ' | '; + } + $this->content_sets[$type] .= $element; + } + + /** + * Convenience function that transforms single-string contents + * into separate content model and content model type + * @param string $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @return array + * @note If contents is an object, an array of two nulls will be + * returned, and the callee needs to take the original $contents + * and use it directly. + */ + public function parseContents($contents) + { + if (!is_string($contents)) { + return array(null, null); + } // defer + switch ($contents) { + // check for shorthand content model forms + case 'Empty': + return array('empty', ''); + case 'Inline': + return array('optional', 'Inline | #PCDATA'); + case 'Flow': + return array('optional', 'Flow | #PCDATA'); + } + list($content_model_type, $content_model) = explode(':', $contents); + $content_model_type = strtolower(trim($content_model_type)); + $content_model = trim($content_model); + return array($content_model_type, $content_model); + } + + /** + * Convenience function that merges a list of attribute includes into + * an attribute array. + * @param array $attr Reference to attr array to modify + * @param array $attr_includes Array of includes / string include to merge in + */ + public function mergeInAttrIncludes(&$attr, $attr_includes) + { + if (!is_array($attr_includes)) { + if (empty($attr_includes)) { + $attr_includes = array(); + } else { + $attr_includes = array($attr_includes); + } + } + $attr[0] = $attr_includes; + } + + /** + * Convenience function that generates a lookup table with boolean + * true as value. + * @param string $list List of values to turn into a lookup + * @note You can also pass an arbitrary number of arguments in + * place of the regular argument + * @return array array equivalent of list + */ + public function makeLookup($list) + { + if (is_string($list)) { + $list = func_get_args(); + } + $ret = array(); + foreach ($list as $value) { + if (is_null($value)) { + continue; + } + $ret[$value] = true; + } + return $ret; + } + + /** + * Lazy load construction of the module after determining whether + * or not it's needed, and also when a finalized configuration object + * is available. + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php new file mode 100644 index 000000000..1e67c790d --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Bdo.php @@ -0,0 +1,44 @@ + array('dir' => false) + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $bdo = $this->addElement( + 'bdo', + 'Inline', + 'Inline', + array('Core', 'Lang'), + array( + 'dir' => 'Enum#ltr,rtl', // required + // The Abstract Module specification has the attribute + // inclusions wrong for bdo: bdo allows Lang + ) + ); + $bdo->attr_transform_post[] = new HTMLPurifier_AttrTransform_BdoDir(); + + $this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl'; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php new file mode 100644 index 000000000..a96ab1bef --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -0,0 +1,31 @@ + array( + 0 => array('Style'), + // 'xml:space' => false, + 'class' => 'Class', + 'id' => 'ID', + 'title' => 'CDATA', + ), + 'Lang' => array(), + 'I18N' => array( + 0 => array('Lang'), // proprietary, for xml:lang/lang + ), + 'Common' => array( + 0 => array('Core', 'I18N') + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php new file mode 100644 index 000000000..a9042a357 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Edit.php @@ -0,0 +1,55 @@ + 'URI', + // 'datetime' => 'Datetime', // not implemented + ); + $this->addElement('del', 'Inline', $contents, 'Common', $attr); + $this->addElement('ins', 'Inline', $contents, 'Common', $attr); + } + + // HTML 4.01 specifies that ins/del must not contain block + // elements when used in an inline context, chameleon is + // a complicated workaround to acheive this effect + + // Inline context ! Block context (exclamation mark is + // separator, see getChildDef for parsing) + + /** + * @type bool + */ + public $defines_child_def = true; + + /** + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef_Chameleon + */ + public function getChildDef($def) + { + if ($def->content_model_type != 'chameleon') { + return false; + } + $value = explode('!', $def->content_model); + return new HTMLPurifier_ChildDef_Chameleon($value[0], $value[1]); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php new file mode 100644 index 000000000..6f7ddbc05 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Forms.php @@ -0,0 +1,190 @@ + 'Form', + 'Inline' => 'Formctrl', + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $form = $this->addElement( + 'form', + 'Form', + 'Required: Heading | List | Block | fieldset', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accept-charset' => 'Charsets', + 'action*' => 'URI', + 'method' => 'Enum#get,post', + // really ContentType, but these two are the only ones used today + 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data', + ) + ); + $form->excludes = array('form' => true); + + $input = $this->addElement( + 'input', + 'Formctrl', + 'Empty', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accesskey' => 'Character', + 'alt' => 'Text', + 'checked' => 'Bool#checked', + 'disabled' => 'Bool#disabled', + 'maxlength' => 'Number', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'size' => 'Number', + 'src' => 'URI#embedded', + 'tabindex' => 'Number', + 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image', + 'value' => 'CDATA', + ) + ); + $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input(); + + $this->addElement( + 'select', + 'Formctrl', + 'Required: optgroup | option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'multiple' => 'Bool#multiple', + 'name' => 'CDATA', + 'size' => 'Number', + 'tabindex' => 'Number', + ) + ); + + $this->addElement( + 'option', + false, + 'Optional: #PCDATA', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label' => 'Text', + 'selected' => 'Bool#selected', + 'value' => 'CDATA', + ) + ); + // It's illegal for there to be more than one selected, but not + // be multiple. Also, no selected means undefined behavior. This might + // be difficult to implement; perhaps an injector, or a context variable. + + $textarea = $this->addElement( + 'textarea', + 'Formctrl', + 'Optional: #PCDATA', + 'Common', + array( + 'accesskey' => 'Character', + 'cols*' => 'Number', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'rows*' => 'Number', + 'tabindex' => 'Number', + ) + ); + $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea(); + + $button = $this->addElement( + 'button', + 'Formctrl', + 'Optional: #PCDATA | Heading | List | Block | Inline', + 'Common', + array( + 'accesskey' => 'Character', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'tabindex' => 'Number', + 'type' => 'Enum#button,submit,reset', + 'value' => 'CDATA', + ) + ); + + // For exclusions, ideally we'd specify content sets, not literal elements + $button->excludes = $this->makeLookup( + 'form', + 'fieldset', // Form + 'input', + 'select', + 'textarea', + 'label', + 'button', // Formctrl + 'a', // as per HTML 4.01 spec, this is omitted by modularization + 'isindex', + 'iframe' // legacy items + ); + + // Extra exclusion: img usemap="" is not permitted within this element. + // We'll omit this for now, since we don't have any good way of + // indicating it yet. + + // This is HIGHLY user-unfriendly; we need a custom child-def for this + $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common'); + + $label = $this->addElement( + 'label', + 'Formctrl', + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + // 'for' => 'IDREF', // IDREF not implemented, cannot allow + ) + ); + $label->excludes = array('label' => true); + + $this->addElement( + 'legend', + false, + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + ) + ); + + $this->addElement( + 'optgroup', + false, + 'Required: option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label*' => 'Text', + ) + ); + // Don't forget an injector for . This one's a little complex + // because it maps to multiple elements. + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php new file mode 100644 index 000000000..72d7a31e6 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Hypertext.php @@ -0,0 +1,40 @@ +addElement( + 'a', + 'Inline', + 'Inline', + 'Common', + array( + // 'accesskey' => 'Character', + // 'charset' => 'Charset', + 'href' => 'URI', + // 'hreflang' => 'LanguageCode', + 'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'), + 'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'), + // 'tabindex' => 'Number', + // 'type' => 'ContentType', + ) + ); + $a->formatting = true; + $a->excludes = array('a' => true); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Iframe.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Iframe.php new file mode 100644 index 000000000..f7e7c91c0 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Iframe.php @@ -0,0 +1,51 @@ +get('HTML.SafeIframe')) { + $this->safe = true; + } + $this->addElement( + 'iframe', + 'Inline', + 'Flow', + 'Common', + array( + 'src' => 'URI#embedded', + 'width' => 'Length', + 'height' => 'Length', + 'name' => 'ID', + 'scrolling' => 'Enum#yes,no,auto', + 'frameborder' => 'Enum#0,1', + 'longdesc' => 'URI', + 'marginheight' => 'Pixels', + 'marginwidth' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php new file mode 100644 index 000000000..0f5fdb3ba --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Image.php @@ -0,0 +1,49 @@ +get('HTML.MaxImgLength'); + $img = $this->addElement( + 'img', + 'Inline', + 'Empty', + 'Common', + array( + 'alt*' => 'Text', + // According to the spec, it's Length, but percents can + // be abused, so we allow only Pixels. + 'height' => 'Pixels#' . $max, + 'width' => 'Pixels#' . $max, + 'longdesc' => 'URI', + 'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded + ) + ); + if ($max === null || $config->get('HTML.Trusted')) { + $img->attr['height'] = + $img->attr['width'] = 'Length'; + } + + // kind of strange, but splitting things up would be inefficient + $img->attr_transform_pre[] = + $img->attr_transform_post[] = + new HTMLPurifier_AttrTransform_ImgRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php new file mode 100644 index 000000000..86b529957 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Legacy.php @@ -0,0 +1,186 @@ +addElement( + 'basefont', + 'Inline', + 'Empty', + null, + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + 'id' => 'ID' + ) + ); + $this->addElement('center', 'Block', 'Flow', 'Common'); + $this->addElement( + 'dir', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + $this->addElement( + 'font', + 'Inline', + 'Inline', + array('Core', 'I18N'), + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + ) + ); + $this->addElement( + 'menu', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + + $s = $this->addElement('s', 'Inline', 'Inline', 'Common'); + $s->formatting = true; + + $strike = $this->addElement('strike', 'Inline', 'Inline', 'Common'); + $strike->formatting = true; + + $u = $this->addElement('u', 'Inline', 'Inline', 'Common'); + $u->formatting = true; + + // setup modifications to old elements + + $align = 'Enum#left,right,center,justify'; + + $address = $this->addBlankElement('address'); + $address->content_model = 'Inline | #PCDATA | p'; + $address->content_model_type = 'optional'; + $address->child = false; + + $blockquote = $this->addBlankElement('blockquote'); + $blockquote->content_model = 'Flow | #PCDATA'; + $blockquote->content_model_type = 'optional'; + $blockquote->child = false; + + $br = $this->addBlankElement('br'); + $br->attr['clear'] = 'Enum#left,all,right,none'; + + $caption = $this->addBlankElement('caption'); + $caption->attr['align'] = 'Enum#top,bottom,left,right'; + + $div = $this->addBlankElement('div'); + $div->attr['align'] = $align; + + $dl = $this->addBlankElement('dl'); + $dl->attr['compact'] = 'Bool#compact'; + + for ($i = 1; $i <= 6; $i++) { + $h = $this->addBlankElement("h$i"); + $h->attr['align'] = $align; + } + + $hr = $this->addBlankElement('hr'); + $hr->attr['align'] = $align; + $hr->attr['noshade'] = 'Bool#noshade'; + $hr->attr['size'] = 'Pixels'; + $hr->attr['width'] = 'Length'; + + $img = $this->addBlankElement('img'); + $img->attr['align'] = 'IAlign'; + $img->attr['border'] = 'Pixels'; + $img->attr['hspace'] = 'Pixels'; + $img->attr['vspace'] = 'Pixels'; + + // figure out this integer business + + $li = $this->addBlankElement('li'); + $li->attr['value'] = new HTMLPurifier_AttrDef_Integer(); + $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle'; + + $ol = $this->addBlankElement('ol'); + $ol->attr['compact'] = 'Bool#compact'; + $ol->attr['start'] = new HTMLPurifier_AttrDef_Integer(); + $ol->attr['type'] = 'Enum#s:1,i,I,a,A'; + + $p = $this->addBlankElement('p'); + $p->attr['align'] = $align; + + $pre = $this->addBlankElement('pre'); + $pre->attr['width'] = 'Number'; + + // script omitted + + $table = $this->addBlankElement('table'); + $table->attr['align'] = 'Enum#left,center,right'; + $table->attr['bgcolor'] = 'Color'; + + $tr = $this->addBlankElement('tr'); + $tr->attr['bgcolor'] = 'Color'; + + $th = $this->addBlankElement('th'); + $th->attr['bgcolor'] = 'Color'; + $th->attr['height'] = 'Length'; + $th->attr['nowrap'] = 'Bool#nowrap'; + $th->attr['width'] = 'Length'; + + $td = $this->addBlankElement('td'); + $td->attr['bgcolor'] = 'Color'; + $td->attr['height'] = 'Length'; + $td->attr['nowrap'] = 'Bool#nowrap'; + $td->attr['width'] = 'Length'; + + $ul = $this->addBlankElement('ul'); + $ul->attr['compact'] = 'Bool#compact'; + $ul->attr['type'] = 'Enum#square,disc,circle'; + + // "safe" modifications to "unsafe" elements + // WARNING: If you want to add support for an unsafe, legacy + // attribute, make a new TrustedLegacy module with the trusted + // bit set appropriately + + $form = $this->addBlankElement('form'); + $form->content_model = 'Flow | #PCDATA'; + $form->content_model_type = 'optional'; + $form->attr['target'] = 'FrameTarget'; + + $input = $this->addBlankElement('input'); + $input->attr['align'] = 'IAlign'; + + $legend = $this->addBlankElement('legend'); + $legend->attr['align'] = 'LAlign'; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/List.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/List.php new file mode 100644 index 000000000..7a20ff701 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/List.php @@ -0,0 +1,51 @@ + 'List'); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $ol = $this->addElement('ol', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + $ul = $this->addElement('ul', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + // XXX The wrap attribute is handled by MakeWellFormed. This is all + // quite unsatisfactory, because we generated this + // *specifically* for lists, and now a big chunk of the handling + // is done properly by the List ChildDef. So actually, we just + // want enough information to make autoclosing work properly, + // and then hand off the tricky stuff to the ChildDef. + $ol->wrap = 'li'; + $ul->wrap = 'li'; + $this->addElement('dl', 'List', 'Required: dt | dd', 'Common'); + + $this->addElement('li', false, 'Flow', 'Common'); + + $this->addElement('dd', false, 'Flow', 'Common'); + $this->addElement('dt', false, 'Inline', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php new file mode 100644 index 000000000..60c054515 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Name.php @@ -0,0 +1,26 @@ +addBlankElement($name); + $element->attr['name'] = 'CDATA'; + if (!$config->get('HTML.Attr.Name.UseCDATA')) { + $element->attr_transform_post[] = new HTMLPurifier_AttrTransform_NameSync(); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Nofollow.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Nofollow.php new file mode 100644 index 000000000..dc9410a89 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Nofollow.php @@ -0,0 +1,25 @@ +addBlankElement('a'); + $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_Nofollow(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php new file mode 100644 index 000000000..da722253a --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php @@ -0,0 +1,20 @@ + array( + 'lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php new file mode 100644 index 000000000..2f9efc5c8 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Object.php @@ -0,0 +1,62 @@ + to cater to legacy browsers: this + * module does not allow this sort of behavior + */ +class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule +{ + /** + * @type string + */ + public $name = 'Object'; + + /** + * @type bool + */ + public $safe = false; + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $this->addElement( + 'object', + 'Inline', + 'Optional: #PCDATA | Flow | param', + 'Common', + array( + 'archive' => 'URI', + 'classid' => 'URI', + 'codebase' => 'URI', + 'codetype' => 'Text', + 'data' => 'URI', + 'declare' => 'Bool#declare', + 'height' => 'Length', + 'name' => 'CDATA', + 'standby' => 'Text', + 'tabindex' => 'Number', + 'type' => 'ContentType', + 'width' => 'Length' + ) + ); + + $this->addElement( + 'param', + false, + 'Empty', + null, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'type' => 'Text', + 'value' => 'Text', + 'valuetype' => 'Enum#data,ref,object' + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php new file mode 100644 index 000000000..6458ce9d8 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Presentation.php @@ -0,0 +1,42 @@ +addElement('hr', 'Block', 'Empty', 'Common'); + $this->addElement('sub', 'Inline', 'Inline', 'Common'); + $this->addElement('sup', 'Inline', 'Inline', 'Common'); + $b = $this->addElement('b', 'Inline', 'Inline', 'Common'); + $b->formatting = true; + $big = $this->addElement('big', 'Inline', 'Inline', 'Common'); + $big->formatting = true; + $i = $this->addElement('i', 'Inline', 'Inline', 'Common'); + $i->formatting = true; + $small = $this->addElement('small', 'Inline', 'Inline', 'Common'); + $small->formatting = true; + $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common'); + $tt->formatting = true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php new file mode 100644 index 000000000..5ee3c8e67 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Proprietary.php @@ -0,0 +1,40 @@ +addElement( + 'marquee', + 'Inline', + 'Flow', + 'Common', + array( + 'direction' => 'Enum#left,right,up,down', + 'behavior' => 'Enum#alternate', + 'width' => 'Length', + 'height' => 'Length', + 'scrolldelay' => 'Number', + 'scrollamount' => 'Number', + 'loop' => 'Number', + 'bgcolor' => 'Color', + 'hspace' => 'Pixels', + 'vspace' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php new file mode 100644 index 000000000..a0d48924d --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Ruby.php @@ -0,0 +1,36 @@ +addElement( + 'ruby', + 'Inline', + 'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))', + 'Common' + ); + $this->addElement('rbc', false, 'Required: rb', 'Common'); + $this->addElement('rtc', false, 'Required: rt', 'Common'); + $rb = $this->addElement('rb', false, 'Inline', 'Common'); + $rb->excludes = array('ruby' => true); + $rt = $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number')); + $rt->excludes = array('ruby' => true); + $this->addElement('rp', false, 'Optional: #PCDATA', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php new file mode 100644 index 000000000..04e6689ea --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeEmbed.php @@ -0,0 +1,40 @@ +get('HTML.MaxImgLength'); + $embed = $this->addElement( + 'embed', + 'Inline', + 'Empty', + 'Common', + array( + 'src*' => 'URI#embedded', + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'allowscriptaccess' => 'Enum#never', + 'allownetworking' => 'Enum#internal', + 'flashvars' => 'Text', + 'wmode' => 'Enum#window,transparent,opaque', + 'name' => 'ID', + ) + ); + $embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php new file mode 100644 index 000000000..1297f80a3 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeObject.php @@ -0,0 +1,62 @@ +get('HTML.MaxImgLength'); + $object = $this->addElement( + 'object', + 'Inline', + 'Optional: param | Flow | #PCDATA', + 'Common', + array( + // While technically not required by the spec, we're forcing + // it to this value. + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'data' => 'URI#embedded', + 'codebase' => new HTMLPurifier_AttrDef_Enum( + array( + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0' + ) + ), + ) + ); + $object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject(); + + $param = $this->addElement( + 'param', + false, + 'Empty', + false, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'value' => 'Text' + ) + ); + $param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam(); + $this->info_injector[] = 'SafeObject'; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeScripting.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeScripting.php new file mode 100644 index 000000000..0330cd97f --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/SafeScripting.php @@ -0,0 +1,40 @@ +get('HTML.SafeScripting'); + $script = $this->addElement( + 'script', + 'Inline', + 'Empty', + null, + array( + // While technically not required by the spec, we're forcing + // it to this value. + 'type' => 'Enum#text/javascript', + 'src*' => new HTMLPurifier_AttrDef_Enum(array_keys($allowed)) + ) + ); + $script->attr_transform_pre[] = + $script->attr_transform_post[] = new HTMLPurifier_AttrTransform_ScriptRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php new file mode 100644 index 000000000..8b28a7b7e --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Scripting.php @@ -0,0 +1,73 @@ + 'script | noscript', 'Inline' => 'script | noscript'); + + /** + * @type bool + */ + public $safe = false; + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + // TODO: create custom child-definition for noscript that + // auto-wraps stray #PCDATA in a similar manner to + // blockquote's custom definition (we would use it but + // blockquote's contents are optional while noscript's contents + // are required) + + // TODO: convert this to new syntax, main problem is getting + // both content sets working + + // In theory, this could be safe, but I don't see any reason to + // allow it. + $this->info['noscript'] = new HTMLPurifier_ElementDef(); + $this->info['noscript']->attr = array(0 => array('Common')); + $this->info['noscript']->content_model = 'Heading | List | Block'; + $this->info['noscript']->content_model_type = 'required'; + + $this->info['script'] = new HTMLPurifier_ElementDef(); + $this->info['script']->attr = array( + 'defer' => new HTMLPurifier_AttrDef_Enum(array('defer')), + 'src' => new HTMLPurifier_AttrDef_URI(true), + 'type' => new HTMLPurifier_AttrDef_Enum(array('text/javascript')) + ); + $this->info['script']->content_model = '#PCDATA'; + $this->info['script']->content_model_type = 'optional'; + $this->info['script']->attr_transform_pre[] = + $this->info['script']->attr_transform_post[] = + new HTMLPurifier_AttrTransform_ScriptRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php new file mode 100644 index 000000000..497b832ae --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/StyleAttribute.php @@ -0,0 +1,33 @@ + array('style' => false), // see constructor + 'Core' => array(0 => array('Style')) + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $this->attr_collections['Style']['style'] = new HTMLPurifier_AttrDef_CSS(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php new file mode 100644 index 000000000..8a0b3b461 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tables.php @@ -0,0 +1,75 @@ +addElement('caption', false, 'Inline', 'Common'); + + $this->addElement( + 'table', + 'Block', + new HTMLPurifier_ChildDef_Table(), + 'Common', + array( + 'border' => 'Pixels', + 'cellpadding' => 'Length', + 'cellspacing' => 'Length', + 'frame' => 'Enum#void,above,below,hsides,lhs,rhs,vsides,box,border', + 'rules' => 'Enum#none,groups,rows,cols,all', + 'summary' => 'Text', + 'width' => 'Length' + ) + ); + + // common attributes + $cell_align = array( + 'align' => 'Enum#left,center,right,justify,char', + 'charoff' => 'Length', + 'valign' => 'Enum#top,middle,bottom,baseline', + ); + + $cell_t = array_merge( + array( + 'abbr' => 'Text', + 'colspan' => 'Number', + 'rowspan' => 'Number', + // Apparently, as of HTML5 this attribute only applies + // to 'th' elements. + 'scope' => 'Enum#row,col,rowgroup,colgroup', + ), + $cell_align + ); + $this->addElement('td', false, 'Flow', 'Common', $cell_t); + $this->addElement('th', false, 'Flow', 'Common', $cell_t); + + $this->addElement('tr', false, 'Required: td | th', 'Common', $cell_align); + + $cell_col = array_merge( + array( + 'span' => 'Number', + 'width' => 'MultiLength', + ), + $cell_align + ); + $this->addElement('col', false, 'Empty', 'Common', $cell_col); + $this->addElement('colgroup', false, 'Optional: col', 'Common', $cell_col); + + $this->addElement('tbody', false, 'Required: tr', 'Common', $cell_align); + $this->addElement('thead', false, 'Required: tr', 'Common', $cell_align); + $this->addElement('tfoot', false, 'Required: tr', 'Common', $cell_align); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php new file mode 100644 index 000000000..b188ac936 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Target.php @@ -0,0 +1,28 @@ +addBlankElement($name); + $e->attr = array( + 'target' => new HTMLPurifier_AttrDef_HTML_FrameTarget() + ); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/TargetBlank.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/TargetBlank.php new file mode 100644 index 000000000..58ccc6894 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/TargetBlank.php @@ -0,0 +1,24 @@ +addBlankElement('a'); + $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_TargetBlank(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php new file mode 100644 index 000000000..7a65e0048 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Text.php @@ -0,0 +1,87 @@ + 'Heading | Block | Inline' + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + // Inline Phrasal ------------------------------------------------- + $this->addElement('abbr', 'Inline', 'Inline', 'Common'); + $this->addElement('acronym', 'Inline', 'Inline', 'Common'); + $this->addElement('cite', 'Inline', 'Inline', 'Common'); + $this->addElement('dfn', 'Inline', 'Inline', 'Common'); + $this->addElement('kbd', 'Inline', 'Inline', 'Common'); + $this->addElement('q', 'Inline', 'Inline', 'Common', array('cite' => 'URI')); + $this->addElement('samp', 'Inline', 'Inline', 'Common'); + $this->addElement('var', 'Inline', 'Inline', 'Common'); + + $em = $this->addElement('em', 'Inline', 'Inline', 'Common'); + $em->formatting = true; + + $strong = $this->addElement('strong', 'Inline', 'Inline', 'Common'); + $strong->formatting = true; + + $code = $this->addElement('code', 'Inline', 'Inline', 'Common'); + $code->formatting = true; + + // Inline Structural ---------------------------------------------- + $this->addElement('span', 'Inline', 'Inline', 'Common'); + $this->addElement('br', 'Inline', 'Empty', 'Core'); + + // Block Phrasal -------------------------------------------------- + $this->addElement('address', 'Block', 'Inline', 'Common'); + $this->addElement('blockquote', 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI')); + $pre = $this->addElement('pre', 'Block', 'Inline', 'Common'); + $pre->excludes = $this->makeLookup( + 'img', + 'big', + 'small', + 'object', + 'applet', + 'font', + 'basefont' + ); + $this->addElement('h1', 'Heading', 'Inline', 'Common'); + $this->addElement('h2', 'Heading', 'Inline', 'Common'); + $this->addElement('h3', 'Heading', 'Inline', 'Common'); + $this->addElement('h4', 'Heading', 'Inline', 'Common'); + $this->addElement('h5', 'Heading', 'Inline', 'Common'); + $this->addElement('h6', 'Heading', 'Inline', 'Common'); + + // Block Structural ----------------------------------------------- + $p = $this->addElement('p', 'Block', 'Inline', 'Common'); + $p->autoclose = array_flip( + array("address", "blockquote", "center", "dir", "div", "dl", "fieldset", "ol", "p", "ul") + ); + + $this->addElement('div', 'Block', 'Flow', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php new file mode 100644 index 000000000..08aa23247 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy.php @@ -0,0 +1,230 @@ + 'none', 'light', 'medium', 'heavy'); + + /** + * Default level to place all fixes in. + * Disabled by default. + * @type string + */ + public $defaultLevel = null; + + /** + * Lists of fixes used by getFixesForLevel(). + * Format is: + * HTMLModule_Tidy->fixesForLevel[$level] = array('fix-1', 'fix-2'); + * @type array + */ + public $fixesForLevel = array( + 'light' => array(), + 'medium' => array(), + 'heavy' => array() + ); + + /** + * Lazy load constructs the module by determining the necessary + * fixes to create and then delegating to the populate() function. + * @param HTMLPurifier_Config $config + * @todo Wildcard matching and error reporting when an added or + * subtracted fix has no effect. + */ + public function setup($config) + { + // create fixes, initialize fixesForLevel + $fixes = $this->makeFixes(); + $this->makeFixesForLevel($fixes); + + // figure out which fixes to use + $level = $config->get('HTML.TidyLevel'); + $fixes_lookup = $this->getFixesForLevel($level); + + // get custom fix declarations: these need namespace processing + $add_fixes = $config->get('HTML.TidyAdd'); + $remove_fixes = $config->get('HTML.TidyRemove'); + + foreach ($fixes as $name => $fix) { + // needs to be refactored a little to implement globbing + if (isset($remove_fixes[$name]) || + (!isset($add_fixes[$name]) && !isset($fixes_lookup[$name]))) { + unset($fixes[$name]); + } + } + + // populate this module with necessary fixes + $this->populate($fixes); + } + + /** + * Retrieves all fixes per a level, returning fixes for that specific + * level as well as all levels below it. + * @param string $level level identifier, see $levels for valid values + * @return array Lookup up table of fixes + */ + public function getFixesForLevel($level) + { + if ($level == $this->levels[0]) { + return array(); + } + $activated_levels = array(); + for ($i = 1, $c = count($this->levels); $i < $c; $i++) { + $activated_levels[] = $this->levels[$i]; + if ($this->levels[$i] == $level) { + break; + } + } + if ($i == $c) { + trigger_error( + 'Tidy level ' . htmlspecialchars($level) . ' not recognized', + E_USER_WARNING + ); + return array(); + } + $ret = array(); + foreach ($activated_levels as $level) { + foreach ($this->fixesForLevel[$level] as $fix) { + $ret[$fix] = true; + } + } + return $ret; + } + + /** + * Dynamically populates the $fixesForLevel member variable using + * the fixes array. It may be custom overloaded, used in conjunction + * with $defaultLevel, or not used at all. + * @param array $fixes + */ + public function makeFixesForLevel($fixes) + { + if (!isset($this->defaultLevel)) { + return; + } + if (!isset($this->fixesForLevel[$this->defaultLevel])) { + trigger_error( + 'Default level ' . $this->defaultLevel . ' does not exist', + E_USER_ERROR + ); + return; + } + $this->fixesForLevel[$this->defaultLevel] = array_keys($fixes); + } + + /** + * Populates the module with transforms and other special-case code + * based on a list of fixes passed to it + * @param array $fixes Lookup table of fixes to activate + */ + public function populate($fixes) + { + foreach ($fixes as $name => $fix) { + // determine what the fix is for + list($type, $params) = $this->getFixType($name); + switch ($type) { + case 'attr_transform_pre': + case 'attr_transform_post': + $attr = $params['attr']; + if (isset($params['element'])) { + $element = $params['element']; + if (empty($this->info[$element])) { + $e = $this->addBlankElement($element); + } else { + $e = $this->info[$element]; + } + } else { + $type = "info_$type"; + $e = $this; + } + // PHP does some weird parsing when I do + // $e->$type[$attr], so I have to assign a ref. + $f =& $e->$type; + $f[$attr] = $fix; + break; + case 'tag_transform': + $this->info_tag_transform[$params['element']] = $fix; + break; + case 'child': + case 'content_model_type': + $element = $params['element']; + if (empty($this->info[$element])) { + $e = $this->addBlankElement($element); + } else { + $e = $this->info[$element]; + } + $e->$type = $fix; + break; + default: + trigger_error("Fix type $type not supported", E_USER_ERROR); + break; + } + } + } + + /** + * Parses a fix name and determines what kind of fix it is, as well + * as other information defined by the fix + * @param $name String name of fix + * @return array(string $fix_type, array $fix_parameters) + * @note $fix_parameters is type dependant, see populate() for usage + * of these parameters + */ + public function getFixType($name) + { + // parse it + $property = $attr = null; + if (strpos($name, '#') !== false) { + list($name, $property) = explode('#', $name); + } + if (strpos($name, '@') !== false) { + list($name, $attr) = explode('@', $name); + } + + // figure out the parameters + $params = array(); + if ($name !== '') { + $params['element'] = $name; + } + if (!is_null($attr)) { + $params['attr'] = $attr; + } + + // special case: attribute transform + if (!is_null($attr)) { + if (is_null($property)) { + $property = 'pre'; + } + $type = 'attr_transform_' . $property; + return array($type, $params); + } + + // special case: tag transform + if (is_null($property)) { + return array('tag_transform', $params); + } + + return array($property, $params); + + } + + /** + * Defines all fixes the module will perform in a compact + * associative array of fix name to fix implementation. + * @return array + */ + public function makeFixes() + { + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php new file mode 100644 index 000000000..a995161b2 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Name.php @@ -0,0 +1,33 @@ +content_model_type != 'strictblockquote') { + return parent::getChildDef($def); + } + return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php new file mode 100644 index 000000000..c095ad974 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/Tidy/Transitional.php @@ -0,0 +1,16 @@ + 'text-align:left;', + 'right' => 'text-align:right;', + 'top' => 'caption-side:top;', + 'bottom' => 'caption-side:bottom;' // not supported by IE + ) + ); + + // @align for img ------------------------------------------------- + $r['img@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS( + 'align', + array( + 'left' => 'float:left;', + 'right' => 'float:right;', + 'top' => 'vertical-align:top;', + 'middle' => 'vertical-align:middle;', + 'bottom' => 'vertical-align:baseline;', + ) + ); + + // @align for table ----------------------------------------------- + $r['table@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS( + 'align', + array( + 'left' => 'float:left;', + 'center' => 'margin-left:auto;margin-right:auto;', + 'right' => 'float:right;' + ) + ); + + // @align for hr ----------------------------------------------- + $r['hr@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS( + 'align', + array( + // we use both text-align and margin because these work + // for different browsers (IE and Firefox, respectively) + // and the melange makes for a pretty cross-compatible + // solution + 'left' => 'margin-left:0;margin-right:auto;text-align:left;', + 'center' => 'margin-left:auto;margin-right:auto;text-align:center;', + 'right' => 'margin-left:auto;margin-right:0;text-align:right;' + ) + ); + + // @align for h1, h2, h3, h4, h5, h6, p, div ---------------------- + // {{{ + $align_lookup = array(); + $align_values = array('left', 'right', 'center', 'justify'); + foreach ($align_values as $v) { + $align_lookup[$v] = "text-align:$v;"; + } + // }}} + $r['h1@align'] = + $r['h2@align'] = + $r['h3@align'] = + $r['h4@align'] = + $r['h5@align'] = + $r['h6@align'] = + $r['p@align'] = + $r['div@align'] = + new HTMLPurifier_AttrTransform_EnumToCSS('align', $align_lookup); + + // @bgcolor for table, tr, td, th --------------------------------- + $r['table@bgcolor'] = + $r['td@bgcolor'] = + $r['th@bgcolor'] = + new HTMLPurifier_AttrTransform_BgColor(); + + // @border for img ------------------------------------------------ + $r['img@border'] = new HTMLPurifier_AttrTransform_Border(); + + // @clear for br -------------------------------------------------- + $r['br@clear'] = + new HTMLPurifier_AttrTransform_EnumToCSS( + 'clear', + array( + 'left' => 'clear:left;', + 'right' => 'clear:right;', + 'all' => 'clear:both;', + 'none' => 'clear:none;', + ) + ); + + // @height for td, th --------------------------------------------- + $r['td@height'] = + $r['th@height'] = + new HTMLPurifier_AttrTransform_Length('height'); + + // @hspace for img ------------------------------------------------ + $r['img@hspace'] = new HTMLPurifier_AttrTransform_ImgSpace('hspace'); + + // @noshade for hr ------------------------------------------------ + // this transformation is not precise but often good enough. + // different browsers use different styles to designate noshade + $r['hr@noshade'] = + new HTMLPurifier_AttrTransform_BoolToCSS( + 'noshade', + 'color:#808080;background-color:#808080;border:0;' + ); + + // @nowrap for td, th --------------------------------------------- + $r['td@nowrap'] = + $r['th@nowrap'] = + new HTMLPurifier_AttrTransform_BoolToCSS( + 'nowrap', + 'white-space:nowrap;' + ); + + // @size for hr -------------------------------------------------- + $r['hr@size'] = new HTMLPurifier_AttrTransform_Length('size', 'height'); + + // @type for li, ol, ul ------------------------------------------- + // {{{ + $ul_types = array( + 'disc' => 'list-style-type:disc;', + 'square' => 'list-style-type:square;', + 'circle' => 'list-style-type:circle;' + ); + $ol_types = array( + '1' => 'list-style-type:decimal;', + 'i' => 'list-style-type:lower-roman;', + 'I' => 'list-style-type:upper-roman;', + 'a' => 'list-style-type:lower-alpha;', + 'A' => 'list-style-type:upper-alpha;' + ); + $li_types = $ul_types + $ol_types; + // }}} + + $r['ul@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ul_types); + $r['ol@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ol_types, true); + $r['li@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $li_types, true); + + // @vspace for img ------------------------------------------------ + $r['img@vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace'); + + // @width for hr, td, th ------------------------------------------ + $r['td@width'] = + $r['th@width'] = + $r['hr@width'] = new HTMLPurifier_AttrTransform_Length('width'); + + return $r; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php new file mode 100644 index 000000000..01dbe9deb --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModule/XMLCommonAttributes.php @@ -0,0 +1,20 @@ + array( + 'xml:lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php new file mode 100644 index 000000000..f3a17cb03 --- /dev/null +++ b/library/vendor/HTMLPurifier/HTMLPurifier/HTMLModuleManager.php @@ -0,0 +1,459 @@ +attrTypes = new HTMLPurifier_AttrTypes(); + $this->doctypes = new HTMLPurifier_DoctypeRegistry(); + + // setup basic modules + $common = array( + 'CommonAttributes', 'Text', 'Hypertext', 'List', + 'Presentation', 'Edit', 'Bdo', 'Tables', 'Image', + 'StyleAttribute', + // Unsafe: + 'Scripting', 'Object', 'Forms', + // Sorta legacy, but present in strict: + 'Name', + ); + $transitional = array('Legacy', 'Target', 'Iframe'); + $xml = array('XMLCommonAttributes'); + $non_xml = array('NonXMLCommonAttributes'); + + // setup basic doctypes + $this->doctypes->register( + 'HTML 4.01 Transitional', + false, + array_merge($common, $transitional, $non_xml), + array('Tidy_Transitional', 'Tidy_Proprietary'), + array(), + '-//W3C//DTD HTML 4.01 Transitional//EN', + 'http://www.w3.org/TR/html4/loose.dtd' + ); + + $this->doctypes->register( + 'HTML 4.01 Strict', + false, + array_merge($common, $non_xml), + array('Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'), + array(), + '-//W3C//DTD HTML 4.01//EN', + 'http://www.w3.org/TR/html4/strict.dtd' + ); + + $this->doctypes->register( + 'XHTML 1.0 Transitional', + true, + array_merge($common, $transitional, $xml, $non_xml), + array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Name'), + array(), + '-//W3C//DTD XHTML 1.0 Transitional//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd' + ); + + $this->doctypes->register( + 'XHTML 1.0 Strict', + true, + array_merge($common, $xml, $non_xml), + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'), + array(), + '-//W3C//DTD XHTML 1.0 Strict//EN', + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd' + ); + + $this->doctypes->register( + 'XHTML 1.1', + true, + // Iframe is a real XHTML 1.1 module, despite being + // "transitional"! + array_merge($common, $xml, array('Ruby', 'Iframe')), + array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Strict', 'Tidy_Name'), // Tidy_XHTML1_1 + array(), + '-//W3C//DTD XHTML 1.1//EN', + 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' + ); + + } + + /** + * Registers a module to the recognized module list, useful for + * overloading pre-existing modules. + * @param $module Mixed: string module name, with or without + * HTMLPurifier_HTMLModule prefix, or instance of + * subclass of HTMLPurifier_HTMLModule. + * @param $overload Boolean whether or not to overload previous modules. + * If this is not set, and you do overload a module, + * HTML Purifier will complain with a warning. + * @note This function will not call autoload, you must instantiate + * (and thus invoke) autoload outside the method. + * @note If a string is passed as a module name, different variants + * will be tested in this order: + * - Check for HTMLPurifier_HTMLModule_$name + * - Check all prefixes with $name in order they were added + * - Check for literal object name + * - Throw fatal error + * If your object name collides with an internal class, specify + * your module manually. All modules must have been included + * externally: registerModule will not perform inclusions for you! + */ + public function registerModule($module, $overload = false) + { + if (is_string($module)) { + // attempt to load the module + $original_module = $module; + $ok = false; + foreach ($this->prefixes as $prefix) { + $module = $prefix . $original_module; + if (class_exists($module)) { + $ok = true; + break; + } + } + if (!$ok) { + $module = $original_module; + if (!class_exists($module)) { + trigger_error( + $original_module . ' module does not exist', + E_USER_ERROR + ); + return; + } + } + $module = new $module(); + } + if (empty($module->name)) { + trigger_error('Module instance of ' . get_class($module) . ' must have name'); + return; + } + if (!$overload && isset($this->registeredModules[$module->name])) { + trigger_error('Overloading ' . $module->name . ' without explicit overload parameter', E_USER_WARNING); + } + $this->registeredModules[$module->name] = $module; + } + + /** + * Adds a module to the current doctype by first registering it, + * and then tacking it on to the active doctype + */ + public function addModule($module) + { + $this->registerModule($module); + if (is_object($module)) { + $module = $module->name; + } + $this->userModules[] = $module; + } + + /** + * Adds a class prefix that registerModule() will use to resolve a + * string name to a concrete class + */ + public function addPrefix($prefix) + { + $this->prefixes[] = $prefix; + } + + /** + * Performs processing on modules, after being called you may + * use getElement() and getElements() + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $this->trusted = $config->get('HTML.Trusted'); + + // generate + $this->doctype = $this->doctypes->make($config); + $modules = $this->doctype->modules; + + // take out the default modules that aren't allowed + $lookup = $config->get('HTML.AllowedModules'); + $special_cases = $config->get('HTML.CoreModules'); + + if (is_array($lookup)) { + foreach ($modules as $k => $m) { + if (isset($special_cases[$m])) { + continue; + } + if (!isset($lookup[$m])) { + unset($modules[$k]); + } + } + } + + // custom modules + if ($config->get('HTML.Proprietary')) { + $modules[] = 'Proprietary'; + } + if ($config->get('HTML.SafeObject')) { + $modules[] = 'SafeObject'; + } + if ($config->get('HTML.SafeEmbed')) { + $modules[] = 'SafeEmbed'; + } + if ($config->get('HTML.SafeScripting') !== array()) { + $modules[] = 'SafeScripting'; + } + if ($config->get('HTML.Nofollow')) { + $modules[] = 'Nofollow'; + } + if ($config->get('HTML.TargetBlank')) { + $modules[] = 'TargetBlank'; + } + + // merge in custom modules + $modules = array_merge($modules, $this->userModules); + + foreach ($modules as $module) { + $this->processModule($module); + $this->modules[$module]->setup($config); + } + + foreach ($this->doctype->tidyModules as $module) { + $this->processModule($module); + $this->modules[$module]->setup($config); + } + + // prepare any injectors + foreach ($this->modules as $module) { + $n = array(); + foreach ($module->info_injector as $injector) { + if (!is_object($injector)) { + $class = "HTMLPurifier_Injector_$injector"; + $injector = new $class; + } + $n[$injector->name] = $injector; + } + $module->info_injector = $n; + } + + // setup lookup table based on all valid modules + foreach ($this->modules as $module) { + foreach ($module->info as $name => $def) { + if (!isset($this->elementLookup[$name])) { + $this->elementLookup[$name] = array(); + } + $this->elementLookup[$name][] = $module->name; + } + } + + // note the different choice + $this->contentSets = new HTMLPurifier_ContentSets( + // content set assembly deals with all possible modules, + // not just ones deemed to be "safe" + $this->modules + ); + $this->attrCollections = new HTMLPurifier_AttrCollections( + $this->attrTypes, + // there is no way to directly disable a global attribute, + // but using AllowedAttributes or simply not including + // the module in your custom doctype should be sufficient + $this->modules + ); + } + + /** + * Takes a module and adds it to the active module collection, + * registering it if necessary. + */ + public function processModule($module) + { + if (!isset($this->registeredModules[$module]) || is_object($module)) { + $this->registerModule($module); + } + $this->modules[$module] = $this->registeredModules[$module]; + } + + /** + * Retrieves merged element definitions. + * @return Array of HTMLPurifier_ElementDef + */ + public function getElements() + { + $elements = array(); + foreach ($this->modules as $module) { + if (!$this->trusted && !$module->safe) { + continue; + } + foreach ($module->info as $name => $v) { + if (isset($elements[$name])) { + continue; + } + $elements[$name] = $this->getElement($name); + } + } + + // remove dud elements, this happens when an element that + // appeared to be safe actually wasn't + foreach ($elements as $n => $v) { + if ($v === false) { + unset($elements[$n]); + } + } + + return $elements; + + } + + /** + * Retrieves a single merged element definition + * @param string $name Name of element + * @param bool $trusted Boolean trusted overriding parameter: set to true + * if you want the full version of an element + * @return HTMLPurifier_ElementDef Merged HTMLPurifier_ElementDef + * @note You may notice that modules are getting iterated over twice (once + * in getElements() and once here). This + * is because + */ + public function getElement($name, $trusted = null) + { + if (!isset($this->elementLookup[$name])) { + return false; + } + + // setup global state variables + $def = false; + if ($trusted === null) { + $trusted = $this->trusted; + } + + // iterate through each module that has registered itself to this + // element + foreach ($this->elementLookup[$name] as $module_name) { + $module = $this->modules[$module_name]; + + // refuse to create/merge from a module that is deemed unsafe-- + // pretend the module doesn't exist--when trusted mode is not on. + if (!$trusted && !$module->safe) { + continue; + } + + // clone is used because, ideally speaking, the original + // definition should not be modified. Usually, this will + // make no difference, but for consistency's sake + $new_def = clone $module->info[$name]; + + if (!$def && $new_def->standalone) { + $def = $new_def; + } elseif ($def) { + // This will occur even if $new_def is standalone. In practice, + // this will usually result in a full replacement. + $def->mergeIn($new_def); + } else { + // :TODO: + // non-standalone definitions that don't have a standalone + // to merge into could be deferred to the end + // HOWEVER, it is perfectly valid for a non-standalone + // definition to lack a standalone definition, even + // after all processing: this allows us to safely + // specify extra attributes for elements that may not be + // enabled all in one place. In particular, this might + // be the case for trusted elements. WARNING: care must + // be taken that the /extra/ definitions are all safe. + continue; + } + + // attribute value expansions + $this->attrCollections->performInclusions($def->attr); + $this->attrCollections->expandIdentifiers($def->attr, $this->attrTypes); + + // descendants_are_inline, for ChildDef_Chameleon + if (is_string($def->content_model) && + strpos($def->content_model, 'Inline') !== false) { + if ($name != 'del' && $name != 'ins') { + // this is for you, ins/del + $def->descendants_are_inline = true; + } + } + + $this->contentSets->generateChildDef($def, $module); + } + + // This can occur if there is a blank definition, but no base to + // mix it in with + if (!$def) { + return false; + } + + // add information on required attributes + foreach ($def->attr as $attr_name => $attr_def) { + if ($attr_def->required) { + $def->required_attr[] = $attr_name; + } + } + return $def; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/IDAccumulator.php b/library/vendor/HTMLPurifier/HTMLPurifier/IDAccumulator.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/IDAccumulator.php rename to library/vendor/HTMLPurifier/HTMLPurifier/IDAccumulator.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/AutoParagraph.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/AutoParagraph.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/AutoParagraph.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/AutoParagraph.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/DisplayLinkURI.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/DisplayLinkURI.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/DisplayLinkURI.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/DisplayLinkURI.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/Linkify.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/Linkify.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/Linkify.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/Linkify.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/PurifierLinkify.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/PurifierLinkify.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/PurifierLinkify.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/PurifierLinkify.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/RemoveEmpty.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/RemoveEmpty.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/RemoveEmpty.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/SafeObject.php b/library/vendor/HTMLPurifier/HTMLPurifier/Injector/SafeObject.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Injector/SafeObject.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Injector/SafeObject.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language.php b/library/vendor/HTMLPurifier/HTMLPurifier/Language.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Language.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/classes/en-x-test.php b/library/vendor/HTMLPurifier/HTMLPurifier/Language/classes/en-x-test.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/classes/en-x-test.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Language/classes/en-x-test.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/messages/en-x-test.php b/library/vendor/HTMLPurifier/HTMLPurifier/Language/messages/en-x-test.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/messages/en-x-test.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Language/messages/en-x-test.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/messages/en-x-testmini.php b/library/vendor/HTMLPurifier/HTMLPurifier/Language/messages/en-x-testmini.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/messages/en-x-testmini.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Language/messages/en-x-testmini.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/messages/en.php b/library/vendor/HTMLPurifier/HTMLPurifier/Language/messages/en.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Language/messages/en.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Language/messages/en.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/LanguageFactory.php b/library/vendor/HTMLPurifier/HTMLPurifier/LanguageFactory.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/LanguageFactory.php rename to library/vendor/HTMLPurifier/HTMLPurifier/LanguageFactory.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Length.php b/library/vendor/HTMLPurifier/HTMLPurifier/Length.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Length.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Length.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer.php b/library/vendor/HTMLPurifier/HTMLPurifier/Lexer.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Lexer.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer/DOMLex.php b/library/vendor/HTMLPurifier/HTMLPurifier/Lexer/DOMLex.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer/DOMLex.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Lexer/DOMLex.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer/DirectLex.php b/library/vendor/HTMLPurifier/HTMLPurifier/Lexer/DirectLex.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer/DirectLex.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Lexer/DirectLex.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer/PH5P.php b/library/vendor/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Lexer/PH5P.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Lexer/PH5P.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node.php b/library/vendor/HTMLPurifier/HTMLPurifier/Node.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Node.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node/Comment.php b/library/vendor/HTMLPurifier/HTMLPurifier/Node/Comment.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node/Comment.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Node/Comment.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node/Element.php b/library/vendor/HTMLPurifier/HTMLPurifier/Node/Element.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node/Element.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Node/Element.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node/Text.php b/library/vendor/HTMLPurifier/HTMLPurifier/Node/Text.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Node/Text.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Node/Text.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/PercentEncoder.php b/library/vendor/HTMLPurifier/HTMLPurifier/PercentEncoder.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/PercentEncoder.php rename to library/vendor/HTMLPurifier/HTMLPurifier/PercentEncoder.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer.php b/library/vendor/HTMLPurifier/HTMLPurifier/Printer.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Printer.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/CSSDefinition.php b/library/vendor/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/CSSDefinition.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Printer/CSSDefinition.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/ConfigForm.php b/library/vendor/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/ConfigForm.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Printer/ConfigForm.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/HTMLDefinition.php b/library/vendor/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/HTMLDefinition.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Printer/HTMLDefinition.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/PropertyList.php b/library/vendor/HTMLPurifier/HTMLPurifier/PropertyList.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/PropertyList.php rename to library/vendor/HTMLPurifier/HTMLPurifier/PropertyList.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/PropertyListIterator.php b/library/vendor/HTMLPurifier/HTMLPurifier/PropertyListIterator.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/PropertyListIterator.php rename to library/vendor/HTMLPurifier/HTMLPurifier/PropertyListIterator.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Queue.php b/library/vendor/HTMLPurifier/HTMLPurifier/Queue.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Queue.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Queue.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/Composite.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy/Composite.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/Composite.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy/Composite.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/Core.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy/Core.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/Core.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy/Core.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/FixNesting.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/FixNesting.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy/FixNesting.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/MakeWellFormed.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/MakeWellFormed.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy/MakeWellFormed.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/RemoveForeignElements.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/RemoveForeignElements.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy/RemoveForeignElements.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/ValidateAttributes.php b/library/vendor/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Strategy/ValidateAttributes.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Strategy/ValidateAttributes.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/StringHash.php b/library/vendor/HTMLPurifier/HTMLPurifier/StringHash.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/StringHash.php rename to library/vendor/HTMLPurifier/HTMLPurifier/StringHash.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/StringHashParser.php b/library/vendor/HTMLPurifier/HTMLPurifier/StringHashParser.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/StringHashParser.php rename to library/vendor/HTMLPurifier/HTMLPurifier/StringHashParser.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TagTransform.php b/library/vendor/HTMLPurifier/HTMLPurifier/TagTransform.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TagTransform.php rename to library/vendor/HTMLPurifier/HTMLPurifier/TagTransform.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TagTransform/Font.php b/library/vendor/HTMLPurifier/HTMLPurifier/TagTransform/Font.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TagTransform/Font.php rename to library/vendor/HTMLPurifier/HTMLPurifier/TagTransform/Font.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TagTransform/Simple.php b/library/vendor/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TagTransform/Simple.php rename to library/vendor/HTMLPurifier/HTMLPurifier/TagTransform/Simple.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Comment.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token/Comment.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Comment.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token/Comment.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Empty.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token/Empty.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Empty.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token/Empty.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/End.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token/End.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/End.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token/End.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Start.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token/Start.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Start.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token/Start.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Tag.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token/Tag.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Tag.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token/Tag.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Text.php b/library/vendor/HTMLPurifier/HTMLPurifier/Token/Text.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Token/Text.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Token/Text.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TokenFactory.php b/library/vendor/HTMLPurifier/HTMLPurifier/TokenFactory.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/TokenFactory.php rename to library/vendor/HTMLPurifier/HTMLPurifier/TokenFactory.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URI.php b/library/vendor/HTMLPurifier/HTMLPurifier/URI.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URI.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URI.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIDefinition.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIDefinition.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIDefinition.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIDefinition.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/DisableExternal.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternal.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/DisableExternal.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternal.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/DisableExternalResources.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/DisableExternalResources.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/DisableExternalResources.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/DisableResources.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/DisableResources.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/DisableResources.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/DisableResources.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/HostBlacklist.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/HostBlacklist.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/HostBlacklist.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/MakeAbsolute.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/MakeAbsolute.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/MakeAbsolute.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/Munge.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/Munge.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/Munge.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/SafeIframe.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/SafeIframe.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIFilter/SafeIframe.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIFilter/SafeIframe.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIParser.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIParser.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIParser.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIParser.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/data.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/data.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/data.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/data.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/file.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/file.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/file.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/file.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/ftp.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/ftp.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/ftp.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/http.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/http.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/http.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/http.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/https.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/https.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/https.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/https.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/mailto.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/mailto.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/mailto.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/mailto.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/news.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/news.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/news.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/news.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/nntp.php b/library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URIScheme/nntp.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URIScheme/nntp.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URISchemeRegistry.php b/library/vendor/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/URISchemeRegistry.php rename to library/vendor/HTMLPurifier/HTMLPurifier/URISchemeRegistry.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/UnitConverter.php b/library/vendor/HTMLPurifier/HTMLPurifier/UnitConverter.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/UnitConverter.php rename to library/vendor/HTMLPurifier/HTMLPurifier/UnitConverter.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParser.php b/library/vendor/HTMLPurifier/HTMLPurifier/VarParser.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParser.php rename to library/vendor/HTMLPurifier/HTMLPurifier/VarParser.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParser/Flexible.php b/library/vendor/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParser/Flexible.php rename to library/vendor/HTMLPurifier/HTMLPurifier/VarParser/Flexible.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParser/Native.php b/library/vendor/HTMLPurifier/HTMLPurifier/VarParser/Native.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParser/Native.php rename to library/vendor/HTMLPurifier/HTMLPurifier/VarParser/Native.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParserException.php b/library/vendor/HTMLPurifier/HTMLPurifier/VarParserException.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/VarParserException.php rename to library/vendor/HTMLPurifier/HTMLPurifier/VarParserException.php diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Zipper.php b/library/vendor/HTMLPurifier/HTMLPurifier/Zipper.php similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Zipper.php rename to library/vendor/HTMLPurifier/HTMLPurifier/Zipper.php diff --git a/library/vendor/HTMLPurifier/IDAccumulator.php b/library/vendor/HTMLPurifier/IDAccumulator.php new file mode 100644 index 000000000..65c902c07 --- /dev/null +++ b/library/vendor/HTMLPurifier/IDAccumulator.php @@ -0,0 +1,57 @@ +load($config->get('Attr.IDBlacklist')); + return $id_accumulator; + } + + /** + * Add an ID to the lookup table. + * @param string $id ID to be added. + * @return bool status, true if success, false if there's a dupe + */ + public function add($id) + { + if (isset($this->ids[$id])) { + return false; + } + return $this->ids[$id] = true; + } + + /** + * Load a list of IDs into the lookup table + * @param $array_of_ids Array of IDs to load + * @note This function doesn't care about duplicates + */ + public function load($array_of_ids) + { + foreach ($array_of_ids as $id) { + $this->ids[$id] = true; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector.php b/library/vendor/HTMLPurifier/Injector.php new file mode 100644 index 000000000..5060eef9e --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector.php @@ -0,0 +1,281 @@ +processToken() + * documentation. + * + * @todo Allow injectors to request a re-run on their output. This + * would help if an operation is recursive. + */ +abstract class HTMLPurifier_Injector +{ + + /** + * Advisory name of injector, this is for friendly error messages. + * @type string + */ + public $name; + + /** + * @type HTMLPurifier_HTMLDefinition + */ + protected $htmlDefinition; + + /** + * Reference to CurrentNesting variable in Context. This is an array + * list of tokens that we are currently "inside" + * @type array + */ + protected $currentNesting; + + /** + * Reference to current token. + * @type HTMLPurifier_Token + */ + protected $currentToken; + + /** + * Reference to InputZipper variable in Context. + * @type HTMLPurifier_Zipper + */ + protected $inputZipper; + + /** + * Array of elements and attributes this injector creates and therefore + * need to be allowed by the definition. Takes form of + * array('element' => array('attr', 'attr2'), 'element2') + * @type array + */ + public $needed = array(); + + /** + * Number of elements to rewind backwards (relative). + * @type bool|int + */ + protected $rewindOffset = false; + + /** + * Rewind to a spot to re-perform processing. This is useful if you + * deleted a node, and now need to see if this change affected any + * earlier nodes. Rewinding does not affect other injectors, and can + * result in infinite loops if not used carefully. + * @param bool|int $offset + * @warning HTML Purifier will prevent you from fast-forwarding with this + * function. + */ + public function rewindOffset($offset) + { + $this->rewindOffset = $offset; + } + + /** + * Retrieves rewind offset, and then unsets it. + * @return bool|int + */ + public function getRewindOffset() + { + $r = $this->rewindOffset; + $this->rewindOffset = false; + return $r; + } + + /** + * Prepares the injector by giving it the config and context objects: + * this allows references to important variables to be made within + * the injector. This function also checks if the HTML environment + * will work with the Injector (see checkNeeded()). + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string Boolean false if success, string of missing needed element/attribute if failure + */ + public function prepare($config, $context) + { + $this->htmlDefinition = $config->getHTMLDefinition(); + // Even though this might fail, some unit tests ignore this and + // still test checkNeeded, so be careful. Maybe get rid of that + // dependency. + $result = $this->checkNeeded($config); + if ($result !== false) { + return $result; + } + $this->currentNesting =& $context->get('CurrentNesting'); + $this->currentToken =& $context->get('CurrentToken'); + $this->inputZipper =& $context->get('InputZipper'); + return false; + } + + /** + * This function checks if the HTML environment + * will work with the Injector: if p tags are not allowed, the + * Auto-Paragraphing injector should not be enabled. + * @param HTMLPurifier_Config $config + * @return bool|string Boolean false if success, string of missing needed element/attribute if failure + */ + public function checkNeeded($config) + { + $def = $config->getHTMLDefinition(); + foreach ($this->needed as $element => $attributes) { + if (is_int($element)) { + $element = $attributes; + } + if (!isset($def->info[$element])) { + return $element; + } + if (!is_array($attributes)) { + continue; + } + foreach ($attributes as $name) { + if (!isset($def->info[$element]->attr[$name])) { + return "$element.$name"; + } + } + } + return false; + } + + /** + * Tests if the context node allows a certain element + * @param string $name Name of element to test for + * @return bool True if element is allowed, false if it is not + */ + public function allowsElement($name) + { + if (!empty($this->currentNesting)) { + $parent_token = array_pop($this->currentNesting); + $this->currentNesting[] = $parent_token; + $parent = $this->htmlDefinition->info[$parent_token->name]; + } else { + $parent = $this->htmlDefinition->info_parent_def; + } + if (!isset($parent->child->elements[$name]) || isset($parent->excludes[$name])) { + return false; + } + // check for exclusion + for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) { + $node = $this->currentNesting[$i]; + $def = $this->htmlDefinition->info[$node->name]; + if (isset($def->excludes[$name])) { + return false; + } + } + return true; + } + + /** + * Iterator function, which starts with the next token and continues until + * you reach the end of the input tokens. + * @warning Please prevent previous references from interfering with this + * functions by setting $i = null beforehand! + * @param int $i Current integer index variable for inputTokens + * @param HTMLPurifier_Token $current Current token variable. + * Do NOT use $token, as that variable is also a reference + * @return bool + */ + protected function forward(&$i, &$current) + { + if ($i === null) { + $i = count($this->inputZipper->back) - 1; + } else { + $i--; + } + if ($i < 0) { + return false; + } + $current = $this->inputZipper->back[$i]; + return true; + } + + /** + * Similar to _forward, but accepts a third parameter $nesting (which + * should be initialized at 0) and stops when we hit the end tag + * for the node $this->inputIndex starts in. + * @param int $i Current integer index variable for inputTokens + * @param HTMLPurifier_Token $current Current token variable. + * Do NOT use $token, as that variable is also a reference + * @param int $nesting + * @return bool + */ + protected function forwardUntilEndToken(&$i, &$current, &$nesting) + { + $result = $this->forward($i, $current); + if (!$result) { + return false; + } + if ($nesting === null) { + $nesting = 0; + } + if ($current instanceof HTMLPurifier_Token_Start) { + $nesting++; + } elseif ($current instanceof HTMLPurifier_Token_End) { + if ($nesting <= 0) { + return false; + } + $nesting--; + } + return true; + } + + /** + * Iterator function, starts with the previous token and continues until + * you reach the beginning of input tokens. + * @warning Please prevent previous references from interfering with this + * functions by setting $i = null beforehand! + * @param int $i Current integer index variable for inputTokens + * @param HTMLPurifier_Token $current Current token variable. + * Do NOT use $token, as that variable is also a reference + * @return bool + */ + protected function backward(&$i, &$current) + { + if ($i === null) { + $i = count($this->inputZipper->front) - 1; + } else { + $i--; + } + if ($i < 0) { + return false; + } + $current = $this->inputZipper->front[$i]; + return true; + } + + /** + * Handler that is called when a text token is processed + */ + public function handleText(&$token) + { + } + + /** + * Handler that is called when a start or empty token is processed + */ + public function handleElement(&$token) + { + } + + /** + * Handler that is called when an end token is processed + */ + public function handleEnd(&$token) + { + $this->notifyEnd($token); + } + + /** + * Notifier that is called when an end token is processed + * @param HTMLPurifier_Token $token Current token variable. + * @note This differs from handlers in that the token is read-only + * @deprecated + */ + public function notifyEnd($token) + { + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/AutoParagraph.php b/library/vendor/HTMLPurifier/Injector/AutoParagraph.php new file mode 100644 index 000000000..4afdd128d --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/AutoParagraph.php @@ -0,0 +1,356 @@ +armor['MakeWellFormed_TagClosedError'] = true; + return $par; + } + + /** + * @param HTMLPurifier_Token_Text $token + */ + public function handleText(&$token) + { + $text = $token->data; + // Does the current parent allow

        tags? + if ($this->allowsElement('p')) { + if (empty($this->currentNesting) || strpos($text, "\n\n") !== false) { + // Note that we have differing behavior when dealing with text + // in the anonymous root node, or a node inside the document. + // If the text as a double-newline, the treatment is the same; + // if it doesn't, see the next if-block if you're in the document. + + $i = $nesting = null; + if (!$this->forwardUntilEndToken($i, $current, $nesting) && $token->is_whitespace) { + // State 1.1: ... ^ (whitespace, then document end) + // ---- + // This is a degenerate case + } else { + if (!$token->is_whitespace || $this->_isInline($current)) { + // State 1.2: PAR1 + // ---- + + // State 1.3: PAR1\n\nPAR2 + // ------------ + + // State 1.4:

        PAR1\n\nPAR2 (see State 2) + // ------------ + $token = array($this->_pStart()); + $this->_splitText($text, $token); + } else { + // State 1.5: \n
        + // -- + } + } + } else { + // State 2:
        PAR1... (similar to 1.4) + // ---- + + // We're in an element that allows paragraph tags, but we're not + // sure if we're going to need them. + if ($this->_pLookAhead()) { + // State 2.1:
        PAR1PAR1\n\nPAR2 + // ---- + // Note: This will always be the first child, since any + // previous inline element would have triggered this very + // same routine, and found the double newline. One possible + // exception would be a comment. + $token = array($this->_pStart(), $token); + } else { + // State 2.2.1:
        PAR1
        + // ---- + + // State 2.2.2:
        PAR1PAR1
        + // ---- + } + } + // Is the current parent a

        tag? + } elseif (!empty($this->currentNesting) && + $this->currentNesting[count($this->currentNesting) - 1]->name == 'p') { + // State 3.1: ...

        PAR1 + // ---- + + // State 3.2: ...

        PAR1\n\nPAR2 + // ------------ + $token = array(); + $this->_splitText($text, $token); + // Abort! + } else { + // State 4.1: ...PAR1 + // ---- + + // State 4.2: ...PAR1\n\nPAR2 + // ------------ + } + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleElement(&$token) + { + // We don't have to check if we're already in a

        tag for block + // tokens, because the tag would have been autoclosed by MakeWellFormed. + if ($this->allowsElement('p')) { + if (!empty($this->currentNesting)) { + if ($this->_isInline($token)) { + // State 1:

        ... + // --- + // Check if this token is adjacent to the parent token + // (seek backwards until token isn't whitespace) + $i = null; + $this->backward($i, $prev); + + if (!$prev instanceof HTMLPurifier_Token_Start) { + // Token wasn't adjacent + if ($prev instanceof HTMLPurifier_Token_Text && + substr($prev->data, -2) === "\n\n" + ) { + // State 1.1.4:

        PAR1

        \n\n + // --- + // Quite frankly, this should be handled by splitText + $token = array($this->_pStart(), $token); + } else { + // State 1.1.1:

        PAR1

        + // --- + // State 1.1.2:

        + // --- + // State 1.1.3:
        PAR + // --- + } + } else { + // State 1.2.1:
        + // --- + // Lookahead to see if

        is needed. + if ($this->_pLookAhead()) { + // State 1.3.1:

        PAR1\n\nPAR2 + // --- + $token = array($this->_pStart(), $token); + } else { + // State 1.3.2:
        PAR1
        + // --- + + // State 1.3.3:
        PAR1
        \n\n
        + // --- + } + } + } else { + // State 2.3: ...
        + // ----- + } + } else { + if ($this->_isInline($token)) { + // State 3.1: + // --- + // This is where the {p} tag is inserted, not reflected in + // inputTokens yet, however. + $token = array($this->_pStart(), $token); + } else { + // State 3.2:
        + // ----- + } + + $i = null; + if ($this->backward($i, $prev)) { + if (!$prev instanceof HTMLPurifier_Token_Text) { + // State 3.1.1: ...

        {p} + // --- + // State 3.2.1: ...

        + // ----- + if (!is_array($token)) { + $token = array($token); + } + array_unshift($token, new HTMLPurifier_Token_Text("\n\n")); + } else { + // State 3.1.2: ...

        \n\n{p} + // --- + // State 3.2.2: ...

        \n\n
        + // ----- + // Note: PAR cannot occur because PAR would have been + // wrapped in

        tags. + } + } + } + } else { + // State 2.2:

        • + // ---- + // State 2.4:

          + // --- + } + } + + /** + * Splits up a text in paragraph tokens and appends them + * to the result stream that will replace the original + * @param string $data String text data that will be processed + * into paragraphs + * @param HTMLPurifier_Token[] $result Reference to array of tokens that the + * tags will be appended onto + */ + private function _splitText($data, &$result) + { + $raw_paragraphs = explode("\n\n", $data); + $paragraphs = array(); // without empty paragraphs + $needs_start = false; + $needs_end = false; + + $c = count($raw_paragraphs); + if ($c == 1) { + // There were no double-newlines, abort quickly. In theory this + // should never happen. + $result[] = new HTMLPurifier_Token_Text($data); + return; + } + for ($i = 0; $i < $c; $i++) { + $par = $raw_paragraphs[$i]; + if (trim($par) !== '') { + $paragraphs[] = $par; + } else { + if ($i == 0) { + // Double newline at the front + if (empty($result)) { + // The empty result indicates that the AutoParagraph + // injector did not add any start paragraph tokens. + // This means that we have been in a paragraph for + // a while, and the newline means we should start a new one. + $result[] = new HTMLPurifier_Token_End('p'); + $result[] = new HTMLPurifier_Token_Text("\n\n"); + // However, the start token should only be added if + // there is more processing to be done (i.e. there are + // real paragraphs in here). If there are none, the + // next start paragraph tag will be handled by the + // next call to the injector + $needs_start = true; + } else { + // We just started a new paragraph! + // Reinstate a double-newline for presentation's sake, since + // it was in the source code. + array_unshift($result, new HTMLPurifier_Token_Text("\n\n")); + } + } elseif ($i + 1 == $c) { + // Double newline at the end + // There should be a trailing

          when we're finally done. + $needs_end = true; + } + } + } + + // Check if this was just a giant blob of whitespace. Move this earlier, + // perhaps? + if (empty($paragraphs)) { + return; + } + + // Add the start tag indicated by \n\n at the beginning of $data + if ($needs_start) { + $result[] = $this->_pStart(); + } + + // Append the paragraphs onto the result + foreach ($paragraphs as $par) { + $result[] = new HTMLPurifier_Token_Text($par); + $result[] = new HTMLPurifier_Token_End('p'); + $result[] = new HTMLPurifier_Token_Text("\n\n"); + $result[] = $this->_pStart(); + } + + // Remove trailing start token; Injector will handle this later if + // it was indeed needed. This prevents from needing to do a lookahead, + // at the cost of a lookbehind later. + array_pop($result); + + // If there is no need for an end tag, remove all of it and let + // MakeWellFormed close it later. + if (!$needs_end) { + array_pop($result); // removes \n\n + array_pop($result); // removes

          + } + } + + /** + * Returns true if passed token is inline (and, ergo, allowed in + * paragraph tags) + * @param HTMLPurifier_Token $token + * @return bool + */ + private function _isInline($token) + { + return isset($this->htmlDefinition->info['p']->child->elements[$token->name]); + } + + /** + * Looks ahead in the token list and determines whether or not we need + * to insert a

          tag. + * @return bool + */ + private function _pLookAhead() + { + if ($this->currentToken instanceof HTMLPurifier_Token_Start) { + $nesting = 1; + } else { + $nesting = 0; + } + $ok = false; + $i = null; + while ($this->forwardUntilEndToken($i, $current, $nesting)) { + $result = $this->_checkNeedsP($current); + if ($result !== null) { + $ok = $result; + break; + } + } + return $ok; + } + + /** + * Determines if a particular token requires an earlier inline token + * to get a paragraph. This should be used with _forwardUntilEndToken + * @param HTMLPurifier_Token $current + * @return bool + */ + private function _checkNeedsP($current) + { + if ($current instanceof HTMLPurifier_Token_Start) { + if (!$this->_isInline($current)) { + //

          PAR1
          + // ---- + // Terminate early, since we hit a block element + return false; + } + } elseif ($current instanceof HTMLPurifier_Token_Text) { + if (strpos($current->data, "\n\n") !== false) { + //
          PAR1PAR1\n\nPAR2 + // ---- + return true; + } else { + //
          PAR1PAR1... + // ---- + } + } + return null; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/DisplayLinkURI.php b/library/vendor/HTMLPurifier/Injector/DisplayLinkURI.php new file mode 100644 index 000000000..c19b1bc27 --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/DisplayLinkURI.php @@ -0,0 +1,40 @@ +start->attr['href'])) { + $url = $token->start->attr['href']; + unset($token->start->attr['href']); + $token = array($token, new HTMLPurifier_Token_Text(" ($url)")); + } else { + // nothing to display + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/Linkify.php b/library/vendor/HTMLPurifier/Injector/Linkify.php new file mode 100644 index 000000000..069708c25 --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/Linkify.php @@ -0,0 +1,59 @@ + array('href')); + + /** + * @param HTMLPurifier_Token $token + */ + public function handleText(&$token) + { + if (!$this->allowsElement('a')) { + return; + } + + if (strpos($token->data, '://') === false) { + // our really quick heuristic failed, abort + // this may not work so well if we want to match things like + // "google.com", but then again, most people don't + return; + } + + // there is/are URL(s). Let's split the string: + // Note: this regex is extremely permissive + $bits = preg_split('#((?:https?|ftp)://[^\s\'",<>()]+)#Su', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE); + + + $token = array(); + + // $i = index + // $c = count + // $l = is link + for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) { + if (!$l) { + if ($bits[$i] === '') { + continue; + } + $token[] = new HTMLPurifier_Token_Text($bits[$i]); + } else { + $token[] = new HTMLPurifier_Token_Start('a', array('href' => $bits[$i])); + $token[] = new HTMLPurifier_Token_Text($bits[$i]); + $token[] = new HTMLPurifier_Token_End('a'); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/PurifierLinkify.php b/library/vendor/HTMLPurifier/Injector/PurifierLinkify.php new file mode 100644 index 000000000..cb9046f33 --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/PurifierLinkify.php @@ -0,0 +1,71 @@ + array('href')); + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function prepare($config, $context) + { + $this->docURL = $config->get('AutoFormat.PurifierLinkify.DocURL'); + return parent::prepare($config, $context); + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleText(&$token) + { + if (!$this->allowsElement('a')) { + return; + } + if (strpos($token->data, '%') === false) { + return; + } + + $bits = preg_split('#%([a-z0-9]+\.[a-z0-9]+)#Si', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE); + $token = array(); + + // $i = index + // $c = count + // $l = is link + for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) { + if (!$l) { + if ($bits[$i] === '') { + continue; + } + $token[] = new HTMLPurifier_Token_Text($bits[$i]); + } else { + $token[] = new HTMLPurifier_Token_Start( + 'a', + array('href' => str_replace('%s', $bits[$i], $this->docURL)) + ); + $token[] = new HTMLPurifier_Token_Text('%' . $bits[$i]); + $token[] = new HTMLPurifier_Token_End('a'); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/RemoveEmpty.php b/library/vendor/HTMLPurifier/Injector/RemoveEmpty.php new file mode 100644 index 000000000..cd885722e --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/RemoveEmpty.php @@ -0,0 +1,101 @@ + 1, 'th' => 1, 'td' => 1, 'iframe' => 1); + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return void + */ + public function prepare($config, $context) + { + parent::prepare($config, $context); + $this->config = $config; + $this->context = $context; + $this->removeNbsp = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp'); + $this->removeNbspExceptions = $config->get('AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions'); + $this->attrValidator = new HTMLPurifier_AttrValidator(); + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleElement(&$token) + { + if (!$token instanceof HTMLPurifier_Token_Start) { + return; + } + $next = false; + $deleted = 1; // the current tag + for ($i = count($this->inputZipper->back) - 1; $i >= 0; $i--, $deleted++) { + $next = $this->inputZipper->back[$i]; + if ($next instanceof HTMLPurifier_Token_Text) { + if ($next->is_whitespace) { + continue; + } + if ($this->removeNbsp && !isset($this->removeNbspExceptions[$token->name])) { + $plain = str_replace("\xC2\xA0", "", $next->data); + $isWsOrNbsp = $plain === '' || ctype_space($plain); + if ($isWsOrNbsp) { + continue; + } + } + } + break; + } + if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) { + if (isset($this->_exclude[$token->name])) { + return; + } + $this->attrValidator->validateToken($token, $this->config, $this->context); + $token->armor['ValidateAttributes'] = true; + if (isset($token->attr['id']) || isset($token->attr['name'])) { + return; + } + $token = $deleted + 1; + for ($b = 0, $c = count($this->inputZipper->front); $b < $c; $b++) { + $prev = $this->inputZipper->front[$b]; + if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) { + continue; + } + break; + } + // This is safe because we removed the token that triggered this. + $this->rewindOffset($b+$deleted); + return; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/library/vendor/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php new file mode 100644 index 000000000..9ee7aa84d --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php @@ -0,0 +1,84 @@ +attrValidator = new HTMLPurifier_AttrValidator(); + $this->config = $config; + $this->context = $context; + return parent::prepare($config, $context); + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleElement(&$token) + { + if ($token->name !== 'span' || !$token instanceof HTMLPurifier_Token_Start) { + return; + } + + // We need to validate the attributes now since this doesn't normally + // happen until after MakeWellFormed. If all the attributes are removed + // the span needs to be removed too. + $this->attrValidator->validateToken($token, $this->config, $this->context); + $token->armor['ValidateAttributes'] = true; + + if (!empty($token->attr)) { + return; + } + + $nesting = 0; + while ($this->forwardUntilEndToken($i, $current, $nesting)) { + } + + if ($current instanceof HTMLPurifier_Token_End && $current->name === 'span') { + // Mark closing span tag for deletion + $current->markForDeletion = true; + // Delete open span tag + $token = false; + } + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleEnd(&$token) + { + if ($token->markForDeletion) { + $token = false; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Injector/SafeObject.php b/library/vendor/HTMLPurifier/Injector/SafeObject.php new file mode 100644 index 000000000..3d17e07af --- /dev/null +++ b/library/vendor/HTMLPurifier/Injector/SafeObject.php @@ -0,0 +1,121 @@ + 'never', + 'allowNetworking' => 'internal', + ); + + /** + * @type array + */ + protected $allowedParam = array( + 'wmode' => true, + 'movie' => true, + 'flashvars' => true, + 'src' => true, + 'allowFullScreen' => true, // if omitted, assume to be 'false' + ); + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return void + */ + public function prepare($config, $context) + { + parent::prepare($config, $context); + } + + /** + * @param HTMLPurifier_Token $token + */ + public function handleElement(&$token) + { + if ($token->name == 'object') { + $this->objectStack[] = $token; + $this->paramStack[] = array(); + $new = array($token); + foreach ($this->addParam as $name => $value) { + $new[] = new HTMLPurifier_Token_Empty('param', array('name' => $name, 'value' => $value)); + } + $token = $new; + } elseif ($token->name == 'param') { + $nest = count($this->currentNesting) - 1; + if ($nest >= 0 && $this->currentNesting[$nest]->name === 'object') { + $i = count($this->objectStack) - 1; + if (!isset($token->attr['name'])) { + $token = false; + return; + } + $n = $token->attr['name']; + // We need this fix because YouTube doesn't supply a data + // attribute, which we need if a type is specified. This is + // *very* Flash specific. + if (!isset($this->objectStack[$i]->attr['data']) && + ($token->attr['name'] == 'movie' || $token->attr['name'] == 'src') + ) { + $this->objectStack[$i]->attr['data'] = $token->attr['value']; + } + // Check if the parameter is the correct value but has not + // already been added + if (!isset($this->paramStack[$i][$n]) && + isset($this->addParam[$n]) && + $token->attr['name'] === $this->addParam[$n]) { + // keep token, and add to param stack + $this->paramStack[$i][$n] = true; + } elseif (isset($this->allowedParam[$n])) { + // keep token, don't do anything to it + // (could possibly check for duplicates here) + } else { + $token = false; + } + } else { + // not directly inside an object, DENY! + $token = false; + } + } + } + + public function handleEnd(&$token) + { + // This is the WRONG way of handling the object and param stacks; + // we should be inserting them directly on the relevant object tokens + // so that the global stack handling handles it. + if ($token->name == 'object') { + array_pop($this->objectStack); + array_pop($this->paramStack); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/LICENSE b/library/vendor/HTMLPurifier/LICENSE similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/LICENSE rename to library/vendor/HTMLPurifier/LICENSE diff --git a/library/vendor/HTMLPurifier/Language.php b/library/vendor/HTMLPurifier/Language.php new file mode 100644 index 000000000..65277dd43 --- /dev/null +++ b/library/vendor/HTMLPurifier/Language.php @@ -0,0 +1,204 @@ +config = $config; + $this->context = $context; + } + + /** + * Loads language object with necessary info from factory cache + * @note This is a lazy loader + */ + public function load() + { + if ($this->_loaded) { + return; + } + $factory = HTMLPurifier_LanguageFactory::instance(); + $factory->loadLanguage($this->code); + foreach ($factory->keys as $key) { + $this->$key = $factory->cache[$this->code][$key]; + } + $this->_loaded = true; + } + + /** + * Retrieves a localised message. + * @param string $key string identifier of message + * @return string localised message + */ + public function getMessage($key) + { + if (!$this->_loaded) { + $this->load(); + } + if (!isset($this->messages[$key])) { + return "[$key]"; + } + return $this->messages[$key]; + } + + /** + * Retrieves a localised error name. + * @param int $int error number, corresponding to PHP's error reporting + * @return string localised message + */ + public function getErrorName($int) + { + if (!$this->_loaded) { + $this->load(); + } + if (!isset($this->errorNames[$int])) { + return "[Error: $int]"; + } + return $this->errorNames[$int]; + } + + /** + * Converts an array list into a string readable representation + * @param array $array + * @return string + */ + public function listify($array) + { + $sep = $this->getMessage('Item separator'); + $sep_last = $this->getMessage('Item separator last'); + $ret = ''; + for ($i = 0, $c = count($array); $i < $c; $i++) { + if ($i == 0) { + } elseif ($i + 1 < $c) { + $ret .= $sep; + } else { + $ret .= $sep_last; + } + $ret .= $array[$i]; + } + return $ret; + } + + /** + * Formats a localised message with passed parameters + * @param string $key string identifier of message + * @param array $args Parameters to substitute in + * @return string localised message + * @todo Implement conditionals? Right now, some messages make + * reference to line numbers, but those aren't always available + */ + public function formatMessage($key, $args = array()) + { + if (!$this->_loaded) { + $this->load(); + } + if (!isset($this->messages[$key])) { + return "[$key]"; + } + $raw = $this->messages[$key]; + $subst = array(); + $generator = false; + foreach ($args as $i => $value) { + if (is_object($value)) { + if ($value instanceof HTMLPurifier_Token) { + // factor this out some time + if (!$generator) { + $generator = $this->context->get('Generator'); + } + if (isset($value->name)) { + $subst['$'.$i.'.Name'] = $value->name; + } + if (isset($value->data)) { + $subst['$'.$i.'.Data'] = $value->data; + } + $subst['$'.$i.'.Compact'] = + $subst['$'.$i.'.Serialized'] = $generator->generateFromToken($value); + // a more complex algorithm for compact representation + // could be introduced for all types of tokens. This + // may need to be factored out into a dedicated class + if (!empty($value->attr)) { + $stripped_token = clone $value; + $stripped_token->attr = array(); + $subst['$'.$i.'.Compact'] = $generator->generateFromToken($stripped_token); + } + $subst['$'.$i.'.Line'] = $value->line ? $value->line : 'unknown'; + } + continue; + } elseif (is_array($value)) { + $keys = array_keys($value); + if (array_keys($keys) === $keys) { + // list + $subst['$'.$i] = $this->listify($value); + } else { + // associative array + // no $i implementation yet, sorry + $subst['$'.$i.'.Keys'] = $this->listify($keys); + $subst['$'.$i.'.Values'] = $this->listify(array_values($value)); + } + continue; + } + $subst['$' . $i] = $value; + } + return strtr($raw, $subst); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Language/classes/en-x-test.php b/library/vendor/HTMLPurifier/Language/classes/en-x-test.php new file mode 100644 index 000000000..8828f5cde --- /dev/null +++ b/library/vendor/HTMLPurifier/Language/classes/en-x-test.php @@ -0,0 +1,9 @@ + 'HTML Purifier X' +); + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Language/messages/en-x-testmini.php b/library/vendor/HTMLPurifier/Language/messages/en-x-testmini.php new file mode 100644 index 000000000..806c83fbf --- /dev/null +++ b/library/vendor/HTMLPurifier/Language/messages/en-x-testmini.php @@ -0,0 +1,12 @@ + 'HTML Purifier XNone' +); + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Language/messages/en.php b/library/vendor/HTMLPurifier/Language/messages/en.php new file mode 100644 index 000000000..c7f197e1e --- /dev/null +++ b/library/vendor/HTMLPurifier/Language/messages/en.php @@ -0,0 +1,55 @@ + 'HTML Purifier', +// for unit testing purposes + 'LanguageFactoryTest: Pizza' => 'Pizza', + 'LanguageTest: List' => '$1', + 'LanguageTest: Hash' => '$1.Keys; $1.Values', + 'Item separator' => ', ', + 'Item separator last' => ' and ', // non-Harvard style + + 'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.', + 'ErrorCollector: At line' => ' at line $line', + 'ErrorCollector: Incidental errors' => 'Incidental errors', + 'Lexer: Unclosed comment' => 'Unclosed comment', + 'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be <', + 'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped', + 'Lexer: Missing attribute key' => 'Attribute declaration has no key', + 'Lexer: Missing end quote' => 'Attribute declaration has no end quote', + 'Lexer: Extracted body' => 'Removed document metadata tags', + 'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized', + 'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1', + 'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text', + 'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed', + 'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed', + 'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed', + 'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end', + 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed', + 'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens', + 'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed', + 'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text', + 'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact', + 'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact', + 'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed', + 'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text', + 'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized', + 'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document', + 'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed', + 'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element', + 'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model', + 'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed', + 'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys', + 'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed', +); + +$errorNames = array( + E_ERROR => 'Error', + E_WARNING => 'Warning', + E_NOTICE => 'Notice' +); + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/LanguageFactory.php b/library/vendor/HTMLPurifier/LanguageFactory.php new file mode 100644 index 000000000..4e35272d8 --- /dev/null +++ b/library/vendor/HTMLPurifier/LanguageFactory.php @@ -0,0 +1,209 @@ +cache[$language_code][$key] = $value + * @type array + */ + public $cache; + + /** + * Valid keys in the HTMLPurifier_Language object. Designates which + * variables to slurp out of a message file. + * @type array + */ + public $keys = array('fallback', 'messages', 'errorNames'); + + /** + * Instance to validate language codes. + * @type HTMLPurifier_AttrDef_Lang + * + */ + protected $validator; + + /** + * Cached copy of dirname(__FILE__), directory of current file without + * trailing slash. + * @type string + */ + protected $dir; + + /** + * Keys whose contents are a hash map and can be merged. + * @type array + */ + protected $mergeable_keys_map = array('messages' => true, 'errorNames' => true); + + /** + * Keys whose contents are a list and can be merged. + * @value array lookup + */ + protected $mergeable_keys_list = array(); + + /** + * Retrieve sole instance of the factory. + * @param HTMLPurifier_LanguageFactory $prototype Optional prototype to overload sole instance with, + * or bool true to reset to default factory. + * @return HTMLPurifier_LanguageFactory + */ + public static function instance($prototype = null) + { + static $instance = null; + if ($prototype !== null) { + $instance = $prototype; + } elseif ($instance === null || $prototype == true) { + $instance = new HTMLPurifier_LanguageFactory(); + $instance->setup(); + } + return $instance; + } + + /** + * Sets up the singleton, much like a constructor + * @note Prevents people from getting this outside of the singleton + */ + public function setup() + { + $this->validator = new HTMLPurifier_AttrDef_Lang(); + $this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier'; + } + + /** + * Creates a language object, handles class fallbacks + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @param bool|string $code Code to override configuration with. Private parameter. + * @return HTMLPurifier_Language + */ + public function create($config, $context, $code = false) + { + // validate language code + if ($code === false) { + $code = $this->validator->validate( + $config->get('Core.Language'), + $config, + $context + ); + } else { + $code = $this->validator->validate($code, $config, $context); + } + if ($code === false) { + $code = 'en'; // malformed code becomes English + } + + $pcode = str_replace('-', '_', $code); // make valid PHP classname + static $depth = 0; // recursion protection + + if ($code == 'en') { + $lang = new HTMLPurifier_Language($config, $context); + } else { + $class = 'HTMLPurifier_Language_' . $pcode; + $file = $this->dir . '/Language/classes/' . $code . '.php'; + if (file_exists($file) || class_exists($class, false)) { + $lang = new $class($config, $context); + } else { + // Go fallback + $raw_fallback = $this->getFallbackFor($code); + $fallback = $raw_fallback ? $raw_fallback : 'en'; + $depth++; + $lang = $this->create($config, $context, $fallback); + if (!$raw_fallback) { + $lang->error = true; + } + $depth--; + } + } + $lang->code = $code; + return $lang; + } + + /** + * Returns the fallback language for language + * @note Loads the original language into cache + * @param string $code language code + * @return string|bool + */ + public function getFallbackFor($code) + { + $this->loadLanguage($code); + return $this->cache[$code]['fallback']; + } + + /** + * Loads language into the cache, handles message file and fallbacks + * @param string $code language code + */ + public function loadLanguage($code) + { + static $languages_seen = array(); // recursion guard + + // abort if we've already loaded it + if (isset($this->cache[$code])) { + return; + } + + // generate filename + $filename = $this->dir . '/Language/messages/' . $code . '.php'; + + // default fallback : may be overwritten by the ensuing include + $fallback = ($code != 'en') ? 'en' : false; + + // load primary localisation + if (!file_exists($filename)) { + // skip the include: will rely solely on fallback + $filename = $this->dir . '/Language/messages/en.php'; + $cache = array(); + } else { + include $filename; + $cache = compact($this->keys); + } + + // load fallback localisation + if (!empty($fallback)) { + + // infinite recursion guard + if (isset($languages_seen[$code])) { + trigger_error( + 'Circular fallback reference in language ' . + $code, + E_USER_ERROR + ); + $fallback = 'en'; + } + $language_seen[$code] = true; + + // load the fallback recursively + $this->loadLanguage($fallback); + $fallback_cache = $this->cache[$fallback]; + + // merge fallback with current language + foreach ($this->keys as $key) { + if (isset($cache[$key]) && isset($fallback_cache[$key])) { + if (isset($this->mergeable_keys_map[$key])) { + $cache[$key] = $cache[$key] + $fallback_cache[$key]; + } elseif (isset($this->mergeable_keys_list[$key])) { + $cache[$key] = array_merge($fallback_cache[$key], $cache[$key]); + } + } else { + $cache[$key] = $fallback_cache[$key]; + } + } + } + + // save to cache for later retrieval + $this->cache[$code] = $cache; + return; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Length.php b/library/vendor/HTMLPurifier/Length.php new file mode 100644 index 000000000..bbfbe6624 --- /dev/null +++ b/library/vendor/HTMLPurifier/Length.php @@ -0,0 +1,160 @@ + true, 'ex' => true, 'px' => true, 'in' => true, + 'cm' => true, 'mm' => true, 'pt' => true, 'pc' => true + ); + + /** + * @param string $n Magnitude + * @param bool|string $u Unit + */ + public function __construct($n = '0', $u = false) + { + $this->n = (string) $n; + $this->unit = $u !== false ? (string) $u : false; + } + + /** + * @param string $s Unit string, like '2em' or '3.4in' + * @return HTMLPurifier_Length + * @warning Does not perform validation. + */ + public static function make($s) + { + if ($s instanceof HTMLPurifier_Length) { + return $s; + } + $n_length = strspn($s, '1234567890.+-'); + $n = substr($s, 0, $n_length); + $unit = substr($s, $n_length); + if ($unit === '') { + $unit = false; + } + return new HTMLPurifier_Length($n, $unit); + } + + /** + * Validates the number and unit. + * @return bool + */ + protected function validate() + { + // Special case: + if ($this->n === '+0' || $this->n === '-0') { + $this->n = '0'; + } + if ($this->n === '0' && $this->unit === false) { + return true; + } + if (!ctype_lower($this->unit)) { + $this->unit = strtolower($this->unit); + } + if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) { + return false; + } + // Hack: + $def = new HTMLPurifier_AttrDef_CSS_Number(); + $result = $def->validate($this->n, false, false); + if ($result === false) { + return false; + } + $this->n = $result; + return true; + } + + /** + * Returns string representation of number. + * @return string + */ + public function toString() + { + if (!$this->isValid()) { + return false; + } + return $this->n . $this->unit; + } + + /** + * Retrieves string numeric magnitude. + * @return string + */ + public function getN() + { + return $this->n; + } + + /** + * Retrieves string unit. + * @return string + */ + public function getUnit() + { + return $this->unit; + } + + /** + * Returns true if this length unit is valid. + * @return bool + */ + public function isValid() + { + if ($this->isValid === null) { + $this->isValid = $this->validate(); + } + return $this->isValid; + } + + /** + * Compares two lengths, and returns 1 if greater, -1 if less and 0 if equal. + * @param HTMLPurifier_Length $l + * @return int + * @warning If both values are too large or small, this calculation will + * not work properly + */ + public function compareTo($l) + { + if ($l === false) { + return false; + } + if ($l->unit !== $this->unit) { + $converter = new HTMLPurifier_UnitConverter(); + $l = $converter->convert($l, $this->unit); + if ($l === false) { + return false; + } + } + return $this->n - $l->n; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Lexer.php b/library/vendor/HTMLPurifier/Lexer.php new file mode 100644 index 000000000..43732621d --- /dev/null +++ b/library/vendor/HTMLPurifier/Lexer.php @@ -0,0 +1,357 @@ +get('Core.LexerImpl'); + } + + $needs_tracking = + $config->get('Core.MaintainLineNumbers') || + $config->get('Core.CollectErrors'); + + $inst = null; + if (is_object($lexer)) { + $inst = $lexer; + } else { + if (is_null($lexer)) { + do { + // auto-detection algorithm + if ($needs_tracking) { + $lexer = 'DirectLex'; + break; + } + + if (class_exists('DOMDocument') && + method_exists('DOMDocument', 'loadHTML') && + !extension_loaded('domxml') + ) { + // check for DOM support, because while it's part of the + // core, it can be disabled compile time. Also, the PECL + // domxml extension overrides the default DOM, and is evil + // and nasty and we shan't bother to support it + $lexer = 'DOMLex'; + } else { + $lexer = 'DirectLex'; + } + } while (0); + } // do..while so we can break + + // instantiate recognized string names + switch ($lexer) { + case 'DOMLex': + $inst = new HTMLPurifier_Lexer_DOMLex(); + break; + case 'DirectLex': + $inst = new HTMLPurifier_Lexer_DirectLex(); + break; + case 'PH5P': + $inst = new HTMLPurifier_Lexer_PH5P(); + break; + default: + throw new HTMLPurifier_Exception( + "Cannot instantiate unrecognized Lexer type " . + htmlspecialchars($lexer) + ); + } + } + + if (!$inst) { + throw new HTMLPurifier_Exception('No lexer was instantiated'); + } + + // once PHP DOM implements native line numbers, or we + // hack out something using XSLT, remove this stipulation + if ($needs_tracking && !$inst->tracksLineNumbers) { + throw new HTMLPurifier_Exception( + 'Cannot use lexer that does not support line numbers with ' . + 'Core.MaintainLineNumbers or Core.CollectErrors (use DirectLex instead)' + ); + } + + return $inst; + + } + + // -- CONVENIENCE MEMBERS --------------------------------------------- + + public function __construct() + { + $this->_entity_parser = new HTMLPurifier_EntityParser(); + } + + /** + * Most common entity to raw value conversion table for special entities. + * @type array + */ + protected $_special_entity2str = + array( + '"' => '"', + '&' => '&', + '<' => '<', + '>' => '>', + ''' => "'", + ''' => "'", + ''' => "'" + ); + + /** + * Parses special entities into the proper characters. + * + * This string will translate escaped versions of the special characters + * into the correct ones. + * + * @warning + * You should be able to treat the output of this function as + * completely parsed, but that's only because all other entities should + * have been handled previously in substituteNonSpecialEntities() + * + * @param string $string String character data to be parsed. + * @return string Parsed character data. + */ + public function parseData($string) + { + // following functions require at least one character + if ($string === '') { + return ''; + } + + // subtracts amps that cannot possibly be escaped + $num_amp = substr_count($string, '&') - substr_count($string, '& ') - + ($string[strlen($string) - 1] === '&' ? 1 : 0); + + if (!$num_amp) { + return $string; + } // abort if no entities + $num_esc_amp = substr_count($string, '&'); + $string = strtr($string, $this->_special_entity2str); + + // code duplication for sake of optimization, see above + $num_amp_2 = substr_count($string, '&') - substr_count($string, '& ') - + ($string[strlen($string) - 1] === '&' ? 1 : 0); + + if ($num_amp_2 <= $num_esc_amp) { + return $string; + } + + // hmm... now we have some uncommon entities. Use the callback. + $string = $this->_entity_parser->substituteSpecialEntities($string); + return $string; + } + + /** + * Lexes an HTML string into tokens. + * @param $string String HTML. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] array representation of HTML. + */ + public function tokenizeHTML($string, $config, $context) + { + trigger_error('Call to abstract class', E_USER_ERROR); + } + + /** + * Translates CDATA sections into regular sections (through escaping). + * @param string $string HTML string to process. + * @return string HTML with CDATA sections escaped. + */ + protected static function escapeCDATA($string) + { + return preg_replace_callback( + '//s', + array('HTMLPurifier_Lexer', 'CDATACallback'), + $string + ); + } + + /** + * Special CDATA case that is especially convoluted for )#si', + array($this, 'scriptCallback'), + $html + ); + } + + $html = $this->normalize($html, $config, $context); + + $cursor = 0; // our location in the text + $inside_tag = false; // whether or not we're parsing the inside of a tag + $array = array(); // result array + + // This is also treated to mean maintain *column* numbers too + $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); + + if ($maintain_line_numbers === null) { + // automatically determine line numbering by checking + // if error collection is on + $maintain_line_numbers = $config->get('Core.CollectErrors'); + } + + if ($maintain_line_numbers) { + $current_line = 1; + $current_col = 0; + $length = strlen($html); + } else { + $current_line = false; + $current_col = false; + $length = false; + } + $context->register('CurrentLine', $current_line); + $context->register('CurrentCol', $current_col); + $nl = "\n"; + // how often to manually recalculate. This will ALWAYS be right, + // but it's pretty wasteful. Set to 0 to turn off + $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // for testing synchronization + $loops = 0; + + while (++$loops) { + // $cursor is either at the start of a token, or inside of + // a tag (i.e. there was a < immediately before it), as indicated + // by $inside_tag + + if ($maintain_line_numbers) { + // $rcursor, however, is always at the start of a token. + $rcursor = $cursor - (int)$inside_tag; + + // Column number is cheap, so we calculate it every round. + // We're interested at the *end* of the newline string, so + // we need to add strlen($nl) == 1 to $nl_pos before subtracting it + // from our "rcursor" position. + $nl_pos = strrpos($html, $nl, $rcursor - $length); + $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); + + // recalculate lines + if ($synchronize_interval && // synchronization is on + $cursor > 0 && // cursor is further than zero + $loops % $synchronize_interval === 0) { // time to synchronize! + $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); + } + } + + $position_next_lt = strpos($html, '<', $cursor); + $position_next_gt = strpos($html, '>', $cursor); + + // triggers on "asdf" but not "asdf " + // special case to set up context + if ($position_next_lt === $cursor) { + $inside_tag = true; + $cursor++; + } + + if (!$inside_tag && $position_next_lt !== false) { + // We are not inside tag and there still is another tag to parse + $token = new + HTMLPurifier_Token_Text( + $this->parseData( + substr( + $html, + $cursor, + $position_next_lt - $cursor + ) + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); + } + $array[] = $token; + $cursor = $position_next_lt + 1; + $inside_tag = true; + continue; + } elseif (!$inside_tag) { + // We are not inside tag but there are no more tags + // If we're already at the end, break + if ($cursor === strlen($html)) { + break; + } + // Create Text of rest of string + $token = new + HTMLPurifier_Token_Text( + $this->parseData( + substr( + $html, + $cursor + ) + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + $array[] = $token; + break; + } elseif ($inside_tag && $position_next_gt !== false) { + // We are in tag and it is well formed + // Grab the internals of the tag + $strlen_segment = $position_next_gt - $cursor; + + if ($strlen_segment < 1) { + // there's nothing to process! + $token = new HTMLPurifier_Token_Text('<'); + $cursor++; + continue; + } + + $segment = substr($html, $cursor, $strlen_segment); + + if ($segment === false) { + // somehow, we attempted to access beyond the end of + // the string, defense-in-depth, reported by Nate Abele + break; + } + + // Check if it's a comment + if (substr($segment, 0, 3) === '!--') { + // re-determine segment length, looking for --> + $position_comment_end = strpos($html, '-->', $cursor); + if ($position_comment_end === false) { + // uh oh, we have a comment that extends to + // infinity. Can't be helped: set comment + // end position to end of string + if ($e) { + $e->send(E_WARNING, 'Lexer: Unclosed comment'); + } + $position_comment_end = strlen($html); + $end = true; + } else { + $end = false; + } + $strlen_segment = $position_comment_end - $cursor; + $segment = substr($html, $cursor, $strlen_segment); + $token = new + HTMLPurifier_Token_Comment( + substr( + $segment, + 3, + $strlen_segment - 3 + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); + } + $array[] = $token; + $cursor = $end ? $position_comment_end : $position_comment_end + 3; + $inside_tag = false; + continue; + } + + // Check if it's an end tag + $is_end_tag = (strpos($segment, '/') === 0); + if ($is_end_tag) { + $type = substr($segment, 1); + $token = new HTMLPurifier_Token_End($type); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Check leading character is alnum, if not, we may + // have accidently grabbed an emoticon. Translate into + // text and go our merry way + if (!ctype_alpha($segment[0])) { + // XML: $segment[0] !== '_' && $segment[0] !== ':' + if ($e) { + $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + } + $token = new HTMLPurifier_Token_Text('<'); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + continue; + } + + // Check if it is explicitly self closing, if so, remove + // trailing slash. Remember, we could have a tag like
          , so + // any later token processing scripts must convert improperly + // classified EmptyTags from StartTags. + $is_self_closing = (strrpos($segment, '/') === $strlen_segment - 1); + if ($is_self_closing) { + $strlen_segment--; + $segment = substr($segment, 0, $strlen_segment); + } + + // Check if there are any attributes + $position_first_space = strcspn($segment, $this->_whitespace); + + if ($position_first_space >= $strlen_segment) { + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($segment); + } else { + $token = new HTMLPurifier_Token_Start($segment); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Grab out all the data + $type = substr($segment, 0, $position_first_space); + $attribute_string = + trim( + substr( + $segment, + $position_first_space + ) + ); + if ($attribute_string) { + $attr = $this->parseAttributeString( + $attribute_string, + $config, + $context + ); + } else { + $attr = array(); + } + + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($type, $attr); + } else { + $token = new HTMLPurifier_Token_Start($type, $attr); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $cursor = $position_next_gt + 1; + $inside_tag = false; + continue; + } else { + // inside tag, but there's no ending > sign + if ($e) { + $e->send(E_WARNING, 'Lexer: Missing gt'); + } + $token = new + HTMLPurifier_Token_Text( + '<' . + $this->parseData( + substr($html, $cursor) + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + // no cursor scroll? Hmm... + $array[] = $token; + break; + } + break; + } + + $context->destroy('CurrentLine'); + $context->destroy('CurrentCol'); + return $array; + } + + /** + * PHP 5.0.x compatible substr_count that implements offset and length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int $length + * @return int + */ + protected function substrCount($haystack, $needle, $offset, $length) + { + static $oldVersion; + if ($oldVersion === null) { + $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); + } + if ($oldVersion) { + $haystack = substr($haystack, $offset, $length); + return substr_count($haystack, $needle); + } else { + return substr_count($haystack, $needle, $offset, $length); + } + } + + /** + * Takes the inside of an HTML tag and makes an assoc array of attributes. + * + * @param string $string Inside of tag excluding name. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array Assoc array of attributes. + */ + public function parseAttributeString($string, $config, $context) + { + $string = (string)$string; // quick typecast + + if ($string == '') { + return array(); + } // no attributes + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // let's see if we can abort as quickly as possible + // one equal sign, no spaces => one attribute + $num_equal = substr_count($string, '='); + $has_space = strpos($string, ' '); + if ($num_equal === 0 && !$has_space) { + // bool attribute + return array($string => $string); + } elseif ($num_equal === 1 && !$has_space) { + // only one attribute + list($key, $quoted_value) = explode('=', $string); + $quoted_value = trim($quoted_value); + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + return array(); + } + if (!$quoted_value) { + return array($key => ''); + } + $first_char = @$quoted_value[0]; + $last_char = @$quoted_value[strlen($quoted_value) - 1]; + + $same_quote = ($first_char == $last_char); + $open_quote = ($first_char == '"' || $first_char == "'"); + + if ($same_quote && $open_quote) { + // well behaved + $value = substr($quoted_value, 1, strlen($quoted_value) - 2); + } else { + // not well behaved + if ($open_quote) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing end quote'); + } + $value = substr($quoted_value, 1); + } else { + $value = $quoted_value; + } + } + if ($value === false) { + $value = ''; + } + return array($key => $this->parseData($value)); + } + + // setup loop environment + $array = array(); // return assoc array of attributes + $cursor = 0; // current position in string (moves forward) + $size = strlen($string); // size of the string (stays the same) + + // if we have unquoted attributes, the parser expects a terminating + // space, so let's guarantee that there's always a terminating space. + $string .= ' '; + + $old_cursor = -1; + while ($cursor < $size) { + if ($old_cursor >= $cursor) { + throw new Exception("Infinite loop detected"); + } + $old_cursor = $cursor; + + $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); + // grab the key + + $key_begin = $cursor; //we're currently at the start of the key + + // scroll past all characters that are the key (not whitespace or =) + $cursor += strcspn($string, $this->_whitespace . '=', $cursor); + + $key_end = $cursor; // now at the end of the key + + $key = substr($string, $key_begin, $key_end - $key_begin); + + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + $cursor += 1 + strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop + continue; // empty key + } + + // scroll past all whitespace + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor >= $size) { + $array[$key] = $key; + break; + } + + // if the next character is an equal sign, we've got a regular + // pair, otherwise, it's a bool attribute + $first_char = @$string[$cursor]; + + if ($first_char == '=') { + // key="value" + + $cursor++; + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor === false) { + $array[$key] = ''; + break; + } + + // we might be in front of a quote right now + + $char = @$string[$cursor]; + + if ($char == '"' || $char == "'") { + // it's quoted, end bound is $char + $cursor++; + $value_begin = $cursor; + $cursor = strpos($string, $char, $cursor); + $value_end = $cursor; + } else { + // it's not quoted, end bound is whitespace + $value_begin = $cursor; + $cursor += strcspn($string, $this->_whitespace, $cursor); + $value_end = $cursor; + } + + // we reached a premature end + if ($cursor === false) { + $cursor = $size; + $value_end = $cursor; + } + + $value = substr($string, $value_begin, $value_end - $value_begin); + if ($value === false) { + $value = ''; + } + $array[$key] = $this->parseData($value); + $cursor++; + } else { + // boolattr + if ($key !== '') { + $array[$key] = $key; + } else { + // purely theoretical + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + } + } + } + return $array; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Lexer/PH5P.php b/library/vendor/HTMLPurifier/Lexer/PH5P.php new file mode 100644 index 000000000..a4587e4cd --- /dev/null +++ b/library/vendor/HTMLPurifier/Lexer/PH5P.php @@ -0,0 +1,4788 @@ +normalize($html, $config, $context); + $new_html = $this->wrapHTML($new_html, $config, $context); + try { + $parser = new HTML5($new_html); + $doc = $parser->save(); + } catch (DOMException $e) { + // Uh oh, it failed. Punt to DirectLex. + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $context->register('PH5PError', $e); // save the error, so we can detect it + return $lexer->tokenizeHTML($html, $config, $context); // use original HTML + } + $tokens = array(); + $this->tokenizeDOM( + $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0)-> // + getElementsByTagName('div')->item(0) //
          + , + $tokens + ); + return $tokens; + } +} + +/* + +Copyright 2007 Jeroen van der Meer + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class HTML5 +{ + private $data; + private $char; + private $EOF; + private $state; + private $tree; + private $token; + private $content_model; + private $escape = false; + private $entities = array( + 'AElig;', + 'AElig', + 'AMP;', + 'AMP', + 'Aacute;', + 'Aacute', + 'Acirc;', + 'Acirc', + 'Agrave;', + 'Agrave', + 'Alpha;', + 'Aring;', + 'Aring', + 'Atilde;', + 'Atilde', + 'Auml;', + 'Auml', + 'Beta;', + 'COPY;', + 'COPY', + 'Ccedil;', + 'Ccedil', + 'Chi;', + 'Dagger;', + 'Delta;', + 'ETH;', + 'ETH', + 'Eacute;', + 'Eacute', + 'Ecirc;', + 'Ecirc', + 'Egrave;', + 'Egrave', + 'Epsilon;', + 'Eta;', + 'Euml;', + 'Euml', + 'GT;', + 'GT', + 'Gamma;', + 'Iacute;', + 'Iacute', + 'Icirc;', + 'Icirc', + 'Igrave;', + 'Igrave', + 'Iota;', + 'Iuml;', + 'Iuml', + 'Kappa;', + 'LT;', + 'LT', + 'Lambda;', + 'Mu;', + 'Ntilde;', + 'Ntilde', + 'Nu;', + 'OElig;', + 'Oacute;', + 'Oacute', + 'Ocirc;', + 'Ocirc', + 'Ograve;', + 'Ograve', + 'Omega;', + 'Omicron;', + 'Oslash;', + 'Oslash', + 'Otilde;', + 'Otilde', + 'Ouml;', + 'Ouml', + 'Phi;', + 'Pi;', + 'Prime;', + 'Psi;', + 'QUOT;', + 'QUOT', + 'REG;', + 'REG', + 'Rho;', + 'Scaron;', + 'Sigma;', + 'THORN;', + 'THORN', + 'TRADE;', + 'Tau;', + 'Theta;', + 'Uacute;', + 'Uacute', + 'Ucirc;', + 'Ucirc', + 'Ugrave;', + 'Ugrave', + 'Upsilon;', + 'Uuml;', + 'Uuml', + 'Xi;', + 'Yacute;', + 'Yacute', + 'Yuml;', + 'Zeta;', + 'aacute;', + 'aacute', + 'acirc;', + 'acirc', + 'acute;', + 'acute', + 'aelig;', + 'aelig', + 'agrave;', + 'agrave', + 'alefsym;', + 'alpha;', + 'amp;', + 'amp', + 'and;', + 'ang;', + 'apos;', + 'aring;', + 'aring', + 'asymp;', + 'atilde;', + 'atilde', + 'auml;', + 'auml', + 'bdquo;', + 'beta;', + 'brvbar;', + 'brvbar', + 'bull;', + 'cap;', + 'ccedil;', + 'ccedil', + 'cedil;', + 'cedil', + 'cent;', + 'cent', + 'chi;', + 'circ;', + 'clubs;', + 'cong;', + 'copy;', + 'copy', + 'crarr;', + 'cup;', + 'curren;', + 'curren', + 'dArr;', + 'dagger;', + 'darr;', + 'deg;', + 'deg', + 'delta;', + 'diams;', + 'divide;', + 'divide', + 'eacute;', + 'eacute', + 'ecirc;', + 'ecirc', + 'egrave;', + 'egrave', + 'empty;', + 'emsp;', + 'ensp;', + 'epsilon;', + 'equiv;', + 'eta;', + 'eth;', + 'eth', + 'euml;', + 'euml', + 'euro;', + 'exist;', + 'fnof;', + 'forall;', + 'frac12;', + 'frac12', + 'frac14;', + 'frac14', + 'frac34;', + 'frac34', + 'frasl;', + 'gamma;', + 'ge;', + 'gt;', + 'gt', + 'hArr;', + 'harr;', + 'hearts;', + 'hellip;', + 'iacute;', + 'iacute', + 'icirc;', + 'icirc', + 'iexcl;', + 'iexcl', + 'igrave;', + 'igrave', + 'image;', + 'infin;', + 'int;', + 'iota;', + 'iquest;', + 'iquest', + 'isin;', + 'iuml;', + 'iuml', + 'kappa;', + 'lArr;', + 'lambda;', + 'lang;', + 'laquo;', + 'laquo', + 'larr;', + 'lceil;', + 'ldquo;', + 'le;', + 'lfloor;', + 'lowast;', + 'loz;', + 'lrm;', + 'lsaquo;', + 'lsquo;', + 'lt;', + 'lt', + 'macr;', + 'macr', + 'mdash;', + 'micro;', + 'micro', + 'middot;', + 'middot', + 'minus;', + 'mu;', + 'nabla;', + 'nbsp;', + 'nbsp', + 'ndash;', + 'ne;', + 'ni;', + 'not;', + 'not', + 'notin;', + 'nsub;', + 'ntilde;', + 'ntilde', + 'nu;', + 'oacute;', + 'oacute', + 'ocirc;', + 'ocirc', + 'oelig;', + 'ograve;', + 'ograve', + 'oline;', + 'omega;', + 'omicron;', + 'oplus;', + 'or;', + 'ordf;', + 'ordf', + 'ordm;', + 'ordm', + 'oslash;', + 'oslash', + 'otilde;', + 'otilde', + 'otimes;', + 'ouml;', + 'ouml', + 'para;', + 'para', + 'part;', + 'permil;', + 'perp;', + 'phi;', + 'pi;', + 'piv;', + 'plusmn;', + 'plusmn', + 'pound;', + 'pound', + 'prime;', + 'prod;', + 'prop;', + 'psi;', + 'quot;', + 'quot', + 'rArr;', + 'radic;', + 'rang;', + 'raquo;', + 'raquo', + 'rarr;', + 'rceil;', + 'rdquo;', + 'real;', + 'reg;', + 'reg', + 'rfloor;', + 'rho;', + 'rlm;', + 'rsaquo;', + 'rsquo;', + 'sbquo;', + 'scaron;', + 'sdot;', + 'sect;', + 'sect', + 'shy;', + 'shy', + 'sigma;', + 'sigmaf;', + 'sim;', + 'spades;', + 'sub;', + 'sube;', + 'sum;', + 'sup1;', + 'sup1', + 'sup2;', + 'sup2', + 'sup3;', + 'sup3', + 'sup;', + 'supe;', + 'szlig;', + 'szlig', + 'tau;', + 'there4;', + 'theta;', + 'thetasym;', + 'thinsp;', + 'thorn;', + 'thorn', + 'tilde;', + 'times;', + 'times', + 'trade;', + 'uArr;', + 'uacute;', + 'uacute', + 'uarr;', + 'ucirc;', + 'ucirc', + 'ugrave;', + 'ugrave', + 'uml;', + 'uml', + 'upsih;', + 'upsilon;', + 'uuml;', + 'uuml', + 'weierp;', + 'xi;', + 'yacute;', + 'yacute', + 'yen;', + 'yen', + 'yuml;', + 'yuml', + 'zeta;', + 'zwj;', + 'zwnj;' + ); + + const PCDATA = 0; + const RCDATA = 1; + const CDATA = 2; + const PLAINTEXT = 3; + + const DOCTYPE = 0; + const STARTTAG = 1; + const ENDTAG = 2; + const COMMENT = 3; + const CHARACTR = 4; + const EOF = 5; + + public function __construct($data) + { + $this->data = $data; + $this->char = -1; + $this->EOF = strlen($data); + $this->tree = new HTML5TreeConstructer; + $this->content_model = self::PCDATA; + + $this->state = 'data'; + + while ($this->state !== null) { + $this->{$this->state . 'State'}(); + } + } + + public function save() + { + return $this->tree->save(); + } + + private function char() + { + return ($this->char < $this->EOF) + ? $this->data[$this->char] + : false; + } + + private function character($s, $l = 0) + { + if ($s + $l < $this->EOF) { + if ($l === 0) { + return $this->data[$s]; + } else { + return substr($this->data, $s, $l); + } + } + } + + private function characters($char_class, $start) + { + return preg_replace('#^([' . $char_class . ']+).*#s', '\\1', substr($this->data, $start)); + } + + private function dataState() + { + // Consume the next input character + $this->char++; + $char = $this->char(); + + if ($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { + /* U+0026 AMPERSAND (&) + When the content model flag is set to one of the PCDATA or RCDATA + states: switch to the entity data state. Otherwise: treat it as per + the "anything else" entry below. */ + $this->state = 'entityData'; + + } elseif ($char === '-') { + /* If the content model flag is set to either the RCDATA state or + the CDATA state, and the escape flag is false, and there are at + least three characters before this one in the input stream, and the + last four characters in the input stream, including this one, are + U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, + and U+002D HYPHEN-MINUS (""), + set the escape flag to false. */ + if (($this->content_model === self::RCDATA || + $this->content_model === self::CDATA) && $this->escape === true && + $this->character($this->char, 3) === '-->' + ) { + $this->escape = false; + } + + /* In any case, emit the input character as a character token. + Stay in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + } elseif ($this->char === $this->EOF) { + /* EOF + Emit an end-of-file token. */ + $this->EOF(); + + } elseif ($this->content_model === self::PLAINTEXT) { + /* When the content model flag is set to the PLAINTEXT state + THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of + the text and emit it as a character token. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => substr($this->data, $this->char) + ) + ); + + $this->EOF(); + + } else { + /* Anything else + THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that + otherwise would also be treated as a character token and emit it + as a single character token. Stay in the data state. */ + $len = strcspn($this->data, '<&', $this->char); + $char = substr($this->data, $this->char, $len); + $this->char += $len - 1; + + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + $this->state = 'data'; + } + } + + private function entityDataState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, emit a U+0026 AMPERSAND character token. + // Otherwise, emit the character token that was returned. + $char = (!$entity) ? '&' : $entity; + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + // Finally, switch to the data state. + $this->state = 'data'; + } + + private function tagOpenState() + { + switch ($this->content_model) { + case self::RCDATA: + case self::CDATA: + /* If the next input character is a U+002F SOLIDUS (/) character, + consume it and switch to the close tag open state. If the next + input character is not a U+002F SOLIDUS (/) character, emit a + U+003C LESS-THAN SIGN character token and switch to the data + state to process the next input character. */ + if ($this->character($this->char + 1) === '/') { + $this->char++; + $this->state = 'closeTagOpen'; + + } else { + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->state = 'data'; + } + break; + + case self::PCDATA: + // If the content model flag is set to the PCDATA state + // Consume the next input character: + $this->char++; + $char = $this->char(); + + if ($char === '!') { + /* U+0021 EXCLAMATION MARK (!) + Switch to the markup declaration open state. */ + $this->state = 'markupDeclarationOpen'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Switch to the close tag open state. */ + $this->state = 'closeTagOpen'; + + } elseif (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new start tag token, set its tag name to the lowercase + version of the input character (add 0x0020 to the character's code + point), then switch to the tag name state. (Don't emit the token + yet; further details will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::STARTTAG, + 'attr' => array() + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Emit a U+003C LESS-THAN SIGN character token and a + U+003E GREATER-THAN SIGN character token. Switch to the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<>' + ) + ); + + $this->state = 'data'; + + } elseif ($char === '?') { + /* U+003F QUESTION MARK (?) + Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + + } else { + /* Anything else + Parse error. Emit a U+003C LESS-THAN SIGN character token and + reconsume the current input character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->char--; + $this->state = 'data'; + } + break; + } + } + + private function closeTagOpenState() + { + $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); + $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; + + if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && + (!$the_same || ($the_same && (!preg_match( + '/[\t\n\x0b\x0c >\/]/', + $this->character($this->char + 1 + strlen($next_node)) + ) || $this->EOF === $this->char))) + ) { + /* If the content model flag is set to the RCDATA or CDATA states then + examine the next few characters. If they do not match the tag name of + the last start tag token emitted (case insensitively), or if they do but + they are not immediately followed by one of the following characters: + * U+0009 CHARACTER TABULATION + * U+000A LINE FEED (LF) + * U+000B LINE TABULATION + * U+000C FORM FEED (FF) + * U+0020 SPACE + * U+003E GREATER-THAN SIGN (>) + * U+002F SOLIDUS (/) + * EOF + ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character + token, a U+002F SOLIDUS character token, and switch to the data state + to process the next input character. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'state = 'data'; + + } else { + /* Otherwise, if the content model flag is set to the PCDATA state, + or if the next few characters do match that tag name, consume the + next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new end tag token, set its tag name to the lowercase version + of the input character (add 0x0020 to the character's code point), then + switch to the tag name state. (Don't emit the token yet; further details + will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::ENDTAG + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Switch to the data state. */ + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F + SOLIDUS character token. Reconsume the EOF character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'char--; + $this->state = 'data'; + + } else { + /* Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + } + } + } + + private function tagNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } else { + /* Anything else + Append the current input character to the current tag token's tag name. + Stay in the tag name state. */ + $this->token['name'] .= strtolower($char); + $this->state = 'tagName'; + } + } + + private function beforeAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Stay in the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function attributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's name. + Stay in the attribute name state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['name'] .= strtolower($char); + + $this->state = 'attributeName'; + } + } + + private function afterAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the after attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the + before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function beforeAttributeValueState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the attribute value (double-quoted) state. */ + $this->state = 'attributeValueDoubleQuoted'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the attribute value (unquoted) state and reconsume + this input character. */ + $this->char--; + $this->state = 'attributeValueUnquoted'; + + } elseif ($char === '\'') { + /* U+0027 APOSTROPHE (') + Switch to the attribute value (single-quoted) state. */ + $this->state = 'attributeValueSingleQuoted'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Switch to the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function attributeValueDoubleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('double'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (double-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueDoubleQuoted'; + } + } + + private function attributeValueSingleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '\'') { + /* U+0022 QUOTATION MARK (') + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('single'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (single-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueSingleQuoted'; + } + } + + private function attributeValueUnquotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState(); + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function entityInAttributeValueState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, append a U+0026 AMPERSAND character to the + // current attribute's value. Otherwise, emit the character token that + // was returned. + $char = (!$entity) + ? '&' + : $entity; + + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + } + + private function bogusCommentState() + { + /* Consume every character up to the first U+003E GREATER-THAN SIGN + character (>) or the end of the file (EOF), whichever comes first. Emit + a comment token whose data is the concatenation of all the characters + starting from and including the character that caused the state machine + to switch into the bogus comment state, up to and including the last + consumed character before the U+003E character, if any, or up to the + end of the file otherwise. (If the comment was started by the end of + the file (EOF), the token is empty.) */ + $data = $this->characters('^>', $this->char); + $this->emitToken( + array( + 'data' => $data, + 'type' => self::COMMENT + ) + ); + + $this->char += strlen($data); + + /* Switch to the data state. */ + $this->state = 'data'; + + /* If the end of the file was reached, reconsume the EOF character. */ + if ($this->char === $this->EOF) { + $this->char = $this->EOF - 1; + } + } + + private function markupDeclarationOpenState() + { + /* If the next two characters are both U+002D HYPHEN-MINUS (-) + characters, consume those two characters, create a comment token whose + data is the empty string, and switch to the comment state. */ + if ($this->character($this->char + 1, 2) === '--') { + $this->char += 2; + $this->state = 'comment'; + $this->token = array( + 'data' => null, + 'type' => self::COMMENT + ); + + /* Otherwise if the next seven chacacters are a case-insensitive match + for the word "DOCTYPE", then consume those characters and switch to the + DOCTYPE state. */ + } elseif (strtolower($this->character($this->char + 1, 7)) === 'doctype') { + $this->char += 7; + $this->state = 'doctype'; + + /* Otherwise, is is a parse error. Switch to the bogus comment state. + The next character that is consumed, if any, is the first character + that will be in the comment. */ + } else { + $this->char++; + $this->state = 'bogusComment'; + } + } + + private function commentState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment dash state */ + $this->state = 'commentDash'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append the input character to the comment token's data. Stay in + the comment state. */ + $this->token['data'] .= $char; + } + } + + private function commentDashState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment end state */ + $this->state = 'commentEnd'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append a U+002D HYPHEN-MINUS (-) character and the input + character to the comment token's data. Switch to the comment state. */ + $this->token['data'] .= '-' . $char; + $this->state = 'comment'; + } + } + + private function commentEndState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '-') { + $this->token['data'] .= '-'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['data'] .= '--' . $char; + $this->state = 'comment'; + } + } + + private function doctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'beforeDoctypeName'; + + } else { + $this->char--; + $this->state = 'beforeDoctypeName'; + } + } + + private function beforeDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the before DOCTYPE name state. + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token = array( + 'name' => strtoupper($char), + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + + } elseif ($char === '>') { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->char--; + $this->state = 'data'; + + } else { + $this->token = array( + 'name' => $char, + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + } + } + + private function doctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'AfterDoctypeName'; + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token['name'] .= strtoupper($char); + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['name'] .= $char; + } + + $this->token['error'] = ($this->token['name'] === 'HTML') + ? false + : true; + } + + private function afterDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the DOCTYPE name state. + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['error'] = true; + $this->state = 'bogusDoctype'; + } + } + + private function bogusDoctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + // Stay in the bogus DOCTYPE state. + } + } + + private function entity() + { + $start = $this->char; + + // This section defines how to consume an entity. This definition is + // used when parsing entities in text and in attributes. + + // The behaviour depends on the identity of the next character (the + // one immediately after the U+0026 AMPERSAND character): + + switch ($this->character($this->char + 1)) { + // U+0023 NUMBER SIGN (#) + case '#': + + // The behaviour further depends on the character after the + // U+0023 NUMBER SIGN: + switch ($this->character($this->char + 1)) { + // U+0078 LATIN SMALL LETTER X + // U+0058 LATIN CAPITAL LETTER X + case 'x': + case 'X': + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 + // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER + // A, through to U+0046 LATIN CAPITAL LETTER F (in other + // words, 0-9, A-F, a-f). + $char = 1; + $char_class = '0-9A-Fa-f'; + break; + + // Anything else + default: + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE (i.e. just 0-9). + $char = 0; + $char_class = '0-9'; + break; + } + + // Consume as many characters as match the range of characters + // given above. + $this->char++; + $e_name = $this->characters($char_class, $this->char + $char + 1); + $entity = $this->character($start, $this->char); + $cond = strlen($e_name) > 0; + + // The rest of the parsing happens bellow. + break; + + // Anything else + default: + // Consume the maximum number of characters possible, with the + // consumed characters case-sensitively matching one of the + // identifiers in the first column of the entities table. + $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); + $len = strlen($e_name); + + for ($c = 1; $c <= $len; $c++) { + $id = substr($e_name, 0, $c); + $this->char++; + + if (in_array($id, $this->entities)) { + if ($e_name[$c - 1] !== ';') { + if ($c < $len && $e_name[$c] == ';') { + $this->char++; // consume extra semicolon + } + } + $entity = $id; + break; + } + } + + $cond = isset($entity); + // The rest of the parsing happens bellow. + break; + } + + if (!$cond) { + // If no match can be made, then this is a parse error. No + // characters are consumed, and nothing is returned. + $this->char = $start; + return false; + } + + // Return a character token for the character corresponding to the + // entity name (as given by the second column of the entities table). + return html_entity_decode('&' . $entity . ';', ENT_QUOTES, 'UTF-8'); + } + + private function emitToken($token) + { + $emit = $this->tree->emitToken($token); + + if (is_int($emit)) { + $this->content_model = $emit; + + } elseif ($token['type'] === self::ENDTAG) { + $this->content_model = self::PCDATA; + } + } + + private function EOF() + { + $this->state = null; + $this->tree->emitToken( + array( + 'type' => self::EOF + ) + ); + } +} + +class HTML5TreeConstructer +{ + public $stack = array(); + + private $phase; + private $mode; + private $dom; + private $foster_parent = null; + private $a_formatting = array(); + + private $head_pointer = null; + private $form_pointer = null; + + private $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th'); + private $formatting = array( + 'a', + 'b', + 'big', + 'em', + 'font', + 'i', + 'nobr', + 's', + 'small', + 'strike', + 'strong', + 'tt', + 'u' + ); + private $special = array( + 'address', + 'area', + 'base', + 'basefont', + 'bgsound', + 'blockquote', + 'body', + 'br', + 'center', + 'col', + 'colgroup', + 'dd', + 'dir', + 'div', + 'dl', + 'dt', + 'embed', + 'fieldset', + 'form', + 'frame', + 'frameset', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'hr', + 'iframe', + 'image', + 'img', + 'input', + 'isindex', + 'li', + 'link', + 'listing', + 'menu', + 'meta', + 'noembed', + 'noframes', + 'noscript', + 'ol', + 'optgroup', + 'option', + 'p', + 'param', + 'plaintext', + 'pre', + 'script', + 'select', + 'spacer', + 'style', + 'tbody', + 'textarea', + 'tfoot', + 'thead', + 'title', + 'tr', + 'ul', + 'wbr' + ); + + // The different phases. + const INIT_PHASE = 0; + const ROOT_PHASE = 1; + const MAIN_PHASE = 2; + const END_PHASE = 3; + + // The different insertion modes for the main phase. + const BEFOR_HEAD = 0; + const IN_HEAD = 1; + const AFTER_HEAD = 2; + const IN_BODY = 3; + const IN_TABLE = 4; + const IN_CAPTION = 5; + const IN_CGROUP = 6; + const IN_TBODY = 7; + const IN_ROW = 8; + const IN_CELL = 9; + const IN_SELECT = 10; + const AFTER_BODY = 11; + const IN_FRAME = 12; + const AFTR_FRAME = 13; + + // The different types of elements. + const SPECIAL = 0; + const SCOPING = 1; + const FORMATTING = 2; + const PHRASING = 3; + + const MARKER = 0; + + public function __construct() + { + $this->phase = self::INIT_PHASE; + $this->mode = self::BEFOR_HEAD; + $this->dom = new DOMDocument; + + $this->dom->encoding = 'UTF-8'; + $this->dom->preserveWhiteSpace = true; + $this->dom->substituteEntities = true; + $this->dom->strictErrorChecking = false; + } + + // Process tag tokens + public function emitToken($token) + { + switch ($this->phase) { + case self::INIT_PHASE: + return $this->initPhase($token); + break; + case self::ROOT_PHASE: + return $this->rootElementPhase($token); + break; + case self::MAIN_PHASE: + return $this->mainPhase($token); + break; + case self::END_PHASE : + return $this->trailingEndPhase($token); + break; + } + } + + private function initPhase($token) + { + /* Initially, the tree construction stage must handle each token + emitted from the tokenisation stage as follows: */ + + /* A DOCTYPE token that is marked as being in error + A comment token + A start tag token + An end tag token + A character token that is not one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE + An end-of-file token */ + if ((isset($token['error']) && $token['error']) || + $token['type'] === HTML5::COMMENT || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF || + ($token['type'] === HTML5::CHARACTR && isset($token['data']) && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) + ) { + /* This specification does not define how to handle this case. In + particular, user agents may ignore the entirety of this specification + altogether for such documents, and instead invoke special parse modes + with a greater emphasis on backwards compatibility. */ + + $this->phase = self::ROOT_PHASE; + return $this->rootElementPhase($token); + + /* A DOCTYPE token marked as being correct */ + } elseif (isset($token['error']) && !$token['error']) { + /* Append a DocumentType node to the Document node, with the name + attribute set to the name given in the DOCTYPE token (which will be + "HTML"), and the other attributes specific to DocumentType objects + set to null, empty lists, or the empty string as appropriate. */ + $doctype = new DOMDocumentType(null, null, 'HTML'); + + /* Then, switch to the root element phase of the tree construction + stage. */ + $this->phase = self::ROOT_PHASE; + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif (isset($token['data']) && preg_match( + '/^[\t\n\x0b\x0c ]+$/', + $token['data'] + ) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + } + } + + private function rootElementPhase($token) + { + /* After the initial phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED + (FF), or U+0020 SPACE + A start tag token + An end tag token + An end-of-file token */ + } elseif (($token['type'] === HTML5::CHARACTR && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF + ) { + /* Create an HTMLElement node with the tag name html, in the HTML + namespace. Append it to the Document object. Switch to the main + phase and reprocess the current token. */ + $html = $this->dom->createElement('html'); + $this->dom->appendChild($html); + $this->stack[] = $html; + + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + } + } + + private function mainPhase($token) + { + /* Tokens in the main phase must be handled as follows: */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A start tag token with the tag name "html" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { + /* If this start tag token was not the first start tag token, then + it is a parse error. */ + + /* For each attribute on the token, check to see if the attribute + is already present on the top element of the stack of open elements. + If it is not, add the attribute and its corresponding value to that + element. */ + foreach ($token['attr'] as $attr) { + if (!$this->stack[0]->hasAttribute($attr['name'])) { + $this->stack[0]->setAttribute($attr['name'], $attr['value']); + } + } + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Anything else. */ + } else { + /* Depends on the insertion mode: */ + switch ($this->mode) { + case self::BEFOR_HEAD: + return $this->beforeHead($token); + break; + case self::IN_HEAD: + return $this->inHead($token); + break; + case self::AFTER_HEAD: + return $this->afterHead($token); + break; + case self::IN_BODY: + return $this->inBody($token); + break; + case self::IN_TABLE: + return $this->inTable($token); + break; + case self::IN_CAPTION: + return $this->inCaption($token); + break; + case self::IN_CGROUP: + return $this->inColumnGroup($token); + break; + case self::IN_TBODY: + return $this->inTableBody($token); + break; + case self::IN_ROW: + return $this->inRow($token); + break; + case self::IN_CELL: + return $this->inCell($token); + break; + case self::IN_SELECT: + return $this->inSelect($token); + break; + case self::AFTER_BODY: + return $this->afterBody($token); + break; + case self::IN_FRAME: + return $this->inFrameset($token); + break; + case self::AFTR_FRAME: + return $this->afterFrameset($token); + break; + case self::END_PHASE: + return $this->trailingEndPhase($token); + break; + } + } + } + + private function beforeHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "head" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { + /* Create an element for the token, append the new element to the + current node and push it onto the stack of open elements. */ + $element = $this->insertElement($token); + + /* Set the head element pointer to this new element node. */ + $this->head_pointer = $element; + + /* Change the insertion mode to "in head". */ + $this->mode = self::IN_HEAD; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title". Or an end tag with the tag name "html". + Or a character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or any other start tag token */ + } elseif ($token['type'] === HTML5::STARTTAG || + ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || + ($token['type'] === HTML5::CHARACTR && !preg_match( + '/^[\t\n\x0b\x0c ]$/', + $token['data'] + )) + ) { + /* Act as if a start tag token with the tag name "head" and no + attributes had been seen, then reprocess the current token. */ + $this->beforeHead( + array( + 'name' => 'head', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inHead($token); + + /* Any other end tag */ + } elseif ($token['type'] === HTML5::ENDTAG) { + /* Parse error. Ignore the token. */ + } + } + + private function inHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. + + THIS DIFFERS FROM THE SPEC: If the current node is either a title, style + or script element, append the character to the current node regardless + of its content. */ + if (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( + $token['type'] === HTML5::CHARACTR && in_array( + end($this->stack)->nodeName, + array('title', 'style', 'script') + )) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('title', 'style', 'script')) + ) { + array_pop($this->stack); + return HTML5::PCDATA; + + /* A start tag with the tag name "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $element = $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the RCDATA state. */ + return HTML5::RCDATA; + + /* A start tag with the tag name "style" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "script" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { + /* Create an element for the token. */ + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "base", "link", or "meta" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta') + ) + ) { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + array_pop($this->stack); + + } else { + $this->insertElement($token); + } + + /* An end tag with the tag name "head" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { + /* If the current node is a head element, pop the current node off + the stack of open elements. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + array_pop($this->stack); + + /* Otherwise, this is a parse error. */ + } else { + // k + } + + /* Change the insertion mode to "after head". */ + $this->mode = self::AFTER_HEAD; + + /* A start tag with the tag name "head" or an end tag except "html". */ + } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || + ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html') + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* If the current node is a head element, act as if an end tag + token with the tag name "head" had been seen. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + $this->inHead( + array( + 'name' => 'head', + 'type' => HTML5::ENDTAG + ) + ); + + /* Otherwise, change the insertion mode to "after head". */ + } else { + $this->mode = self::AFTER_HEAD; + } + + /* Then, reprocess the current token. */ + return $this->afterHead($token); + } + } + + private function afterHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "body" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { + /* Insert a body element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in body". */ + $this->mode = self::IN_BODY; + + /* A start tag token with the tag name "frameset" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { + /* Insert a frameset element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in frameset". */ + $this->mode = self::IN_FRAME; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta', 'script', 'style', 'title') + ) + ) { + /* Parse error. Switch the insertion mode back to "in head" and + reprocess the token. */ + $this->mode = self::IN_HEAD; + return $this->inHead($token); + + /* Anything else */ + } else { + /* Act as if a start tag token with the tag name "body" and no + attributes had been seen, and then reprocess the current token. */ + $this->afterHead( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inBody($token); + } + } + + private function inBody($token) + { + /* Handle the token as follows: */ + + switch ($token['type']) { + /* A character token */ + case HTML5::CHARACTR: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + break; + + /* A comment token */ + case HTML5::COMMENT: + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + break; + + case HTML5::STARTTAG: + switch ($token['name']) { + /* A start tag token whose tag name is one of: "script", + "style" */ + case 'script': + case 'style': + /* Process the token as if the insertion mode had been "in + head". */ + return $this->inHead($token); + break; + + /* A start tag token whose tag name is one of: "base", "link", + "meta", "title" */ + case 'base': + case 'link': + case 'meta': + case 'title': + /* Parse error. Process the token as if the insertion mode + had been "in head". */ + return $this->inHead($token); + break; + + /* A start tag token with the tag name "body" */ + case 'body': + /* Parse error. If the second element on the stack of open + elements is not a body element, or, if the stack of open + elements has only one node on it, then ignore the token. + (innerHTML case) */ + if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { + // Ignore + + /* Otherwise, for each attribute on the token, check to see + if the attribute is already present on the body element (the + second element) on the stack of open elements. If it is not, + add the attribute and its corresponding value to that + element. */ + } else { + foreach ($token['attr'] as $attr) { + if (!$this->stack[1]->hasAttribute($attr['name'])) { + $this->stack[1]->setAttribute($attr['name'], $attr['value']); + } + } + } + break; + + /* A start tag whose tag name is one of: "address", + "blockquote", "center", "dir", "div", "dl", "fieldset", + "listing", "menu", "ol", "p", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'p': + case 'ul': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "form" */ + case 'form': + /* If the form element pointer is not null, ignore the + token with a parse error. */ + if ($this->form_pointer !== null) { + // Ignore. + + /* Otherwise: */ + } else { + /* If the stack of open elements has a p element in + scope, then act as if an end tag with the tag name p + had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token, and set the + form element pointer to point to the element created. */ + $element = $this->insertElement($token); + $this->form_pointer = $element; + } + break; + + /* A start tag whose tag name is "li", "dd" or "dt" */ + case 'li': + case 'dd': + case 'dt': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + $stack_length = count($this->stack) - 1; + + for ($n = $stack_length; 0 <= $n; $n--) { + /* 1. Initialise node to be the current node (the + bottommost node of the stack). */ + $stop = false; + $node = $this->stack[$n]; + $cat = $this->getElementCategory($node->tagName); + + /* 2. If node is an li, dd or dt element, then pop all + the nodes from the current node up to node, including + node, then stop this algorithm. */ + if ($token['name'] === $node->tagName || ($token['name'] !== 'li' + && ($node->tagName === 'dd' || $node->tagName === 'dt')) + ) { + for ($x = $stack_length; $x >= $n; $x--) { + array_pop($this->stack); + } + + break; + } + + /* 3. If node is not in the formatting category, and is + not in the phrasing category, and is not an address or + div element, then stop this algorithm. */ + if ($cat !== self::FORMATTING && $cat !== self::PHRASING && + $node->tagName !== 'address' && $node->tagName !== 'div' + ) { + break; + } + } + + /* Finally, insert an HTML element with the same tag + name as the token's. */ + $this->insertElement($token); + break; + + /* A start tag token whose tag name is "plaintext" */ + case 'plaintext': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + return HTML5::PLAINTEXT; + break; + + /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + this is a parse error; pop elements from the stack until an + element with one of those tag names has been popped from the + stack. */ + while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { + array_pop($this->stack); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "a" */ + case 'a': + /* If the list of active formatting elements contains + an element whose tag name is "a" between the end of the + list and the last marker on the list (or the start of + the list if there is no marker on the list), then this + is a parse error; act as if an end tag with the tag name + "a" had been seen, then remove that element from the list + of active formatting elements and the stack of open + elements if the end tag didn't already remove it (it + might not have if the element is not in table scope). */ + $leng = count($this->a_formatting); + + for ($n = $leng - 1; $n >= 0; $n--) { + if ($this->a_formatting[$n] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$n]->nodeName === 'a') { + $this->emitToken( + array( + 'name' => 'a', + 'type' => HTML5::ENDTAG + ) + ); + break; + } + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag whose tag name is one of: "b", "big", "em", "font", + "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag token whose tag name is "button" */ + case 'button': + /* If the stack of open elements has a button element in scope, + then this is a parse error; act as if an end tag with the tag + name "button" had been seen, then reprocess the token. (We don't + do that. Unnecessary.) */ + if ($this->elementInScope('button')) { + $this->inBody( + array( + 'name' => 'button', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is one of: "marquee", "object" */ + case 'marquee': + case 'object': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is "xmp" */ + case 'xmp': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Switch the content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "table" */ + case 'table': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + break; + + /* A start tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'img': + case 'param': + case 'spacer': + case 'wbr': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "hr" */ + case 'hr': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "image" */ + case 'image': + /* Parse error. Change the token's tag name to "img" and + reprocess it. (Don't ask.) */ + $token['name'] = 'img'; + return $this->inBody($token); + break; + + /* A start tag whose tag name is "input" */ + case 'input': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an input element for the token. */ + $element = $this->insertElement($token, false); + + /* If the form element pointer is not null, then associate the + input element with the form element pointed to by the form + element pointer. */ + $this->form_pointer !== null + ? $this->form_pointer->appendChild($element) + : end($this->stack)->appendChild($element); + + /* Pop that input element off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "isindex" */ + case 'isindex': + /* Parse error. */ + // w/e + + /* If the form element pointer is not null, + then ignore the token. */ + if ($this->form_pointer === null) { + /* Act as if a start tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a stream of character tokens had been seen. */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if a start tag token with the tag name "input" + had been seen, with all the attributes from the "isindex" + token, except with the "name" attribute set to the value + "isindex" (ignoring any explicit "name" attribute). */ + $attr = $token['attr']; + $attr[] = array('name' => 'name', 'value' => 'isindex'); + + $this->inBody( + array( + 'name' => 'input', + 'type' => HTML5::STARTTAG, + 'attr' => $attr + ) + ); + + /* Act as if a stream of character tokens had been seen + (see below for what they should say). */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if an end tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'form', + 'type' => HTML5::ENDTAG + ) + ); + } + break; + + /* A start tag whose tag name is "textarea" */ + case 'textarea': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the + RCDATA state. */ + return HTML5::RCDATA; + break; + + /* A start tag whose tag name is one of: "iframe", "noembed", + "noframes" */ + case 'iframe': + case 'noembed': + case 'noframes': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "select" */ + case 'select': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in select". */ + $this->mode = self::IN_SELECT; + break; + + /* A start or end tag whose tag name is one of: "caption", "col", + "colgroup", "frame", "frameset", "head", "option", "optgroup", + "tbody", "td", "tfoot", "th", "thead", "tr". */ + case 'caption': + case 'col': + case 'colgroup': + case 'frame': + case 'frameset': + case 'head': + case 'option': + case 'optgroup': + case 'tbody': + case 'td': + case 'tfoot': + case 'th': + case 'thead': + case 'tr': + // Parse error. Ignore the token. + break; + + /* A start or end tag whose tag name is one of: "event-source", + "section", "nav", "article", "aside", "header", "footer", + "datagrid", "command" */ + case 'event-source': + case 'section': + case 'nav': + case 'article': + case 'aside': + case 'header': + case 'footer': + case 'datagrid': + case 'command': + // Work in progress! + break; + + /* A start tag token not covered by the previous entries */ + default: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + $this->insertElement($token, true, true); + break; + } + break; + + case HTML5::ENDTAG: + switch ($token['name']) { + /* An end tag with the tag name "body" */ + case 'body': + /* If the second element in the stack of open elements is + not a body element, this is a parse error. Ignore the token. + (innerHTML case) */ + if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { + // Ignore. + + /* If the current node is not the body element, then this + is a parse error. */ + } elseif (end($this->stack)->nodeName !== 'body') { + // Parse error. + } + + /* Change the insertion mode to "after body". */ + $this->mode = self::AFTER_BODY; + break; + + /* An end tag with the tag name "html" */ + case 'html': + /* Act as if an end tag with tag name "body" had been seen, + then, if that token wasn't ignored, reprocess the current + token. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->afterBody($token); + break; + + /* An end tag whose tag name is one of: "address", "blockquote", + "center", "dir", "div", "dl", "fieldset", "listing", "menu", + "ol", "pre", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'pre': + case 'ul': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with + the same tag name as that of the token, then this + is a parse error. */ + // w/e + + /* If the stack of open elements has an element in + scope with the same tag name as that of the token, + then pop elements from this stack until an element + with that tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is "form" */ + case 'form': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + } + + if (end($this->stack)->nodeName !== $token['name']) { + /* Now, if the current node is not an element with the + same tag name as that of the token, then this is a parse + error. */ + // w/e + + } else { + /* Otherwise, if the current node is an element with + the same tag name as that of the token pop that element + from the stack. */ + array_pop($this->stack); + } + + /* In any case, set the form element pointer to null. */ + $this->form_pointer = null; + break; + + /* An end tag whose tag name is "p" */ + case 'p': + /* If the stack of open elements has a p element in scope, + then generate implied end tags, except for p elements. */ + if ($this->elementInScope('p')) { + $this->generateImpliedEndTags(array('p')); + + /* If the current node is not a p element, then this is + a parse error. */ + // k + + /* If the stack of open elements has a p element in + scope, then pop elements from this stack until the stack + no longer has a p element in scope. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->elementInScope('p')) { + array_pop($this->stack); + + } else { + break; + } + } + } + break; + + /* An end tag whose tag name is "dd", "dt", or "li" */ + case 'dd': + case 'dt': + case 'li': + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + generate implied end tags, except for elements with the + same tag name as the token. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(array($token['name'])); + + /* If the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + pop elements from this stack until an element with that + tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + generate implied end tags. */ + if ($this->elementInScope($elements)) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as that of the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has in scope an element + whose tag name is one of "h1", "h2", "h3", "h4", "h5", or + "h6", then pop elements from the stack until an element + with one of those tag names has been popped from the stack. */ + while ($this->elementInScope($elements)) { + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "a", "b", "big", "em", + "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'a': + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* 1. Let the formatting element be the last element in + the list of active formatting elements that: + * is between the end of the list and the last scope + marker in the list, if any, or the start of the list + otherwise, and + * has the same tag name as the token. + */ + while (true) { + for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) { + if ($this->a_formatting[$a] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$a]->tagName === $token['name']) { + $formatting_element = $this->a_formatting[$a]; + $in_stack = in_array($formatting_element, $this->stack, true); + $fe_af_pos = $a; + break; + } + } + + /* If there is no such node, or, if that node is + also in the stack of open elements but the element + is not in scope, then this is a parse error. Abort + these steps. The token is ignored. */ + if (!isset($formatting_element) || ($in_stack && + !$this->elementInScope($token['name'])) + ) { + break; + + /* Otherwise, if there is such a node, but that node + is not in the stack of open elements, then this is a + parse error; remove the element from the list, and + abort these steps. */ + } elseif (isset($formatting_element) && !$in_stack) { + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 2. Let the furthest block be the topmost node in the + stack of open elements that is lower in the stack + than the formatting element, and is not an element in + the phrasing or formatting categories. There might + not be one. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $length = count($this->stack); + + for ($s = $fe_s_pos + 1; $s < $length; $s++) { + $category = $this->getElementCategory($this->stack[$s]->nodeName); + + if ($category !== self::PHRASING && $category !== self::FORMATTING) { + $furthest_block = $this->stack[$s]; + } + } + + /* 3. If there is no furthest block, then the UA must + skip the subsequent steps and instead just pop all + the nodes from the bottom of the stack of open + elements, from the current node up to the formatting + element, and remove the formatting element from the + list of active formatting elements. */ + if (!isset($furthest_block)) { + for ($n = $length - 1; $n >= $fe_s_pos; $n--) { + array_pop($this->stack); + } + + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 4. Let the common ancestor be the element + immediately above the formatting element in the stack + of open elements. */ + $common_ancestor = $this->stack[$fe_s_pos - 1]; + + /* 5. If the furthest block has a parent node, then + remove the furthest block from its parent node. */ + if ($furthest_block->parentNode !== null) { + $furthest_block->parentNode->removeChild($furthest_block); + } + + /* 6. Let a bookmark note the position of the + formatting element in the list of active formatting + elements relative to the elements on either side + of it in the list. */ + $bookmark = $fe_af_pos; + + /* 7. Let node and last node be the furthest block. + Follow these steps: */ + $node = $furthest_block; + $last_node = $furthest_block; + + while (true) { + for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { + /* 7.1 Let node be the element immediately + prior to node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 7.2 If node is not in the list of active + formatting elements, then remove node from + the stack of open elements and then go back + to step 1. */ + if (!in_array($node, $this->a_formatting, true)) { + unset($this->stack[$n]); + $this->stack = array_merge($this->stack); + + } else { + break; + } + } + + /* 7.3 Otherwise, if node is the formatting + element, then go to the next step in the overall + algorithm. */ + if ($node === $formatting_element) { + break; + + /* 7.4 Otherwise, if last node is the furthest + block, then move the aforementioned bookmark to + be immediately after the node in the list of + active formatting elements. */ + } elseif ($last_node === $furthest_block) { + $bookmark = array_search($node, $this->a_formatting, true) + 1; + } + + /* 7.5 If node has any children, perform a + shallow clone of node, replace the entry for + node in the list of active formatting elements + with an entry for the clone, replace the entry + for node in the stack of open elements with an + entry for the clone, and let node be the clone. */ + if ($node->hasChildNodes()) { + $clone = $node->cloneNode(); + $s_pos = array_search($node, $this->stack, true); + $a_pos = array_search($node, $this->a_formatting, true); + + $this->stack[$s_pos] = $clone; + $this->a_formatting[$a_pos] = $clone; + $node = $clone; + } + + /* 7.6 Insert last node into node, first removing + it from its previous parent node if any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $node->appendChild($last_node); + + /* 7.7 Let last node be node. */ + $last_node = $node; + } + + /* 8. Insert whatever last node ended up being in + the previous step into the common ancestor node, + first removing it from its previous parent node if + any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $common_ancestor->appendChild($last_node); + + /* 9. Perform a shallow clone of the formatting + element. */ + $clone = $formatting_element->cloneNode(); + + /* 10. Take all of the child nodes of the furthest + block and append them to the clone created in the + last step. */ + while ($furthest_block->hasChildNodes()) { + $child = $furthest_block->firstChild; + $furthest_block->removeChild($child); + $clone->appendChild($child); + } + + /* 11. Append that clone to the furthest block. */ + $furthest_block->appendChild($clone); + + /* 12. Remove the formatting element from the list + of active formatting elements, and insert the clone + into the list of active formatting elements at the + position of the aforementioned bookmark. */ + $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + + $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); + $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); + $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); + + /* 13. Remove the formatting element from the stack + of open elements, and insert the clone into the stack + of open elements immediately after (i.e. in a more + deeply nested position than) the position of the + furthest block in that stack. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $fb_s_pos = array_search($furthest_block, $this->stack, true); + unset($this->stack[$fe_s_pos]); + + $s_part1 = array_slice($this->stack, 0, $fb_s_pos); + $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); + $this->stack = array_merge($s_part1, array($clone), $s_part2); + + /* 14. Jump back to step 1 in this series of steps. */ + unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); + } + break; + + /* An end tag token whose tag name is one of: "button", + "marquee", "object" */ + case 'button': + case 'marquee': + case 'object': + /* If the stack of open elements has an element in scope whose + tag name matches the tag name of the token, then generate implied + tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // k + + /* Now, if the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then pop + elements from the stack until that element has been popped from + the stack, and clear the list of active formatting elements up + to the last marker. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + + $marker = end(array_keys($this->a_formatting, self::MARKER, true)); + + for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) { + array_pop($this->a_formatting); + } + } + break; + + /* Or an end tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "hr", "iframe", "image", "img", + "input", "isindex", "noembed", "noframes", "param", "select", + "spacer", "table", "textarea", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'hr': + case 'iframe': + case 'image': + case 'img': + case 'input': + case 'isindex': + case 'noembed': + case 'noframes': + case 'param': + case 'select': + case 'spacer': + case 'table': + case 'textarea': + case 'wbr': + // Parse error. Ignore the token. + break; + + /* An end tag token not covered by the previous entries */ + default: + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + /* Initialise node to be the current node (the bottommost + node of the stack). */ + $node = end($this->stack); + + /* If node has the same tag name as the end tag token, + then: */ + if ($token['name'] === $node->nodeName) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* If the tag name of the end tag token does not + match the tag name of the current node, this is a + parse error. */ + // k + + /* Pop all the nodes from the current node up to + node, including node, then stop this algorithm. */ + for ($x = count($this->stack) - $n; $x >= $n; $x--) { + array_pop($this->stack); + } + + } else { + $category = $this->getElementCategory($node); + + if ($category !== self::SPECIAL && $category !== self::SCOPING) { + /* Otherwise, if node is in neither the formatting + category nor the phrasing category, then this is a + parse error. Stop this algorithm. The end tag token + is ignored. */ + return false; + } + } + } + break; + } + break; + } + } + + private function inTable($token) + { + $clear = array('html', 'table'); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "caption" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'caption' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + + /* Insert an HTML element for the token, then switch the + insertion mode to "in caption". */ + $this->insertElement($token); + $this->mode = self::IN_CAPTION; + + /* A start tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'colgroup' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the + insertion mode to "in column group". */ + $this->insertElement($token); + $this->mode = self::IN_CGROUP; + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'col' + ) { + $this->inTable( + array( + 'name' => 'colgroup', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + $this->inColumnGroup($token); + + /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('tbody', 'tfoot', 'thead') + ) + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in table body". */ + $this->insertElement($token); + $this->mode = self::IN_TBODY; + + /* A start tag whose tag name is one of: "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && + in_array($token['name'], array('td', 'th', 'tr')) + ) { + /* Act as if a start tag token with the tag name "tbody" had been + seen, then reprocess the current token. */ + $this->inTable( + array( + 'name' => 'tbody', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inTableBody($token); + + /* A start tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'table' + ) { + /* Parse error. Act as if an end tag token with the tag name "table" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inTable( + array( + 'name' => 'table', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + + /* An end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + return false; + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a table element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a table element has been + popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'table') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'caption', + 'col', + 'colgroup', + 'html', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Parse error. Process the token as if the insertion mode was "in + body", with the following exception: */ + + /* If the current node is a table, tbody, tfoot, thead, or tr + element, then, whenever a node would be inserted into the current + node, it must instead be inserted into the foster parent element. */ + if (in_array( + end($this->stack)->nodeName, + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* The foster parent element is the parent element of the last + table element in the stack of open elements, if there is a + table element and it has such a parent element. If there is no + table element in the stack of open elements (innerHTML case), + then the foster parent element is the first element in the + stack of open elements (the html element). Otherwise, if there + is a table element in the stack of open elements, but the last + table element in the stack of open elements has no parent, or + its parent node is not an element, then the foster parent + element is the element before the last table element in the + stack of open elements. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table') { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $table->parentNode !== null) { + $this->foster_parent = $table->parentNode; + + } elseif (!isset($table)) { + $this->foster_parent = $this->stack[0]; + + } elseif (isset($table) && ($table->parentNode === null || + $table->parentNode->nodeType !== XML_ELEMENT_NODE) + ) { + $this->foster_parent = $this->stack[$n - 1]; + } + } + + $this->inBody($token); + } + } + + private function inCaption($token) + { + /* An end tag whose tag name is "caption" */ + if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a caption element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a caption element has + been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === 'caption') { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag + name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + )) || ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table') + ) { + /* Parse error. Act as if an end tag with the tag name "caption" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inCaption( + array( + 'name' => 'caption', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + + /* An end tag whose tag name is one of: "body", "col", "colgroup", + "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'col', + 'colgroup', + 'html', + 'tbody', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inColumnGroup($token) + { + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { + /* Insert a col element for the token. Immediately pop the current + node off the stack of open elements. */ + $this->insertElement($token); + array_pop($this->stack); + + /* An end tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'colgroup' + ) { + /* If the current node is the root html element, then this is a + parse error, ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + /* Otherwise, pop the current node (which will be a colgroup + element) from the stack of open elements. Switch the insertion + mode to "in table". */ + } else { + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* An end tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Act as if an end tag with the tag name "colgroup" had been seen, + and then, if that token wasn't ignored, reprocess the current token. */ + $this->inColumnGroup( + array( + 'name' => 'colgroup', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + } + } + + private function inTableBody($token) + { + $clear = array('tbody', 'tfoot', 'thead', 'html'); + + /* A start tag whose tag name is "tr" */ + if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Insert a tr element for the token, then switch the insertion + mode to "in row". */ + $this->insertElement($token); + $this->mode = self::IN_ROW; + + /* A start tag whose tag name is one of: "th", "td" */ + } elseif ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Parse error. Act as if a start tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inTableBody( + array( + 'name' => 'tr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inRow($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node from the stack of open elements. Switch + the insertion mode to "in table". */ + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead') + )) || + ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table') + ) { + /* If the stack of open elements does not have a tbody, thead, or + tfoot element in table scope, this is a parse error. Ignore the + token. (innerHTML case) */ + if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Act as if an end tag with the same tag name as the current + node ("tbody", "tfoot", or "thead") had been seen, then + reprocess the current token. */ + $this->inTableBody( + array( + 'name' => end($this->stack)->nodeName, + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inRow($token) + { + $clear = array('tr', 'html'); + + /* A start tag whose tag name is one of: "th", "td" */ + if ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in cell". */ + $this->insertElement($token); + $this->mode = self::IN_CELL; + + /* Insert a marker at the end of the list of active formatting + elements. */ + $this->a_formatting[] = self::MARKER; + + /* An end tag whose tag name is "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node (which will be a tr element) from the + stack of open elements. Switch the insertion mode to "in table + body". */ + array_pop($this->stack); + $this->mode = self::IN_TBODY; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* Act as if an end tag with the tag name "tr" had been seen, then, + if that token wasn't ignored, reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Otherwise, act as if an end tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inCell($token) + { + /* An end tag whose tag name is one of: "td", "th" */ + if ($token['type'] === HTML5::ENDTAG && + ($token['name'] === 'td' || $token['name'] === 'th') + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token, then this is a + parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Generate implied end tags, except for elements with the same + tag name as the token. */ + $this->generateImpliedEndTags(array($token['name'])); + + /* Now, if the current node is not an element with the same tag + name as the token, then this is a parse error. */ + // k + + /* Pop elements from this stack until an element with the same + tag name as the token has been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === $token['name']) { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in row". (The current node + will be a tr element at this point.) */ + $this->mode = self::IN_ROW; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html') + ) + ) { + /* Parse error. Ignore the token. */ + + /* An end tag whose tag name is one of: "table", "tbody", "tfoot", + "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token (which can only + happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), + then this is a parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inSelect($token) + { + /* Handle the token as follows: */ + + /* A character token */ + if ($token['type'] === HTML5::CHARACTR) { + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* A start tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'optgroup' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, act as if an end tag + with the tag name "optgroup" had been seen. */ + if (end($this->stack)->nodeName === 'optgroup') { + $this->inSelect( + array( + 'name' => 'optgroup', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* An end tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'optgroup' + ) { + /* First, if the current node is an option element, and the node + immediately before it in the stack of open elements is an optgroup + element, then act as if an end tag with the tag name "option" had + been seen. */ + $elements_in_stack = count($this->stack); + + if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' && + $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup' + ) { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if ($this->stack[$elements_in_stack - 1] === 'optgroup') { + array_pop($this->stack); + } + + /* An end tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if (end($this->stack)->nodeName === 'option') { + array_pop($this->stack); + } + + /* An end tag whose tag name is "select" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'select' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // w/e + + /* Otherwise: */ + } else { + /* Pop elements from the stack of open elements until a select + element has been popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'select') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* A start tag whose tag name is "select" */ + } elseif ($token['name'] === 'select' && + $token['type'] === HTML5::STARTTAG + ) { + /* Parse error. Act as if the token had been an end tag with the + tag name "select" instead. */ + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + /* An end tag whose tag name is one of: "caption", "table", "tbody", + "tfoot", "thead", "tr", "td", "th" */ + } elseif (in_array( + $token['name'], + array( + 'caption', + 'table', + 'tbody', + 'tfoot', + 'thead', + 'tr', + 'td', + 'th' + ) + ) && $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. */ + // w/e + + /* If the stack of open elements has an element in table scope with + the same tag name as that of the token, then act as if an end tag + with the tag name "select" had been seen, and reprocess the token. + Otherwise, ignore the token. */ + if ($this->elementInScope($token['name'], true)) { + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + $this->mainPhase($token); + } + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterBody($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed if the insertion mode + was "in body". */ + $this->inBody($token); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the first element in the stack of open + elements (the html element), with the data attribute set to the + data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->stack[0]->appendChild($comment); + + /* An end tag with the tag name "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { + /* If the parser was originally created in order to handle the + setting of an element's innerHTML attribute, this is a parse error; + ignore the token. (The element will be an html element in this + case.) (innerHTML case) */ + + /* Otherwise, switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* Anything else */ + } else { + /* Parse error. Set the insertion mode to "in body" and reprocess + the token. */ + $this->mode = self::IN_BODY; + return $this->inBody($token); + } + } + + private function inFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::STARTTAG + ) { + $this->insertElement($token); + + /* An end tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::ENDTAG + ) { + /* If the current node is the root html element, then this is a + parse error; ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + } else { + /* Otherwise, pop the current node from the stack of open + elements. */ + array_pop($this->stack); + + /* If the parser was not originally created in order to handle + the setting of an element's innerHTML attribute (innerHTML case), + and the current node is no longer a frameset element, then change + the insertion mode to "after frameset". */ + $this->mode = self::AFTR_FRAME; + } + + /* A start tag with the tag name "frame" */ + } elseif ($token['name'] === 'frame' && + $token['type'] === HTML5::STARTTAG + ) { + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* An end tag with the tag name "html" */ + } elseif ($token['name'] === 'html' && + $token['type'] === HTML5::ENDTAG + ) { + /* Switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function trailingEndPhase($token) + { + /* After the main phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed in the main phase. */ + $this->mainPhase($token); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or a start tag token. Or an end tag token. */ + } elseif (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. Switch back to the main phase and reprocess the + token. */ + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* OMG DONE!! */ + } + } + + private function insertElement($token, $append = true, $check = false) + { + // Proprietary workaround for libxml2's limitations with tag names + if ($check) { + // Slightly modified HTML5 tag-name modification, + // removing anything that's not an ASCII letter, digit, or hyphen + $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); + // Remove leading hyphens and numbers + $token['name'] = ltrim($token['name'], '-0..9'); + // In theory, this should ever be needed, but just in case + if ($token['name'] === '') { + $token['name'] = 'span'; + } // arbitrary generic choice + } + + $el = $this->dom->createElement($token['name']); + + foreach ($token['attr'] as $attr) { + if (!$el->hasAttribute($attr['name'])) { + $el->setAttribute($attr['name'], $attr['value']); + } + } + + $this->appendToRealParent($el); + $this->stack[] = $el; + + return $el; + } + + private function insertText($data) + { + $text = $this->dom->createTextNode($data); + $this->appendToRealParent($text); + } + + private function insertComment($data) + { + $comment = $this->dom->createComment($data); + $this->appendToRealParent($comment); + } + + private function appendToRealParent($node) + { + if ($this->foster_parent === null) { + end($this->stack)->appendChild($node); + + } elseif ($this->foster_parent !== null) { + /* If the foster parent element is the parent element of the + last table element in the stack of open elements, then the new + node must be inserted immediately before the last table element + in the stack of open elements in the foster parent element; + otherwise, the new node must be appended to the foster parent + element. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table' && + $this->stack[$n]->parentNode !== null + ) { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) { + $this->foster_parent->insertBefore($node, $table); + } else { + $this->foster_parent->appendChild($node); + } + + $this->foster_parent = null; + } + } + + private function elementInScope($el, $table = false) + { + if (is_array($el)) { + foreach ($el as $element) { + if ($this->elementInScope($element, $table)) { + return true; + } + } + + return false; + } + + $leng = count($this->stack); + + for ($n = 0; $n < $leng; $n++) { + /* 1. Initialise node to be the current node (the bottommost node of + the stack). */ + $node = $this->stack[$leng - 1 - $n]; + + if ($node->tagName === $el) { + /* 2. If node is the target node, terminate in a match state. */ + return true; + + } elseif ($node->tagName === 'table') { + /* 3. Otherwise, if node is a table element, terminate in a failure + state. */ + return false; + + } elseif ($table === true && in_array( + $node->tagName, + array( + 'caption', + 'td', + 'th', + 'button', + 'marquee', + 'object' + ) + ) + ) { + /* 4. Otherwise, if the algorithm is the "has an element in scope" + variant (rather than the "has an element in table scope" variant), + and node is one of the following, terminate in a failure state. */ + return false; + + } elseif ($node === $node->ownerDocument->documentElement) { + /* 5. Otherwise, if node is an html element (root element), terminate + in a failure state. (This can only happen if the node is the topmost + node of the stack of open elements, and prevents the next step from + being invoked if there are no more elements in the stack.) */ + return false; + } + + /* Otherwise, set node to the previous entry in the stack of open + elements and return to step 2. (This will never fail, since the loop + will always terminate in the previous step if the top of the stack + is reached.) */ + } + } + + private function reconstructActiveFormattingElements() + { + /* 1. If there are no entries in the list of active formatting elements, + then there is nothing to reconstruct; stop this algorithm. */ + $formatting_elements = count($this->a_formatting); + + if ($formatting_elements === 0) { + return false; + } + + /* 3. Let entry be the last (most recently added) element in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. If the last (most recently added) entry in the list of active + formatting elements is a marker, or if it is an element that is in the + stack of open elements, then there is nothing to reconstruct; stop this + algorithm. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + return false; + } + + for ($a = $formatting_elements - 1; $a >= 0; true) { + /* 4. If there are no entries before entry in the list of active + formatting elements, then jump to step 8. */ + if ($a === 0) { + $step_seven = false; + break; + } + + /* 5. Let entry be the entry one earlier than entry in the list of + active formatting elements. */ + $a--; + $entry = $this->a_formatting[$a]; + + /* 6. If entry is neither a marker nor an element that is also in + thetack of open elements, go to step 4. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + break; + } + } + + while (true) { + /* 7. Let entry be the element one later than entry in the list of + active formatting elements. */ + if (isset($step_seven) && $step_seven === true) { + $a++; + $entry = $this->a_formatting[$a]; + } + + /* 8. Perform a shallow clone of the element entry to obtain clone. */ + $clone = $entry->cloneNode(); + + /* 9. Append clone to the current node and push it onto the stack + of open elements so that it is the new current node. */ + end($this->stack)->appendChild($clone); + $this->stack[] = $clone; + + /* 10. Replace the entry for entry in the list with an entry for + clone. */ + $this->a_formatting[$a] = $clone; + + /* 11. If the entry for clone in the list of active formatting + elements is not the last entry in the list, return to step 7. */ + if (end($this->a_formatting) !== $clone) { + $step_seven = true; + } else { + break; + } + } + } + + private function clearTheActiveFormattingElementsUpToTheLastMarker() + { + /* When the steps below require the UA to clear the list of active + formatting elements up to the last marker, the UA must perform the + following steps: */ + + while (true) { + /* 1. Let entry be the last (most recently added) entry in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. Remove entry from the list of active formatting elements. */ + array_pop($this->a_formatting); + + /* 3. If entry was a marker, then stop the algorithm at this point. + The list has been cleared up to the last marker. */ + if ($entry === self::MARKER) { + break; + } + } + } + + private function generateImpliedEndTags($exclude = array()) + { + /* When the steps below require the UA to generate implied end tags, + then, if the current node is a dd element, a dt element, an li element, + a p element, a td element, a th element, or a tr element, the UA must + act as if an end tag with the respective tag name had been seen and + then generate implied end tags again. */ + $node = end($this->stack); + $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); + + while (in_array(end($this->stack)->nodeName, $elements)) { + array_pop($this->stack); + } + } + + private function getElementCategory($node) + { + $name = $node->tagName; + if (in_array($name, $this->special)) { + return self::SPECIAL; + } elseif (in_array($name, $this->scoping)) { + return self::SCOPING; + } elseif (in_array($name, $this->formatting)) { + return self::FORMATTING; + } else { + return self::PHRASING; + } + } + + private function clearStackToTableContext($elements) + { + /* When the steps above require the UA to clear the stack back to a + table context, it means that the UA must, while the current node is not + a table element or an html element, pop elements from the stack of open + elements. If this causes any elements to be popped from the stack, then + this is a parse error. */ + while (true) { + $node = end($this->stack)->nodeName; + + if (in_array($node, $elements)) { + break; + } else { + array_pop($this->stack); + } + } + } + + private function resetInsertionMode() + { + /* 1. Let last be false. */ + $last = false; + $leng = count($this->stack); + + for ($n = $leng - 1; $n >= 0; $n--) { + /* 2. Let node be the last node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 3. If node is the first node in the stack of open elements, then + set last to true. If the element whose innerHTML attribute is being + set is neither a td element nor a th element, then set node to the + element whose innerHTML attribute is being set. (innerHTML case) */ + if ($this->stack[0]->isSameNode($node)) { + $last = true; + } + + /* 4. If node is a select element, then switch the insertion mode to + "in select" and abort these steps. (innerHTML case) */ + if ($node->nodeName === 'select') { + $this->mode = self::IN_SELECT; + break; + + /* 5. If node is a td or th element, then switch the insertion mode + to "in cell" and abort these steps. */ + } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') { + $this->mode = self::IN_CELL; + break; + + /* 6. If node is a tr element, then switch the insertion mode to + "in row" and abort these steps. */ + } elseif ($node->nodeName === 'tr') { + $this->mode = self::IN_ROW; + break; + + /* 7. If node is a tbody, thead, or tfoot element, then switch the + insertion mode to "in table body" and abort these steps. */ + } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { + $this->mode = self::IN_TBODY; + break; + + /* 8. If node is a caption element, then switch the insertion mode + to "in caption" and abort these steps. */ + } elseif ($node->nodeName === 'caption') { + $this->mode = self::IN_CAPTION; + break; + + /* 9. If node is a colgroup element, then switch the insertion mode + to "in column group" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'colgroup') { + $this->mode = self::IN_CGROUP; + break; + + /* 10. If node is a table element, then switch the insertion mode + to "in table" and abort these steps. */ + } elseif ($node->nodeName === 'table') { + $this->mode = self::IN_TABLE; + break; + + /* 11. If node is a head element, then switch the insertion mode + to "in body" ("in body"! not "in head"!) and abort these steps. + (innerHTML case) */ + } elseif ($node->nodeName === 'head') { + $this->mode = self::IN_BODY; + break; + + /* 12. If node is a body element, then switch the insertion mode to + "in body" and abort these steps. */ + } elseif ($node->nodeName === 'body') { + $this->mode = self::IN_BODY; + break; + + /* 13. If node is a frameset element, then switch the insertion + mode to "in frameset" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'frameset') { + $this->mode = self::IN_FRAME; + break; + + /* 14. If node is an html element, then: if the head element + pointer is null, switch the insertion mode to "before head", + otherwise, switch the insertion mode to "after head". In either + case, abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'html') { + $this->mode = ($this->head_pointer === null) + ? self::BEFOR_HEAD + : self::AFTER_HEAD; + + break; + + /* 15. If last is true, then set the insertion mode to "in body" + and abort these steps. (innerHTML case) */ + } elseif ($last) { + $this->mode = self::IN_BODY; + break; + } + } + } + + private function closeCell() + { + /* If the stack of open elements has a td or th element in table scope, + then act as if an end tag token with that tag name had been seen. */ + foreach (array('td', 'th') as $cell) { + if ($this->elementInScope($cell, true)) { + $this->inCell( + array( + 'name' => $cell, + 'type' => HTML5::ENDTAG + ) + ); + + break; + } + } + } + + public function save() + { + return $this->dom; + } +} diff --git a/library/vendor/HTMLPurifier/Node.php b/library/vendor/HTMLPurifier/Node.php new file mode 100644 index 000000000..3995fec9f --- /dev/null +++ b/library/vendor/HTMLPurifier/Node.php @@ -0,0 +1,49 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Comment($this->data, $this->line, $this->col), null); + } +} diff --git a/library/vendor/HTMLPurifier/Node/Element.php b/library/vendor/HTMLPurifier/Node/Element.php new file mode 100644 index 000000000..6cbf56dad --- /dev/null +++ b/library/vendor/HTMLPurifier/Node/Element.php @@ -0,0 +1,59 @@ + form or the form, i.e. + * is it a pair of start/end tokens or an empty token. + * @bool + */ + public $empty = false; + + public $endCol = null, $endLine = null, $endArmor = array(); + + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) { + $this->name = $name; + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toTokenPair() { + // XXX inefficiency here, normalization is not necessary + if ($this->empty) { + return array(new HTMLPurifier_Token_Empty($this->name, $this->attr, $this->line, $this->col, $this->armor), null); + } else { + $start = new HTMLPurifier_Token_Start($this->name, $this->attr, $this->line, $this->col, $this->armor); + $end = new HTMLPurifier_Token_End($this->name, array(), $this->endLine, $this->endCol, $this->endArmor); + //$end->start = $start; + return array($start, $end); + } + } +} + diff --git a/library/vendor/HTMLPurifier/Node/Text.php b/library/vendor/HTMLPurifier/Node/Text.php new file mode 100644 index 000000000..aec916647 --- /dev/null +++ b/library/vendor/HTMLPurifier/Node/Text.php @@ -0,0 +1,54 @@ +data = $data; + $this->is_whitespace = $is_whitespace; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Text($this->data, $this->line, $this->col), null); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/PercentEncoder.php b/library/vendor/HTMLPurifier/PercentEncoder.php new file mode 100644 index 000000000..18c8bbb00 --- /dev/null +++ b/library/vendor/HTMLPurifier/PercentEncoder.php @@ -0,0 +1,111 @@ +preserve[$i] = true; + } + for ($i = 65; $i <= 90; $i++) { // upper-case + $this->preserve[$i] = true; + } + for ($i = 97; $i <= 122; $i++) { // lower-case + $this->preserve[$i] = true; + } + $this->preserve[45] = true; // Dash - + $this->preserve[46] = true; // Period . + $this->preserve[95] = true; // Underscore _ + $this->preserve[126]= true; // Tilde ~ + + // extra letters not to escape + if ($preserve !== false) { + for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { + $this->preserve[ord($preserve[$i])] = true; + } + } + } + + /** + * Our replacement for urlencode, it encodes all non-reserved characters, + * as well as any extra characters that were instructed to be preserved. + * @note + * Assumes that the string has already been normalized, making any + * and all percent escape sequences valid. Percents will not be + * re-escaped, regardless of their status in $preserve + * @param string $string String to be encoded + * @return string Encoded string. + */ + public function encode($string) + { + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])])) { + $ret .= '%' . sprintf('%02X', $int); + } else { + $ret .= $string[$i]; + } + } + return $ret; + } + + /** + * Fix up percent-encoding by decoding unreserved characters and normalizing. + * @warning This function is affected by $preserve, even though the + * usual desired behavior is for this not to preserve those + * characters. Be careful when reusing instances of PercentEncoder! + * @param string $string String to normalize + * @return string + */ + public function normalize($string) + { + if ($string == '') { + return ''; + } + $parts = explode('%', $string); + $ret = array_shift($parts); + foreach ($parts as $part) { + $length = strlen($part); + if ($length < 2) { + $ret .= '%25' . $part; + continue; + } + $encoding = substr($part, 0, 2); + $text = substr($part, 2); + if (!ctype_xdigit($encoding)) { + $ret .= '%25' . $part; + continue; + } + $int = hexdec($encoding); + if (isset($this->preserve[$int])) { + $ret .= chr($int) . $text; + continue; + } + $encoding = strtoupper($encoding); + $ret .= '%' . $encoding . $text; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Printer.php b/library/vendor/HTMLPurifier/Printer.php new file mode 100644 index 000000000..549e4cea1 --- /dev/null +++ b/library/vendor/HTMLPurifier/Printer.php @@ -0,0 +1,218 @@ +getAll(); + $context = new HTMLPurifier_Context(); + $this->generator = new HTMLPurifier_Generator($config, $context); + } + + /** + * Main function that renders object or aspect of that object + * @note Parameters vary depending on printer + */ + // function render() {} + + /** + * Returns a start tag + * @param string $tag Tag name + * @param array $attr Attribute array + * @return string + */ + protected function start($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) + ); + } + + /** + * Returns an end tag + * @param string $tag Tag name + * @return string + */ + protected function end($tag) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_End($tag) + ); + } + + /** + * Prints a complete element with content inside + * @param string $tag Tag name + * @param string $contents Element contents + * @param array $attr Tag attributes + * @param bool $escape whether or not to escape contents + * @return string + */ + protected function element($tag, $contents, $attr = array(), $escape = true) + { + return $this->start($tag, $attr) . + ($escape ? $this->escape($contents) : $contents) . + $this->end($tag); + } + + /** + * @param string $tag + * @param array $attr + * @return string + */ + protected function elementEmpty($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Empty($tag, $attr) + ); + } + + /** + * @param string $text + * @return string + */ + protected function text($text) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Text($text) + ); + } + + /** + * Prints a simple key/value row in a table. + * @param string $name Key + * @param mixed $value Value + * @return string + */ + protected function row($name, $value) + { + if (is_bool($value)) { + $value = $value ? 'On' : 'Off'; + } + return + $this->start('tr') . "\n" . + $this->element('th', $name) . "\n" . + $this->element('td', $value) . "\n" . + $this->end('tr'); + } + + /** + * Escapes a string for HTML output. + * @param string $string String to escape + * @return string + */ + protected function escape($string) + { + $string = HTMLPurifier_Encoder::cleanUTF8($string); + $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); + return $string; + } + + /** + * Takes a list of strings and turns them into a single list + * @param string[] $array List of strings + * @param bool $polite Bool whether or not to add an end before the last + * @return string + */ + protected function listify($array, $polite = false) + { + if (empty($array)) { + return 'None'; + } + $ret = ''; + $i = count($array); + foreach ($array as $value) { + $i--; + $ret .= $value; + if ($i > 0 && !($polite && $i == 1)) { + $ret .= ', '; + } + if ($polite && $i == 1) { + $ret .= 'and '; + } + } + return $ret; + } + + /** + * Retrieves the class of an object without prefixes, as well as metadata + * @param object $obj Object to determine class of + * @param string $sec_prefix Further prefix to remove + * @return string + */ + protected function getClass($obj, $sec_prefix = '') + { + static $five = null; + if ($five === null) { + $five = version_compare(PHP_VERSION, '5', '>='); + } + $prefix = 'HTMLPurifier_' . $sec_prefix; + if (!$five) { + $prefix = strtolower($prefix); + } + $class = str_replace($prefix, '', get_class($obj)); + $lclass = strtolower($class); + $class .= '('; + switch ($lclass) { + case 'enum': + $values = array(); + foreach ($obj->valid_values as $value => $bool) { + $values[] = $value; + } + $class .= implode(', ', $values); + break; + case 'css_composite': + $values = array(); + foreach ($obj->defs as $def) { + $values[] = $this->getClass($def, $sec_prefix); + } + $class .= implode(', ', $values); + break; + case 'css_multiple': + $class .= $this->getClass($obj->single, $sec_prefix) . ', '; + $class .= $obj->max; + break; + case 'css_denyelementdecorator': + $class .= $this->getClass($obj->def, $sec_prefix) . ', '; + $class .= $obj->element; + break; + case 'css_importantdecorator': + $class .= $this->getClass($obj->def, $sec_prefix); + if ($obj->allow) { + $class .= ', !important'; + } + break; + } + $class .= ')'; + return $class; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Printer/CSSDefinition.php b/library/vendor/HTMLPurifier/Printer/CSSDefinition.php new file mode 100644 index 000000000..29505fe12 --- /dev/null +++ b/library/vendor/HTMLPurifier/Printer/CSSDefinition.php @@ -0,0 +1,44 @@ +def = $config->getCSSDefinition(); + $ret = ''; + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + $ret .= $this->start('table'); + + $ret .= $this->element('caption', 'Properties ($info)'); + + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Property', array('class' => 'heavy')); + $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + + ksort($this->def->info); + foreach ($this->def->info as $property => $obj) { + $name = $this->getClass($obj, 'AttrDef_'); + $ret .= $this->row($property, $name); + } + + $ret .= $this->end('table'); + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/ConfigForm.css b/library/vendor/HTMLPurifier/Printer/ConfigForm.css similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/ConfigForm.css rename to library/vendor/HTMLPurifier/Printer/ConfigForm.css diff --git a/library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/ConfigForm.js b/library/vendor/HTMLPurifier/Printer/ConfigForm.js similarity index 100% rename from library/IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier/Printer/ConfigForm.js rename to library/vendor/HTMLPurifier/Printer/ConfigForm.js diff --git a/library/vendor/HTMLPurifier/Printer/ConfigForm.php b/library/vendor/HTMLPurifier/Printer/ConfigForm.php new file mode 100644 index 000000000..36100ce73 --- /dev/null +++ b/library/vendor/HTMLPurifier/Printer/ConfigForm.php @@ -0,0 +1,447 @@ +docURL = $doc_url; + $this->name = $name; + $this->compress = $compress; + // initialize sub-printers + $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); + $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); + } + + /** + * Sets default column and row size for textareas in sub-printers + * @param $cols Integer columns of textarea, null to use default + * @param $rows Integer rows of textarea, null to use default + */ + public function setTextareaDimensions($cols = null, $rows = null) + { + if ($cols) { + $this->fields['default']->cols = $cols; + } + if ($rows) { + $this->fields['default']->rows = $rows; + } + } + + /** + * Retrieves styling, in case it is not accessible by webserver + */ + public static function getCSS() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); + } + + /** + * Retrieves JavaScript, in case it is not accessible by webserver + */ + public static function getJavaScript() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); + } + + /** + * Returns HTML output for a configuration form + * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array + * where [0] has an HTML namespace and [1] is being rendered. + * @param array|bool $allowed Optional namespace(s) and directives to restrict form to. + * @param bool $render_controls + * @return string + */ + public function render($config, $allowed = true, $render_controls = true) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + + $this->config = $config; + $this->genConfig = $gen_config; + $this->prepareGenerator($gen_config); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); + $all = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $all[$ns][$directive] = $config->get($ns . '.' . $directive); + } + + $ret = ''; + $ret .= $this->start('table', array('class' => 'hp-config')); + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); + $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + foreach ($all as $ns => $directives) { + $ret .= $this->renderNamespace($ns, $directives); + } + if ($render_controls) { + $ret .= $this->start('tbody'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a single namespace + * @param $ns String namespace name + * @param array $directives array of directives to values + * @return string + */ + protected function renderNamespace($ns, $directives) + { + $ret = ''; + $ret .= $this->start('tbody', array('class' => 'namespace')); + $ret .= $this->start('tr'); + $ret .= $this->element('th', $ns, array('colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + $ret .= $this->start('tbody'); + foreach ($directives as $directive => $value) { + $ret .= $this->start('tr'); + $ret .= $this->start('th'); + if ($this->docURL) { + $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); + $ret .= $this->start('a', array('href' => $url)); + } + $attr = array('for' => "{$this->name}:$ns.$directive"); + + // crop directive name if it's too long + if (!$this->compress || (strlen($directive) < $this->compress)) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; + $attr['title'] = $directive; + } + + $ret .= $this->element( + 'label', + $directive_disp, + // component printers must create an element with this id + $attr + ); + if ($this->docURL) { + $ret .= $this->end('a'); + } + $ret .= $this->end('th'); + + $ret .= $this->start('td'); + $def = $this->config->def->info["$ns.$directive"]; + if (is_int($def)) { + $allow_null = $def < 0; + $type = abs($def); + } else { + $type = $def->type; + $allow_null = isset($def->allow_null); + } + if (!isset($this->fields[$type])) { + $type = 0; + } // default + $type_obj = $this->fields[$type]; + if ($allow_null) { + $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); + } + $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + } + $ret .= $this->end('tbody'); + return $ret; + } + +} + +/** + * Printer decorator for directives that accept null + */ +class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer +{ + /** + * Printer being decorated + * @type HTMLPurifier_Printer + */ + protected $obj; + + /** + * @param HTMLPurifier_Printer $obj Printer to decorate + */ + public function __construct($obj) + { + parent::__construct(); + $this->obj = $obj; + } + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + + $ret = ''; + $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Null/Disabled'); + $ret .= $this->end('label'); + $attr = array( + 'type' => 'checkbox', + 'value' => '1', + 'class' => 'null-toggle', + 'name' => "$name" . "[Null_$ns.$directive]", + 'id' => "$name:Null_$ns.$directive", + 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! + ); + if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { + // modify inline javascript slightly + $attr['onclick'] = + "toggleWriteability('$name:Yes_$ns.$directive',checked);" . + "toggleWriteability('$name:No_$ns.$directive',checked)"; + } + if ($value === null) { + $attr['checked'] = 'checked'; + } + $ret .= $this->elementEmpty('input', $attr); + $ret .= $this->text(' or '); + $ret .= $this->elementEmpty('br'); + $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); + return $ret; + } +} + +/** + * Swiss-army knife configuration form field printer + */ +class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer +{ + /** + * @type int + */ + public $cols = 18; + + /** + * @type int + */ + public $rows = 5; + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + // this should probably be split up a little + $ret = ''; + $def = $config->def->info["$ns.$directive"]; + if (is_int($def)) { + $type = abs($def); + } else { + $type = $def->type; + } + if (is_array($value)) { + switch ($type) { + case HTMLPurifier_VarParser::LOOKUP: + $array = $value; + $value = array(); + foreach ($array as $val => $b) { + $value[] = $val; + } + //TODO does this need a break? + case HTMLPurifier_VarParser::ALIST: + $value = implode(PHP_EOL, $value); + break; + case HTMLPurifier_VarParser::HASH: + $nvalue = ''; + foreach ($value as $i => $v) { + $nvalue .= "$i:$v" . PHP_EOL; + } + $value = $nvalue; + break; + default: + $value = ''; + } + } + if ($type === HTMLPurifier_VarParser::MIXED) { + return 'Not supported'; + $value = serialize($value); + } + $attr = array( + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:$ns.$directive" + ); + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + if (isset($def->allowed)) { + $ret .= $this->start('select', $attr); + foreach ($def->allowed as $val => $b) { + $attr = array(); + if ($value == $val) { + $attr['selected'] = 'selected'; + } + $ret .= $this->element('option', $val, $attr); + } + $ret .= $this->end('select'); + } elseif ($type === HTMLPurifier_VarParser::TEXT || + $type === HTMLPurifier_VarParser::ITEXT || + $type === HTMLPurifier_VarParser::ALIST || + $type === HTMLPurifier_VarParser::HASH || + $type === HTMLPurifier_VarParser::LOOKUP) { + $attr['cols'] = $this->cols; + $attr['rows'] = $this->rows; + $ret .= $this->start('textarea', $attr); + $ret .= $this->text($value); + $ret .= $this->end('textarea'); + } else { + $attr['value'] = $value; + $attr['type'] = 'text'; + $ret .= $this->elementEmpty('input', $attr); + } + return $ret; + } +} + +/** + * Bool form field printer + */ +class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer +{ + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + $ret = ''; + $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); + + $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Yes'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:Yes_$ns.$directive", + 'value' => '1' + ); + if ($value === true) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' No'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:No_$ns.$directive", + 'value' => '0' + ); + if ($value === false) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Printer/HTMLDefinition.php b/library/vendor/HTMLPurifier/Printer/HTMLDefinition.php new file mode 100644 index 000000000..5f2f2f8a7 --- /dev/null +++ b/library/vendor/HTMLPurifier/Printer/HTMLDefinition.php @@ -0,0 +1,324 @@ +config =& $config; + + $this->def = $config->getHTMLDefinition(); + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + + $ret .= $this->renderDoctype(); + $ret .= $this->renderEnvironment(); + $ret .= $this->renderContentSets(); + $ret .= $this->renderInfo(); + + $ret .= $this->end('div'); + + return $ret; + } + + /** + * Renders the Doctype table + * @return string + */ + protected function renderDoctype() + { + $doctype = $this->def->doctype; + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Doctype'); + $ret .= $this->row('Name', $doctype->name); + $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); + $ret .= $this->row('Default Modules', implode($doctype->modules, ', ')); + $ret .= $this->row('Default Tidy Modules', implode($doctype->tidyModules, ', ')); + $ret .= $this->end('table'); + return $ret; + } + + + /** + * Renders environment table, which is miscellaneous info + * @return string + */ + protected function renderEnvironment() + { + $def = $this->def; + + $ret = ''; + + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Environment'); + + $ret .= $this->row('Parent of fragment', $def->info_parent); + $ret .= $this->renderChildren($def->info_parent_def->child); + $ret .= $this->row('Block wrap name', $def->info_block_wrapper); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Global attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Tag transforms'); + $list = array(); + foreach ($def->info_tag_transform as $old => $new) { + $new = $this->getClass($new, 'TagTransform_'); + $list[] = "<$old> with $new"; + } + $ret .= $this->element('td', $this->listify($list)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); + $ret .= $this->end('tr'); + + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Content Sets table + * @return string + */ + protected function renderContentSets() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Content Sets'); + foreach ($this->def->info_content_sets as $name => $lookup) { + $ret .= $this->heavyHeader($name); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($lookup)); + $ret .= $this->end('tr'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Elements ($info) table + * @return string + */ + protected function renderInfo() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Elements ($info)'); + ksort($this->def->info); + $ret .= $this->heavyHeader('Allowed tags', 2); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); + $ret .= $this->end('tr'); + foreach ($this->def->info as $name => $def) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Inline content'); + $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); + $ret .= $this->end('tr'); + if (!empty($def->excludes)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Excludes'); + $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_pre)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_post)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); + $ret .= $this->end('tr'); + } + if (!empty($def->auto_close)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Auto closed by'); + $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); + $ret .= $this->end('tr'); + } + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Allowed attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0); + $ret .= $this->end('tr'); + + if (!empty($def->required_attr)) { + $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); + } + + $ret .= $this->renderChildren($def->child); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a row describing the allowed children of an element + * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element + * @return string + */ + protected function renderChildren($def) + { + $context = new HTMLPurifier_Context(); + $ret = ''; + $ret .= $this->start('tr'); + $elements = array(); + $attr = array(); + if (isset($def->elements)) { + if ($def->type == 'strictblockquote') { + $def->validateChildren(array(), $this->config, $context); + } + $elements = $def->elements; + } + if ($def->type == 'chameleon') { + $attr['rowspan'] = 2; + } elseif ($def->type == 'empty') { + $elements = array(); + } elseif ($def->type == 'table') { + $elements = array_flip( + array( + 'col', + 'caption', + 'colgroup', + 'thead', + 'tfoot', + 'tbody', + 'tr' + ) + ); + } + $ret .= $this->element('th', 'Allowed children', $attr); + + if ($def->type == 'chameleon') { + + $ret .= $this->element( + 'td', + 'Block: ' . + $this->escape($this->listifyTagLookup($def->block->elements)), + null, + 0 + ); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element( + 'td', + 'Inline: ' . + $this->escape($this->listifyTagLookup($def->inline->elements)), + null, + 0 + ); + + } elseif ($def->type == 'custom') { + + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $def->dtd_regex + ); + + } else { + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $this->escape($this->listifyTagLookup($elements)), + null, + 0 + ); + } + $ret .= $this->end('tr'); + return $ret; + } + + /** + * Listifies a tag lookup table. + * @param array $array Tag lookup array in form of array('tagname' => true) + * @return string + */ + protected function listifyTagLookup($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $discard) { + if ($name !== '#PCDATA' && !isset($this->def->info[$name])) { + continue; + } + $list[] = $name; + } + return $this->listify($list); + } + + /** + * Listifies a list of objects by retrieving class names and internal state + * @param array $array List of objects + * @return string + * @todo Also add information about internal state + */ + protected function listifyObjectList($array) + { + ksort($array); + $list = array(); + foreach ($array as $obj) { + $list[] = $this->getClass($obj, 'AttrTransform_'); + } + return $this->listify($list); + } + + /** + * Listifies a hash of attributes to AttrDef classes + * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + * @return string + */ + protected function listifyAttr($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $obj) { + if ($obj === false) { + continue; + } + $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; + } + return $this->listify($list); + } + + /** + * Creates a heavy header row + * @param string $text + * @param int $num + * @return string + */ + protected function heavyHeader($text, $num = 1) + { + $ret = ''; + $ret .= $this->start('tr'); + $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); + $ret .= $this->end('tr'); + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/PropertyList.php b/library/vendor/HTMLPurifier/PropertyList.php new file mode 100644 index 000000000..189348fd9 --- /dev/null +++ b/library/vendor/HTMLPurifier/PropertyList.php @@ -0,0 +1,122 @@ +parent = $parent; + } + + /** + * Recursively retrieves the value for a key + * @param string $name + * @throws HTMLPurifier_Exception + */ + public function get($name) + { + if ($this->has($name)) { + return $this->data[$name]; + } + // possible performance bottleneck, convert to iterative if necessary + if ($this->parent) { + return $this->parent->get($name); + } + throw new HTMLPurifier_Exception("Key '$name' not found"); + } + + /** + * Sets the value of a key, for this plist + * @param string $name + * @param mixed $value + */ + public function set($name, $value) + { + $this->data[$name] = $value; + } + + /** + * Returns true if a given key exists + * @param string $name + * @return bool + */ + public function has($name) + { + return array_key_exists($name, $this->data); + } + + /** + * Resets a value to the value of it's parent, usually the default. If + * no value is specified, the entire plist is reset. + * @param string $name + */ + public function reset($name = null) + { + if ($name == null) { + $this->data = array(); + } else { + unset($this->data[$name]); + } + } + + /** + * Squashes this property list and all of its property lists into a single + * array, and returns the array. This value is cached by default. + * @param bool $force If true, ignores the cache and regenerates the array. + * @return array + */ + public function squash($force = false) + { + if ($this->cache !== null && !$force) { + return $this->cache; + } + if ($this->parent) { + return $this->cache = array_merge($this->parent->squash($force), $this->data); + } else { + return $this->cache = $this->data; + } + } + + /** + * Returns the parent plist. + * @return HTMLPurifier_PropertyList + */ + public function getParent() + { + return $this->parent; + } + + /** + * Sets the parent plist. + * @param HTMLPurifier_PropertyList $plist Parent plist + */ + public function setParent($plist) + { + $this->parent = $plist; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/PropertyListIterator.php b/library/vendor/HTMLPurifier/PropertyListIterator.php new file mode 100644 index 000000000..15b330ea3 --- /dev/null +++ b/library/vendor/HTMLPurifier/PropertyListIterator.php @@ -0,0 +1,42 @@ +l = strlen($filter); + $this->filter = $filter; + } + + /** + * @return bool + */ + public function accept() + { + $key = $this->getInnerIterator()->key(); + if (strncmp($key, $this->filter, $this->l) !== 0) { + return false; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Queue.php b/library/vendor/HTMLPurifier/Queue.php new file mode 100644 index 000000000..f58db9042 --- /dev/null +++ b/library/vendor/HTMLPurifier/Queue.php @@ -0,0 +1,56 @@ +input = $input; + $this->output = array(); + } + + /** + * Shifts an element off the front of the queue. + */ + public function shift() { + if (empty($this->output)) { + $this->output = array_reverse($this->input); + $this->input = array(); + } + if (empty($this->output)) { + return NULL; + } + return array_pop($this->output); + } + + /** + * Pushes an element onto the front of the queue. + */ + public function push($x) { + array_push($this->input, $x); + } + + /** + * Checks if it's empty. + */ + public function isEmpty() { + return empty($this->input) && empty($this->output); + } +} diff --git a/library/vendor/HTMLPurifier/SOURCE b/library/vendor/HTMLPurifier/SOURCE new file mode 100644 index 000000000..034876b50 --- /dev/null +++ b/library/vendor/HTMLPurifier/SOURCE @@ -0,0 +1,5 @@ +curl https://codeload.github.com/ezyang/htmlpurifier/tar.gz/v4.6.0 -o htmlpurifier-4.6.0.tar.gz +tar xzf htmlpurifier-4.6.0.tar.gz --strip-components 1 htmlpurifier-4.6.0/LICENSE +tar xzf htmlpurifier-4.6.0.tar.gz --strip-components 2 htmlpurifier-4.6.0/library/*.php +tar xzf htmlpurifier-4.6.0.tar.gz --strip-components 3 htmlpurifier-4.6.0/library/HTMLPurifier/* +rm htmlpurifier-4.6.0.tar.gz diff --git a/library/vendor/HTMLPurifier/Strategy.php b/library/vendor/HTMLPurifier/Strategy.php new file mode 100644 index 000000000..e1ff3b72d --- /dev/null +++ b/library/vendor/HTMLPurifier/Strategy.php @@ -0,0 +1,26 @@ +strategies as $strategy) { + $tokens = $strategy->execute($tokens, $config, $context); + } + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Strategy/Core.php b/library/vendor/HTMLPurifier/Strategy/Core.php new file mode 100644 index 000000000..4414c17d6 --- /dev/null +++ b/library/vendor/HTMLPurifier/Strategy/Core.php @@ -0,0 +1,17 @@ +strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); + $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); + $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Strategy/FixNesting.php b/library/vendor/HTMLPurifier/Strategy/FixNesting.php new file mode 100644 index 000000000..6fa673db9 --- /dev/null +++ b/library/vendor/HTMLPurifier/Strategy/FixNesting.php @@ -0,0 +1,181 @@ +getHTMLDefinition(); + + $excludes_enabled = !$config->get('Core.DisableExcludes'); + + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree + $is_inline = $definition->info_parent_def->descendants_are_inline; + $context->register('IsInline', $is_inline); + + // setup error collector + $e =& $context->get('ErrorCollector', true); + + //####################################################################// + // Loop initialization + + // stack that contains all elements that are excluded + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. + $exclude_stack = array($definition->info_parent_def->excludes); + + // variable that contains the start token while we are processing + // nodes. This enables error reporting to do its job + $node = $top_node; + // dummy token + list($token, $d) = $node->toTokenPair(); + $context->register('CurrentNode', $node); + $context->register('CurrentToken', $token); + + //####################################################################// + // Loop + + // We need to implement a post-order traversal iteratively, to + // avoid running into stack space limits. This is pretty tricky + // to reason about, so we just manually stack-ify the recursive + // variant: + // + // function f($node) { + // foreach ($node->children as $child) { + // f($child); + // } + // validate($node); + // } + // + // Thus, we will represent a stack frame as array($node, + // $is_inline, stack of children) + // e.g. array_reverse($node->children) - already processed + // children. + + $parent_def = $definition->info_parent_def; + $stack = array( + array($top_node, + $parent_def->descendants_are_inline, + $parent_def->excludes, // exclusions + 0) + ); + + while (!empty($stack)) { + list($node, $is_inline, $excludes, $ix) = array_pop($stack); + // recursive call + $go = false; + $def = empty($stack) ? $definition->info_parent_def : $definition->info[$node->name]; + while (isset($node->children[$ix])) { + $child = $node->children[$ix++]; + if ($child instanceof HTMLPurifier_Node_Element) { + $go = true; + $stack[] = array($node, $is_inline, $excludes, $ix); + $stack[] = array($child, + // ToDo: I don't think it matters if it's def or + // child_def, but double check this... + $is_inline || $def->descendants_are_inline, + empty($def->excludes) ? $excludes + : array_merge($excludes, $def->excludes), + 0); + break; + } + }; + if ($go) continue; + list($token, $d) = $node->toTokenPair(); + // base case + if ($excludes_enabled && isset($excludes[$node->name])) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); + } else { + // XXX I suppose it would be slightly more efficient to + // avoid the allocation here and have children + // strategies handle it + $children = array(); + foreach ($node->children as $child) { + if (!$child->dead) $children[] = $child; + } + $result = $def->child->validateChildren($children, $config, $context); + if ($result === true) { + // nop + $node->children = $children; + } elseif ($result === false) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); + } else { + $node->children = $result; + if ($e) { + // XXX This will miss mutations of internal nodes. Perhaps defer to the child validators + if (empty($result) && !empty($children)) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + } else if ($result != $children) { + $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + } + } + } + } + } + + //####################################################################// + // Post-processing + + // remove context variables + $context->destroy('IsInline'); + $context->destroy('CurrentNode'); + $context->destroy('CurrentToken'); + + //####################################################################// + // Return + + return HTMLPurifier_Arborize::flatten($node, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Strategy/MakeWellFormed.php b/library/vendor/HTMLPurifier/Strategy/MakeWellFormed.php new file mode 100644 index 000000000..e389e0011 --- /dev/null +++ b/library/vendor/HTMLPurifier/Strategy/MakeWellFormed.php @@ -0,0 +1,600 @@ +getHTMLDefinition(); + + // local variables + $generator = new HTMLPurifier_Generator($config, $context); + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + // used for autoclose early abortion + $global_parent_allowed_elements = $definition->info_parent_def->child->getAllowedElements($config); + $e = $context->get('ErrorCollector', true); + $i = false; // injector index + list($zipper, $token) = HTMLPurifier_Zipper::fromArray($tokens); + if ($token === NULL) { + return array(); + } + $reprocess = false; // whether or not to reprocess the same token + $stack = array(); + + // member variables + $this->stack =& $stack; + $this->tokens =& $tokens; + $this->token =& $token; + $this->zipper =& $zipper; + $this->config = $config; + $this->context = $context; + + // context variables + $context->register('CurrentNesting', $stack); + $context->register('InputZipper', $zipper); + $context->register('CurrentToken', $token); + + // -- begin INJECTOR -- + + $this->injectors = array(); + + $injectors = $config->getBatch('AutoFormat'); + $def_injectors = $definition->info_injector; + $custom_injectors = $injectors['Custom']; + unset($injectors['Custom']); // special case + foreach ($injectors as $injector => $b) { + // XXX: Fix with a legitimate lookup table of enabled filters + if (strpos($injector, '.') !== false) { + continue; + } + $injector = "HTMLPurifier_Injector_$injector"; + if (!$b) { + continue; + } + $this->injectors[] = new $injector; + } + foreach ($def_injectors as $injector) { + // assumed to be objects + $this->injectors[] = $injector; + } + foreach ($custom_injectors as $injector) { + if (!$injector) { + continue; + } + if (is_string($injector)) { + $injector = "HTMLPurifier_Injector_$injector"; + $injector = new $injector; + } + $this->injectors[] = $injector; + } + + // give the injectors references to the definition and context + // variables for performance reasons + foreach ($this->injectors as $ix => $injector) { + $error = $injector->prepare($config, $context); + if (!$error) { + continue; + } + array_splice($this->injectors, $ix, 1); // rm the injector + trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); + } + + // -- end INJECTOR -- + + // a note on reprocessing: + // In order to reduce code duplication, whenever some code needs + // to make HTML changes in order to make things "correct", the + // new HTML gets sent through the purifier, regardless of its + // status. This means that if we add a start token, because it + // was totally necessary, we don't have to update nesting; we just + // punt ($reprocess = true; continue;) and it does that for us. + + // isset is in loop because $tokens size changes during loop exec + for (;; + // only increment if we don't need to reprocess + $reprocess ? $reprocess = false : $token = $zipper->next($token)) { + + // check for a rewind + if (is_int($i)) { + // possibility: disable rewinding if the current token has a + // rewind set on it already. This would offer protection from + // infinite loop, but might hinder some advanced rewinding. + $rewind_offset = $this->injectors[$i]->getRewindOffset(); + if (is_int($rewind_offset)) { + for ($j = 0; $j < $rewind_offset; $j++) { + if (empty($zipper->front)) break; + $token = $zipper->prev($token); + // indicate that other injectors should not process this token, + // but we need to reprocess it + unset($token->skip[$i]); + $token->rewind = $i; + if ($token instanceof HTMLPurifier_Token_Start) { + array_pop($this->stack); + } elseif ($token instanceof HTMLPurifier_Token_End) { + $this->stack[] = $token->start; + } + } + } + $i = false; + } + + // handle case of document end + if ($token === NULL) { + // kill processing if stack is empty + if (empty($this->stack)) { + break; + } + + // peek + $top_nesting = array_pop($this->stack); + $this->stack[] = $top_nesting; + + // send error [TagClosedSuppress] + if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); + } + + // append, don't splice, since this is the end + $token = new HTMLPurifier_Token_End($top_nesting->name); + + // punt! + $reprocess = true; + continue; + } + + //echo '
          '; printZipper($zipper, $token);//printTokens($this->stack); + //flush(); + + // quick-check: if it's not a tag, no need to process + if (empty($token->is_tag)) { + if ($token instanceof HTMLPurifier_Token_Text) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + // XXX fuckup + $r = $token; + $injector->handleText($r); + $token = $this->processToken($r, $i); + $reprocess = true; + break; + } + } + // another possibility is a comment + continue; + } + + if (isset($definition->info[$token->name])) { + $type = $definition->info[$token->name]->child->type; + } else { + $type = false; // Type is unknown, treat accordingly + } + + // quick tag checks: anything that's *not* an end tag + $ok = false; + if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { + // claims to be a start tag but is empty + $token = new HTMLPurifier_Token_Empty( + $token->name, + $token->attr, + $token->line, + $token->col, + $token->armor + ); + $ok = true; + } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { + // claims to be empty but really is a start tag + // NB: this assignment is required + $old_token = $token; + $token = new HTMLPurifier_Token_End($token->name); + $token = $this->insertBefore( + new HTMLPurifier_Token_Start($old_token->name, $old_token->attr, $old_token->line, $old_token->col, $old_token->armor) + ); + // punt (since we had to modify the input stream in a non-trivial way) + $reprocess = true; + continue; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // real empty token + $ok = true; + } elseif ($token instanceof HTMLPurifier_Token_Start) { + // start tag + + // ...unless they also have to close their parent + if (!empty($this->stack)) { + + // Performance note: you might think that it's rather + // inefficient, recalculating the autoclose information + // for every tag that a token closes (since when we + // do an autoclose, we push a new token into the + // stream and then /process/ that, before + // re-processing this token.) But this is + // necessary, because an injector can make an + // arbitrary transformations to the autoclosing + // tokens we introduce, so things may have changed + // in the meantime. Also, doing the inefficient thing is + // "easy" to reason about (for certain perverse definitions + // of "easy") + + $parent = array_pop($this->stack); + $this->stack[] = $parent; + + $parent_def = null; + $parent_elements = null; + $autoclose = false; + if (isset($definition->info[$parent->name])) { + $parent_def = $definition->info[$parent->name]; + $parent_elements = $parent_def->child->getAllowedElements($config); + $autoclose = !isset($parent_elements[$token->name]); + } + + if ($autoclose && $definition->info[$token->name]->wrap) { + // Check if an element can be wrapped by another + // element to make it valid in a context (for + // example,
              needs a
            • in between) + $wrapname = $definition->info[$token->name]->wrap; + $wrapdef = $definition->info[$wrapname]; + $elements = $wrapdef->child->getAllowedElements($config); + if (isset($elements[$token->name]) && isset($parent_elements[$wrapname])) { + $newtoken = new HTMLPurifier_Token_Start($wrapname); + $token = $this->insertBefore($newtoken); + $reprocess = true; + continue; + } + } + + $carryover = false; + if ($autoclose && $parent_def->formatting) { + $carryover = true; + } + + if ($autoclose) { + // check if this autoclose is doomed to fail + // (this rechecks $parent, which his harmless) + $autoclose_ok = isset($global_parent_allowed_elements[$token->name]); + if (!$autoclose_ok) { + foreach ($this->stack as $ancestor) { + $elements = $definition->info[$ancestor->name]->child->getAllowedElements($config); + if (isset($elements[$token->name])) { + $autoclose_ok = true; + break; + } + if ($definition->info[$token->name]->wrap) { + $wrapname = $definition->info[$token->name]->wrap; + $wrapdef = $definition->info[$wrapname]; + $wrap_elements = $wrapdef->child->getAllowedElements($config); + if (isset($wrap_elements[$token->name]) && isset($elements[$wrapname])) { + $autoclose_ok = true; + break; + } + } + } + } + if ($autoclose_ok) { + // errors need to be updated + $new_token = new HTMLPurifier_Token_End($parent->name); + $new_token->start = $parent; + // [TagClosedSuppress] + if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) { + if (!$carryover) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent); + } else { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent); + } + } + if ($carryover) { + $element = clone $parent; + // [TagClosedAuto] + $element->armor['MakeWellFormed_TagClosedError'] = true; + $element->carryover = true; + $token = $this->processToken(array($new_token, $token, $element)); + } else { + $token = $this->insertBefore($new_token); + } + } else { + $token = $this->remove(); + } + $reprocess = true; + continue; + } + + } + $ok = true; + } + + if ($ok) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + $r = $token; + $injector->handleElement($r); + $token = $this->processToken($r, $i); + $reprocess = true; + break; + } + if (!$reprocess) { + // ah, nothing interesting happened; do normal processing + if ($token instanceof HTMLPurifier_Token_Start) { + $this->stack[] = $token; + } elseif ($token instanceof HTMLPurifier_Token_End) { + throw new HTMLPurifier_Exception( + 'Improper handling of end tag in start code; possible error in MakeWellFormed' + ); + } + } + continue; + } + + // sanity check: we should be dealing with a closing tag + if (!$token instanceof HTMLPurifier_Token_End) { + throw new HTMLPurifier_Exception('Unaccounted for tag token in input stream, bug in HTML Purifier'); + } + + // make sure that we have something open + if (empty($this->stack)) { + if ($escape_invalid_tags) { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text'); + } + $token = new HTMLPurifier_Token_Text($generator->generateFromToken($token)); + } else { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed'); + } + $token = $this->remove(); + } + $reprocess = true; + continue; + } + + // first, check for the simplest case: everything closes neatly. + // Eventually, everything passes through here; if there are problems + // we modify the input stream accordingly and then punt, so that + // the tokens get processed again. + $current_parent = array_pop($this->stack); + if ($current_parent->name == $token->name) { + $token->start = $current_parent; + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + $r = $token; + $injector->handleEnd($r); + $token = $this->processToken($r, $i); + $this->stack[] = $current_parent; + $reprocess = true; + break; + } + continue; + } + + // okay, so we're trying to close the wrong tag + + // undo the pop previous pop + $this->stack[] = $current_parent; + + // scroll back the entire nest, trying to find our tag. + // (feature could be to specify how far you'd like to go) + $size = count($this->stack); + // -2 because -1 is the last element, but we already checked that + $skipped_tags = false; + for ($j = $size - 2; $j >= 0; $j--) { + if ($this->stack[$j]->name == $token->name) { + $skipped_tags = array_slice($this->stack, $j); + break; + } + } + + // we didn't find the tag, so remove + if ($skipped_tags === false) { + if ($escape_invalid_tags) { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text'); + } + $token = new HTMLPurifier_Token_Text($generator->generateFromToken($token)); + } else { + if ($e) { + $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed'); + } + $token = $this->remove(); + } + $reprocess = true; + continue; + } + + // do errors, in REVERSE $j order: a,b,c with + $c = count($skipped_tags); + if ($e) { + for ($j = $c - 1; $j > 0; $j--) { + // notice we exclude $j == 0, i.e. the current ending tag, from + // the errors... [TagClosedSuppress] + if (!isset($skipped_tags[$j]->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]); + } + } + } + + // insert tags, in FORWARD $j order: c,b,a with + $replace = array($token); + for ($j = 1; $j < $c; $j++) { + // ...as well as from the insertions + $new_token = new HTMLPurifier_Token_End($skipped_tags[$j]->name); + $new_token->start = $skipped_tags[$j]; + array_unshift($replace, $new_token); + if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) { + // [TagClosedAuto] + $element = clone $skipped_tags[$j]; + $element->carryover = true; + $element->armor['MakeWellFormed_TagClosedError'] = true; + $replace[] = $element; + } + } + $token = $this->processToken($replace); + $reprocess = true; + continue; + } + + $context->destroy('CurrentToken'); + $context->destroy('CurrentNesting'); + $context->destroy('InputZipper'); + + unset($this->injectors, $this->stack, $this->tokens); + return $zipper->toArray($token); + } + + /** + * Processes arbitrary token values for complicated substitution patterns. + * In general: + * + * If $token is an array, it is a list of tokens to substitute for the + * current token. These tokens then get individually processed. If there + * is a leading integer in the list, that integer determines how many + * tokens from the stream should be removed. + * + * If $token is a regular token, it is swapped with the current token. + * + * If $token is false, the current token is deleted. + * + * If $token is an integer, that number of tokens (with the first token + * being the current one) will be deleted. + * + * @param HTMLPurifier_Token|array|int|bool $token Token substitution value + * @param HTMLPurifier_Injector|int $injector Injector that performed the substitution; default is if + * this is not an injector related operation. + * @throws HTMLPurifier_Exception + */ + protected function processToken($token, $injector = -1) + { + // normalize forms of token + if (is_object($token)) { + $token = array(1, $token); + } + if (is_int($token)) { + $token = array($token); + } + if ($token === false) { + $token = array(1); + } + if (!is_array($token)) { + throw new HTMLPurifier_Exception('Invalid token type from injector'); + } + if (!is_int($token[0])) { + array_unshift($token, 1); + } + if ($token[0] === 0) { + throw new HTMLPurifier_Exception('Deleting zero tokens is not valid'); + } + + // $token is now an array with the following form: + // array(number nodes to delete, new node 1, new node 2, ...) + + $delete = array_shift($token); + list($old, $r) = $this->zipper->splice($this->token, $delete, $token); + + if ($injector > -1) { + // determine appropriate skips + $oldskip = isset($old[0]) ? $old[0]->skip : array(); + foreach ($token as $object) { + $object->skip = $oldskip; + $object->skip[$injector] = true; + } + } + + return $r; + + } + + /** + * Inserts a token before the current token. Cursor now points to + * this token. You must reprocess after this. + * @param HTMLPurifier_Token $token + */ + private function insertBefore($token) + { + // NB not $this->zipper->insertBefore(), due to positioning + // differences + $splice = $this->zipper->splice($this->token, 0, array($token)); + + return $splice[1]; + } + + /** + * Removes current token. Cursor now points to new token occupying previously + * occupied space. You must reprocess after this. + */ + private function remove() + { + return $this->zipper->delete(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Strategy/RemoveForeignElements.php b/library/vendor/HTMLPurifier/Strategy/RemoveForeignElements.php new file mode 100644 index 000000000..1a8149ecc --- /dev/null +++ b/library/vendor/HTMLPurifier/Strategy/RemoveForeignElements.php @@ -0,0 +1,207 @@ +getHTMLDefinition(); + $generator = new HTMLPurifier_Generator($config, $context); + $result = array(); + + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + $remove_invalid_img = $config->get('Core.RemoveInvalidImg'); + + // currently only used to determine if comments should be kept + $trusted = $config->get('HTML.Trusted'); + $comment_lookup = $config->get('HTML.AllowedComments'); + $comment_regexp = $config->get('HTML.AllowedCommentsRegexp'); + $check_comments = $comment_lookup !== array() || $comment_regexp !== null; + + $remove_script_contents = $config->get('Core.RemoveScriptContents'); + $hidden_elements = $config->get('Core.HiddenElements'); + + // remove script contents compatibility + if ($remove_script_contents === true) { + $hidden_elements['script'] = true; + } elseif ($remove_script_contents === false && isset($hidden_elements['script'])) { + unset($hidden_elements['script']); + } + + $attr_validator = new HTMLPurifier_AttrValidator(); + + // removes tokens until it reaches a closing tag with its value + $remove_until = false; + + // converts comments into text tokens when this is equal to a tag name + $textify_comments = false; + + $token = false; + $context->register('CurrentToken', $token); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + foreach ($tokens as $token) { + if ($remove_until) { + if (empty($token->is_tag) || $token->name !== $remove_until) { + continue; + } + } + if (!empty($token->is_tag)) { + // DEFINITION CALL + + // before any processing, try to transform the element + if (isset($definition->info_tag_transform[$token->name])) { + $original_name = $token->name; + // there is a transformation for this tag + // DEFINITION CALL + $token = $definition-> + info_tag_transform[$token->name]->transform($token, $config, $context); + if ($e) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name); + } + } + + if (isset($definition->info[$token->name])) { + // mostly everything's good, but + // we need to make sure required attributes are in order + if (($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) && + $definition->info[$token->name]->required_attr && + ($token->name != 'img' || $remove_invalid_img) // ensure config option still works + ) { + $attr_validator->validateToken($token, $config, $context); + $ok = true; + foreach ($definition->info[$token->name]->required_attr as $name) { + if (!isset($token->attr[$name])) { + $ok = false; + break; + } + } + if (!$ok) { + if ($e) { + $e->send( + E_ERROR, + 'Strategy_RemoveForeignElements: Missing required attribute', + $name + ); + } + continue; + } + $token->armor['ValidateAttributes'] = true; + } + + if (isset($hidden_elements[$token->name]) && $token instanceof HTMLPurifier_Token_Start) { + $textify_comments = $token->name; + } elseif ($token->name === $textify_comments && $token instanceof HTMLPurifier_Token_End) { + $textify_comments = false; + } + + } elseif ($escape_invalid_tags) { + // invalid tag, generate HTML representation and insert in + if ($e) { + $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text'); + } + $token = new HTMLPurifier_Token_Text( + $generator->generateFromToken($token) + ); + } else { + // check if we need to destroy all of the tag's children + // CAN BE GENERICIZED + if (isset($hidden_elements[$token->name])) { + if ($token instanceof HTMLPurifier_Token_Start) { + $remove_until = $token->name; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // do nothing: we're still looking + } else { + $remove_until = false; + } + if ($e) { + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed'); + } + } else { + if ($e) { + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed'); + } + } + continue; + } + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + // textify comments in script tags when they are allowed + if ($textify_comments !== false) { + $data = $token->data; + $token = new HTMLPurifier_Token_Text($data); + } elseif ($trusted || $check_comments) { + // always cleanup comments + $trailing_hyphen = false; + if ($e) { + // perform check whether or not there's a trailing hyphen + if (substr($token->data, -1) == '-') { + $trailing_hyphen = true; + } + } + $token->data = rtrim($token->data, '-'); + $found_double_hyphen = false; + while (strpos($token->data, '--') !== false) { + $found_double_hyphen = true; + $token->data = str_replace('--', '-', $token->data); + } + if ($trusted || !empty($comment_lookup[trim($token->data)]) || + ($comment_regexp !== null && preg_match($comment_regexp, trim($token->data)))) { + // OK good + if ($e) { + if ($trailing_hyphen) { + $e->send( + E_NOTICE, + 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' + ); + } + if ($found_double_hyphen) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed'); + } + } + } else { + if ($e) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); + } + continue; + } + } else { + // strip comments + if ($e) { + $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed'); + } + continue; + } + } elseif ($token instanceof HTMLPurifier_Token_Text) { + } else { + continue; + } + $result[] = $token; + } + if ($remove_until && $e) { + // we removed tokens until the end, throw error + $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', $remove_until); + } + $context->destroy('CurrentToken'); + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Strategy/ValidateAttributes.php b/library/vendor/HTMLPurifier/Strategy/ValidateAttributes.php new file mode 100644 index 000000000..fbb3d27c8 --- /dev/null +++ b/library/vendor/HTMLPurifier/Strategy/ValidateAttributes.php @@ -0,0 +1,45 @@ +register('CurrentToken', $token); + + foreach ($tokens as $key => $token) { + + // only process tokens that have attributes, + // namely start and empty tags + if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) { + continue; + } + + // skip tokens that are armored + if (!empty($token->armor['ValidateAttributes'])) { + continue; + } + + // note that we have no facilities here for removing tokens + $validator->validateToken($token, $config, $context); + } + $context->destroy('CurrentToken'); + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/StringHash.php b/library/vendor/HTMLPurifier/StringHash.php new file mode 100644 index 000000000..c07370197 --- /dev/null +++ b/library/vendor/HTMLPurifier/StringHash.php @@ -0,0 +1,47 @@ +accessed[$index] = true; + return parent::offsetGet($index); + } + + /** + * Returns a lookup array of all array indexes that have been accessed. + * @return array in form array($index => true). + */ + public function getAccessed() + { + return $this->accessed; + } + + /** + * Resets the access array. + */ + public function resetAccessed() + { + $this->accessed = array(); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/StringHashParser.php b/library/vendor/HTMLPurifier/StringHashParser.php new file mode 100644 index 000000000..7c73f8083 --- /dev/null +++ b/library/vendor/HTMLPurifier/StringHashParser.php @@ -0,0 +1,136 @@ + 'DefaultKeyValue', + * 'KEY' => 'Value', + * 'KEY2' => 'Value2', + * 'MULTILINE-KEY' => "Multiline\nvalue.\n", + * ) + * + * We use this as an easy to use file-format for configuration schema + * files, but the class itself is usage agnostic. + * + * You can use ---- to forcibly terminate parsing of a single string-hash; + * this marker is used in multi string-hashes to delimit boundaries. + */ +class HTMLPurifier_StringHashParser +{ + + /** + * @type string + */ + public $default = 'ID'; + + /** + * Parses a file that contains a single string-hash. + * @param string $file + * @return array + */ + public function parseFile($file) + { + if (!file_exists($file)) { + return false; + } + $fh = fopen($file, 'r'); + if (!$fh) { + return false; + } + $ret = $this->parseHandle($fh); + fclose($fh); + return $ret; + } + + /** + * Parses a file that contains multiple string-hashes delimited by '----' + * @param string $file + * @return array + */ + public function parseMultiFile($file) + { + if (!file_exists($file)) { + return false; + } + $ret = array(); + $fh = fopen($file, 'r'); + if (!$fh) { + return false; + } + while (!feof($fh)) { + $ret[] = $this->parseHandle($fh); + } + fclose($fh); + return $ret; + } + + /** + * Internal parser that acepts a file handle. + * @note While it's possible to simulate in-memory parsing by using + * custom stream wrappers, if such a use-case arises we should + * factor out the file handle into its own class. + * @param resource $fh File handle with pointer at start of valid string-hash + * block. + * @return array + */ + protected function parseHandle($fh) + { + $state = false; + $single = false; + $ret = array(); + do { + $line = fgets($fh); + if ($line === false) { + break; + } + $line = rtrim($line, "\n\r"); + if (!$state && $line === '') { + continue; + } + if ($line === '----') { + break; + } + if (strncmp('--#', $line, 3) === 0) { + // Comment + continue; + } elseif (strncmp('--', $line, 2) === 0) { + // Multiline declaration + $state = trim($line, '- '); + if (!isset($ret[$state])) { + $ret[$state] = ''; + } + continue; + } elseif (!$state) { + $single = true; + if (strpos($line, ':') !== false) { + // Single-line declaration + list($state, $line) = explode(':', $line, 2); + $line = trim($line); + } else { + // Use default declaration + $state = $this->default; + } + } + if ($single) { + $ret[$state] = $line; + $single = false; + $state = false; + } else { + $ret[$state] .= "$line\n"; + } + } while (!feof($fh)); + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/TagTransform.php b/library/vendor/HTMLPurifier/TagTransform.php new file mode 100644 index 000000000..7b8d83343 --- /dev/null +++ b/library/vendor/HTMLPurifier/TagTransform.php @@ -0,0 +1,37 @@ + 'xx-small', + '1' => 'xx-small', + '2' => 'small', + '3' => 'medium', + '4' => 'large', + '5' => 'x-large', + '6' => 'xx-large', + '7' => '300%', + '-1' => 'smaller', + '-2' => '60%', + '+1' => 'larger', + '+2' => '150%', + '+3' => '200%', + '+4' => '300%' + ); + + /** + * @param HTMLPurifier_Token_Tag $tag + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token_End|string + */ + public function transform($tag, $config, $context) + { + if ($tag instanceof HTMLPurifier_Token_End) { + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + return $new_tag; + } + + $attr = $tag->attr; + $prepend_style = ''; + + // handle color transform + if (isset($attr['color'])) { + $prepend_style .= 'color:' . $attr['color'] . ';'; + unset($attr['color']); + } + + // handle face transform + if (isset($attr['face'])) { + $prepend_style .= 'font-family:' . $attr['face'] . ';'; + unset($attr['face']); + } + + // handle size transform + if (isset($attr['size'])) { + // normalize large numbers + if ($attr['size'] !== '') { + if ($attr['size']{0} == '+' || $attr['size']{0} == '-') { + $size = (int)$attr['size']; + if ($size < -2) { + $attr['size'] = '-2'; + } + if ($size > 4) { + $attr['size'] = '+4'; + } + } else { + $size = (int)$attr['size']; + if ($size > 7) { + $attr['size'] = '7'; + } + } + } + if (isset($this->_size_lookup[$attr['size']])) { + $prepend_style .= 'font-size:' . + $this->_size_lookup[$attr['size']] . ';'; + } + unset($attr['size']); + } + + if ($prepend_style) { + $attr['style'] = isset($attr['style']) ? + $prepend_style . $attr['style'] : + $prepend_style; + } + + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + $new_tag->attr = $attr; + + return $new_tag; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/TagTransform/Simple.php b/library/vendor/HTMLPurifier/TagTransform/Simple.php new file mode 100644 index 000000000..71bf10b91 --- /dev/null +++ b/library/vendor/HTMLPurifier/TagTransform/Simple.php @@ -0,0 +1,44 @@ +transform_to = $transform_to; + $this->style = $style; + } + + /** + * @param HTMLPurifier_Token_Tag $tag + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function transform($tag, $config, $context) + { + $new_tag = clone $tag; + $new_tag->name = $this->transform_to; + if (!is_null($this->style) && + ($new_tag instanceof HTMLPurifier_Token_Start || $new_tag instanceof HTMLPurifier_Token_Empty) + ) { + $this->prependCSS($new_tag->attr, $this->style); + } + return $new_tag; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Token.php b/library/vendor/HTMLPurifier/Token.php new file mode 100644 index 000000000..85b85e072 --- /dev/null +++ b/library/vendor/HTMLPurifier/Token.php @@ -0,0 +1,100 @@ +line = $l; + $this->col = $c; + } + + /** + * Convenience function for DirectLex settings line/col position. + * @param int $l + * @param int $c + */ + public function rawPosition($l, $c) + { + if ($c === -1) { + $l++; + } + $this->line = $l; + $this->col = $c; + } + + /** + * Converts a token into its corresponding node. + */ + abstract public function toNode(); +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Token/Comment.php b/library/vendor/HTMLPurifier/Token/Comment.php new file mode 100644 index 000000000..23453c705 --- /dev/null +++ b/library/vendor/HTMLPurifier/Token/Comment.php @@ -0,0 +1,38 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toNode() { + return new HTMLPurifier_Node_Comment($this->data, $this->line, $this->col); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Token/Empty.php b/library/vendor/HTMLPurifier/Token/Empty.php new file mode 100644 index 000000000..78a95f555 --- /dev/null +++ b/library/vendor/HTMLPurifier/Token/Empty.php @@ -0,0 +1,15 @@ +empty = true; + return $n; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Token/End.php b/library/vendor/HTMLPurifier/Token/End.php new file mode 100644 index 000000000..59b38fdc5 --- /dev/null +++ b/library/vendor/HTMLPurifier/Token/End.php @@ -0,0 +1,24 @@ +toNode not supported!"); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Token/Start.php b/library/vendor/HTMLPurifier/Token/Start.php new file mode 100644 index 000000000..019f317ad --- /dev/null +++ b/library/vendor/HTMLPurifier/Token/Start.php @@ -0,0 +1,10 @@ +!empty($obj->is_tag) + * without having to use a function call is_a(). + * @type bool + */ + public $is_tag = true; + + /** + * The lower-case name of the tag, like 'a', 'b' or 'blockquote'. + * + * @note Strictly speaking, XML tags are case sensitive, so we shouldn't + * be lower-casing them, but these tokens cater to HTML tags, which are + * insensitive. + * @type string + */ + public $name; + + /** + * Associative array of the tag's attributes. + * @type array + */ + public $attr = array(); + + /** + * Non-overloaded constructor, which lower-cases passed tag name. + * + * @param string $name String name. + * @param array $attr Associative array of attributes. + * @param int $line + * @param int $col + * @param array $armor + */ + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) + { + $this->name = ctype_lower($name) ? $name : strtolower($name); + foreach ($attr as $key => $value) { + // normalization only necessary when key is not lowercase + if (!ctype_lower($key)) { + $new_key = strtolower($key); + if (!isset($attr[$new_key])) { + $attr[$new_key] = $attr[$key]; + } + if ($new_key !== $key) { + unset($attr[$key]); + } + } + } + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toNode() { + return new HTMLPurifier_Node_Element($this->name, $this->attr, $this->line, $this->col, $this->armor); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/Token/Text.php b/library/vendor/HTMLPurifier/Token/Text.php new file mode 100644 index 000000000..f26a1c211 --- /dev/null +++ b/library/vendor/HTMLPurifier/Token/Text.php @@ -0,0 +1,53 @@ +data = $data; + $this->is_whitespace = ctype_space($data); + $this->line = $line; + $this->col = $col; + } + + public function toNode() { + return new HTMLPurifier_Node_Text($this->data, $this->is_whitespace, $this->line, $this->col); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/TokenFactory.php b/library/vendor/HTMLPurifier/TokenFactory.php new file mode 100644 index 000000000..dea2446b9 --- /dev/null +++ b/library/vendor/HTMLPurifier/TokenFactory.php @@ -0,0 +1,118 @@ +p_start = new HTMLPurifier_Token_Start('', array()); + $this->p_end = new HTMLPurifier_Token_End(''); + $this->p_empty = new HTMLPurifier_Token_Empty('', array()); + $this->p_text = new HTMLPurifier_Token_Text(''); + $this->p_comment = new HTMLPurifier_Token_Comment(''); + } + + /** + * Creates a HTMLPurifier_Token_Start. + * @param string $name Tag name + * @param array $attr Associative array of attributes + * @return HTMLPurifier_Token_Start Generated HTMLPurifier_Token_Start + */ + public function createStart($name, $attr = array()) + { + $p = clone $this->p_start; + $p->__construct($name, $attr); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_End. + * @param string $name Tag name + * @return HTMLPurifier_Token_End Generated HTMLPurifier_Token_End + */ + public function createEnd($name) + { + $p = clone $this->p_end; + $p->__construct($name); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Empty. + * @param string $name Tag name + * @param array $attr Associative array of attributes + * @return HTMLPurifier_Token_Empty Generated HTMLPurifier_Token_Empty + */ + public function createEmpty($name, $attr = array()) + { + $p = clone $this->p_empty; + $p->__construct($name, $attr); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Text. + * @param string $data Data of text token + * @return HTMLPurifier_Token_Text Generated HTMLPurifier_Token_Text + */ + public function createText($data) + { + $p = clone $this->p_text; + $p->__construct($data); + return $p; + } + + /** + * Creates a HTMLPurifier_Token_Comment. + * @param string $data Data of comment token + * @return HTMLPurifier_Token_Comment Generated HTMLPurifier_Token_Comment + */ + public function createComment($data) + { + $p = clone $this->p_comment; + $p->__construct($data); + return $p; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URI.php b/library/vendor/HTMLPurifier/URI.php new file mode 100644 index 000000000..a5e7ae298 --- /dev/null +++ b/library/vendor/HTMLPurifier/URI.php @@ -0,0 +1,314 @@ +scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme); + $this->userinfo = $userinfo; + $this->host = $host; + $this->port = is_null($port) ? $port : (int)$port; + $this->path = $path; + $this->query = $query; + $this->fragment = $fragment; + } + + /** + * Retrieves a scheme object corresponding to the URI's scheme/default + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_URIScheme Scheme object appropriate for validating this URI + */ + public function getSchemeObj($config, $context) + { + $registry = HTMLPurifier_URISchemeRegistry::instance(); + if ($this->scheme !== null) { + $scheme_obj = $registry->getScheme($this->scheme, $config, $context); + if (!$scheme_obj) { + return false; + } // invalid scheme, clean it out + } else { + // no scheme: retrieve the default one + $def = $config->getDefinition('URI'); + $scheme_obj = $def->getDefaultScheme($config, $context); + if (!$scheme_obj) { + // something funky happened to the default scheme object + trigger_error( + 'Default scheme object "' . $def->defaultScheme . '" was not readable', + E_USER_WARNING + ); + return false; + } + } + return $scheme_obj; + } + + /** + * Generic validation method applicable for all schemes. May modify + * this URI in order to get it into a compliant form. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool True if validation/filtering succeeds, false if failure + */ + public function validate($config, $context) + { + // ABNF definitions from RFC 3986 + $chars_sub_delims = '!$&\'()*+,;='; + $chars_gen_delims = ':/?#[]@'; + $chars_pchar = $chars_sub_delims . ':@'; + + // validate host + if (!is_null($this->host)) { + $host_def = new HTMLPurifier_AttrDef_URI_Host(); + $this->host = $host_def->validate($this->host, $config, $context); + if ($this->host === false) { + $this->host = null; + } + } + + // validate scheme + // NOTE: It's not appropriate to check whether or not this + // scheme is in our registry, since a URIFilter may convert a + // URI that we don't allow into one we do. So instead, we just + // check if the scheme can be dropped because there is no host + // and it is our default scheme. + if (!is_null($this->scheme) && is_null($this->host) || $this->host === '') { + // support for relative paths is pretty abysmal when the + // scheme is present, so axe it when possible + $def = $config->getDefinition('URI'); + if ($def->defaultScheme === $this->scheme) { + $this->scheme = null; + } + } + + // validate username + if (!is_null($this->userinfo)) { + $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':'); + $this->userinfo = $encoder->encode($this->userinfo); + } + + // validate port + if (!is_null($this->port)) { + if ($this->port < 1 || $this->port > 65535) { + $this->port = null; + } + } + + // validate path + $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/'); + if (!is_null($this->host)) { // this catches $this->host === '' + // path-abempty (hier and relative) + // http://www.example.com/my/path + // //www.example.com/my/path (looks odd, but works, and + // recognized by most browsers) + // (this set is valid or invalid on a scheme by scheme + // basis, so we'll deal with it later) + // file:///my/path + // ///my/path + $this->path = $segments_encoder->encode($this->path); + } elseif ($this->path !== '') { + if ($this->path[0] === '/') { + // path-absolute (hier and relative) + // http:/my/path + // /my/path + if (strlen($this->path) >= 2 && $this->path[1] === '/') { + // This could happen if both the host gets stripped + // out + // http://my/path + // //my/path + $this->path = ''; + } else { + $this->path = $segments_encoder->encode($this->path); + } + } elseif (!is_null($this->scheme)) { + // path-rootless (hier) + // http:my/path + // Short circuit evaluation means we don't need to check nz + $this->path = $segments_encoder->encode($this->path); + } else { + // path-noscheme (relative) + // my/path + // (once again, not checking nz) + $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@'); + $c = strpos($this->path, '/'); + if ($c !== false) { + $this->path = + $segment_nc_encoder->encode(substr($this->path, 0, $c)) . + $segments_encoder->encode(substr($this->path, $c)); + } else { + $this->path = $segment_nc_encoder->encode($this->path); + } + } + } else { + // path-empty (hier and relative) + $this->path = ''; // just to be safe + } + + // qf = query and fragment + $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?'); + + if (!is_null($this->query)) { + $this->query = $qf_encoder->encode($this->query); + } + + if (!is_null($this->fragment)) { + $this->fragment = $qf_encoder->encode($this->fragment); + } + return true; + } + + /** + * Convert URI back to string + * @return string URI appropriate for output + */ + public function toString() + { + // reconstruct authority + $authority = null; + // there is a rendering difference between a null authority + // (http:foo-bar) and an empty string authority + // (http:///foo-bar). + if (!is_null($this->host)) { + $authority = ''; + if (!is_null($this->userinfo)) { + $authority .= $this->userinfo . '@'; + } + $authority .= $this->host; + if (!is_null($this->port)) { + $authority .= ':' . $this->port; + } + } + + // Reconstruct the result + // One might wonder about parsing quirks from browsers after + // this reconstruction. Unfortunately, parsing behavior depends + // on what *scheme* was employed (file:///foo is handled *very* + // differently than http:///foo), so unfortunately we have to + // defer to the schemes to do the right thing. + $result = ''; + if (!is_null($this->scheme)) { + $result .= $this->scheme . ':'; + } + if (!is_null($authority)) { + $result .= '//' . $authority; + } + $result .= $this->path; + if (!is_null($this->query)) { + $result .= '?' . $this->query; + } + if (!is_null($this->fragment)) { + $result .= '#' . $this->fragment; + } + + return $result; + } + + /** + * Returns true if this URL might be considered a 'local' URL given + * the current context. This is true when the host is null, or + * when it matches the host supplied to the configuration. + * + * Note that this does not do any scheme checking, so it is mostly + * only appropriate for metadata that doesn't care about protocol + * security. isBenign is probably what you actually want. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function isLocal($config, $context) + { + if ($this->host === null) { + return true; + } + $uri_def = $config->getDefinition('URI'); + if ($uri_def->host === $this->host) { + return true; + } + return false; + } + + /** + * Returns true if this URL should be considered a 'benign' URL, + * that is: + * + * - It is a local URL (isLocal), and + * - It has a equal or better level of security + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function isBenign($config, $context) + { + if (!$this->isLocal($config, $context)) { + return false; + } + + $scheme_obj = $this->getSchemeObj($config, $context); + if (!$scheme_obj) { + return false; + } // conservative approach + + $current_scheme_obj = $config->getDefinition('URI')->getDefaultScheme($config, $context); + if ($current_scheme_obj->secure) { + if (!$scheme_obj->secure) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIDefinition.php b/library/vendor/HTMLPurifier/URIDefinition.php new file mode 100644 index 000000000..e0bd8bcca --- /dev/null +++ b/library/vendor/HTMLPurifier/URIDefinition.php @@ -0,0 +1,112 @@ +registerFilter(new HTMLPurifier_URIFilter_DisableExternal()); + $this->registerFilter(new HTMLPurifier_URIFilter_DisableExternalResources()); + $this->registerFilter(new HTMLPurifier_URIFilter_DisableResources()); + $this->registerFilter(new HTMLPurifier_URIFilter_HostBlacklist()); + $this->registerFilter(new HTMLPurifier_URIFilter_SafeIframe()); + $this->registerFilter(new HTMLPurifier_URIFilter_MakeAbsolute()); + $this->registerFilter(new HTMLPurifier_URIFilter_Munge()); + } + + public function registerFilter($filter) + { + $this->registeredFilters[$filter->name] = $filter; + } + + public function addFilter($filter, $config) + { + $r = $filter->prepare($config); + if ($r === false) return; // null is ok, for backwards compat + if ($filter->post) { + $this->postFilters[$filter->name] = $filter; + } else { + $this->filters[$filter->name] = $filter; + } + } + + protected function doSetup($config) + { + $this->setupMemberVariables($config); + $this->setupFilters($config); + } + + protected function setupFilters($config) + { + foreach ($this->registeredFilters as $name => $filter) { + if ($filter->always_load) { + $this->addFilter($filter, $config); + } else { + $conf = $config->get('URI.' . $name); + if ($conf !== false && $conf !== null) { + $this->addFilter($filter, $config); + } + } + } + unset($this->registeredFilters); + } + + protected function setupMemberVariables($config) + { + $this->host = $config->get('URI.Host'); + $base_uri = $config->get('URI.Base'); + if (!is_null($base_uri)) { + $parser = new HTMLPurifier_URIParser(); + $this->base = $parser->parse($base_uri); + $this->defaultScheme = $this->base->scheme; + if (is_null($this->host)) $this->host = $this->base->host; + } + if (is_null($this->defaultScheme)) $this->defaultScheme = $config->get('URI.DefaultScheme'); + } + + public function getDefaultScheme($config, $context) + { + return HTMLPurifier_URISchemeRegistry::instance()->getScheme($this->defaultScheme, $config, $context); + } + + public function filter(&$uri, $config, $context) + { + foreach ($this->filters as $name => $f) { + $result = $f->filter($uri, $config, $context); + if (!$result) return false; + } + return true; + } + + public function postFilter(&$uri, $config, $context) + { + foreach ($this->postFilters as $name => $f) { + $result = $f->filter($uri, $config, $context); + if (!$result) return false; + } + return true; + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter.php b/library/vendor/HTMLPurifier/URIFilter.php new file mode 100644 index 000000000..09724e9f4 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter.php @@ -0,0 +1,74 @@ +getDefinition('URI')->host; + if ($our_host !== null) { + $this->ourHostParts = array_reverse(explode('.', $our_host)); + } + } + + /** + * @param HTMLPurifier_URI $uri Reference + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + if (is_null($uri->host)) { + return true; + } + if ($this->ourHostParts === false) { + return false; + } + $host_parts = array_reverse(explode('.', $uri->host)); + foreach ($this->ourHostParts as $i => $x) { + if (!isset($host_parts[$i])) { + return false; + } + if ($host_parts[$i] != $this->ourHostParts[$i]) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter/DisableExternalResources.php b/library/vendor/HTMLPurifier/URIFilter/DisableExternalResources.php new file mode 100644 index 000000000..c6562169e --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter/DisableExternalResources.php @@ -0,0 +1,25 @@ +get('EmbeddedURI', true)) { + return true; + } + return parent::filter($uri, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter/DisableResources.php b/library/vendor/HTMLPurifier/URIFilter/DisableResources.php new file mode 100644 index 000000000..d5c412c44 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter/DisableResources.php @@ -0,0 +1,22 @@ +get('EmbeddedURI', true); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter/HostBlacklist.php b/library/vendor/HTMLPurifier/URIFilter/HostBlacklist.php new file mode 100644 index 000000000..a6645c17e --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter/HostBlacklist.php @@ -0,0 +1,46 @@ +blacklist = $config->get('URI.HostBlacklist'); + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + foreach ($this->blacklist as $blacklisted_host_fragment) { + if (strpos($uri->host, $blacklisted_host_fragment) !== false) { + return false; + } + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter/MakeAbsolute.php b/library/vendor/HTMLPurifier/URIFilter/MakeAbsolute.php new file mode 100644 index 000000000..c507bbff8 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter/MakeAbsolute.php @@ -0,0 +1,158 @@ +getDefinition('URI'); + $this->base = $def->base; + if (is_null($this->base)) { + trigger_error( + 'URI.MakeAbsolute is being ignored due to lack of ' . + 'value for URI.Base configuration', + E_USER_WARNING + ); + return false; + } + $this->base->fragment = null; // fragment is invalid for base URI + $stack = explode('/', $this->base->path); + array_pop($stack); // discard last segment + $stack = $this->_collapseStack($stack); // do pre-parsing + $this->basePathStack = $stack; + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + if (is_null($this->base)) { + return true; + } // abort early + if ($uri->path === '' && is_null($uri->scheme) && + is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment)) { + // reference to current document + $uri = clone $this->base; + return true; + } + if (!is_null($uri->scheme)) { + // absolute URI already: don't change + if (!is_null($uri->host)) { + return true; + } + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + // scheme not recognized + return false; + } + if (!$scheme_obj->hierarchical) { + // non-hierarchal URI with explicit scheme, don't change + return true; + } + // special case: had a scheme but always is hierarchical and had no authority + } + if (!is_null($uri->host)) { + // network path, don't bother + return true; + } + if ($uri->path === '') { + $uri->path = $this->base->path; + } elseif ($uri->path[0] !== '/') { + // relative path, needs more complicated processing + $stack = explode('/', $uri->path); + $new_stack = array_merge($this->basePathStack, $stack); + if ($new_stack[0] !== '' && !is_null($this->base->host)) { + array_unshift($new_stack, ''); + } + $new_stack = $this->_collapseStack($new_stack); + $uri->path = implode('/', $new_stack); + } else { + // absolute path, but still we should collapse + $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); + } + // re-combine + $uri->scheme = $this->base->scheme; + if (is_null($uri->userinfo)) { + $uri->userinfo = $this->base->userinfo; + } + if (is_null($uri->host)) { + $uri->host = $this->base->host; + } + if (is_null($uri->port)) { + $uri->port = $this->base->port; + } + return true; + } + + /** + * Resolve dots and double-dots in a path stack + * @param array $stack + * @return array + */ + private function _collapseStack($stack) + { + $result = array(); + $is_folder = false; + for ($i = 0; isset($stack[$i]); $i++) { + $is_folder = false; + // absorb an internally duplicated slash + if ($stack[$i] == '' && $i && isset($stack[$i + 1])) { + continue; + } + if ($stack[$i] == '..') { + if (!empty($result)) { + $segment = array_pop($result); + if ($segment === '' && empty($result)) { + // error case: attempted to back out too far: + // restore the leading slash + $result[] = ''; + } elseif ($segment === '..') { + $result[] = '..'; // cannot remove .. with .. + } + } else { + // relative path, preserve the double-dots + $result[] = '..'; + } + $is_folder = true; + continue; + } + if ($stack[$i] == '.') { + // silently absorb + $is_folder = true; + continue; + } + $result[] = $stack[$i]; + } + if ($is_folder) { + $result[] = ''; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter/Munge.php b/library/vendor/HTMLPurifier/URIFilter/Munge.php new file mode 100644 index 000000000..6e03315a1 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter/Munge.php @@ -0,0 +1,115 @@ +target = $config->get('URI.' . $this->name); + $this->parser = new HTMLPurifier_URIParser(); + $this->doEmbed = $config->get('URI.MungeResources'); + $this->secretKey = $config->get('URI.MungeSecretKey'); + if ($this->secretKey && !function_exists('hash_hmac')) { + throw new Exception("Cannot use %URI.MungeSecretKey without hash_hmac support."); + } + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + if ($context->get('EmbeddedURI', true) && !$this->doEmbed) { + return true; + } + + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + return true; + } // ignore unknown schemes, maybe another postfilter did it + if (!$scheme_obj->browsable) { + return true; + } // ignore non-browseable schemes, since we can't munge those in a reasonable way + if ($uri->isBenign($config, $context)) { + return true; + } // don't redirect if a benign URL + + $this->makeReplace($uri, $config, $context); + $this->replace = array_map('rawurlencode', $this->replace); + + $new_uri = strtr($this->target, $this->replace); + $new_uri = $this->parser->parse($new_uri); + // don't redirect if the target host is the same as the + // starting host + if ($uri->host === $new_uri->host) { + return true; + } + $uri = $new_uri; // overwrite + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + protected function makeReplace($uri, $config, $context) + { + $string = $uri->toString(); + // always available + $this->replace['%s'] = $string; + $this->replace['%r'] = $context->get('EmbeddedURI', true); + $token = $context->get('CurrentToken', true); + $this->replace['%n'] = $token ? $token->name : null; + $this->replace['%m'] = $context->get('CurrentAttr', true); + $this->replace['%p'] = $context->get('CurrentCSSProperty', true); + // not always available + if ($this->secretKey) { + $this->replace['%t'] = hash_hmac("sha256", $string, $this->secretKey); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIFilter/SafeIframe.php b/library/vendor/HTMLPurifier/URIFilter/SafeIframe.php new file mode 100644 index 000000000..f609c47a3 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIFilter/SafeIframe.php @@ -0,0 +1,68 @@ +regexp = $config->get('URI.SafeIframeRegexp'); + return true; + } + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function filter(&$uri, $config, $context) + { + // check if filter not applicable + if (!$config->get('HTML.SafeIframe')) { + return true; + } + // check if the filter should actually trigger + if (!$context->get('EmbeddedURI', true)) { + return true; + } + $token = $context->get('CurrentToken', true); + if (!($token && $token->name == 'iframe')) { + return true; + } + // check if we actually have some whitelists enabled + if ($this->regexp === null) { + return false; + } + // actually check the whitelists + return preg_match($this->regexp, $uri->toString()); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIParser.php b/library/vendor/HTMLPurifier/URIParser.php new file mode 100644 index 000000000..0e7381a07 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIParser.php @@ -0,0 +1,71 @@ +percentEncoder = new HTMLPurifier_PercentEncoder(); + } + + /** + * Parses a URI. + * @param $uri string URI to parse + * @return HTMLPurifier_URI representation of URI. This representation has + * not been validated yet and may not conform to RFC. + */ + public function parse($uri) + { + $uri = $this->percentEncoder->normalize($uri); + + // Regexp is as per Appendix B. + // Note that ["<>] are an addition to the RFC's recommended + // characters, because they represent external delimeters. + $r_URI = '!'. + '(([a-zA-Z0-9\.\+\-]+):)?'. // 2. Scheme + '(//([^/?#"<>]*))?'. // 4. Authority + '([^?#"<>]*)'. // 5. Path + '(\?([^#"<>]*))?'. // 7. Query + '(#([^"<>]*))?'. // 8. Fragment + '!'; + + $matches = array(); + $result = preg_match($r_URI, $uri, $matches); + + if (!$result) return false; // *really* invalid URI + + // seperate out parts + $scheme = !empty($matches[1]) ? $matches[2] : null; + $authority = !empty($matches[3]) ? $matches[4] : null; + $path = $matches[5]; // always present, can be empty + $query = !empty($matches[6]) ? $matches[7] : null; + $fragment = !empty($matches[8]) ? $matches[9] : null; + + // further parse authority + if ($authority !== null) { + $r_authority = "/^((.+?)@)?(\[[^\]]+\]|[^:]*)(:(\d*))?/"; + $matches = array(); + preg_match($r_authority, $authority, $matches); + $userinfo = !empty($matches[1]) ? $matches[2] : null; + $host = !empty($matches[3]) ? $matches[3] : ''; + $port = !empty($matches[4]) ? (int) $matches[5] : null; + } else { + $port = $host = $userinfo = null; + } + + return new HTMLPurifier_URI( + $scheme, $userinfo, $host, $port, $path, $query, $fragment); + } + +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme.php b/library/vendor/HTMLPurifier/URIScheme.php new file mode 100644 index 000000000..fe9e82cf2 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme.php @@ -0,0 +1,102 @@ +, resolves edge cases + * with making relative URIs absolute + * @type bool + */ + public $hierarchical = false; + + /** + * Whether or not the URI may omit a hostname when the scheme is + * explicitly specified, ala file:///path/to/file. As of writing, + * 'file' is the only scheme that browsers support his properly. + * @type bool + */ + public $may_omit_host = false; + + /** + * Validates the components of a URI for a specific scheme. + * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool success or failure + */ + abstract public function doValidate(&$uri, $config, $context); + + /** + * Public interface for validating components of a URI. Performs a + * bunch of default actions. Don't overload this method. + * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool success or failure + */ + public function validate(&$uri, $config, $context) + { + if ($this->default_port == $uri->port) { + $uri->port = null; + } + // kludge: browsers do funny things when the scheme but not the + // authority is set + if (!$this->may_omit_host && + // if the scheme is present, a missing host is always in error + (!is_null($uri->scheme) && ($uri->host === '' || is_null($uri->host))) || + // if the scheme is not present, a *blank* host is in error, + // since this translates into '///path' which most browsers + // interpret as being 'http://path'. + (is_null($uri->scheme) && $uri->host === '') + ) { + do { + if (is_null($uri->scheme)) { + if (substr($uri->path, 0, 2) != '//') { + $uri->host = null; + break; + } + // URI is '////path', so we cannot nullify the + // host to preserve semantics. Try expanding the + // hostname instead (fall through) + } + // first see if we can manually insert a hostname + $host = $config->get('URI.Host'); + if (!is_null($host)) { + $uri->host = $host; + } else { + // we can't do anything sensible, reject the URL. + return false; + } + } while (false); + } + return $this->doValidate($uri, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme/data.php b/library/vendor/HTMLPurifier/URIScheme/data.php new file mode 100644 index 000000000..6ebca4984 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/data.php @@ -0,0 +1,127 @@ + true, + 'image/gif' => true, + 'image/png' => true, + ); + // this is actually irrelevant since we only write out the path + // component + /** + * @type bool + */ + public $may_omit_host = true; + + /** + * @param HTMLPurifier_URI $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function doValidate(&$uri, $config, $context) + { + $result = explode(',', $uri->path, 2); + $is_base64 = false; + $charset = null; + $content_type = null; + if (count($result) == 2) { + list($metadata, $data) = $result; + // do some legwork on the metadata + $metas = explode(';', $metadata); + while (!empty($metas)) { + $cur = array_shift($metas); + if ($cur == 'base64') { + $is_base64 = true; + break; + } + if (substr($cur, 0, 8) == 'charset=') { + // doesn't match if there are arbitrary spaces, but + // whatever dude + if ($charset !== null) { + continue; + } // garbage + $charset = substr($cur, 8); // not used + } else { + if ($content_type !== null) { + continue; + } // garbage + $content_type = $cur; + } + } + } else { + $data = $result[0]; + } + if ($content_type !== null && empty($this->allowed_types[$content_type])) { + return false; + } + if ($charset !== null) { + // error; we don't allow plaintext stuff + $charset = null; + } + $data = rawurldecode($data); + if ($is_base64) { + $raw_data = base64_decode($data); + } else { + $raw_data = $data; + } + // XXX probably want to refactor this into a general mechanism + // for filtering arbitrary content types + $file = tempnam("/tmp", ""); + file_put_contents($file, $raw_data); + if (function_exists('exif_imagetype')) { + $image_code = exif_imagetype($file); + unlink($file); + } elseif (function_exists('getimagesize')) { + set_error_handler(array($this, 'muteErrorHandler')); + $info = getimagesize($file); + restore_error_handler(); + unlink($file); + if ($info == false) { + return false; + } + $image_code = $info[2]; + } else { + trigger_error("could not find exif_imagetype or getimagesize functions", E_USER_ERROR); + } + $real_content_type = image_type_to_mime_type($image_code); + if ($real_content_type != $content_type) { + // we're nice guys; if the content type is something else we + // support, change it over + if (empty($this->allowed_types[$real_content_type])) { + return false; + } + $content_type = $real_content_type; + } + // ok, it's kosher, rewrite what we need + $uri->userinfo = null; + $uri->host = null; + $uri->port = null; + $uri->fragment = null; + $uri->query = null; + $uri->path = "$content_type;base64," . base64_encode($raw_data); + return true; + } + + /** + * @param int $errno + * @param string $errstr + */ + public function muteErrorHandler($errno, $errstr) + { + } +} diff --git a/library/vendor/HTMLPurifier/URIScheme/file.php b/library/vendor/HTMLPurifier/URIScheme/file.php new file mode 100644 index 000000000..215be4ba8 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/file.php @@ -0,0 +1,44 @@ +userinfo = null; + // file:// makes no provisions for accessing the resource + $uri->port = null; + // While it seems to work on Firefox, the querystring has + // no possible effect and is thus stripped. + $uri->query = null; + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme/ftp.php b/library/vendor/HTMLPurifier/URIScheme/ftp.php new file mode 100644 index 000000000..1eb43ee5c --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/ftp.php @@ -0,0 +1,58 @@ +query = null; + + // typecode check + $semicolon_pos = strrpos($uri->path, ';'); // reverse + if ($semicolon_pos !== false) { + $type = substr($uri->path, $semicolon_pos + 1); // no semicolon + $uri->path = substr($uri->path, 0, $semicolon_pos); + $type_ret = ''; + if (strpos($type, '=') !== false) { + // figure out whether or not the declaration is correct + list($key, $typecode) = explode('=', $type, 2); + if ($key !== 'type') { + // invalid key, tack it back on encoded + $uri->path .= '%3B' . $type; + } elseif ($typecode === 'a' || $typecode === 'i' || $typecode === 'd') { + $type_ret = ";type=$typecode"; + } + } else { + $uri->path .= '%3B' . $type; + } + $uri->path = str_replace(';', '%3B', $uri->path); + $uri->path .= $type_ret; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme/http.php b/library/vendor/HTMLPurifier/URIScheme/http.php new file mode 100644 index 000000000..ce69ec438 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/http.php @@ -0,0 +1,36 @@ +userinfo = null; + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme/https.php b/library/vendor/HTMLPurifier/URIScheme/https.php new file mode 100644 index 000000000..0e96882db --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/https.php @@ -0,0 +1,18 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + // we need to validate path against RFC 2368's addr-spec + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme/news.php b/library/vendor/HTMLPurifier/URIScheme/news.php new file mode 100644 index 000000000..7490927d6 --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/news.php @@ -0,0 +1,35 @@ +userinfo = null; + $uri->host = null; + $uri->port = null; + $uri->query = null; + // typecode check needed on path + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URIScheme/nntp.php b/library/vendor/HTMLPurifier/URIScheme/nntp.php new file mode 100644 index 000000000..f211d715e --- /dev/null +++ b/library/vendor/HTMLPurifier/URIScheme/nntp.php @@ -0,0 +1,32 @@ +userinfo = null; + $uri->query = null; + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/URISchemeRegistry.php b/library/vendor/HTMLPurifier/URISchemeRegistry.php new file mode 100644 index 000000000..4ac8a0b76 --- /dev/null +++ b/library/vendor/HTMLPurifier/URISchemeRegistry.php @@ -0,0 +1,81 @@ +get('URI.AllowedSchemes'); + if (!$config->get('URI.OverrideAllowedSchemes') && + !isset($allowed_schemes[$scheme]) + ) { + return; + } + + if (isset($this->schemes[$scheme])) { + return $this->schemes[$scheme]; + } + if (!isset($allowed_schemes[$scheme])) { + return; + } + + $class = 'HTMLPurifier_URIScheme_' . $scheme; + if (!class_exists($class)) { + return; + } + $this->schemes[$scheme] = new $class(); + return $this->schemes[$scheme]; + } + + /** + * Registers a custom scheme to the cache, bypassing reflection. + * @param string $scheme Scheme name + * @param HTMLPurifier_URIScheme $scheme_obj + */ + public function register($scheme, $scheme_obj) + { + $this->schemes[$scheme] = $scheme_obj; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/UnitConverter.php b/library/vendor/HTMLPurifier/UnitConverter.php new file mode 100644 index 000000000..166f3bf30 --- /dev/null +++ b/library/vendor/HTMLPurifier/UnitConverter.php @@ -0,0 +1,307 @@ + array( + 'px' => 3, // This is as per CSS 2.1 and Firefox. Your mileage may vary + 'pt' => 4, + 'pc' => 48, + 'in' => 288, + self::METRIC => array('pt', '0.352777778', 'mm'), + ), + self::METRIC => array( + 'mm' => 1, + 'cm' => 10, + self::ENGLISH => array('mm', '2.83464567', 'pt'), + ), + ); + + /** + * Minimum bcmath precision for output. + * @type int + */ + protected $outputPrecision; + + /** + * Bcmath precision for internal calculations. + * @type int + */ + protected $internalPrecision; + + /** + * Whether or not BCMath is available. + * @type bool + */ + private $bcmath; + + public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false) + { + $this->outputPrecision = $output_precision; + $this->internalPrecision = $internal_precision; + $this->bcmath = !$force_no_bcmath && function_exists('bcmul'); + } + + /** + * Converts a length object of one unit into another unit. + * @param HTMLPurifier_Length $length + * Instance of HTMLPurifier_Length to convert. You must validate() + * it before passing it here! + * @param string $to_unit + * Unit to convert to. + * @return HTMLPurifier_Length|bool + * @note + * About precision: This conversion function pays very special + * attention to the incoming precision of values and attempts + * to maintain a number of significant figure. Results are + * fairly accurate up to nine digits. Some caveats: + * - If a number is zero-padded as a result of this significant + * figure tracking, the zeroes will be eliminated. + * - If a number contains less than four sigfigs ($outputPrecision) + * and this causes some decimals to be excluded, those + * decimals will be added on. + */ + public function convert($length, $to_unit) + { + if (!$length->isValid()) { + return false; + } + + $n = $length->getN(); + $unit = $length->getUnit(); + + if ($n === '0' || $unit === false) { + return new HTMLPurifier_Length('0', false); + } + + $state = $dest_state = false; + foreach (self::$units as $k => $x) { + if (isset($x[$unit])) { + $state = $k; + } + if (isset($x[$to_unit])) { + $dest_state = $k; + } + } + if (!$state || !$dest_state) { + return false; + } + + // Some calculations about the initial precision of the number; + // this will be useful when we need to do final rounding. + $sigfigs = $this->getSigFigs($n); + if ($sigfigs < $this->outputPrecision) { + $sigfigs = $this->outputPrecision; + } + + // BCMath's internal precision deals only with decimals. Use + // our default if the initial number has no decimals, or increase + // it by how ever many decimals, thus, the number of guard digits + // will always be greater than or equal to internalPrecision. + $log = (int)floor(log(abs($n), 10)); + $cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision + + for ($i = 0; $i < 2; $i++) { + + // Determine what unit IN THIS SYSTEM we need to convert to + if ($dest_state === $state) { + // Simple conversion + $dest_unit = $to_unit; + } else { + // Convert to the smallest unit, pending a system shift + $dest_unit = self::$units[$state][$dest_state][0]; + } + + // Do the conversion if necessary + if ($dest_unit !== $unit) { + $factor = $this->div(self::$units[$state][$unit], self::$units[$state][$dest_unit], $cp); + $n = $this->mul($n, $factor, $cp); + $unit = $dest_unit; + } + + // Output was zero, so bail out early. Shouldn't ever happen. + if ($n === '') { + $n = '0'; + $unit = $to_unit; + break; + } + + // It was a simple conversion, so bail out + if ($dest_state === $state) { + break; + } + + if ($i !== 0) { + // Conversion failed! Apparently, the system we forwarded + // to didn't have this unit. This should never happen! + return false; + } + + // Pre-condition: $i == 0 + + // Perform conversion to next system of units + $n = $this->mul($n, self::$units[$state][$dest_state][1], $cp); + $unit = self::$units[$state][$dest_state][2]; + $state = $dest_state; + + // One more loop around to convert the unit in the new system. + + } + + // Post-condition: $unit == $to_unit + if ($unit !== $to_unit) { + return false; + } + + // Useful for debugging: + //echo "
              n";
              +        //echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n
              \n"; + + $n = $this->round($n, $sigfigs); + if (strpos($n, '.') !== false) { + $n = rtrim($n, '0'); + } + $n = rtrim($n, '.'); + + return new HTMLPurifier_Length($n, $unit); + } + + /** + * Returns the number of significant figures in a string number. + * @param string $n Decimal number + * @return int number of sigfigs + */ + public function getSigFigs($n) + { + $n = ltrim($n, '0+-'); + $dp = strpos($n, '.'); // decimal position + if ($dp === false) { + $sigfigs = strlen(rtrim($n, '0')); + } else { + $sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character + if ($dp !== 0) { + $sigfigs--; + } + } + return $sigfigs; + } + + /** + * Adds two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function add($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcadd($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 + (float)$s2, $scale); + } + } + + /** + * Multiples two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function mul($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcmul($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 * (float)$s2, $scale); + } + } + + /** + * Divides two numbers, using arbitrary precision when available. + * @param string $s1 + * @param string $s2 + * @param int $scale + * @return string + */ + private function div($s1, $s2, $scale) + { + if ($this->bcmath) { + return bcdiv($s1, $s2, $scale); + } else { + return $this->scale((float)$s1 / (float)$s2, $scale); + } + } + + /** + * Rounds a number according to the number of sigfigs it should have, + * using arbitrary precision when available. + * @param float $n + * @param int $sigfigs + * @return string + */ + private function round($n, $sigfigs) + { + $new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1 + $rp = $sigfigs - $new_log - 1; // Number of decimal places needed + $neg = $n < 0 ? '-' : ''; // Negative sign + if ($this->bcmath) { + if ($rp >= 0) { + $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1); + $n = bcdiv($n, '1', $rp); + } else { + // This algorithm partially depends on the standardized + // form of numbers that comes out of bcmath. + $n = bcadd($n, $neg . '5' . str_repeat('0', $new_log - $sigfigs), 0); + $n = substr($n, 0, $sigfigs + strlen($neg)) . str_repeat('0', $new_log - $sigfigs + 1); + } + return $n; + } else { + return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); + } + } + + /** + * Scales a float to $scale digits right of decimal point, like BCMath. + * @param float $r + * @param int $scale + * @return string + */ + private function scale($r, $scale) + { + if ($scale < 0) { + // The f sprintf type doesn't support negative numbers, so we + // need to cludge things manually. First get the string. + $r = sprintf('%.0f', (float)$r); + // Due to floating point precision loss, $r will more than likely + // look something like 4652999999999.9234. We grab one more digit + // than we need to precise from $r and then use that to round + // appropriately. + $precise = (string)round(substr($r, 0, strlen($r) + $scale), -1); + // Now we return it, truncating the zero that was rounded off. + return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); + } + return sprintf('%.' . $scale . 'f', (float)$r); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/VarParser.php b/library/vendor/HTMLPurifier/VarParser.php new file mode 100644 index 000000000..50cba6910 --- /dev/null +++ b/library/vendor/HTMLPurifier/VarParser.php @@ -0,0 +1,198 @@ + self::STRING, + 'istring' => self::ISTRING, + 'text' => self::TEXT, + 'itext' => self::ITEXT, + 'int' => self::INT, + 'float' => self::FLOAT, + 'bool' => self::BOOL, + 'lookup' => self::LOOKUP, + 'list' => self::ALIST, + 'hash' => self::HASH, + 'mixed' => self::MIXED + ); + + /** + * Lookup table of types that are string, and can have aliases or + * allowed value lists. + */ + public static $stringTypes = array( + self::STRING => true, + self::ISTRING => true, + self::TEXT => true, + self::ITEXT => true, + ); + + /** + * Validate a variable according to type. + * It may return NULL as a valid type if $allow_null is true. + * + * @param mixed $var Variable to validate + * @param int $type Type of variable, see HTMLPurifier_VarParser->types + * @param bool $allow_null Whether or not to permit null as a value + * @return string Validated and type-coerced variable + * @throws HTMLPurifier_VarParserException + */ + final public function parse($var, $type, $allow_null = false) + { + if (is_string($type)) { + if (!isset(HTMLPurifier_VarParser::$types[$type])) { + throw new HTMLPurifier_VarParserException("Invalid type '$type'"); + } else { + $type = HTMLPurifier_VarParser::$types[$type]; + } + } + $var = $this->parseImplementation($var, $type, $allow_null); + if ($allow_null && $var === null) { + return null; + } + // These are basic checks, to make sure nothing horribly wrong + // happened in our implementations. + switch ($type) { + case (self::STRING): + case (self::ISTRING): + case (self::TEXT): + case (self::ITEXT): + if (!is_string($var)) { + break; + } + if ($type == self::ISTRING || $type == self::ITEXT) { + $var = strtolower($var); + } + return $var; + case (self::INT): + if (!is_int($var)) { + break; + } + return $var; + case (self::FLOAT): + if (!is_float($var)) { + break; + } + return $var; + case (self::BOOL): + if (!is_bool($var)) { + break; + } + return $var; + case (self::LOOKUP): + case (self::ALIST): + case (self::HASH): + if (!is_array($var)) { + break; + } + if ($type === self::LOOKUP) { + foreach ($var as $k) { + if ($k !== true) { + $this->error('Lookup table contains value other than true'); + } + } + } elseif ($type === self::ALIST) { + $keys = array_keys($var); + if (array_keys($keys) !== $keys) { + $this->error('Indices for list are not uniform'); + } + } + return $var; + case (self::MIXED): + return $var; + default: + $this->errorInconsistent(get_class($this), $type); + } + $this->errorGeneric($var, $type); + } + + /** + * Actually implements the parsing. Base implementation does not + * do anything to $var. Subclasses should overload this! + * @param mixed $var + * @param int $type + * @param bool $allow_null + * @return string + */ + protected function parseImplementation($var, $type, $allow_null) + { + return $var; + } + + /** + * Throws an exception. + * @throws HTMLPurifier_VarParserException + */ + protected function error($msg) + { + throw new HTMLPurifier_VarParserException($msg); + } + + /** + * Throws an inconsistency exception. + * @note This should not ever be called. It would be called if we + * extend the allowed values of HTMLPurifier_VarParser without + * updating subclasses. + * @param string $class + * @param int $type + * @throws HTMLPurifier_Exception + */ + protected function errorInconsistent($class, $type) + { + throw new HTMLPurifier_Exception( + "Inconsistency in $class: " . HTMLPurifier_VarParser::getTypeName($type) . + " not implemented" + ); + } + + /** + * Generic error for if a type didn't work. + * @param mixed $var + * @param int $type + */ + protected function errorGeneric($var, $type) + { + $vtype = gettype($var); + $this->error("Expected type " . HTMLPurifier_VarParser::getTypeName($type) . ", got $vtype"); + } + + /** + * @param int $type + * @return string + */ + public static function getTypeName($type) + { + static $lookup; + if (!$lookup) { + // Lazy load the alternative lookup table + $lookup = array_flip(HTMLPurifier_VarParser::$types); + } + if (!isset($lookup[$type])) { + return 'unknown'; + } + return $lookup[$type]; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/VarParser/Flexible.php b/library/vendor/HTMLPurifier/VarParser/Flexible.php new file mode 100644 index 000000000..b15016c5b --- /dev/null +++ b/library/vendor/HTMLPurifier/VarParser/Flexible.php @@ -0,0 +1,130 @@ + $j) { + $var[$i] = trim($j); + } + if ($type === self::HASH) { + // key:value,key2:value2 + $nvar = array(); + foreach ($var as $keypair) { + $c = explode(':', $keypair, 2); + if (!isset($c[1])) { + continue; + } + $nvar[trim($c[0])] = trim($c[1]); + } + $var = $nvar; + } + } + if (!is_array($var)) { + break; + } + $keys = array_keys($var); + if ($keys === array_keys($keys)) { + if ($type == self::ALIST) { + return $var; + } elseif ($type == self::LOOKUP) { + $new = array(); + foreach ($var as $key) { + $new[$key] = true; + } + return $new; + } else { + break; + } + } + if ($type === self::ALIST) { + trigger_error("Array list did not have consecutive integer indexes", E_USER_WARNING); + return array_values($var); + } + if ($type === self::LOOKUP) { + foreach ($var as $key => $value) { + if ($value !== true) { + trigger_error( + "Lookup array has non-true value at key '$key'; " . + "maybe your input array was not indexed numerically", + E_USER_WARNING + ); + } + $var[$key] = true; + } + } + return $var; + default: + $this->errorInconsistent(__CLASS__, $type); + } + $this->errorGeneric($var, $type); + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/VarParser/Native.php b/library/vendor/HTMLPurifier/VarParser/Native.php new file mode 100644 index 000000000..f11c318ef --- /dev/null +++ b/library/vendor/HTMLPurifier/VarParser/Native.php @@ -0,0 +1,38 @@ +evalExpression($var); + } + + /** + * @param string $expr + * @return mixed + * @throws HTMLPurifier_VarParserException + */ + protected function evalExpression($expr) + { + $var = null; + $result = eval("\$var = $expr;"); + if ($result === false) { + throw new HTMLPurifier_VarParserException("Fatal error in evaluated code"); + } + return $var; + } +} + +// vim: et sw=4 sts=4 diff --git a/library/vendor/HTMLPurifier/VarParserException.php b/library/vendor/HTMLPurifier/VarParserException.php new file mode 100644 index 000000000..5df341495 --- /dev/null +++ b/library/vendor/HTMLPurifier/VarParserException.php @@ -0,0 +1,11 @@ +front = $front; + $this->back = $back; + } + + /** + * Creates a zipper from an array, with a hole in the + * 0-index position. + * @param Array to zipper-ify. + * @return Tuple of zipper and element of first position. + */ + static public function fromArray($array) { + $z = new self(array(), array_reverse($array)); + $t = $z->delete(); // delete the "dummy hole" + return array($z, $t); + } + + /** + * Convert zipper back into a normal array, optionally filling in + * the hole with a value. (Usually you should supply a $t, unless you + * are at the end of the array.) + */ + public function toArray($t = NULL) { + $a = $this->front; + if ($t !== NULL) $a[] = $t; + for ($i = count($this->back)-1; $i >= 0; $i--) { + $a[] = $this->back[$i]; + } + return $a; + } + + /** + * Move hole to the next element. + * @param $t Element to fill hole with + * @return Original contents of new hole. + */ + public function next($t) { + if ($t !== NULL) array_push($this->front, $t); + return empty($this->back) ? NULL : array_pop($this->back); + } + + /** + * Iterated hole advancement. + * @param $t Element to fill hole with + * @param $i How many forward to advance hole + * @return Original contents of new hole, i away + */ + public function advance($t, $n) { + for ($i = 0; $i < $n; $i++) { + $t = $this->next($t); + } + return $t; + } + + /** + * Move hole to the previous element + * @param $t Element to fill hole with + * @return Original contents of new hole. + */ + public function prev($t) { + if ($t !== NULL) array_push($this->back, $t); + return empty($this->front) ? NULL : array_pop($this->front); + } + + /** + * Delete contents of current hole, shifting hole to + * next element. + * @return Original contents of new hole. + */ + public function delete() { + return empty($this->back) ? NULL : array_pop($this->back); + } + + /** + * Returns true if we are at the end of the list. + * @return bool + */ + public function done() { + return empty($this->back); + } + + /** + * Insert element before hole. + * @param Element to insert + */ + public function insertBefore($t) { + if ($t !== NULL) array_push($this->front, $t); + } + + /** + * Insert element after hole. + * @param Element to insert + */ + public function insertAfter($t) { + if ($t !== NULL) array_push($this->back, $t); + } + + /** + * Splice in multiple elements at hole. Functional specification + * in terms of array_splice: + * + * $arr1 = $arr; + * $old1 = array_splice($arr1, $i, $delete, $replacement); + * + * list($z, $t) = HTMLPurifier_Zipper::fromArray($arr); + * $t = $z->advance($t, $i); + * list($old2, $t) = $z->splice($t, $delete, $replacement); + * $arr2 = $z->toArray($t); + * + * assert($old1 === $old2); + * assert($arr1 === $arr2); + * + * NB: the absolute index location after this operation is + * *unchanged!* + * + * @param Current contents of hole. + */ + public function splice($t, $delete, $replacement) { + // delete + $old = array(); + $r = $t; + for ($i = $delete; $i > 0; $i--) { + $old[] = $r; + $r = $this->delete(); + } + // insert + for ($i = count($replacement)-1; $i >= 0; $i--) { + $this->insertAfter($r); + $r = $replacement[$i]; + } + return array($old, $r); + } +} diff --git a/library/IcingaVendor/JShrink/LICENSE b/library/vendor/JShrink/LICENSE similarity index 100% rename from library/IcingaVendor/JShrink/LICENSE rename to library/vendor/JShrink/LICENSE diff --git a/library/IcingaVendor/JShrink/Minifier.php b/library/vendor/JShrink/Minifier.php similarity index 99% rename from library/IcingaVendor/JShrink/Minifier.php rename to library/vendor/JShrink/Minifier.php index c8f17d93e..22ae087a0 100644 --- a/library/IcingaVendor/JShrink/Minifier.php +++ b/library/vendor/JShrink/Minifier.php @@ -155,6 +155,7 @@ class Minifier { $this->options = array_merge(static::$defaultOptions, $options); $js = str_replace("\r\n", "\n", $js); + $js = str_replace('/**/', '', $js); $this->input = str_replace("\r", "\n", $js); // We add a newline to the end of the script to make it easier to deal diff --git a/library/vendor/JShrink/SOURCE b/library/vendor/JShrink/SOURCE new file mode 100644 index 000000000..fb7b42024 --- /dev/null +++ b/library/vendor/JShrink/SOURCE @@ -0,0 +1,4 @@ +curl https://codeload.github.com/tedious/JShrink/tar.gz/v1.0.1 -o JShrink-1.0.1.tar.gz +tar xzf JShrink-1.0.1.tar.gz --strip-components 1 JShrink-1.0.1/LICENSE +tar xzf JShrink-1.0.1.tar.gz --strip-components 3 JShrink-1.0.1/src/JShrink/Minifier.php +rm JShrink-1.0.1.tar.gz diff --git a/library/IcingaVendor/Parsedown/LICENSE.txt b/library/vendor/Parsedown/LICENSE.txt similarity index 100% rename from library/IcingaVendor/Parsedown/LICENSE.txt rename to library/vendor/Parsedown/LICENSE.txt diff --git a/library/IcingaVendor/Parsedown/Parsedown.php b/library/vendor/Parsedown/Parsedown.php similarity index 100% rename from library/IcingaVendor/Parsedown/Parsedown.php rename to library/vendor/Parsedown/Parsedown.php diff --git a/library/IcingaVendor/Parsedown/SOURCE b/library/vendor/Parsedown/SOURCE similarity index 100% rename from library/IcingaVendor/Parsedown/SOURCE rename to library/vendor/Parsedown/SOURCE diff --git a/library/vendor/Zend/Acl.php b/library/vendor/Zend/Acl.php new file mode 100644 index 000000000..79a2eac15 --- /dev/null +++ b/library/vendor/Zend/Acl.php @@ -0,0 +1,1224 @@ + array( + 'allRoles' => array( + 'allPrivileges' => array( + 'type' => self::TYPE_DENY, + 'assert' => null + ), + 'byPrivilegeId' => array() + ), + 'byRoleId' => array() + ), + 'byResourceId' => array() + ); + + /** + * Adds a Role having an identifier unique to the registry + * + * The $parents parameter may be a reference to, or the string identifier for, + * a Role existing in the registry, or $parents may be passed as an array of + * these - mixing string identifiers and objects is ok - to indicate the Roles + * from which the newly added Role will directly inherit. + * + * In order to resolve potential ambiguities with conflicting rules inherited + * from different parents, the most recently added parent takes precedence over + * parents that were previously added. In other words, the first parent added + * will have the least priority, and the last parent added will have the + * highest priority. + * + * @param Zend_Acl_Role_Interface|string $role + * @param Zend_Acl_Role_Interface|string|array $parents + * @uses Zend_Acl_Role_Registry::add() + * @return Zend_Acl Provides a fluent interface + */ + public function addRole($role, $parents = null) + { + if (is_string($role)) { + $role = new Zend_Acl_Role($role); + } + + if (!$role instanceof Zend_Acl_Role_Interface) { + throw new Zend_Acl_Exception('addRole() expects $role to be of type Zend_Acl_Role_Interface'); + } + + + $this->_getRoleRegistry()->add($role, $parents); + + return $this; + } + + /** + * Returns the identified Role + * + * The $role parameter can either be a Role or Role identifier. + * + * @param Zend_Acl_Role_Interface|string $role + * @uses Zend_Acl_Role_Registry::get() + * @return Zend_Acl_Role_Interface + */ + public function getRole($role) + { + return $this->_getRoleRegistry()->get($role); + } + + /** + * Returns true if and only if the Role exists in the registry + * + * The $role parameter can either be a Role or a Role identifier. + * + * @param Zend_Acl_Role_Interface|string $role + * @uses Zend_Acl_Role_Registry::has() + * @return boolean + */ + public function hasRole($role) + { + return $this->_getRoleRegistry()->has($role); + } + + /** + * Returns true if and only if $role inherits from $inherit + * + * Both parameters may be either a Role or a Role identifier. If + * $onlyParents is true, then $role must inherit directly from + * $inherit in order to return true. By default, this method looks + * through the entire inheritance DAG to determine whether $role + * inherits from $inherit through its ancestor Roles. + * + * @param Zend_Acl_Role_Interface|string $role + * @param Zend_Acl_Role_Interface|string $inherit + * @param boolean $onlyParents + * @uses Zend_Acl_Role_Registry::inherits() + * @return boolean + */ + public function inheritsRole($role, $inherit, $onlyParents = false) + { + return $this->_getRoleRegistry()->inherits($role, $inherit, $onlyParents); + } + + /** + * Removes the Role from the registry + * + * The $role parameter can either be a Role or a Role identifier. + * + * @param Zend_Acl_Role_Interface|string $role + * @uses Zend_Acl_Role_Registry::remove() + * @return Zend_Acl Provides a fluent interface + */ + public function removeRole($role) + { + $this->_getRoleRegistry()->remove($role); + + if ($role instanceof Zend_Acl_Role_Interface) { + $roleId = $role->getRoleId(); + } else { + $roleId = $role; + } + + foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) { + if ($roleId === $roleIdCurrent) { + unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]); + } + } + foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) { + if (array_key_exists('byRoleId', $visitor)) { + foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) { + if ($roleId === $roleIdCurrent) { + unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]); + } + } + } + } + + return $this; + } + + /** + * Removes all Roles from the registry + * + * @uses Zend_Acl_Role_Registry::removeAll() + * @return Zend_Acl Provides a fluent interface + */ + public function removeRoleAll() + { + $this->_getRoleRegistry()->removeAll(); + + foreach ($this->_rules['allResources']['byRoleId'] as $roleIdCurrent => $rules) { + unset($this->_rules['allResources']['byRoleId'][$roleIdCurrent]); + } + foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $visitor) { + foreach ($visitor['byRoleId'] as $roleIdCurrent => $rules) { + unset($this->_rules['byResourceId'][$resourceIdCurrent]['byRoleId'][$roleIdCurrent]); + } + } + + return $this; + } + + /** + * Adds a Resource having an identifier unique to the ACL + * + * The $parent parameter may be a reference to, or the string identifier for, + * the existing Resource from which the newly added Resource will inherit. + * + * @param Zend_Acl_Resource_Interface|string $resource + * @param Zend_Acl_Resource_Interface|string $parent + * @throws Zend_Acl_Exception + * @return Zend_Acl Provides a fluent interface + */ + public function addResource($resource, $parent = null) + { + if (is_string($resource)) { + $resource = new Zend_Acl_Resource($resource); + } + + if (!$resource instanceof Zend_Acl_Resource_Interface) { + throw new Zend_Acl_Exception('addResource() expects $resource to be of type Zend_Acl_Resource_Interface'); + } + + $resourceId = $resource->getResourceId(); + + if ($this->has($resourceId)) { + throw new Zend_Acl_Exception("Resource id '$resourceId' already exists in the ACL"); + } + + $resourceParent = null; + + if (null !== $parent) { + try { + if ($parent instanceof Zend_Acl_Resource_Interface) { + $resourceParentId = $parent->getResourceId(); + } else { + $resourceParentId = $parent; + } + $resourceParent = $this->get($resourceParentId); + } catch (Zend_Acl_Exception $e) { + throw new Zend_Acl_Exception("Parent Resource id '$resourceParentId' does not exist", 0, $e); + } + $this->_resources[$resourceParentId]['children'][$resourceId] = $resource; + } + + $this->_resources[$resourceId] = array( + 'instance' => $resource, + 'parent' => $resourceParent, + 'children' => array() + ); + + return $this; + } + + /** + * Adds a Resource having an identifier unique to the ACL + * + * The $parent parameter may be a reference to, or the string identifier for, + * the existing Resource from which the newly added Resource will inherit. + * + * @deprecated in version 1.9.1 and will be available till 2.0. New code + * should use addResource() instead. + * + * @param Zend_Acl_Resource_Interface $resource + * @param Zend_Acl_Resource_Interface|string $parent + * @throws Zend_Acl_Exception + * @return Zend_Acl Provides a fluent interface + */ + public function add(Zend_Acl_Resource_Interface $resource, $parent = null) + { + return $this->addResource($resource, $parent); + } + + /** + * Returns the identified Resource + * + * The $resource parameter can either be a Resource or a Resource identifier. + * + * @param Zend_Acl_Resource_Interface|string $resource + * @throws Zend_Acl_Exception + * @return Zend_Acl_Resource_Interface + */ + public function get($resource) + { + if ($resource instanceof Zend_Acl_Resource_Interface) { + $resourceId = $resource->getResourceId(); + } else { + $resourceId = (string) $resource; + } + + if (!$this->has($resource)) { + throw new Zend_Acl_Exception("Resource '$resourceId' not found"); + } + + return $this->_resources[$resourceId]['instance']; + } + + /** + * Returns true if and only if the Resource exists in the ACL + * + * The $resource parameter can either be a Resource or a Resource identifier. + * + * @param Zend_Acl_Resource_Interface|string $resource + * @return boolean + */ + public function has($resource) + { + if ($resource instanceof Zend_Acl_Resource_Interface) { + $resourceId = $resource->getResourceId(); + } else { + $resourceId = (string) $resource; + } + + return isset($this->_resources[$resourceId]); + } + + /** + * Returns true if and only if $resource inherits from $inherit + * + * Both parameters may be either a Resource or a Resource identifier. If + * $onlyParent is true, then $resource must inherit directly from + * $inherit in order to return true. By default, this method looks + * through the entire inheritance tree to determine whether $resource + * inherits from $inherit through its ancestor Resources. + * + * @param Zend_Acl_Resource_Interface|string $resource + * @param Zend_Acl_Resource_Interface|string $inherit + * @param boolean $onlyParent + * @throws Zend_Acl_Resource_Registry_Exception + * @return boolean + */ + public function inherits($resource, $inherit, $onlyParent = false) + { + try { + $resourceId = $this->get($resource)->getResourceId(); + $inheritId = $this->get($inherit)->getResourceId(); + } catch (Zend_Acl_Exception $e) { + throw new Zend_Acl_Exception($e->getMessage(), $e->getCode(), $e); + } + + if (null !== $this->_resources[$resourceId]['parent']) { + $parentId = $this->_resources[$resourceId]['parent']->getResourceId(); + if ($inheritId === $parentId) { + return true; + } else if ($onlyParent) { + return false; + } + } else { + return false; + } + + while (null !== $this->_resources[$parentId]['parent']) { + $parentId = $this->_resources[$parentId]['parent']->getResourceId(); + if ($inheritId === $parentId) { + return true; + } + } + + return false; + } + + /** + * Removes a Resource and all of its children + * + * The $resource parameter can either be a Resource or a Resource identifier. + * + * @param Zend_Acl_Resource_Interface|string $resource + * @throws Zend_Acl_Exception + * @return Zend_Acl Provides a fluent interface + */ + public function remove($resource) + { + try { + $resourceId = $this->get($resource)->getResourceId(); + } catch (Zend_Acl_Exception $e) { + throw new Zend_Acl_Exception($e->getMessage(), $e->getCode(), $e); + } + + $resourcesRemoved = array($resourceId); + if (null !== ($resourceParent = $this->_resources[$resourceId]['parent'])) { + unset($this->_resources[$resourceParent->getResourceId()]['children'][$resourceId]); + } + foreach ($this->_resources[$resourceId]['children'] as $childId => $child) { + $this->remove($childId); + $resourcesRemoved[] = $childId; + } + + foreach ($resourcesRemoved as $resourceIdRemoved) { + foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) { + if ($resourceIdRemoved === $resourceIdCurrent) { + unset($this->_rules['byResourceId'][$resourceIdCurrent]); + } + } + } + + unset($this->_resources[$resourceId]); + + return $this; + } + + /** + * Removes all Resources + * + * @return Zend_Acl Provides a fluent interface + */ + public function removeAll() + { + foreach ($this->_resources as $resourceId => $resource) { + foreach ($this->_rules['byResourceId'] as $resourceIdCurrent => $rules) { + if ($resourceId === $resourceIdCurrent) { + unset($this->_rules['byResourceId'][$resourceIdCurrent]); + } + } + } + + $this->_resources = array(); + + return $this; + } + + /** + * Adds an "allow" rule to the ACL + * + * @param Zend_Acl_Role_Interface|string|array $roles + * @param Zend_Acl_Resource_Interface|string|array $resources + * @param string|array $privileges + * @param Zend_Acl_Assert_Interface $assert + * @uses Zend_Acl::setRule() + * @return Zend_Acl Provides a fluent interface + */ + public function allow($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null) + { + return $this->setRule(self::OP_ADD, self::TYPE_ALLOW, $roles, $resources, $privileges, $assert); + } + + /** + * Adds a "deny" rule to the ACL + * + * @param Zend_Acl_Role_Interface|string|array $roles + * @param Zend_Acl_Resource_Interface|string|array $resources + * @param string|array $privileges + * @param Zend_Acl_Assert_Interface $assert + * @uses Zend_Acl::setRule() + * @return Zend_Acl Provides a fluent interface + */ + public function deny($roles = null, $resources = null, $privileges = null, Zend_Acl_Assert_Interface $assert = null) + { + return $this->setRule(self::OP_ADD, self::TYPE_DENY, $roles, $resources, $privileges, $assert); + } + + /** + * Removes "allow" permissions from the ACL + * + * @param Zend_Acl_Role_Interface|string|array $roles + * @param Zend_Acl_Resource_Interface|string|array $resources + * @param string|array $privileges + * @uses Zend_Acl::setRule() + * @return Zend_Acl Provides a fluent interface + */ + public function removeAllow($roles = null, $resources = null, $privileges = null) + { + return $this->setRule(self::OP_REMOVE, self::TYPE_ALLOW, $roles, $resources, $privileges); + } + + /** + * Removes "deny" restrictions from the ACL + * + * @param Zend_Acl_Role_Interface|string|array $roles + * @param Zend_Acl_Resource_Interface|string|array $resources + * @param string|array $privileges + * @uses Zend_Acl::setRule() + * @return Zend_Acl Provides a fluent interface + */ + public function removeDeny($roles = null, $resources = null, $privileges = null) + { + return $this->setRule(self::OP_REMOVE, self::TYPE_DENY, $roles, $resources, $privileges); + } + + /** + * Performs operations on ACL rules + * + * The $operation parameter may be either OP_ADD or OP_REMOVE, depending on whether the + * user wants to add or remove a rule, respectively: + * + * OP_ADD specifics: + * + * A rule is added that would allow one or more Roles access to [certain $privileges + * upon] the specified Resource(s). + * + * OP_REMOVE specifics: + * + * The rule is removed only in the context of the given Roles, Resources, and privileges. + * Existing rules to which the remove operation does not apply would remain in the + * ACL. + * + * The $type parameter may be either TYPE_ALLOW or TYPE_DENY, depending on whether the + * rule is intended to allow or deny permission, respectively. + * + * The $roles and $resources parameters may be references to, or the string identifiers for, + * existing Resources/Roles, or they may be passed as arrays of these - mixing string identifiers + * and objects is ok - to indicate the Resources and Roles to which the rule applies. If either + * $roles or $resources is null, then the rule applies to all Roles or all Resources, respectively. + * Both may be null in order to work with the default rule of the ACL. + * + * The $privileges parameter may be used to further specify that the rule applies only + * to certain privileges upon the Resource(s) in question. This may be specified to be a single + * privilege with a string, and multiple privileges may be specified as an array of strings. + * + * If $assert is provided, then its assert() method must return true in order for + * the rule to apply. If $assert is provided with $roles, $resources, and $privileges all + * equal to null, then a rule having a type of: + * + * TYPE_ALLOW will imply a type of TYPE_DENY, and + * + * TYPE_DENY will imply a type of TYPE_ALLOW + * + * when the rule's assertion fails. This is because the ACL needs to provide expected + * behavior when an assertion upon the default ACL rule fails. + * + * @param string $operation + * @param string $type + * @param Zend_Acl_Role_Interface|string|array $roles + * @param Zend_Acl_Resource_Interface|string|array $resources + * @param string|array $privileges + * @param Zend_Acl_Assert_Interface $assert + * @throws Zend_Acl_Exception + * @uses Zend_Acl_Role_Registry::get() + * @uses Zend_Acl::get() + * @return Zend_Acl Provides a fluent interface + */ + public function setRule($operation, $type, $roles = null, $resources = null, $privileges = null, + Zend_Acl_Assert_Interface $assert = null) + { + // ensure that the rule type is valid; normalize input to uppercase + $type = strtoupper($type); + if (self::TYPE_ALLOW !== $type && self::TYPE_DENY !== $type) { + throw new Zend_Acl_Exception("Unsupported rule type; must be either '" . self::TYPE_ALLOW . "' or '" + . self::TYPE_DENY . "'"); + } + + // ensure that all specified Roles exist; normalize input to array of Role objects or null + if (!is_array($roles)) { + $roles = array($roles); + } else if (0 === count($roles)) { + $roles = array(null); + } + $rolesTemp = $roles; + $roles = array(); + foreach ($rolesTemp as $role) { + if (null !== $role) { + $roles[] = $this->_getRoleRegistry()->get($role); + } else { + $roles[] = null; + } + } + unset($rolesTemp); + + // ensure that all specified Resources exist; normalize input to array of Resource objects or null + if ($resources !== null) { + if (!is_array($resources)) { + $resources = array($resources); + } else if (0 === count($resources)) { + $resources = array(null); + } + $resourcesTemp = $resources; + $resources = array(); + foreach ($resourcesTemp as $resource) { + if (null !== $resource) { + $resources[] = $this->get($resource); + } else { + $resources[] = null; + } + } + unset($resourcesTemp, $resource); + } else { + $allResources = array(); // this might be used later if resource iteration is required + foreach ($this->_resources as $rTarget) { + $allResources[] = $rTarget['instance']; + } + unset($rTarget); + } + + // normalize privileges to array + if (null === $privileges) { + $privileges = array(); + } else if (!is_array($privileges)) { + $privileges = array($privileges); + } + + switch ($operation) { + + // add to the rules + case self::OP_ADD: + if ($resources !== null) { + // this block will iterate the provided resources + foreach ($resources as $resource) { + foreach ($roles as $role) { + $rules =& $this->_getRules($resource, $role, true); + if (0 === count($privileges)) { + $rules['allPrivileges']['type'] = $type; + $rules['allPrivileges']['assert'] = $assert; + if (!isset($rules['byPrivilegeId'])) { + $rules['byPrivilegeId'] = array(); + } + } else { + foreach ($privileges as $privilege) { + $rules['byPrivilegeId'][$privilege]['type'] = $type; + $rules['byPrivilegeId'][$privilege]['assert'] = $assert; + } + } + } + } + } else { + // this block will apply to all resources in a global rule + foreach ($roles as $role) { + $rules =& $this->_getRules(null, $role, true); + if (0 === count($privileges)) { + $rules['allPrivileges']['type'] = $type; + $rules['allPrivileges']['assert'] = $assert; + } else { + foreach ($privileges as $privilege) { + $rules['byPrivilegeId'][$privilege]['type'] = $type; + $rules['byPrivilegeId'][$privilege]['assert'] = $assert; + } + } + } + } + break; + + // remove from the rules + case self::OP_REMOVE: + if ($resources !== null) { + // this block will iterate the provided resources + foreach ($resources as $resource) { + foreach ($roles as $role) { + $rules =& $this->_getRules($resource, $role); + if (null === $rules) { + continue; + } + if (0 === count($privileges)) { + if (null === $resource && null === $role) { + if ($type === $rules['allPrivileges']['type']) { + $rules = array( + 'allPrivileges' => array( + 'type' => self::TYPE_DENY, + 'assert' => null + ), + 'byPrivilegeId' => array() + ); + } + continue; + } + + if (isset($rules['allPrivileges']['type']) && + $type === $rules['allPrivileges']['type']) + { + unset($rules['allPrivileges']); + } + } else { + foreach ($privileges as $privilege) { + if (isset($rules['byPrivilegeId'][$privilege]) && + $type === $rules['byPrivilegeId'][$privilege]['type']) + { + unset($rules['byPrivilegeId'][$privilege]); + } + } + } + } + } + } else { + // this block will apply to all resources in a global rule + foreach ($roles as $role) { + /** + * since null (all resources) was passed to this setRule() call, we need + * clean up all the rules for the global allResources, as well as the indivually + * set resources (per privilege as well) + */ + foreach (array_merge(array(null), $allResources) as $resource) { + $rules =& $this->_getRules($resource, $role, true); + if (null === $rules) { + continue; + } + if (0 === count($privileges)) { + if (null === $role) { + if ($type === $rules['allPrivileges']['type']) { + $rules = array( + 'allPrivileges' => array( + 'type' => self::TYPE_DENY, + 'assert' => null + ), + 'byPrivilegeId' => array() + ); + } + continue; + } + + if (isset($rules['allPrivileges']['type']) && $type === $rules['allPrivileges']['type']) { + unset($rules['allPrivileges']); + } + } else { + foreach ($privileges as $privilege) { + if (isset($rules['byPrivilegeId'][$privilege]) && + $type === $rules['byPrivilegeId'][$privilege]['type']) + { + unset($rules['byPrivilegeId'][$privilege]); + } + } + } + } + } + } + break; + + default: + throw new Zend_Acl_Exception("Unsupported operation; must be either '" . self::OP_ADD . "' or '" + . self::OP_REMOVE . "'"); + } + + return $this; + } + + /** + * Returns true if and only if the Role has access to the Resource + * + * The $role and $resource parameters may be references to, or the string identifiers for, + * an existing Resource and Role combination. + * + * If either $role or $resource is null, then the query applies to all Roles or all Resources, + * respectively. Both may be null to query whether the ACL has a "blacklist" rule + * (allow everything to all). By default, Zend_Acl creates a "whitelist" rule (deny + * everything to all), and this method would return false unless this default has + * been overridden (i.e., by executing $acl->allow()). + * + * If a $privilege is not provided, then this method returns false if and only if the + * Role is denied access to at least one privilege upon the Resource. In other words, this + * method returns true if and only if the Role is allowed all privileges on the Resource. + * + * This method checks Role inheritance using a depth-first traversal of the Role registry. + * The highest priority parent (i.e., the parent most recently added) is checked first, + * and its respective parents are checked similarly before the lower-priority parents of + * the Role are checked. + * + * @param Zend_Acl_Role_Interface|string $role + * @param Zend_Acl_Resource_Interface|string $resource + * @param string $privilege + * @uses Zend_Acl::get() + * @uses Zend_Acl_Role_Registry::get() + * @return boolean + */ + public function isAllowed($role = null, $resource = null, $privilege = null) + { + // reset role & resource to null + $this->_isAllowedRole = null; + $this->_isAllowedResource = null; + $this->_isAllowedPrivilege = null; + + if (null !== $role) { + // keep track of originally called role + $this->_isAllowedRole = $role; + $role = $this->_getRoleRegistry()->get($role); + if (!$this->_isAllowedRole instanceof Zend_Acl_Role_Interface) { + $this->_isAllowedRole = $role; + } + } + + if (null !== $resource) { + // keep track of originally called resource + $this->_isAllowedResource = $resource; + $resource = $this->get($resource); + if (!$this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) { + $this->_isAllowedResource = $resource; + } + } + + if (null === $privilege) { + // query on all privileges + do { + // depth-first search on $role if it is not 'allRoles' pseudo-parent + if (null !== $role && null !== ($result = $this->_roleDFSAllPrivileges($role, $resource, $privilege))) { + return $result; + } + + // look for rule on 'allRoles' psuedo-parent + if (null !== ($rules = $this->_getRules($resource, null))) { + foreach ($rules['byPrivilegeId'] as $privilege => $rule) { + if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, null, $privilege))) { + return false; + } + } + if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) { + return self::TYPE_ALLOW === $ruleTypeAllPrivileges; + } + } + + // try next Resource + $resource = $this->_resources[$resource->getResourceId()]['parent']; + + } while (true); // loop terminates at 'allResources' pseudo-parent + } else { + $this->_isAllowedPrivilege = $privilege; + // query on one privilege + do { + // depth-first search on $role if it is not 'allRoles' pseudo-parent + if (null !== $role && null !== ($result = $this->_roleDFSOnePrivilege($role, $resource, $privilege))) { + return $result; + } + + // look for rule on 'allRoles' pseudo-parent + if (null !== ($ruleType = $this->_getRuleType($resource, null, $privilege))) { + return self::TYPE_ALLOW === $ruleType; + } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, null, null))) { + return self::TYPE_ALLOW === $ruleTypeAllPrivileges; + } + + // try next Resource + $resource = $this->_resources[$resource->getResourceId()]['parent']; + + } while (true); // loop terminates at 'allResources' pseudo-parent + } + } + + /** + * Returns the Role registry for this ACL + * + * If no Role registry has been created yet, a new default Role registry + * is created and returned. + * + * @return Zend_Acl_Role_Registry + */ + protected function _getRoleRegistry() + { + if (null === $this->_roleRegistry) { + $this->_roleRegistry = new Zend_Acl_Role_Registry(); + } + return $this->_roleRegistry; + } + + /** + * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule + * allowing/denying $role access to all privileges upon $resource + * + * This method returns true if a rule is found and allows access. If a rule exists and denies access, + * then this method returns false. If no applicable rule is found, then this method returns null. + * + * @param Zend_Acl_Role_Interface $role + * @param Zend_Acl_Resource_Interface $resource + * @return boolean|null + */ + protected function _roleDFSAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null) + { + $dfs = array( + 'visited' => array(), + 'stack' => array() + ); + + if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) { + return $result; + } + + while (null !== ($role = array_pop($dfs['stack']))) { + if (!isset($dfs['visited'][$role->getRoleId()])) { + if (null !== ($result = $this->_roleDFSVisitAllPrivileges($role, $resource, $dfs))) { + return $result; + } + } + } + + return null; + } + + /** + * Visits an $role in order to look for a rule allowing/denying $role access to all privileges upon $resource + * + * This method returns true if a rule is found and allows access. If a rule exists and denies access, + * then this method returns false. If no applicable rule is found, then this method returns null. + * + * This method is used by the internal depth-first search algorithm and may modify the DFS data structure. + * + * @param Zend_Acl_Role_Interface $role + * @param Zend_Acl_Resource_Interface $resource + * @param array $dfs + * @return boolean|null + * @throws Zend_Acl_Exception + */ + protected function _roleDFSVisitAllPrivileges(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null, + &$dfs = null) + { + if (null === $dfs) { + /** + * @see Zend_Acl_Exception + */ + throw new Zend_Acl_Exception('$dfs parameter may not be null'); + } + + if (null !== ($rules = $this->_getRules($resource, $role))) { + foreach ($rules['byPrivilegeId'] as $privilege => $rule) { + if (self::TYPE_DENY === ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) { + return false; + } + } + if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) { + return self::TYPE_ALLOW === $ruleTypeAllPrivileges; + } + } + + $dfs['visited'][$role->getRoleId()] = true; + foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) { + $dfs['stack'][] = $roleParent; + } + + return null; + } + + /** + * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule + * allowing/denying $role access to a $privilege upon $resource + * + * This method returns true if a rule is found and allows access. If a rule exists and denies access, + * then this method returns false. If no applicable rule is found, then this method returns null. + * + * @param Zend_Acl_Role_Interface $role + * @param Zend_Acl_Resource_Interface $resource + * @param string $privilege + * @return boolean|null + * @throws Zend_Acl_Exception + */ + protected function _roleDFSOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null, + $privilege = null) + { + if (null === $privilege) { + /** + * @see Zend_Acl_Exception + */ + throw new Zend_Acl_Exception('$privilege parameter may not be null'); + } + + $dfs = array( + 'visited' => array(), + 'stack' => array() + ); + + if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) { + return $result; + } + + while (null !== ($role = array_pop($dfs['stack']))) { + if (!isset($dfs['visited'][$role->getRoleId()])) { + if (null !== ($result = $this->_roleDFSVisitOnePrivilege($role, $resource, $privilege, $dfs))) { + return $result; + } + } + } + + return null; + } + + /** + * Visits an $role in order to look for a rule allowing/denying $role access to a $privilege upon $resource + * + * This method returns true if a rule is found and allows access. If a rule exists and denies access, + * then this method returns false. If no applicable rule is found, then this method returns null. + * + * This method is used by the internal depth-first search algorithm and may modify the DFS data structure. + * + * @param Zend_Acl_Role_Interface $role + * @param Zend_Acl_Resource_Interface $resource + * @param string $privilege + * @param array $dfs + * @return boolean|null + * @throws Zend_Acl_Exception + */ + protected function _roleDFSVisitOnePrivilege(Zend_Acl_Role_Interface $role, Zend_Acl_Resource_Interface $resource = null, + $privilege = null, &$dfs = null) + { + if (null === $privilege) { + /** + * @see Zend_Acl_Exception + */ + throw new Zend_Acl_Exception('$privilege parameter may not be null'); + } + + if (null === $dfs) { + /** + * @see Zend_Acl_Exception + */ + throw new Zend_Acl_Exception('$dfs parameter may not be null'); + } + + if (null !== ($ruleTypeOnePrivilege = $this->_getRuleType($resource, $role, $privilege))) { + return self::TYPE_ALLOW === $ruleTypeOnePrivilege; + } else if (null !== ($ruleTypeAllPrivileges = $this->_getRuleType($resource, $role, null))) { + return self::TYPE_ALLOW === $ruleTypeAllPrivileges; + } + + $dfs['visited'][$role->getRoleId()] = true; + foreach ($this->_getRoleRegistry()->getParents($role) as $roleParentId => $roleParent) { + $dfs['stack'][] = $roleParent; + } + + return null; + } + + /** + * Returns the rule type associated with the specified Resource, Role, and privilege + * combination. + * + * If a rule does not exist or its attached assertion fails, which means that + * the rule is not applicable, then this method returns null. Otherwise, the + * rule type applies and is returned as either TYPE_ALLOW or TYPE_DENY. + * + * If $resource or $role is null, then this means that the rule must apply to + * all Resources or Roles, respectively. + * + * If $privilege is null, then the rule must apply to all privileges. + * + * If all three parameters are null, then the default ACL rule type is returned, + * based on whether its assertion method passes. + * + * @param Zend_Acl_Resource_Interface $resource + * @param Zend_Acl_Role_Interface $role + * @param string $privilege + * @return string|null + */ + protected function _getRuleType(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null, + $privilege = null) + { + // get the rules for the $resource and $role + if (null === ($rules = $this->_getRules($resource, $role))) { + return null; + } + + // follow $privilege + if (null === $privilege) { + if (isset($rules['allPrivileges'])) { + $rule = $rules['allPrivileges']; + } else { + return null; + } + } else if (!isset($rules['byPrivilegeId'][$privilege])) { + return null; + } else { + $rule = $rules['byPrivilegeId'][$privilege]; + } + + // check assertion first + if ($rule['assert']) { + $assertion = $rule['assert']; + $assertionValue = $assertion->assert( + $this, + ($this->_isAllowedRole instanceof Zend_Acl_Role_Interface) ? $this->_isAllowedRole : $role, + ($this->_isAllowedResource instanceof Zend_Acl_Resource_Interface) ? $this->_isAllowedResource : $resource, + $this->_isAllowedPrivilege + ); + } + + if (null === $rule['assert'] || $assertionValue) { + return $rule['type']; + } else if (null !== $resource || null !== $role || null !== $privilege) { + return null; + } else if (self::TYPE_ALLOW === $rule['type']) { + return self::TYPE_DENY; + } else { + return self::TYPE_ALLOW; + } + } + + /** + * Returns the rules associated with a Resource and a Role, or null if no such rules exist + * + * If either $resource or $role is null, this means that the rules returned are for all Resources or all Roles, + * respectively. Both can be null to return the default rule set for all Resources and all Roles. + * + * If the $create parameter is true, then a rule set is first created and then returned to the caller. + * + * @param Zend_Acl_Resource_Interface $resource + * @param Zend_Acl_Role_Interface $role + * @param boolean $create + * @return array|null + */ + protected function &_getRules(Zend_Acl_Resource_Interface $resource = null, Zend_Acl_Role_Interface $role = null, + $create = false) + { + // create a reference to null + $null = null; + $nullRef =& $null; + + // follow $resource + do { + if (null === $resource) { + $visitor =& $this->_rules['allResources']; + break; + } + $resourceId = $resource->getResourceId(); + if (!isset($this->_rules['byResourceId'][$resourceId])) { + if (!$create) { + return $nullRef; + } + $this->_rules['byResourceId'][$resourceId] = array(); + } + $visitor =& $this->_rules['byResourceId'][$resourceId]; + } while (false); + + + // follow $role + if (null === $role) { + if (!isset($visitor['allRoles'])) { + if (!$create) { + return $nullRef; + } + $visitor['allRoles']['byPrivilegeId'] = array(); + } + return $visitor['allRoles']; + } + $roleId = $role->getRoleId(); + if (!isset($visitor['byRoleId'][$roleId])) { + if (!$create) { + return $nullRef; + } + $visitor['byRoleId'][$roleId]['byPrivilegeId'] = array(); + $visitor['byRoleId'][$roleId]['allPrivileges'] = array('type' => null, 'assert' => null); + } + return $visitor['byRoleId'][$roleId]; + } + + + /** + * @return array of registered roles (Deprecated) + * @deprecated Deprecated since version 1.10 (December 2009) + */ + public function getRegisteredRoles() + { + trigger_error('The method getRegisteredRoles() was deprecated as of ' + . 'version 1.0, and may be removed. You\'re encouraged ' + . 'to use getRoles() instead.'); + + return $this->_getRoleRegistry()->getRoles(); + } + + /** + * Returns an array of registered roles. + * + * Note that this method does not return instances of registered roles, + * but only the role identifiers. + * + * @return array of registered roles + */ + public function getRoles() + { + return array_keys($this->_getRoleRegistry()->getRoles()); + } + + /** + * @return array of registered resources + */ + public function getResources() + { + return array_keys($this->_resources); + } + +} + diff --git a/library/vendor/Zend/Acl/Assert/Interface.php b/library/vendor/Zend/Acl/Assert/Interface.php new file mode 100644 index 000000000..37fdabaac --- /dev/null +++ b/library/vendor/Zend/Acl/Assert/Interface.php @@ -0,0 +1,61 @@ +_resourceId = (string) $resourceId; + } + + /** + * Defined by Zend_Acl_Resource_Interface; returns the Resource identifier + * + * @return string + */ + public function getResourceId() + { + return $this->_resourceId; + } + + /** + * Defined by Zend_Acl_Resource_Interface; returns the Resource identifier + * Proxies to getResourceId() + * + * @return string + */ + public function __toString() + { + return $this->getResourceId(); + } +} diff --git a/library/vendor/Zend/Acl/Resource/Interface.php b/library/vendor/Zend/Acl/Resource/Interface.php new file mode 100644 index 000000000..3c6d35807 --- /dev/null +++ b/library/vendor/Zend/Acl/Resource/Interface.php @@ -0,0 +1,37 @@ +_roleId = (string) $roleId; + } + + /** + * Defined by Zend_Acl_Role_Interface; returns the Role identifier + * + * @return string + */ + public function getRoleId() + { + return $this->_roleId; + } + + /** + * Defined by Zend_Acl_Role_Interface; returns the Role identifier + * Proxies to getRoleId() + * + * @return string + */ + public function __toString() + { + return $this->getRoleId(); + } +} diff --git a/library/vendor/Zend/Acl/Role/Interface.php b/library/vendor/Zend/Acl/Role/Interface.php new file mode 100644 index 000000000..0bd3fb59d --- /dev/null +++ b/library/vendor/Zend/Acl/Role/Interface.php @@ -0,0 +1,37 @@ +getRoleId(); + + if ($this->has($roleId)) { + /** + * @see Zend_Acl_Role_Registry_Exception + */ + throw new Zend_Acl_Role_Registry_Exception("Role id '$roleId' already exists in the registry"); + } + + $roleParents = array(); + + if (null !== $parents) { + if (!is_array($parents)) { + $parents = array($parents); + } + /** + * @see Zend_Acl_Role_Registry_Exception + */ + foreach ($parents as $parent) { + try { + if ($parent instanceof Zend_Acl_Role_Interface) { + $roleParentId = $parent->getRoleId(); + } else { + $roleParentId = $parent; + } + $roleParent = $this->get($roleParentId); + } catch (Zend_Acl_Role_Registry_Exception $e) { + throw new Zend_Acl_Role_Registry_Exception("Parent Role id '$roleParentId' does not exist", 0, $e); + } + $roleParents[$roleParentId] = $roleParent; + $this->_roles[$roleParentId]['children'][$roleId] = $role; + } + } + + $this->_roles[$roleId] = array( + 'instance' => $role, + 'parents' => $roleParents, + 'children' => array() + ); + + return $this; + } + + /** + * Returns the identified Role + * + * The $role parameter can either be a Role or a Role identifier. + * + * @param Zend_Acl_Role_Interface|string $role + * @throws Zend_Acl_Role_Registry_Exception + * @return Zend_Acl_Role_Interface + */ + public function get($role) + { + if ($role instanceof Zend_Acl_Role_Interface) { + $roleId = $role->getRoleId(); + } else { + $roleId = (string) $role; + } + + if (!$this->has($role)) { + /** + * @see Zend_Acl_Role_Registry_Exception + */ + throw new Zend_Acl_Role_Registry_Exception("Role '$roleId' not found"); + } + + return $this->_roles[$roleId]['instance']; + } + + /** + * Returns true if and only if the Role exists in the registry + * + * The $role parameter can either be a Role or a Role identifier. + * + * @param Zend_Acl_Role_Interface|string $role + * @return boolean + */ + public function has($role) + { + if ($role instanceof Zend_Acl_Role_Interface) { + $roleId = $role->getRoleId(); + } else { + $roleId = (string) $role; + } + + return isset($this->_roles[$roleId]); + } + + /** + * Returns an array of an existing Role's parents + * + * The array keys are the identifiers of the parent Roles, and the values are + * the parent Role instances. The parent Roles are ordered in this array by + * ascending priority. The highest priority parent Role, last in the array, + * corresponds with the parent Role most recently added. + * + * If the Role does not have any parents, then an empty array is returned. + * + * @param Zend_Acl_Role_Interface|string $role + * @uses Zend_Acl_Role_Registry::get() + * @return array + */ + public function getParents($role) + { + $roleId = $this->get($role)->getRoleId(); + + return $this->_roles[$roleId]['parents']; + } + + /** + * Returns true if and only if $role inherits from $inherit + * + * Both parameters may be either a Role or a Role identifier. If + * $onlyParents is true, then $role must inherit directly from + * $inherit in order to return true. By default, this method looks + * through the entire inheritance DAG to determine whether $role + * inherits from $inherit through its ancestor Roles. + * + * @param Zend_Acl_Role_Interface|string $role + * @param Zend_Acl_Role_Interface|string $inherit + * @param boolean $onlyParents + * @throws Zend_Acl_Role_Registry_Exception + * @return boolean + */ + public function inherits($role, $inherit, $onlyParents = false) + { + /** + * @see Zend_Acl_Role_Registry_Exception + */ + try { + $roleId = $this->get($role)->getRoleId(); + $inheritId = $this->get($inherit)->getRoleId(); + } catch (Zend_Acl_Role_Registry_Exception $e) { + throw new Zend_Acl_Role_Registry_Exception($e->getMessage(), $e->getCode(), $e); + } + + $inherits = isset($this->_roles[$roleId]['parents'][$inheritId]); + + if ($inherits || $onlyParents) { + return $inherits; + } + + foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) { + if ($this->inherits($parentId, $inheritId)) { + return true; + } + } + + return false; + } + + /** + * Removes the Role from the registry + * + * The $role parameter can either be a Role or a Role identifier. + * + * @param Zend_Acl_Role_Interface|string $role + * @throws Zend_Acl_Role_Registry_Exception + * @return Zend_Acl_Role_Registry Provides a fluent interface + */ + public function remove($role) + { + /** + * @see Zend_Acl_Role_Registry_Exception + */ + try { + $roleId = $this->get($role)->getRoleId(); + } catch (Zend_Acl_Role_Registry_Exception $e) { + throw new Zend_Acl_Role_Registry_Exception($e->getMessage(), $e->getCode(), $e); + } + + foreach ($this->_roles[$roleId]['children'] as $childId => $child) { + unset($this->_roles[$childId]['parents'][$roleId]); + } + foreach ($this->_roles[$roleId]['parents'] as $parentId => $parent) { + unset($this->_roles[$parentId]['children'][$roleId]); + } + + unset($this->_roles[$roleId]); + + return $this; + } + + /** + * Removes all Roles from the registry + * + * @return Zend_Acl_Role_Registry Provides a fluent interface + */ + public function removeAll() + { + $this->_roles = array(); + + return $this; + } + + public function getRoles() + { + return $this->_roles; + } + +} diff --git a/library/vendor/Zend/Acl/Role/Registry/Exception.php b/library/vendor/Zend/Acl/Role/Registry/Exception.php new file mode 100644 index 000000000..10ff5345b --- /dev/null +++ b/library/vendor/Zend/Acl/Role/Registry/Exception.php @@ -0,0 +1,35 @@ +_acl = new Zend_Acl(); + $xml = Zend_Xml_Security::scanFile($rolefile); +/* +Roles file format: + + + + + + + + +*/ + foreach($xml->role as $role) { + $this->_acl->addRole(new Zend_Acl_Role((string)$role["id"])); + foreach($role->user as $user) { + $this->_users[(string)$user["name"]] = array("password" => (string)$user["password"], + "role" => (string)$role["id"]); + } + } + } + + /** + * Get ACL with roles from XML file + * + * @return Zend_Acl + */ + public function getAcl() + { + return $this->_acl; + } + + /** + * Perform authentication + * + * @throws Zend_Auth_Adapter_Exception + * @return Zend_Auth_Result + * @see Zend_Auth_Adapter_Interface#authenticate() + */ + public function authenticate() + { + if (empty($this->_username) || + empty($this->_password)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Username/password should be set'); + } + + if(!isset($this->_users[$this->_username])) { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, + null, + array('Username not found') + ); + } + + $user = $this->_users[$this->_username]; + if($user["password"] != $this->_password) { + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, + null, + array('Authentication failed') + ); + } + + $id = new stdClass(); + $id->role = $user["role"]; + $id->name = $this->_username; + return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $id); + } +} diff --git a/library/vendor/Zend/Amf/Adobe/DbInspector.php b/library/vendor/Zend/Amf/Adobe/DbInspector.php new file mode 100755 index 000000000..48b46be43 --- /dev/null +++ b/library/vendor/Zend/Amf/Adobe/DbInspector.php @@ -0,0 +1,103 @@ +describeTable('Pdo_Mysql', + * array( + * 'host' => '127.0.0.1', + * 'username' => 'webuser', + * 'password' => 'xxxxxxxx', + * 'dbname' => 'test' + * ), + * 'mytable' + * ); + * + * @param string $dbType Database adapter type for Zend_Db + * @param array|object $dbDescription Adapter-specific connection settings + * @param string $tableName Table name + * @return array Table description + * @see Zend_Db::describeTable() + * @see Zend_Db::factory() + */ + public function describeTable($dbType, $dbDescription, $tableName) + { + $db = $this->_connect($dbType, $dbDescription); + return $db->describeTable($tableName); + } + + /** + * Test database connection + * + * @param string $dbType Database adapter type for Zend_Db + * @param array|object $dbDescription Adapter-specific connection settings + * @return bool + * @see Zend_Db::factory() + */ + public function connect($dbType, $dbDescription) + { + $db = $this->_connect($dbType, $dbDescription); + $db->listTables(); + return true; + } + + /** + * Get the list of database tables + * + * @param string $dbType Database adapter type for Zend_Db + * @param array|object $dbDescription Adapter-specific connection settings + * @return array List of the tables + */ + public function getTables($dbType, $dbDescription) + { + $db = $this->_connect($dbType, $dbDescription); + return $db->listTables(); + } +} diff --git a/library/vendor/Zend/Amf/Adobe/Introspector.php b/library/vendor/Zend/Amf/Adobe/Introspector.php new file mode 100755 index 000000000..f5b144c60 --- /dev/null +++ b/library/vendor/Zend/Amf/Adobe/Introspector.php @@ -0,0 +1,314 @@ +_xml = new DOMDocument('1.0', 'utf-8'); + } + + /** + * Create XML definition on an AMF service class + * + * @param string $serviceClass Service class name + * @param array $options invocation options + * @return string XML with service class introspection + */ + public function introspect($serviceClass, $options = array()) + { + $this->_options = $options; + + if (strpbrk($serviceClass, '\\/<>')) { + return $this->_returnError('Invalid service name'); + } + + // Transform com.foo.Bar into com_foo_Bar + $serviceClass = str_replace('.' , '_', $serviceClass); + + // Introspect! + if (!class_exists($serviceClass)) { + Zend_Loader::loadClass($serviceClass, $this->_getServicePath()); + } + + $serv = $this->_xml->createElement('service-description'); + $serv->setAttribute('xmlns', 'http://ns.adobe.com/flex/service-description/2008'); + + $this->_types = $this->_xml->createElement('types'); + $this->_ops = $this->_xml->createElement('operations'); + + $r = Zend_Server_Reflection::reflectClass($serviceClass); + $this->_addService($r, $this->_ops); + + $serv->appendChild($this->_types); + $serv->appendChild($this->_ops); + $this->_xml->appendChild($serv); + + return $this->_xml->saveXML(); + } + + /** + * Authentication handler + * + * @param Zend_Acl $acl + * @return unknown_type + */ + public function initAcl(Zend_Acl $acl) + { + return false; // we do not need auth for this class + } + + /** + * Generate map of public class attributes + * + * @param string $typename type name + * @param DOMElement $typexml target XML element + * @return void + */ + protected function _addClassAttributes($typename, DOMElement $typexml) + { + // Do not try to autoload here because _phpTypeToAS should + // have already attempted to load this class + if (!class_exists($typename, false)) { + return; + } + + $rc = new Zend_Reflection_Class($typename); + foreach ($rc->getProperties() as $prop) { + if (!$prop->isPublic()) { + continue; + } + + $propxml = $this->_xml->createElement('property'); + $propxml->setAttribute('name', $prop->getName()); + + $type = $this->_registerType($this->_getPropertyType($prop)); + $propxml->setAttribute('type', $type); + + $typexml->appendChild($propxml); + } + } + + /** + * Build XML service description from reflection class + * + * @param Zend_Server_Reflection_Class $refclass + * @param DOMElement $target target XML element + * @return void + */ + protected function _addService(Zend_Server_Reflection_Class $refclass, DOMElement $target) + { + foreach ($refclass->getMethods() as $method) { + if (!$method->isPublic() + || $method->isConstructor() + || ('__' == substr($method->name, 0, 2)) + ) { + continue; + } + + foreach ($method->getPrototypes() as $proto) { + $op = $this->_xml->createElement('operation'); + $op->setAttribute('name', $method->getName()); + + $rettype = $this->_registerType($proto->getReturnType()); + $op->setAttribute('returnType', $rettype); + + foreach ($proto->getParameters() as $param) { + $arg = $this->_xml->createElement('argument'); + $arg->setAttribute('name', $param->getName()); + + $type = $param->getType(); + if ($type == 'mixed' && ($pclass = $param->getClass())) { + $type = $pclass->getName(); + } + + $ptype = $this->_registerType($type); + $arg->setAttribute('type', $ptype); + + if($param->isDefaultValueAvailable()) { + $arg->setAttribute('defaultvalue', $param->getDefaultValue()); + } + + $op->appendChild($arg); + } + + $target->appendChild($op); + } + } + } + + /** + * Extract type of the property from DocBlock + * + * @param Zend_Reflection_Property $prop reflection property object + * @return string Property type + */ + protected function _getPropertyType(Zend_Reflection_Property $prop) + { + $docBlock = $prop->getDocComment(); + + if (!$docBlock) { + return 'Unknown'; + } + + if (!$docBlock->hasTag('var')) { + return 'Unknown'; + } + + $tag = $docBlock->getTag('var'); + return trim($tag->getDescription()); + } + + /** + * Get the array of service directories + * + * @return array Service class directories + */ + protected function _getServicePath() + { + if (isset($this->_options['server'])) { + return $this->_options['server']->getDirectory(); + } + + if (isset($this->_options['directories'])) { + return $this->_options['directories']; + } + + return array(); + } + + /** + * Map from PHP type name to AS type name + * + * @param string $typename PHP type name + * @return string AS type name + */ + protected function _phpTypeToAS($typename) + { + if (class_exists($typename)) { + $vars = get_class_vars($typename); + + if (isset($vars['_explicitType'])) { + return $vars['_explicitType']; + } + } + + if (false !== ($asname = Zend_Amf_Parse_TypeLoader::getMappedClassName($typename))) { + return $asname; + } + + return $typename; + } + + /** + * Register new type on the system + * + * @param string $typename type name + * @return string New type name + */ + protected function _registerType($typename) + { + // Known type - return its AS name + if (isset($this->_typesMap[$typename])) { + return $this->_typesMap[$typename]; + } + + // Standard types + if (in_array($typename, array('void', 'null', 'mixed', 'unknown_type'))) { + return 'Unknown'; + } + + // Arrays + if ('array' == $typename) { + return 'Unknown[]'; + } + + if (in_array($typename, array('int', 'integer', 'bool', 'boolean', 'float', 'string', 'object', 'Unknown', 'stdClass'))) { + return $typename; + } + + // Resolve and store AS name + $asTypeName = $this->_phpTypeToAS($typename); + $this->_typesMap[$typename] = $asTypeName; + + // Create element for the name + $typeEl = $this->_xml->createElement('type'); + $typeEl->setAttribute('name', $asTypeName); + $this->_addClassAttributes($typename, $typeEl); + $this->_types->appendChild($typeEl); + + return $asTypeName; + } + + /** + * Return error with error message + * + * @param string $msg Error message + * @return string + */ + protected function _returnError($msg) + { + return 'ERROR: $msg'; + } +} diff --git a/library/vendor/Zend/Amf/Auth/Abstract.php b/library/vendor/Zend/Amf/Auth/Abstract.php new file mode 100755 index 000000000..8d8c4a4b0 --- /dev/null +++ b/library/vendor/Zend/Amf/Auth/Abstract.php @@ -0,0 +1,41 @@ +_username = $username; + $this->_password = $password; + } +} diff --git a/library/vendor/Zend/Amf/Constants.php b/library/vendor/Zend/Amf/Constants.php new file mode 100644 index 000000000..5584e25d1 --- /dev/null +++ b/library/vendor/Zend/Amf/Constants.php @@ -0,0 +1,87 @@ +_stream->readByte(); + } + + switch($typeMarker) { + // number + case Zend_Amf_Constants::AMF0_NUMBER: + return $this->_stream->readDouble(); + + // boolean + case Zend_Amf_Constants::AMF0_BOOLEAN: + return (boolean) $this->_stream->readByte(); + + // string + case Zend_Amf_Constants::AMF0_STRING: + return $this->_stream->readUTF(); + + // object + case Zend_Amf_Constants::AMF0_OBJECT: + return $this->readObject(); + + // null + case Zend_Amf_Constants::AMF0_NULL: + return null; + + // undefined + case Zend_Amf_Constants::AMF0_UNDEFINED: + return null; + + // Circular references are returned here + case Zend_Amf_Constants::AMF0_REFERENCE: + return $this->readReference(); + + // mixed array with numeric and string keys + case Zend_Amf_Constants::AMF0_MIXEDARRAY: + return $this->readMixedArray(); + + // array + case Zend_Amf_Constants::AMF0_ARRAY: + return $this->readArray(); + + // date + case Zend_Amf_Constants::AMF0_DATE: + return $this->readDate(); + + // longString strlen(string) > 2^16 + case Zend_Amf_Constants::AMF0_LONGSTRING: + return $this->_stream->readLongUTF(); + + //internal AS object, not supported + case Zend_Amf_Constants::AMF0_UNSUPPORTED: + return null; + + // XML + case Zend_Amf_Constants::AMF0_XML: + return $this->readXmlString(); + + // typed object ie Custom Class + case Zend_Amf_Constants::AMF0_TYPEDOBJECT: + return $this->readTypedObject(); + + //AMF3-specific + case Zend_Amf_Constants::AMF0_AMF3: + return $this->readAmf3TypeMarker(); + + default: + throw new Zend_Amf_Exception('Unsupported marker type: ' . $typeMarker); + } + } + + /** + * Read AMF objects and convert to PHP objects + * + * Read the name value pair objects form the php message and convert them to + * a php object class. + * + * Called when the marker type is 3. + * + * @param array|null $object + * @return object + */ + public function readObject($object = null) + { + if ($object === null) { + $object = array(); + } + + while (true) { + $key = $this->_stream->readUTF(); + $typeMarker = $this->_stream->readByte(); + if ($typeMarker != Zend_Amf_Constants::AMF0_OBJECTTERM ){ + //Recursivly call readTypeMarker to get the types of properties in the object + $object[$key] = $this->readTypeMarker($typeMarker); + } else { + //encountered AMF object terminator + break; + } + } + $this->_reference[] = $object; + return (object) $object; + } + + /** + * Read reference objects + * + * Used to gain access to the private array of reference objects. + * Called when marker type is 7. + * + * @return object + * @throws Zend_Amf_Exception for invalid reference keys + */ + public function readReference() + { + $key = $this->_stream->readInt(); + if (!array_key_exists($key, $this->_reference)) { + throw new Zend_Amf_Exception('Invalid reference key: '. $key); + } + return $this->_reference[$key]; + } + + /** + * Reads an array with numeric and string indexes. + * + * Called when marker type is 8 + * + * @todo As of Flash Player 9 there is not support for mixed typed arrays + * so we handle this as an object. With the introduction of vectors + * in Flash Player 10 this may need to be reconsidered. + * @return array + */ + public function readMixedArray() + { + $length = $this->_stream->readLong(); + return $this->readObject(); + } + + /** + * Converts numerically indexed actiosncript arrays into php arrays. + * + * Called when marker type is 10 + * + * @return array + */ + public function readArray() + { + $length = $this->_stream->readLong(); + $array = array(); + while ($length--) { + $array[] = $this->readTypeMarker(); + } + return $array; + } + + /** + * Convert AS Date to Zend_Date + * + * @return Zend_Date + */ + public function readDate() + { + // get the unix time stamp. Not sure why ActionScript does not use + // milliseconds + $timestamp = floor($this->_stream->readDouble() / 1000); + + // The timezone offset is never returned to the server; it is always 0, + // so read and ignore. + $offset = $this->_stream->readInt(); + + $date = new Zend_Date($timestamp); + return $date; + } + + /** + * Convert XML to SimpleXml + * If user wants DomDocument they can use dom_import_simplexml + * + * @return SimpleXml Object + */ + public function readXmlString() + { + $string = $this->_stream->readLongUTF(); + return Zend_Xml_Security::scan($string); //simplexml_load_string($string); + } + + /** + * Read Class that is to be mapped to a server class. + * + * Commonly used for Value Objects on the server + * + * @todo implement Typed Class mapping + * @return object|array + * @throws Zend_Amf_Exception if unable to load type + */ + public function readTypedObject() + { + // get the remote class name + $className = $this->_stream->readUTF(); + $loader = Zend_Amf_Parse_TypeLoader::loadType($className); + $returnObject = new $loader(); + $properties = get_object_vars($this->readObject()); + foreach($properties as $key=>$value) { + if($key) { + $returnObject->$key = $value; + } + } + if($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) { + $returnObject = get_object_vars($returnObject); + } + return $returnObject; + } + + /** + * AMF3 data type encountered load AMF3 Deserializer to handle + * type markers. + * + * @return string + */ + public function readAmf3TypeMarker() + { + $deserializer = new Zend_Amf_Parse_Amf3_Deserializer($this->_stream); + $this->_objectEncoding = Zend_Amf_Constants::AMF3_OBJECT_ENCODING; + return $deserializer->readTypeMarker(); + } + + /** + * Return the object encoding to check if an AMF3 object + * is going to be return. + * + * @return int + */ + public function getObjectEncoding() + { + return $this->_objectEncoding; + } +} diff --git a/library/vendor/Zend/Amf/Parse/Amf0/Serializer.php b/library/vendor/Zend/Amf/Parse/Amf0/Serializer.php new file mode 100644 index 000000000..12674b394 --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/Amf0/Serializer.php @@ -0,0 +1,355 @@ +writeObjectReference($data, $markerType)) { + // Write the Type Marker to denote the following action script data type + $this->_stream->writeByte($markerType); + switch($markerType) { + case Zend_Amf_Constants::AMF0_NUMBER: + $this->_stream->writeDouble($data); + break; + case Zend_Amf_Constants::AMF0_BOOLEAN: + $this->_stream->writeByte($data); + break; + case Zend_Amf_Constants::AMF0_STRING: + $this->_stream->writeUTF($data); + break; + case Zend_Amf_Constants::AMF0_OBJECT: + $this->writeObject($data); + break; + case Zend_Amf_Constants::AMF0_NULL: + break; + case Zend_Amf_Constants::AMF0_REFERENCE: + $this->_stream->writeInt($data); + break; + case Zend_Amf_Constants::AMF0_MIXEDARRAY: + // Write length of numeric keys as zero. + $this->_stream->writeLong(0); + $this->writeObject($data); + break; + case Zend_Amf_Constants::AMF0_ARRAY: + $this->writeArray($data); + break; + case Zend_Amf_Constants::AMF0_DATE: + $this->writeDate($data); + break; + case Zend_Amf_Constants::AMF0_LONGSTRING: + $this->_stream->writeLongUTF($data); + break; + case Zend_Amf_Constants::AMF0_TYPEDOBJECT: + $this->writeTypedObject($data); + break; + case Zend_Amf_Constants::AMF0_AMF3: + $this->writeAmf3TypeMarker($data); + break; + default: + throw new Zend_Amf_Exception("Unknown Type Marker: " . $markerType); + } + } + } else { + if (is_resource($data)) { + $data = Zend_Amf_Parse_TypeLoader::handleResource($data); + } + switch (true) { + case (is_int($data) || is_float($data)): + $markerType = Zend_Amf_Constants::AMF0_NUMBER; + break; + case (is_bool($data)): + $markerType = Zend_Amf_Constants::AMF0_BOOLEAN; + break; + case (is_string($data) && (($this->_mbStringFunctionsOverloaded ? mb_strlen($data, '8bit') : strlen($data)) > 65536)): + $markerType = Zend_Amf_Constants::AMF0_LONGSTRING; + break; + case (is_string($data)): + $markerType = Zend_Amf_Constants::AMF0_STRING; + break; + case (is_object($data)): + if (($data instanceof DateTime) || ($data instanceof Zend_Date)) { + $markerType = Zend_Amf_Constants::AMF0_DATE; + } else { + + if($className = $this->getClassName($data)){ + //Object is a Typed object set classname + $markerType = Zend_Amf_Constants::AMF0_TYPEDOBJECT; + $this->_className = $className; + } else { + // Object is a generic classname + $markerType = Zend_Amf_Constants::AMF0_OBJECT; + } + break; + } + break; + case (null === $data): + $markerType = Zend_Amf_Constants::AMF0_NULL; + break; + case (is_array($data)): + // check if it is an associative array + $i = 0; + foreach (array_keys($data) as $key) { + // check if it contains non-integer keys + if (!is_numeric($key) || intval($key) != $key) { + $markerType = Zend_Amf_Constants::AMF0_OBJECT; + break; + // check if it is a sparse indexed array + } else if ($key != $i) { + $markerType = Zend_Amf_Constants::AMF0_MIXEDARRAY; + break; + } + $i++; + } + // Dealing with a standard numeric array + if(!$markerType){ + $markerType = Zend_Amf_Constants::AMF0_ARRAY; + break; + } + break; + default: + throw new Zend_Amf_Exception('Unsupported data type: ' . gettype($data)); + } + + $this->writeTypeMarker($data, $markerType); + } + return $this; + } + + /** + * Check if the given object is in the reference table, write the reference if it exists, + * otherwise add the object to the reference table + * + * @param mixed $object object reference to check for reference + * @param string $markerType AMF type of the object to write + * @param mixed $objectByVal object to check for reference + * @return Boolean true, if the reference was written, false otherwise + */ + protected function writeObjectReference(&$object, $markerType, $objectByVal = false) + { + // Workaround for PHP5 with E_STRICT enabled complaining about "Only + // variables should be passed by reference" + if ((null === $object) && ($objectByVal !== false)) { + $object = &$objectByVal; + } + + if ($markerType == Zend_Amf_Constants::AMF0_OBJECT + || $markerType == Zend_Amf_Constants::AMF0_MIXEDARRAY + || $markerType == Zend_Amf_Constants::AMF0_ARRAY + || $markerType == Zend_Amf_Constants::AMF0_TYPEDOBJECT + ) { + $ref = array_search($object, $this->_referenceObjects, true); + //handle object reference + if($ref !== false){ + $this->writeTypeMarker($ref,Zend_Amf_Constants::AMF0_REFERENCE); + return true; + } + + $this->_referenceObjects[] = $object; + } + + return false; + } + + /** + * Write a PHP array with string or mixed keys. + * + * @param object $data + * @return Zend_Amf_Parse_Amf0_Serializer + */ + public function writeObject($object) + { + // Loop each element and write the name of the property. + foreach ($object as $key => &$value) { + // skip variables starting with an _ private transient + if( $key[0] == "_") continue; + $this->_stream->writeUTF($key); + $this->writeTypeMarker($value); + } + + // Write the end object flag + $this->_stream->writeInt(0); + $this->_stream->writeByte(Zend_Amf_Constants::AMF0_OBJECTTERM); + return $this; + } + + /** + * Write a standard numeric array to the output stream. If a mixed array + * is encountered call writeTypeMarker with mixed array. + * + * @param array $array + * @return Zend_Amf_Parse_Amf0_Serializer + */ + public function writeArray(&$array) + { + $length = count($array); + if (!$length < 0) { + // write the length of the array + $this->_stream->writeLong(0); + } else { + // Write the length of the numeric array + $this->_stream->writeLong($length); + for ($i=0; $i<$length; $i++) { + $value = isset($array[$i]) ? $array[$i] : null; + $this->writeTypeMarker($value); + } + } + return $this; + } + + /** + * Convert the DateTime into an AMF Date + * + * @param DateTime|Zend_Date $data + * @return Zend_Amf_Parse_Amf0_Serializer + */ + public function writeDate($data) + { + if ($data instanceof DateTime) { + $dateString = $data->format('U'); + } elseif ($data instanceof Zend_Date) { + $dateString = $data->toString('U'); + } else { + throw new Zend_Amf_Exception('Invalid date specified; must be a DateTime or Zend_Date object'); + } + $dateString *= 1000; + + // Make the conversion and remove milliseconds. + $this->_stream->writeDouble($dateString); + + // Flash does not respect timezone but requires it. + $this->_stream->writeInt(0); + + return $this; + } + + /** + * Write a class mapped object to the output stream. + * + * @param object $data + * @return Zend_Amf_Parse_Amf0_Serializer + */ + public function writeTypedObject($data) + { + $this->_stream->writeUTF($this->_className); + $this->writeObject($data); + return $this; + } + + /** + * Encountered and AMF3 Type Marker use AMF3 serializer. Once AMF3 is + * encountered it will not return to AMf0. + * + * @param string $data + * @return Zend_Amf_Parse_Amf0_Serializer + */ + public function writeAmf3TypeMarker(&$data) + { + $serializer = new Zend_Amf_Parse_Amf3_Serializer($this->_stream); + $serializer->writeTypeMarker($data); + return $this; + } + + /** + * Find if the class name is a class mapped name and return the + * respective classname if it is. + * + * @param object $object + * @return false|string $className + */ + protected function getClassName($object) + { + //Check to see if the object is a typed object and we need to change + $className = ''; + switch (true) { + // the return class mapped name back to actionscript class name. + case Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object)): + $className = Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object)); + break; + // Check to see if the user has defined an explicit Action Script type. + case isset($object->_explicitType): + $className = $object->_explicitType; + break; + // Check if user has defined a method for accessing the Action Script type + case method_exists($object, 'getASClassName'): + $className = $object->getASClassName(); + break; + // No return class name is set make it a generic object + case ($object instanceof stdClass): + $className = ''; + break; + // By default, use object's class name + default: + $className = get_class($object); + break; + } + if(!$className == '') { + return $className; + } else { + return false; + } + } +} diff --git a/library/vendor/Zend/Amf/Parse/Amf3/Deserializer.php b/library/vendor/Zend/Amf/Parse/Amf3/Deserializer.php new file mode 100644 index 000000000..3ead204ae --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/Amf3/Deserializer.php @@ -0,0 +1,414 @@ +_stream->readByte(); + } + + switch($typeMarker) { + case Zend_Amf_Constants::AMF3_UNDEFINED: + return null; + case Zend_Amf_Constants::AMF3_NULL: + return null; + case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE: + return false; + case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE: + return true; + case Zend_Amf_Constants::AMF3_INTEGER: + return $this->readInteger(); + case Zend_Amf_Constants::AMF3_NUMBER: + return $this->_stream->readDouble(); + case Zend_Amf_Constants::AMF3_STRING: + return $this->readString(); + case Zend_Amf_Constants::AMF3_DATE: + return $this->readDate(); + case Zend_Amf_Constants::AMF3_ARRAY: + return $this->readArray(); + case Zend_Amf_Constants::AMF3_OBJECT: + return $this->readObject(); + case Zend_Amf_Constants::AMF3_XML: + case Zend_Amf_Constants::AMF3_XMLSTRING: + return $this->readXmlString(); + case Zend_Amf_Constants::AMF3_BYTEARRAY: + return $this->readString(); + default: + throw new Zend_Amf_Exception('Unsupported type marker: ' . $typeMarker); + } + } + + /** + * Read and deserialize an integer + * + * AMF 3 represents smaller integers with fewer bytes using the most + * significant bit of each byte. The worst case uses 32-bits + * to represent a 29-bit number, which is what we would have + * done with no compression. + * - 0x00000000 - 0x0000007F : 0xxxxxxx + * - 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx + * - 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx + * - 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx + * - 0x40000000 - 0xFFFFFFFF : throw range exception + * + * 0x04 -> integer type code, followed by up to 4 bytes of data. + * + * Parsing integers on OSFlash for the AMF3 integer data format: + * @link http://osflash.org/amf3/parsing_integers + * @return int|float + */ + public function readInteger() + { + $count = 1; + $intReference = $this->_stream->readByte(); + $result = 0; + while ((($intReference & 0x80) != 0) && $count < 4) { + $result <<= 7; + $result |= ($intReference & 0x7f); + $intReference = $this->_stream->readByte(); + $count++; + } + if ($count < 4) { + $result <<= 7; + $result |= $intReference; + } else { + // Use all 8 bits from the 4th byte + $result <<= 8; + $result |= $intReference; + + // Check if the integer should be negative + if (($result & 0x10000000) != 0) { + //and extend the sign bit + $result |= ~0xFFFFFFF; + } + } + return $result; + } + + /** + * Read and deserialize a string + * + * Strings can be sent as a reference to a previously + * occurring String by using an index to the implicit string reference table. + * Strings are encoding using UTF-8 - however the header may either + * describe a string literal or a string reference. + * + * - string = 0x06 string-data + * - string-data = integer-data [ modified-utf-8 ] + * - modified-utf-8 = *OCTET + * + * @return String + */ + public function readString() + { + $stringReference = $this->readInteger(); + + //Check if this is a reference string + if (($stringReference & 0x01) == 0) { + // reference string + $stringReference = $stringReference >> 1; + if ($stringReference >= count($this->_referenceStrings)) { + throw new Zend_Amf_Exception('Undefined string reference: ' . $stringReference); + } + // reference string found + return $this->_referenceStrings[$stringReference]; + } + + $length = $stringReference >> 1; + if ($length) { + $string = $this->_stream->readBytes($length); + $this->_referenceStrings[] = $string; + } else { + $string = ""; + } + return $string; + } + + /** + * Read and deserialize a date + * + * Data is the number of milliseconds elapsed since the epoch + * of midnight, 1st Jan 1970 in the UTC time zone. + * Local time zone information is not sent to flash. + * + * - date = 0x08 integer-data [ number-data ] + * + * @return Zend_Date + */ + public function readDate() + { + $dateReference = $this->readInteger(); + if (($dateReference & 0x01) == 0) { + $dateReference = $dateReference >> 1; + if ($dateReference>=count($this->_referenceObjects)) { + throw new Zend_Amf_Exception('Undefined date reference: ' . $dateReference); + } + return $this->_referenceObjects[$dateReference]; + } + + $timestamp = floor($this->_stream->readDouble() / 1000); + + $dateTime = new Zend_Date($timestamp); + $this->_referenceObjects[] = $dateTime; + return $dateTime; + } + + /** + * Read amf array to PHP array + * + * - array = 0x09 integer-data ( [ 1OCTET *amf3-data ] | [OCTET *amf3-data 1] | [ OCTET *amf-data ] ) + * + * @return array + */ + public function readArray() + { + $arrayReference = $this->readInteger(); + if (($arrayReference & 0x01)==0){ + $arrayReference = $arrayReference >> 1; + if ($arrayReference>=count($this->_referenceObjects)) { + throw new Zend_Amf_Exception('Unknow array reference: ' . $arrayReference); + } + return $this->_referenceObjects[$arrayReference]; + } + + // Create a holder for the array in the reference list + $data = array(); + $this->_referenceObjects[] =& $data; + $key = $this->readString(); + + // Iterating for string based keys. + while ($key != '') { + $data[$key] = $this->readTypeMarker(); + $key = $this->readString(); + } + + $arrayReference = $arrayReference >>1; + + //We have a dense array + for ($i=0; $i < $arrayReference; $i++) { + $data[] = $this->readTypeMarker(); + } + + return $data; + } + + /** + * Read an object from the AMF stream and convert it into a PHP object + * + * @todo Rather than using an array of traitsInfo create Zend_Amf_Value_TraitsInfo + * @return object|array + */ + public function readObject() + { + $traitsInfo = $this->readInteger(); + $storedObject = ($traitsInfo & 0x01)==0; + $traitsInfo = $traitsInfo >> 1; + + // Check if the Object is in the stored Objects reference table + if ($storedObject) { + $ref = $traitsInfo; + if (!isset($this->_referenceObjects[$ref])) { + throw new Zend_Amf_Exception('Unknown Object reference: ' . $ref); + } + $returnObject = $this->_referenceObjects[$ref]; + } else { + // Check if the Object is in the stored Definitions reference table + $storedClass = ($traitsInfo & 0x01) == 0; + $traitsInfo = $traitsInfo >> 1; + if ($storedClass) { + $ref = $traitsInfo; + if (!isset($this->_referenceDefinitions[$ref])) { + throw new Zend_Amf_Exception('Unknows Definition reference: '. $ref); + } + // Populate the reference attributes + $className = $this->_referenceDefinitions[$ref]['className']; + $encoding = $this->_referenceDefinitions[$ref]['encoding']; + $propertyNames = $this->_referenceDefinitions[$ref]['propertyNames']; + } else { + // The class was not in the reference tables. Start reading rawdata to build traits. + // Create a traits table. Zend_Amf_Value_TraitsInfo would be ideal + $className = $this->readString(); + $encoding = $traitsInfo & 0x03; + $propertyNames = array(); + $traitsInfo = $traitsInfo >> 2; + } + + // We now have the object traits defined in variables. Time to go to work: + if (!$className) { + // No class name generic object + $returnObject = new stdClass(); + } else { + // Defined object + // Typed object lookup against registered classname maps + if ($loader = Zend_Amf_Parse_TypeLoader::loadType($className)) { + $returnObject = new $loader(); + } else { + //user defined typed object + throw new Zend_Amf_Exception('Typed object not found: '. $className . ' '); + } + } + + // Add the Object to the reference table + $this->_referenceObjects[] = $returnObject; + + $properties = array(); // clear value + // Check encoding types for additional processing. + switch ($encoding) { + case (Zend_Amf_Constants::ET_EXTERNAL): + // Externalizable object such as {ArrayCollection} and {ObjectProxy} + if (!$storedClass) { + $this->_referenceDefinitions[] = array( + 'className' => $className, + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + } + $returnObject->externalizedData = $this->readTypeMarker(); + break; + case (Zend_Amf_Constants::ET_DYNAMIC): + // used for Name-value encoding + if (!$storedClass) { + $this->_referenceDefinitions[] = array( + 'className' => $className, + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + } + // not a reference object read name value properties from byte stream + do { + $property = $this->readString(); + if ($property != "") { + $propertyNames[] = $property; + $properties[$property] = $this->readTypeMarker(); + } + } while ($property !=""); + break; + default: + // basic property list object. + if (!$storedClass) { + $count = $traitsInfo; // Number of properties in the list + for($i=0; $i< $count; $i++) { + $propertyNames[] = $this->readString(); + } + // Add a reference to the class. + $this->_referenceDefinitions[] = array( + 'className' => $className, + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + } + foreach ($propertyNames as $property) { + $properties[$property] = $this->readTypeMarker(); + } + break; + } + + // Add properties back to the return object. + if (!is_array($properties)) $properties = array(); + foreach($properties as $key=>$value) { + if($key) { + $returnObject->$key = $value; + } + } + + + } + + if ($returnObject instanceof Zend_Amf_Value_Messaging_ArrayCollection) { + if (isset($returnObject->externalizedData)) { + $returnObject = $returnObject->externalizedData; + } else { + $returnObject = get_object_vars($returnObject); + } + } + + return $returnObject; + } + + /** + * Convert XML to SimpleXml + * If user wants DomDocument they can use dom_import_simplexml + * + * @return SimpleXml Object + */ + public function readXmlString() + { + $xmlReference = $this->readInteger(); + $length = $xmlReference >> 1; + $string = $this->_stream->readBytes($length); + return Zend_Xml_Security::scan($string); + } +} diff --git a/library/vendor/Zend/Amf/Parse/Amf3/Serializer.php b/library/vendor/Zend/Amf/Parse/Amf3/Serializer.php new file mode 100644 index 000000000..77a6059cd --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/Amf3/Serializer.php @@ -0,0 +1,523 @@ +_stream->writeByte($markerType); + + switch ($markerType) { + case Zend_Amf_Constants::AMF3_NULL: + break; + case Zend_Amf_Constants::AMF3_BOOLEAN_FALSE: + break; + case Zend_Amf_Constants::AMF3_BOOLEAN_TRUE: + break; + case Zend_Amf_Constants::AMF3_INTEGER: + $this->writeInteger($data); + break; + case Zend_Amf_Constants::AMF3_NUMBER: + $this->_stream->writeDouble($data); + break; + case Zend_Amf_Constants::AMF3_STRING: + $this->writeString($data); + break; + case Zend_Amf_Constants::AMF3_DATE: + $this->writeDate($data); + break; + case Zend_Amf_Constants::AMF3_ARRAY: + $this->writeArray($data); + break; + case Zend_Amf_Constants::AMF3_OBJECT: + $this->writeObject($data); + break; + case Zend_Amf_Constants::AMF3_BYTEARRAY: + $this->writeByteArray($data); + break; + case Zend_Amf_Constants::AMF3_XMLSTRING; + $this->writeXml($data); + break; + default: + throw new Zend_Amf_Exception('Unknown Type Marker: ' . $markerType); + } + } else { + // Detect Type Marker + if (is_resource($data)) { + $data = Zend_Amf_Parse_TypeLoader::handleResource($data); + } + switch (true) { + case (null === $data): + $markerType = Zend_Amf_Constants::AMF3_NULL; + break; + case (is_bool($data)): + if ($data){ + $markerType = Zend_Amf_Constants::AMF3_BOOLEAN_TRUE; + } else { + $markerType = Zend_Amf_Constants::AMF3_BOOLEAN_FALSE; + } + break; + case (is_int($data)): + if (($data > 0xFFFFFFF) || ($data < -268435456)) { + $markerType = Zend_Amf_Constants::AMF3_NUMBER; + } else { + $markerType = Zend_Amf_Constants::AMF3_INTEGER; + } + break; + case (is_float($data)): + $markerType = Zend_Amf_Constants::AMF3_NUMBER; + break; + case (is_string($data)): + $markerType = Zend_Amf_Constants::AMF3_STRING; + break; + case (is_array($data)): + $markerType = Zend_Amf_Constants::AMF3_ARRAY; + break; + case (is_object($data)): + // Handle object types. + if (($data instanceof DateTime) || ($data instanceof Zend_Date)) { + $markerType = Zend_Amf_Constants::AMF3_DATE; + } else if ($data instanceof Zend_Amf_Value_ByteArray) { + $markerType = Zend_Amf_Constants::AMF3_BYTEARRAY; + } else if (($data instanceof DOMDocument) || ($data instanceof SimpleXMLElement)) { + $markerType = Zend_Amf_Constants::AMF3_XMLSTRING; + } else { + $markerType = Zend_Amf_Constants::AMF3_OBJECT; + } + break; + default: + throw new Zend_Amf_Exception('Unsupported data type: ' . gettype($data)); + } + $this->writeTypeMarker($data, $markerType); + } + } + + /** + * Write an AMF3 integer + * + * @param int|float $data + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeInteger($int) + { + if (($int & 0xffffff80) == 0) { + $this->_stream->writeByte($int & 0x7f); + return $this; + } + + if (($int & 0xffffc000) == 0 ) { + $this->_stream->writeByte(($int >> 7 ) | 0x80); + $this->_stream->writeByte($int & 0x7f); + return $this; + } + + if (($int & 0xffe00000) == 0) { + $this->_stream->writeByte(($int >> 14 ) | 0x80); + $this->_stream->writeByte(($int >> 7 ) | 0x80); + $this->_stream->writeByte($int & 0x7f); + return $this; + } + + $this->_stream->writeByte(($int >> 22 ) | 0x80); + $this->_stream->writeByte(($int >> 15 ) | 0x80); + $this->_stream->writeByte(($int >> 8 ) | 0x80); + $this->_stream->writeByte($int & 0xff); + return $this; + } + + /** + * Send string to output stream, without trying to reference it. + * The string is prepended with strlen($string) << 1 | 0x01 + * + * @param string $string + * @return Zend_Amf_Parse_Amf3_Serializer + */ + protected function writeBinaryString(&$string){ + $ref = ($this->_mbStringFunctionsOverloaded ? mb_strlen($string, '8bit') : strlen($string)) << 1 | 0x01; + $this->writeInteger($ref); + $this->_stream->writeBytes($string); + + return $this; + } + + /** + * Send string to output stream + * + * @param string $string + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeString(&$string) + { + $len = $this->_mbStringFunctionsOverloaded ? mb_strlen($string, '8bit') : strlen($string); + if(!$len){ + $this->writeInteger(0x01); + return $this; + } + + $ref = array_key_exists($string, $this->_referenceStrings) + ? $this->_referenceStrings[$string] + : false; + if ($ref === false){ + $this->_referenceStrings[$string] = count($this->_referenceStrings); + $this->writeBinaryString($string); + } else { + $ref <<= 1; + $this->writeInteger($ref); + } + + return $this; + } + + /** + * Send ByteArray to output stream + * + * @param string|Zend_Amf_Value_ByteArray $data + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeByteArray(&$data) + { + if ($this->writeObjectReference($data)) { + return $this; + } + + if (is_string($data)) { + //nothing to do + } else if ($data instanceof Zend_Amf_Value_ByteArray) { + $data = $data->getData(); + } else { + throw new Zend_Amf_Exception('Invalid ByteArray specified; must be a string or Zend_Amf_Value_ByteArray'); + } + + $this->writeBinaryString($data); + + return $this; + } + + /** + * Send xml to output stream + * + * @param DOMDocument|SimpleXMLElement $xml + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeXml($xml) + { + if ($this->writeObjectReference($xml)) { + return $this; + } + + if(is_string($xml)) { + //nothing to do + } else if ($xml instanceof DOMDocument) { + $xml = $xml->saveXml(); + } else if ($xml instanceof SimpleXMLElement) { + $xml = $xml->asXML(); + } else { + throw new Zend_Amf_Exception('Invalid xml specified; must be a DOMDocument or SimpleXMLElement'); + } + + $this->writeBinaryString($xml); + + return $this; + } + + /** + * Convert DateTime/Zend_Date to AMF date + * + * @param DateTime|Zend_Date $date + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeDate($date) + { + if ($this->writeObjectReference($date)) { + return $this; + } + + if ($date instanceof DateTime) { + $dateString = $date->format('U') * 1000; + } elseif ($date instanceof Zend_Date) { + $dateString = $date->toString('U') * 1000; + } else { + throw new Zend_Amf_Exception('Invalid date specified; must be a string DateTime or Zend_Date object'); + } + + $this->writeInteger(0x01); + // write time to stream minus milliseconds + $this->_stream->writeDouble($dateString); + return $this; + } + + /** + * Write a PHP array back to the amf output stream + * + * @param array $array + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeArray(&$array) + { + // arrays aren't reference here but still counted + $this->_referenceObjects[] = $array; + + // have to seperate mixed from numberic keys. + $numeric = array(); + $string = array(); + foreach ($array as $key => &$value) { + if (is_int($key)) { + $numeric[] = $value; + } else { + $string[$key] = $value; + } + } + + // write the preamble id of the array + $length = count($numeric); + $id = ($length << 1) | 0x01; + $this->writeInteger($id); + + //Write the mixed type array to the output stream + foreach($string as $key => &$value) { + $this->writeString($key) + ->writeTypeMarker($value); + } + $this->writeString($this->_strEmpty); + + // Write the numeric array to ouput stream + foreach($numeric as &$value) { + $this->writeTypeMarker($value); + } + return $this; + } + + /** + * Check if the given object is in the reference table, write the reference if it exists, + * otherwise add the object to the reference table + * + * @param mixed $object object reference to check for reference + * @param mixed $objectByVal object to check for reference + * @return Boolean true, if the reference was written, false otherwise + */ + protected function writeObjectReference(&$object, $objectByVal = false) + { + // Workaround for PHP5 with E_STRICT enabled complaining about "Only + // variables should be passed by reference" + if ((null === $object) && ($objectByVal !== false)) { + $object = &$objectByVal; + } + + $hash = spl_object_hash($object); + $ref = array_key_exists($hash, $this->_referenceObjects) + ? $this->_referenceObjects[$hash] + : false; + + // quickly handle object references + if ($ref !== false){ + $ref <<= 1; + $this->writeInteger($ref); + return true; + } + $this->_referenceObjects[$hash] = count($this->_referenceObjects); + return false; + } + + /** + * Write object to ouput stream + * + * @param mixed $data + * @return Zend_Amf_Parse_Amf3_Serializer + */ + public function writeObject($object) + { + if($this->writeObjectReference($object)){ + return $this; + } + + $className = ''; + + //Check to see if the object is a typed object and we need to change + switch (true) { + // the return class mapped name back to actionscript class name. + case ($className = Zend_Amf_Parse_TypeLoader::getMappedClassName(get_class($object))): + break; + + // Check to see if the user has defined an explicit Action Script type. + case isset($object->_explicitType): + $className = $object->_explicitType; + break; + + // Check if user has defined a method for accessing the Action Script type + case method_exists($object, 'getASClassName'): + $className = $object->getASClassName(); + break; + + // No return class name is set make it a generic object + case ($object instanceof stdClass): + $className = ''; + break; + + // By default, use object's class name + default: + $className = get_class($object); + break; + } + + $writeTraits = true; + + //check to see, if we have a corresponding definition + if(array_key_exists($className, $this->_referenceDefinitions)){ + $traitsInfo = $this->_referenceDefinitions[$className]['id']; + $encoding = $this->_referenceDefinitions[$className]['encoding']; + $propertyNames = $this->_referenceDefinitions[$className]['propertyNames']; + + $traitsInfo = ($traitsInfo << 2) | 0x01; + + $writeTraits = false; + } else { + $propertyNames = array(); + + if($className == ''){ + //if there is no className, we interpret the class as dynamic without any sealed members + $encoding = Zend_Amf_Constants::ET_DYNAMIC; + } else { + $encoding = Zend_Amf_Constants::ET_PROPLIST; + + foreach($object as $key => $value) { + if( $key[0] != "_") { + $propertyNames[] = $key; + } + } + } + + $this->_referenceDefinitions[$className] = array( + 'id' => count($this->_referenceDefinitions), + 'encoding' => $encoding, + 'propertyNames' => $propertyNames, + ); + + $traitsInfo = Zend_Amf_Constants::AMF3_OBJECT_ENCODING; + $traitsInfo |= $encoding << 2; + $traitsInfo |= (count($propertyNames) << 4); + } + + $this->writeInteger($traitsInfo); + + if($writeTraits){ + $this->writeString($className); + foreach ($propertyNames as $value) { + $this->writeString($value); + } + } + + try { + switch($encoding) { + case Zend_Amf_Constants::ET_PROPLIST: + //Write the sealed values to the output stream. + foreach ($propertyNames as $key) { + $this->writeTypeMarker($object->$key); + } + break; + case Zend_Amf_Constants::ET_DYNAMIC: + //Write the sealed values to the output stream. + foreach ($propertyNames as $key) { + $this->writeTypeMarker($object->$key); + } + + //Write remaining properties + foreach($object as $key => $value){ + if(!in_array($key,$propertyNames) && $key[0] != "_"){ + $this->writeString($key); + $this->writeTypeMarker($value); + } + } + + //Write an empty string to end the dynamic part + $this->writeString($this->_strEmpty); + break; + case Zend_Amf_Constants::ET_EXTERNAL: + throw new Zend_Amf_Exception('External Object Encoding not implemented'); + break; + default: + throw new Zend_Amf_Exception('Unknown Object Encoding type: ' . $encoding); + } + } catch (Exception $e) { + throw new Zend_Amf_Exception('Unable to writeObject output: ' . $e->getMessage(), 0, $e); + } + + return $this; + } +} diff --git a/library/vendor/Zend/Amf/Parse/Deserializer.php b/library/vendor/Zend/Amf/Parse/Deserializer.php new file mode 100644 index 000000000..ce99c6cbd --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/Deserializer.php @@ -0,0 +1,65 @@ +_stream = $stream; + } + + /** + * Checks for AMF marker types and calls the appropriate methods + * for deserializing those marker types. Markers are the data type of + * the following value. + * + * @param int $typeMarker + * @return mixed Whatever the data type is of the marker in php + */ + public abstract function readTypeMarker($markerType = null); +} diff --git a/library/vendor/Zend/Amf/Parse/InputStream.php b/library/vendor/Zend/Amf/Parse/InputStream.php new file mode 100644 index 000000000..b77dd65a4 --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/InputStream.php @@ -0,0 +1,38 @@ + Value is Mysql type (exact string) => PHP type + */ + static public $fieldTypes = array( + "int" => "int", + "timestamp" => "int", + "year" => "int", + "real" => "float", + ); + /** + * Parse resource into array + * + * @param resource $resource + * @return array + */ + public function parse($resource) { + $result = array(); + $fieldcnt = mysql_num_fields($resource); + $fields_transform = array(); + for($i=0;$i<$fieldcnt;$i++) { + $type = mysql_field_type($resource, $i); + if(isset(self::$fieldTypes[$type])) { + $fields_transform[mysql_field_name($resource, $i)] = self::$fieldTypes[$type]; + } + } + + while($row = mysql_fetch_object($resource)) { + foreach($fields_transform as $fieldname => $fieldtype) { + settype($row->$fieldname, $fieldtype); + } + $result[] = $row; + } + return $result; + } +} diff --git a/library/vendor/Zend/Amf/Parse/Resource/MysqliResult.php b/library/vendor/Zend/Amf/Parse/Resource/MysqliResult.php new file mode 100644 index 000000000..86ac44890 --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/Resource/MysqliResult.php @@ -0,0 +1,128 @@ + "MYSQLI_TYPE_DECIMAL", + 1 => "MYSQLI_TYPE_TINYINT", + 2 => "MYSQLI_TYPE_SMALLINT", + 3 => "MYSQLI_TYPE_INTEGER", + 4 => "MYSQLI_TYPE_FLOAT", + 5 => "MYSQLI_TYPE_DOUBLE", + 7 => "MYSQLI_TYPE_TIMESTAMP", + 8 => "MYSQLI_TYPE_BIGINT", + 9 => "MYSQLI_TYPE_MEDIUMINT", + 10 => "MYSQLI_TYPE_DATE", + 11 => "MYSQLI_TYPE_TIME", + 12 => "MYSQLI_TYPE_DATETIME", + 13 => "MYSQLI_TYPE_YEAR", + 14 => "MYSQLI_TYPE_DATE", + 16 => "MYSQLI_TYPE_BIT", + 246 => "MYSQLI_TYPE_DECIMAL", + 247 => "MYSQLI_TYPE_ENUM", + 248 => "MYSQLI_TYPE_SET", + 249 => "MYSQLI_TYPE_TINYBLOB", + 250 => "MYSQLI_TYPE_MEDIUMBLOB", + 251 => "MYSQLI_TYPE_LONGBLOB", + 252 => "MYSQLI_TYPE_BLOB", + 253 => "MYSQLI_TYPE_VARCHAR", + 254 => "MYSQLI_TYPE_CHAR", + 255 => "MYSQLI_TYPE_GEOMETRY", + ); + + // Build an associative array for a type look up + static $mysqli_to_php = array( + "MYSQLI_TYPE_DECIMAL" => 'float', + "MYSQLI_TYPE_NEWDECIMAL" => 'float', + "MYSQLI_TYPE_BIT" => 'integer', + "MYSQLI_TYPE_TINYINT" => 'integer', + "MYSQLI_TYPE_SMALLINT" => 'integer', + "MYSQLI_TYPE_MEDIUMINT" => 'integer', + "MYSQLI_TYPE_BIGINT" => 'integer', + "MYSQLI_TYPE_INTEGER" => 'integer', + "MYSQLI_TYPE_FLOAT" => 'float', + "MYSQLI_TYPE_DOUBLE" => 'float', + "MYSQLI_TYPE_NULL" => 'null', + "MYSQLI_TYPE_TIMESTAMP" => 'string', + "MYSQLI_TYPE_INT24" => 'integer', + "MYSQLI_TYPE_DATE" => 'string', + "MYSQLI_TYPE_TIME" => 'string', + "MYSQLI_TYPE_DATETIME" => 'string', + "MYSQLI_TYPE_YEAR" => 'string', + "MYSQLI_TYPE_NEWDATE" => 'string', + "MYSQLI_TYPE_ENUM" => 'string', + "MYSQLI_TYPE_SET" => 'string', + "MYSQLI_TYPE_TINYBLOB" => 'object', + "MYSQLI_TYPE_MEDIUMBLOB" => 'object', + "MYSQLI_TYPE_LONGBLOB" => 'object', + "MYSQLI_TYPE_BLOB" => 'object', + "MYSQLI_TYPE_CHAR" => 'string', + "MYSQLI_TYPE_VARCHAR" => 'string', + "MYSQLI_TYPE_GEOMETRY" => 'object', + "MYSQLI_TYPE_BIT" => 'integer', + ); + + /** + * Parse resource into array + * + * @param resource $resource + * @return array + */ + public function parse($resource) { + + $result = array(); + $fieldcnt = mysqli_num_fields($resource); + + + $fields_transform = array(); + + for($i=0;$i<$fieldcnt;$i++) { + $finfo = mysqli_fetch_field_direct($resource, $i); + + if(isset(self::$mysqli_type[$finfo->type])) { + $fields_transform[$finfo->name] = self::$mysqli_to_php[self::$mysqli_type[$finfo->type]]; + } + } + + while($row = mysqli_fetch_assoc($resource)) { + foreach($fields_transform as $fieldname => $fieldtype) { + settype($row[$fieldname], $fieldtype); + } + $result[] = $row; + } + return $result; + } +} diff --git a/library/vendor/Zend/Amf/Parse/Resource/Stream.php b/library/vendor/Zend/Amf/Parse/Resource/Stream.php new file mode 100755 index 000000000..c1b361b73 --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/Resource/Stream.php @@ -0,0 +1,42 @@ +_stream = $stream; + $this->_mbStringFunctionsOverloaded = function_exists('mb_strlen') && (ini_get('mbstring.func_overload') !== '') && ((int)ini_get('mbstring.func_overload') & 2); + } + + /** + * Find the PHP object type and convert it into an AMF object type + * + * @param mixed $content + * @param int $markerType + * @param mixed $contentByVal + * @return void + */ + public abstract function writeTypeMarker(&$content, $markerType = null, $contentByVal = false); +} diff --git a/library/vendor/Zend/Amf/Parse/TypeLoader.php b/library/vendor/Zend/Amf/Parse/TypeLoader.php new file mode 100644 index 000000000..431734f31 --- /dev/null +++ b/library/vendor/Zend/Amf/Parse/TypeLoader.php @@ -0,0 +1,222 @@ + 'Zend_Amf_Value_Messaging_AcknowledgeMessage', + 'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_AsyncMessage', + 'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage', + 'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage', + 'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage', + 'flex.messaging.io.ArrayCollection' => 'Zend_Amf_Value_Messaging_ArrayCollection', + ); + + /** + * @var array Default class map + */ + protected static $_defaultClassMap = array( + 'flex.messaging.messages.AcknowledgeMessage' => 'Zend_Amf_Value_Messaging_AcknowledgeMessage', + 'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_AsyncMessage', + 'flex.messaging.messages.CommandMessage' => 'Zend_Amf_Value_Messaging_CommandMessage', + 'flex.messaging.messages.ErrorMessage' => 'Zend_Amf_Value_Messaging_ErrorMessage', + 'flex.messaging.messages.RemotingMessage' => 'Zend_Amf_Value_Messaging_RemotingMessage', + 'flex.messaging.io.ArrayCollection' => 'Zend_Amf_Value_Messaging_ArrayCollection', + ); + + /** + * @var Zend_Loader_PluginLoader_Interface + */ + protected static $_resourceLoader = null; + + + /** + * Load the mapped class type into a callback. + * + * @param string $className + * @return object|false + */ + public static function loadType($className) + { + $class = self::getMappedClassName($className); + if(!$class) { + $class = str_replace('.', '_', $className); + } + if (!class_exists($class)) { + return "stdClass"; + } + return $class; + } + + /** + * Looks up the supplied call name to its mapped class name + * + * @param string $className + * @return string + */ + public static function getMappedClassName($className) + { + $mappedName = array_search($className, self::$classMap); + + if ($mappedName) { + return $mappedName; + } + + $mappedName = array_search($className, array_flip(self::$classMap)); + + if ($mappedName) { + return $mappedName; + } + + return false; + } + + /** + * Map PHP class names to ActionScript class names + * + * Allows users to map the class names of there action script classes + * to the equivelent php class name. Used in deserialization to load a class + * and serialiation to set the class name of the returned object. + * + * @param string $asClassName + * @param string $phpClassName + * @return void + */ + public static function setMapping($asClassName, $phpClassName) + { + self::$classMap[$asClassName] = $phpClassName; + } + + /** + * Reset type map + * + * @return void + */ + public static function resetMap() + { + self::$classMap = self::$_defaultClassMap; + } + + /** + * Set loader for resource type handlers + * + * @param Zend_Loader_PluginLoader_Interface $loader + */ + public static function setResourceLoader(Zend_Loader_PluginLoader_Interface $loader) + { + self::$_resourceLoader = $loader; + } + + /** + * Add directory to the list of places where to look for resource handlers + * + * @param string $prefix + * @param string $dir + */ + public static function addResourceDirectory($prefix, $dir) + { + if(self::$_resourceLoader) { + self::$_resourceLoader->addPrefixPath($prefix, $dir); + } + } + + /** + * Get plugin class that handles this resource + * + * @param resource $resource Resource type + * @return string Class name + */ + public static function getResourceParser($resource) + { + if(self::$_resourceLoader) { + $type = preg_replace("/[^A-Za-z0-9_]/", " ", get_resource_type($resource)); + $type = str_replace(" ","", ucwords($type)); + return self::$_resourceLoader->load($type); + } + return false; + } + + /** + * Convert resource to a serializable object + * + * @param resource $resource + * @return mixed + */ + public static function handleResource($resource) + { + if(!self::$_resourceLoader) { + throw new Zend_Amf_Exception('Unable to handle resources - resource plugin loader not set'); + } + try { + while(is_resource($resource)) { + $resclass = self::getResourceParser($resource); + if(!$resclass) { + throw new Zend_Amf_Exception('Can not serialize resource type: '. get_resource_type($resource)); + } + $parser = new $resclass(); + if(is_callable(array($parser, 'parse'))) { + $resource = $parser->parse($resource); + } else { + throw new Zend_Amf_Exception("Could not call parse() method on class $resclass"); + } + } + return $resource; + } catch(Zend_Amf_Exception $e) { + throw new Zend_Amf_Exception($e->getMessage(), $e->getCode(), $e); + } catch(Exception $e) { + throw new Zend_Amf_Exception('Can not serialize resource type: '. get_resource_type($resource), 0, $e); + } + } +} diff --git a/library/vendor/Zend/Amf/Request.php b/library/vendor/Zend/Amf/Request.php new file mode 100644 index 000000000..89731e90e --- /dev/null +++ b/library/vendor/Zend/Amf/Request.php @@ -0,0 +1,243 @@ +_inputStream = new Zend_Amf_Parse_InputStream($request); + $this->_deserializer = new Zend_Amf_Parse_Amf0_Deserializer($this->_inputStream); + $this->readMessage($this->_inputStream); + return $this; + } + + /** + * Takes the raw AMF input stream and converts it into valid PHP objects + * + * @param Zend_Amf_Parse_InputStream + * @return Zend_Amf_Request + */ + public function readMessage(Zend_Amf_Parse_InputStream $stream) + { + $clientVersion = $stream->readUnsignedShort(); + if (($clientVersion != Zend_Amf_Constants::AMF0_OBJECT_ENCODING) + && ($clientVersion != Zend_Amf_Constants::AMF3_OBJECT_ENCODING) + && ($clientVersion != Zend_Amf_Constants::FMS_OBJECT_ENCODING) + ) { + throw new Zend_Amf_Exception('Unknown Player Version ' . $clientVersion); + } + + $this->_bodies = array(); + $this->_headers = array(); + $headerCount = $stream->readInt(); + + // Iterate through the AMF envelope header + while ($headerCount--) { + $this->_headers[] = $this->readHeader(); + } + + // Iterate through the AMF envelope body + $bodyCount = $stream->readInt(); + while ($bodyCount--) { + $this->_bodies[] = $this->readBody(); + } + + return $this; + } + + /** + * Deserialize a message header from the input stream. + * + * A message header is structured as: + * - NAME String + * - MUST UNDERSTAND Boolean + * - LENGTH Int + * - DATA Object + * + * @return Zend_Amf_Value_MessageHeader + */ + public function readHeader() + { + $name = $this->_inputStream->readUTF(); + $mustRead = (bool)$this->_inputStream->readByte(); + $length = $this->_inputStream->readLong(); + + try { + $data = $this->_deserializer->readTypeMarker(); + } catch (Exception $e) { + throw new Zend_Amf_Exception('Unable to parse ' . $name . ' header data: ' . $e->getMessage() . ' '. $e->getLine(), 0, $e); + } + + $header = new Zend_Amf_Value_MessageHeader($name, $mustRead, $data, $length); + return $header; + } + + /** + * Deserialize a message body from the input stream + * + * @return Zend_Amf_Value_MessageBody + */ + public function readBody() + { + $targetURI = $this->_inputStream->readUTF(); + $responseURI = $this->_inputStream->readUTF(); + $length = $this->_inputStream->readLong(); + + try { + $data = $this->_deserializer->readTypeMarker(); + } catch (Exception $e) { + throw new Zend_Amf_Exception('Unable to parse ' . $targetURI . ' body data ' . $e->getMessage(), 0, $e); + } + + // Check for AMF3 objectEncoding + if ($this->_deserializer->getObjectEncoding() == Zend_Amf_Constants::AMF3_OBJECT_ENCODING) { + /* + * When and AMF3 message is sent to the server it is nested inside + * an AMF0 array called Content. The following code gets the object + * out of the content array and sets it as the message data. + */ + if(is_array($data) && $data[0] instanceof Zend_Amf_Value_Messaging_AbstractMessage){ + $data = $data[0]; + } + + // set the encoding so we return our message in AMF3 + $this->_objectEncoding = Zend_Amf_Constants::AMF3_OBJECT_ENCODING; + } + + $body = new Zend_Amf_Value_MessageBody($targetURI, $responseURI, $data); + return $body; + } + + /** + * Return an array of the body objects that were found in the amf request. + * + * @return array {target, response, length, content} + */ + public function getAmfBodies() + { + return $this->_bodies; + } + + /** + * Accessor to private array of message bodies. + * + * @param Zend_Amf_Value_MessageBody $message + * @return Zend_Amf_Request + */ + public function addAmfBody(Zend_Amf_Value_MessageBody $message) + { + $this->_bodies[] = $message; + return $this; + } + + /** + * Return an array of headers that were found in the amf request. + * + * @return array {operation, mustUnderstand, length, param} + */ + public function getAmfHeaders() + { + return $this->_headers; + } + + /** + * Return the either 0 or 3 for respect AMF version + * + * @return int + */ + public function getObjectEncoding() + { + return $this->_objectEncoding; + } + + /** + * Set the object response encoding + * + * @param mixed $int + * @return Zend_Amf_Request + */ + public function setObjectEncoding($int) + { + $this->_objectEncoding = $int; + return $this; + } +} diff --git a/library/vendor/Zend/Amf/Request/Http.php b/library/vendor/Zend/Amf/Request/Http.php new file mode 100644 index 000000000..a3369484d --- /dev/null +++ b/library/vendor/Zend/Amf/Request/Http.php @@ -0,0 +1,79 @@ +_rawRequest = $amfRequest; + $this->initialize($amfRequest); + } else { + echo '

              Zend Amf Endpoint

              ' ; + } + } + + /** + * Retrieve raw AMF Request + * + * @return string + */ + public function getRawRequest() + { + return $this->_rawRequest; + } +} diff --git a/library/vendor/Zend/Amf/Response.php b/library/vendor/Zend/Amf/Response.php new file mode 100644 index 000000000..c077f1e20 --- /dev/null +++ b/library/vendor/Zend/Amf/Response.php @@ -0,0 +1,202 @@ +_outputStream = new Zend_Amf_Parse_OutputStream(); + $this->writeMessage($this->_outputStream); + return $this; + } + + /** + * Serialize the PHP data types back into Actionscript and + * create and AMF stream. + * + * @param Zend_Amf_Parse_OutputStream $stream + * @return Zend_Amf_Response + */ + public function writeMessage(Zend_Amf_Parse_OutputStream $stream) + { + $objectEncoding = $this->_objectEncoding; + + //Write encoding to start of stream. Preamble byte is written of two byte Unsigned Short + $stream->writeByte(0x00); + $stream->writeByte($objectEncoding); + + // Loop through the AMF Headers that need to be returned. + $headerCount = count($this->_headers); + $stream->writeInt($headerCount); + foreach ($this->getAmfHeaders() as $header) { + $serializer = new Zend_Amf_Parse_Amf0_Serializer($stream); + $stream->writeUTF($header->name); + $stream->writeByte($header->mustRead); + $stream->writeLong(Zend_Amf_Constants::UNKNOWN_CONTENT_LENGTH); + if (is_object($header->data)) { + // Workaround for PHP5 with E_STRICT enabled complaining about + // "Only variables should be passed by reference" + $placeholder = null; + $serializer->writeTypeMarker($placeholder, null, $header->data); + } else { + $serializer->writeTypeMarker($header->data); + } + } + + // loop through the AMF bodies that need to be returned. + $bodyCount = count($this->_bodies); + $stream->writeInt($bodyCount); + foreach ($this->_bodies as $body) { + $serializer = new Zend_Amf_Parse_Amf0_Serializer($stream); + $stream->writeUTF($body->getTargetURI()); + $stream->writeUTF($body->getResponseURI()); + $stream->writeLong(Zend_Amf_Constants::UNKNOWN_CONTENT_LENGTH); + $bodyData = $body->getData(); + $markerType = ($this->_objectEncoding == Zend_Amf_Constants::AMF0_OBJECT_ENCODING) ? null : Zend_Amf_Constants::AMF0_AMF3; + if (is_object($bodyData)) { + // Workaround for PHP5 with E_STRICT enabled complaining about + // "Only variables should be passed by reference" + $placeholder = null; + $serializer->writeTypeMarker($placeholder, $markerType, $bodyData); + } else { + $serializer->writeTypeMarker($bodyData, $markerType); + } + } + + return $this; + } + + /** + * Return the output stream content + * + * @return string The contents of the output stream + */ + public function getResponse() + { + return $this->_outputStream->getStream(); + } + + /** + * Return the output stream content + * + * @return string + */ + public function __toString() + { + return $this->getResponse(); + } + + /** + * Add an AMF body to be sent to the Flash Player + * + * @param Zend_Amf_Value_MessageBody $body + * @return Zend_Amf_Response + */ + public function addAmfBody(Zend_Amf_Value_MessageBody $body) + { + $this->_bodies[] = $body; + return $this; + } + + /** + * Return an array of AMF bodies to be serialized + * + * @return array + */ + public function getAmfBodies() + { + return $this->_bodies; + } + + /** + * Add an AMF Header to be sent back to the flash player + * + * @param Zend_Amf_Value_MessageHeader $header + * @return Zend_Amf_Response + */ + public function addAmfHeader(Zend_Amf_Value_MessageHeader $header) + { + $this->_headers[] = $header; + return $this; + } + + /** + * Retrieve attached AMF message headers + * + * @return array Array of Zend_Amf_Value_MessageHeader objects + */ + public function getAmfHeaders() + { + return $this->_headers; + } + + /** + * Set the AMF encoding that will be used for serialization + * + * @param int $encoding + * @return Zend_Amf_Response + */ + public function setObjectEncoding($encoding) + { + $this->_objectEncoding = $encoding; + return $this; + } +} diff --git a/library/vendor/Zend/Amf/Response/Http.php b/library/vendor/Zend/Amf/Response/Http.php new file mode 100644 index 000000000..c80de673c --- /dev/null +++ b/library/vendor/Zend/Amf/Response/Http.php @@ -0,0 +1,72 @@ +isIeOverSsl()) { + header('Cache-Control: cache, must-revalidate'); + header('Pragma: public'); + } else { + header('Cache-Control: no-cache, must-revalidate'); + header('Pragma: no-cache'); + } + header('Expires: Thu, 19 Nov 1981 08:52:00 GMT'); + header('Content-Type: application/x-amf'); + } + return parent::getResponse(); + } + + protected function isIeOverSsl() + { + $ssl = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : false; + if (!$ssl || ($ssl == 'off')) { + // IIS reports "off", whereas other browsers simply don't populate + return false; + } + + $ua = $_SERVER['HTTP_USER_AGENT']; + if (!preg_match('/; MSIE \d+\.\d+;/', $ua)) { + // Not MicroSoft Internet Explorer + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Amf/Server.php b/library/vendor/Zend/Amf/Server.php new file mode 100644 index 000000000..f1099b934 --- /dev/null +++ b/library/vendor/Zend/Amf/Server.php @@ -0,0 +1,1007 @@ + method pairs + * @var array + */ + protected $_table = array(); + + /** + * + * @var bool session flag; whether or not to add a session to each response. + */ + protected $_session = false; + + /** + * Namespace allows all AMF calls to not clobber other PHP session variables + * @var Zend_Session_NameSpace default session namespace zend_amf + */ + protected $_sesionNamespace = 'zend_amf'; + + /** + * Set the default session.name if php_ + * @var string + */ + protected $_sessionName = 'PHPSESSID'; + + /** + * Authentication handler object + * + * @var Zend_Amf_Auth_Abstract + */ + protected $_auth; + /** + * ACL handler object + * + * @var Zend_Acl + */ + protected $_acl; + /** + * The server constructor + */ + public function __construct() + { + Zend_Amf_Parse_TypeLoader::setResourceLoader(new Zend_Loader_PluginLoader(array("Zend_Amf_Parse_Resource" => "Zend/Amf/Parse/Resource"))); + } + + /** + * Set authentication adapter + * + * If the authentication adapter implements a "getAcl()" method, populate + * the ACL of this instance with it (if none exists already). + * + * @param Zend_Amf_Auth_Abstract $auth + * @return Zend_Amf_Server + */ + public function setAuth(Zend_Amf_Auth_Abstract $auth) + { + $this->_auth = $auth; + if ((null === $this->getAcl()) && method_exists($auth, 'getAcl')) { + $this->setAcl($auth->getAcl()); + } + return $this; + } + /** + * Get authentication adapter + * + * @return Zend_Amf_Auth_Abstract + */ + public function getAuth() + { + return $this->_auth; + } + + /** + * Set ACL adapter + * + * @param Zend_Acl $acl + * @return Zend_Amf_Server + */ + public function setAcl(Zend_Acl $acl) + { + $this->_acl = $acl; + return $this; + } + /** + * Get ACL adapter + * + * @return Zend_Acl + */ + public function getAcl() + { + return $this->_acl; + } + + /** + * Set production flag + * + * @param bool $flag + * @return Zend_Amf_Server + */ + public function setProduction($flag) + { + $this->_production = (bool) $flag; + return $this; + } + + /** + * Whether or not the server is in production + * + * @return bool + */ + public function isProduction() + { + return $this->_production; + } + + /** + * @param namespace of all incoming sessions defaults to Zend_Amf + * @return Zend_Amf_Server + */ + public function setSession($namespace = 'Zend_Amf') + { + $this->_session = true; + $this->_sesionNamespace = new Zend_Session_Namespace($namespace); + return $this; + } + + /** + * Whether of not the server is using sessions + * @return bool + */ + public function isSession() + { + return $this->_session; + } + + /** + * Check if the ACL allows accessing the function or method + * + * @param string|object $object Object or class being accessed + * @param string $function Function or method being accessed + * @return unknown_type + */ + protected function _checkAcl($object, $function) + { + if(!$this->_acl) { + return true; + } + if($object) { + $class = is_object($object)?get_class($object):$object; + if(!$this->_acl->has($class)) { + $this->_acl->add(new Zend_Acl_Resource($class)); + } + $call = array($object, "initAcl"); + if(is_callable($call) && !call_user_func($call, $this->_acl)) { + // if initAcl returns false, no ACL check + return true; + } + } else { + $class = null; + } + + $auth = Zend_Auth::getInstance(); + if($auth->hasIdentity()) { + $role = $auth->getIdentity()->role; + } else { + if($this->_acl->hasRole(Zend_Amf_Constants::GUEST_ROLE)) { + $role = Zend_Amf_Constants::GUEST_ROLE; + } else { + throw new Zend_Amf_Server_Exception("Unauthenticated access not allowed"); + } + } + if($this->_acl->isAllowed($role, $class, $function)) { + return true; + } else { + throw new Zend_Amf_Server_Exception("Access not allowed"); + } + } + + /** + * Get PluginLoader for the Server + * + * @return Zend_Loader_PluginLoader + */ + protected function getLoader() + { + if(empty($this->_loader)) { + $this->_loader = new Zend_Loader_PluginLoader(); + } + return $this->_loader; + } + + /** + * Loads a remote class or method and executes the function and returns + * the result + * + * @param string $method Is the method to execute + * @param mixed $param values for the method + * @return mixed $response the result of executing the method + * @throws Zend_Amf_Server_Exception + */ + protected function _dispatch($method, $params = null, $source = null) + { + if($source) { + if(($mapped = Zend_Amf_Parse_TypeLoader::getMappedClassName($source)) !== false) { + $source = $mapped; + } + } + $qualifiedName = empty($source) ? $method : $source . '.' . $method; + + if (!isset($this->_table[$qualifiedName])) { + // if source is null a method that was not defined was called. + if ($source) { + $className = str_replace('.', '_', $source); + if(class_exists($className, false) && !isset($this->_classAllowed[$className])) { + throw new Zend_Amf_Server_Exception('Can not call "' . $className . '" - use setClass()'); + } + try { + $this->getLoader()->load($className); + } catch (Exception $e) { + throw new Zend_Amf_Server_Exception('Class "' . $className . '" does not exist: '.$e->getMessage(), 0, $e); + } + // Add the new loaded class to the server. + $this->setClass($className, $source); + } + + if (!isset($this->_table[$qualifiedName])) { + // Source is null or doesn't contain specified method + throw new Zend_Amf_Server_Exception('Method "' . $method . '" does not exist'); + } + } + + $info = $this->_table[$qualifiedName]; + $argv = $info->getInvokeArguments(); + + if (0 < count($argv)) { + $params = array_merge($params, $argv); + } + + $params = $this->_castParameters($info, $params); + + if ($info instanceof Zend_Server_Reflection_Function) { + $func = $info->getName(); + $this->_checkAcl(null, $func); + $return = call_user_func_array($func, $params); + } elseif ($info instanceof Zend_Server_Reflection_Method) { + // Get class + $class = $info->getDeclaringClass()->getName(); + if ('static' == $info->isStatic()) { + // for some reason, invokeArgs() does not work the same as + // invoke(), and expects the first argument to be an object. + // So, using a callback if the method is static. + $this->_checkAcl($class, $info->getName()); + $return = call_user_func_array(array($class, $info->getName()), $params); + } else { + // Object methods + try { + $object = $info->getDeclaringClass()->newInstance(); + } catch (Exception $e) { + throw new Zend_Amf_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': '.$e->getMessage(), 621, $e); + } + $this->_checkAcl($object, $info->getName()); + $return = $info->invokeArgs($object, $params); + } + } else { + throw new Zend_Amf_Server_Exception('Method missing implementation ' . get_class($info)); + } + + return $return; + } + + /** + * Handles each of the 11 different command message types. + * + * A command message is a flex.messaging.messages.CommandMessage + * + * @see Zend_Amf_Value_Messaging_CommandMessage + * @param Zend_Amf_Value_Messaging_CommandMessage $message + * @return Zend_Amf_Value_Messaging_AcknowledgeMessage + */ + protected function _loadCommandMessage(Zend_Amf_Value_Messaging_CommandMessage $message) + { + switch($message->operation) { + case Zend_Amf_Value_Messaging_CommandMessage::DISCONNECT_OPERATION : + case Zend_Amf_Value_Messaging_CommandMessage::CLIENT_PING_OPERATION : + $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); + break; + case Zend_Amf_Value_Messaging_CommandMessage::LOGIN_OPERATION : + $data = explode(':', base64_decode($message->body)); + $userid = $data[0]; + $password = isset($data[1])?$data[1]:""; + if(empty($userid)) { + throw new Zend_Amf_Server_Exception('Login failed: username not supplied'); + } + if(!$this->_handleAuth($userid, $password)) { + throw new Zend_Amf_Server_Exception('Authentication failed'); + } + $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); + break; + case Zend_Amf_Value_Messaging_CommandMessage::LOGOUT_OPERATION : + if($this->_auth) { + Zend_Auth::getInstance()->clearIdentity(); + } + $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); + break; + default : + throw new Zend_Amf_Server_Exception('CommandMessage::' . $message->operation . ' not implemented'); + break; + } + return $return; + } + + /** + * Create appropriate error message + * + * @param int $objectEncoding Current AMF encoding + * @param string $message Message that was being processed when error happened + * @param string $description Error description + * @param mixed $detail Detailed data about the error + * @param int $code Error code + * @param int $line Error line + * @return Zend_Amf_Value_Messaging_ErrorMessage|array + */ + protected function _errorMessage($objectEncoding, $message, $description, $detail, $code, $line) + { + $return = null; + switch ($objectEncoding) { + case Zend_Amf_Constants::AMF0_OBJECT_ENCODING : + return array ( + 'description' => ($this->isProduction ()) ? '' : $description, + 'detail' => ($this->isProduction ()) ? '' : $detail, + 'line' => ($this->isProduction ()) ? 0 : $line, + 'code' => $code + ); + case Zend_Amf_Constants::AMF3_OBJECT_ENCODING : + $return = new Zend_Amf_Value_Messaging_ErrorMessage ( $message ); + $return->faultString = $this->isProduction () ? '' : $description; + $return->faultCode = $code; + $return->faultDetail = $this->isProduction () ? '' : $detail; + break; + } + return $return; + } + + /** + * Handle AMF authentication + * + * @param string $userid + * @param string $password + * @return boolean + */ + protected function _handleAuth( $userid, $password) + { + if (!$this->_auth) { + return true; + } + $this->_auth->setCredentials($userid, $password); + $auth = Zend_Auth::getInstance(); + $result = $auth->authenticate($this->_auth); + if ($result->isValid()) { + if (!$this->isSession()) { + $this->setSession(); + } + return true; + } else { + // authentication failed, good bye + throw new Zend_Amf_Server_Exception( + "Authentication failed: " . join("\n", + $result->getMessages()), $result->getCode()); + } + + } + + /** + * Takes the deserialized AMF request and performs any operations. + * + * @todo should implement and SPL observer pattern for custom AMF headers + * @todo DescribeService support + * @param Zend_Amf_Request $request + * @return Zend_Amf_Response + * @throws Zend_Amf_server_Exception|Exception + */ + protected function _handle(Zend_Amf_Request $request) + { + // Get the object encoding of the request. + $objectEncoding = $request->getObjectEncoding(); + + // create a response object to place the output from the services. + $response = $this->getResponse(); + + // set response encoding + $response->setObjectEncoding($objectEncoding); + + // Authenticate, if we have credential headers + $error = false; + $headers = $request->getAmfHeaders(); + if (isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]) + && isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid) + && isset($headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password) + ) { + try { + if ($this->_handleAuth( + $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->userid, + $headers[Zend_Amf_Constants::CREDENTIALS_HEADER]->password + )) { + // use RequestPersistentHeader to clear credentials + $response->addAmfHeader( + new Zend_Amf_Value_MessageHeader( + Zend_Amf_Constants::PERSISTENT_HEADER, + false, + new Zend_Amf_Value_MessageHeader( + Zend_Amf_Constants::CREDENTIALS_HEADER, + false, null + ) + ) + ); + } + } catch (Exception $e) { + // Error during authentication; report it + $error = $this->_errorMessage( + $objectEncoding, + '', + $e->getMessage(), + $e->getTraceAsString(), + $e->getCode(), + $e->getLine() + ); + $responseType = Zend_AMF_Constants::STATUS_METHOD; + } + } + + // Iterate through each of the service calls in the AMF request + foreach($request->getAmfBodies() as $body) + { + if ($error) { + // Error during authentication; just report it and be done + $responseURI = $body->getResponseURI() . $responseType; + $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $error); + $response->addAmfBody($newBody); + continue; + } + try { + switch ($objectEncoding) { + case Zend_Amf_Constants::AMF0_OBJECT_ENCODING: + // AMF0 Object Encoding + $targetURI = $body->getTargetURI(); + $message = ''; + + // Split the target string into its values. + $source = substr($targetURI, 0, strrpos($targetURI, '.')); + + if ($source) { + // Break off method name from namespace into source + $method = substr(strrchr($targetURI, '.'), 1); + $return = $this->_dispatch($method, $body->getData(), $source); + } else { + // Just have a method name. + $return = $this->_dispatch($targetURI, $body->getData()); + } + break; + case Zend_Amf_Constants::AMF3_OBJECT_ENCODING: + default: + // AMF3 read message type + $message = $body->getData(); + if ($message instanceof Zend_Amf_Value_Messaging_CommandMessage) { + // async call with command message + $return = $this->_loadCommandMessage($message); + } elseif ($message instanceof Zend_Amf_Value_Messaging_RemotingMessage) { + $return = new Zend_Amf_Value_Messaging_AcknowledgeMessage($message); + $return->body = $this->_dispatch($message->operation, $message->body, $message->source); + } else { + // Amf3 message sent with netConnection + $targetURI = $body->getTargetURI(); + + // Split the target string into its values. + $source = substr($targetURI, 0, strrpos($targetURI, '.')); + + if ($source) { + // Break off method name from namespace into source + $method = substr(strrchr($targetURI, '.'), 1); + $return = $this->_dispatch($method, $body->getData(), $source); + } else { + // Just have a method name. + $return = $this->_dispatch($targetURI, $body->getData()); + } + } + break; + } + $responseType = Zend_AMF_Constants::RESULT_METHOD; + } catch (Exception $e) { + $return = $this->_errorMessage($objectEncoding, $message, + $e->getMessage(), $e->getTraceAsString(),$e->getCode(), $e->getLine()); + $responseType = Zend_AMF_Constants::STATUS_METHOD; + } + + $responseURI = $body->getResponseURI() . $responseType; + $newBody = new Zend_Amf_Value_MessageBody($responseURI, null, $return); + $response->addAmfBody($newBody); + } + // Add a session header to the body if session is requested. + if($this->isSession()) { + $currentID = session_id(); + $joint = "?"; + if(isset($_SERVER['QUERY_STRING'])) { + if(!strpos($_SERVER['QUERY_STRING'], $currentID) !== FALSE) { + if(strrpos($_SERVER['QUERY_STRING'], "?") !== FALSE) { + $joint = "&"; + } + } + } + + // create a new AMF message header with the session id as a variable. + $sessionValue = $joint . $this->_sessionName . "=" . $currentID; + $sessionHeader = new Zend_Amf_Value_MessageHeader(Zend_Amf_Constants::URL_APPEND_HEADER, false, $sessionValue); + $response->addAmfHeader($sessionHeader); + } + + // serialize the response and return serialized body. + $response->finalize(); + } + + /** + * Handle an AMF call from the gateway. + * + * @param null|Zend_Amf_Request $request Optional + * @return Zend_Amf_Response + */ + public function handle($request = null) + { + // Check if request was passed otherwise get it from the server + if ($request === null || !$request instanceof Zend_Amf_Request) { + $request = $this->getRequest(); + } else { + $this->setRequest($request); + } + if ($this->isSession()) { + // Check if a session is being sent from the amf call + if (isset($_COOKIE[$this->_sessionName])) { + session_id($_COOKIE[$this->_sessionName]); + } + } + + // Check for errors that may have happend in deserialization of Request. + try { + // Take converted PHP objects and handle service call. + // Serialize to Zend_Amf_response for output stream + $this->_handle($request); + $response = $this->getResponse(); + } catch (Exception $e) { + // Handle any errors in the serialization and service calls. + throw new Zend_Amf_Server_Exception('Handle error: ' . $e->getMessage() . ' ' . $e->getLine(), 0, $e); + } + + // Return the Amf serialized output string + return $response; + } + + /** + * Set request object + * + * @param string|Zend_Amf_Request $request + * @return Zend_Amf_Server + */ + public function setRequest($request) + { + if (is_string($request) && class_exists($request)) { + $request = new $request(); + if (!$request instanceof Zend_Amf_Request) { + throw new Zend_Amf_Server_Exception('Invalid request class'); + } + } elseif (!$request instanceof Zend_Amf_Request) { + throw new Zend_Amf_Server_Exception('Invalid request object'); + } + $this->_request = $request; + return $this; + } + + /** + * Return currently registered request object + * + * @return null|Zend_Amf_Request + */ + public function getRequest() + { + if (null === $this->_request) { + $this->setRequest(new Zend_Amf_Request_Http()); + } + + return $this->_request; + } + + /** + * Public access method to private Zend_Amf_Server_Response reference + * + * @param string|Zend_Amf_Server_Response $response + * @return Zend_Amf_Server + */ + public function setResponse($response) + { + if (is_string($response) && class_exists($response)) { + $response = new $response(); + if (!$response instanceof Zend_Amf_Response) { + throw new Zend_Amf_Server_Exception('Invalid response class'); + } + } elseif (!$response instanceof Zend_Amf_Response) { + throw new Zend_Amf_Server_Exception('Invalid response object'); + } + $this->_response = $response; + return $this; + } + + /** + * get a reference to the Zend_Amf_response instance + * + * @return Zend_Amf_Server_Response + */ + public function getResponse() + { + if (null === ($response = $this->_response)) { + $this->setResponse(new Zend_Amf_Response_Http()); + } + return $this->_response; + } + + /** + * Attach a class or object to the server + * + * Class may be either a class name or an instantiated object. Reflection + * is done on the class or object to determine the available public + * methods, and each is attached to the server as and available method. If + * a $namespace has been provided, that namespace is used to prefix + * AMF service call. + * + * @param string|object $class + * @param string $namespace Optional + * @param mixed $arg Optional arguments to pass to a method + * @return Zend_Amf_Server + * @throws Zend_Amf_Server_Exception on invalid input + */ + public function setClass($class, $namespace = '', $argv = null) + { + if (is_string($class) && !class_exists($class)){ + throw new Zend_Amf_Server_Exception('Invalid method or class'); + } elseif (!is_string($class) && !is_object($class)) { + throw new Zend_Amf_Server_Exception('Invalid method or class; must be a classname or object'); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = array_slice(func_get_args(), 2); + } + + // Use the class name as the name space by default. + + if ($namespace == '') { + $namespace = is_object($class) ? get_class($class) : $class; + } + + $this->_classAllowed[is_object($class) ? get_class($class) : $class] = true; + + $this->_methods[] = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); + $this->_buildDispatchTable(); + + return $this; + } + + /** + * Attach a function to the server + * + * Additional arguments to pass to the function at dispatch may be passed; + * any arguments following the namespace will be aggregated and passed at + * dispatch time. + * + * @param string|array $function Valid callback + * @param string $namespace Optional namespace prefix + * @return Zend_Amf_Server + * @throws Zend_Amf_Server_Exception + */ + public function addFunction($function, $namespace = '') + { + if (!is_string($function) && !is_array($function)) { + throw new Zend_Amf_Server_Exception('Unable to attach function'); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = array_slice(func_get_args(), 2); + } + + $function = (array) $function; + foreach ($function as $func) { + if (!is_string($func) || !function_exists($func)) { + throw new Zend_Amf_Server_Exception('Unable to attach function'); + } + $this->_methods[] = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace); + } + + $this->_buildDispatchTable(); + return $this; + } + + + /** + * Creates an array of directories in which services can reside. + * TODO: add support for prefixes? + * + * @param string $dir + */ + public function addDirectory($dir) + { + $this->getLoader()->addPrefixPath("", $dir); + } + + /** + * Returns an array of directories that can hold services. + * + * @return array + */ + public function getDirectory() + { + return $this->getLoader()->getPaths(""); + } + + /** + * (Re)Build the dispatch table + * + * The dispatch table consists of a an array of method name => + * Zend_Server_Reflection_Function_Abstract pairs + * + * @return void + */ + protected function _buildDispatchTable() + { + $table = array(); + foreach ($this->_methods as $key => $dispatchable) { + if ($dispatchable instanceof Zend_Server_Reflection_Function_Abstract) { + $ns = $dispatchable->getNamespace(); + $name = $dispatchable->getName(); + $name = empty($ns) ? $name : $ns . '.' . $name; + + if (isset($table[$name])) { + throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name); + } + $table[$name] = $dispatchable; + continue; + } + + if ($dispatchable instanceof Zend_Server_Reflection_Class) { + foreach ($dispatchable->getMethods() as $method) { + $ns = $method->getNamespace(); + $name = $method->getName(); + $name = empty($ns) ? $name : $ns . '.' . $name; + + if (isset($table[$name])) { + throw new Zend_Amf_Server_Exception('Duplicate method registered: ' . $name); + } + $table[$name] = $method; + continue; + } + } + } + $this->_table = $table; + } + + + + /** + * Raise a server fault + * + * Unimplemented + * + * @param string|Exception $fault + * @return void + */ + public function fault($fault = null, $code = 404) + { + } + + /** + * Returns a list of registered methods + * + * Returns an array of dispatchables (Zend_Server_Reflection_Function, + * _Method, and _Class items). + * + * @return array + */ + public function getFunctions() + { + return $this->_table; + } + + /** + * Set server persistence + * + * Unimplemented + * + * @param mixed $mode + * @return void + */ + public function setPersistence($mode) + { + } + + /** + * Load server definition + * + * Unimplemented + * + * @param array $definition + * @return void + */ + public function loadFunctions($definition) + { + } + + /** + * Map ActionScript classes to PHP classes + * + * @param string $asClass + * @param string $phpClass + * @return Zend_Amf_Server + */ + public function setClassMap($asClass, $phpClass) + { + Zend_Amf_Parse_TypeLoader::setMapping($asClass, $phpClass); + return $this; + } + + /** + * List all available methods + * + * Returns an array of method names. + * + * @return array + */ + public function listMethods() + { + return array_keys($this->_table); + } + + /** + * Cast parameters + * + * Takes the provided parameters from the request, and attempts to cast them + * to objects, if the prototype defines any as explicit object types + * + * @param Reflection $reflectionMethod + * @param array $params + * @return array + */ + protected function _castParameters($reflectionMethod, array $params) + { + $prototypes = $reflectionMethod->getPrototypes(); + $nonObjectTypes = array( + 'null', + 'mixed', + 'void', + 'unknown', + 'bool', + 'boolean', + 'number', + 'int', + 'integer', + 'double', + 'float', + 'string', + 'array', + 'object', + 'stdclass', + ); + $types = array(); + foreach ($prototypes as $prototype) { + foreach ($prototype->getParameters() as $parameter) { + $type = $parameter->getType(); + if (in_array(strtolower($type), $nonObjectTypes)) { + continue; + } + $position = $parameter->getPosition(); + $types[$position] = $type; + } + } + + if (empty($types)) { + return $params; + } + + foreach ($params as $position => $value) { + if (!isset($types[$position])) { + // No specific type to cast to? done + continue; + } + + $type = $types[$position]; + + if (!class_exists($type)) { + // Not a class, apparently. done + continue; + } + + if ($value instanceof $type) { + // Already of the right type? done + continue; + } + + if (!is_array($value) && !is_object($value)) { + // Can't cast scalars to objects easily; done + continue; + } + + // Create instance, and loop through value to set + $object = new $type; + foreach ($value as $property => $defined) { + $object->{$property} = $defined; + } + + $params[$position] = $object; + } + + return $params; + } +} diff --git a/library/vendor/Zend/Amf/Server/Exception.php b/library/vendor/Zend/Amf/Server/Exception.php new file mode 100644 index 000000000..d44b458a3 --- /dev/null +++ b/library/vendor/Zend/Amf/Server/Exception.php @@ -0,0 +1,36 @@ +_stream = $stream; + $this->_needle = 0; + $this->_mbStringFunctionsOverloaded = function_exists('mb_strlen') && (ini_get('mbstring.func_overload') !== '') && ((int)ini_get('mbstring.func_overload') & 2); + $this->_streamLength = $this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream); + $this->_bigEndian = (pack('l', 1) === "\x00\x00\x00\x01"); + } + + /** + * Returns the current stream + * + * @return string + */ + public function getStream() + { + return $this->_stream; + } + + /** + * Read the number of bytes in a row for the length supplied. + * + * @todo Should check that there are enough bytes left in the stream we are about to read. + * @param int $length + * @return string + * @throws Zend_Amf_Exception for buffer underrun + */ + public function readBytes($length) + { + if (($length + $this->_needle) > $this->_streamLength) { + throw new Zend_Amf_Exception('Buffer underrun at needle position: ' . $this->_needle . ' while requesting length: ' . $length); + } + $bytes = $this->_mbStringFunctionsOverloaded ? mb_substr($this->_stream, $this->_needle, $length, '8bit') : substr($this->_stream, $this->_needle, $length); + $this->_needle+= $length; + return $bytes; + } + + /** + * Write any length of bytes to the stream + * + * Usually a string. + * + * @param string $bytes + * @return Zend_Amf_Util_BinaryStream + */ + public function writeBytes($bytes) + { + $this->_stream.= $bytes; + return $this; + } + + /** + * Reads a signed byte + * + * @return int Value is in the range of -128 to 127. + * @throws Zend_Amf_Exception + */ + public function readByte() + { + if (($this->_needle + 1) > $this->_streamLength) { + throw new Zend_Amf_Exception( + 'Buffer underrun at needle position: ' + . $this->_needle + . ' while requesting length: ' + . $this->_streamLength + ); + } + + return ord($this->_stream{$this->_needle++}); + } + + /** + * Writes the passed string into a signed byte on the stream. + * + * @param string $stream + * @return Zend_Amf_Util_BinaryStream + */ + public function writeByte($stream) + { + $this->_stream.= pack('c', $stream); + return $this; + } + + /** + * Reads a signed 32-bit integer from the data stream. + * + * @return int Value is in the range of -2147483648 to 2147483647 + */ + public function readInt() + { + return ($this->readByte() << 8) + $this->readByte(); + } + + /** + * Write an the integer to the output stream as a 32 bit signed integer + * + * @param int $stream + * @return Zend_Amf_Util_BinaryStream + */ + public function writeInt($stream) + { + $this->_stream.= pack('n', $stream); + return $this; + } + + /** + * Reads a UTF-8 string from the data stream + * + * @return string A UTF-8 string produced by the byte representation of characters + */ + public function readUtf() + { + $length = $this->readInt(); + return $this->readBytes($length); + } + + /** + * Wite a UTF-8 string to the outputstream + * + * @param string $stream + * @return Zend_Amf_Util_BinaryStream + */ + public function writeUtf($stream) + { + $this->writeInt($this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream)); + $this->_stream.= $stream; + return $this; + } + + + /** + * Read a long UTF string + * + * @return string + */ + public function readLongUtf() + { + $length = $this->readLong(); + return $this->readBytes($length); + } + + /** + * Write a long UTF string to the buffer + * + * @param string $stream + * @return Zend_Amf_Util_BinaryStream + */ + public function writeLongUtf($stream) + { + $this->writeLong($this->_mbStringFunctionsOverloaded ? mb_strlen($stream, '8bit') : strlen($stream)); + $this->_stream.= $stream; + } + + /** + * Read a long numeric value + * + * @return double + */ + public function readLong() + { + return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte(); + } + + /** + * Write long numeric value to output stream + * + * @param int|string $stream + * @return Zend_Amf_Util_BinaryStream + */ + public function writeLong($stream) + { + $this->_stream.= pack('N', $stream); + return $this; + } + + /** + * Read a 16 bit unsigned short. + * + * @todo This could use the unpack() w/ S,n, or v + * @return double + */ + public function readUnsignedShort() + { + $byte1 = $this->readByte(); + $byte2 = $this->readByte(); + return (($byte1 << 8) | $byte2); + } + + /** + * Reads an IEEE 754 double-precision floating point number from the data stream. + * + * @return double Floating point number + */ + public function readDouble() + { + $bytes = $this->_mbStringFunctionsOverloaded ? mb_substr($this->_stream, $this->_needle, 8, '8bit') : substr($this->_stream, $this->_needle, 8); + $this->_needle+= 8; + + if (!$this->_bigEndian) { + $bytes = strrev($bytes); + } + + $double = unpack('dflt', $bytes); + return $double['flt']; + } + + /** + * Writes an IEEE 754 double-precision floating point number from the data stream. + * + * @param string|double $stream + * @return Zend_Amf_Util_BinaryStream + */ + public function writeDouble($stream) + { + $stream = pack('d', $stream); + if (!$this->_bigEndian) { + $stream = strrev($stream); + } + $this->_stream.= $stream; + return $this; + } + +} diff --git a/library/vendor/Zend/Amf/Value/ByteArray.php b/library/vendor/Zend/Amf/Value/ByteArray.php new file mode 100644 index 000000000..0ab5b81da --- /dev/null +++ b/library/vendor/Zend/Amf/Value/ByteArray.php @@ -0,0 +1,58 @@ +_data = $data; + } + + /** + * Return the byte stream + * + * @return string + */ + public function getData() + { + return $this->_data; + } +} diff --git a/library/vendor/Zend/Amf/Value/MessageBody.php b/library/vendor/Zend/Amf/Value/MessageBody.php new file mode 100644 index 000000000..55b3fe5ba --- /dev/null +++ b/library/vendor/Zend/Amf/Value/MessageBody.php @@ -0,0 +1,182 @@ + + * This Message structure defines how a local client would + * invoke a method/operation on a remote server. Additionally, + * the response from the Server is structured identically. + * + * @package Zend_Amf + * @subpackage Value + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Amf_Value_MessageBody +{ + /** + * A string describing which operation, function, or method + * is to be remotley invoked. + * @var string + */ + protected $_targetUri = ""; + + /** + * Universal Resource Identifier that uniquely targets the originator's + * Object that should receive the server's response. The server will + * use this path specification to target the "OnResult()" or "onStatus()" + * handlers within the client. For Flash, it specifies an ActionScript + * Object path only. The NetResponse object pointed to by the Response Uri + * contains the connection state information. Passing/specifying this + * provides a convenient mechanism for the client/server to share access + * to an object that is managing the state of the shared connection. + * + * Since the server will use this field in the event of an error, + * this field is required even if a successful server request would + * not be expected to return a value to the client. + * + * @var string + */ + protected $_responseUri = ""; + + /** + * Contains the actual data associated with the operation. It contains + * the client's parameter data that is passed to the server's operation/method. + * When serializing a root level data type or a parameter list array, no + * name field is included. That is, the data is anonomously represented + * as "Type Marker"/"Value" pairs. When serializing member data, the data is + * represented as a series of "Name"/"Type"/"Value" combinations. + * + * For server generated responses, it may contain any ActionScript + * data/objects that the server was expected to provide. + * + * @var string + */ + protected $_data; + + /** + * Constructor + * + * @param string $targetUri + * @param string $responseUri + * @param string $data + * @return void + */ + public function __construct($targetUri, $responseUri, $data) + { + $this->setTargetUri($targetUri); + $this->setResponseUri($responseUri); + $this->setData($data); + } + + /** + * Retrieve target Uri + * + * @return string + */ + public function getTargetUri() + { + return $this->_targetUri; + } + + /** + * Set target Uri + * + * @param string $targetUri + * @return Zend_Amf_Value_MessageBody + */ + public function setTargetUri($targetUri) + { + if (null === $targetUri) { + $targetUri = ''; + } + $this->_targetUri = (string) $targetUri; + return $this; + } + + /** + * Get target Uri + * + * @return string + */ + public function getResponseUri() + { + return $this->_responseUri; + } + + /** + * Set response Uri + * + * @param string $responseUri + * @return Zend_Amf_Value_MessageBody + */ + public function setResponseUri($responseUri) + { + if (null === $responseUri) { + $responseUri = ''; + } + $this->_responseUri = $responseUri; + return $this; + } + + /** + * Retrieve response data + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Set response data + * + * @param mixed $data + * @return Zend_Amf_Value_MessageBody + */ + public function setData($data) + { + $this->_data = $data; + return $this; + } + + /** + * Set reply method + * + * @param string $methodName + * @return Zend_Amf_Value_MessageBody + */ + public function setReplyMethod($methodName) + { + if (!preg_match('#^[/?]#', $methodName)) { + $this->_targetUri = rtrim($this->_targetUri, '/') . '/'; + } + $this->_targetUri = $this->_targetUri . $methodName; + return $this; + } +} diff --git a/library/vendor/Zend/Amf/Value/MessageHeader.php b/library/vendor/Zend/Amf/Value/MessageHeader.php new file mode 100644 index 000000000..9b0a49fb9 --- /dev/null +++ b/library/vendor/Zend/Amf/Value/MessageHeader.php @@ -0,0 +1,81 @@ +name = $name; + $this->mustRead = (bool) $mustRead; + $this->data = $data; + if (null !== $length) { + $this->length = (int) $length; + } + } +} diff --git a/library/vendor/Zend/Amf/Value/Messaging/AbstractMessage.php b/library/vendor/Zend/Amf/Value/Messaging/AbstractMessage.php new file mode 100644 index 000000000..f832f9390 --- /dev/null +++ b/library/vendor/Zend/Amf/Value/Messaging/AbstractMessage.php @@ -0,0 +1,92 @@ +clientId = $this->generateId(); + $this->destination = null; + $this->messageId = $this->generateId(); + $this->timestamp = time().'00'; + $this->timeToLive = 0; + $this->headers = new STDClass(); + $this->body = null; + + // correleate the two messages + if ($message && isset($message->messageId)) { + $this->correlationId = $message->messageId; + } + } +} diff --git a/library/vendor/Zend/Amf/Value/Messaging/ArrayCollection.php b/library/vendor/Zend/Amf/Value/Messaging/ArrayCollection.php new file mode 100755 index 000000000..8b1933e10 --- /dev/null +++ b/library/vendor/Zend/Amf/Value/Messaging/ArrayCollection.php @@ -0,0 +1,35 @@ +body + * of the message. + */ + const LOGIN_OPERATION = 8; + + /** + * This operation is used to log the user out of the current channel, and + * will invalidate the server session if the channel is HTTP based. + */ + const LOGOUT_OPERATION = 9; + + /** + * This operation is used to indicate that the client's subscription to a + * remote destination has been invalidated. + */ + const SESSION_INVALIDATE_OPERATION = 10; + + /** + * This operation is used by the MultiTopicConsumer to subscribe/unsubscribe + * from multiple subtopics/selectors in the same message. + */ + const MULTI_SUBSCRIBE_OPERATION = 11; + + /** + * This operation is used to indicate that a channel has disconnected + */ + const DISCONNECT_OPERATION = 12; + + /** + * This is the default operation for new CommandMessage instances. + */ + const UNKNOWN_OPERATION = 10000; + + /** + * The operation to execute for messages of this type + * @var int + */ + public $operation = self::UNKNOWN_OPERATION; +} diff --git a/library/vendor/Zend/Amf/Value/Messaging/ErrorMessage.php b/library/vendor/Zend/Amf/Value/Messaging/ErrorMessage.php new file mode 100644 index 000000000..beb93300c --- /dev/null +++ b/library/vendor/Zend/Amf/Value/Messaging/ErrorMessage.php @@ -0,0 +1,66 @@ +clientId = $this->generateId(); + $this->destination = null; + $this->messageId = $this->generateId(); + $this->timestamp = time().'00'; + $this->timeToLive = 0; + $this->headers = new stdClass(); + $this->body = null; + } +} diff --git a/library/vendor/Zend/Amf/Value/TraitsInfo.php b/library/vendor/Zend/Amf/Value/TraitsInfo.php new file mode 100644 index 000000000..f048b946a --- /dev/null +++ b/library/vendor/Zend/Amf/Value/TraitsInfo.php @@ -0,0 +1,154 @@ +_className = $className; + $this->_dynamic = $dynamic; + $this->_externalizable = $externalizable; + $this->_properties = $properties; + } + + /** + * Test if the class is a dynamic class + * + * @return boolean + */ + public function isDynamic() + { + return $this->_dynamic; + } + + /** + * Test if class is externalizable + * + * @return boolean + */ + public function isExternalizable() + { + return $this->_externalizable; + } + + /** + * Return the number of properties in the class + * + * @return int + */ + public function length() + { + return count($this->_properties); + } + + /** + * Return the class name + * + * @return string + */ + public function getClassName() + { + return $this->_className; + } + + /** + * Add an additional property + * + * @param string $name + * @return Zend_Amf_Value_TraitsInfo + */ + public function addProperty($name) + { + $this->_properties[] = $name; + return $this; + } + + /** + * Add all properties of the class. + * + * @param array $props + * @return Zend_Amf_Value_TraitsInfo + */ + public function addAllProperties(array $props) + { + $this->_properties = $props; + return $this; + } + + /** + * Get the property at a given index + * + * @param int $index + * @return string + */ + public function getProperty($index) + { + return $this->_properties[(int) $index]; + } + + /** + * Return all properties of the class. + * + * @return array + */ + public function getAllProperties() + { + return $this->_properties; + } +} diff --git a/library/vendor/Zend/Application.php b/library/vendor/Zend/Application.php new file mode 100644 index 000000000..fcb9a1c45 --- /dev/null +++ b/library/vendor/Zend/Application.php @@ -0,0 +1,415 @@ +_environment = (string) $environment; + + $this->_autoloader = Zend_Loader_Autoloader::getInstance(); + + if (null !== $options) { + if (is_string($options)) { + $options = $this->_loadConfig($options); + } elseif ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + throw new Zend_Application_Exception('Invalid options provided; must be location of config file, a config object, or an array'); + } + + $this->setOptions($options); + } + } + + /** + * Retrieve current environment + * + * @return string + */ + public function getEnvironment() + { + return $this->_environment; + } + + /** + * Retrieve autoloader instance + * + * @return Zend_Loader_Autoloader + */ + public function getAutoloader() + { + return $this->_autoloader; + } + + /** + * Set application options + * + * @param array $options + * @throws Zend_Application_Exception When no bootstrap path is provided + * @throws Zend_Application_Exception When invalid bootstrap information are provided + * @return Zend_Application + */ + public function setOptions(array $options) + { + if (!empty($options['config'])) { + if (is_array($options['config'])) { + $_options = array(); + foreach ($options['config'] as $tmp) { + $_options = $this->mergeOptions($_options, $this->_loadConfig($tmp)); + } + $options = $this->mergeOptions($_options, $options); + } else { + $options = $this->mergeOptions($this->_loadConfig($options['config']), $options); + } + } + + $this->_options = $options; + + $options = array_change_key_case($options, CASE_LOWER); + + $this->_optionKeys = array_keys($options); + + if (!empty($options['phpsettings'])) { + $this->setPhpSettings($options['phpsettings']); + } + + if (!empty($options['includepaths'])) { + $this->setIncludePaths($options['includepaths']); + } + + if (!empty($options['autoloadernamespaces'])) { + $this->setAutoloaderNamespaces($options['autoloadernamespaces']); + } + + if (!empty($options['autoloaderzfpath'])) { + $autoloader = $this->getAutoloader(); + if (method_exists($autoloader, 'setZfPath')) { + $zfPath = $options['autoloaderzfpath']; + $zfVersion = !empty($options['autoloaderzfversion']) + ? $options['autoloaderzfversion'] + : 'latest'; + $autoloader->setZfPath($zfPath, $zfVersion); + } + } + + if (!empty($options['bootstrap'])) { + $bootstrap = $options['bootstrap']; + + if (is_string($bootstrap)) { + $this->setBootstrap($bootstrap); + } elseif (is_array($bootstrap)) { + if (empty($bootstrap['path'])) { + throw new Zend_Application_Exception('No bootstrap path provided'); + } + + $path = $bootstrap['path']; + $class = null; + + if (!empty($bootstrap['class'])) { + $class = $bootstrap['class']; + } + + $this->setBootstrap($path, $class); + } else { + throw new Zend_Application_Exception('Invalid bootstrap information provided'); + } + } + + return $this; + } + + /** + * Retrieve application options (for caching) + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Is an option present? + * + * @param string $key + * @return bool + */ + public function hasOption($key) + { + return in_array(strtolower($key), $this->_optionKeys); + } + + /** + * Retrieve a single option + * + * @param string $key + * @return mixed + */ + public function getOption($key) + { + if ($this->hasOption($key)) { + $options = $this->getOptions(); + $options = array_change_key_case($options, CASE_LOWER); + return $options[strtolower($key)]; + } + return null; + } + + /** + * Merge options recursively + * + * @param array $array1 + * @param mixed $array2 + * @return array + */ + public function mergeOptions(array $array1, $array2 = null) + { + if (is_array($array2)) { + foreach ($array2 as $key => $val) { + if (is_array($array2[$key])) { + $array1[$key] = (array_key_exists($key, $array1) && is_array($array1[$key])) + ? $this->mergeOptions($array1[$key], $array2[$key]) + : $array2[$key]; + } else { + $array1[$key] = $val; + } + } + } + return $array1; + } + + /** + * Set PHP configuration settings + * + * @param array $settings + * @param string $prefix Key prefix to prepend to array values (used to map . separated INI values) + * @return Zend_Application + */ + public function setPhpSettings(array $settings, $prefix = '') + { + foreach ($settings as $key => $value) { + $key = empty($prefix) ? $key : $prefix . $key; + if (is_scalar($value)) { + ini_set($key, $value); + } elseif (is_array($value)) { + $this->setPhpSettings($value, $key . '.'); + } + } + + return $this; + } + + /** + * Set include path + * + * @param array $paths + * @return Zend_Application + */ + public function setIncludePaths(array $paths) + { + $path = implode(PATH_SEPARATOR, $paths); + set_include_path($path . PATH_SEPARATOR . get_include_path()); + return $this; + } + + /** + * Set autoloader namespaces + * + * @param array $namespaces + * @return Zend_Application + */ + public function setAutoloaderNamespaces(array $namespaces) + { + $autoloader = $this->getAutoloader(); + + foreach ($namespaces as $namespace) { + $autoloader->registerNamespace($namespace); + } + + return $this; + } + + /** + * Set bootstrap path/class + * + * @param string $path + * @param string $class + * @return Zend_Application + */ + public function setBootstrap($path, $class = null) + { + // setOptions() can potentially send a null value; specify default + // here + if (null === $class) { + $class = 'Bootstrap'; + } + + if (!class_exists($class, false)) { + if (!class_exists($class, false)) { + throw new Zend_Application_Exception('Bootstrap class not found'); + } + } + $this->_bootstrap = new $class($this); + + if (!$this->_bootstrap instanceof Zend_Application_Bootstrap_Bootstrapper) { + throw new Zend_Application_Exception('Bootstrap class does not implement Zend_Application_Bootstrap_Bootstrapper'); + } + + return $this; + } + + /** + * Get bootstrap object + * + * @return Zend_Application_Bootstrap_BootstrapAbstract + */ + public function getBootstrap() + { + if (null === $this->_bootstrap) { + $this->_bootstrap = new Zend_Application_Bootstrap_Bootstrap($this); + } + return $this->_bootstrap; + } + + /** + * Bootstrap application + * + * @param null|string|array $resource + * @return Zend_Application + */ + public function bootstrap($resource = null) + { + $this->getBootstrap()->bootstrap($resource); + return $this; + } + + /** + * Run the application + * + * @return void + */ + public function run() + { + $this->getBootstrap()->run(); + } + + /** + * Load configuration file of options + * + * @param string $file + * @throws Zend_Application_Exception When invalid configuration file is provided + * @return array + */ + protected function _loadConfig($file) + { + $environment = $this->getEnvironment(); + $suffix = pathinfo($file, PATHINFO_EXTENSION); + $suffix = ($suffix === 'dist') + ? pathinfo(basename($file, ".$suffix"), PATHINFO_EXTENSION) + : $suffix; + + switch (strtolower($suffix)) { + case 'ini': + $config = new Zend_Config_Ini($file, $environment); + break; + + case 'xml': + $config = new Zend_Config_Xml($file, $environment); + break; + + case 'json': + $config = new Zend_Config_Json($file, $environment); + break; + + case 'yaml': + case 'yml': + $config = new Zend_Config_Yaml($file, $environment); + break; + + case 'php': + case 'inc': + $config = include $file; + if (!is_array($config)) { + throw new Zend_Application_Exception('Invalid configuration file provided; PHP file does not return array value'); + } + return $config; + break; + + default: + throw new Zend_Application_Exception('Invalid configuration file provided; unknown config type'); + } + + return $config->toArray(); + } +} diff --git a/library/vendor/Zend/Application/Bootstrap/Bootstrap.php b/library/vendor/Zend/Application/Bootstrap/Bootstrap.php new file mode 100644 index 000000000..a62c78fcc --- /dev/null +++ b/library/vendor/Zend/Application/Bootstrap/Bootstrap.php @@ -0,0 +1,159 @@ +hasOption('resourceloader')) { + $this->setOptions(array( + 'resourceloader' => $application->getOption('resourceloader') + )); + } + $this->getResourceLoader(); + + if (!$this->hasPluginResource('FrontController')) { + $this->registerPluginResource('FrontController'); + } + } + + /** + * Run the application + * + * Checks to see that we have a default controller directory. If not, an + * exception is thrown. + * + * If so, it registers the bootstrap with the 'bootstrap' parameter of + * the front controller, and dispatches the front controller. + * + * @return mixed + * @throws Zend_Application_Bootstrap_Exception + */ + public function run() + { + $front = $this->getResource('FrontController'); + $default = $front->getDefaultModule(); + if (null === $front->getControllerDirectory($default)) { + throw new Zend_Application_Bootstrap_Exception( + 'No default controller directory registered with front controller' + ); + } + + $front->setParam('bootstrap', $this); + $response = $front->dispatch(); + if ($front->returnResponse()) { + return $response; + } + } + + /** + * Set module resource loader + * + * @param Zend_Loader_Autoloader_Resource $loader + * @return Zend_Application_Module_Bootstrap + */ + public function setResourceLoader(Zend_Loader_Autoloader_Resource $loader) + { + $this->_resourceLoader = $loader; + return $this; + } + + /** + * Retrieve module resource loader + * + * @return Zend_Loader_Autoloader_Resource + */ + public function getResourceLoader() + { + if ((null === $this->_resourceLoader) + && (false !== ($namespace = $this->getAppNamespace())) + ) { + $r = new ReflectionClass($this); + $path = $r->getFileName(); + $this->setResourceLoader(new Zend_Application_Module_Autoloader(array( + 'namespace' => $namespace, + 'basePath' => dirname($path), + ))); + } + return $this->_resourceLoader; + } + + /** + * Get application namespace (used for module autoloading) + * + * @return string + */ + public function getAppNamespace() + { + return $this->_appNamespace; + } + + /** + * Set application namespace (for module autoloading) + * + * @param string + * @return Zend_Application_Bootstrap_Bootstrap + */ + public function setAppNamespace($value) + { + $this->_appNamespace = (string) $value; + return $this; + } +} diff --git a/library/vendor/Zend/Application/Bootstrap/BootstrapAbstract.php b/library/vendor/Zend/Application/Bootstrap/BootstrapAbstract.php new file mode 100644 index 000000000..055266e74 --- /dev/null +++ b/library/vendor/Zend/Application/Bootstrap/BootstrapAbstract.php @@ -0,0 +1,782 @@ +setApplication($application); + $options = $application->getOptions(); + $this->setOptions($options); + } + + /** + * Set class state + * + * @param array $options + * @return Zend_Application_Bootstrap_BootstrapAbstract + */ + public function setOptions(array $options) + { + $this->_options = $this->mergeOptions($this->_options, $options); + + $options = array_change_key_case($options, CASE_LOWER); + $this->_optionKeys = array_merge($this->_optionKeys, array_keys($options)); + + $methods = get_class_methods($this); + foreach ($methods as $key => $method) { + $methods[$key] = strtolower($method); + } + + if (array_key_exists('pluginpaths', $options)) { + $pluginLoader = $this->getPluginLoader(); + + foreach ($options['pluginpaths'] as $prefix => $path) { + $pluginLoader->addPrefixPath($prefix, $path); + } + unset($options['pluginpaths']); + } + + foreach ($options as $key => $value) { + $method = 'set' . strtolower($key); + + if (in_array($method, $methods)) { + $this->$method($value); + } elseif ('resources' == $key) { + foreach ($value as $resource => $resourceOptions) { + $this->registerPluginResource($resource, $resourceOptions); + } + } + } + return $this; + } + + /** + * Get current options from bootstrap + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Is an option present? + * + * @param string $key + * @return bool + */ + public function hasOption($key) + { + return in_array(strtolower($key), $this->_optionKeys); + } + + /** + * Retrieve a single option + * + * @param string $key + * @return mixed + */ + public function getOption($key) + { + if ($this->hasOption($key)) { + $options = $this->getOptions(); + $options = array_change_key_case($options, CASE_LOWER); + return $options[strtolower($key)]; + } + return null; + } + + /** + * Merge options recursively + * + * @param array $array1 + * @param mixed $array2 + * @return array + */ + public function mergeOptions(array $array1, $array2 = null) + { + if (is_array($array2)) { + foreach ($array2 as $key => $val) { + if (is_array($array2[$key])) { + $array1[$key] = (array_key_exists($key, $array1) && is_array($array1[$key])) + ? $this->mergeOptions($array1[$key], $array2[$key]) + : $array2[$key]; + } else { + $array1[$key] = $val; + } + } + } + return $array1; + } + + /** + * Get class resources (as resource/method pairs) + * + * Uses get_class_methods() by default, reflection on prior to 5.2.6, + * as a bug prevents the usage of get_class_methods() there. + * + * @return array + */ + public function getClassResources() + { + if (null === $this->_classResources) { + if (version_compare(PHP_VERSION, '5.2.6') === -1) { + $class = new ReflectionObject($this); + $classMethods = $class->getMethods(); + $methodNames = array(); + + foreach ($classMethods as $method) { + $methodNames[] = $method->getName(); + } + } else { + $methodNames = get_class_methods($this); + } + + $this->_classResources = array(); + foreach ($methodNames as $method) { + if (5 < strlen($method) && '_init' === substr($method, 0, 5)) { + $this->_classResources[strtolower(substr($method, 5))] = $method; + } + } + } + + return $this->_classResources; + } + + /** + * Get class resource names + * + * @return array + */ + public function getClassResourceNames() + { + $resources = $this->getClassResources(); + return array_keys($resources); + } + + /** + * Register a new resource plugin + * + * @param string|Zend_Application_Resource_Resource $resource + * @param mixed $options + * @return Zend_Application_Bootstrap_BootstrapAbstract + * @throws Zend_Application_Bootstrap_Exception When invalid resource is provided + */ + public function registerPluginResource($resource, $options = null) + { + if ($resource instanceof Zend_Application_Resource_Resource) { + $resource->setBootstrap($this); + $pluginName = $this->_resolvePluginResourceName($resource); + $this->_pluginResources[$pluginName] = $resource; + return $this; + } + + if (!is_string($resource)) { + throw new Zend_Application_Bootstrap_Exception('Invalid resource provided to ' . __METHOD__); + } + + $this->_pluginResources[$resource] = $options; + return $this; + } + + /** + * Unregister a resource from the bootstrap + * + * @param string|Zend_Application_Resource_Resource $resource + * @return Zend_Application_Bootstrap_BootstrapAbstract + * @throws Zend_Application_Bootstrap_Exception When unknown resource type is provided + */ + public function unregisterPluginResource($resource) + { + if ($resource instanceof Zend_Application_Resource_Resource) { + if ($index = array_search($resource, $this->_pluginResources, true)) { + unset($this->_pluginResources[$index]); + } + return $this; + } + + if (!is_string($resource)) { + throw new Zend_Application_Bootstrap_Exception('Unknown resource type provided to ' . __METHOD__); + } + + $resource = strtolower($resource); + if (array_key_exists($resource, $this->_pluginResources)) { + unset($this->_pluginResources[$resource]); + } + + return $this; + } + + /** + * Is the requested plugin resource registered? + * + * @param string $resource + * @return bool + */ + public function hasPluginResource($resource) + { + return (null !== $this->getPluginResource($resource)); + } + + /** + * Get a registered plugin resource + * + * @param string $resource + * @return Zend_Application_Resource_Resource + * @throws Zend_Application_Bootstrap_Exception + */ + public function getPluginResource($resource) + { + if (array_key_exists(strtolower($resource), $this->_pluginResources)) { + $resource = strtolower($resource); + if (!$this->_pluginResources[$resource] instanceof Zend_Application_Resource_Resource) { + $resourceName = $this->_loadPluginResource($resource, $this->_pluginResources[$resource]); + if (!$resourceName) { + throw new Zend_Application_Bootstrap_Exception(sprintf('Unable to resolve plugin "%s"; no corresponding plugin with that name', $resource)); + } + $resource = $resourceName; + } + return $this->_pluginResources[$resource]; + } + + foreach ($this->_pluginResources as $plugin => $spec) { + if ($spec instanceof Zend_Application_Resource_Resource) { + $pluginName = $this->_resolvePluginResourceName($spec); + if (0 === strcasecmp($resource, $pluginName)) { + unset($this->_pluginResources[$plugin]); + $this->_pluginResources[$pluginName] = $spec; + return $spec; + } + continue; + } + + if (false !== $pluginName = $this->_loadPluginResource($plugin, $spec)) { + if (0 === strcasecmp($resource, $pluginName)) { + return $this->_pluginResources[$pluginName]; + } + continue; + } + + if (class_exists($plugin) + && is_subclass_of($plugin, 'Zend_Application_Resource_Resource') + ) { //@SEE ZF-7550 + $spec = (array) $spec; + $spec['bootstrap'] = $this; + $instance = new $plugin($spec); + $pluginName = $this->_resolvePluginResourceName($instance); + unset($this->_pluginResources[$plugin]); + $this->_pluginResources[$pluginName] = $instance; + + if (0 === strcasecmp($resource, $pluginName)) { + return $instance; + } + } + } + + return null; + } + + /** + * Retrieve all plugin resources + * + * @return array + */ + public function getPluginResources() + { + foreach (array_keys($this->_pluginResources) as $resource) { + $this->getPluginResource($resource); + } + return $this->_pluginResources; + } + + /** + * Retrieve plugin resource names + * + * @return array + */ + public function getPluginResourceNames() + { + $this->getPluginResources(); + return array_keys($this->_pluginResources); + } + + /** + * Set plugin loader for loading resources + * + * @param Zend_Loader_PluginLoader_Interface $loader + * @return Zend_Application_Bootstrap_BootstrapAbstract + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader) + { + $this->_pluginLoader = $loader; + return $this; + } + + /** + * Get the plugin loader for resources + * + * @return Zend_Loader_PluginLoader_Interface + */ + public function getPluginLoader() + { + if ($this->_pluginLoader === null) { + $options = array( + 'Zend_Application_Resource' => 'Zend/Application/Resource', + 'ZendX_Application_Resource' => 'ZendX/Application/Resource' + ); + + $this->_pluginLoader = new Zend_Loader_PluginLoader($options); + } + + return $this->_pluginLoader; + } + + /** + * Set application/parent bootstrap + * + * @param Zend_Application|Zend_Application_Bootstrap_Bootstrapper $application + * @return Zend_Application_Bootstrap_BootstrapAbstract + * @throws Zend_Application_Bootstrap_Exception + */ + public function setApplication($application) + { + if (($application instanceof Zend_Application) + || ($application instanceof Zend_Application_Bootstrap_Bootstrapper) + ) { + if ($application === $this) { + throw new Zend_Application_Bootstrap_Exception('Cannot set application to same object; creates recursion'); + } + $this->_application = $application; + } else { + throw new Zend_Application_Bootstrap_Exception('Invalid application provided to bootstrap constructor (received "' . get_class($application) . '" instance)'); + } + return $this; + } + + /** + * Retrieve parent application instance + * + * @return Zend_Application|Zend_Application_Bootstrap_Bootstrapper + */ + public function getApplication() + { + return $this->_application; + } + + /** + * Retrieve application environment + * + * @return string + */ + public function getEnvironment() + { + if (null === $this->_environment) { + $this->_environment = $this->getApplication()->getEnvironment(); + } + return $this->_environment; + } + + /** + * Set resource container + * + * By default, if a resource callback has a non-null return value, this + * value will be stored in a container using the resource name as the + * key. + * + * Containers must be objects, and must allow setting public properties. + * + * @param object $container + * @return Zend_Application_Bootstrap_BootstrapAbstract + * @throws Zend_Application_Bootstrap_Exception + */ + public function setContainer($container) + { + if (!is_object($container)) { + throw new Zend_Application_Bootstrap_Exception('Resource containers must be objects'); + } + $this->_container = $container; + return $this; + } + + /** + * Retrieve resource container + * + * @return object + */ + public function getContainer() + { + if (null === $this->_container) { + $this->setContainer(new Zend_Registry()); + } + return $this->_container; + } + + /** + * Determine if a resource has been stored in the container + * + * During bootstrap resource initialization, you may return a value. If + * you do, it will be stored in the {@link setContainer() container}. + * You can use this method to determine if a value was stored. + * + * @param string $name + * @return bool + */ + public function hasResource($name) + { + $resource = strtolower($name); + $container = $this->getContainer(); + return isset($container->{$resource}); + } + + /** + * Retrieve a resource from the container + * + * During bootstrap resource initialization, you may return a value. If + * you do, it will be stored in the {@link setContainer() container}. + * You can use this method to retrieve that value. + * + * If no value was returned, this will return a null value. + * + * @param string $name + * @return null|mixed + */ + public function getResource($name) + { + $resource = strtolower($name); + $container = $this->getContainer(); + if ($this->hasResource($resource)) { + return $container->{$resource}; + } + return null; + } + + /** + * Implement PHP's magic to retrieve a resource + * in the bootstrap + * + * @param string $prop + * @return null|mixed + */ + public function __get($prop) + { + return $this->getResource($prop); + } + + /** + * Implement PHP's magic to ask for the + * existence of a resource in the bootstrap + * + * @param string $prop + * @return bool + */ + public function __isset($prop) + { + return $this->hasResource($prop); + } + + /** + * Bootstrap individual, all, or multiple resources + * + * Marked as final to prevent issues when subclassing and naming the + * child class 'Bootstrap' (in which case, overriding this method + * would result in it being treated as a constructor). + * + * If you need to override this functionality, override the + * {@link _bootstrap()} method. + * + * @param null|string|array $resource + * @return Zend_Application_Bootstrap_BootstrapAbstract + * @throws Zend_Application_Bootstrap_Exception When invalid argument was passed + */ + final public function bootstrap($resource = null) + { + $this->_bootstrap($resource); + return $this; + } + + /** + * Overloading: intercept calls to bootstrap() methods + * + * @param string $method + * @param array $args + * @return Zend_Application_Bootstrap_BootstrapAbstract + * @throws Zend_Application_Bootstrap_Exception On invalid method name + */ + public function __call($method, $args) + { + if (9 < strlen($method) && 'bootstrap' === substr($method, 0, 9)) { + $resource = substr($method, 9); + return $this->bootstrap($resource); + } + + throw new Zend_Application_Bootstrap_Exception('Invalid method "' . $method . '"'); + } + + /** + * Bootstrap implementation + * + * This method may be overridden to provide custom bootstrapping logic. + * It is the sole method called by {@link bootstrap()}. + * + * @param null|string|array $resource + * @return void + * @throws Zend_Application_Bootstrap_Exception When invalid argument was passed + */ + protected function _bootstrap($resource = null) + { + if (null === $resource) { + foreach ($this->getClassResourceNames() as $resource) { + $this->_executeResource($resource); + } + + foreach ($this->getPluginResourceNames() as $resource) { + $this->_executeResource($resource); + } + } elseif (is_string($resource)) { + $this->_executeResource($resource); + } elseif (is_array($resource)) { + foreach ($resource as $r) { + $this->_executeResource($r); + } + } else { + throw new Zend_Application_Bootstrap_Exception('Invalid argument passed to ' . __METHOD__); + } + } + + /** + * Execute a resource + * + * Checks to see if the resource has already been run. If not, it searches + * first to see if a local method matches the resource, and executes that. + * If not, it checks to see if a plugin resource matches, and executes that + * if found. + * + * Finally, if not found, it throws an exception. + * + * @param string $resource + * @return void + * @throws Zend_Application_Bootstrap_Exception When resource not found + */ + protected function _executeResource($resource) + { + $resourceName = strtolower($resource); + + if (in_array($resourceName, $this->_run)) { + return; + } + + if (isset($this->_started[$resourceName]) && $this->_started[$resourceName]) { + throw new Zend_Application_Bootstrap_Exception('Circular resource dependency detected'); + } + + $classResources = $this->getClassResources(); + if (array_key_exists($resourceName, $classResources)) { + $this->_started[$resourceName] = true; + $method = $classResources[$resourceName]; + $return = $this->$method(); + unset($this->_started[$resourceName]); + $this->_markRun($resourceName); + + if (null !== $return) { + $this->getContainer()->{$resourceName} = $return; + } + + return; + } + + if ($this->hasPluginResource($resource)) { + $this->_started[$resourceName] = true; + $plugin = $this->getPluginResource($resource); + $return = $plugin->init(); + unset($this->_started[$resourceName]); + $this->_markRun($resourceName); + + if (null !== $return) { + $this->getContainer()->{$resourceName} = $return; + } + + return; + } + + throw new Zend_Application_Bootstrap_Exception('Resource matching "' . $resource . '" not found'); + } + + /** + * Load a plugin resource + * + * @param string $resource + * @param array|object|null $options + * @return string|false + */ + protected function _loadPluginResource($resource, $options) + { + $options = (array) $options; + $options['bootstrap'] = $this; + $className = $this->getPluginLoader()->load(strtolower($resource), false); + + if (!$className) { + return false; + } + + $instance = new $className($options); + + unset($this->_pluginResources[$resource]); + + if (isset($instance->_explicitType)) { + $resource = $instance->_explicitType; + } + $resource = strtolower($resource); + $this->_pluginResources[$resource] = $instance; + + return $resource; + } + + /** + * Mark a resource as having run + * + * @param string $resource + * @return void + */ + protected function _markRun($resource) + { + if (!in_array($resource, $this->_run)) { + $this->_run[] = $resource; + } + } + + /** + * Resolve a plugin resource name + * + * Uses, in order of preference + * - $_explicitType property of resource + * - Short name of resource (if a matching prefix path is found) + * - class name (if none of the above are true) + * + * The name is then cast to lowercase. + * + * @param Zend_Application_Resource_Resource $resource + * @return string + */ + protected function _resolvePluginResourceName($resource) + { + if (isset($resource->_explicitType)) { + $pluginName = $resource->_explicitType; + } else { + $className = get_class($resource); + $pluginName = $className; + $loader = $this->getPluginLoader(); + foreach ($loader->getPaths() as $prefix => $paths) { + if (0 === strpos($className, $prefix)) { + $pluginName = substr($className, strlen($prefix)); + $pluginName = trim($pluginName, '_'); + break; + } + } + } + $pluginName = strtolower($pluginName); + return $pluginName; + } +} diff --git a/library/vendor/Zend/Application/Bootstrap/Bootstrapper.php b/library/vendor/Zend/Application/Bootstrap/Bootstrapper.php new file mode 100644 index 000000000..9ea7c784f --- /dev/null +++ b/library/vendor/Zend/Application/Bootstrap/Bootstrapper.php @@ -0,0 +1,93 @@ +initDefaultResourceTypes(); + } + + /** + * Initialize default resource types for module resource classes + * + * @return void + */ + public function initDefaultResourceTypes() + { + $basePath = $this->getBasePath(); + $this->addResourceTypes(array( + 'dbtable' => array( + 'namespace' => 'Model_DbTable', + 'path' => 'models/DbTable', + ), + 'mappers' => array( + 'namespace' => 'Model_Mapper', + 'path' => 'models/mappers', + ), + 'form' => array( + 'namespace' => 'Form', + 'path' => 'forms', + ), + 'model' => array( + 'namespace' => 'Model', + 'path' => 'models', + ), + 'plugin' => array( + 'namespace' => 'Plugin', + 'path' => 'plugins', + ), + 'service' => array( + 'namespace' => 'Service', + 'path' => 'services', + ), + 'viewhelper' => array( + 'namespace' => 'View_Helper', + 'path' => 'views/helpers', + ), + 'viewfilter' => array( + 'namespace' => 'View_Filter', + 'path' => 'views/filters', + ), + )); + $this->setDefaultResourceType('model'); + } +} diff --git a/library/vendor/Zend/Application/Module/Bootstrap.php b/library/vendor/Zend/Application/Module/Bootstrap.php new file mode 100644 index 000000000..1dfe6b4e5 --- /dev/null +++ b/library/vendor/Zend/Application/Module/Bootstrap.php @@ -0,0 +1,126 @@ +setApplication($application); + + // Use same plugin loader as parent bootstrap + if ($application instanceof Zend_Application_Bootstrap_ResourceBootstrapper) { + $this->setPluginLoader($application->getPluginLoader()); + } + + $key = strtolower($this->getModuleName()); + if ($application->hasOption($key)) { + // Don't run via setOptions() to prevent duplicate initialization + $this->setOptions($application->getOption($key)); + } + + if ($application->hasOption('resourceloader')) { + $this->setOptions(array( + 'resourceloader' => $application->getOption('resourceloader') + )); + } + $this->initResourceLoader(); + + // ZF-6545: ensure front controller resource is loaded + if (!$this->hasPluginResource('FrontController')) { + $this->registerPluginResource('FrontController'); + } + + // ZF-6545: prevent recursive registration of modules + if ($this->hasPluginResource('modules')) { + $this->unregisterPluginResource('modules'); + } + } + + /** + * Ensure resource loader is loaded + * + * @return void + */ + public function initResourceLoader() + { + $this->getResourceLoader(); + } + + /** + * Get default application namespace + * + * Proxies to {@link getModuleName()}, and returns the current module + * name + * + * @return string + */ + public function getAppNamespace() + { + return $this->getModuleName(); + } + + /** + * Retrieve module name + * + * @return string + */ + public function getModuleName() + { + if (empty($this->_moduleName)) { + $class = get_class($this); + if (preg_match('/^([a-z][a-z0-9]*)_/i', $class, $matches)) { + $prefix = $matches[1]; + } else { + $prefix = $class; + } + $this->_moduleName = $prefix; + } + return $this->_moduleName; + } +} diff --git a/library/vendor/Zend/Application/Resource/Cachemanager.php b/library/vendor/Zend/Application/Resource/Cachemanager.php new file mode 100644 index 000000000..c52f58d9d --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Cachemanager.php @@ -0,0 +1,81 @@ +getCacheManager(); + } + + /** + * Retrieve Zend_Cache_Manager instance + * + * @return Zend_Cache_Manager + */ + public function getCacheManager() + { + if (null === $this->_manager) { + $this->_manager = new Zend_Cache_Manager; + + $options = $this->getOptions(); + foreach ($options as $key => $value) { + // Logger + if (isset($value['frontend']['options']['logger'])) { + $logger = $value['frontend']['options']['logger']; + if (is_array($logger)) { + $value['frontend']['options']['logger'] = Zend_Log::factory($logger); + } + } + + // Cache templates + if ($this->_manager->hasCacheTemplate($key)) { + $this->_manager->setTemplateOptions($key, $value); + } else { + $this->_manager->setCacheTemplate($key, $value); + } + } + } + + return $this->_manager; + } +} diff --git a/library/vendor/Zend/Application/Resource/Db.php b/library/vendor/Zend/Application/Resource/Db.php new file mode 100644 index 000000000..420140336 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Db.php @@ -0,0 +1,197 @@ +_adapter = $adapter; + return $this; + } + + /** + * Adapter type to use + * + * @return string + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Set the adapter params + * + * @param array $params + * @return Zend_Application_Resource_Db + */ + public function setParams(array $params) + { + $this->_params = $params; + return $this; + } + + /** + * Adapter parameters + * + * @return array + */ + public function getParams() + { + return $this->_params; + } + + /** + * Set whether to use this as default table adapter + * + * @param bool $isDefaultTableAdapter + * @return Zend_Application_Resource_Db + */ + public function setIsDefaultTableAdapter($isDefaultTableAdapter) + { + $this->_isDefaultTableAdapter = $isDefaultTableAdapter; + return $this; + } + + /** + * Is this adapter the default table adapter? + * + * @return bool + */ + public function isDefaultTableAdapter() + { + return $this->_isDefaultTableAdapter; + } + + /** + * Retrieve initialized DB connection + * + * @return null|Zend_Db_Adapter_Abstract + */ + public function getDbAdapter() + { + if ((null === $this->_db) + && (null !== ($adapter = $this->getAdapter())) + ) { + $this->_db = Zend_Db::factory($adapter, $this->getParams()); + + if ($this->_db instanceof Zend_Db_Adapter_Abstract + && $this->isDefaultTableAdapter() + ) { + Zend_Db_Table::setDefaultAdapter($this->_db); + } + } + return $this->_db; + } + + /** + * Defined by Zend_Application_Resource_Resource + * + * @return Zend_Db_Adapter_Abstract|null + */ + public function init() + { + if (null !== ($db = $this->getDbAdapter())) { + return $db; + } + + return null; + } + + /** + * Set the default metadata cache + * + * @param string|Zend_Cache_Core $cache + * @return Zend_Application_Resource_Db + */ + public function setDefaultMetadataCache($cache) + { + $metadataCache = null; + + if (is_string($cache)) { + $bootstrap = $this->getBootstrap(); + if ($bootstrap instanceof Zend_Application_Bootstrap_ResourceBootstrapper + && $bootstrap->hasPluginResource('CacheManager') + ) { + $cacheManager = $bootstrap->bootstrap('CacheManager') + ->getResource('CacheManager'); + if (null !== $cacheManager && $cacheManager->hasCache($cache)) { + $metadataCache = $cacheManager->getCache($cache); + } + } + } else if ($cache instanceof Zend_Cache_Core) { + $metadataCache = $cache; + } + + if ($metadataCache instanceof Zend_Cache_Core) { + Zend_Db_Table::setDefaultMetadataCache($metadataCache); + } + + return $this; + } +} diff --git a/library/vendor/Zend/Application/Resource/Dojo.php b/library/vendor/Zend/Application/Resource/Dojo.php new file mode 100644 index 000000000..34bd2f8ff --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Dojo.php @@ -0,0 +1,75 @@ +getDojo(); + } + + /** + * Retrieve Dojo View Helper + * + * @return Zend_Dojo_View_Dojo_Container + */ + public function getDojo() + { + if (null === $this->_dojo) { + $this->getBootstrap()->bootstrap('view'); + $view = $this->getBootstrap()->view; + + Zend_Dojo::enableView($view); + $view->dojo()->setOptions($this->getOptions()); + + $this->_dojo = $view->dojo(); + } + + return $this->_dojo; + } +} diff --git a/library/vendor/Zend/Application/Resource/Exception.php b/library/vendor/Zend/Application/Resource/Exception.php new file mode 100644 index 000000000..cc0e8346a --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Exception.php @@ -0,0 +1,39 @@ +getFrontController(); + + foreach ($this->getOptions() as $key => $value) { + switch (strtolower($key)) { + case 'controllerdirectory': + if (is_string($value)) { + $front->setControllerDirectory($value); + } elseif (is_array($value)) { + foreach ($value as $module => $directory) { + $front->addControllerDirectory($directory, $module); + } + } + break; + + case 'modulecontrollerdirectoryname': + $front->setModuleControllerDirectoryName($value); + break; + + case 'moduledirectory': + if (is_string($value)) { + $front->addModuleDirectory($value); + } elseif (is_array($value)) { + foreach($value as $moduleDir) { + $front->addModuleDirectory($moduleDir); + } + } + break; + + case 'defaultcontrollername': + $front->setDefaultControllerName($value); + break; + + case 'defaultaction': + $front->setDefaultAction($value); + break; + + case 'defaultmodule': + $front->setDefaultModule($value); + break; + + case 'baseurl': + if (!empty($value)) { + $front->setBaseUrl($value); + } + break; + + case 'params': + $front->setParams($value); + break; + + case 'plugins': + foreach ((array) $value as $pluginClass) { + $stackIndex = null; + if(is_array($pluginClass)) { + $pluginClass = array_change_key_case($pluginClass, CASE_LOWER); + if(isset($pluginClass['class'])) + { + if(isset($pluginClass['stackindex'])) { + $stackIndex = $pluginClass['stackindex']; + } + + $pluginClass = $pluginClass['class']; + } + } + + $plugin = new $pluginClass(); + $front->registerPlugin($plugin, $stackIndex); + } + break; + + case 'returnresponse': + $front->returnResponse((bool) $value); + break; + + case 'throwexceptions': + $front->throwExceptions((bool) $value); + break; + + case 'actionhelperpaths': + if (is_array($value)) { + foreach ($value as $helperPrefix => $helperPath) { + Zend_Controller_Action_HelperBroker::addPath($helperPath, $helperPrefix); + } + } + break; + + case 'dispatcher': + if(!isset($value['class'])) { + throw new Zend_Application_Exception('You must specify both '); + } + if (!isset($value['params'])) { + $value['params'] = array(); + } + + $dispatchClass = $value['class']; + if(!class_exists($dispatchClass)) { + throw new Zend_Application_Exception('Dispatcher class not found!'); + } + $front->setDispatcher(new $dispatchClass((array)$value['params'])); + break; + default: + $front->setParam($key, $value); + break; + } + } + + if (null !== ($bootstrap = $this->getBootstrap())) { + $this->getBootstrap()->frontController = $front; + } + + return $front; + } + + /** + * Retrieve front controller instance + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + if (null === $this->_front) { + $this->_front = Zend_Controller_Front::getInstance(); + } + return $this->_front; + } +} diff --git a/library/vendor/Zend/Application/Resource/Layout.php b/library/vendor/Zend/Application/Resource/Layout.php new file mode 100644 index 000000000..59b0baffe --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Layout.php @@ -0,0 +1,69 @@ +getBootstrap()->bootstrap('FrontController'); + return $this->getLayout(); + } + + /** + * Retrieve layout object + * + * @return Zend_Layout + */ + public function getLayout() + { + if (null === $this->_layout) { + $this->_layout = Zend_Layout::startMvc($this->getOptions()); + } + return $this->_layout; + } +} diff --git a/library/vendor/Zend/Application/Resource/Locale.php b/library/vendor/Zend/Application/Resource/Locale.php new file mode 100644 index 000000000..bd6853cbc --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Locale.php @@ -0,0 +1,116 @@ +getLocale(); + } + + /** + * Retrieve locale object + * + * @return Zend_Locale + */ + public function getLocale() + { + if (null === $this->_locale) { + $options = $this->getOptions(); + + if (!isset($options['default'])) { + $this->_locale = new Zend_Locale(); + } elseif(!isset($options['force']) || + (bool) $options['force'] == false) + { + // Don't force any locale, just go for auto detection + Zend_Locale::setDefault($options['default']); + $this->_locale = new Zend_Locale(); + } else { + $this->_locale = new Zend_Locale($options['default']); + } + + $key = (isset($options['registry_key']) && !is_numeric($options['registry_key'])) + ? $options['registry_key'] + : self::DEFAULT_REGISTRY_KEY; + Zend_Registry::set($key, $this->_locale); + } + + return $this->_locale; + } + + /** + * Set the cache + * + * @param string|Zend_Cache_Core $cache + * @return Zend_Application_Resource_Locale + */ + public function setCache($cache) + { + if (is_string($cache)) { + $bootstrap = $this->getBootstrap(); + if ($bootstrap instanceof Zend_Application_Bootstrap_ResourceBootstrapper + && $bootstrap->hasPluginResource('CacheManager') + ) { + $cacheManager = $bootstrap->bootstrap('CacheManager') + ->getResource('CacheManager'); + if (null !== $cacheManager && $cacheManager->hasCache($cache)) { + $cache = $cacheManager->getCache($cache); + } + } + } + + if ($cache instanceof Zend_Cache_Core) { + Zend_Locale::setCache($cache); + } + + return $this; + } +} diff --git a/library/vendor/Zend/Application/Resource/Log.php b/library/vendor/Zend/Application/Resource/Log.php new file mode 100644 index 000000000..06f2bca35 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Log.php @@ -0,0 +1,82 @@ +getLog(); + } + + /** + * Attach logger + * + * @param Zend_Log $log + * @return Zend_Application_Resource_Log + */ + public function setLog(Zend_Log $log) + { + $this->_log = $log; + return $this; + } + + /** + * Retrieve logger object + * + * @return Zend_Log + */ + public function getLog() + { + if (null === $this->_log) { + $options = $this->getOptions(); + $log = Zend_Log::factory($options); + $this->setLog($log); + } + return $this->_log; + } +} diff --git a/library/vendor/Zend/Application/Resource/Mail.php b/library/vendor/Zend/Application/Resource/Mail.php new file mode 100644 index 000000000..8a86571d4 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Mail.php @@ -0,0 +1,146 @@ +getMail(); + } + + /** + * + * @return Zend_Mail_Transport_Abstract|null + */ + public function getMail() + { + if (null === $this->_transport) { + $options = $this->getOptions(); + foreach($options as $key => $option) { + $options[strtolower($key)] = $option; + } + $this->setOptions($options); + + if(isset($options['transport']) && + !is_numeric($options['transport'])) + { + $this->_transport = $this->_setupTransport($options['transport']); + if(!isset($options['transport']['register']) || + $options['transport']['register'] == '1' || + (isset($options['transport']['register']) && + !is_numeric($options['transport']['register']) && + (bool) $options['transport']['register'] == true)) + { + Zend_Mail::setDefaultTransport($this->_transport); + } + } + + $this->_setDefaults('from'); + $this->_setDefaults('replyTo'); + } + + return $this->_transport; + } + + protected function _setDefaults($type) { + $key = strtolower('default' . $type); + $options = $this->getOptions(); + + if(isset($options[$key]['email']) && + !is_numeric($options[$key]['email'])) + { + $method = array('Zend_Mail', 'setDefault' . ucfirst($type)); + if(isset($options[$key]['name']) && + !is_numeric($options[$key]['name'])) + { + call_user_func($method, $options[$key]['email'], + $options[$key]['name']); + } else { + call_user_func($method, $options[$key]['email']); + } + } + } + + protected function _setupTransport($options) + { + if(!isset($options['type'])) { + $options['type'] = 'sendmail'; + } + + $transportName = $options['type']; + if(!Zend_Loader_Autoloader::autoload($transportName)) + { + $transportName = ucfirst(strtolower($transportName)); + + if(!Zend_Loader_Autoloader::autoload($transportName)) + { + $transportName = 'Zend_Mail_Transport_' . $transportName; + if(!Zend_Loader_Autoloader::autoload($transportName)) { + throw new Zend_Application_Resource_Exception( + "Specified Mail Transport '{$transportName}'" + . 'could not be found' + ); + } + } + } + + unset($options['type']); + unset($options['register']); //@see ZF-11022 + + switch($transportName) { + case 'Zend_Mail_Transport_Smtp': + if(!isset($options['host'])) { + throw new Zend_Application_Resource_Exception( + 'A host is necessary for smtp transport,' + .' but none was given'); + } + + $transport = new $transportName($options['host'], $options); + break; + case 'Zend_Mail_Transport_Sendmail': + default: + $transport = new $transportName($options); + break; + } + + return $transport; + } +} diff --git a/library/vendor/Zend/Application/Resource/Modules.php b/library/vendor/Zend/Application/Resource/Modules.php new file mode 100644 index 000000000..de3d8e976 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Modules.php @@ -0,0 +1,153 @@ +_bootstraps = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); + parent::__construct($options); + } + + /** + * Initialize modules + * + * @return array + * @throws Zend_Application_Resource_Exception When bootstrap class was not found + */ + public function init() + { + $bootstraps = array(); + $bootstrap = $this->getBootstrap(); + $bootstrap->bootstrap('FrontController'); + $front = $bootstrap->getResource('FrontController'); + + $modules = $front->getControllerDirectory(); + $default = $front->getDefaultModule(); + $curBootstrapClass = get_class($bootstrap); + foreach ($modules as $module => $moduleDirectory) { + $bootstrapClass = $this->_formatModuleName($module) . '_Bootstrap'; + if (!class_exists($bootstrapClass, false)) { + $bootstrapPath = dirname($moduleDirectory) . '/Bootstrap.php'; + if (file_exists($bootstrapPath)) { + $eMsgTpl = 'Bootstrap file found for module "%s" but bootstrap class "%s" not found'; + include_once $bootstrapPath; + if (($default != $module) + && !class_exists($bootstrapClass, false) + ) { + throw new Zend_Application_Resource_Exception(sprintf( + $eMsgTpl, $module, $bootstrapClass + )); + } elseif ($default == $module) { + if (!class_exists($bootstrapClass, false)) { + $bootstrapClass = 'Bootstrap'; + if (!class_exists($bootstrapClass, false)) { + throw new Zend_Application_Resource_Exception(sprintf( + $eMsgTpl, $module, $bootstrapClass + )); + } + } + } + } else { + continue; + } + } + + if ($bootstrapClass == $curBootstrapClass) { + // If the found bootstrap class matches the one calling this + // resource, don't re-execute. + continue; + } + + $bootstraps[$module] = $bootstrapClass; + } + + return $this->_bootstraps = $this->bootstrapBootstraps($bootstraps); + } + + /* + * Bootstraps the bootstraps found. Allows for easy extension. + * @param array $bootstraps Array containing the bootstraps to instantiate + */ + protected function bootstrapBootstraps($bootstraps) + { + $bootstrap = $this->getBootstrap(); + $out = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); + + foreach($bootstraps as $module => $bootstrapClass) { + $moduleBootstrap = new $bootstrapClass($bootstrap); + $moduleBootstrap->bootstrap(); + $out[$module] = $moduleBootstrap; + } + + return $out; + } + + /** + * Get bootstraps that have been run + * + * @return ArrayObject + */ + public function getExecutedBootstraps() + { + return $this->_bootstraps; + } + + /** + * Format a module name to the module class prefix + * + * @param string $name + * @return string + */ + protected function _formatModuleName($name) + { + $name = strtolower($name); + $name = str_replace(array('-', '.'), ' ', $name); + $name = ucwords($name); + $name = str_replace(' ', '', $name); + return $name; + } +} diff --git a/library/vendor/Zend/Application/Resource/Multidb.php b/library/vendor/Zend/Application/Resource/Multidb.php new file mode 100644 index 000000000..59f00ed9f --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Multidb.php @@ -0,0 +1,208 @@ + + * resources.multidb.defaultMetadataCache = "database" + * + * resources.multidb.db1.adapter = "pdo_mysql" + * resources.multidb.db1.host = "localhost" + * resources.multidb.db1.username = "webuser" + * resources.multidb.db1.password = "XXXX" + * resources.multidb.db1.dbname = "db1" + * resources.multidb.db1.default = true + * + * resources.multidb.db2.adapter = "pdo_pgsql" + * resources.multidb.db2.host = "example.com" + * resources.multidb.db2.username = "dba" + * resources.multidb.db2.password = "notthatpublic" + * resources.multidb.db2.dbname = "db2" + * + * + * @category Zend + * @package Zend_Application + * @subpackage Resource + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Application_Resource_Multidb extends Zend_Application_Resource_ResourceAbstract +{ + /** + * Associative array containing all configured db's + * + * @var array + */ + protected $_dbs = array(); + + /** + * An instance of the default db, if set + * + * @var null|Zend_Db_Adapter_Abstract + */ + protected $_defaultDb; + + /** + * Initialize the Database Connections (instances of Zend_Db_Table_Abstract) + * + * @return Zend_Application_Resource_Multidb + */ + public function init() + { + $options = $this->getOptions(); + + if (isset($options['defaultMetadataCache'])) { + $this->_setDefaultMetadataCache($options['defaultMetadataCache']); + unset($options['defaultMetadataCache']); + } + + foreach ($options as $id => $params) { + $adapter = $params['adapter']; + $default = (int) ( + isset($params['isDefaultTableAdapter']) && $params['isDefaultTableAdapter'] + || isset($params['default']) && $params['default'] + ); + unset( + $params['adapter'], + $params['default'], + $params['isDefaultTableAdapter'] + ); + + $this->_dbs[$id] = Zend_Db::factory($adapter, $params); + + if ($default) { + $this->_setDefault($this->_dbs[$id]); + } + } + + return $this; + } + + /** + * Determine if the given db(identifier) is the default db. + * + * @param string|Zend_Db_Adapter_Abstract $db The db to determine whether it's set as default + * @return boolean True if the given parameter is configured as default. False otherwise + */ + public function isDefault($db) + { + if(!$db instanceof Zend_Db_Adapter_Abstract) { + $db = $this->getDb($db); + } + + return $db === $this->_defaultDb; + } + + /** + * Retrieve the specified database connection + * + * @param null|string|Zend_Db_Adapter_Abstract $db The adapter to retrieve. + * Null to retrieve the default connection + * @return Zend_Db_Adapter_Abstract + * @throws Zend_Application_Resource_Exception if the given parameter could not be found + */ + public function getDb($db = null) + { + if ($db === null) { + return $this->getDefaultDb(); + } + + if (isset($this->_dbs[$db])) { + return $this->_dbs[$db]; + } + + throw new Zend_Application_Resource_Exception( + 'A DB adapter was tried to retrieve, but was not configured' + ); + } + + /** + * Get the default db connection + * + * @param boolean $justPickOne If true, a random (the first one in the stack) + * connection is returned if no default was set. + * If false, null is returned if no default was set. + * @return null|Zend_Db_Adapter_Abstract + */ + public function getDefaultDb($justPickOne = true) + { + if ($this->_defaultDb !== null) { + return $this->_defaultDb; + } + + if ($justPickOne) { + return reset($this->_dbs); // Return first db in db pool + } + + return null; + } + + /** + * Set the default db adapter + * + * @var Zend_Db_Adapter_Abstract $adapter Adapter to set as default + */ + protected function _setDefault(Zend_Db_Adapter_Abstract $adapter) + { + Zend_Db_Table::setDefaultAdapter($adapter); + $this->_defaultDb = $adapter; + } + + /** + * Set the default metadata cache + * + * @param string|Zend_Cache_Core $cache + * @return Zend_Application_Resource_Multidb + */ + protected function _setDefaultMetadataCache($cache) + { + $metadataCache = null; + + if (is_string($cache)) { + $bootstrap = $this->getBootstrap(); + if ($bootstrap instanceof Zend_Application_Bootstrap_ResourceBootstrapper && + $bootstrap->hasPluginResource('CacheManager') + ) { + $cacheManager = $bootstrap->bootstrap('CacheManager') + ->getResource('CacheManager'); + if (null !== $cacheManager && $cacheManager->hasCache($cache)) { + $metadataCache = $cacheManager->getCache($cache); + } + } + } else if ($cache instanceof Zend_Cache_Core) { + $metadataCache = $cache; + } + + if ($metadataCache instanceof Zend_Cache_Core) { + Zend_Db_Table::setDefaultMetadataCache($metadataCache); + } + + return $this; + } +} diff --git a/library/vendor/Zend/Application/Resource/Navigation.php b/library/vendor/Zend/Application/Resource/Navigation.php new file mode 100644 index 000000000..30cbeed96 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Navigation.php @@ -0,0 +1,127 @@ +_container) { + $options = $this->getOptions(); + + if(isset($options['defaultPageType'])) { + Zend_Navigation_Page::setDefaultPageType($options['defaultPageType']); + } + + $pages = isset($options['pages']) ? $options['pages'] : array(); + $this->_container = new Zend_Navigation($pages); + } + + $this->store(); + return $this->_container; + } + + /** + * Stores navigation container in registry or Navigation view helper + * + * @return void + */ + public function store() + { + $options = $this->getOptions(); + if (isset($options['storage']['registry']) && + $options['storage']['registry'] == true) { + $this->_storeRegistry(); + } else { + $this->_storeHelper(); + } + } + + /** + * Stores navigation container in the registry + * + * @return void + */ + protected function _storeRegistry() + { + $options = $this->getOptions(); + if(isset($options['storage']['registry']['key']) && + !is_numeric($options['storage']['registry']['key'])) // see ZF-7461 + { + $key = $options['storage']['registry']['key']; + } else { + $key = self::DEFAULT_REGISTRY_KEY; + } + + Zend_Registry::set($key,$this->getContainer()); + } + + /** + * Stores navigation container in the Navigation helper + * + * @return void + */ + protected function _storeHelper() + { + $this->getBootstrap()->bootstrap('view'); + $view = $this->getBootstrap()->view; + $view->getHelper('navigation')->navigation($this->getContainer()); + } + + /** + * Returns navigation container + * + * @return Zend_Navigation + */ + public function getContainer() + { + return $this->_container; + } +} diff --git a/library/vendor/Zend/Application/Resource/Resource.php b/library/vendor/Zend/Application/Resource/Resource.php new file mode 100644 index 000000000..37243cad6 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Resource.php @@ -0,0 +1,79 @@ +setOptions($options); + } else if ($options instanceof Zend_Config) { + $this->setOptions($options->toArray()); + } + } + + /** + * Set options from array + * + * @param array $options Configuration for resource + * @return Zend_Application_Resource_ResourceAbstract + */ + public function setOptions(array $options) + { + if (array_key_exists('bootstrap', $options)) { + $this->setBootstrap($options['bootstrap']); + unset($options['bootstrap']); + } + + foreach ($options as $key => $value) { + if (in_array(strtolower($key), $this->_skipOptions)) { + continue; + } + + $method = 'set' . strtolower($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + + $this->_options = $this->mergeOptions($this->_options, $options); + + return $this; + } + + /** + * Retrieve resource options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Merge options recursively + * + * @param array $array1 + * @param mixed $array2 + * @return array + */ + public function mergeOptions(array $array1, $array2 = null) + { + if (is_array($array2)) { + foreach ($array2 as $key => $val) { + if (is_array($array2[$key])) { + $array1[$key] = (array_key_exists($key, $array1) && is_array($array1[$key])) + ? $this->mergeOptions($array1[$key], $array2[$key]) + : $array2[$key]; + } else { + $array1[$key] = $val; + } + } + } + return $array1; + } + + /** + * Set the bootstrap to which the resource is attached + * + * @param Zend_Application_Bootstrap_Bootstrapper $bootstrap + * @return Zend_Application_Resource_Resource + */ + public function setBootstrap(Zend_Application_Bootstrap_Bootstrapper $bootstrap) + { + $this->_bootstrap = $bootstrap; + return $this; + } + + /** + * Retrieve the bootstrap to which the resource is attached + * + * @return null|Zend_Application_Bootstrap_Bootstrapper + */ + public function getBootstrap() + { + return $this->_bootstrap; + } +} diff --git a/library/vendor/Zend/Application/Resource/Router.php b/library/vendor/Zend/Application/Resource/Router.php new file mode 100644 index 000000000..259dbf129 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Router.php @@ -0,0 +1,86 @@ +getRouter(); + } + + /** + * Retrieve router object + * + * @return Zend_Controller_Router_Rewrite + */ + public function getRouter() + { + if (null === $this->_router) { + $bootstrap = $this->getBootstrap(); + $bootstrap->bootstrap('FrontController'); + $this->_router = $bootstrap->getContainer()->frontcontroller->getRouter(); + + $options = $this->getOptions(); + if (!isset($options['routes'])) { + $options['routes'] = array(); + } + + if (isset($options['chainNameSeparator'])) { + $this->_router->setChainNameSeparator($options['chainNameSeparator']); + } + + if (isset($options['useRequestParametersAsGlobal'])) { + $this->_router->useRequestParametersAsGlobal($options['useRequestParametersAsGlobal']); + } + + $this->_router->addConfig(new Zend_Config($options['routes'])); + } + + return $this->_router; + } +} diff --git a/library/vendor/Zend/Application/Resource/Session.php b/library/vendor/Zend/Application/Resource/Session.php new file mode 100644 index 000000000..59975963e --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Session.php @@ -0,0 +1,118 @@ +_saveHandler = $saveHandler; + return $this; + } + + /** + * Get session save handler + * + * @return Zend_Session_SaveHandler_Interface + * @throws Zend_Application_Resource_Exception + */ + public function getSaveHandler() + { + if (!$this->_saveHandler instanceof Zend_Session_SaveHandler_Interface) { + if (is_array($this->_saveHandler)) { + if (!array_key_exists('class', $this->_saveHandler)) { + throw new Zend_Application_Resource_Exception('Session save handler class not provided in options'); + } + $options = array(); + if (array_key_exists('options', $this->_saveHandler)) { + $options = $this->_saveHandler['options']; + } + $this->_saveHandler = $this->_saveHandler['class']; + $this->_saveHandler = new $this->_saveHandler($options); + } elseif (is_string($this->_saveHandler)) { + $this->_saveHandler = new $this->_saveHandler(); + } + + if (!$this->_saveHandler instanceof Zend_Session_SaveHandler_Interface) { + throw new Zend_Application_Resource_Exception('Invalid session save handler'); + } + } + return $this->_saveHandler; + } + + /** + * @return bool + */ + protected function _hasSaveHandler() + { + return ($this->_saveHandler !== null); + } + + /** + * Defined by Zend_Application_Resource_Resource + * + * @return void + */ + public function init() + { + $options = array_change_key_case($this->getOptions(), CASE_LOWER); + if (isset($options['savehandler'])) { + unset($options['savehandler']); + } + + if (count($options) > 0) { + Zend_Session::setOptions($options); + } + + if ($this->_hasSaveHandler()) { + Zend_Session::setSaveHandler($this->getSaveHandler()); + } + } +} diff --git a/library/vendor/Zend/Application/Resource/Translate.php b/library/vendor/Zend/Application/Resource/Translate.php new file mode 100644 index 000000000..19ebe63b7 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Translate.php @@ -0,0 +1,136 @@ +getTranslate(); + } + + /** + * Retrieve translate object + * + * @return Zend_Translate + * @throws Zend_Application_Resource_Exception if registry key was used + * already but is no instance of Zend_Translate + */ + public function getTranslate() + { + if (null === $this->_translate) { + $options = $this->getOptions(); + + if (!isset($options['content']) && !isset($options['data'])) { + throw new Zend_Application_Resource_Exception('No translation source data provided.'); + } else if (array_key_exists('content', $options) && array_key_exists('data', $options)) { + throw new Zend_Application_Resource_Exception( + 'Conflict on translation source data: choose only one key between content and data.' + ); + } + + if (empty($options['adapter'])) { + $options['adapter'] = Zend_Translate::AN_ARRAY; + } + + if (!empty($options['data'])) { + $options['content'] = $options['data']; + unset($options['data']); + } + + if (isset($options['log'])) { + if (is_array($options['log'])) { + $options['log'] = Zend_Log::factory($options['log']); + } + } + + if (isset($options['options'])) { + foreach($options['options'] as $key => $value) { + $options[$key] = $value; + } + } + + if (!empty($options['cache']) && is_string($options['cache'])) { + $bootstrap = $this->getBootstrap(); + if ($bootstrap instanceof Zend_Application_Bootstrap_ResourceBootstrapper && + $bootstrap->hasPluginResource('CacheManager') + ) { + $cacheManager = $bootstrap->bootstrap('CacheManager') + ->getResource('CacheManager'); + if (null !== $cacheManager && + $cacheManager->hasCache($options['cache']) + ) { + $options['cache'] = $cacheManager->getCache($options['cache']); + } + } + } + + $key = (isset($options['registry_key']) && !is_numeric($options['registry_key'])) + ? $options['registry_key'] + : self::DEFAULT_REGISTRY_KEY; + unset($options['registry_key']); + + if(Zend_Registry::isRegistered($key)) { + $translate = Zend_Registry::get($key); + if(!$translate instanceof Zend_Translate) { + throw new Zend_Application_Resource_Exception($key + . ' already registered in registry but is ' + . 'no instance of Zend_Translate'); + } + + $translate->addTranslation($options); + $this->_translate = $translate; + } else { + $this->_translate = new Zend_Translate($options); + Zend_Registry::set($key, $this->_translate); + } + } + + return $this->_translate; + } +} diff --git a/library/vendor/Zend/Application/Resource/Useragent.php b/library/vendor/Zend/Application/Resource/Useragent.php new file mode 100644 index 000000000..fa090c2b7 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/Useragent.php @@ -0,0 +1,72 @@ +getUserAgent(); + + // Optionally seed the UserAgent view helper + $bootstrap = $this->getBootstrap(); + if ($bootstrap->hasResource('view') || $bootstrap->hasPluginResource('view')) { + $bootstrap->bootstrap('view'); + $view = $bootstrap->getResource('view'); + if (null !== $view) { + $view->userAgent($userAgent); + } + } + + return $userAgent; + } + + /** + * Get UserAgent instance + * + * @return Zend_Http_UserAgent + */ + public function getUserAgent() + { + if (null === $this->_userAgent) { + $options = $this->getOptions(); + $this->_userAgent = new Zend_Http_UserAgent($options); + } + + return $this->_userAgent; + } +} diff --git a/library/vendor/Zend/Application/Resource/View.php b/library/vendor/Zend/Application/Resource/View.php new file mode 100644 index 000000000..699548ee5 --- /dev/null +++ b/library/vendor/Zend/Application/Resource/View.php @@ -0,0 +1,85 @@ +getView(); + + $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + $viewRenderer->setView($view); + return $view; + } + + /** + * Retrieve view object + * + * @return Zend_View + */ + public function getView() + { + if (null === $this->_view) { + $options = $this->getOptions(); + $this->_view = new Zend_View($options); + + if (isset($options['doctype'])) { + $this->_view->doctype()->setDoctype(strtoupper($options['doctype'])); + if (isset($options['charset']) && $this->_view->doctype()->isHtml5()) { + $this->_view->headMeta()->setCharset($options['charset']); + } + } + if (isset($options['contentType'])) { + $this->_view->headMeta()->appendHttpEquiv('Content-Type', $options['contentType']); + } + if (isset($options['assign']) && is_array($options['assign'])) { + $this->_view->assign($options['assign']); + } + } + return $this->_view; + } +} diff --git a/library/vendor/Zend/Auth.php b/library/vendor/Zend/Auth.php new file mode 100644 index 000000000..d5ad1150a --- /dev/null +++ b/library/vendor/Zend/Auth.php @@ -0,0 +1,168 @@ +_storage) { + /** + * @see Zend_Auth_Storage_Session + */ + $this->setStorage(new Zend_Auth_Storage_Session()); + } + + return $this->_storage; + } + + /** + * Sets the persistent storage handler + * + * @param Zend_Auth_Storage_Interface $storage + * @return Zend_Auth Provides a fluent interface + */ + public function setStorage(Zend_Auth_Storage_Interface $storage) + { + $this->_storage = $storage; + return $this; + } + + /** + * Authenticates against the supplied adapter + * + * @param Zend_Auth_Adapter_Interface $adapter + * @return Zend_Auth_Result + */ + public function authenticate(Zend_Auth_Adapter_Interface $adapter) + { + $result = $adapter->authenticate(); + + /** + * ZF-7546 - prevent multiple succesive calls from storing inconsistent results + * Ensure storage has clean state + */ + if ($this->hasIdentity()) { + $this->clearIdentity(); + } + + if ($result->isValid()) { + $this->getStorage()->write($result->getIdentity()); + } + + return $result; + } + + /** + * Returns true if and only if an identity is available from storage + * + * @return boolean + */ + public function hasIdentity() + { + return !$this->getStorage()->isEmpty(); + } + + /** + * Returns the identity from storage or null if no identity is available + * + * @return mixed|null + */ + public function getIdentity() + { + $storage = $this->getStorage(); + + if ($storage->isEmpty()) { + return null; + } + + return $storage->read(); + } + + /** + * Clears the identity from persistent storage + * + * @return void + */ + public function clearIdentity() + { + $this->getStorage()->clear(); + } +} diff --git a/library/vendor/Zend/Auth/Adapter/DbTable.php b/library/vendor/Zend/Auth/Adapter/DbTable.php new file mode 100644 index 000000000..08bacd4f9 --- /dev/null +++ b/library/vendor/Zend/Auth/Adapter/DbTable.php @@ -0,0 +1,553 @@ +_setDbAdapter($zendDb); + + if (null !== $tableName) { + $this->setTableName($tableName); + } + + if (null !== $identityColumn) { + $this->setIdentityColumn($identityColumn); + } + + if (null !== $credentialColumn) { + $this->setCredentialColumn($credentialColumn); + } + + if (null !== $credentialTreatment) { + $this->setCredentialTreatment($credentialTreatment); + } + } + + /** + * _setDbAdapter() - set the database adapter to be used for quering + * + * @param Zend_Db_Adapter_Abstract + * @throws Zend_Auth_Adapter_Exception + * @return Zend_Auth_Adapter_DbTable + */ + protected function _setDbAdapter(Zend_Db_Adapter_Abstract $zendDb = null) + { + $this->_zendDb = $zendDb; + + /** + * If no adapter is specified, fetch default database adapter. + */ + if(null === $this->_zendDb) { + $this->_zendDb = Zend_Db_Table_Abstract::getDefaultAdapter(); + if (null === $this->_zendDb) { + throw new Zend_Auth_Adapter_Exception('No database adapter present'); + } + } + + return $this; + } + + /** + * setTableName() - set the table name to be used in the select query + * + * @param string $tableName + * @return Zend_Auth_Adapter_DbTable Provides a fluent interface + */ + public function setTableName($tableName) + { + $this->_tableName = $tableName; + return $this; + } + + /** + * setIdentityColumn() - set the column name to be used as the identity column + * + * @param string $identityColumn + * @return Zend_Auth_Adapter_DbTable Provides a fluent interface + */ + public function setIdentityColumn($identityColumn) + { + $this->_identityColumn = $identityColumn; + return $this; + } + + /** + * setCredentialColumn() - set the column name to be used as the credential column + * + * @param string $credentialColumn + * @return Zend_Auth_Adapter_DbTable Provides a fluent interface + */ + public function setCredentialColumn($credentialColumn) + { + $this->_credentialColumn = $credentialColumn; + return $this; + } + + /** + * setCredentialTreatment() - allows the developer to pass a parameterized string that is + * used to transform or treat the input credential data. + * + * In many cases, passwords and other sensitive data are encrypted, hashed, encoded, + * obscured, or otherwise treated through some function or algorithm. By specifying a + * parameterized treatment string with this method, a developer may apply arbitrary SQL + * upon input credential data. + * + * Examples: + * + * 'PASSWORD(?)' + * 'MD5(?)' + * + * @param string $treatment + * @return Zend_Auth_Adapter_DbTable Provides a fluent interface + */ + public function setCredentialTreatment($treatment) + { + $this->_credentialTreatment = $treatment; + return $this; + } + + /** + * setIdentity() - set the value to be used as the identity + * + * @param string $value + * @return Zend_Auth_Adapter_DbTable Provides a fluent interface + */ + public function setIdentity($value) + { + $this->_identity = $value; + return $this; + } + + /** + * setCredential() - set the credential value to be used, optionally can specify a treatment + * to be used, should be supplied in parameterized form, such as 'MD5(?)' or 'PASSWORD(?)' + * + * @param string $credential + * @return Zend_Auth_Adapter_DbTable Provides a fluent interface + */ + public function setCredential($credential) + { + $this->_credential = $credential; + return $this; + } + + /** + * setAmbiguityIdentity() - sets a flag for usage of identical identities + * with unique credentials. It accepts integers (0, 1) or boolean (true, + * false) parameters. Default is false. + * + * @param int|bool $flag + * @return Zend_Auth_Adapter_DbTable + */ + public function setAmbiguityIdentity($flag) + { + if (is_integer($flag)) { + $this->_ambiguityIdentity = (1 === $flag ? true : false); + } elseif (is_bool($flag)) { + $this->_ambiguityIdentity = $flag; + } + return $this; + } + /** + * getAmbiguityIdentity() - returns TRUE for usage of multiple identical + * identies with different credentials, FALSE if not used. + * + * @return bool + */ + public function getAmbiguityIdentity() + { + return $this->_ambiguityIdentity; + } + + /** + * getDbSelect() - Return the preauthentication Db Select object for userland select query modification + * + * @return Zend_Db_Select + */ + public function getDbSelect() + { + if ($this->_dbSelect == null) { + $this->_dbSelect = $this->_zendDb->select(); + } + + return $this->_dbSelect; + } + + /** + * getResultRowObject() - Returns the result row as a stdClass object + * + * @param string|array $returnColumns + * @param string|array $omitColumns + * @return stdClass|boolean + */ + public function getResultRowObject($returnColumns = null, $omitColumns = null) + { + if (!$this->_resultRow) { + return false; + } + + $returnObject = new stdClass(); + + if (null !== $returnColumns) { + + $availableColumns = array_keys($this->_resultRow); + foreach ( (array) $returnColumns as $returnColumn) { + if (in_array($returnColumn, $availableColumns)) { + $returnObject->{$returnColumn} = $this->_resultRow[$returnColumn]; + } + } + return $returnObject; + + } elseif (null !== $omitColumns) { + + $omitColumns = (array) $omitColumns; + foreach ($this->_resultRow as $resultColumn => $resultValue) { + if (!in_array($resultColumn, $omitColumns)) { + $returnObject->{$resultColumn} = $resultValue; + } + } + return $returnObject; + + } else { + + foreach ($this->_resultRow as $resultColumn => $resultValue) { + $returnObject->{$resultColumn} = $resultValue; + } + return $returnObject; + + } + } + + /** + * authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to + * attempt an authentication. Previous to this call, this adapter would have already + * been configured with all necessary information to successfully connect to a database + * table and attempt to find a record matching the provided identity. + * + * @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible + * @return Zend_Auth_Result + */ + public function authenticate() + { + $this->_authenticateSetup(); + $dbSelect = $this->_authenticateCreateSelect(); + $resultIdentities = $this->_authenticateQuerySelect($dbSelect); + + if ( ($authResult = $this->_authenticateValidateResultSet($resultIdentities)) instanceof Zend_Auth_Result) { + return $authResult; + } + + if (true === $this->getAmbiguityIdentity()) { + $validIdentities = array (); + $zendAuthCredentialMatchColumn = $this->_zendDb->foldCase('zend_auth_credential_match'); + foreach ($resultIdentities as $identity) { + if (1 === (int) $identity[$zendAuthCredentialMatchColumn]) { + $validIdentities[] = $identity; + } + } + $resultIdentities = $validIdentities; + } + + $authResult = $this->_authenticateValidateResult(array_shift($resultIdentities)); + return $authResult; + } + + /** + * _authenticateSetup() - This method abstracts the steps involved with + * making sure that this adapter was indeed setup properly with all + * required pieces of information. + * + * @throws Zend_Auth_Adapter_Exception - in the event that setup was not done properly + * @return true + */ + protected function _authenticateSetup() + { + $exception = null; + + if ($this->_tableName == '') { + $exception = 'A table must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.'; + } elseif ($this->_identityColumn == '') { + $exception = 'An identity column must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.'; + } elseif ($this->_credentialColumn == '') { + $exception = 'A credential column must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.'; + } elseif ($this->_identity == '') { + $exception = 'A value for the identity was not provided prior to authentication with Zend_Auth_Adapter_DbTable.'; + } elseif ($this->_credential === null) { + $exception = 'A credential value was not provided prior to authentication with Zend_Auth_Adapter_DbTable.'; + } + + if (null !== $exception) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception($exception); + } + + $this->_authenticateResultInfo = array( + 'code' => Zend_Auth_Result::FAILURE, + 'identity' => $this->_identity, + 'messages' => array() + ); + + return true; + } + + /** + * _authenticateCreateSelect() - This method creates a Zend_Db_Select object that + * is completely configured to be queried against the database. + * + * @return Zend_Db_Select + */ + protected function _authenticateCreateSelect() + { + // build credential expression + if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, '?') === false)) { + $this->_credentialTreatment = '?'; + } + + $credentialExpression = new Zend_Db_Expr( + '(CASE WHEN ' . + $this->_zendDb->quoteInto( + $this->_zendDb->quoteIdentifier($this->_credentialColumn, true) + . ' = ' . $this->_credentialTreatment, $this->_credential + ) + . ' THEN 1 ELSE 0 END) AS ' + . $this->_zendDb->quoteIdentifier( + $this->_zendDb->foldCase('zend_auth_credential_match') + ) + ); + + // get select + $dbSelect = clone $this->getDbSelect(); + $dbSelect->from($this->_tableName, array('*', $credentialExpression)) + ->where($this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity); + + return $dbSelect; + } + + /** + * _authenticateQuerySelect() - This method accepts a Zend_Db_Select object and + * performs a query against the database with that object. + * + * @param Zend_Db_Select $dbSelect + * @throws Zend_Auth_Adapter_Exception - when an invalid select + * object is encountered + * @return array + */ + protected function _authenticateQuerySelect(Zend_Db_Select $dbSelect) + { + try { + if ($this->_zendDb->getFetchMode() != Zend_DB::FETCH_ASSOC) { + $origDbFetchMode = $this->_zendDb->getFetchMode(); + $this->_zendDb->setFetchMode(Zend_DB::FETCH_ASSOC); + } + $resultIdentities = $this->_zendDb->fetchAll($dbSelect); + if (isset($origDbFetchMode)) { + $this->_zendDb->setFetchMode($origDbFetchMode); + unset($origDbFetchMode); + } + } catch (Exception $e) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('The supplied parameters to Zend_Auth_Adapter_DbTable failed to ' + . 'produce a valid sql statement, please check table and column names ' + . 'for validity.', 0, $e); + } + return $resultIdentities; + } + + /** + * _authenticateValidateResultSet() - This method attempts to make + * certain that only one record was returned in the resultset + * + * @param array $resultIdentities + * @return true|Zend_Auth_Result + */ + protected function _authenticateValidateResultSet(array $resultIdentities) + { + + if (count($resultIdentities) < 1) { + $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; + $this->_authenticateResultInfo['messages'][] = 'A record with the supplied identity could not be found.'; + return $this->_authenticateCreateAuthResult(); + } elseif (count($resultIdentities) > 1 && false === $this->getAmbiguityIdentity()) { + $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS; + $this->_authenticateResultInfo['messages'][] = 'More than one record matches the supplied identity.'; + return $this->_authenticateCreateAuthResult(); + } + + return true; + } + + /** + * _authenticateValidateResult() - This method attempts to validate that + * the record in the resultset is indeed a record that matched the + * identity provided to this adapter. + * + * @param array $resultIdentity + * @return Zend_Auth_Result + */ + protected function _authenticateValidateResult($resultIdentity) + { + $zendAuthCredentialMatchColumn = $this->_zendDb->foldCase('zend_auth_credential_match'); + + if ($resultIdentity[$zendAuthCredentialMatchColumn] != '1') { + $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; + $this->_authenticateResultInfo['messages'][] = 'Supplied credential is invalid.'; + return $this->_authenticateCreateAuthResult(); + } + + unset($resultIdentity[$zendAuthCredentialMatchColumn]); + $this->_resultRow = $resultIdentity; + + $this->_authenticateResultInfo['code'] = Zend_Auth_Result::SUCCESS; + $this->_authenticateResultInfo['messages'][] = 'Authentication successful.'; + return $this->_authenticateCreateAuthResult(); + } + + /** + * _authenticateCreateAuthResult() - Creates a Zend_Auth_Result object from + * the information that has been collected during the authenticate() attempt. + * + * @return Zend_Auth_Result + */ + protected function _authenticateCreateAuthResult() + { + return new Zend_Auth_Result( + $this->_authenticateResultInfo['code'], + $this->_authenticateResultInfo['identity'], + $this->_authenticateResultInfo['messages'] + ); + } + +} diff --git a/library/vendor/Zend/Auth/Adapter/Digest.php b/library/vendor/Zend/Auth/Adapter/Digest.php new file mode 100644 index 000000000..ab53281bd --- /dev/null +++ b/library/vendor/Zend/Auth/Adapter/Digest.php @@ -0,0 +1,248 @@ +$methodName($$option); + } + } + } + + /** + * Returns the filename option value or null if it has not yet been set + * + * @return string|null + */ + public function getFilename() + { + return $this->_filename; + } + + /** + * Sets the filename option value + * + * @param mixed $filename + * @return Zend_Auth_Adapter_Digest Provides a fluent interface + */ + public function setFilename($filename) + { + $this->_filename = (string) $filename; + return $this; + } + + /** + * Returns the realm option value or null if it has not yet been set + * + * @return string|null + */ + public function getRealm() + { + return $this->_realm; + } + + /** + * Sets the realm option value + * + * @param mixed $realm + * @return Zend_Auth_Adapter_Digest Provides a fluent interface + */ + public function setRealm($realm) + { + $this->_realm = (string) $realm; + return $this; + } + + /** + * Returns the username option value or null if it has not yet been set + * + * @return string|null + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Sets the username option value + * + * @param mixed $username + * @return Zend_Auth_Adapter_Digest Provides a fluent interface + */ + public function setUsername($username) + { + $this->_username = (string) $username; + return $this; + } + + /** + * Returns the password option value or null if it has not yet been set + * + * @return string|null + */ + public function getPassword() + { + return $this->_password; + } + + /** + * Sets the password option value + * + * @param mixed $password + * @return Zend_Auth_Adapter_Digest Provides a fluent interface + */ + public function setPassword($password) + { + $this->_password = (string) $password; + return $this; + } + + /** + * Defined by Zend_Auth_Adapter_Interface + * + * @throws Zend_Auth_Adapter_Exception + * @return Zend_Auth_Result + */ + public function authenticate() + { + $optionsRequired = array('filename', 'realm', 'username', 'password'); + foreach ($optionsRequired as $optionRequired) { + if (null === $this->{"_$optionRequired"}) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception("Option '$optionRequired' must be set before authentication"); + } + } + + if (false === ($fileHandle = @fopen($this->_filename, 'r'))) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception("Cannot open '$this->_filename' for reading"); + } + + $id = "$this->_username:$this->_realm"; + $idLength = strlen($id); + + $result = array( + 'code' => Zend_Auth_Result::FAILURE, + 'identity' => array( + 'realm' => $this->_realm, + 'username' => $this->_username, + ), + 'messages' => array() + ); + + while ($line = trim(fgets($fileHandle))) { + if (substr($line, 0, $idLength) === $id) { + if ($this->_secureStringCompare(substr($line, -32), md5("$this->_username:$this->_realm:$this->_password"))) { + $result['code'] = Zend_Auth_Result::SUCCESS; + } else { + $result['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; + $result['messages'][] = 'Password incorrect'; + } + return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); + } + } + + $result['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; + $result['messages'][] = "Username '$this->_username' and realm '$this->_realm' combination not found"; + return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); + } + + /** + * Securely compare two strings for equality while avoided C level memcmp() + * optimisations capable of leaking timing information useful to an attacker + * attempting to iteratively guess the unknown string (e.g. password) being + * compared against. + * + * @param string $a + * @param string $b + * @return bool + */ + protected function _secureStringCompare($a, $b) + { + if (strlen($a) !== strlen($b)) { + return false; + } + $result = 0; + for ($i = 0; $i < strlen($a); $i++) { + $result |= ord($a[$i]) ^ ord($b[$i]); + } + return $result == 0; + } +} diff --git a/library/vendor/Zend/Auth/Adapter/Exception.php b/library/vendor/Zend/Auth/Adapter/Exception.php new file mode 100644 index 000000000..b7d4fd125 --- /dev/null +++ b/library/vendor/Zend/Auth/Adapter/Exception.php @@ -0,0 +1,37 @@ + 'basic'|'digest'|'basic digest' + * 'realm' => + * 'digest_domains' => Space-delimited list of URIs + * 'nonce_timeout' => + * 'use_opaque' => Whether to send the opaque value in the header + * 'alogrithm' => See $_supportedAlgos. Default: MD5 + * 'proxy_auth' => Whether to do authentication as a Proxy + * @throws Zend_Auth_Adapter_Exception + */ + public function __construct(array $config) + { + if (!extension_loaded('hash')) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception(__CLASS__ . ' requires the \'hash\' extension'); + } + + $this->_request = null; + $this->_response = null; + $this->_ieNoOpaque = false; + + + if (empty($config['accept_schemes'])) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Config key \'accept_schemes\' is required'); + } + + $schemes = explode(' ', $config['accept_schemes']); + $this->_acceptSchemes = array_intersect($schemes, $this->_supportedSchemes); + if (empty($this->_acceptSchemes)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('No supported schemes given in \'accept_schemes\'. Valid values: ' + . implode(', ', $this->_supportedSchemes)); + } + + // Double-quotes are used to delimit the realm string in the HTTP header, + // and colons are field delimiters in the password file. + if (empty($config['realm']) || + !ctype_print($config['realm']) || + strpos($config['realm'], ':') !== false || + strpos($config['realm'], '"') !== false) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Config key \'realm\' is required, and must contain only printable ' + . 'characters, excluding quotation marks and colons'); + } else { + $this->_realm = $config['realm']; + } + + if (in_array('digest', $this->_acceptSchemes)) { + if (empty($config['digest_domains']) || + !ctype_print($config['digest_domains']) || + strpos($config['digest_domains'], '"') !== false) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Config key \'digest_domains\' is required, and must contain ' + . 'only printable characters, excluding quotation marks'); + } else { + $this->_domains = $config['digest_domains']; + } + + if (empty($config['nonce_timeout']) || + !is_numeric($config['nonce_timeout'])) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Config key \'nonce_timeout\' is required, and must be an ' + . 'integer'); + } else { + $this->_nonceTimeout = (int) $config['nonce_timeout']; + } + + // We use the opaque value unless explicitly told not to + if (isset($config['use_opaque']) && false == (bool) $config['use_opaque']) { + $this->_useOpaque = false; + } else { + $this->_useOpaque = true; + } + + if (isset($config['algorithm']) && in_array($config['algorithm'], $this->_supportedAlgos)) { + $this->_algo = $config['algorithm']; + } else { + $this->_algo = 'MD5'; + } + } + + // Don't be a proxy unless explicitly told to do so + if (isset($config['proxy_auth']) && true == (bool) $config['proxy_auth']) { + $this->_imaProxy = true; // I'm a Proxy + } else { + $this->_imaProxy = false; + } + } + + /** + * Setter for the _basicResolver property + * + * @param Zend_Auth_Adapter_Http_Resolver_Interface $resolver + * @return Zend_Auth_Adapter_Http Provides a fluent interface + */ + public function setBasicResolver(Zend_Auth_Adapter_Http_Resolver_Interface $resolver) + { + $this->_basicResolver = $resolver; + + return $this; + } + + /** + * Getter for the _basicResolver property + * + * @return Zend_Auth_Adapter_Http_Resolver_Interface + */ + public function getBasicResolver() + { + return $this->_basicResolver; + } + + /** + * Setter for the _digestResolver property + * + * @param Zend_Auth_Adapter_Http_Resolver_Interface $resolver + * @return Zend_Auth_Adapter_Http Provides a fluent interface + */ + public function setDigestResolver(Zend_Auth_Adapter_Http_Resolver_Interface $resolver) + { + $this->_digestResolver = $resolver; + + return $this; + } + + /** + * Getter for the _digestResolver property + * + * @return Zend_Auth_Adapter_Http_Resolver_Interface + */ + public function getDigestResolver() + { + return $this->_digestResolver; + } + + /** + * Setter for the Request object + * + * @param Zend_Controller_Request_Http $request + * @return Zend_Auth_Adapter_Http Provides a fluent interface + */ + public function setRequest(Zend_Controller_Request_Http $request) + { + $this->_request = $request; + + return $this; + } + + /** + * Getter for the Request object + * + * @return Zend_Controller_Request_Http + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Setter for the Response object + * + * @param Zend_Controller_Response_Http $response + * @return Zend_Auth_Adapter_Http Provides a fluent interface + */ + public function setResponse(Zend_Controller_Response_Http $response) + { + $this->_response = $response; + + return $this; + } + + /** + * Getter for the Response object + * + * @return Zend_Controller_Response_Http + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Authenticate + * + * @throws Zend_Auth_Adapter_Exception + * @return Zend_Auth_Result + */ + public function authenticate() + { + if (empty($this->_request) || + empty($this->_response)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Request and Response objects must be set before calling ' + . 'authenticate()'); + } + + if ($this->_imaProxy) { + $getHeader = 'Proxy-Authorization'; + } else { + $getHeader = 'Authorization'; + } + + $authHeader = $this->_request->getHeader($getHeader); + if (!$authHeader) { + return $this->_challengeClient(); + } + + list($clientScheme) = explode(' ', $authHeader); + $clientScheme = strtolower($clientScheme); + + // The server can issue multiple challenges, but the client should + // answer with only the selected auth scheme. + if (!in_array($clientScheme, $this->_supportedSchemes)) { + $this->_response->setHttpResponseCode(400); + return new Zend_Auth_Result( + Zend_Auth_Result::FAILURE_UNCATEGORIZED, + array(), + array('Client requested an incorrect or unsupported authentication scheme') + ); + } + + // client sent a scheme that is not the one required + if (!in_array($clientScheme, $this->_acceptSchemes)) { + // challenge again the client + return $this->_challengeClient(); + } + + switch ($clientScheme) { + case 'basic': + $result = $this->_basicAuth($authHeader); + break; + case 'digest': + $result = $this->_digestAuth($authHeader); + break; + default: + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Unsupported authentication scheme'); + } + + return $result; + } + + /** + * Challenge Client + * + * Sets a 401 or 407 Unauthorized response code, and creates the + * appropriate Authenticate header(s) to prompt for credentials. + * + * @return Zend_Auth_Result Always returns a non-identity Auth result + */ + protected function _challengeClient() + { + if ($this->_imaProxy) { + $statusCode = 407; + $headerName = 'Proxy-Authenticate'; + } else { + $statusCode = 401; + $headerName = 'WWW-Authenticate'; + } + + $this->_response->setHttpResponseCode($statusCode); + + // Send a challenge in each acceptable authentication scheme + if (in_array('basic', $this->_acceptSchemes)) { + $this->_response->setHeader($headerName, $this->_basicHeader()); + } + if (in_array('digest', $this->_acceptSchemes)) { + $this->_response->setHeader($headerName, $this->_digestHeader()); + } + return new Zend_Auth_Result( + Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, + array(), + array('Invalid or absent credentials; challenging client') + ); + } + + /** + * Basic Header + * + * Generates a Proxy- or WWW-Authenticate header value in the Basic + * authentication scheme. + * + * @return string Authenticate header value + */ + protected function _basicHeader() + { + return 'Basic realm="' . $this->_realm . '"'; + } + + /** + * Digest Header + * + * Generates a Proxy- or WWW-Authenticate header value in the Digest + * authentication scheme. + * + * @return string Authenticate header value + */ + protected function _digestHeader() + { + $wwwauth = 'Digest realm="' . $this->_realm . '", ' + . 'domain="' . $this->_domains . '", ' + . 'nonce="' . $this->_calcNonce() . '", ' + . ($this->_useOpaque ? 'opaque="' . $this->_calcOpaque() . '", ' : '') + . 'algorithm="' . $this->_algo . '", ' + . 'qop="' . implode(',', $this->_supportedQops) . '"'; + + return $wwwauth; + } + + /** + * Basic Authentication + * + * @param string $header Client's Authorization header + * @throws Zend_Auth_Adapter_Exception + * @return Zend_Auth_Result + */ + protected function _basicAuth($header) + { + if (empty($header)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('The value of the client Authorization header is required'); + } + if (empty($this->_basicResolver)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('A basicResolver object must be set before doing Basic ' + . 'authentication'); + } + + // Decode the Authorization header + $auth = substr($header, strlen('Basic ')); + $auth = base64_decode($auth); + if (!$auth) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Unable to base64_decode Authorization header value'); + } + + // See ZF-1253. Validate the credentials the same way the digest + // implementation does. If invalid credentials are detected, + // re-challenge the client. + if (!ctype_print($auth)) { + return $this->_challengeClient(); + } + // Fix for ZF-1515: Now re-challenges on empty username or password + $creds = array_filter(explode(':', $auth)); + if (count($creds) != 2) { + return $this->_challengeClient(); + } + + $password = $this->_basicResolver->resolve($creds[0], $this->_realm); + if ($password && $this->_secureStringCompare($password, $creds[1])) { + $identity = array('username'=>$creds[0], 'realm'=>$this->_realm); + return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $identity); + } else { + return $this->_challengeClient(); + } + } + + /** + * Digest Authentication + * + * @param string $header Client's Authorization header + * @throws Zend_Auth_Adapter_Exception + * @return Zend_Auth_Result Valid auth result only on successful auth + */ + protected function _digestAuth($header) + { + if (empty($header)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('The value of the client Authorization header is required'); + } + if (empty($this->_digestResolver)) { + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('A digestResolver object must be set before doing Digest authentication'); + } + + $data = $this->_parseDigestAuth($header); + if ($data === false) { + $this->_response->setHttpResponseCode(400); + return new Zend_Auth_Result( + Zend_Auth_Result::FAILURE_UNCATEGORIZED, + array(), + array('Invalid Authorization header format') + ); + } + + // See ZF-1052. This code was a bit too unforgiving of invalid + // usernames. Now, if the username is bad, we re-challenge the client. + if ('::invalid::' == $data['username']) { + return $this->_challengeClient(); + } + + // Verify that the client sent back the same nonce + if ($this->_calcNonce() != $data['nonce']) { + return $this->_challengeClient(); + } + // The opaque value is also required to match, but of course IE doesn't + // play ball. + if (!$this->_ieNoOpaque && $this->_calcOpaque() != $data['opaque']) { + return $this->_challengeClient(); + } + + // Look up the user's password hash. If not found, deny access. + // This makes no assumptions about how the password hash was + // constructed beyond that it must have been built in such a way as + // to be recreatable with the current settings of this object. + $ha1 = $this->_digestResolver->resolve($data['username'], $data['realm']); + if ($ha1 === false) { + return $this->_challengeClient(); + } + + // If MD5-sess is used, a1 value is made of the user's password + // hash with the server and client nonce appended, separated by + // colons. + if ($this->_algo == 'MD5-sess') { + $ha1 = hash('md5', $ha1 . ':' . $data['nonce'] . ':' . $data['cnonce']); + } + + // Calculate h(a2). The value of this hash depends on the qop + // option selected by the client and the supported hash functions + switch ($data['qop']) { + case 'auth': + $a2 = $this->_request->getMethod() . ':' . $data['uri']; + break; + case 'auth-int': + // Should be REQUEST_METHOD . ':' . uri . ':' . hash(entity-body), + // but this isn't supported yet, so fall through to default case + default: + /** + * @see Zend_Auth_Adapter_Exception + */ + throw new Zend_Auth_Adapter_Exception('Client requested an unsupported qop option'); + } + // Using hash() should make parameterizing the hash algorithm + // easier + $ha2 = hash('md5', $a2); + + + // Calculate the server's version of the request-digest. This must + // match $data['response']. See RFC 2617, section 3.2.2.1 + $message = $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . $ha2; + $digest = hash('md5', $ha1 . ':' . $message); + + // If our digest matches the client's let them in, otherwise return + // a 401 code and exit to prevent access to the protected resource. + if ($this->_secureStringCompare($digest, $data['response'])) { + $identity = array('username'=>$data['username'], 'realm'=>$data['realm']); + return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $identity); + } else { + return $this->_challengeClient(); + } + } + + /** + * Calculate Nonce + * + * @return string The nonce value + */ + protected function _calcNonce() + { + // Once subtle consequence of this timeout calculation is that it + // actually divides all of time into _nonceTimeout-sized sections, such + // that the value of timeout is the point in time of the next + // approaching "boundary" of a section. This allows the server to + // consistently generate the same timeout (and hence the same nonce + // value) across requests, but only as long as one of those + // "boundaries" is not crossed between requests. If that happens, the + // nonce will change on its own, and effectively log the user out. This + // would be surprising if the user just logged in. + $timeout = ceil(time() / $this->_nonceTimeout) * $this->_nonceTimeout; + + $nonce = hash('md5', $timeout . ':' . $this->_request->getServer('HTTP_USER_AGENT') . ':' . __CLASS__); + return $nonce; + } + + /** + * Calculate Opaque + * + * The opaque string can be anything; the client must return it exactly as + * it was sent. It may be useful to store data in this string in some + * applications. Ideally, a new value for this would be generated each time + * a WWW-Authenticate header is sent (in order to reduce predictability), + * but we would have to be able to create the same exact value across at + * least two separate requests from the same client. + * + * @return string The opaque value + */ + protected function _calcOpaque() + { + return hash('md5', 'Opaque Data:' . __CLASS__); + } + + /** + * Parse Digest Authorization header + * + * @param string $header Client's Authorization: HTTP header + * @return array|false Data elements from header, or false if any part of + * the header is invalid + */ + protected function _parseDigestAuth($header) + { + $temp = null; + $data = array(); + + // See ZF-1052. Detect invalid usernames instead of just returning a + // 400 code. + $ret = preg_match('/username="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1]) + || !ctype_print($temp[1]) + || strpos($temp[1], ':') !== false) { + $data['username'] = '::invalid::'; + } else { + $data['username'] = $temp[1]; + } + $temp = null; + + $ret = preg_match('/realm="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + if (!ctype_print($temp[1]) || strpos($temp[1], ':') !== false) { + return false; + } else { + $data['realm'] = $temp[1]; + } + $temp = null; + + $ret = preg_match('/nonce="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + if (!ctype_xdigit($temp[1])) { + return false; + } else { + $data['nonce'] = $temp[1]; + } + $temp = null; + + $ret = preg_match('/uri="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + // Section 3.2.2.5 in RFC 2617 says the authenticating server must + // verify that the URI field in the Authorization header is for the + // same resource requested in the Request Line. + $rUri = @parse_url($this->_request->getRequestUri()); + $cUri = @parse_url($temp[1]); + if (false === $rUri || false === $cUri) { + return false; + } else { + // Make sure the path portion of both URIs is the same + if ($rUri['path'] != $cUri['path']) { + return false; + } + // Section 3.2.2.5 seems to suggest that the value of the URI + // Authorization field should be made into an absolute URI if the + // Request URI is absolute, but it's vague, and that's a bunch of + // code I don't want to write right now. + $data['uri'] = $temp[1]; + } + $temp = null; + + $ret = preg_match('/response="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + if (32 != strlen($temp[1]) || !ctype_xdigit($temp[1])) { + return false; + } else { + $data['response'] = $temp[1]; + } + $temp = null; + + // The spec says this should default to MD5 if omitted. OK, so how does + // that square with the algo we send out in the WWW-Authenticate header, + // if it can easily be overridden by the client? + $ret = preg_match('/algorithm="?(' . $this->_algo . ')"?/', $header, $temp); + if ($ret && !empty($temp[1]) + && in_array($temp[1], $this->_supportedAlgos)) { + $data['algorithm'] = $temp[1]; + } else { + $data['algorithm'] = 'MD5'; // = $this->_algo; ? + } + $temp = null; + + // Not optional in this implementation + $ret = preg_match('/cnonce="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + if (!ctype_print($temp[1])) { + return false; + } else { + $data['cnonce'] = $temp[1]; + } + $temp = null; + + // If the server sent an opaque value, the client must send it back + if ($this->_useOpaque) { + $ret = preg_match('/opaque="([^"]+)"/', $header, $temp); + if (!$ret || empty($temp[1])) { + + // Big surprise: IE isn't RFC 2617-compliant. + if (false !== strpos($this->_request->getHeader('User-Agent'), 'MSIE')) { + $temp[1] = ''; + $this->_ieNoOpaque = true; + } else { + return false; + } + } + // This implementation only sends MD5 hex strings in the opaque value + if (!$this->_ieNoOpaque && + (32 != strlen($temp[1]) || !ctype_xdigit($temp[1]))) { + return false; + } else { + $data['opaque'] = $temp[1]; + } + $temp = null; + } + + // Not optional in this implementation, but must be one of the supported + // qop types + $ret = preg_match('/qop="?(' . implode('|', $this->_supportedQops) . ')"?/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + if (!in_array($temp[1], $this->_supportedQops)) { + return false; + } else { + $data['qop'] = $temp[1]; + } + $temp = null; + + // Not optional in this implementation. The spec says this value + // shouldn't be a quoted string, but apparently some implementations + // quote it anyway. See ZF-1544. + $ret = preg_match('/nc="?([0-9A-Fa-f]{8})"?/', $header, $temp); + if (!$ret || empty($temp[1])) { + return false; + } + if (8 != strlen($temp[1]) || !ctype_xdigit($temp[1])) { + return false; + } else { + $data['nc'] = $temp[1]; + } + $temp = null; + + return $data; + } + + /** + * Securely compare two strings for equality while avoided C level memcmp() + * optimisations capable of leaking timing information useful to an attacker + * attempting to iteratively guess the unknown string (e.g. password) being + * compared against. + * + * @param string $a + * @param string $b + * @return bool + */ + protected function _secureStringCompare($a, $b) + { + if (strlen($a) !== strlen($b)) { + return false; + } + $result = 0; + for ($i = 0; $i < strlen($a); $i++) { + $result |= ord($a[$i]) ^ ord($b[$i]); + } + return $result == 0; + } +} diff --git a/library/vendor/Zend/Auth/Adapter/Http/Resolver/Exception.php b/library/vendor/Zend/Auth/Adapter/Http/Resolver/Exception.php new file mode 100644 index 000000000..50b0b51de --- /dev/null +++ b/library/vendor/Zend/Auth/Adapter/Http/Resolver/Exception.php @@ -0,0 +1,39 @@ +setFile($path); + } + } + + /** + * Set the path to the credentials file + * + * @param string $path + * @throws Zend_Auth_Adapter_Http_Resolver_Exception + * @return Zend_Auth_Adapter_Http_Resolver_File Provides a fluent interface + */ + public function setFile($path) + { + if (empty($path) || !is_readable($path)) { + /** + * @see Zend_Auth_Adapter_Http_Resolver_Exception + */ + throw new Zend_Auth_Adapter_Http_Resolver_Exception('Path not readable: ' . $path); + } + $this->_file = $path; + + return $this; + } + + /** + * Returns the path to the credentials file + * + * @return string + */ + public function getFile() + { + return $this->_file; + } + + /** + * Resolve credentials + * + * Only the first matching username/realm combination in the file is + * returned. If the file contains credentials for Digest authentication, + * the returned string is the password hash, or h(a1) from RFC 2617. The + * returned string is the plain-text password for Basic authentication. + * + * The expected format of the file is: + * username:realm:sharedSecret + * + * That is, each line consists of the user's username, the applicable + * authentication realm, and the password or hash, each delimited by + * colons. + * + * @param string $username Username + * @param string $realm Authentication Realm + * @throws Zend_Auth_Adapter_Http_Resolver_Exception + * @return string|false User's shared secret, if the user is found in the + * realm, false otherwise. + */ + public function resolve($username, $realm) + { + if (empty($username)) { + /** + * @see Zend_Auth_Adapter_Http_Resolver_Exception + */ + throw new Zend_Auth_Adapter_Http_Resolver_Exception('Username is required'); + } else if (!ctype_print($username) || strpos($username, ':') !== false) { + /** + * @see Zend_Auth_Adapter_Http_Resolver_Exception + */ + throw new Zend_Auth_Adapter_Http_Resolver_Exception('Username must consist only of printable characters, ' + . 'excluding the colon'); + } + if (empty($realm)) { + /** + * @see Zend_Auth_Adapter_Http_Resolver_Exception + */ + throw new Zend_Auth_Adapter_Http_Resolver_Exception('Realm is required'); + } else if (!ctype_print($realm) || strpos($realm, ':') !== false) { + /** + * @see Zend_Auth_Adapter_Http_Resolver_Exception + */ + throw new Zend_Auth_Adapter_Http_Resolver_Exception('Realm must consist only of printable characters, ' + . 'excluding the colon.'); + } + + // Open file, read through looking for matching credentials + $fp = @fopen($this->_file, 'r'); + if (!$fp) { + /** + * @see Zend_Auth_Adapter_Http_Resolver_Exception + */ + throw new Zend_Auth_Adapter_Http_Resolver_Exception('Unable to open password file: ' . $this->_file); + } + + // No real validation is done on the contents of the password file. The + // assumption is that we trust the administrators to keep it secure. + while (($line = fgetcsv($fp, 512, ':')) !== false) { + if ($line[0] == $username && $line[1] == $realm) { + $password = $line[2]; + fclose($fp); + return $password; + } + } + + fclose($fp); + return false; + } +} diff --git a/library/vendor/Zend/Auth/Adapter/Http/Resolver/Interface.php b/library/vendor/Zend/Auth/Adapter/Http/Resolver/Interface.php new file mode 100644 index 000000000..59f765eea --- /dev/null +++ b/library/vendor/Zend/Auth/Adapter/Http/Resolver/Interface.php @@ -0,0 +1,47 @@ +_id = $id; + $this->_storage = $storage; + $this->_returnTo = $returnTo; + $this->_root = $root; + $this->_extensions = $extensions; + $this->_response = $response; + } + + /** + * Sets the value to be used as the identity + * + * @param string $id the identity value + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setIdentity($id) + { + $this->_id = $id; + return $this; + } + + /** + * Sets the storage implementation which will be use by OpenId + * + * @param Zend_OpenId_Consumer_Storage $storage + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setStorage(Zend_OpenId_Consumer_Storage $storage) + { + $this->_storage = $storage; + return $this; + } + + /** + * Sets the HTTP URL to redirect response from server to + * + * @param string $returnTo + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setReturnTo($returnTo) + { + $this->_returnTo = $returnTo; + return $this; + } + + /** + * Sets HTTP URL to identify consumer on server + * + * @param string $root + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setRoot($root) + { + $this->_root = $root; + return $this; + } + + /** + * Sets OpenID extension(s) + * + * @param mixed $extensions + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setExtensions($extensions) + { + $this->_extensions = $extensions; + return $this; + } + + /** + * Sets an optional response object to perform HTTP or HTML form redirection + * + * @param string $response + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setResponse($response) + { + $this->_response = $response; + return $this; + } + + /** + * Enables or disables interaction with user during authentication on + * OpenID provider. + * + * @param bool $check_immediate + * @return Zend_Auth_Adapter_OpenId Provides a fluent interface + */ + public function setCheckImmediate($check_immediate) + { + $this->_check_immediate = $check_immediate; + return $this; + } + + /** + * Sets HTTP client object to make HTTP requests + * + * @param Zend_Http_Client $client HTTP client object to be used + */ + public function setHttpClient($client) { + $this->_httpClient = $client; + } + + /** + * Authenticates the given OpenId identity. + * Defined by Zend_Auth_Adapter_Interface. + * + * @throws Zend_Auth_Adapter_Exception If answering the authentication query is impossible + * @return Zend_Auth_Result + */ + public function authenticate() { + $id = $this->_id; + if (!empty($id)) { + $consumer = new Zend_OpenId_Consumer($this->_storage); + $consumer->setHttpClient($this->_httpClient); + /* login() is never returns on success */ + if (!$this->_check_immediate) { + if (!$consumer->login($id, + $this->_returnTo, + $this->_root, + $this->_extensions, + $this->_response)) { + return new Zend_Auth_Result( + Zend_Auth_Result::FAILURE, + $id, + array("Authentication failed", $consumer->getError())); + } + } else { + if (!$consumer->check($id, + $this->_returnTo, + $this->_root, + $this->_extensions, + $this->_response)) { + return new Zend_Auth_Result( + Zend_Auth_Result::FAILURE, + $id, + array("Authentication failed", $consumer->getError())); + } + } + } else { + $params = (isset($_SERVER['REQUEST_METHOD']) && + $_SERVER['REQUEST_METHOD']=='POST') ? $_POST: $_GET; + $consumer = new Zend_OpenId_Consumer($this->_storage); + $consumer->setHttpClient($this->_httpClient); + if ($consumer->verify( + $params, + $id, + $this->_extensions)) { + return new Zend_Auth_Result( + Zend_Auth_Result::SUCCESS, + $id, + array("Authentication successful")); + } else { + return new Zend_Auth_Result( + Zend_Auth_Result::FAILURE, + $id, + array("Authentication failed", $consumer->getError())); + } + } + } + +} diff --git a/library/vendor/Zend/Auth/Exception.php b/library/vendor/Zend/Auth/Exception.php new file mode 100644 index 000000000..9b4db3e6a --- /dev/null +++ b/library/vendor/Zend/Auth/Exception.php @@ -0,0 +1,35 @@ + self::SUCCESS ) { + $code = 1; + } + + $this->_code = $code; + $this->_identity = $identity; + $this->_messages = $messages; + } + + /** + * Returns whether the result represents a successful authentication attempt + * + * @return boolean + */ + public function isValid() + { + return ($this->_code > 0) ? true : false; + } + + /** + * getCode() - Get the result code for this authentication attempt + * + * @return int + */ + public function getCode() + { + return $this->_code; + } + + /** + * Returns the identity used in the authentication attempt + * + * @return mixed + */ + public function getIdentity() + { + return $this->_identity; + } + + /** + * Returns an array of string reasons why the authentication attempt was unsuccessful + * + * If authentication was successful, this method returns an empty array. + * + * @return array + */ + public function getMessages() + { + return $this->_messages; + } +} diff --git a/library/vendor/Zend/Auth/Storage/Exception.php b/library/vendor/Zend/Auth/Storage/Exception.php new file mode 100644 index 000000000..10a81ac56 --- /dev/null +++ b/library/vendor/Zend/Auth/Storage/Exception.php @@ -0,0 +1,37 @@ +_data); + } + + /** + * Returns the contents of storage + * Behavior is undefined when storage is empty. + * + * @throws Zend_Auth_Storage_Exception If reading contents from storage is impossible + * @return mixed + */ + public function read() + { + return $this->_data; + } + + /** + * Writes $contents to storage + * + * @param mixed $contents + * @throws Zend_Auth_Storage_Exception If writing $contents to storage is impossible + * @return void + */ + public function write($contents) + { + $this->_data = $contents; + } + + /** + * Clears contents from storage + * + * @throws Zend_Auth_Storage_Exception If clearing contents from storage is impossible + * @return void + */ + public function clear() + { + $this->_data = null; + } +} diff --git a/library/vendor/Zend/Auth/Storage/Session.php b/library/vendor/Zend/Auth/Storage/Session.php new file mode 100644 index 000000000..3a86fa9cf --- /dev/null +++ b/library/vendor/Zend/Auth/Storage/Session.php @@ -0,0 +1,147 @@ +_namespace = $namespace; + $this->_member = $member; + $this->_session = new Zend_Session_Namespace($this->_namespace); + } + + /** + * Returns the session namespace + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * Returns the name of the session object member + * + * @return string + */ + public function getMember() + { + return $this->_member; + } + + /** + * Defined by Zend_Auth_Storage_Interface + * + * @return boolean + */ + public function isEmpty() + { + return !isset($this->_session->{$this->_member}); + } + + /** + * Defined by Zend_Auth_Storage_Interface + * + * @return mixed + */ + public function read() + { + return $this->_session->{$this->_member}; + } + + /** + * Defined by Zend_Auth_Storage_Interface + * + * @param mixed $contents + * @return void + */ + public function write($contents) + { + $this->_session->{$this->_member} = $contents; + } + + /** + * Defined by Zend_Auth_Storage_Interface + * + * @return void + */ + public function clear() + { + unset($this->_session->{$this->_member}); + } +} diff --git a/library/vendor/Zend/Barcode.php b/library/vendor/Zend/Barcode.php new file mode 100644 index 000000000..914f633ae --- /dev/null +++ b/library/vendor/Zend/Barcode.php @@ -0,0 +1,343 @@ +rendererParams)) { + $rendererConfig = $barcode->rendererParams->toArray(); + } + if (isset($barcode->renderer)) { + $renderer = (string) $barcode->renderer; + } + if (isset($barcode->barcodeParams)) { + $barcodeConfig = $barcode->barcodeParams->toArray(); + } + if (isset($barcode->barcode)) { + $barcode = (string) $barcode->barcode; + } else { + $barcode = null; + } + } + + try { + $barcode = self::makeBarcode($barcode, $barcodeConfig); + $renderer = self::makeRenderer($renderer, $rendererConfig); + } catch (Zend_Exception $e) { + $renderable = ($e instanceof Zend_Barcode_Exception) ? $e->isRenderable() : false; + if ($automaticRenderError && $renderable) { + $barcode = self::makeBarcode('error', array( + 'text' => $e->getMessage() + )); + $renderer = self::makeRenderer($renderer, array()); + } else { + throw $e; + } + } + + $renderer->setAutomaticRenderError($automaticRenderError); + return $renderer->setBarcode($barcode); + } + + /** + * Barcode Constructor + * + * @param mixed $barcode String name of barcode class, or Zend_Config object. + * @param mixed $barcodeConfig OPTIONAL; an array or Zend_Config object with barcode parameters. + * @return Zend_Barcode_Object + */ + public static function makeBarcode($barcode, $barcodeConfig = array()) + { + if ($barcode instanceof Zend_Barcode_Object_ObjectAbstract) { + return $barcode; + } + + /* + * Convert Zend_Config argument to plain string + * barcode name and separate config object. + */ + if ($barcode instanceof Zend_Config) { + if (isset($barcode->barcodeParams) && $barcode->barcodeParams instanceof Zend_Config) { + $barcodeConfig = $barcode->barcodeParams->toArray(); + } + if (isset($barcode->barcode)) { + $barcode = (string) $barcode->barcode; + } else { + $barcode = null; + } + } + if ($barcodeConfig instanceof Zend_Config) { + $barcodeConfig = $barcodeConfig->toArray(); + } + + /* + * Verify that barcode parameters are in an array. + */ + if (!is_array($barcodeConfig)) { + /** + * @see Zend_Barcode_Exception + */ + throw new Zend_Barcode_Exception( + 'Barcode parameters must be in an array or a Zend_Config object' + ); + } + + /* + * Verify that an barcode name has been specified. + */ + if (!is_string($barcode) || empty($barcode)) { + /** + * @see Zend_Barcode_Exception + */ + throw new Zend_Barcode_Exception( + 'Barcode name must be specified in a string' + ); + } + /* + * Form full barcode class name + */ + $barcodeNamespace = 'Zend_Barcode_Object'; + if (isset($barcodeConfig['barcodeNamespace'])) { + $barcodeNamespace = $barcodeConfig['barcodeNamespace']; + } + + $barcodeName = strtolower($barcodeNamespace . '_' . $barcode); + $barcodeName = str_replace(' ', '_', ucwords( + str_replace( '_', ' ', $barcodeName) + )); + + /* + * Load the barcode class. This throws an exception + * if the specified class cannot be loaded. + */ + if (!class_exists($barcodeName)) { + Zend_Loader::loadClass($barcodeName); + } + + /* + * Create an instance of the barcode class. + * Pass the config to the barcode class constructor. + */ + $bcAdapter = new $barcodeName($barcodeConfig); + + /* + * Verify that the object created is a descendent of the abstract barcode type. + */ + if (!$bcAdapter instanceof Zend_Barcode_Object_ObjectAbstract) { + /** + * @see Zend_Barcode_Exception + */ + throw new Zend_Barcode_Exception( + "Barcode class '$barcodeName' does not extend Zend_Barcode_Object_ObjectAbstract" + ); + } + return $bcAdapter; + } + + /** + * Renderer Constructor + * + * @param mixed $renderer String name of renderer class, or Zend_Config object. + * @param mixed $rendererConfig OPTIONAL; an array or Zend_Config object with renderer parameters. + * @return Zend_Barcode_Renderer + */ + public static function makeRenderer($renderer = 'image', $rendererConfig = array()) + { + if ($renderer instanceof Zend_Barcode_Renderer_RendererAbstract) { + return $renderer; + } + + /* + * Convert Zend_Config argument to plain string + * barcode name and separate config object. + */ + if ($renderer instanceof Zend_Config) { + if (isset($renderer->rendererParams)) { + $rendererConfig = $renderer->rendererParams->toArray(); + } + if (isset($renderer->renderer)) { + $renderer = (string) $renderer->renderer; + } + } + if ($rendererConfig instanceof Zend_Config) { + $rendererConfig = $rendererConfig->toArray(); + } + + /* + * Verify that barcode parameters are in an array. + */ + if (!is_array($rendererConfig)) { + /** + * @see Zend_Barcode_Exception + */ + $e = new Zend_Barcode_Exception( + 'Barcode parameters must be in an array or a Zend_Config object' + ); + $e->setIsRenderable(false); + throw $e; + } + + /* + * Verify that an barcode name has been specified. + */ + if (!is_string($renderer) || empty($renderer)) { + /** + * @see Zend_Barcode_Exception + */ + $e = new Zend_Barcode_Exception( + 'Renderer name must be specified in a string' + ); + $e->setIsRenderable(false); + throw $e; + } + + /* + * Form full barcode class name + */ + $rendererNamespace = 'Zend_Barcode_Renderer'; + if (isset($rendererConfig['rendererNamespace'])) { + $rendererNamespace = $rendererConfig['rendererNamespace']; + } + + $rendererName = strtolower($rendererNamespace . '_' . $renderer); + $rendererName = str_replace(' ', '_', ucwords( + str_replace( '_', ' ', $rendererName) + )); + + /* + * Load the barcode class. This throws an exception + * if the specified class cannot be loaded. + */ + if (!class_exists($rendererName)) { + Zend_Loader::loadClass($rendererName); + } + + /* + * Create an instance of the barcode class. + * Pass the config to the barcode class constructor. + */ + $rdrAdapter = new $rendererName($rendererConfig); + + /* + * Verify that the object created is a descendent of the abstract barcode type. + */ + if (!$rdrAdapter instanceof Zend_Barcode_Renderer_RendererAbstract) { + /** + * @see Zend_Barcode_Exception + */ + $e = new Zend_Barcode_Exception( + "Renderer class '$rendererName' does not extend Zend_Barcode_Renderer_RendererAbstract" + ); + $e->setIsRenderable(false); + throw $e; + } + return $rdrAdapter; + } + + /** + * Proxy to renderer render() method + * + * @param string | Zend_Barcode_Object | array | Zend_Config $barcode + * @param string | Zend_Barcode_Renderer $renderer + * @param array | Zend_Config $barcodeConfig + * @param array | Zend_Config $rendererConfig + */ + public static function render( + $barcode, + $renderer, + $barcodeConfig = array(), + $rendererConfig = array() + ) { + self::factory($barcode, $renderer, $barcodeConfig, $rendererConfig)->render(); + } + + /** + * Proxy to renderer draw() method + * + * @param string | Zend_Barcode_Object | array | Zend_Config $barcode + * @param string | Zend_Barcode_Renderer $renderer + * @param array | Zend_Config $barcodeConfig + * @param array | Zend_Config $rendererConfig + * @return mixed + */ + public static function draw( + $barcode, + $renderer, + $barcodeConfig = array(), + $rendererConfig = array() + ) { + return self::factory($barcode, $renderer, $barcodeConfig, $rendererConfig)->draw(); + } + + /** + * Proxy for setBarcodeFont of Zend_Barcode_Object + * @param string $font + * @eturn void + */ + public static function setBarcodeFont($font) + { + Zend_Barcode_Object_ObjectAbstract::setBarcodeFont($font); + } +} diff --git a/library/vendor/Zend/Barcode/Exception.php b/library/vendor/Zend/Barcode/Exception.php new file mode 100644 index 000000000..e40b89290 --- /dev/null +++ b/library/vendor/Zend/Barcode/Exception.php @@ -0,0 +1,62 @@ +_isRenderable = (bool) $flag; + return $this; + } + + /** + * Retrieve renderable flag + * + * @return bool + */ + public function isRenderable() + { + return $this->_isRenderable; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Code128.php b/library/vendor/Zend/Barcode/Object/Code128.php new file mode 100644 index 000000000..ce2919354 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Code128.php @@ -0,0 +1,393 @@ + "11011001100", 1 => "11001101100", 2 => "11001100110", + 3 => "10010011000", 4 => "10010001100", 5 => "10001001100", + 6 => "10011001000", 7 => "10011000100", 8 => "10001100100", + 9 => "11001001000", 10 => "11001000100", 11 => "11000100100", + 12 => "10110011100", 13 => "10011011100", 14 => "10011001110", + 15 => "10111001100", 16 => "10011101100", 17 => "10011100110", + 18 => "11001110010", 19 => "11001011100", 20 => "11001001110", + 21 => "11011100100", 22 => "11001110100", 23 => "11101101110", + 24 => "11101001100", 25 => "11100101100", 26 => "11100100110", + 27 => "11101100100", 28 => "11100110100", 29 => "11100110010", + 30 => "11011011000", 31 => "11011000110", 32 => "11000110110", + 33 => "10100011000", 34 => "10001011000", 35 => "10001000110", + 36 => "10110001000", 37 => "10001101000", 38 => "10001100010", + 39 => "11010001000", 40 => "11000101000", 41 => "11000100010", + 42 => "10110111000", 43 => "10110001110", 44 => "10001101110", + 45 => "10111011000", 46 => "10111000110", 47 => "10001110110", + 48 => "11101110110", 49 => "11010001110", 50 => "11000101110", + 51 => "11011101000", 52 => "11011100010", 53 => "11011101110", + 54 => "11101011000", 55 => "11101000110", 56 => "11100010110", + 57 => "11101101000", 58 => "11101100010", 59 => "11100011010", + 60 => "11101111010", 61 => "11001000010", 62 => "11110001010", + 63 => "10100110000", 64 => "10100001100", 65 => "10010110000", + 66 => "10010000110", 67 => "10000101100", 68 => "10000100110", + 69 => "10110010000", 70 => "10110000100", 71 => "10011010000", + 72 => "10011000010", 73 => "10000110100", 74 => "10000110010", + 75 => "11000010010", 76 => "11001010000", 77 => "11110111010", + 78 => "11000010100", 79 => "10001111010", 80 => "10100111100", + 81 => "10010111100", 82 => "10010011110", 83 => "10111100100", + 84 => "10011110100", 85 => "10011110010", 86 => "11110100100", + 87 => "11110010100", 88 => "11110010010", 89 => "11011011110", + 90 => "11011110110", 91 => "11110110110", 92 => "10101111000", + 93 => "10100011110", 94 => "10001011110", 95 => "10111101000", + 96 => "10111100010", 97 => "11110101000", 98 => "11110100010", + 99 => "10111011110", 100 => "10111101110", 101 => "11101011110", + 102 => "11110101110", + 103 => "11010000100", 104 => "11010010000", 105 => "11010011100", + 106 => "1100011101011"); + + /** + * Character sets ABC + * @var array + */ + protected $_charSets = array( + 'A' => array( + ' ', '!', '"', '#', '$', '%', '&', "'", + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 'FNC3', 'FNC2', 'SHIFT', 'Code C', 'Code B', 'FNC4', 'FNC1', + 'START A', 'START B', 'START C', 'STOP'), + 'B' => array( + ' ', '!', '"', '#', '$', '%', '&', "'", + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', 0x7F, + 'FNC3', 'FNC2', 'SHIFT', 'Code C', 'FNC4', 'Code A', 'FNC1', + 'START A', 'START B', 'START C', 'STOP',), + 'C' => array( + '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', + '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', + '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', + '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', + '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', + '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', + '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', + '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', + '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', + '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', + 'Code B', 'Code A', 'FNC1', 'START A', 'START B', 'START C', 'STOP')); + /*'A' => array( + ' '=>0, '!'=>1, '"'=>2, '#'=>3, '$'=>4, '%'=>5, '&'=>6, "'"=>7, + '('=>8, ')'=>9, '*'=>10, '+'=>11, ','=>12, '-'=>13, '.'=>14, '/'=>15, + '0'=>16, '1'=>17, '2'=>18, '3'=>19, '4'=>20, '5'=>21, '6'=>22, '7'=>23, + '8'=>24, '9'=>25, ':'=>26, ';'=>27, '<'=>28, '='=>29, '>'=>30, '?'=>31, + '@'=>32, 'A'=>33, 'B'=>34, 'C'=>35, 'D'=>36, 'E'=>37, 'F'=>38, 'G'=>39, + 'H'=>40, 'I'=>41, 'J'=>42, 'K'=>43, 'L'=>44, 'M'=>45, 'N'=>46, 'O'=>47, + 'P'=>48, 'Q'=>49, 'R'=>50, 'S'=>51, 'T'=>52, 'U'=>53, 'V'=>54, 'W'=>55, + 'X'=>56, 'Y'=>57, 'Z'=>58, '['=>59, '\\'=>60, ']'=>61, '^'=>62, '_'=>63, + 0x00=>64, 0x01=>65, 0x02=>66, 0x03=>67, 0x04=>68, 0x05=>69, 0x06=>70, 0x07=>71, + 0x08=>72, 0x09=>73, 0x0A=>74, 0x0B=>75, 0x0C=>76, 0x0D=>77, 0x0E=>78, 0x0F=>79, + 0x10=>80, 0x11=>81, 0x12=>82, 0x13=>83, 0x14=>84, 0x15=>85, 0x16=>86, 0x17=>87, + 0x18=>88, 0x19=>89, 0x1A=>90, 0x1B=>91, 0x1C=>92, 0x1D=>93, 0x1E=>94, 0x1F=>95, + 'FNC3'=>96, 'FNC2'=>97, 'SHIFT'=>98, 'Code C'=>99, 'Code B'=>100, 'FNC4'=>101, 'FNC1'=>102, 'START A'=>103, + 'START B'=>104, 'START C'=>105, 'STOP'=>106), + 'B' => array( + ' '=>0, '!'=>1, '"'=>2, '#'=>3, '$'=>4, '%'=>5, '&'=>6, "'"=>7, + '('=>8, ')'=>9, '*'=>10, '+'=>11, ','=>12, '-'=>13, '.'=>14, '/'=>15, + '0'=>16, '1'=>17, '2'=>18, '3'=>19, '4'=>20, '5'=>21, '6'=>22, '7'=>23, + '8'=>24, '9'=>25, ':'=>26, ';'=>27, '<'=>28, '='=>29, '>'=>30, '?'=>31, + '@'=>32, 'A'=>33, 'B'=>34, 'C'=>35, 'D'=>36, 'E'=>37, 'F'=>38, 'G'=>39, + 'H'=>40, 'I'=>41, 'J'=>42, 'K'=>43, 'L'=>44, 'M'=>45, 'N'=>46, 'O'=>47, + 'P'=>48, 'Q'=>49, 'R'=>50, 'S'=>51, 'T'=>52, 'U'=>53, 'V'=>54, 'W'=>55, + 'X'=>56, 'Y'=>57, 'Z'=>58, '['=>59, '\\'=>60, ']'=>61, '^'=>62, '_'=>63, + '`' =>64, 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, + 'h'=>72, 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, + 'p'=>80, 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, + 'x'=>88, 'y'=>89, 'z'=>90, '{'=>91, '|'=>92, '}'=>93, '~'=>94, 0x7F=>95, + 'FNC3'=>96, 'FNC2'=>97, 'SHIFT'=>98, 'Code C'=>99, 'FNC4'=>100, 'Code A'=>101, 'FNC1'=>102, 'START A'=>103, + 'START B'=>104, 'START C'=>105, 'STOP'=>106,), + 'C' => array( + '00'=>0, '01'=>1, '02'=>2, '03'=>3, '04'=>4, '05'=>5, '06'=>6, '07'=>7, '08'=>8, '09'=>9, + '10'=>10, '11'=>11, '12'=>12, '13'=>13, '14'=>14, '15'=>15, '16'=>16, '17'=>17, '18'=>18, '19'=>19, + '20'=>20, '21'=>21, '22'=>22, '23'=>23, '24'=>24, '25'=>25, '26'=>26, '27'=>27, '28'=>28, '29'=>29, + '30'=>30, '31'=>31, '32'=>32, '33'=>33, '34'=>34, '35'=>35, '36'=>36, '37'=>37, '38'=>38, '39'=>39, + '40'=>40, '41'=>41, '42'=>42, '43'=>43, '44'=>44, '45'=>45, '46'=>46, '47'=>47, '48'=>48, '49'=>49, + '50'=>50, '51'=>51, '52'=>52, '53'=>53, '54'=>54, '55'=>55, '56'=>56, '57'=>57, '58'=>58, '59'=>59, + '60'=>60, '61'=>61, '62'=>62, '63'=>63, '64'=>64, '65'=>65, '66'=>66, '67'=>67, '68'=>68, '69'=>69, + '70'=>70, '71'=>71, '72'=>72, '73'=>73, '74'=>74, '75'=>75, '76'=>76, '77'=>77, '78'=>78, '79'=>79, + '80'=>80, '81'=>81, '82'=>82, '83'=>83, '84'=>84, '85'=>85, '86'=>86, '87'=>87, '88'=>88, '89'=>89, + '90'=>90, '91'=>91, '92'=>92, '93'=>93, '94'=>94, '95'=>95, '96'=>96, '97'=>97, '98'=>98, '99'=>99, + 'Code B'=>100, 'Code A'=>101, 'FNC1'=>102, 'START A'=>103, 'START B'=>104, 'START C'=>105, 'STOP'=>106));*/ + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + // Each characters contain 11 bars... + $characterLength = 11 * $this->_barThinWidth * $this->_factor; + $convertedChars = count($this->_convertToBarcodeChars($this->getText())); + if ($this->_withChecksum) { + $convertedChars++; + } + $encodedData = $convertedChars * $characterLength; + // ...except the STOP character (13) + $encodedData += $characterLength + 2 * $this->_barThinWidth * $this->_factor; + $width = $quietZone + $encodedData + $quietZone; + return $width; + } + + /** + * Partial check of code128 barcode + * @return void + */ + protected function _checkParams() + { + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + + $convertedChars = $this->_convertToBarcodeChars($this->getText()); + + if ($this->_withChecksum) { + $convertedChars[] = $this->getChecksum($this->getText()); + } + + // STOP CHARACTER + $convertedChars[] = 106; + + foreach ($convertedChars as $barcodeChar) { + $barcodePattern = $this->_codingMap[$barcodeChar]; + foreach (str_split($barcodePattern) as $c) { + $barcodeTable[] = array($c, $this->_barThinWidth, 0, 1); + } + } + return $barcodeTable; + } + + /** + * Checks if the next $length chars of $string starting at $pos are numeric. + * Returns false if the end of the string is reached. + * @param string $string String to search + * @param int $pos Starting position + * @param int $length Length to search + * @return bool + */ + protected static function _isDigit($string, $pos, $length = 2) + { + if ($pos + $length > strlen($string)) { + return false; + } + + for ($i = $pos; $i < $pos + $length; $i++) { + if (!is_numeric($string[$i])) { + return false; + } + } + return true; + } + + /** + * Convert string to barcode string + * + * @param $string + * @return array + */ + protected function _convertToBarcodeChars($string) + { + $string = (string) $string; + if (!strlen($string)) { + return array(); + } + + if (isset($this->_convertedText[md5($string)])) { + return $this->_convertedText[md5($string)]; + } + + $currentCharset = null; + $sum = 0; + $fak = 0; + $result = array(); + + for ($pos = 0; $pos < strlen($string); $pos++) { + $char = $string[$pos]; + $code = null; + + if (self::_isDigit($string, $pos, 4) && $currentCharset != 'C' + || self::_isDigit($string, $pos, 2) && $currentCharset == 'C') { + /** + * Switch to C if the next 4 chars are numeric or stay C if the next 2 + * chars are numeric + */ + if ($currentCharset != 'C') { + if ($pos == 0) { + $code = array_search("START C", $this->_charSets['C']); + } else { + $code = array_search("Code C", $this->_charSets[$currentCharset]); + } + $result[] = $code; + $currentCharset = 'C'; + } + } else if (in_array($char, $this->_charSets['B']) && $currentCharset != 'B' + && !(in_array($char, $this->_charSets['A']) && $currentCharset == 'A')) { + /** + * Switch to B as B contains the char and B is not the current charset. + */ + if ($pos == 0) { + $code = array_search("START B", $this->_charSets['B']); + } else { + $code = array_search("Code B", $this->_charSets[$currentCharset]); + } + $result[] = $code; + $currentCharset = 'B'; + } else if (array_key_exists($char, $this->_charSets['A']) && $currentCharset != 'A' + && !(array_key_exists($char, $this->_charSets['B']) && $currentCharset == 'B')) { + /** + * Switch to C as C contains the char and C is not the current charset. + */ + if ($pos == 0) { + $code = array_search("START A", $this->_charSets['A']); + } else { + $code =array_search("Code A", $this->_charSets[$currentCharset]); + } + $result[] = $code; + $currentCharset = 'A'; + } + + if ($currentCharset == 'C') { + $code = array_search(substr($string, $pos, 2), $this->_charSets['C']); + $pos++; //Two chars from input + } else { + $code = array_search($string[$pos], $this->_charSets[$currentCharset]); + } + $result[] = $code; + } + + $this->_convertedText[md5($string)] = $result; + return $result; + } + + /** + * Set text to encode + * @param string $value + * @return Zend_Barcode_Object + */ + public function setText($value) + { + $this->_text = $value; + return $this; + } + + /** + * Retrieve text to encode + * @return string + */ + public function getText() + { + return $this->_text; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $tableOfChars = $this->_convertToBarcodeChars($text); + + $sum = $tableOfChars[0]; + unset($tableOfChars[0]); + + $k = 1; + foreach ($tableOfChars as $char) { + $sum += ($k++) * $char; + } + + $checksum = $sum % 103; + + return $checksum; + } + + /** + * Standard validation for most of barcode objects + * + * @param string $value + * @param array $options + * @return bool + */ + protected function _validateText($value, $options = array()) + { + // @TODO: add code128 validator + return true; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Code25.php b/library/vendor/Zend/Barcode/Object/Code25.php new file mode 100644 index 000000000..3dfa1cb12 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Code25.php @@ -0,0 +1,141 @@ + '00110', + '1' => '10001', + '2' => '01001', + '3' => '11000', + '4' => '00101', + '5' => '10100', + '6' => '01100', + '7' => '00011', + '8' => '10010', + '9' => '01010', + ); + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (2 * $this->_barThickWidth + 4 * $this->_barThinWidth) * $this->_factor; + $characterLength = (3 * $this->_barThinWidth + 2 * $this->_barThickWidth + 5 * $this->_barThinWidth) + * $this->_factor; + $encodedData = strlen($this->getText()) * $characterLength; + $stopCharacter = (2 * $this->_barThickWidth + 4 * $this->_barThinWidth) * $this->_factor; + return $quietZone + $startCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Partial check of interleaved 2 of 5 barcode + * @return void + */ + protected function _checkParams() + { + $this->_checkRatio(); + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + + // Start character (30301) + $barcodeTable[] = array(1 , $this->_barThickWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThickWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth); + + $text = str_split($this->getText()); + foreach ($text as $char) { + $barcodeChar = str_split($this->_codingMap[$char]); + foreach ($barcodeChar as $c) { + /* visible, width, top, length */ + $width = $c ? $this->_barThickWidth : $this->_barThinWidth; + $barcodeTable[] = array(1 , $width , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth); + } + } + + // Stop character (30103) + $barcodeTable[] = array(1 , $this->_barThickWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThickWidth , 0 , 1); + return $barcodeTable; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $factor = 3; + $checksum = 0; + + for ($i = strlen($text); $i > 0; $i --) { + $checksum += intval($text{$i - 1}) * $factor; + $factor = 4 - $factor; + } + + $checksum = (10 - ($checksum % 10)) % 10; + + return $checksum; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Code25interleaved.php b/library/vendor/Zend/Barcode/Object/Code25interleaved.php new file mode 100644 index 000000000..67612fb50 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Code25interleaved.php @@ -0,0 +1,177 @@ +_barcodeLength = 'even'; + } + + /** + * Activate/deactivate drawing of bearer bars + * @param boolean $value + * @return Zend_Barcode_Object_Int25 + */ + public function setWithBearerBars($value) + { + $this->_withBearerBars = (bool) $value; + return $this; + } + + /** + * Retrieve if bearer bars are enabled + * @return boolean + */ + public function getWithBearerBars() + { + return $this->_withBearerBars; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (4 * $this->_barThinWidth) * $this->_factor; + $characterLength = (3 * $this->_barThinWidth + 2 * $this->_barThickWidth) * $this->_factor; + $encodedData = strlen($this->getText()) * $characterLength; + $stopCharacter = ($this->_barThickWidth + 2 * $this->_barThinWidth) * $this->_factor; + return $quietZone + $startCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + if ($this->_withBearerBars) { + $this->_withBorder = false; + } + + // Start character (0000) + $barcodeTable[] = array(1, $this->_barThinWidth, 0, 1); + $barcodeTable[] = array(0, $this->_barThinWidth, 0, 1); + $barcodeTable[] = array(1, $this->_barThinWidth, 0, 1); + $barcodeTable[] = array(0, $this->_barThinWidth, 0, 1); + + // Encoded $text + $text = $this->getText(); + for ($i = 0; $i < strlen($text); $i += 2) { // Draw 2 chars at a time + $char1 = substr($text, $i, 1); + $char2 = substr($text, $i + 1, 1); + + // Interleave + for ($ibar = 0; $ibar < 5; $ibar ++) { + // Draws char1 bar (fore color) + $barWidth = (substr($this->_codingMap[$char1], $ibar, 1)) + ? $this->_barThickWidth + : $this->_barThinWidth; + + $barcodeTable[] = array(1, $barWidth, 0, 1); + + // Left space corresponding to char2 (background color) + $barWidth = (substr($this->_codingMap[$char2], $ibar, 1)) + ? $this->_barThickWidth + : $this->_barThinWidth; + $barcodeTable[] = array(0, $barWidth, 0 , 1); + } + } + + // Stop character (100) + $barcodeTable[] = array(1 , $this->_barThickWidth, 0, 1); + $barcodeTable[] = array(0 , $this->_barThinWidth, 0, 1); + $barcodeTable[] = array(1 , $this->_barThinWidth, 0, 1); + return $barcodeTable; + } + + /** + * Drawing of bearer bars (if enabled) + * + * @return void + */ + protected function _postDrawBarcode() + { + if (!$this->_withBearerBars) { + return; + } + + $width = $this->_barThickWidth * $this->_factor; + $point1 = $this->_rotate(-1, -1); + $point2 = $this->_rotate($this->_calculateWidth() - 1, -1); + $point3 = $this->_rotate($this->_calculateWidth() - 1, $width - 1); + $point4 = $this->_rotate(-1, $width - 1); + $this->_addPolygon(array( + $point1, + $point2, + $point3, + $point4, + )); + $point1 = $this->_rotate( + 0, + 0 + $this->_barHeight * $this->_factor - 1 + ); + $point2 = $this->_rotate( + $this->_calculateWidth() - 1, + 0 + $this->_barHeight * $this->_factor - 1 + ); + $point3 = $this->_rotate( + $this->_calculateWidth() - 1, + 0 + $this->_barHeight * $this->_factor - $width + ); + $point4 = $this->_rotate( + 0, + 0 + $this->_barHeight * $this->_factor - $width + ); + $this->_addPolygon(array( + $point1, + $point2, + $point3, + $point4, + )); + } +} diff --git a/library/vendor/Zend/Barcode/Object/Code39.php b/library/vendor/Zend/Barcode/Object/Code39.php new file mode 100644 index 000000000..46441243d --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Code39.php @@ -0,0 +1,186 @@ + '000110100', + '1' => '100100001', + '2' => '001100001', + '3' => '101100000', + '4' => '000110001', + '5' => '100110000', + '6' => '001110000', + '7' => '000100101', + '8' => '100100100', + '9' => '001100100', + 'A' => '100001001', + 'B' => '001001001', + 'C' => '101001000', + 'D' => '000011001', + 'E' => '100011000', + 'F' => '001011000', + 'G' => '000001101', + 'H' => '100001100', + 'I' => '001001100', + 'J' => '000011100', + 'K' => '100000011', + 'L' => '001000011', + 'M' => '101000010', + 'N' => '000010011', + 'O' => '100010010', + 'P' => '001010010', + 'Q' => '000000111', + 'R' => '100000110', + 'S' => '001000110', + 'T' => '000010110', + 'U' => '110000001', + 'V' => '011000001', + 'W' => '111000000', + 'X' => '010010001', + 'Y' => '110010000', + 'Z' => '011010000', + '-' => '010000101', + '.' => '110000100', + ' ' => '011000100', + '$' => '010101000', + '/' => '010100010', + '+' => '010001010', + '%' => '000101010', + '*' => '010010100', + ); + + /** + * Partial check of Code39 barcode + * @return void + */ + protected function _checkParams() + { + $this->_checkRatio(); + } + + /** + * Width of the barcode (in pixels) + * @return int + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $characterLength = (6 * $this->_barThinWidth + 3 * $this->_barThickWidth + 1) * $this->_factor; + $encodedData = strlen($this->getText()) * $characterLength - $this->_factor; + return $quietZone + $encodedData + $quietZone; + } + + /** + * Set text to encode + * @param string $value + * @return Zend_Barcode_Object + */ + public function setText($value) + { + $this->_text = $value; + return $this; + } + + /** + * Retrieve text to display + * @return string + */ + public function getText() + { + return '*' . parent::getText() . '*'; + } + + /** + * Retrieve text to display + * @return string + */ + public function getTextToDisplay() + { + $text = parent::getTextToDisplay(); + if (substr($text, 0, 1) != '*' && substr($text, -1) != '*') { + return '*' . $text . '*'; + } else { + return $text; + } + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $text = str_split($this->getText()); + $barcodeTable = array(); + foreach ($text as $char) { + $barcodeChar = str_split($this->_codingMap[$char]); + $visible = true; + foreach ($barcodeChar as $c) { + /* visible, width, top, length */ + $width = $c ? $this->_barThickWidth : $this->_barThinWidth; + $barcodeTable[] = array((int) $visible, $width, 0, 1); + $visible = ! $visible; + } + $barcodeTable[] = array(0 , $this->_barThinWidth); + } + return $barcodeTable; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $text = str_split($text); + $charset = array_flip(array_keys($this->_codingMap)); + $checksum = 0; + foreach ($text as $character) { + $checksum += $charset[$character]; + } + return array_search(($checksum % 43), $charset); + } +} diff --git a/library/vendor/Zend/Barcode/Object/Ean13.php b/library/vendor/Zend/Barcode/Object/Ean13.php new file mode 100644 index 000000000..968d7b293 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Ean13.php @@ -0,0 +1,223 @@ + array( + 0 => "0001101", 1 => "0011001", 2 => "0010011", 3 => "0111101", 4 => "0100011", + 5 => "0110001", 6 => "0101111", 7 => "0111011", 8 => "0110111", 9 => "0001011" + ), + 'B' => array( + 0 => "0100111", 1 => "0110011", 2 => "0011011", 3 => "0100001", 4 => "0011101", + 5 => "0111001", 6 => "0000101", 7 => "0010001", 8 => "0001001", 9 => "0010111" + ), + 'C' => array( + 0 => "1110010", 1 => "1100110", 2 => "1101100", 3 => "1000010", 4 => "1011100", + 5 => "1001110", 6 => "1010000", 7 => "1000100", 8 => "1001000", 9 => "1110100" + )); + + protected $_parities = array( + 0 => array('A','A','A','A','A','A'), + 1 => array('A','A','B','A','B','B'), + 2 => array('A','A','B','B','A','B'), + 3 => array('A','A','B','B','B','A'), + 4 => array('A','B','A','A','B','B'), + 5 => array('A','B','B','A','A','B'), + 6 => array('A','B','B','B','A','A'), + 7 => array('A','B','A','B','A','B'), + 8 => array('A','B','A','B','B','A'), + 9 => array('A','B','B','A','B','A') + ); + + /** + * Default options for Postnet barcode + * @return void + */ + protected function _getDefaultOptions() + { + $this->_barcodeLength = 13; + $this->_mandatoryChecksum = true; + $this->_mandatoryQuietZones = true; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $middleCharacter = (5 * $this->_barThinWidth) * $this->_factor; + $stopCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $encodedData = (7 * $this->_barThinWidth) * $this->_factor * 12; + return $quietZone + $startCharacter + $middleCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Partial check of interleaved EAN/UPC barcode + * @return void + */ + protected function _checkParams() + {} + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + $height = ($this->_drawText) ? 1.1 : 1; + + // Start character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + + $textTable = str_split($this->getText()); + $parity = $this->_parities[$textTable[0]]; + + // First part + for ($i = 1; $i < 7; $i++) { + $bars = str_split($this->_codingMap[$parity[$i - 1]][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Middle character (01010) + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + + // Second part + for ($i = 7; $i < 13; $i++) { + $bars = str_split($this->_codingMap['C'][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Stop character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + return $barcodeTable; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $factor = 3; + $checksum = 0; + + for ($i = strlen($text); $i > 0; $i --) { + $checksum += intval($text{$i - 1}) * $factor; + $factor = 4 - $factor; + } + + $checksum = (10 - ($checksum % 10)) % 10; + + return $checksum; + } + + /** + * Partial function to draw text + * @return void + */ + protected function _drawText() + { + if (get_class($this) == 'Zend_Barcode_Object_Ean13') { + $this->_drawEan13Text(); + } else { + parent::_drawText(); + } + } + + protected function _drawEan13Text() + { + if ($this->_drawText) { + $text = $this->getTextToDisplay(); + $characterWidth = (7 * $this->_barThinWidth) * $this->_factor; + $leftPosition = $this->getQuietZone() - $characterWidth; + for ($i = 0; $i < $this->_barcodeLength; $i ++) { + $this->_addText( + $text{$i}, + $this->_fontSize * $this->_factor, + $this->_rotate( + $leftPosition, + (int) $this->_withBorder * 2 + + $this->_factor * ($this->_barHeight + $this->_fontSize) + 1 + ), + $this->_font, + $this->_foreColor, + 'left', + - $this->_orientation + ); + switch ($i) { + case 0: + $factor = 3; + break; + case 6: + $factor = 4; + break; + default: + $factor = 0; + } + $leftPosition = $leftPosition + $characterWidth + ($factor * $this->_barThinWidth * $this->_factor); + } + } + } +} diff --git a/library/vendor/Zend/Barcode/Object/Ean2.php b/library/vendor/Zend/Barcode/Object/Ean2.php new file mode 100644 index 000000000..8868b0190 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Ean2.php @@ -0,0 +1,63 @@ + array('A','A'), + 1 => array('A','B'), + 2 => array('B','A'), + 3 => array('B','B') + ); + + /** + * Default options for Ean2 barcode + * @return void + */ + protected function _getDefaultOptions() + { + $this->_barcodeLength = 2; + } + + protected function _getParity($i) + { + $modulo = $this->getText() % 4; + return $this->_parities[$modulo][$i]; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Ean5.php b/library/vendor/Zend/Barcode/Object/Ean5.php new file mode 100644 index 000000000..7b50c7302 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Ean5.php @@ -0,0 +1,145 @@ + array('B','B','A','A','A'), + 1 => array('B','A','B','A','A'), + 2 => array('B','A','A','B','A'), + 3 => array('B','A','A','A','B'), + 4 => array('A','B','B','A','A'), + 5 => array('A','A','B','B','A'), + 6 => array('A','A','A','B','B'), + 7 => array('A','B','A','B','A'), + 8 => array('A','B','A','A','B'), + 9 => array('A','A','B','A','B') + ); + + /** + * Default options for Ean5 barcode + * @return void + */ + protected function _getDefaultOptions() + { + $this->_barcodeLength = 5; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (5 * $this->_barThinWidth) * $this->_factor; + $middleCharacter = (2 * $this->_barThinWidth) * $this->_factor; + $encodedData = (7 * $this->_barThinWidth) * $this->_factor; + return $quietZone + $startCharacter + ($this->_barcodeLength - 1) * $middleCharacter + $this->_barcodeLength * $encodedData + $quietZone; + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + + // Start character (01011) + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + + $firstCharacter = true; + $textTable = str_split($this->getText()); + + // Characters + for ($i = 0; $i < $this->_barcodeLength; $i++) { + if ($firstCharacter) { + $firstCharacter = false; + } else { + // Intermediate character (01) + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + } + $bars = str_split($this->_codingMap[$this->_getParity($i)][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + return $barcodeTable; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $checksum = 0; + + for ($i = 0 ; $i < $this->_barcodeLength; $i ++) { + $checksum += intval($text{$i}) * ($i % 2 ? 9 : 3); + } + + return ($checksum % 10); + } + + protected function _getParity($i) + { + $checksum = $this->getChecksum($this->getText()); + return $this->_parities[$checksum][$i]; + } + + /** + * Retrieve text to encode + * @return string + */ + public function getText() + { + return $this->_addLeadingZeros($this->_text); + } +} diff --git a/library/vendor/Zend/Barcode/Object/Ean8.php b/library/vendor/Zend/Barcode/Object/Ean8.php new file mode 100644 index 000000000..4cb18fbac --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Ean8.php @@ -0,0 +1,174 @@ +_barcodeLength = 8; + $this->_mandatoryChecksum = true; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $middleCharacter = (5 * $this->_barThinWidth) * $this->_factor; + $stopCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $encodedData = (7 * $this->_barThinWidth) * $this->_factor * 8; + return $quietZone + $startCharacter + $middleCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + $height = ($this->_drawText) ? 1.1 : 1; + + // Start character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + + $textTable = str_split($this->getText()); + + // First part + for ($i = 0; $i < 4; $i++) { + $bars = str_split($this->_codingMap['A'][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Middle character (01010) + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + + // Second part + for ($i = 4; $i < 8; $i++) { + $bars = str_split($this->_codingMap['C'][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Stop character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + return $barcodeTable; + } + + /** + * Partial function to draw text + * @return void + */ + protected function _drawText() + { + if ($this->_drawText) { + $text = $this->getTextToDisplay(); + $characterWidth = (7 * $this->_barThinWidth) * $this->_factor; + $leftPosition = $this->getQuietZone() + (3 * $this->_barThinWidth) * $this->_factor; + for ($i = 0; $i < $this->_barcodeLength; $i ++) { + $this->_addText( + $text{$i}, + $this->_fontSize * $this->_factor, + $this->_rotate( + $leftPosition, + (int) $this->_withBorder * 2 + + $this->_factor * ($this->_barHeight + $this->_fontSize) + 1 + ), + $this->_font, + $this->_foreColor, + 'left', + - $this->_orientation + ); + switch ($i) { + case 3: + $factor = 4; + break; + default: + $factor = 0; + } + $leftPosition = $leftPosition + $characterWidth + ($factor * $this->_barThinWidth * $this->_factor); + } + } + } + + /** + * Particular validation for Ean8 barcode objects + * (to suppress checksum character substitution) + * + * @param string $value + * @param array $options + * @throws Zend_Barcode_Object_Exception + */ + protected function _validateText($value, $options = array()) + { + $validator = new Zend_Validate_Barcode(array( + 'adapter' => 'ean8', + 'checksum' => false, + )); + + $value = $this->_addLeadingZeros($value, true); + + if (!$validator->isValid($value)) { + $message = implode("\n", $validator->getMessages()); + + /** + * @see Zend_Barcode_Object_Exception + */ + throw new Zend_Barcode_Object_Exception($message); + } + } +} diff --git a/library/vendor/Zend/Barcode/Object/Error.php b/library/vendor/Zend/Barcode/Object/Error.php new file mode 100644 index 000000000..ff84afd7a --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Error.php @@ -0,0 +1,103 @@ +_instructions = array(); + $this->_addText('ERROR:', 10, array(5 , 18), $this->_font, 0, 'left'); + $this->_addText($this->_text, 10, array(5 , 32), $this->_font, 0, 'left'); + return $this->_instructions; + } + + /** + * For compatibility reason + * @return void + */ + protected function _prepareBarcode() + { + } + + /** + * For compatibility reason + * @return void + */ + protected function _checkParams() + { + } + + /** + * For compatibility reason + * @return void + */ + protected function _calculateBarcodeWidth() + { + } +} diff --git a/library/vendor/Zend/Barcode/Object/Exception.php b/library/vendor/Zend/Barcode/Object/Exception.php new file mode 100644 index 000000000..363335d9f --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Exception.php @@ -0,0 +1,34 @@ +_barcodeLength = 12; + $this->_mandatoryChecksum = true; + } + + /** + * Retrieve text to display + * @return string + */ + public function getTextToDisplay() + { + return preg_replace('/([0-9]{2})([0-9]{3})([0-9]{3})([0-9]{3})([0-9])/', + '$1.$2 $3.$4 $5', + $this->getText()); + } + + /** + * Check allowed characters + * @param string $value + * @return string + * @throws Zend_Barcode_Object_Exception + */ + public function validateText($value) + { + $this->_validateText($value, array('validator' => $this->getType())); + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $checksum = 0; + + for ($i = strlen($text); $i > 0; $i --) { + $checksum += intval($text{$i - 1}) * (($i % 2) ? 4 : 9); + } + + $checksum = (10 - ($checksum % 10)) % 10; + + return $checksum; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Itf14.php b/library/vendor/Zend/Barcode/Object/Itf14.php new file mode 100644 index 000000000..2c80340f0 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Itf14.php @@ -0,0 +1,47 @@ +_barcodeLength = 14; + $this->_mandatoryChecksum = true; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Leitcode.php b/library/vendor/Zend/Barcode/Object/Leitcode.php new file mode 100644 index 000000000..cf0473a26 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Leitcode.php @@ -0,0 +1,62 @@ +_barcodeLength = 14; + $this->_mandatoryChecksum = true; + } + + /** + * Retrieve text to display + * @return string + */ + public function getTextToDisplay() + { + return preg_replace('/([0-9]{5})([0-9]{3})([0-9]{3})([0-9]{2})([0-9])/', + '$1.$2.$3.$4 $5', + $this->getText()); + } +} diff --git a/library/vendor/Zend/Barcode/Object/ObjectAbstract.php b/library/vendor/Zend/Barcode/Object/ObjectAbstract.php new file mode 100644 index 000000000..f22e31ec9 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/ObjectAbstract.php @@ -0,0 +1,1327 @@ +_getDefaultOptions(); + if (self::$_staticFont !== null) { + $this->_font = self::$_staticFont; + } + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + if (is_array($options)) { + $this->setOptions($options); + } + $this->_type = strtolower(substr(get_class($this), strlen($this->_barcodeNamespace) + 1)); + if ($this->_mandatoryChecksum) { + $this->_withChecksum = true; + $this->_withChecksumInText = true; + } + } + + /** + * Set default options for particular object + * @return void + */ + protected function _getDefaultOptions() + { + } + + /** + * Set barcode state from options array + * @param array $options + * @return Zend_Barcode_Object + */ + public function setOptions($options) + { + foreach ($options as $key => $value) { + $method = 'set' . $key; + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set barcode state from config object + * @param Zend_Config $config + * @return Zend_Barcode_Object + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config->toArray()); + } + + /** + * Set barcode namespace for autoloading + * + * @param string $namespace + * @return Zend_Barcode_Object + */ + public function setBarcodeNamespace($namespace) + { + $this->_barcodeNamespace = $namespace; + return $this; + } + + /** + * Retrieve barcode namespace + * + * @return string + */ + public function getBarcodeNamespace() + { + return $this->_barcodeNamespace; + } + + /** + * Retrieve type of barcode + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Set height of the barcode bar + * @param integer $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setBarHeight($value) + { + if (intval($value) <= 0) { + throw new Zend_Barcode_Object_Exception( + 'Bar height must be greater than 0' + ); + } + $this->_barHeight = intval($value); + return $this; + } + + /** + * Get height of the barcode bar + * @return integer + */ + public function getBarHeight() + { + return $this->_barHeight; + } + + /** + * Set thickness of thin bar + * @param integer $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setBarThinWidth($value) + { + if (intval($value) <= 0) { + throw new Zend_Barcode_Object_Exception( + 'Bar width must be greater than 0' + ); + } + $this->_barThinWidth = intval($value); + return $this; + } + + /** + * Get thickness of thin bar + * @return integer + */ + public function getBarThinWidth() + { + return $this->_barThinWidth; + } + + /** + * Set thickness of thick bar + * @param integer $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setBarThickWidth($value) + { + if (intval($value) <= 0) { + throw new Zend_Barcode_Object_Exception( + 'Bar width must be greater than 0' + ); + } + $this->_barThickWidth = intval($value); + return $this; + } + + /** + * Get thickness of thick bar + * @return integer + */ + public function getBarThickWidth() + { + return $this->_barThickWidth; + } + + /** + * Set factor applying to + * thinBarWidth - thickBarWidth - barHeight - fontSize + * @param float $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setFactor($value) + { + if (floatval($value) <= 0) { + throw new Zend_Barcode_Object_Exception( + 'Factor must be greater than 0' + ); + } + $this->_factor = floatval($value); + return $this; + } + + /** + * Get factor applying to + * thinBarWidth - thickBarWidth - barHeight - fontSize + * @return integer + */ + public function getFactor() + { + return $this->_factor; + } + + /** + * Set color of the barcode and text + * @param string $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setForeColor($value) + { + if (preg_match('`\#[0-9A-F]{6}`', $value)) { + $this->_foreColor = hexdec($value); + } elseif (is_numeric($value) && $value >= 0 && $value <= 16777125) { + $this->_foreColor = intval($value); + } else { + throw new Zend_Barcode_Object_Exception( + 'Text color must be set as #[0-9A-F]{6}' + ); + } + return $this; + } + + /** + * Retrieve color of the barcode and text + * @return unknown + */ + public function getForeColor() + { + return $this->_foreColor; + } + + /** + * Set the color of the background + * @param integer $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setBackgroundColor($value) + { + if (preg_match('`\#[0-9A-F]{6}`', $value)) { + $this->_backgroundColor = hexdec($value); + } elseif (is_numeric($value) && $value >= 0 && $value <= 16777125) { + $this->_backgroundColor = intval($value); + } else { + throw new Zend_Barcode_Object_Exception( + 'Background color must be set as #[0-9A-F]{6}' + ); + } + return $this; + } + + /** + * Retrieve background color of the image + * @return integer + */ + public function getBackgroundColor() + { + return $this->_backgroundColor; + } + + /** + * Activate/deactivate drawing of the bar + * @param boolean $value + * @return Zend_Barcode_Object + */ + public function setWithBorder($value) + { + $this->_withBorder = (bool) $value; + return $this; + } + + /** + * Retrieve if border are draw or not + * @return boolean + */ + public function getWithBorder() + { + return $this->_withBorder; + } + + /** + * Activate/deactivate drawing of the quiet zones + * @param boolean $value + * @return Zend_Barcode_Object + */ + public function setWithQuietZones($value) + { + $this->_withQuietZones = (bool) $value; + return $this; + } + + /** + * Retrieve if quiet zones are draw or not + * @return boolean + */ + public function getWithQuietZones() + { + return $this->_withQuietZones; + } + + /** + * Allow fast inversion of font/bars color and background color + * @return Zend_Barcode_Object + */ + public function setReverseColor() + { + $tmp = $this->_foreColor; + $this->_foreColor = $this->_backgroundColor; + $this->_backgroundColor = $tmp; + return $this; + } + + /** + * Set orientation of barcode and text + * @param float $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setOrientation($value) + { + $this->_orientation = floatval($value) - floor(floatval($value) / 360) * 360; + return $this; + } + + /** + * Retrieve orientation of barcode and text + * @return float + */ + public function getOrientation() + { + return $this->_orientation; + } + + /** + * Set text to encode + * @param string $value + * @return Zend_Barcode_Object + */ + public function setText($value) + { + $this->_text = trim($value); + return $this; + } + + /** + * Retrieve text to encode + * @return string + */ + public function getText() + { + $text = $this->_text; + if ($this->_withChecksum) { + $text .= $this->getChecksum($this->_text); + } + return $this->_addLeadingZeros($text); + } + + /** + * Automatically add leading zeros if barcode length is fixed + * + * @param string $text + * @param boolean $withoutChecksum + * @return string + */ + protected function _addLeadingZeros($text, $withoutChecksum = false) + { + if ($this->_barcodeLength && $this->_addLeadingZeros) { + $omitChecksum = (int) ($this->_withChecksum && $withoutChecksum); + if (is_int($this->_barcodeLength)) { + $length = $this->_barcodeLength - $omitChecksum; + if (strlen($text) < $length) { + $text = str_repeat('0', $length - strlen($text)) . $text; + } + } else { + if ($this->_barcodeLength == 'even') { + $text = ((strlen($text) - $omitChecksum) % 2 ? '0' . $text : $text); + } + } + } + return $text; + } + + /** + * Retrieve text to encode + * @return string + */ + public function getRawText() + { + return $this->_text; + } + + /** + * Retrieve text to display + * @return string + */ + public function getTextToDisplay() + { + if ($this->_withChecksumInText) { + return $this->getText(); + } else { + return $this->_addLeadingZeros($this->_text, true); + } + } + + /** + * Activate/deactivate drawing of text to encode + * @param boolean $value + * @return Zend_Barcode_Object + */ + public function setDrawText($value) + { + $this->_drawText = (bool) $value; + return $this; + } + + /** + * Retrieve if drawing of text to encode is enabled + * @return boolean + */ + public function getDrawText() + { + return $this->_drawText; + } + + /** + * Activate/deactivate the adjustment of the position + * of the characters to the position of the bars + * @param boolean $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setStretchText($value) + { + $this->_stretchText = (bool) $value; + return $this; + } + + /** + * Retrieve if the adjustment of the position of the characters + * to the position of the bars is enabled + * @return boolean + */ + public function getStretchText() + { + return $this->_stretchText; + } + + /** + * Activate/deactivate the automatic generation + * of the checksum character + * added to the barcode text + * @param boolean $value + * @return Zend_Barcode_Object + */ + public function setWithChecksum($value) + { + if (!$this->_mandatoryChecksum) { + $this->_withChecksum = (bool) $value; + } + return $this; + } + + /** + * Retrieve if the checksum character is automatically + * added to the barcode text + * @return boolean + */ + public function getWithChecksum() + { + return $this->_withChecksum; + } + + /** + * Activate/deactivate the automatic generation + * of the checksum character + * added to the barcode text + * @param boolean $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setWithChecksumInText($value) + { + if (!$this->_mandatoryChecksum) { + $this->_withChecksumInText = (bool) $value; + } + return $this; + } + + /** + * Retrieve if the checksum character is automatically + * added to the barcode text + * @return boolean + */ + public function getWithChecksumInText() + { + return $this->_withChecksumInText; + } + + /** + * Set the font for all instances of barcode + * @param string $font + * @return void + */ + public static function setBarcodeFont($font) + { + if (is_string($font) || (is_int($font) && $font >= 1 && $font <= 5)) { + self::$_staticFont = $font; + } + } + + /** + * Set the font: + * - if integer between 1 and 5, use gd built-in fonts + * - if string, $value is assumed to be the path to a TTF font + * @param integer|string $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setFont($value) + { + if (is_int($value) && $value >= 1 && $value <= 5) { + if (!extension_loaded('gd')) { + throw new Zend_Barcode_Object_Exception( + 'GD extension is required to use numeric font' + ); + } + + // Case of numeric font with GD + $this->_font = $value; + + // In this case font size is given by: + $this->_fontSize = imagefontheight($value); + } elseif (is_string($value)) { + $this->_font = $value; + } else { + throw new Zend_Barcode_Object_Exception(sprintf( + 'Invalid font "%s" provided to setFont()', + $value + )); + } + return $this; + } + + /** + * Retrieve the font + * @return integer|string + */ + public function getFont() + { + return $this->_font; + } + + /** + * Set the size of the font in case of TTF + * @param float $value + * @return Zend_Barcode_Object + * @throws Zend_Barcode_Object_Exception + */ + public function setFontSize($value) + { + if (is_numeric($this->_font)) { + // Case of numeric font with GD + return $this; + } + + if (!is_numeric($value)) { + throw new Zend_Barcode_Object_Exception( + 'Font size must be a numeric value' + ); + } + + $this->_fontSize = $value; + return $this; + } + + /** + * Retrieve the size of the font in case of TTF + * @return float + */ + public function getFontSize() + { + return $this->_fontSize; + } + + /** + * Quiet zone before first bar + * and after the last bar + * @return integer + */ + public function getQuietZone() + { + if ($this->_withQuietZones || $this->_mandatoryQuietZones) { + return 10 * $this->_barThinWidth * $this->_factor; + } else { + return 0; + } + } + + /** + * Add an instruction in the array of instructions + * @param array $instruction + */ + protected function _addInstruction(array $instruction) + { + $this->_instructions[] = $instruction; + } + + /** + * Retrieve the set of drawing instructions + * @return array + */ + public function getInstructions() + { + return $this->_instructions; + } + + /** + * Add a polygon drawing instruction in the set of instructions + * @param array $points + * @param integer $color + * @param boolean $filled + */ + protected function _addPolygon(array $points, $color = null, $filled = true) + { + if ($color === null) { + $color = $this->_foreColor; + } + $this->_addInstruction(array( + 'type' => 'polygon', + 'points' => $points, + 'color' => $color, + 'filled' => $filled, + )); + } + + /** + * Add a text drawing instruction in the set of instructions + * + * @param string $text + * @param float $size + * @param array $position + * @param string $font + * @param integer $color + * @param string $alignment + * @param float|int $orientation + */ + protected function _addText( + $text, + $size, + $position, + $font, + $color, + $alignment = 'center', + $orientation = 0 + ) { + if ($color === null) { + $color = $this->_foreColor; + } + $this->_addInstruction(array( + 'type' => 'text', + 'text' => $text, + 'size' => $size, + 'position' => $position, + 'font' => $font, + 'color' => $color, + 'alignment' => $alignment, + 'orientation' => $orientation, + )); + } + + /** + * Checking of parameters after all settings + * + * @return bool + */ + public function checkParams() + { + $this->_checkText(); + $this->_checkFontAndOrientation(); + $this->_checkParams(); + return true; + } + + /** + * Check if a text is really provided to barcode + * + * @param string|null $value + * @return void + * @throws Zend_Barcode_Object_Exception + */ + protected function _checkText($value = null) + { + if ($value === null) { + $value = $this->_text; + } + if (!strlen($value)) { + throw new Zend_Barcode_Object_Exception( + 'A text must be provide to Barcode before drawing' + ); + } + $this->validateText($value); + } + + /** + * Check the ratio between the thick and the thin bar + * + * @param int $min + * @param int $max + * @return void + * @throws Zend_Barcode_Object_Exception + */ + protected function _checkRatio($min = 2, $max = 3) + { + $ratio = $this->_barThickWidth / $this->_barThinWidth; + if (!($ratio >= $min && $ratio <= $max)) { + throw new Zend_Barcode_Object_Exception(sprintf( + 'Ratio thick/thin bar must be between %0.1f and %0.1f (actual %0.3f)', + $min, + $max, + $ratio + )); + } + } + + /** + * Drawing with an angle is just allow TTF font + * + * @return void + * @throws Zend_Barcode_Object_Exception + */ + protected function _checkFontAndOrientation() + { + if (is_numeric($this->_font) && $this->_orientation != 0) { + throw new Zend_Barcode_Object_Exception( + 'Only drawing with TTF font allow orientation of the barcode.' + ); + } + } + + /** + * Width of the result image (before any rotation) + * + * @return integer + */ + protected function _calculateWidth() + { + return (int) $this->_withBorder + + $this->_calculateBarcodeWidth() + + (int) $this->_withBorder; + } + + /** + * Calculate the width of the barcode + * + * @return integer + */ + abstract protected function _calculateBarcodeWidth(); + + /** + * Height of the result object + * + * @return int + */ + protected function _calculateHeight() + { + return (int) $this->_withBorder * 2 + + $this->_calculateBarcodeHeight() + + (int) $this->_withBorder * 2; + } + + /** + * Height of the barcode + * + * @return int + */ + protected function _calculateBarcodeHeight() + { + $textHeight = 0; + $extraHeight = 0; + if ($this->_drawText) { + $textHeight += $this->_fontSize; + $extraHeight = 2; + } + return ($this->_barHeight + $textHeight) * $this->_factor + $extraHeight; + } + + /** + * Get height of the result object + * + * @param bool $recalculate + * @return int + */ + public function getHeight($recalculate = false) + { + if ($this->_height === null || $recalculate) { + $this->_height = + abs($this->_calculateHeight() * cos($this->_orientation / 180 * pi())) + + abs($this->_calculateWidth() * sin($this->_orientation / 180 * pi())); + } + return $this->_height; + } + + /** + * Get width of the result object + * + * @param bool $recalculate + * @return int + */ + public function getWidth($recalculate = false) + { + if ($this->_width === null || $recalculate) { + $this->_width = + abs($this->_calculateWidth() * cos($this->_orientation / 180 * pi())) + + abs($this->_calculateHeight() * sin($this->_orientation / 180 * pi())); + } + return $this->_width; + } + + /** + * Calculate the offset from the left of the object + * if an orientation is activated + * + * @param bool $recalculate + * @return float + */ + public function getOffsetLeft($recalculate = false) + { + if ($this->_offsetLeft === null || $recalculate) { + $this->_offsetLeft = - min(array( + 0 * cos( + $this->_orientation / 180 * pi()) - 0 * sin( + $this->_orientation / 180 * pi()), + 0 * cos( + $this->_orientation / 180 * pi()) - $this->_calculateBarcodeHeight() * sin( + $this->_orientation / 180 * pi()), + $this->_calculateBarcodeWidth() * cos( + $this->_orientation / 180 * pi()) - $this->_calculateBarcodeHeight() * sin( + $this->_orientation / 180 * pi()), + $this->_calculateBarcodeWidth() * cos( + $this->_orientation / 180 * pi()) - 0 * sin( + $this->_orientation / 180 * pi()), + )); + } + return $this->_offsetLeft; + } + + /** + * Calculate the offset from the top of the object + * if an orientation is activated + * + * @param bool $recalculate + * @return float + */ + public function getOffsetTop($recalculate = false) + { + if ($this->_offsetTop === null || $recalculate) { + $this->_offsetTop = - min(array( + 0 * cos( + $this->_orientation / 180 * pi()) + 0 * sin( + $this->_orientation / 180 * pi()), + $this->_calculateBarcodeHeight() * cos( + $this->_orientation / 180 * pi()) + 0 * sin( + $this->_orientation / 180 * pi()), + $this->_calculateBarcodeHeight() * cos( + $this->_orientation / 180 * pi()) + $this->_calculateBarcodeWidth() * sin( + $this->_orientation / 180 * pi()), + 0 * cos( + $this->_orientation / 180 * pi()) + $this->_calculateBarcodeWidth() * sin( + $this->_orientation / 180 * pi()), + )); + } + return $this->_offsetTop; + } + + /** + * Apply rotation on a point in X/Y dimensions + * + * @param float $x1 x-position before rotation + * @param float $y1 y-position before rotation + * @return array Array of two elements corresponding to the new XY point + */ + protected function _rotate($x1, $y1) + { + $x2 = $x1 * cos($this->_orientation / 180 * pi()) + - $y1 * sin($this->_orientation / 180 * pi()) + + $this->getOffsetLeft(); + $y2 = $y1 * cos($this->_orientation / 180 * pi()) + + $x1 * sin($this->_orientation / 180 * pi()) + + $this->getOffsetTop(); + return array(intval($x2) , intval($y2)); + } + + /** + * Complete drawing of the barcode + * + * @return array Table of instructions + */ + public function draw() + { + $this->checkParams(); + $this->_drawBarcode(); + $this->_drawBorder(); + $this->_drawText(); + return $this->getInstructions(); + } + + /** + * Draw the barcode + * + * @return void + */ + protected function _drawBarcode() + { + $barcodeTable = $this->_prepareBarcode(); + + $this->_preDrawBarcode(); + + $xpos = (int) $this->_withBorder; + $ypos = (int) $this->_withBorder; + + $point1 = $this->_rotate(0, 0); + $point2 = $this->_rotate(0, $this->_calculateHeight() - 1); + $point3 = $this->_rotate( + $this->_calculateWidth() - 1, + $this->_calculateHeight() - 1 + ); + $point4 = $this->_rotate($this->_calculateWidth() - 1, 0); + + $this->_addPolygon(array( + $point1, + $point2, + $point3, + $point4 + ), $this->_backgroundColor); + + $xpos += $this->getQuietZone(); + $barLength = $this->_barHeight * $this->_factor; + + foreach ($barcodeTable as $bar) { + $width = $bar[1] * $this->_factor; + if ($bar[0]) { + $point1 = $this->_rotate($xpos, $ypos + $bar[2] * $barLength); + $point2 = $this->_rotate($xpos, $ypos + $bar[3] * $barLength); + $point3 = $this->_rotate( + $xpos + $width - 1, + $ypos + $bar[3] * $barLength + ); + $point4 = $this->_rotate( + $xpos + $width - 1, + $ypos + $bar[2] * $barLength + ); + $this->_addPolygon(array( + $point1, + $point2, + $point3, + $point4, + )); + } + $xpos += $width; + } + + $this->_postDrawBarcode(); + } + + /** + * Partial function to draw border + * + * @return void + */ + protected function _drawBorder() + { + if ($this->_withBorder) { + $point1 = $this->_rotate(0, 0); + $point2 = $this->_rotate($this->_calculateWidth() - 1, 0); + $point3 = $this->_rotate( + $this->_calculateWidth() - 1, + $this->_calculateHeight() - 1 + ); + $point4 = $this->_rotate(0, $this->_calculateHeight() - 1); + $this->_addPolygon(array( + $point1, + $point2, + $point3, + $point4, + $point1, + ), $this->_foreColor, false); + } + } + + /** + * Partial function to draw text + * @return void + */ + protected function _drawText() + { + if ($this->_drawText) { + $text = $this->getTextToDisplay(); + if ($this->_stretchText) { + $textLength = strlen($text); + $space = ($this->_calculateWidth() - 2 * $this->getQuietZone()) / $textLength; + for ($i = 0; $i < $textLength; $i ++) { + $leftPosition = $this->getQuietZone() + $space * ($i + 0.5); + $this->_addText( + $text{$i}, + $this->_fontSize * $this->_factor, + $this->_rotate( + $leftPosition, + (int) $this->_withBorder * 2 + + $this->_factor * ($this->_barHeight + $this->_fontSize) + 1 + ), + $this->_font, + $this->_foreColor, + 'center', + - $this->_orientation + ); + } + } else { + $this->_addText( + $text, + $this->_fontSize * $this->_factor, + $this->_rotate( + $this->_calculateWidth() / 2, + (int) $this->_withBorder * 2 + + $this->_factor * ($this->_barHeight + $this->_fontSize) + 1 + ), + $this->_font, + $this->_foreColor, + 'center', + - $this->_orientation + ); + } + } + } + + /** + * Check for invalid characters + * @param string $value Text to be ckecked + * @return void + */ + public function validateText($value) + { + $this->_validateText($value); + } + + /** + * Standard validation for most of barcode objects + * + * @param string $value + * @param array $options + * @throws Zend_Barcode_Object_Exception + */ + protected function _validateText($value, $options = array()) + { + $validatorName = (isset($options['validator'])) ? $options['validator'] : $this->getType(); + + $validator = new Zend_Validate_Barcode(array( + 'adapter' => $validatorName, + 'checksum' => false, + )); + + $checksumCharacter = ''; + $withChecksum = false; + if ($this->_mandatoryChecksum) { + $checksumCharacter = $this->_substituteChecksumCharacter; + $withChecksum = true; + } + + $value = $this->_addLeadingZeros($value, $withChecksum) . $checksumCharacter; + + if (!$validator->isValid($value)) { + $message = implode("\n", $validator->getMessages()); + + /** + * @see Zend_Barcode_Object_Exception + */ + throw new Zend_Barcode_Object_Exception($message); + } + } + + /** + * Each child must prepare the barcode and return + * a table like array( + * 0 => array( + * 0 => int (visible(black) or not(white)) + * 1 => int (width of the bar) + * 2 => float (0->1 position from the top of the beginning of the bar in %) + * 3 => float (0->1 position from the top of the end of the bar in %) + * ), + * 1 => ... + * ) + * + * @return array + */ + abstract protected function _prepareBarcode(); + + /** + * Checking of parameters after all settings + * + * @return void + */ + abstract protected function _checkParams(); + + /** + * Allow each child to draw something else + * + * @return void + */ + protected function _preDrawBarcode() + { + } + + /** + * Allow each child to draw something else + * (ex: bearer bars in interleaved 2 of 5 code) + * + * @return void + */ + protected function _postDrawBarcode() + { + } +} diff --git a/library/vendor/Zend/Barcode/Object/Planet.php b/library/vendor/Zend/Barcode/Object/Planet.php new file mode 100644 index 000000000..262e6fbe7 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Planet.php @@ -0,0 +1,60 @@ + "00111", + 1 => "11100", + 2 => "11010", + 3 => "11001", + 4 => "10110", + 5 => "10101", + 6 => "10011", + 7 => "01110", + 8 => "01101", + 9 => "01011" + ); +} diff --git a/library/vendor/Zend/Barcode/Object/Postnet.php b/library/vendor/Zend/Barcode/Object/Postnet.php new file mode 100644 index 000000000..ec7910b91 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Postnet.php @@ -0,0 +1,134 @@ + "11000", + 1 => "00011", + 2 => "00101", + 3 => "00110", + 4 => "01001", + 5 => "01010", + 6 => "01100", + 7 => "10001", + 8 => "10010", + 9 => "10100" + ); + + /** + * Default options for Postnet barcode + * @return void + */ + protected function _getDefaultOptions() + { + $this->_barThinWidth = 2; + $this->_barHeight = 20; + $this->_drawText = false; + $this->_stretchText = true; + $this->_mandatoryChecksum = true; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (2 * $this->_barThinWidth) * $this->_factor; + $stopCharacter = (1 * $this->_barThinWidth) * $this->_factor; + $encodedData = (10 * $this->_barThinWidth) * $this->_factor * strlen($this->getText()); + return $quietZone + $startCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Partial check of interleaved Postnet barcode + * @return void + */ + protected function _checkParams() + {} + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + + // Start character (1) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + + // Text to encode + $textTable = str_split($this->getText()); + foreach ($textTable as $char) { + $bars = str_split($this->_codingMap[$char]); + foreach ($bars as $b) { + $barcodeTable[] = array(1 , $this->_barThinWidth , 0.5 - $b * 0.5 , 1); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + } + } + + // Stop character (1) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + return $barcodeTable; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $sum = array_sum(str_split($text)); + $checksum = (10 - ($sum % 10)) % 10; + return $checksum; + } +} diff --git a/library/vendor/Zend/Barcode/Object/Royalmail.php b/library/vendor/Zend/Barcode/Object/Royalmail.php new file mode 100644 index 000000000..14db43744 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Royalmail.php @@ -0,0 +1,161 @@ + '3300', '1' => '3210', '2' => '3201', '3' => '2310', '4' => '2301', '5' => '2211', + '6' => '3120', '7' => '3030', '8' => '3021', '9' => '2130', 'A' => '2121', 'B' => '2031', + 'C' => '3102', 'D' => '3012', 'E' => '3003', 'F' => '2112', 'G' => '2103', 'H' => '2013', + 'I' => '1320', 'J' => '1230', 'K' => '1221', 'L' => '0330', 'M' => '0321', 'N' => '0231', + 'O' => '1302', 'P' => '1212', 'Q' => '1203', 'R' => '0312', 'S' => '0303', 'T' => '0213', + 'U' => '1122', 'V' => '1032', 'W' => '1023', 'X' => '0132', 'Y' => '0123', 'Z' => '0033' + ); + + protected $_rows = array( + '0' => 1, '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1, + '6' => 2, '7' => 2, '8' => 2, '9' => 2, 'A' => 2, 'B' => 2, + 'C' => 3, 'D' => 3, 'E' => 3, 'F' => 3, 'G' => 3, 'H' => 3, + 'I' => 4, 'J' => 4, 'K' => 4, 'L' => 4, 'M' => 4, 'N' => 4, + 'O' => 5, 'P' => 5, 'Q' => 5, 'R' => 5, 'S' => 5, 'T' => 5, + 'U' => 0, 'V' => 0, 'W' => 0, 'X' => 0, 'Y' => 0, 'Z' => 0, + ); + + protected $_columns = array( + '0' => 1, '1' => 2, '2' => 3, '3' => 4, '4' => 5, '5' => 0, + '6' => 1, '7' => 2, '8' => 3, '9' => 4, 'A' => 5, 'B' => 0, + 'C' => 1, 'D' => 2, 'E' => 3, 'F' => 4, 'G' => 5, 'H' => 0, + 'I' => 1, 'J' => 2, 'K' => 3, 'L' => 4, 'M' => 5, 'N' => 0, + 'O' => 1, 'P' => 2, 'Q' => 3, 'R' => 4, 'S' => 5, 'T' => 0, + 'U' => 1, 'V' => 2, 'W' => 3, 'X' => 4, 'Y' => 5, 'Z' => 0, + ); + + /** + * Default options for Postnet barcode + * @return void + */ + protected function _getDefaultOptions() + { + $this->_barThinWidth = 2; + $this->_barHeight = 20; + $this->_drawText = false; + $this->_stretchText = true; + $this->_mandatoryChecksum = true; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (2 * $this->_barThinWidth) * $this->_factor; + $stopCharacter = (1 * $this->_barThinWidth) * $this->_factor; + $encodedData = (8 * $this->_barThinWidth) * $this->_factor * strlen($this->getText()); + return $quietZone + $startCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Partial check of interleaved Postnet barcode + * @return void + */ + protected function _checkParams() + {} + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + + // Start character (1) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 5/8); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + + // Text to encode + $textTable = str_split($this->getText()); + foreach ($textTable as $char) { + $bars = str_split($this->_codingMap[$char]); + foreach ($bars as $b) { + $barcodeTable[] = array(1 , $this->_barThinWidth , ($b > 1 ? 3/8 : 0) , ($b % 2 ? 5/8 : 1)); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , 1); + } + } + + // Stop character (1) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , 1); + return $barcodeTable; + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $this->_checkText($text); + $values = str_split($text); + $rowvalue = 0; + $colvalue = 0; + foreach($values as $row) { + $rowvalue += $this->_rows[$row]; + $colvalue += $this->_columns[$row]; + } + + $rowvalue %= 6; + $colvalue %= 6; + + $rowchkvalue = array_keys($this->_rows, $rowvalue); + $colchkvalue = array_keys($this->_columns, $colvalue); + return current(array_intersect($rowchkvalue, $colchkvalue)); + } +} diff --git a/library/vendor/Zend/Barcode/Object/Upca.php b/library/vendor/Zend/Barcode/Object/Upca.php new file mode 100644 index 000000000..4fbf5c6ad --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Upca.php @@ -0,0 +1,170 @@ +_barcodeLength = 12; + $this->_mandatoryChecksum = true; + $this->_mandatoryQuietZones = true; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $middleCharacter = (5 * $this->_barThinWidth) * $this->_factor; + $stopCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $encodedData = (7 * $this->_barThinWidth) * $this->_factor * 12; + return $quietZone + $startCharacter + $middleCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + $height = ($this->_drawText) ? 1.1 : 1; + + // Start character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + + $textTable = str_split($this->getText()); + + // First character + $bars = str_split($this->_codingMap['A'][$textTable[0]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , $height); + } + + // First part + for ($i = 1; $i < 6; $i++) { + $bars = str_split($this->_codingMap['A'][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Middle character (01010) + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + + // Second part + for ($i = 6; $i < 11; $i++) { + $bars = str_split($this->_codingMap['C'][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Last character + $bars = str_split($this->_codingMap['C'][$textTable[11]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , $height); + } + + // Stop character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + return $barcodeTable; + } + + /** + * Partial function to draw text + * @return void + */ + protected function _drawText() + { + if ($this->_drawText) { + $text = $this->getTextToDisplay(); + $characterWidth = (7 * $this->_barThinWidth) * $this->_factor; + $leftPosition = $this->getQuietZone() - $characterWidth; + for ($i = 0; $i < $this->_barcodeLength; $i ++) { + $fontSize = $this->_fontSize; + if ($i == 0 || $i == 11) { + $fontSize *= 0.8; + } + $this->_addText( + $text{$i}, + $fontSize * $this->_factor, + $this->_rotate( + $leftPosition, + (int) $this->_withBorder * 2 + + $this->_factor * ($this->_barHeight + $fontSize) + 1 + ), + $this->_font, + $this->_foreColor, + 'left', + - $this->_orientation + ); + switch ($i) { + case 0: + $factor = 10; + break; + case 5: + $factor = 4; + break; + case 10: + $factor = 11; + break; + default: + $factor = 0; + } + $leftPosition = $leftPosition + $characterWidth + ($factor * $this->_barThinWidth * $this->_factor); + } + } + } +} diff --git a/library/vendor/Zend/Barcode/Object/Upce.php b/library/vendor/Zend/Barcode/Object/Upce.php new file mode 100644 index 000000000..eafbb3d29 --- /dev/null +++ b/library/vendor/Zend/Barcode/Object/Upce.php @@ -0,0 +1,227 @@ + array( + 0 => array('B','B','B','A','A','A'), + 1 => array('B','B','A','B','A','A'), + 2 => array('B','B','A','A','B','A'), + 3 => array('B','B','A','A','A','B'), + 4 => array('B','A','B','B','A','A'), + 5 => array('B','A','A','B','B','A'), + 6 => array('B','A','A','A','B','B'), + 7 => array('B','A','B','A','B','A'), + 8 => array('B','A','B','A','A','B'), + 9 => array('B','A','A','B','A','B')), + 1 => array( + 0 => array('A','A','A','B','B','B'), + 1 => array('A','A','B','A','B','B'), + 2 => array('A','A','B','B','A','B'), + 3 => array('A','A','B','B','B','A'), + 4 => array('A','B','A','A','B','B'), + 5 => array('A','B','B','A','A','B'), + 6 => array('A','B','B','B','A','A'), + 7 => array('A','B','A','B','A','B'), + 8 => array('A','B','A','B','B','A'), + 9 => array('A','B','B','A','B','A')) + ); + + /** + * Default options for Postnet barcode + * @return void + */ + protected function _getDefaultOptions() + { + $this->_barcodeLength = 8; + $this->_mandatoryChecksum = true; + $this->_mandatoryQuietZones = true; + } + + /** + * Retrieve text to encode + * @return string + */ + public function getText() + { + $text = parent::getText(); + if ($text{0} != 1) { + $text{0} = 0; + } + return $text; + } + + /** + * Width of the barcode (in pixels) + * @return integer + */ + protected function _calculateBarcodeWidth() + { + $quietZone = $this->getQuietZone(); + $startCharacter = (3 * $this->_barThinWidth) * $this->_factor; + $stopCharacter = (6 * $this->_barThinWidth) * $this->_factor; + $encodedData = (7 * $this->_barThinWidth) * $this->_factor * 6; + return $quietZone + $startCharacter + $encodedData + $stopCharacter + $quietZone; + } + + /** + * Prepare array to draw barcode + * @return array + */ + protected function _prepareBarcode() + { + $barcodeTable = array(); + $height = ($this->_drawText) ? 1.1 : 1; + + // Start character (101) + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + + $textTable = str_split($this->getText()); + $system = 0; + if ($textTable[0] == 1) { + $system = 1; + } + $checksum = $textTable[7]; + $parity = $this->_parities[$system][$checksum]; + + for ($i = 1; $i < 7; $i++) { + $bars = str_split($this->_codingMap[$parity[$i - 1]][$textTable[$i]]); + foreach ($bars as $b) { + $barcodeTable[] = array($b , $this->_barThinWidth , 0 , 1); + } + } + + // Stop character (10101) + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(0 , $this->_barThinWidth , 0 , $height); + $barcodeTable[] = array(1 , $this->_barThinWidth , 0 , $height); + return $barcodeTable; + } + + /** + * Partial function to draw text + * @return void + */ + protected function _drawText() + { + if ($this->_drawText) { + $text = $this->getTextToDisplay(); + $characterWidth = (7 * $this->_barThinWidth) * $this->_factor; + $leftPosition = $this->getQuietZone() - $characterWidth; + for ($i = 0; $i < $this->_barcodeLength; $i ++) { + $fontSize = $this->_fontSize; + if ($i == 0 || $i == 7) { + $fontSize *= 0.8; + } + $this->_addText( + $text{$i}, + $fontSize * $this->_factor, + $this->_rotate( + $leftPosition, + (int) $this->_withBorder * 2 + + $this->_factor * ($this->_barHeight + $fontSize) + 1 + ), + $this->_font, + $this->_foreColor, + 'left', + - $this->_orientation + ); + switch ($i) { + case 0: + $factor = 3; + break; + case 6: + $factor = 5; + break; + default: + $factor = 0; + } + $leftPosition = $leftPosition + $characterWidth + ($factor * $this->_barThinWidth * $this->_factor); + } + } + } + + /** + * Particular validation for Upce barcode objects + * (to suppress checksum character substitution) + * + * @param string $value + * @param array $options + * @throws Zend_Barcode_Object_Exception + */ + protected function _validateText($value, $options = array()) + { + $validator = new Zend_Validate_Barcode(array( + 'adapter' => 'upce', + 'checksum' => false, + )); + + $value = $this->_addLeadingZeros($value, true); + + if (!$validator->isValid($value)) { + $message = implode("\n", $validator->getMessages()); + + /** + * @see Zend_Barcode_Object_Exception + */ + throw new Zend_Barcode_Object_Exception($message); + } + } + + /** + * Get barcode checksum + * + * @param string $text + * @return int + */ + public function getChecksum($text) + { + $text = $this->_addLeadingZeros($text, true); + if ($text{0} != 1) { + $text{0} = 0; + } + return parent::getChecksum($text); + } +} diff --git a/library/vendor/Zend/Barcode/Renderer/Exception.php b/library/vendor/Zend/Barcode/Renderer/Exception.php new file mode 100644 index 000000000..6d3dd762c --- /dev/null +++ b/library/vendor/Zend/Barcode/Renderer/Exception.php @@ -0,0 +1,34 @@ +_userHeight = intval($value); + return $this; + } + + /** + * Get barcode height + * + * @return int + */ + public function getHeight() + { + return $this->_userHeight; + } + + /** + * Set barcode width + * + * @param mixed $value + * @return self + * @throws Zend_Barcode_Renderer_Exception + */ + public function setWidth($value) + { + if (!is_numeric($value) || intval($value) < 0) { + throw new Zend_Barcode_Renderer_Exception( + 'Image width must be greater than or equals 0' + ); + } + $this->_userWidth = intval($value); + return $this; + } + + /** + * Get barcode width + * + * @return int + */ + public function getWidth() + { + return $this->_userWidth; + } + + /** + * Set an image resource to draw the barcode inside + * + * @param $image + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setResource($image) + { + if (gettype($image) != 'resource' || get_resource_type($image) != 'gd') { + throw new Zend_Barcode_Renderer_Exception( + 'Invalid image resource provided to setResource()' + ); + } + $this->_resource = $image; + return $this; + } + + /** + * Set the image type to produce (png, jpeg, gif) + * + * @param string $value + * @return Zend_Barcode_RendererAbstract + * @throws Zend_Barcode_Renderer_Exception + */ + public function setImageType($value) + { + if ($value == 'jpg') { + $value = 'jpeg'; + } + + if (!in_array($value, $this->_allowedImageType)) { + throw new Zend_Barcode_Renderer_Exception(sprintf( + 'Invalid type "%s" provided to setImageType()', + $value + )); + } + + $this->_imageType = $value; + return $this; + } + + /** + * Retrieve the image type to produce + * + * @return string + */ + public function getImageType() + { + return $this->_imageType; + } + + /** + * Initialize the image resource + * + * @return void + * @throws Zend_Barcode_Exception + */ + protected function _initRenderer() + { + if (!extension_loaded('gd')) { + $e = new Zend_Barcode_Exception( + 'Gd extension must be loaded to render barcode as image' + ); + $e->setIsRenderable(false); + throw $e; + } + + $barcodeWidth = $this->_barcode->getWidth(true); + $barcodeHeight = $this->_barcode->getHeight(true); + + if ($this->_resource !== null) { + $foreColor = $this->_barcode->getForeColor(); + $backgroundColor = $this->_barcode->getBackgroundColor(); + $this->_imageBackgroundColor = imagecolorallocate( + $this->_resource, + ($backgroundColor & 0xFF0000) >> 16, + ($backgroundColor & 0x00FF00) >> 8, + $backgroundColor & 0x0000FF + ); + $this->_imageForeColor = imagecolorallocate( + $this->_resource, + ($foreColor & 0xFF0000) >> 16, + ($foreColor & 0x00FF00) >> 8, + $foreColor & 0x0000FF + ); + } else { + $width = $barcodeWidth; + $height = $barcodeHeight; + if ($this->_userWidth && $this->_barcode->getType() != 'error') { + $width = $this->_userWidth; + } + if ($this->_userHeight && $this->_barcode->getType() != 'error') { + $height = $this->_userHeight; + } + + $foreColor = $this->_barcode->getForeColor(); + $backgroundColor = $this->_barcode->getBackgroundColor(); + $this->_resource = imagecreatetruecolor($width, $height); + + $this->_imageBackgroundColor = imagecolorallocate( + $this->_resource, + ($backgroundColor & 0xFF0000) >> 16, + ($backgroundColor & 0x00FF00) >> 8, + $backgroundColor & 0x0000FF + ); + $this->_imageForeColor = imagecolorallocate( + $this->_resource, + ($foreColor & 0xFF0000) >> 16, + ($foreColor & 0x00FF00) >> 8, + $foreColor & 0x0000FF + ); + $white = imagecolorallocate($this->_resource, 255, 255, 255); + imagefilledrectangle($this->_resource, 0, 0, $width - 1, $height - 1, $white); + } + $this->_adjustPosition(imagesy($this->_resource), imagesx($this->_resource)); + imagefilledrectangle( + $this->_resource, + $this->_leftOffset, + $this->_topOffset, + $this->_leftOffset + $barcodeWidth - 1, + $this->_topOffset + $barcodeHeight - 1, + $this->_imageBackgroundColor + ); + } + + /** + * Check barcode parameters + * + * @return void + */ + protected function _checkParams() + { + $this->_checkDimensions(); + } + + /** + * Check barcode dimensions + * + * @return void + * @throws Zend_Barcode_Renderer_Exception + */ + protected function _checkDimensions() + { + if ($this->_resource !== null) { + if (imagesy($this->_resource) < $this->_barcode->getHeight(true)) { + throw new Zend_Barcode_Renderer_Exception( + 'Barcode is define outside the image (height)' + ); + } + } else { + if ($this->_userHeight) { + $height = $this->_barcode->getHeight(true); + if ($this->_userHeight < $height) { + throw new Zend_Barcode_Renderer_Exception(sprintf( + "Barcode is define outside the image (calculated: '%d', provided: '%d')", + $height, + $this->_userHeight + )); + } + } + } + if ($this->_resource !== null) { + if (imagesx($this->_resource) < $this->_barcode->getWidth(true)) { + throw new Zend_Barcode_Renderer_Exception( + 'Barcode is define outside the image (width)' + ); + } + } else { + if ($this->_userWidth) { + $width = $this->_barcode->getWidth(true); + if ($this->_userWidth < $width) { + throw new Zend_Barcode_Renderer_Exception(sprintf( + "Barcode is define outside the image (calculated: '%d', provided: '%d')", + $width, + $this->_userWidth + )); + } + } + } + } + + /** + * Draw and render the barcode with correct headers + * + * @return mixed + */ + public function render() + { + $this->draw(); + header("Content-Type: image/" . $this->_imageType); + $functionName = 'image' . $this->_imageType; + call_user_func($functionName, $this->_resource); + @imagedestroy($this->_resource); + } + + /** + * Draw a polygon in the image resource + * + * @param array $points + * @param integer $color + * @param boolean $filled + */ + protected function _drawPolygon($points, $color, $filled = true) + { + $newPoints = array( + $points[0][0] + $this->_leftOffset, + $points[0][1] + $this->_topOffset, + $points[1][0] + $this->_leftOffset, + $points[1][1] + $this->_topOffset, + $points[2][0] + $this->_leftOffset, + $points[2][1] + $this->_topOffset, + $points[3][0] + $this->_leftOffset, + $points[3][1] + $this->_topOffset, + ); + + $allocatedColor = imagecolorallocate( + $this->_resource, + ($color & 0xFF0000) >> 16, + ($color & 0x00FF00) >> 8, + $color & 0x0000FF + ); + + if ($filled) { + imagefilledpolygon($this->_resource, $newPoints, 4, $allocatedColor); + } else { + imagepolygon($this->_resource, $newPoints, 4, $allocatedColor); + } + } + + /** + * Draw a polygon in the image resource + * + * @param string $text + * @param float $size + * @param array $position + * @param string $font + * @param integer $color + * @param string $alignment + * @param float|int $orientation + * @throws Zend_Barcode_Renderer_Exception + */ + protected function _drawText($text, $size, $position, $font, $color, $alignment = 'center', $orientation = 0) + { + $allocatedColor = imagecolorallocate( + $this->_resource, + ($color & 0xFF0000) >> 16, + ($color & 0x00FF00) >> 8, + $color & 0x0000FF + ); + + if ($font == null) { + $font = 3; + } + $position[0] += $this->_leftOffset; + $position[1] += $this->_topOffset; + + if (is_numeric($font)) { + if ($orientation) { + /** + * imagestring() doesn't allow orientation, if orientation + * needed: a TTF font is required. + * Throwing an exception here, allow to use automaticRenderError + * to informe user of the problem instead of simply not drawing + * the text + */ + throw new Zend_Barcode_Renderer_Exception( + 'No orientation possible with GD internal font' + ); + } + $fontWidth = imagefontwidth($font); + $positionY = $position[1] - imagefontheight($font) + 1; + switch ($alignment) { + case 'left': + $positionX = $position[0]; + break; + case 'center': + $positionX = $position[0] - ceil(($fontWidth * strlen($text)) / 2); + break; + case 'right': + $positionX = $position[0] - ($fontWidth * strlen($text)); + break; + } + imagestring($this->_resource, $font, $positionX, $positionY, $text, $color); + } else { + + if (!function_exists('imagettfbbox')) { + throw new Zend_Barcode_Renderer_Exception( + 'A font was provided, but this instance of PHP does not have TTF (FreeType) support' + ); + } + + $box = imagettfbbox($size, 0, $font, $text); + switch ($alignment) { + case 'left': + $width = 0; + break; + case 'center': + $width = ($box[2] - $box[0]) / 2; + break; + case 'right': + $width = ($box[2] - $box[0]); + break; + } + imagettftext( + $this->_resource, + $size, + $orientation, + $position[0] - ($width * cos(pi() * $orientation / 180)), + $position[1] + ($width * sin(pi() * $orientation / 180)), + $allocatedColor, + $font, + $text + ); + } + } +} diff --git a/library/vendor/Zend/Barcode/Renderer/Pdf.php b/library/vendor/Zend/Barcode/Renderer/Pdf.php new file mode 100644 index 000000000..fc49793db --- /dev/null +++ b/library/vendor/Zend/Barcode/Renderer/Pdf.php @@ -0,0 +1,240 @@ +_resource = $pdf; + $this->_page = intval($page); + + if (!count($this->_resource->pages)) { + $this->_page = 0; + $this->_resource->pages[] = new Zend_Pdf_Page( + Zend_Pdf_Page::SIZE_A4 + ); + } + return $this; + } + + /** + * Check renderer parameters + * + * @return void + */ + protected function _checkParams() + { + } + + /** + * Draw the barcode in the PDF, send headers and the PDF + * @return mixed + */ + public function render() + { + $this->draw(); + header("Content-Type: application/pdf"); + echo $this->_resource->render(); + } + + /** + * Initialize the PDF resource + * @return void + */ + protected function _initRenderer() + { + if ($this->_resource === null) { + $this->_resource = new Zend_Pdf(); + $this->_resource->pages[] = new Zend_Pdf_Page( + Zend_Pdf_Page::SIZE_A4 + ); + } + + $pdfPage = $this->_resource->pages[$this->_page]; + $this->_adjustPosition($pdfPage->getHeight(), $pdfPage->getWidth()); + } + + /** + * Draw a polygon in the rendering resource + * @param array $points + * @param integer $color + * @param boolean $filled + */ + protected function _drawPolygon($points, $color, $filled = true) + { + $page = $this->_resource->pages[$this->_page]; + foreach ($points as $point) { + $x[] = $point[0] * $this->_moduleSize + $this->_leftOffset; + $y[] = $page->getHeight() - $point[1] * $this->_moduleSize - $this->_topOffset; + } + if (count($y) == 4) { + if ($x[0] != $x[3] && $y[0] == $y[3]) { + $y[0] -= ($this->_moduleSize / 2); + $y[3] -= ($this->_moduleSize / 2); + } + if ($x[1] != $x[2] && $y[1] == $y[2]) { + $y[1] += ($this->_moduleSize / 2); + $y[2] += ($this->_moduleSize / 2); + } + } + + $color = new Zend_Pdf_Color_Rgb( + (($color & 0xFF0000) >> 16) / 255.0, + (($color & 0x00FF00) >> 8) / 255.0, + ($color & 0x0000FF) / 255.0 + ); + + $page->setLineColor($color); + $page->setFillColor($color); + $page->setLineWidth($this->_moduleSize); + + $fillType = ($filled) + ? Zend_Pdf_Page::SHAPE_DRAW_FILL_AND_STROKE + : Zend_Pdf_Page::SHAPE_DRAW_STROKE; + + $page->drawPolygon($x, $y, $fillType); + } + + /** + * Draw a text in the rendering resource + * + * @param string $text + * @param float $size + * @param array $position + * @param string $font + * @param integer $color + * @param string $alignment + * @param float|int $orientation + */ + protected function _drawText( + $text, + $size, + $position, + $font, + $color, + $alignment = 'center', + $orientation = 0 + ) { + $page = $this->_resource->pages[$this->_page]; + $color = new Zend_Pdf_Color_Rgb( + (($color & 0xFF0000) >> 16) / 255.0, + (($color & 0x00FF00) >> 8) / 255.0, + ($color & 0x0000FF) / 255.0 + ); + + $page->setLineColor($color); + $page->setFillColor($color); + $page->setFont(Zend_Pdf_Font::fontWithPath($font), $size * $this->_moduleSize * 1.2); + + $width = $this->widthForStringUsingFontSize( + $text, + Zend_Pdf_Font::fontWithPath($font), + $size * $this->_moduleSize + ); + + $angle = pi() * $orientation / 180; + $left = $position[0] * $this->_moduleSize + $this->_leftOffset; + $top = $page->getHeight() - $position[1] * $this->_moduleSize - $this->_topOffset; + + switch ($alignment) { + case 'center': + $left -= ($width / 2) * cos($angle); + $top -= ($width / 2) * sin($angle); + break; + case 'right': + $left -= $width; + break; + } + $page->rotate($left, $top, $angle); + $page->drawText($text, $left, $top); + $page->rotate($left, $top, - $angle); + } + + /** + * Calculate the width of a string: + * in case of using alignment parameter in drawText + * @param string $text + * @param Zend_Pdf_Font $font + * @param float $fontSize + * @return float + */ + public function widthForStringUsingFontSize($text, $font, $fontSize) + { + $drawingString = iconv('UTF-8', 'UTF-16BE//IGNORE', $text); + $characters = array(); + for ($i = 0; $i < strlen($drawingString); $i ++) { + $characters[] = (ord($drawingString[$i ++]) << 8) | ord($drawingString[$i]); + } + $glyphs = $font->glyphNumbersForCharacters($characters); + $widths = $font->widthsForGlyphs($glyphs); + $stringWidth = (array_sum($widths) / $font->getUnitsPerEm()) * $fontSize; + return $stringWidth; + } +} diff --git a/library/vendor/Zend/Barcode/Renderer/RendererAbstract.php b/library/vendor/Zend/Barcode/Renderer/RendererAbstract.php new file mode 100644 index 000000000..3d06645e9 --- /dev/null +++ b/library/vendor/Zend/Barcode/Renderer/RendererAbstract.php @@ -0,0 +1,543 @@ +toArray(); + } + if (is_array($options)) { + $this->setOptions($options); + } + $this->_type = strtolower(substr( + get_class($this), + strlen($this->_rendererNamespace) + 1 + )); + } + + /** + * Set renderer state from options array + * @param array $options + * @return Zend_Renderer_Object + */ + public function setOptions($options) + { + foreach ($options as $key => $value) { + $method = 'set' . $key; + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set renderer state from config object + * @param Zend_Config $config + * @return Zend_Renderer_Object + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config->toArray()); + } + + /** + * Set renderer namespace for autoloading + * + * @param string $namespace + * @return Zend_Renderer_Object + */ + public function setRendererNamespace($namespace) + { + $this->_rendererNamespace = $namespace; + return $this; + } + + /** + * Retrieve renderer namespace + * + * @return string + */ + public function getRendererNamespace() + { + return $this->_rendererNamespace; + } + + /** + * Retrieve renderer type + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Manually adjust top position + * @param integer $value + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setTopOffset($value) + { + if (!is_numeric($value) || intval($value) < 0) { + throw new Zend_Barcode_Renderer_Exception( + 'Vertical position must be greater than or equals 0' + ); + } + $this->_topOffset = intval($value); + return $this; + } + + /** + * Retrieve vertical adjustment + * @return integer + */ + public function getTopOffset() + { + return $this->_topOffset; + } + + /** + * Manually adjust left position + * @param integer $value + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setLeftOffset($value) + { + if (!is_numeric($value) || intval($value) < 0) { + throw new Zend_Barcode_Renderer_Exception( + 'Horizontal position must be greater than or equals 0' + ); + } + $this->_leftOffset = intval($value); + return $this; + } + + /** + * Retrieve vertical adjustment + * @return integer + */ + public function getLeftOffset() + { + return $this->_leftOffset; + } + + /** + * Activate/Deactivate the automatic rendering of exception + * + * @param boolean $value + * @return $this + */ + public function setAutomaticRenderError($value) + { + $this->_automaticRenderError = (bool) $value; + return $this; + } + + /** + * Horizontal position of the barcode in the rendering resource + * + * @param string $value + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setHorizontalPosition($value) + { + if (!in_array($value, array('left' , 'center' , 'right'))) { + throw new Zend_Barcode_Renderer_Exception( + "Invalid barcode position provided must be 'left', 'center' or 'right'" + ); + } + $this->_horizontalPosition = $value; + return $this; + } + + /** + * Horizontal position of the barcode in the rendering resource + * @return string + */ + public function getHorizontalPosition() + { + return $this->_horizontalPosition; + } + + /** + * Vertical position of the barcode in the rendering resource + * + * @param string $value + * @return self + * @throws Zend_Barcode_Renderer_Exception + */ + public function setVerticalPosition($value) + { + if (!in_array($value, array('top' , 'middle' , 'bottom'))) { + throw new Zend_Barcode_Renderer_Exception( + "Invalid barcode position provided must be 'top', 'middle' or 'bottom'" + ); + } + $this->_verticalPosition = $value; + return $this; + } + + /** + * Vertical position of the barcode in the rendering resource + * @return string + */ + public function getVerticalPosition() + { + return $this->_verticalPosition; + } + + /** + * Set the size of a module + * @param float $value + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setModuleSize($value) + { + if (!is_numeric($value) || floatval($value) <= 0) { + throw new Zend_Barcode_Renderer_Exception( + 'Float size must be greater than 0' + ); + } + $this->_moduleSize = floatval($value); + return $this; + } + + + /** + * Set the size of a module + * @return float + */ + public function getModuleSize() + { + return $this->_moduleSize; + } + + /** + * Retrieve the automatic rendering of exception + * @return boolean + */ + public function getAutomaticRenderError() + { + return $this->_automaticRenderError; + } + + /** + * Set the barcode object + * + * @param Zend_Barcode_Object $barcode + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setBarcode($barcode) + { + if (!$barcode instanceof Zend_Barcode_Object_ObjectAbstract) { + throw new Zend_Barcode_Renderer_Exception( + 'Invalid barcode object provided to setBarcode()' + ); + } + $this->_barcode = $barcode; + return $this; + } + + /** + * Retrieve the barcode object + * @return Zend_Barcode_Object + */ + public function getBarcode() + { + return $this->_barcode; + } + + /** + * Checking of parameters after all settings + * @return boolean + */ + public function checkParams() + { + $this->_checkBarcodeObject(); + $this->_checkParams(); + return true; + } + + /** + * Check if a barcode object is correctly provided + * @return void + * @throws Zend_Barcode_Renderer_Exception + */ + protected function _checkBarcodeObject() + { + if ($this->_barcode === null) { + /** + * @see Zend_Barcode_Renderer_Exception + */ + throw new Zend_Barcode_Renderer_Exception( + 'No barcode object provided' + ); + } + } + + /** + * Calculate the left and top offset of the barcode in the + * rendering support + * + * @param float $supportHeight + * @param float $supportWidth + * @return void + */ + protected function _adjustPosition($supportHeight, $supportWidth) + { + $barcodeHeight = $this->_barcode->getHeight(true) * $this->_moduleSize; + if ($barcodeHeight != $supportHeight && $this->_topOffset == 0) { + switch ($this->_verticalPosition) { + case 'middle': + $this->_topOffset = floor( + ($supportHeight - $barcodeHeight) / 2); + break; + case 'bottom': + $this->_topOffset = $supportHeight - $barcodeHeight; + break; + case 'top': + default: + $this->_topOffset = 0; + break; + } + } + $barcodeWidth = $this->_barcode->getWidth(true) * $this->_moduleSize; + if ($barcodeWidth != $supportWidth && $this->_leftOffset == 0) { + switch ($this->_horizontalPosition) { + case 'center': + $this->_leftOffset = floor( + ($supportWidth - $barcodeWidth) / 2); + break; + case 'right': + $this->_leftOffset = $supportWidth - $barcodeWidth; + break; + case 'left': + default: + $this->_leftOffset = 0; + break; + } + } + } + + /** + * Draw the barcode in the rendering resource + * + * @return mixed + * @throws Zend_Exception + * @throws Zend_Barcode_Exception + */ + public function draw() + { + try { + $this->checkParams(); + $this->_initRenderer(); + $this->_drawInstructionList(); + } catch (Zend_Exception $e) { + $renderable = false; + if ($e instanceof Zend_Barcode_Exception) { + $renderable = $e->isRenderable(); + } + if ($this->_automaticRenderError && $renderable) { + $barcode = Zend_Barcode::makeBarcode( + 'error', + array('text' => $e->getMessage()) + ); + $this->setBarcode($barcode); + $this->_resource = null; + $this->_initRenderer(); + $this->_drawInstructionList(); + } else { + if ($e instanceof Zend_Barcode_Exception) { + $e->setIsRenderable(false); + } + throw $e; + } + } + return $this->_resource; + } + + /** + * Sub process to draw the barcode instructions + * Needed by the automatic error rendering + */ + private function _drawInstructionList() + { + $instructionList = $this->_barcode->draw(); + foreach ($instructionList as $instruction) { + switch ($instruction['type']) { + case 'polygon': + $this->_drawPolygon( + $instruction['points'], + $instruction['color'], + $instruction['filled'] + ); + break; + case 'text': //$text, $size, $position, $font, $color, $alignment = 'center', $orientation = 0) + $this->_drawText( + $instruction['text'], + $instruction['size'], + $instruction['position'], + $instruction['font'], + $instruction['color'], + $instruction['alignment'], + $instruction['orientation'] + ); + break; + default: + /** + * @see Zend_Barcode_Renderer_Exception + */ + throw new Zend_Barcode_Renderer_Exception( + 'Unkown drawing command' + ); + } + } + } + + /** + * Checking of parameters after all settings + * @return void + */ + abstract protected function _checkParams(); + + /** + * Render the resource by sending headers and drawed resource + * @return mixed + */ + abstract public function render(); + + /** + * Initialize the rendering resource + * @return void + */ + abstract protected function _initRenderer(); + + /** + * Draw a polygon in the rendering resource + * @param array $points + * @param integer $color + * @param boolean $filled + */ + abstract protected function _drawPolygon($points, $color, $filled = true); + + /** + * Draw a polygon in the rendering resource + * + * @param string $text + * @param float $size + * @param array $position + * @param string $font + * @param integer $color + * @param string $alignment + * @param float|int $orientation + */ + abstract protected function _drawText( + $text, + $size, + $position, + $font, + $color, + $alignment = 'center', + $orientation = 0 + ); +} diff --git a/library/vendor/Zend/Barcode/Renderer/Svg.php b/library/vendor/Zend/Barcode/Renderer/Svg.php new file mode 100644 index 000000000..b791aaec4 --- /dev/null +++ b/library/vendor/Zend/Barcode/Renderer/Svg.php @@ -0,0 +1,377 @@ +_userHeight = intval($value); + return $this; + } + + /** + * Get barcode height + * + * @return int + */ + public function getHeight() + { + return $this->_userHeight; + } + + /** + * Set barcode width + * + * @param mixed $value + * @return self + * @throws Zend_Barcode_Renderer_Exception + */ + public function setWidth($value) + { + if (!is_numeric($value) || intval($value) < 0) { + throw new Zend_Barcode_Renderer_Exception( + 'Svg width must be greater than or equals 0' + ); + } + $this->_userWidth = intval($value); + return $this; + } + + /** + * Get barcode width + * + * @return int + */ + public function getWidth() + { + return $this->_userWidth; + } + + /** + * Set an image resource to draw the barcode inside + * + * @param $svg + * @return Zend_Barcode_Renderer + * @throws Zend_Barcode_Renderer_Exception + */ + public function setResource($svg) + { + if (!$svg instanceof DOMDocument) { + throw new Zend_Barcode_Renderer_Exception( + 'Invalid DOMDocument resource provided to setResource()' + ); + } + $this->_resource = $svg; + return $this; + } + + /** + * Initialize the image resource + * + * @return void + */ + protected function _initRenderer() + { + $barcodeWidth = $this->_barcode->getWidth(true); + $barcodeHeight = $this->_barcode->getHeight(true); + + $backgroundColor = $this->_barcode->getBackgroundColor(); + $imageBackgroundColor = 'rgb(' . implode(', ', array(($backgroundColor & 0xFF0000) >> 16, + ($backgroundColor & 0x00FF00) >> 8, + ($backgroundColor & 0x0000FF))) . ')'; + + $width = $barcodeWidth; + $height = $barcodeHeight; + if ($this->_userWidth && $this->_barcode->getType() != 'error') { + $width = $this->_userWidth; + } + if ($this->_userHeight && $this->_barcode->getType() != 'error') { + $height = $this->_userHeight; + } + if ($this->_resource === null) { + $this->_resource = new DOMDocument('1.0', 'utf-8'); + $this->_resource->formatOutput = true; + $this->_rootElement = $this->_resource->createElement('svg'); + $this->_rootElement->setAttribute('xmlns', "http://www.w3.org/2000/svg"); + $this->_rootElement->setAttribute('version', '1.1'); + $this->_rootElement->setAttribute('width', $width); + $this->_rootElement->setAttribute('height', $height); + + $this->_appendRootElement('title', + array(), + "Barcode " . strtoupper($this->_barcode->getType()) . " " . $this->_barcode->getText()); + } else { + $this->_readRootElement(); + $width = $this->_rootElement->getAttribute('width'); + $height = $this->_rootElement->getAttribute('height'); + } + $this->_adjustPosition($height, $width); + + $this->_appendRootElement('rect', + array('x' => $this->_leftOffset, + 'y' => $this->_topOffset, + 'width' => ($this->_leftOffset + $barcodeWidth - 1), + 'height' => ($this->_topOffset + $barcodeHeight - 1), + 'fill' => $imageBackgroundColor)); + } + + protected function _readRootElement() + { + if ($this->_resource !== null) { + $this->_rootElement = $this->_resource->documentElement; + } + } + + /** + * Append a new DOMElement to the root element + * + * @param string $tagName + * @param array $attributes + * @param string $textContent + */ + protected function _appendRootElement($tagName, $attributes = array(), $textContent = null) + { + $newElement = $this->_createElement($tagName, $attributes, $textContent); + $this->_rootElement->appendChild($newElement); + } + + /** + * Create DOMElement + * + * @param string $tagName + * @param array $attributes + * @param string $textContent + * @return DOMElement + */ + protected function _createElement($tagName, $attributes = array(), $textContent = null) + { + $element = $this->_resource->createElement($tagName); + foreach ($attributes as $k =>$v) { + $element->setAttribute($k, $v); + } + if ($textContent !== null) { + $element->appendChild(new DOMText((string) $textContent)); + } + return $element; + } + + /** + * Check barcode parameters + * + * @return void + */ + protected function _checkParams() + { + $this->_checkDimensions(); + } + + /** + * Check barcode dimensions + * + * @return void + * @throws Zend_Barcode_Renderer_Exception + */ + protected function _checkDimensions() + { + if ($this->_resource !== null) { + $this->_readRootElement(); + $height = (float) $this->_rootElement->getAttribute('height'); + if ($height < $this->_barcode->getHeight(true)) { + throw new Zend_Barcode_Renderer_Exception( + 'Barcode is define outside the image (height)' + ); + } + } else { + if ($this->_userHeight) { + $height = $this->_barcode->getHeight(true); + if ($this->_userHeight < $height) { + throw new Zend_Barcode_Renderer_Exception(sprintf( + "Barcode is define outside the image (calculated: '%d', provided: '%d')", + $height, + $this->_userHeight + )); + } + } + } + if ($this->_resource !== null) { + $this->_readRootElement(); + $width = $this->_rootElement->getAttribute('width'); + if ($width < $this->_barcode->getWidth(true)) { + throw new Zend_Barcode_Renderer_Exception( + 'Barcode is define outside the image (width)' + ); + } + } else { + if ($this->_userWidth) { + $width = (float) $this->_barcode->getWidth(true); + if ($this->_userWidth < $width) { + throw new Zend_Barcode_Renderer_Exception(sprintf( + "Barcode is define outside the image (calculated: '%d', provided: '%d')", + $width, + $this->_userWidth + )); + } + } + } + } + + /** + * Draw the barcode in the rendering resource + * @return mixed + */ + public function draw() + { + parent::draw(); + $this->_resource->appendChild($this->_rootElement); + return $this->_resource; + } + + /** + * Draw and render the barcode with correct headers + * + * @return mixed + */ + public function render() + { + $this->draw(); + header("Content-Type: image/svg+xml"); + echo $this->_resource->saveXML(); + } + + /** + * Draw a polygon in the svg resource + * + * @param array $points + * @param integer $color + * @param boolean $filled + */ + protected function _drawPolygon($points, $color, $filled = true) + { + $color = 'rgb(' . implode(', ', array(($color & 0xFF0000) >> 16, + ($color & 0x00FF00) >> 8, + ($color & 0x0000FF))) . ')'; + $orientation = $this->getBarcode()->getOrientation(); + $newPoints = array( + $points[0][0] + $this->_leftOffset, + $points[0][1] + $this->_topOffset, + $points[1][0] + $this->_leftOffset, + $points[1][1] + $this->_topOffset, + $points[2][0] + $this->_leftOffset + cos(-$orientation), + $points[2][1] + $this->_topOffset - sin($orientation), + $points[3][0] + $this->_leftOffset + cos(-$orientation), + $points[3][1] + $this->_topOffset - sin($orientation), + ); + $newPoints = implode(' ', $newPoints); + $attributes['points'] = $newPoints; + $attributes['fill'] = $color; + $this->_appendRootElement('polygon', $attributes); + } + + /** + * Draw a polygon in the svg resource + * + * @param string $text + * @param float $size + * @param array $position + * @param string $font + * @param integer $color + * @param string $alignment + * @param float|int $orientation + */ + protected function _drawText($text, $size, $position, $font, $color, $alignment = 'center', $orientation = 0) + { + $color = 'rgb(' . implode(', ', array(($color & 0xFF0000) >> 16, + ($color & 0x00FF00) >> 8, + ($color & 0x0000FF))) . ')'; + $attributes['x'] = $position[0] + $this->_leftOffset; + $attributes['y'] = $position[1] + $this->_topOffset; + //$attributes['font-family'] = $font; + $attributes['color'] = $color; + $attributes['font-size'] = $size * 1.2; + switch ($alignment) { + case 'left': + $textAnchor = 'start'; + break; + case 'right': + $textAnchor = 'end'; + break; + case 'center': + default: + $textAnchor = 'middle'; + } + $attributes['style'] = 'text-anchor: ' . $textAnchor; + $attributes['transform'] = 'rotate(' + . (- $orientation) + . ', ' + . ($position[0] + $this->_leftOffset) + . ', ' . ($position[1] + $this->_topOffset) + . ')'; + $this->_appendRootElement('text', $attributes, $text); + } +} diff --git a/library/vendor/Zend/Cache.php b/library/vendor/Zend/Cache.php new file mode 100644 index 000000000..209b7dff9 --- /dev/null +++ b/library/vendor/Zend/Cache.php @@ -0,0 +1,244 @@ +setBackend($backendObject); + return $frontendObject; + } + + /** + * Backend Constructor + * + * @param string $backend + * @param array $backendOptions + * @param boolean $customBackendNaming + * @param boolean $autoload + * @return Zend_Cache_Backend + */ + public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false) + { + if (!$customBackendNaming) { + $backend = self::_normalizeName($backend); + } + if (in_array($backend, Zend_Cache::$standardBackends)) { + // we use a standard backend + $backendClass = 'Zend_Cache_Backend_' . $backend; + // security controls are explicit + } else { + // we use a custom backend + if (!preg_match('~^[\w\\\\]+$~D', $backend)) { + Zend_Cache::throwException("Invalid backend name [$backend]"); + } + if (!$customBackendNaming) { + // we use this boolean to avoid an API break + $backendClass = 'Zend_Cache_Backend_' . $backend; + } else { + $backendClass = $backend; + } + if (!$autoload) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php'; + if (!(self::_isReadable($file))) { + self::throwException("file $file not found in include_path"); + } + } + } + return new $backendClass($backendOptions); + } + + /** + * Frontend Constructor + * + * @param string $frontend + * @param array $frontendOptions + * @param boolean $customFrontendNaming + * @param boolean $autoload + * @return Zend_Cache_Core|Zend_Cache_Frontend + */ + public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false) + { + if (!$customFrontendNaming) { + $frontend = self::_normalizeName($frontend); + } + if (in_array($frontend, self::$standardFrontends)) { + // we use a standard frontend + // For perfs reasons, with frontend == 'Core', we can interact with the Core itself + $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend; + // security controls are explicit + } else { + // we use a custom frontend + if (!preg_match('~^[\w\\\\]+$~D', $frontend)) { + Zend_Cache::throwException("Invalid frontend name [$frontend]"); + } + if (!$customFrontendNaming) { + // we use this boolean to avoid an API break + $frontendClass = 'Zend_Cache_Frontend_' . $frontend; + } else { + $frontendClass = $frontend; + } + if (!$autoload) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php'; + if (!(self::_isReadable($file))) { + self::throwException("file $file not found in include_path"); + } + } + } + return new $frontendClass($frontendOptions); + } + + /** + * Throw an exception + * + * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic + * @param string $msg Message for the exception + * @throws Zend_Cache_Exception + */ + public static function throwException($msg, Exception $e = null) + { + // For perfs reasons, we use this dynamic inclusion + throw new Zend_Cache_Exception($msg, 0, $e); + } + + /** + * Normalize frontend and backend names to allow multiple words TitleCased + * + * @param string $name Name to normalize + * @return string + */ + protected static function _normalizeName($name) + { + $name = ucfirst(strtolower($name)); + $name = str_replace(array('-', '_', '.'), ' ', $name); + $name = ucwords($name); + $name = str_replace(' ', '', $name); + if (stripos($name, 'ZendServer') === 0) { + $name = 'ZendServer_' . substr($name, strlen('ZendServer')); + } + + return $name; + } + + /** + * Returns TRUE if the $filename is readable, or FALSE otherwise. + * This function uses the PHP include_path, where PHP's is_readable() + * does not. + * + * Note : this method comes from Zend_Loader (see #ZF-2891 for details) + * + * @param string $filename + * @return boolean + */ + private static function _isReadable($filename) + { + if (!$fh = @fopen($filename, 'r', true)) { + return false; + } + @fclose($fh); + return true; + } + +} diff --git a/library/vendor/Zend/Cache/Backend.php b/library/vendor/Zend/Cache/Backend.php new file mode 100644 index 000000000..988cb08b4 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend.php @@ -0,0 +1,285 @@ + (int) lifetime : + * - Cache lifetime (in seconds) + * - If null, the cache is valid forever + * + * =====> (int) logging : + * - if set to true, a logging is activated throw Zend_Log + * + * @var array directives + */ + protected $_directives = array( + 'lifetime' => 3600, + 'logging' => false, + 'logger' => null + ); + + /** + * Available options + * + * @var array available options + */ + protected $_options = array(); + + /** + * Constructor + * + * @param array $options Associative array of options + */ + public function __construct(array $options = array()) + { + while (list($name, $value) = each($options)) { + $this->setOption($name, $value); + } + } + + /** + * Set the frontend directives + * + * @param array $directives Assoc of directives + * @throws Zend_Cache_Exception + * @return void + */ + public function setDirectives($directives) + { + if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array'); + while (list($name, $value) = each($directives)) { + if (!is_string($name)) { + Zend_Cache::throwException("Incorrect option name : $name"); + } + $name = strtolower($name); + if (array_key_exists($name, $this->_directives)) { + $this->_directives[$name] = $value; + } + + } + + $this->_loggerSanity(); + } + + /** + * Set an option + * + * @param string $name + * @param mixed $value + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if (!is_string($name)) { + Zend_Cache::throwException("Incorrect option name : $name"); + } + $name = strtolower($name); + if (array_key_exists($name, $this->_options)) { + $this->_options[$name] = $value; + } + } + + /** + * Returns an option + * + * @param string $name Optional, the options name to return + * @throws Zend_Cache_Exceptions + * @return mixed + */ + public function getOption($name) + { + $name = strtolower($name); + + if (array_key_exists($name, $this->_options)) { + return $this->_options[$name]; + } + + if (array_key_exists($name, $this->_directives)) { + return $this->_directives[$name]; + } + + Zend_Cache::throwException("Incorrect option name : {$name}"); + } + + /** + * Get the life time + * + * if $specificLifetime is not false, the given specific life time is used + * else, the global lifetime is used + * + * @param int $specificLifetime + * @return int Cache life time + */ + public function getLifetime($specificLifetime) + { + if ($specificLifetime === false) { + return $this->_directives['lifetime']; + } + return $specificLifetime; + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * DEPRECATED : use getCapabilities() instead + * + * @deprecated + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return true; + } + + /** + * Determine system TMP directory and detect if we have read access + * + * inspired from Zend_File_Transfer_Adapter_Abstract + * + * @return string + * @throws Zend_Cache_Exception if unable to determine directory + */ + public function getTmpDir() + { + $tmpdir = array(); + foreach (array($_ENV, $_SERVER) as $tab) { + foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) { + if (isset($tab[$key]) && is_string($tab[$key])) { + if (($key == 'windir') or ($key == 'SystemRoot')) { + $dir = realpath($tab[$key] . '\\temp'); + } else { + $dir = realpath($tab[$key]); + } + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + } + } + $upload = ini_get('upload_tmp_dir'); + if ($upload) { + $dir = realpath($upload); + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + if (function_exists('sys_get_temp_dir')) { + $dir = sys_get_temp_dir(); + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + // Attemp to detect by creating a temporary file + $tempFile = tempnam(md5(uniqid(rand(), TRUE)), ''); + if ($tempFile) { + $dir = realpath(dirname($tempFile)); + unlink($tempFile); + if ($this->_isGoodTmpDir($dir)) { + return $dir; + } + } + if ($this->_isGoodTmpDir('/tmp')) { + return '/tmp'; + } + if ($this->_isGoodTmpDir('\\temp')) { + return '\\temp'; + } + Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually'); + } + + /** + * Verify if the given temporary directory is readable and writable + * + * @param string $dir temporary directory + * @return boolean true if the directory is ok + */ + protected function _isGoodTmpDir($dir) + { + if (is_readable($dir)) { + if (is_writable($dir)) { + return true; + } + } + return false; + } + + /** + * Make sure if we enable logging that the Zend_Log class + * is available. + * Create a default log object if none is set. + * + * @throws Zend_Cache_Exception + * @return void + */ + protected function _loggerSanity() + { + if (!isset($this->_directives['logging']) || !$this->_directives['logging']) { + return; + } + + if (isset($this->_directives['logger'])) { + if ($this->_directives['logger'] instanceof Zend_Log) { + return; + } + Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.'); + } + + // Create a default logger to the standard output stream + $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output')); + $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<=')); + $this->_directives['logger'] = $logger; + } + + /** + * Log a message at the WARN (4) priority. + * + * @param string $message + * @param int $priority + * @return void + */ + protected function _log($message, $priority = 4) + { + if (!$this->_directives['logging']) { + return; + } + + if (!isset($this->_directives['logger'])) { + Zend_Cache::throwException('Logging is enabled but logger is not set.'); + } + $logger = $this->_directives['logger']; + if (!$logger instanceof Zend_Log) { + Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.'); + } + $logger->log($message, $priority); + } +} diff --git a/library/vendor/Zend/Cache/Backend/BlackHole.php b/library/vendor/Zend/Cache/Backend/BlackHole.php new file mode 100644 index 000000000..e61ad4bb7 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/BlackHole.php @@ -0,0 +1,248 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + return true; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return true; + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => remove too old cache entries ($tags is not used) + * 'matchingTag' => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * 'notMatchingTag' => remove cache entries not matching one of the given tags + * ($tags can be an array of strings or a single string) + * 'matchingAnyTag' => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode clean mode + * @param tags array $tags array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + return true; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return array(); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + return array(); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + * @throws Zend_Cache_Exception + */ + public function getFillingPercentage() + { + return 0; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => true, + 'priority' => true, + 'infinite_lifetime' => true, + 'get_list' => true, + ); + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id cache id + */ + public function ___expire($id) + { + } +} diff --git a/library/vendor/Zend/Cache/Backend/ExtendedInterface.php b/library/vendor/Zend/Cache/Backend/ExtendedInterface.php new file mode 100644 index 000000000..1d96f2dcb --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ExtendedInterface.php @@ -0,0 +1,125 @@ + (string) cache_dir : + * - Directory where to put the cache files + * + * =====> (boolean) file_locking : + * - Enable / disable file_locking + * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread + * webservers and on NFS filesystems for example + * + * =====> (boolean) read_control : + * - Enable / disable read control + * - If enabled, a control key is embeded in cache file and this key is compared with the one + * calculated after the reading. + * + * =====> (string) read_control_type : + * - Type of read control (only if read control is enabled). Available values are : + * 'md5' for a md5 hash control (best but slowest) + * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice) + * 'adler32' for an adler32 hash control (excellent choice too, faster than crc32) + * 'strlen' for a length only test (fastest) + * + * =====> (int) hashed_directory_level : + * - Hashed directory level + * - Set the hashed directory structure level. 0 means "no hashed directory + * structure", 1 means "one level of directory", 2 means "two levels"... + * This option can speed up the cache only when you have many thousands of + * cache file. Only specific benchs can help you to choose the perfect value + * for you. Maybe, 1 or 2 is a good start. + * + * =====> (int) hashed_directory_umask : + * - deprecated + * - Permissions for hashed directory structure + * + * =====> (int) hashed_directory_perm : + * - Permissions for hashed directory structure + * + * =====> (string) file_name_prefix : + * - prefix for cache files + * - be really carefull with this option because a too generic value in a system cache dir + * (like /tmp) can cause disasters when cleaning the cache + * + * =====> (int) cache_file_umask : + * - deprecated + * - Permissions for cache files + * + * =====> (int) cache_file_perm : + * - Permissions for cache files + * + * =====> (int) metatadatas_array_max_size : + * - max size for the metadatas array (don't change this value unless you + * know what you are doing) + * + * @var array available options + */ + protected $_options = array( + 'cache_dir' => null, + 'file_locking' => true, + 'read_control' => true, + 'read_control_type' => 'crc32', + 'hashed_directory_level' => 0, + 'hashed_directory_perm' => 0700, + 'file_name_prefix' => 'zend_cache', + 'cache_file_perm' => 0600, + 'metadatas_array_max_size' => 100 + ); + + /** + * Array of metadatas (each item is an associative array) + * + * @var array + */ + protected $_metadatasArray = array(); + + + /** + * Constructor + * + * @param array $options associative array of options + * @throws Zend_Cache_Exception + */ + public function __construct(array $options = array()) + { + parent::__construct($options); + if ($this->_options['cache_dir'] !== null) { // particular case for this option + $this->setCacheDir($this->_options['cache_dir']); + } else { + $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false); + } + if (isset($this->_options['file_name_prefix'])) { // particular case for this option + if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) { + Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]'); + } + } + if ($this->_options['metadatas_array_max_size'] < 10) { + Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10'); + } + + if (isset($options['hashed_directory_umask'])) { + // See #ZF-12047 + trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE); + if (!isset($options['hashed_directory_perm'])) { + $options['hashed_directory_perm'] = $options['hashed_directory_umask']; + } + } + if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) { + // See #ZF-4422 + $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']); + } + + if (isset($options['cache_file_umask'])) { + // See #ZF-12047 + trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE); + if (!isset($options['cache_file_perm'])) { + $options['cache_file_perm'] = $options['cache_file_umask']; + } + } + if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) { + // See #ZF-4422 + $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']); + } + } + + /** + * Set the cache_dir (particular case of setOption() method) + * + * @param string $value + * @param boolean $trailingSeparator If true, add a trailing separator is necessary + * @throws Zend_Cache_Exception + * @return void + */ + public function setCacheDir($value, $trailingSeparator = true) + { + if (!is_dir($value)) { + Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value)); + } + if (!is_writable($value)) { + Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value)); + } + if ($trailingSeparator) { + // add a trailing DIRECTORY_SEPARATOR if necessary + $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR; + } + $this->_options['cache_dir'] = $value; + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id cache id + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + if (!($this->_test($id, $doNotTestCacheValidity))) { + // The cache is not hit ! + return false; + } + $metadatas = $this->_getMetadatas($id); + $file = $this->_file($id); + $data = $this->_fileGetContents($file); + if ($this->_options['read_control']) { + $hashData = $this->_hash($data, $this->_options['read_control_type']); + $hashControl = $metadatas['hash']; + if ($hashData != $hashControl) { + // Problem detected by the read control ! + $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match'); + $this->remove($id); + return false; + } + } + return $data; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + clearstatcache(); + return $this->_test($id, false); + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param boolean|int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + clearstatcache(); + $file = $this->_file($id); + $path = $this->_path($id); + if ($this->_options['hashed_directory_level'] > 0) { + if (!is_writable($path)) { + // maybe, we just have to build the directory structure + $this->_recursiveMkdirAndChmod($id); + } + if (!is_writable($path)) { + return false; + } + } + if ($this->_options['read_control']) { + $hash = $this->_hash($data, $this->_options['read_control_type']); + } else { + $hash = ''; + } + $metadatas = array( + 'hash' => $hash, + 'mtime' => time(), + 'expire' => $this->_expireTime($this->getLifetime($specificLifetime)), + 'tags' => $tags + ); + $res = $this->_setMetadatas($id, $metadatas); + if (!$res) { + $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata'); + return false; + } + $res = $this->_filePutContents($file, $data); + return $res; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + $file = $this->_file($id); + $boolRemove = $this->_remove($file); + $boolMetadata = $this->_delMetadatas($id); + return $boolMetadata && $boolRemove; + } + + /** + * Clean some cache records + * + * Available modes are : + * + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode clean mode + * @param array $tags array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + // We use this protected method to hide the recursive stuff + clearstatcache(); + return $this->_clean($this->_options['cache_dir'], $mode, $tags); + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return $this->_get($this->_options['cache_dir'], 'ids', array()); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return $this->_get($this->_options['cache_dir'], 'tags', array()); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + return $this->_get($this->_options['cache_dir'], 'matching', $tags); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + return $this->_get($this->_options['cache_dir'], 'notMatching', $tags); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags); + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $free = disk_free_space($this->_options['cache_dir']); + $total = disk_total_space($this->_options['cache_dir']); + if ($total == 0) { + Zend_Cache::throwException('can\'t get disk_total_space'); + } else { + if ($free >= $total) { + return 100; + } + return ((int) (100. * ($total - $free) / $total)); + } + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $metadatas = $this->_getMetadatas($id); + if (!$metadatas) { + return false; + } + if (time() > $metadatas['expire']) { + return false; + } + return array( + 'expire' => $metadatas['expire'], + 'tags' => $metadatas['tags'], + 'mtime' => $metadatas['mtime'] + ); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $metadatas = $this->_getMetadatas($id); + if (!$metadatas) { + return false; + } + if (time() > $metadatas['expire']) { + return false; + } + $newMetadatas = array( + 'hash' => $metadatas['hash'], + 'mtime' => time(), + 'expire' => $metadatas['expire'] + $extraLifetime, + 'tags' => $metadatas['tags'] + ); + $res = $this->_setMetadatas($id, $newMetadatas); + if (!$res) { + return false; + } + return true; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => true, + 'priority' => false, + 'infinite_lifetime' => true, + 'get_list' => true + ); + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id cache id + */ + public function ___expire($id) + { + $metadatas = $this->_getMetadatas($id); + if ($metadatas) { + $metadatas['expire'] = 1; + $this->_setMetadatas($id, $metadatas); + } + } + + /** + * Get a metadatas record + * + * @param string $id Cache id + * @return array|false Associative array of metadatas + */ + protected function _getMetadatas($id) + { + if (isset($this->_metadatasArray[$id])) { + return $this->_metadatasArray[$id]; + } else { + $metadatas = $this->_loadMetadatas($id); + if (!$metadatas) { + return false; + } + $this->_setMetadatas($id, $metadatas, false); + return $metadatas; + } + } + + /** + * Set a metadatas record + * + * @param string $id Cache id + * @param array $metadatas Associative array of metadatas + * @param boolean $save optional pass false to disable saving to file + * @return boolean True if no problem + */ + protected function _setMetadatas($id, $metadatas, $save = true) + { + if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) { + $n = (int) ($this->_options['metadatas_array_max_size'] / 10); + $this->_metadatasArray = array_slice($this->_metadatasArray, $n); + } + if ($save) { + $result = $this->_saveMetadatas($id, $metadatas); + if (!$result) { + return false; + } + } + $this->_metadatasArray[$id] = $metadatas; + return true; + } + + /** + * Drop a metadata record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + protected function _delMetadatas($id) + { + if (isset($this->_metadatasArray[$id])) { + unset($this->_metadatasArray[$id]); + } + $file = $this->_metadatasFile($id); + return $this->_remove($file); + } + + /** + * Clear the metadatas array + * + * @return void + */ + protected function _cleanMetadatas() + { + $this->_metadatasArray = array(); + } + + /** + * Load metadatas from disk + * + * @param string $id Cache id + * @return array|false Metadatas associative array + */ + protected function _loadMetadatas($id) + { + $file = $this->_metadatasFile($id); + $result = $this->_fileGetContents($file); + if (!$result) { + return false; + } + $tmp = @unserialize($result); + return $tmp; + } + + /** + * Save metadatas to disk + * + * @param string $id Cache id + * @param array $metadatas Associative array + * @return boolean True if no problem + */ + protected function _saveMetadatas($id, $metadatas) + { + $file = $this->_metadatasFile($id); + $result = $this->_filePutContents($file, serialize($metadatas)); + if (!$result) { + return false; + } + return true; + } + + /** + * Make and return a file name (with path) for metadatas + * + * @param string $id Cache id + * @return string Metadatas file name (with path) + */ + protected function _metadatasFile($id) + { + $path = $this->_path($id); + $fileName = $this->_idToFileName('internal-metadatas---' . $id); + return $path . $fileName; + } + + /** + * Check if the given filename is a metadatas one + * + * @param string $fileName File name + * @return boolean True if it's a metadatas one + */ + protected function _isMetadatasFile($fileName) + { + $id = $this->_fileNameToId($fileName); + if (substr($id, 0, 21) == 'internal-metadatas---') { + return true; + } else { + return false; + } + } + + /** + * Remove a file + * + * If we can't remove the file (because of locks or any problem), we will touch + * the file to invalidate it + * + * @param string $file Complete file path + * @return boolean True if ok + */ + protected function _remove($file) + { + if (!is_file($file)) { + return false; + } + if (!@unlink($file)) { + # we can't remove the file (because of locks or any problem) + $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file"); + return false; + } + return true; + } + + /** + * Clean some cache records (protected method used for recursive stuff) + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $dir Directory to clean + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + if (!is_dir($dir)) { + return false; + } + $result = true; + $prefix = $this->_options['file_name_prefix']; + $glob = @glob($dir . $prefix . '--*'); + if ($glob === false) { + // On some systems it is impossible to distinguish between empty match and an error. + return true; + } + $metadataFiles = array(); + foreach ($glob as $file) { + if (is_file($file)) { + $fileName = basename($file); + if ($this->_isMetadatasFile($fileName)) { + // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files. + // To do that, we need to save the list of the metadata files first. + if ($mode == Zend_Cache::CLEANING_MODE_ALL) { + $metadataFiles[] = $file; + } + continue; + } + $id = $this->_fileNameToId($fileName); + $metadatas = $this->_getMetadatas($id); + if ($metadatas === FALSE) { + $metadatas = array('expire' => 1, 'tags' => array()); + } + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $result = $result && $this->remove($id); + break; + case Zend_Cache::CLEANING_MODE_OLD: + if (time() > $metadatas['expire']) { + $result = $this->remove($id) && $result; + } + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $matching = true; + foreach ($tags as $tag) { + if (!in_array($tag, $metadatas['tags'])) { + $matching = false; + break; + } + } + if ($matching) { + $result = $this->remove($id) && $result; + } + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if (!$matching) { + $result = $this->remove($id) && $result; + } + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if ($matching) { + $result = $this->remove($id) && $result; + } + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) { + // Recursive call + $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result; + if ($mode == Zend_Cache::CLEANING_MODE_ALL) { + // we try to drop the structure too + @rmdir($file); + } + } + } + + // cycle through metadataFiles and delete orphaned ones + foreach ($metadataFiles as $file) { + if (file_exists($file)) { + $result = $this->_remove($file) && $result; + } + } + + return $result; + } + + protected function _get($dir, $mode, $tags = array()) + { + if (!is_dir($dir)) { + return false; + } + $result = array(); + $prefix = $this->_options['file_name_prefix']; + $glob = @glob($dir . $prefix . '--*'); + if ($glob === false) { + // On some systems it is impossible to distinguish between empty match and an error. + return array(); + } + foreach ($glob as $file) { + if (is_file($file)) { + $fileName = basename($file); + $id = $this->_fileNameToId($fileName); + $metadatas = $this->_getMetadatas($id); + if ($metadatas === FALSE) { + continue; + } + if (time() > $metadatas['expire']) { + continue; + } + switch ($mode) { + case 'ids': + $result[] = $id; + break; + case 'tags': + $result = array_unique(array_merge($result, $metadatas['tags'])); + break; + case 'matching': + $matching = true; + foreach ($tags as $tag) { + if (!in_array($tag, $metadatas['tags'])) { + $matching = false; + break; + } + } + if ($matching) { + $result[] = $id; + } + break; + case 'notMatching': + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if (!$matching) { + $result[] = $id; + } + break; + case 'matchingAny': + $matching = false; + foreach ($tags as $tag) { + if (in_array($tag, $metadatas['tags'])) { + $matching = true; + break; + } + } + if ($matching) { + $result[] = $id; + } + break; + default: + Zend_Cache::throwException('Invalid mode for _get() method'); + break; + } + } + if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) { + // Recursive call + $recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags); + if ($recursiveRs === false) { + $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"'); + } else { + $result = array_unique(array_merge($result, $recursiveRs)); + } + } + } + return array_unique($result); + } + + /** + * Compute & return the expire time + * + * @param int $lifetime + * @return int expire time (unix timestamp) + */ + protected function _expireTime($lifetime) + { + if ($lifetime === null) { + return 9999999999; + } + return time() + $lifetime; + } + + /** + * Make a control key with the string containing datas + * + * @param string $data Data + * @param string $controlType Type of control 'md5', 'crc32' or 'strlen' + * @throws Zend_Cache_Exception + * @return string Control key + */ + protected function _hash($data, $controlType) + { + switch ($controlType) { + case 'md5': + return md5($data); + case 'crc32': + return crc32($data); + case 'strlen': + return strlen($data); + case 'adler32': + return hash('adler32', $data); + default: + Zend_Cache::throwException("Incorrect hash function : $controlType"); + } + } + + /** + * Transform a cache id into a file name and return it + * + * @param string $id Cache id + * @return string File name + */ + protected function _idToFileName($id) + { + $prefix = $this->_options['file_name_prefix']; + $result = $prefix . '---' . $id; + return $result; + } + + /** + * Make and return a file name (with path) + * + * @param string $id Cache id + * @return string File name (with path) + */ + protected function _file($id) + { + $path = $this->_path($id); + $fileName = $this->_idToFileName($id); + return $path . $fileName; + } + + /** + * Return the complete directory path of a filename (including hashedDirectoryStructure) + * + * @param string $id Cache id + * @param boolean $parts if true, returns array of directory parts instead of single string + * @return string Complete directory path + */ + protected function _path($id, $parts = false) + { + $partsArray = array(); + $root = $this->_options['cache_dir']; + $prefix = $this->_options['file_name_prefix']; + if ($this->_options['hashed_directory_level']>0) { + $hash = hash('adler32', $id); + for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) { + $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR; + $partsArray[] = $root; + } + } + if ($parts) { + return $partsArray; + } else { + return $root; + } + } + + /** + * Make the directory strucuture for the given id + * + * @param string $id cache id + * @return boolean true + */ + protected function _recursiveMkdirAndChmod($id) + { + if ($this->_options['hashed_directory_level'] <=0) { + return true; + } + $partsArray = $this->_path($id, true); + foreach ($partsArray as $part) { + if (!is_dir($part)) { + @mkdir($part, $this->_options['hashed_directory_perm']); + @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations) + } + } + return true; + } + + /** + * Test if the given cache id is available (and still valid as a cache record) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + protected function _test($id, $doNotTestCacheValidity) + { + $metadatas = $this->_getMetadatas($id); + if (!$metadatas) { + return false; + } + if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) { + return $metadatas['mtime']; + } + return false; + } + + /** + * Return the file content of the given file + * + * @param string $file File complete path + * @return string File content (or false if problem) + */ + protected function _fileGetContents($file) + { + $result = false; + if (!is_file($file)) { + return false; + } + $f = @fopen($file, 'rb'); + if ($f) { + if ($this->_options['file_locking']) @flock($f, LOCK_SH); + $result = stream_get_contents($f); + if ($this->_options['file_locking']) @flock($f, LOCK_UN); + @fclose($f); + } + return $result; + } + + /** + * Put the given string into the given file + * + * @param string $file File complete path + * @param string $string String to put in file + * @return boolean true if no problem + */ + protected function _filePutContents($file, $string) + { + $result = false; + $f = @fopen($file, 'ab+'); + if ($f) { + if ($this->_options['file_locking']) @flock($f, LOCK_EX); + fseek($f, 0); + ftruncate($f, 0); + $tmp = @fwrite($f, $string); + if (!($tmp === FALSE)) { + $result = true; + } + @fclose($f); + } + @chmod($file, $this->_options['cache_file_perm']); + return $result; + } + + /** + * Transform a file name into cache id and return it + * + * @param string $fileName File name + * @return string Cache id + */ + protected function _fileNameToId($fileName) + { + $prefix = $this->_options['file_name_prefix']; + return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Interface.php b/library/vendor/Zend/Cache/Backend/Interface.php new file mode 100644 index 000000000..3a2789529 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Interface.php @@ -0,0 +1,99 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false); + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id); + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()); + +} diff --git a/library/vendor/Zend/Cache/Backend/Sqlite.php b/library/vendor/Zend/Cache/Backend/Sqlite.php new file mode 100644 index 000000000..2b8e911dc --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Sqlite.php @@ -0,0 +1,676 @@ + (string) cache_db_complete_path : + * - the complete path (filename included) of the SQLITE database + * + * ====> (int) automatic_vacuum_factor : + * - Disable / Tune the automatic vacuum process + * - The automatic vacuum process defragment the database file (and make it smaller) + * when a clean() or delete() is called + * 0 => no automatic vacuum + * 1 => systematic vacuum (when delete() or clean() methods are called) + * x (integer) > 1 => automatic vacuum randomly 1 times on x clean() or delete() + * + * @var array Available options + */ + protected $_options = array( + 'cache_db_complete_path' => null, + 'automatic_vacuum_factor' => 10 + ); + + /** + * DB ressource + * + * @var mixed $_db + */ + private $_db = null; + + /** + * Boolean to store if the structure has benn checked or not + * + * @var boolean $_structureChecked + */ + private $_structureChecked = false; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + parent::__construct($options); + if ($this->_options['cache_db_complete_path'] === null) { + Zend_Cache::throwException('cache_db_complete_path option has to set'); + } + if (!extension_loaded('sqlite')) { + Zend_Cache::throwException("Cannot use SQLite storage because the 'sqlite' extension is not loaded in the current PHP environment"); + } + $this->_getConnection(); + } + + /** + * Destructor + * + * @return void + */ + public function __destruct() + { + @sqlite_close($this->_getConnection()); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false Cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + $this->_checkAndBuildStructure(); + $sql = "SELECT content FROM cache WHERE id='$id'"; + if (!$doNotTestCacheValidity) { + $sql = $sql . " AND (expire=0 OR expire>" . time() . ')'; + } + $result = $this->_query($sql); + $row = @sqlite_fetch_array($result); + if ($row) { + return $row['content']; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id Cache id + * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $this->_checkAndBuildStructure(); + $sql = "SELECT lastModified FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')'; + $result = $this->_query($sql); + $row = @sqlite_fetch_array($result); + if ($row) { + return ((int) $row['lastModified']); + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $this->_checkAndBuildStructure(); + $lifetime = $this->getLifetime($specificLifetime); + $data = @sqlite_escape_string($data); + $mktime = time(); + if ($lifetime === null) { + $expire = 0; + } else { + $expire = $mktime + $lifetime; + } + $this->_query("DELETE FROM cache WHERE id='$id'"); + $sql = "INSERT INTO cache (id, content, lastModified, expire) VALUES ('$id', '$data', $mktime, $expire)"; + $res = $this->_query($sql); + if (!$res) { + $this->_log("Zend_Cache_Backend_Sqlite::save() : impossible to store the cache id=$id"); + return false; + } + $res = true; + foreach ($tags as $tag) { + $res = $this->_registerTag($id, $tag) && $res; + } + return $res; + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + $this->_checkAndBuildStructure(); + $res = $this->_query("SELECT COUNT(*) AS nbr FROM cache WHERE id='$id'"); + $result1 = @sqlite_fetch_single($res); + $result2 = $this->_query("DELETE FROM cache WHERE id='$id'"); + $result3 = $this->_query("DELETE FROM tag WHERE id='$id'"); + $this->_automaticVacuum(); + return ($result1 && $result2 && $result3); + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + $this->_checkAndBuildStructure(); + $return = $this->_clean($mode, $tags); + $this->_automaticVacuum(); + return $return; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $this->_checkAndBuildStructure(); + $res = $this->_query("SELECT id FROM cache WHERE (expire=0 OR expire>" . time() . ")"); + $result = array(); + while ($id = @sqlite_fetch_single($res)) { + $result[] = $id; + } + return $result; + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_checkAndBuildStructure(); + $res = $this->_query("SELECT DISTINCT(name) AS name FROM tag"); + $result = array(); + while ($id = @sqlite_fetch_single($res)) { + $result[] = $id; + } + return $result; + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $first = true; + $ids = array(); + foreach ($tags as $tag) { + $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'"); + if (!$res) { + return array(); + } + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + $ids2 = array(); + foreach ($rows as $row) { + $ids2[] = $row['id']; + } + if ($first) { + $ids = $ids2; + $first = false; + } else { + $ids = array_intersect($ids, $ids2); + } + } + $result = array(); + foreach ($ids as $id) { + $result[] = $id; + } + return $result; + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $res = $this->_query("SELECT id FROM cache"); + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + $result = array(); + foreach ($rows as $row) { + $id = $row['id']; + $matching = false; + foreach ($tags as $tag) { + $res = $this->_query("SELECT COUNT(*) AS nbr FROM tag WHERE name='$tag' AND id='$id'"); + if (!$res) { + return array(); + } + $nbr = (int) @sqlite_fetch_single($res); + if ($nbr > 0) { + $matching = true; + } + } + if (!$matching) { + $result[] = $id; + } + } + return $result; + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $first = true; + $ids = array(); + foreach ($tags as $tag) { + $res = $this->_query("SELECT DISTINCT(id) AS id FROM tag WHERE name='$tag'"); + if (!$res) { + return array(); + } + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + $ids2 = array(); + foreach ($rows as $row) { + $ids2[] = $row['id']; + } + if ($first) { + $ids = $ids2; + $first = false; + } else { + $ids = array_merge($ids, $ids2); + } + } + $result = array(); + foreach ($ids as $id) { + $result[] = $id; + } + return $result; + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $dir = dirname($this->_options['cache_db_complete_path']); + $free = disk_free_space($dir); + $total = disk_total_space($dir); + if ($total == 0) { + Zend_Cache::throwException('can\'t get disk_total_space'); + } else { + if ($free >= $total) { + return 100; + } + return ((int) (100. * ($total - $free) / $total)); + } + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tags = array(); + $res = $this->_query("SELECT name FROM tag WHERE id='$id'"); + if ($res) { + $rows = @sqlite_fetch_all($res, SQLITE_ASSOC); + foreach ($rows as $row) { + $tags[] = $row['name']; + } + } + $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)'); + $res = $this->_query("SELECT lastModified,expire FROM cache WHERE id='$id'"); + if (!$res) { + return false; + } + $row = @sqlite_fetch_array($res, SQLITE_ASSOC); + return array( + 'tags' => $tags, + 'mtime' => $row['lastModified'], + 'expire' => $row['expire'] + ); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $sql = "SELECT expire FROM cache WHERE id='$id' AND (expire=0 OR expire>" . time() . ')'; + $res = $this->_query($sql); + if (!$res) { + return false; + } + $expire = @sqlite_fetch_single($res); + $newExpire = $expire + $extraLifetime; + $res = $this->_query("UPDATE cache SET lastModified=" . time() . ", expire=$newExpire WHERE id='$id'"); + if ($res) { + return true; + } else { + return false; + } + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => true, + 'priority' => false, + 'infinite_lifetime' => true, + 'get_list' => true + ); + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id Cache id + */ + public function ___expire($id) + { + $time = time() - 1; + $this->_query("UPDATE cache SET lastModified=$time, expire=$time WHERE id='$id'"); + } + + /** + * Return the connection resource + * + * If we are not connected, the connection is made + * + * @throws Zend_Cache_Exception + * @return resource Connection resource + */ + private function _getConnection() + { + if (is_resource($this->_db)) { + return $this->_db; + } else { + $this->_db = @sqlite_open($this->_options['cache_db_complete_path']); + if (!(is_resource($this->_db))) { + Zend_Cache::throwException("Impossible to open " . $this->_options['cache_db_complete_path'] . " cache DB file"); + } + return $this->_db; + } + } + + /** + * Execute an SQL query silently + * + * @param string $query SQL query + * @return mixed|false query results + */ + private function _query($query) + { + $db = $this->_getConnection(); + if (is_resource($db)) { + $res = @sqlite_query($db, $query); + if ($res === false) { + return false; + } else { + return $res; + } + } + return false; + } + + /** + * Deal with the automatic vacuum process + * + * @return void + */ + private function _automaticVacuum() + { + if ($this->_options['automatic_vacuum_factor'] > 0) { + $rand = rand(1, $this->_options['automatic_vacuum_factor']); + if ($rand == 1) { + $this->_query('VACUUM'); + } + } + } + + /** + * Register a cache id with the given tag + * + * @param string $id Cache id + * @param string $tag Tag + * @return boolean True if no problem + */ + private function _registerTag($id, $tag) { + $res = $this->_query("DELETE FROM TAG WHERE name='$tag' AND id='$id'"); + $res = $this->_query("INSERT INTO tag (name, id) VALUES ('$tag', '$id')"); + if (!$res) { + $this->_log("Zend_Cache_Backend_Sqlite::_registerTag() : impossible to register tag=$tag on id=$id"); + return false; + } + return true; + } + + /** + * Build the database structure + * + * @return false + */ + private function _buildStructure() + { + $this->_query('DROP INDEX tag_id_index'); + $this->_query('DROP INDEX tag_name_index'); + $this->_query('DROP INDEX cache_id_expire_index'); + $this->_query('DROP TABLE version'); + $this->_query('DROP TABLE cache'); + $this->_query('DROP TABLE tag'); + $this->_query('CREATE TABLE version (num INTEGER PRIMARY KEY)'); + $this->_query('CREATE TABLE cache (id TEXT PRIMARY KEY, content BLOB, lastModified INTEGER, expire INTEGER)'); + $this->_query('CREATE TABLE tag (name TEXT, id TEXT)'); + $this->_query('CREATE INDEX tag_id_index ON tag(id)'); + $this->_query('CREATE INDEX tag_name_index ON tag(name)'); + $this->_query('CREATE INDEX cache_id_expire_index ON cache(id, expire)'); + $this->_query('INSERT INTO version (num) VALUES (1)'); + } + + /** + * Check if the database structure is ok (with the good version) + * + * @return boolean True if ok + */ + private function _checkStructureVersion() + { + $result = $this->_query("SELECT num FROM version"); + if (!$result) return false; + $row = @sqlite_fetch_array($result); + if (!$row) { + return false; + } + if (((int) $row['num']) != 1) { + // old cache structure + $this->_log('Zend_Cache_Backend_Sqlite::_checkStructureVersion() : old cache structure version detected => the cache is going to be dropped'); + return false; + } + return true; + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean True if no problem + */ + private function _clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $res1 = $this->_query('DELETE FROM cache'); + $res2 = $this->_query('DELETE FROM tag'); + return $res1 && $res2; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $mktime = time(); + $res1 = $this->_query("DELETE FROM tag WHERE id IN (SELECT id FROM cache WHERE expire>0 AND expire<=$mktime)"); + $res2 = $this->_query("DELETE FROM cache WHERE expire>0 AND expire<=$mktime"); + return $res1 && $res2; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $ids = $this->getIdsMatchingTags($tags); + $result = true; + foreach ($ids as $id) { + $result = $this->remove($id) && $result; + } + return $result; + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $ids = $this->getIdsNotMatchingTags($tags); + $result = true; + foreach ($ids as $id) { + $result = $this->remove($id) && $result; + } + return $result; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $ids = $this->getIdsMatchingAnyTags($tags); + $result = true; + foreach ($ids as $id) { + $result = $this->remove($id) && $result; + } + return $result; + break; + default: + break; + } + return false; + } + + /** + * Check if the database structure is ok (with the good version), if no : build it + * + * @throws Zend_Cache_Exception + * @return boolean True if ok + */ + private function _checkAndBuildStructure() + { + if (!($this->_structureChecked)) { + if (!$this->_checkStructureVersion()) { + $this->_buildStructure(); + if (!$this->_checkStructureVersion()) { + Zend_Cache::throwException("Impossible to build cache structure in " . $this->_options['cache_db_complete_path']); + } + } + $this->_structureChecked = true; + } + return true; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Static.php b/library/vendor/Zend/Cache/Backend/Static.php new file mode 100644 index 000000000..c23d31d1e --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Static.php @@ -0,0 +1,577 @@ + null, + 'sub_dir' => 'html', + 'file_extension' => '.html', + 'index_filename' => 'index', + 'file_locking' => true, + 'cache_file_perm' => 0600, + 'cache_directory_perm' => 0700, + 'debug_header' => false, + 'tag_cache' => null, + 'disable_caching' => false + ); + + /** + * Cache for handling tags + * @var Zend_Cache_Core + */ + protected $_tagCache = null; + + /** + * Tagged items + * @var array + */ + protected $_tagged = null; + + /** + * Interceptor child method to handle the case where an Inner + * Cache object is being set since it's not supported by the + * standard backend interface + * + * @param string $name + * @param mixed $value + * @return Zend_Cache_Backend_Static + */ + public function setOption($name, $value) + { + if ($name == 'tag_cache') { + $this->setInnerCache($value); + } else { + // See #ZF-12047 and #GH-91 + if ($name == 'cache_file_umask') { + trigger_error( + "'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", + E_USER_NOTICE + ); + + $name = 'cache_file_perm'; + } + if ($name == 'cache_directory_umask') { + trigger_error( + "'cache_directory_umask' is deprecated -> please use 'cache_directory_perm' instead", + E_USER_NOTICE + ); + + $name = 'cache_directory_perm'; + } + + parent::setOption($name, $value); + } + return $this; + } + + /** + * Retrieve any option via interception of the parent's statically held + * options including the local option for a tag cache. + * + * @param string $name + * @return mixed + */ + public function getOption($name) + { + $name = strtolower($name); + + if ($name == 'tag_cache') { + return $this->getInnerCache(); + } + + return parent::getOption($name); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * Note : return value is always "string" (unserialization is done by the core not by the backend) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + if (($id = (string)$id) === '') { + $id = $this->_detectId(); + } else { + $id = $this->_decodeId($id); + } + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + if ($doNotTestCacheValidity) { + $this->_log("Zend_Cache_Backend_Static::load() : \$doNotTestCacheValidity=true is unsupported by the Static backend"); + } + + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + $pathName = $this->_options['public_dir'] . dirname($id); + $file = rtrim($pathName, '/') . '/' . $fileName . $this->_options['file_extension']; + if (file_exists($file)) { + $content = file_get_contents($file); + return $content; + } + + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return bool + */ + public function test($id) + { + $id = $this->_decodeId($id); + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif (!$this->_tagged) { + return false; + } + $pathName = $this->_options['public_dir'] . dirname($id); + + // Switch extension if needed + if (isset($this->_tagged[$id])) { + $extension = $this->_tagged[$id]['extension']; + } else { + $extension = $this->_options['file_extension']; + } + $file = $pathName . '/' . $fileName . $extension; + if (file_exists($file)) { + return true; + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + if ($this->_options['disable_caching']) { + return true; + } + $extension = null; + if ($this->_isSerialized($data)) { + $data = unserialize($data); + $extension = '.' . ltrim($data[1], '.'); + $data = $data[0]; + } + + clearstatcache(); + if (($id = (string)$id) === '') { + $id = $this->_detectId(); + } else { + $id = $this->_decodeId($id); + } + + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + + $pathName = realpath($this->_options['public_dir']) . dirname($id); + $this->_createDirectoriesFor($pathName); + + if ($id === null || strlen($id) == 0) { + $dataUnserialized = unserialize($data); + $data = $dataUnserialized['data']; + } + $ext = $this->_options['file_extension']; + if ($extension) $ext = $extension; + $file = rtrim($pathName, '/') . '/' . $fileName . $ext; + if ($this->_options['file_locking']) { + $result = file_put_contents($file, $data, LOCK_EX); + } else { + $result = file_put_contents($file, $data); + } + @chmod($file, $this->_octdec($this->_options['cache_file_perm'])); + + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif ($this->_tagged === null) { + $this->_tagged = array(); + } + if (!isset($this->_tagged[$id])) { + $this->_tagged[$id] = array(); + } + if (!isset($this->_tagged[$id]['tags'])) { + $this->_tagged[$id]['tags'] = array(); + } + $this->_tagged[$id]['tags'] = array_unique(array_merge($this->_tagged[$id]['tags'], $tags)); + $this->_tagged[$id]['extension'] = $ext; + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + return (bool) $result; + } + + /** + * Recursively create the directories needed to write the static file + */ + protected function _createDirectoriesFor($path) + { + if (!is_dir($path)) { + $oldUmask = umask(0); + if ( !@mkdir($path, $this->_octdec($this->_options['cache_directory_perm']), true)) { + $lastErr = error_get_last(); + umask($oldUmask); + Zend_Cache::throwException("Can't create directory: {$lastErr['message']}"); + } + umask($oldUmask); + } + } + + /** + * Detect serialization of data (cannot predict since this is the only way + * to obey the interface yet pass in another parameter). + * + * In future, ZF 2.0, check if we can just avoid the interface restraints. + * + * This format is the only valid one possible for the class, so it's simple + * to just run a regular expression for the starting serialized format. + */ + protected function _isSerialized($data) + { + return preg_match("/a:2:\{i:0;s:\d+:\"/", $data); + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + $fileName = basename($id); + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif (!$this->_tagged) { + return false; + } + if (isset($this->_tagged[$id])) { + $extension = $this->_tagged[$id]['extension']; + } else { + $extension = $this->_options['file_extension']; + } + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + $pathName = $this->_options['public_dir'] . dirname($id); + $file = realpath($pathName) . '/' . $fileName . $extension; + if (!file_exists($file)) { + return false; + } + return unlink($file); + } + + /** + * Remove a cache record recursively for the given directory matching a + * REQUEST_URI based relative path (deletes the actual file matching this + * in addition to the matching directory) + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function removeRecursively($id) + { + if (!$this->_verifyPath($id)) { + Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path'); + } + $fileName = basename($id); + if ($fileName === '') { + $fileName = $this->_options['index_filename']; + } + $pathName = $this->_options['public_dir'] . dirname($id); + $file = $pathName . '/' . $fileName . $this->_options['file_extension']; + $directory = $pathName . '/' . $fileName; + if (file_exists($directory)) { + if (!is_writable($directory)) { + return false; + } + if (is_dir($directory)) { + foreach (new DirectoryIterator($directory) as $file) { + if (true === $file->isFile()) { + if (false === unlink($file->getPathName())) { + return false; + } + } + } + } + rmdir($directory); + } + if (file_exists($file)) { + if (!is_writable($file)) { + return false; + } + return unlink($file); + } + return true; + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean true if no problem + * @throws Zend_Exception + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + $result = false; + switch ($mode) { + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + if (empty($tags)) { + throw new Zend_Exception('Cannot use tag matching modes as no tags were defined'); + } + if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) { + $this->_tagged = $tagged; + } elseif (!$this->_tagged) { + return true; + } + foreach ($tags as $tag) { + $urls = array_keys($this->_tagged); + foreach ($urls as $url) { + if (isset($this->_tagged[$url]['tags']) && in_array($tag, $this->_tagged[$url]['tags'])) { + $this->remove($url); + unset($this->_tagged[$url]); + } + } + } + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + $result = true; + break; + case Zend_Cache::CLEANING_MODE_ALL: + if ($this->_tagged === null) { + $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME); + $this->_tagged = $tagged; + } + if ($this->_tagged === null || empty($this->_tagged)) { + return true; + } + $urls = array_keys($this->_tagged); + foreach ($urls as $url) { + $this->remove($url); + unset($this->_tagged[$url]); + } + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + $result = true; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Static : Selected Cleaning Mode Currently Unsupported By This Backend"); + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + if (empty($tags)) { + throw new Zend_Exception('Cannot use tag matching modes as no tags were defined'); + } + if ($this->_tagged === null) { + $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME); + $this->_tagged = $tagged; + } + if ($this->_tagged === null || empty($this->_tagged)) { + return true; + } + $urls = array_keys($this->_tagged); + foreach ($urls as $url) { + $difference = array_diff($tags, $this->_tagged[$url]['tags']); + if (count($tags) == count($difference)) { + $this->remove($url); + unset($this->_tagged[$url]); + } + } + $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME); + $result = true; + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + return $result; + } + + /** + * Set an Inner Cache, used here primarily to store Tags associated + * with caches created by this backend. Note: If Tags are lost, the cache + * should be completely cleaned as the mapping of tags to caches will + * have been irrevocably lost. + * + * @param Zend_Cache_Core + * @return void + */ + public function setInnerCache(Zend_Cache_Core $cache) + { + $this->_tagCache = $cache; + $this->_options['tag_cache'] = $cache; + } + + /** + * Get the Inner Cache if set + * + * @return Zend_Cache_Core + */ + public function getInnerCache() + { + if ($this->_tagCache === null) { + Zend_Cache::throwException('An Inner Cache has not been set; use setInnerCache()'); + } + return $this->_tagCache; + } + + /** + * Verify path exists and is non-empty + * + * @param string $path + * @return bool + */ + protected function _verifyPath($path) + { + $path = realpath($path); + $base = realpath($this->_options['public_dir']); + return strncmp($path, $base, strlen($base)) !== 0; + } + + /** + * Determine the page to save from the request + * + * @return string + */ + protected function _detectId() + { + return $_SERVER['REQUEST_URI']; + } + + /** + * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...) + * + * Throw an exception if a problem is found + * + * @param string $string Cache id or tag + * @throws Zend_Cache_Exception + * @return void + * @deprecated Not usable until perhaps ZF 2.0 + */ + protected static function _validateIdOrTag($string) + { + if (!is_string($string)) { + Zend_Cache::throwException('Invalid id or tag : must be a string'); + } + + // Internal only checked in Frontend - not here! + if (substr($string, 0, 9) == 'internal-') { + return; + } + + // Validation assumes no query string, fragments or scheme included - only the path + if (!preg_match( + '/^(?:\/(?:(?:%[[:xdigit:]]{2}|[A-Za-z0-9-_.!~*\'()\[\]:@&=+$,;])*)?)+$/', + $string + ) + ) { + Zend_Cache::throwException("Invalid id or tag '$string' : must be a valid URL path"); + } + } + + /** + * Detect an octal string and return its octal value for file permission ops + * otherwise return the non-string (assumed octal or decimal int already) + * + * @param string $val The potential octal in need of conversion + * @return int + */ + protected function _octdec($val) + { + if (is_string($val) && decoct(octdec($val)) == $val) { + return octdec($val); + } + return $val; + } + + /** + * Decode a request URI from the provided ID + * + * @param string $id + * @return string + */ + protected function _decodeId($id) + { + return pack('H*', $id); + } +} diff --git a/library/vendor/Zend/Cache/Backend/Test.php b/library/vendor/Zend/Cache/Backend/Test.php new file mode 100644 index 000000000..a9cd61bb2 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Test.php @@ -0,0 +1,414 @@ +_addLog('construct', array($options)); + } + + /** + * Set the frontend directives + * + * @param array $directives assoc of directives + * @return void + */ + public function setDirectives($directives) + { + $this->_addLog('setDirectives', array($directives)); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * For this test backend only, if $id == 'false', then the method will return false + * if $id == 'serialized', the method will return a serialized array + * ('foo' else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string Cached datas (or false) + */ + public function load($id, $doNotTestCacheValidity = false) + { + $this->_addLog('get', array($id, $doNotTestCacheValidity)); + + if ( $id == 'false' + || $id == 'd8523b3ee441006261eeffa5c3d3a0a7' + || $id == 'e83249ea22178277d5befc2c5e2e9ace' + || $id == '40f649b94977c0a6e76902e2a0b43587' + || $id == '88161989b73a4cbfd0b701c446115a99' + || $id == '205fc79cba24f0f0018eb92c7c8b3ba4' + || $id == '170720e35f38150b811f68a937fb042d') + { + return false; + } + if ($id=='serialized') { + return serialize(array('foo')); + } + if ($id=='serialized2') { + return serialize(array('headers' => array(), 'data' => 'foo')); + } + if ( $id == '71769f39054f75894288e397df04e445' || $id == '615d222619fb20b527168340cebd0578' + || $id == '8a02d218a5165c467e7a5747cc6bd4b6' || $id == '648aca1366211d17cbf48e65dc570bee' + || $id == '4a923ef02d7f997ca14d56dfeae25ea7') { + return serialize(array('foo', 'bar')); + } + if ( $id == 'f53c7d912cc523d9a65834c8286eceb9') { + return serialize(array('foobar')); + } + return 'foo'; + } + + /** + * Test if a cache is available or not (for the given id) + * + * For this test backend only, if $id == 'false', then the method will return false + * (123456 else) + * + * @param string $id Cache id + * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $this->_addLog('test', array($id)); + if ($id=='false') { + return false; + } + if (($id=='3c439c922209e2cb0b54d6deffccd75a')) { + return false; + } + return 123456; + } + + /** + * Save some string datas into a cache record + * + * For this test backend only, if $id == 'false', then the method will return false + * (true else) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean True if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $this->_addLog('save', array($data, $id, $tags)); + if (substr($id,-5)=='false') { + return false; + } + return true; + } + + /** + * Remove a cache record + * + * For this test backend only, if $id == 'false', then the method will return false + * (true else) + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + $this->_addLog('remove', array($id)); + if (substr($id,-5)=='false') { + return false; + } + return true; + } + + /** + * Clean some cache records + * + * For this test backend only, if $mode == 'false', then the method will return false + * (true else) + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + $this->_addLog('clean', array($mode, $tags)); + if ($mode=='false') { + return false; + } + return true; + } + + /** + * Get the last log + * + * @return string The last log + */ + public function getLastLog() + { + return $this->_log[$this->_index - 1]; + } + + /** + * Get the log index + * + * @return int Log index + */ + public function getLogIndex() + { + return $this->_index; + } + + /** + * Get the complete log array + * + * @return array Complete log array + */ + public function getAllLogs() + { + return $this->_log; + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return true; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return array( + 'prefix_id1', 'prefix_id2' + ); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return array( + 'tag1', 'tag2' + ); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + if ($tags == array('tag1', 'tag2')) { + return array('prefix_id1', 'prefix_id2'); + } + + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + if ($tags == array('tag3', 'tag4')) { + return array('prefix_id3', 'prefix_id4'); + } + + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + if ($tags == array('tag5', 'tag6')) { + return array('prefix_id5', 'prefix_id6'); + } + + return array(); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + return 50; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + return true; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => true, + 'tags' => true, + 'expired_read' => false, + 'priority' => true, + 'infinite_lifetime' => true, + 'get_list' => true + ); + } + + /** + * Add an event to the log array + * + * @param string $methodName MethodName + * @param array $args Arguments + * @return void + */ + private function _addLog($methodName, $args) + { + $this->_log[$this->_index] = array( + 'methodName' => $methodName, + 'args' => $args + ); + $this->_index = $this->_index + 1; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/TwoLevels.php b/library/vendor/Zend/Cache/Backend/TwoLevels.php new file mode 100644 index 000000000..902412952 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/TwoLevels.php @@ -0,0 +1,546 @@ + (string) slow_backend : + * - Slow backend name + * - Must implement the Zend_Cache_Backend_ExtendedInterface + * - Should provide a big storage + * + * =====> (string) fast_backend : + * - Flow backend name + * - Must implement the Zend_Cache_Backend_ExtendedInterface + * - Must be much faster than slow_backend + * + * =====> (array) slow_backend_options : + * - Slow backend options (see corresponding backend) + * + * =====> (array) fast_backend_options : + * - Fast backend options (see corresponding backend) + * + * =====> (int) stats_update_factor : + * - Disable / Tune the computation of the fast backend filling percentage + * - When saving a record into cache : + * 1 => systematic computation of the fast backend filling percentage + * x (integer) > 1 => computation of the fast backend filling percentage randomly 1 times on x cache write + * + * =====> (boolean) slow_backend_custom_naming : + * =====> (boolean) fast_backend_custom_naming : + * =====> (boolean) slow_backend_autoload : + * =====> (boolean) fast_backend_autoload : + * - See Zend_Cache::factory() method + * + * =====> (boolean) auto_fill_fast_cache + * - If true, automatically fill the fast cache when a cache record was not found in fast cache, but did + * exist in slow cache. This can be usefull when a non-persistent cache like APC or Memcached got + * purged for whatever reason. + * + * =====> (boolean) auto_refresh_fast_cache + * - If true, auto refresh the fast cache when a cache record is hit + * + * @var array available options + */ + protected $_options = array( + 'slow_backend' => 'File', + 'fast_backend' => 'Apc', + 'slow_backend_options' => array(), + 'fast_backend_options' => array(), + 'stats_update_factor' => 10, + 'slow_backend_custom_naming' => false, + 'fast_backend_custom_naming' => false, + 'slow_backend_autoload' => false, + 'fast_backend_autoload' => false, + 'auto_fill_fast_cache' => true, + 'auto_refresh_fast_cache' => true + ); + + /** + * Slow Backend + * + * @var Zend_Cache_Backend_ExtendedInterface + */ + protected $_slowBackend; + + /** + * Fast Backend + * + * @var Zend_Cache_Backend_ExtendedInterface + */ + protected $_fastBackend; + + /** + * Cache for the fast backend filling percentage + * + * @var int + */ + protected $_fastBackendFillingPercentage = null; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + parent::__construct($options); + + if ($this->_options['slow_backend'] === null) { + Zend_Cache::throwException('slow_backend option has to set'); + } elseif ($this->_options['slow_backend'] instanceof Zend_Cache_Backend_ExtendedInterface) { + $this->_slowBackend = $this->_options['slow_backend']; + } else { + $this->_slowBackend = Zend_Cache::_makeBackend( + $this->_options['slow_backend'], + $this->_options['slow_backend_options'], + $this->_options['slow_backend_custom_naming'], + $this->_options['slow_backend_autoload'] + ); + if (!in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_slowBackend))) { + Zend_Cache::throwException('slow_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'); + } + } + + if ($this->_options['fast_backend'] === null) { + Zend_Cache::throwException('fast_backend option has to set'); + } elseif ($this->_options['fast_backend'] instanceof Zend_Cache_Backend_ExtendedInterface) { + $this->_fastBackend = $this->_options['fast_backend']; + } else { + $this->_fastBackend = Zend_Cache::_makeBackend( + $this->_options['fast_backend'], + $this->_options['fast_backend_options'], + $this->_options['fast_backend_custom_naming'], + $this->_options['fast_backend_autoload'] + ); + if (!in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_fastBackend))) { + Zend_Cache::throwException('fast_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'); + } + } + + $this->_slowBackend->setDirectives($this->_directives); + $this->_fastBackend->setDirectives($this->_directives); + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $fastTest = $this->_fastBackend->test($id); + if ($fastTest) { + return $fastTest; + } else { + return $this->_slowBackend->test($id); + } + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Datas to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false, $priority = 8) + { + $usage = $this->_getFastFillingPercentage('saving'); + $boolFast = true; + $lifetime = $this->getLifetime($specificLifetime); + $preparedData = $this->_prepareData($data, $lifetime, $priority); + if (($priority > 0) && (10 * $priority >= $usage)) { + $fastLifetime = $this->_getFastLifetime($lifetime, $priority); + $boolFast = $this->_fastBackend->save($preparedData, $id, array(), $fastLifetime); + $boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime); + } else { + $boolSlow = $this->_slowBackend->save($preparedData, $id, $tags, $lifetime); + if ($boolSlow === true) { + $boolFast = $this->_fastBackend->remove($id); + if (!$boolFast && !$this->_fastBackend->test($id)) { + // some backends return false on remove() even if the key never existed. (and it won't if fast is full) + // all we care about is that the key doesn't exist now + $boolFast = true; + } + } + } + + return ($boolFast && $boolSlow); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * Note : return value is always "string" (unserialization is done by the core not by the backend) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @return string|false cached datas + */ + public function load($id, $doNotTestCacheValidity = false) + { + $resultFast = $this->_fastBackend->load($id, $doNotTestCacheValidity); + if ($resultFast === false) { + $resultSlow = $this->_slowBackend->load($id, $doNotTestCacheValidity); + if ($resultSlow === false) { + // there is no cache at all for this id + return false; + } + } + $array = $resultFast !== false ? unserialize($resultFast) : unserialize($resultSlow); + + //In case no cache entry was found in the FastCache and auto-filling is enabled, copy data to FastCache + if ($resultFast === false && $this->_options['auto_fill_fast_cache']) { + $preparedData = $this->_prepareData($array['data'], $array['lifetime'], $array['priority']); + $this->_fastBackend->save($preparedData, $id, array(), $array['lifetime']); + } + // maybe, we have to refresh the fast cache ? + elseif ($this->_options['auto_refresh_fast_cache']) { + if ($array['priority'] == 10) { + // no need to refresh the fast cache with priority = 10 + return $array['data']; + } + $newFastLifetime = $this->_getFastLifetime($array['lifetime'], $array['priority'], time() - $array['expire']); + // we have the time to refresh the fast cache + $usage = $this->_getFastFillingPercentage('loading'); + if (($array['priority'] > 0) && (10 * $array['priority'] >= $usage)) { + // we can refresh the fast cache + $preparedData = $this->_prepareData($array['data'], $array['lifetime'], $array['priority']); + $this->_fastBackend->save($preparedData, $id, array(), $newFastLifetime); + } + } + return $array['data']; + } + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + $boolFast = $this->_fastBackend->remove($id); + $boolSlow = $this->_slowBackend->remove($id); + return $boolFast && $boolSlow; + } + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags} + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $boolFast = $this->_fastBackend->clean(Zend_Cache::CLEANING_MODE_ALL); + $boolSlow = $this->_slowBackend->clean(Zend_Cache::CLEANING_MODE_ALL); + return $boolFast && $boolSlow; + break; + case Zend_Cache::CLEANING_MODE_OLD: + return $this->_slowBackend->clean(Zend_Cache::CLEANING_MODE_OLD); + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $ids = $this->_slowBackend->getIdsMatchingTags($tags); + $res = true; + foreach ($ids as $id) { + $bool = $this->remove($id); + $res = $res && $bool; + } + return $res; + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $ids = $this->_slowBackend->getIdsNotMatchingTags($tags); + $res = true; + foreach ($ids as $id) { + $bool = $this->remove($id); + $res = $res && $bool; + } + return $res; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $ids = $this->_slowBackend->getIdsMatchingAnyTags($tags); + $res = true; + foreach ($ids as $id) { + $bool = $this->remove($id); + $res = $res && $bool; + } + return $res; + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + return $this->_slowBackend->getIds(); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + return $this->_slowBackend->getTags(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + return $this->_slowBackend->getIdsMatchingTags($tags); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + return $this->_slowBackend->getIdsNotMatchingTags($tags); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + return $this->_slowBackend->getIdsMatchingAnyTags($tags); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + return $this->_slowBackend->getFillingPercentage(); + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + return $this->_slowBackend->getMetadatas($id); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + return $this->_slowBackend->touch($id, $extraLifetime); + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + $slowBackendCapabilities = $this->_slowBackend->getCapabilities(); + return array( + 'automatic_cleaning' => $slowBackendCapabilities['automatic_cleaning'], + 'tags' => $slowBackendCapabilities['tags'], + 'expired_read' => $slowBackendCapabilities['expired_read'], + 'priority' => $slowBackendCapabilities['priority'], + 'infinite_lifetime' => $slowBackendCapabilities['infinite_lifetime'], + 'get_list' => $slowBackendCapabilities['get_list'] + ); + } + + /** + * Prepare a serialized array to store datas and metadatas informations + * + * @param string $data data to store + * @param int $lifetime original lifetime + * @param int $priority priority + * @return string serialize array to store into cache + */ + private function _prepareData($data, $lifetime, $priority) + { + $lt = $lifetime; + if ($lt === null) { + $lt = 9999999999; + } + return serialize(array( + 'data' => $data, + 'lifetime' => $lifetime, + 'expire' => time() + $lt, + 'priority' => $priority + )); + } + + /** + * Compute and return the lifetime for the fast backend + * + * @param int $lifetime original lifetime + * @param int $priority priority + * @param int $maxLifetime maximum lifetime + * @return int lifetime for the fast backend + */ + private function _getFastLifetime($lifetime, $priority, $maxLifetime = null) + { + if ($lifetime <= 0) { + // if no lifetime, we have an infinite lifetime + // we need to use arbitrary lifetimes + $fastLifetime = (int) (2592000 / (11 - $priority)); + } else { + // prevent computed infinite lifetime (0) by ceil + $fastLifetime = (int) ceil($lifetime / (11 - $priority)); + } + + if ($maxLifetime >= 0 && $fastLifetime > $maxLifetime) { + return $maxLifetime; + } + + return $fastLifetime; + } + + /** + * PUBLIC METHOD FOR UNIT TESTING ONLY ! + * + * Force a cache record to expire + * + * @param string $id cache id + */ + public function ___expire($id) + { + $this->_fastBackend->remove($id); + $this->_slowBackend->___expire($id); + } + + private function _getFastFillingPercentage($mode) + { + + if ($mode == 'saving') { + // mode saving + if ($this->_fastBackendFillingPercentage === null) { + $this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage(); + } else { + $rand = rand(1, $this->_options['stats_update_factor']); + if ($rand == 1) { + // we force a refresh + $this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage(); + } + } + } else { + // mode loading + // we compute the percentage only if it's not available in cache + if ($this->_fastBackendFillingPercentage === null) { + $this->_fastBackendFillingPercentage = $this->_fastBackend->getFillingPercentage(); + } + } + return $this->_fastBackendFillingPercentage; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/WinCache.php b/library/vendor/Zend/Cache/Backend/WinCache.php new file mode 100644 index 000000000..f47b998d2 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/WinCache.php @@ -0,0 +1,347 @@ + infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $result = wincache_ucache_set($id, array($data, time(), $lifetime), $lifetime); + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + } + return $result; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return wincache_ucache_delete($id); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + return wincache_ucache_clear(); + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_WinCache::clean() : CLEANING_MODE_OLD is unsupported by the WinCache backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_WINCACHE_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * DEPRECATED : use getCapabilities() instead + * + * @deprecated + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + + /** + * Return the filling percentage of the backend storage + * + * @throws Zend_Cache_Exception + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + $mem = wincache_ucache_meminfo(); + $memSize = $mem['memory_total']; + $memUsed = $memSize - $mem['memory_free']; + if ($memSize == 0) { + Zend_Cache::throwException('can\'t get WinCache memory size'); + } + if ($memUsed > $memSize) { + return 100; + } + return ((int) (100. * ($memUsed / $memSize))); + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of any matching cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_WINCACHE_BACKEND); + return array(); + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + $res = array(); + $array = wincache_ucache_info(); + $records = $array['ucache_entries']; + foreach ($records as $record) { + $res[] = $record['key_name']; + } + return $res; + } + + /** + * Return an array of metadatas for the given cache id + * + * The array must include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + $tmp = wincache_ucache_get($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + return false; + } + $lifetime = $tmp[2]; + return array( + 'expire' => $mtime + $lifetime, + 'tags' => array(), + 'mtime' => $mtime + ); + } + return false; + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + $tmp = wincache_ucache_get($id); + if (is_array($tmp)) { + $data = $tmp[0]; + $mtime = $tmp[1]; + if (!isset($tmp[2])) { + return false; + } + $lifetime = $tmp[2]; + $newLifetime = $lifetime - (time() - $mtime) + $extraLifetime; + if ($newLifetime <=0) { + return false; + } + return wincache_ucache_set($id, array($data, time(), $newLifetime), $newLifetime); + } + return false; + } + + /** + * Return an associative array of capabilities (booleans) of the backend + * + * The array must include these keys : + * - automatic_cleaning (is automating cleaning necessary) + * - tags (are tags supported) + * - expired_read (is it possible to read expired cache records + * (for doNotTestCacheValidity option for example)) + * - priority does the backend deal with priority when saving + * - infinite_lifetime (is infinite lifetime can work with this backend) + * - get_list (is it possible to get the list of cache ids and the complete list of tags) + * + * @return array associative of with capabilities + */ + public function getCapabilities() + { + return array( + 'automatic_cleaning' => false, + 'tags' => false, + 'expired_read' => false, + 'priority' => false, + 'infinite_lifetime' => false, + 'get_list' => true + ); + } + +} diff --git a/library/vendor/Zend/Cache/Backend/Xcache.php b/library/vendor/Zend/Cache/Backend/Xcache.php new file mode 100644 index 000000000..6c7e22c28 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/Xcache.php @@ -0,0 +1,219 @@ + (string) user : + * xcache.admin.user (necessary for the clean() method) + * + * =====> (string) password : + * xcache.admin.pass (clear, not MD5) (necessary for the clean() method) + * + * @var array available options + */ + protected $_options = array( + 'user' => null, + 'password' => null + ); + + /** + * Constructor + * + * @param array $options associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + if (!extension_loaded('xcache')) { + Zend_Cache::throwException('The xcache extension must be loaded for using this backend !'); + } + parent::__construct($options); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * WARNING $doNotTestCacheValidity=true is unsupported by the Xcache backend + * + * @param string $id cache id + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string cached datas (or false) + */ + public function load($id, $doNotTestCacheValidity = false) + { + if ($doNotTestCacheValidity) { + $this->_log("Zend_Cache_Backend_Xcache::load() : \$doNotTestCacheValidity=true is unsupported by the Xcache backend"); + } + $tmp = xcache_get($id); + if (is_array($tmp)) { + return $tmp[0]; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + if (xcache_isset($id)) { + $tmp = xcache_get($id); + if (is_array($tmp)) { + return $tmp[1]; + } + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data datas to cache + * @param string $id cache id + * @param array $tags array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $result = xcache_set($id, array($data, time()), $lifetime); + if (count($tags) > 0) { + $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_XCACHE_BACKEND); + } + return $result; + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + return xcache_unset($id); + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + // Necessary because xcache_clear_cache() need basic authentification + $backup = array(); + if (isset($_SERVER['PHP_AUTH_USER'])) { + $backup['PHP_AUTH_USER'] = $_SERVER['PHP_AUTH_USER']; + } + if (isset($_SERVER['PHP_AUTH_PW'])) { + $backup['PHP_AUTH_PW'] = $_SERVER['PHP_AUTH_PW']; + } + if ($this->_options['user']) { + $_SERVER['PHP_AUTH_USER'] = $this->_options['user']; + } + if ($this->_options['password']) { + $_SERVER['PHP_AUTH_PW'] = $this->_options['password']; + } + + $cnt = xcache_count(XC_TYPE_VAR); + for ($i=0; $i < $cnt; $i++) { + xcache_clear_cache(XC_TYPE_VAR, $i); + } + + if (isset($backup['PHP_AUTH_USER'])) { + $_SERVER['PHP_AUTH_USER'] = $backup['PHP_AUTH_USER']; + $_SERVER['PHP_AUTH_PW'] = $backup['PHP_AUTH_PW']; + } + return true; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_Xcache::clean() : CLEANING_MODE_OLD is unsupported by the Xcache backend"); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_log(self::TAGS_UNSUPPORTED_BY_CLEAN_OF_XCACHE_BACKEND); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Return true if the automatic cleaning is available for the backend + * + * @return boolean + */ + public function isAutomaticCleaningAvailable() + { + return false; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/ZendPlatform.php b/library/vendor/Zend/Cache/Backend/ZendPlatform.php new file mode 100644 index 000000000..0eea9eef5 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendPlatform.php @@ -0,0 +1,315 @@ +_directives['lifetime']; + } + $res = output_cache_get($id, $lifetime); + if($res) { + return $res[0]; + } else { + return false; + } + } + + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id Cache id + * @return mixed|false false (a cache is not available) or "last modified" timestamp (int) of the available cache record + */ + public function test($id) + { + $result = output_cache_get($id, $this->_directives['lifetime']); + if ($result) { + return $result[1]; + } + return false; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data Data to cache + * @param string $id Cache id + * @param array $tags Array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + if (!($specificLifetime === false)) { + $this->_log("Zend_Cache_Backend_ZendPlatform::save() : non false specifc lifetime is unsuported for this backend"); + } + + $lifetime = $this->_directives['lifetime']; + $result1 = output_cache_put($id, array($data, time())); + $result2 = (count($tags) == 0); + + foreach ($tags as $tag) { + $tagid = self::TAGS_PREFIX.$tag; + $old_tags = output_cache_get($tagid, $lifetime); + if ($old_tags === false) { + $old_tags = array(); + } + $old_tags[$id] = $id; + output_cache_remove_key($tagid); + $result2 = output_cache_put($tagid, $old_tags); + } + + return $result1 && $result2; + } + + + /** + * Remove a cache record + * + * @param string $id Cache id + * @return boolean True if no problem + */ + public function remove($id) + { + return output_cache_remove_key($id); + } + + + /** + * Clean some cache records + * + * Available modes are : + * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used) + * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used) + * This mode is not supported in this backend + * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => unsupported + * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode Clean mode + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + case Zend_Cache::CLEANING_MODE_OLD: + $cache_dir = ini_get('zend_accelerator.output_cache_dir'); + if (!$cache_dir) { + return false; + } + $cache_dir .= '/.php_cache_api/'; + return $this->_clean($cache_dir, $mode); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + $idlist = null; + foreach ($tags as $tag) { + $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); + if ($idlist) { + $idlist = array_intersect_assoc($idlist, $next_idlist); + } else { + $idlist = $next_idlist; + } + if (count($idlist) == 0) { + // if ID list is already empty - we may skip checking other IDs + $idlist = null; + break; + } + } + if ($idlist) { + foreach ($idlist as $id) { + output_cache_remove_key($id); + } + } + return true; + break; + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + $this->_log("Zend_Cache_Backend_ZendPlatform::clean() : CLEANING_MODE_NOT_MATCHING_TAG is not supported by the Zend Platform backend"); + return false; + break; + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $idlist = null; + foreach ($tags as $tag) { + $next_idlist = output_cache_get(self::TAGS_PREFIX.$tag, $this->_directives['lifetime']); + if ($idlist) { + $idlist = array_merge_recursive($idlist, $next_idlist); + } else { + $idlist = $next_idlist; + } + if (count($idlist) == 0) { + // if ID list is already empty - we may skip checking other IDs + $idlist = null; + break; + } + } + if ($idlist) { + foreach ($idlist as $id) { + output_cache_remove_key($id); + } + } + return true; + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } + + /** + * Clean a directory and recursivly go over it's subdirectories + * + * Remove all the cached files that need to be cleaned (according to mode and files mtime) + * + * @param string $dir Path of directory ot clean + * @param string $mode The same parameter as in Zend_Cache_Backend_ZendPlatform::clean() + * @return boolean True if ok + */ + private function _clean($dir, $mode) + { + $d = @dir($dir); + if (!$d) { + return false; + } + $result = true; + while (false !== ($file = $d->read())) { + if ($file == '.' || $file == '..') { + continue; + } + $file = $d->path . $file; + if (is_dir($file)) { + $result = ($this->_clean($file .'/', $mode)) && ($result); + } else { + if ($mode == Zend_Cache::CLEANING_MODE_ALL) { + $result = ($this->_remove($file)) && ($result); + } else if ($mode == Zend_Cache::CLEANING_MODE_OLD) { + // Files older than lifetime get deleted from cache + if ($this->_directives['lifetime'] !== null) { + if ((time() - @filemtime($file)) > $this->_directives['lifetime']) { + $result = ($this->_remove($file)) && ($result); + } + } + } + } + } + $d->close(); + return $result; + } + + /** + * Remove a file + * + * If we can't remove the file (because of locks or any problem), we will touch + * the file to invalidate it + * + * @param string $file Complete file path + * @return boolean True if ok + */ + private function _remove($file) + { + if (!@unlink($file)) { + # If we can't remove the file (because of locks or any problem), we will touch + # the file to invalidate it + $this->_log("Zend_Cache_Backend_ZendPlatform::_remove() : we can't remove $file => we are going to try to invalidate it"); + if ($this->_directives['lifetime'] === null) { + return false; + } + if (!file_exists($file)) { + return false; + } + return @touch($file, time() - 2*abs($this->_directives['lifetime'])); + } + return true; + } + +} diff --git a/library/vendor/Zend/Cache/Backend/ZendServer.php b/library/vendor/Zend/Cache/Backend/ZendServer.php new file mode 100755 index 000000000..47f5539b3 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendServer.php @@ -0,0 +1,205 @@ + (string) namespace : + * Namespace to be used for chaching operations + * + * @var array available options + */ + protected $_options = array( + 'namespace' => 'zendframework' + ); + + /** + * Store data + * + * @param mixed $data Object to store + * @param string $id Cache id + * @param int $timeToLive Time to live in seconds + * @throws Zend_Cache_Exception + */ + abstract protected function _store($data, $id, $timeToLive); + + /** + * Fetch data + * + * @param string $id Cache id + * @throws Zend_Cache_Exception + */ + abstract protected function _fetch($id); + + /** + * Unset data + * + * @param string $id Cache id + */ + abstract protected function _unset($id); + + /** + * Clear cache + */ + abstract protected function _clear(); + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id cache id + * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested + * @return string cached datas (or false) + */ + public function load($id, $doNotTestCacheValidity = false) + { + $tmp = $this->_fetch($id); + if ($tmp !== null) { + return $tmp; + } + return false; + } + + /** + * Test if a cache is available or not (for the given id) + * + * @param string $id cache id + * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record + * @throws Zend_Cache_Exception + */ + public function test($id) + { + $tmp = $this->_fetch('internal-metadatas---' . $id); + if ($tmp !== false) { + if (!is_array($tmp) || !isset($tmp['mtime'])) { + Zend_Cache::throwException('Cache metadata for \'' . $id . '\' id is corrupted' ); + } + return $tmp['mtime']; + } + return false; + } + + /** + * Compute & return the expire time + * + * @return int expire time (unix timestamp) + */ + private function _expireTime($lifetime) + { + if ($lifetime === null) { + return 9999999999; + } + return time() + $lifetime; + } + + /** + * Save some string datas into a cache record + * + * Note : $data is always "string" (serialization is done by the + * core not by the backend) + * + * @param string $data datas to cache + * @param string $id cache id + * @param array $tags array of strings, the cache record will be tagged by each string entry + * @param int $specificLifetime if != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @return boolean true if no problem + */ + public function save($data, $id, $tags = array(), $specificLifetime = false) + { + $lifetime = $this->getLifetime($specificLifetime); + $metadatas = array( + 'mtime' => time(), + 'expire' => $this->_expireTime($lifetime), + ); + + if (count($tags) > 0) { + $this->_log('Zend_Cache_Backend_ZendServer::save() : tags are unsupported by the ZendServer backends'); + } + + return $this->_store($data, $id, $lifetime) && + $this->_store($metadatas, 'internal-metadatas---' . $id, $lifetime); + } + + /** + * Remove a cache record + * + * @param string $id cache id + * @return boolean true if no problem + */ + public function remove($id) + { + $result1 = $this->_unset($id); + $result2 = $this->_unset('internal-metadatas---' . $id); + + return $result1 && $result2; + } + + /** + * Clean some cache records + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => unsupported + * 'matchingTag' => unsupported + * 'notMatchingTag' => unsupported + * 'matchingAnyTag' => unsupported + * + * @param string $mode clean mode + * @param array $tags array of tags + * @throws Zend_Cache_Exception + * @return boolean true if no problem + */ + public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) + { + switch ($mode) { + case Zend_Cache::CLEANING_MODE_ALL: + $this->_clear(); + return true; + break; + case Zend_Cache::CLEANING_MODE_OLD: + $this->_log("Zend_Cache_Backend_ZendServer::clean() : CLEANING_MODE_OLD is unsupported by the Zend Server backends."); + break; + case Zend_Cache::CLEANING_MODE_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: + case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: + $this->_clear(); + $this->_log('Zend_Cache_Backend_ZendServer::clean() : tags are unsupported by the Zend Server backends.'); + break; + default: + Zend_Cache::throwException('Invalid mode for clean() method'); + break; + } + } +} diff --git a/library/vendor/Zend/Cache/Backend/ZendServer/Disk.php b/library/vendor/Zend/Cache/Backend/ZendServer/Disk.php new file mode 100755 index 000000000..017f7d859 --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendServer/Disk.php @@ -0,0 +1,99 @@ +_options['namespace'] . '::' . $id, + $data, + $timeToLive) === false) { + $this->_log('Store operation failed.'); + return false; + } + return true; + } + + /** + * Fetch data + * + * @param string $id Cache id + * @return mixed|null + */ + protected function _fetch($id) + { + return zend_disk_cache_fetch($this->_options['namespace'] . '::' . $id); + } + + /** + * Unset data + * + * @param string $id Cache id + * @return boolean true if no problem + */ + protected function _unset($id) + { + return zend_disk_cache_delete($this->_options['namespace'] . '::' . $id); + } + + /** + * Clear cache + */ + protected function _clear() + { + zend_disk_cache_clear($this->_options['namespace']); + } +} diff --git a/library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php b/library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php new file mode 100755 index 000000000..7884362ca --- /dev/null +++ b/library/vendor/Zend/Cache/Backend/ZendServer/ShMem.php @@ -0,0 +1,99 @@ +_options['namespace'] . '::' . $id, + $data, + $timeToLive) === false) { + $this->_log('Store operation failed.'); + return false; + } + return true; + } + + /** + * Fetch data + * + * @param string $id Cache id + * @return mixed|null + */ + protected function _fetch($id) + { + return zend_shm_cache_fetch($this->_options['namespace'] . '::' . $id); + } + + /** + * Unset data + * + * @param string $id Cache id + * @return boolean true if no problem + */ + protected function _unset($id) + { + return zend_shm_cache_delete($this->_options['namespace'] . '::' . $id); + } + + /** + * Clear cache + */ + protected function _clear() + { + zend_shm_cache_clear($this->_options['namespace']); + } +} diff --git a/library/vendor/Zend/Cache/Core.php b/library/vendor/Zend/Cache/Core.php new file mode 100644 index 000000000..7a9626f2b --- /dev/null +++ b/library/vendor/Zend/Cache/Core.php @@ -0,0 +1,762 @@ + (boolean) write_control : + * - Enable / disable write control (the cache is read just after writing to detect corrupt entries) + * - Enable write control will lightly slow the cache writing but not the cache reading + * Write control can detect some corrupt cache files but maybe it's not a perfect control + * + * ====> (boolean) caching : + * - Enable / disable caching + * (can be very useful for the debug of cached scripts) + * + * =====> (string) cache_id_prefix : + * - prefix for cache ids (namespace) + * + * ====> (boolean) automatic_serialization : + * - Enable / disable automatic serialization + * - It can be used to save directly datas which aren't strings (but it's slower) + * + * ====> (int) automatic_cleaning_factor : + * - Disable / Tune the automatic cleaning process + * - The automatic cleaning process destroy too old (for the given life time) + * cache files when a new cache file is written : + * 0 => no automatic cache cleaning + * 1 => systematic cache cleaning + * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write + * + * ====> (int) lifetime : + * - Cache lifetime (in seconds) + * - If null, the cache is valid forever. + * + * ====> (boolean) logging : + * - If set to true, logging is activated (but the system is slower) + * + * ====> (boolean) ignore_user_abort + * - If set to true, the core will set the ignore_user_abort PHP flag inside the + * save() method to avoid cache corruptions in some cases (default false) + * + * @var array $_options available options + */ + protected $_options = array( + 'write_control' => true, + 'caching' => true, + 'cache_id_prefix' => null, + 'automatic_serialization' => false, + 'automatic_cleaning_factor' => 10, + 'lifetime' => 3600, + 'logging' => false, + 'logger' => null, + 'ignore_user_abort' => false + ); + + /** + * Array of options which have to be transfered to backend + * + * @var array $_directivesList + */ + protected static $_directivesList = array('lifetime', 'logging', 'logger'); + + /** + * Not used for the core, just a sort a hint to get a common setOption() method (for the core and for frontends) + * + * @var array $_specificOptions + */ + protected $_specificOptions = array(); + + /** + * Last used cache id + * + * @var string $_lastId + */ + private $_lastId = null; + + /** + * True if the backend implements Zend_Cache_Backend_ExtendedInterface + * + * @var boolean $_extendedBackend + */ + protected $_extendedBackend = false; + + /** + * Array of capabilities of the backend (only if it implements Zend_Cache_Backend_ExtendedInterface) + * + * @var array + */ + protected $_backendCapabilities = array(); + + /** + * Constructor + * + * @param array|Zend_Config $options Associative array of options or Zend_Config instance + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + if (!is_array($options)) { + Zend_Cache::throwException("Options passed were not an array" + . " or Zend_Config instance."); + } + while (list($name, $value) = each($options)) { + $this->setOption($name, $value); + } + $this->_loggerSanity(); + } + + /** + * Set options using an instance of type Zend_Config + * + * @param Zend_Config $config + * @return Zend_Cache_Core + */ + public function setConfig(Zend_Config $config) + { + $options = $config->toArray(); + while (list($name, $value) = each($options)) { + $this->setOption($name, $value); + } + return $this; + } + + /** + * Set the backend + * + * @param Zend_Cache_Backend $backendObject + * @throws Zend_Cache_Exception + * @return void + */ + public function setBackend(Zend_Cache_Backend $backendObject) + { + $this->_backend= $backendObject; + // some options (listed in $_directivesList) have to be given + // to the backend too (even if they are not "backend specific") + $directives = array(); + foreach (Zend_Cache_Core::$_directivesList as $directive) { + $directives[$directive] = $this->_options[$directive]; + } + $this->_backend->setDirectives($directives); + if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) { + $this->_extendedBackend = true; + $this->_backendCapabilities = $this->_backend->getCapabilities(); + } + + } + + /** + * Returns the backend + * + * @return Zend_Cache_Backend backend object + */ + public function getBackend() + { + return $this->_backend; + } + + /** + * Public frontend to set an option + * + * There is an additional validation (relatively to the protected _setOption method) + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if (!is_string($name)) { + Zend_Cache::throwException("Incorrect option name!"); + } + $name = strtolower($name); + if (array_key_exists($name, $this->_options)) { + // This is a Core option + $this->_setOption($name, $value); + return; + } + if (array_key_exists($name, $this->_specificOptions)) { + // This a specic option of this frontend + $this->_specificOptions[$name] = $value; + return; + } + } + + /** + * Public frontend to get an option value + * + * @param string $name Name of the option + * @throws Zend_Cache_Exception + * @return mixed option value + */ + public function getOption($name) + { + $name = strtolower($name); + + if (array_key_exists($name, $this->_options)) { + // This is a Core option + return $this->_options[$name]; + } + + if (array_key_exists($name, $this->_specificOptions)) { + // This a specic option of this frontend + return $this->_specificOptions[$name]; + } + + Zend_Cache::throwException("Incorrect option name : $name"); + } + + /** + * Set an option + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + private function _setOption($name, $value) + { + if (!is_string($name) || !array_key_exists($name, $this->_options)) { + Zend_Cache::throwException("Incorrect option name : $name"); + } + if ($name == 'lifetime' && empty($value)) { + $value = null; + } + $this->_options[$name] = $value; + } + + /** + * Force a new lifetime + * + * The new value is set for the core/frontend but for the backend too (directive) + * + * @param int $newLifetime New lifetime (in seconds) + * @return void + */ + public function setLifetime($newLifetime) + { + $this->_options['lifetime'] = $newLifetime; + $this->_backend->setDirectives(array( + 'lifetime' => $newLifetime + )); + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use + * @return mixed|false Cached datas + */ + public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false) + { + if (!$this->_options['caching']) { + return false; + } + $id = $this->_id($id); // cache id may need prefix + $this->_lastId = $id; + self::_validateIdOrTag($id); + + $this->_log("Zend_Cache_Core: load item '{$id}'", 7); + $data = $this->_backend->load($id, $doNotTestCacheValidity); + if ($data===false) { + // no cache available + return false; + } + if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) { + // we need to unserialize before sending the result + return unserialize($data); + } + return $data; + } + + /** + * Test if a cache is available for the given id + * + * @param string $id Cache id + * @return int|false Last modified time of cache entry if it is available, false otherwise + */ + public function test($id) + { + if (!$this->_options['caching']) { + return false; + } + $id = $this->_id($id); // cache id may need prefix + self::_validateIdOrTag($id); + $this->_lastId = $id; + + $this->_log("Zend_Cache_Core: test item '{$id}'", 7); + return $this->_backend->test($id); + } + + /** + * Save some data in a cache + * + * @param mixed $data Data to put in cache (can be another type than string if automatic_serialization is on) + * @param string $id Cache id (if not set, the last cache id will be used) + * @param array $tags Cache tags + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @throws Zend_Cache_Exception + * @return boolean True if no problem + */ + public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8) + { + if (!$this->_options['caching']) { + return true; + } + if ($id === null) { + $id = $this->_lastId; + } else { + $id = $this->_id($id); + } + self::_validateIdOrTag($id); + self::_validateTagsArray($tags); + if ($this->_options['automatic_serialization']) { + // we need to serialize datas before storing them + $data = serialize($data); + } else { + if (!is_string($data)) { + Zend_Cache::throwException("Datas must be string or set automatic_serialization = true"); + } + } + + // automatic cleaning + if ($this->_options['automatic_cleaning_factor'] > 0) { + $rand = rand(1, $this->_options['automatic_cleaning_factor']); + if ($rand==1) { + // new way || deprecated way + if ($this->_extendedBackend || method_exists($this->_backend, 'isAutomaticCleaningAvailable')) { + $this->_log("Zend_Cache_Core::save(): automatic cleaning running", 7); + $this->clean(Zend_Cache::CLEANING_MODE_OLD); + } else { + $this->_log("Zend_Cache_Core::save(): automatic cleaning is not available/necessary with current backend", 4); + } + } + } + + $this->_log("Zend_Cache_Core: save item '{$id}'", 7); + if ($this->_options['ignore_user_abort']) { + $abort = ignore_user_abort(true); + } + if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) { + $result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority); + } else { + $result = $this->_backend->save($data, $id, $tags, $specificLifetime); + } + if ($this->_options['ignore_user_abort']) { + ignore_user_abort($abort); + } + + if (!$result) { + // maybe the cache is corrupted, so we remove it ! + $this->_log("Zend_Cache_Core::save(): failed to save item '{$id}' -> removing it", 4); + $this->_backend->remove($id); + return false; + } + + if ($this->_options['write_control']) { + $data2 = $this->_backend->load($id, true); + if ($data!=$data2) { + $this->_log("Zend_Cache_Core::save(): write control of item '{$id}' failed -> removing it", 4); + $this->_backend->remove($id); + return false; + } + } + + return true; + } + + /** + * Remove a cache + * + * @param string $id Cache id to remove + * @return boolean True if ok + */ + public function remove($id) + { + if (!$this->_options['caching']) { + return true; + } + $id = $this->_id($id); // cache id may need prefix + self::_validateIdOrTag($id); + + $this->_log("Zend_Cache_Core: remove item '{$id}'", 7); + return $this->_backend->remove($id); + } + + /** + * Clean cache entries + * + * Available modes are : + * 'all' (default) => remove all cache entries ($tags is not used) + * 'old' => remove too old cache entries ($tags is not used) + * 'matchingTag' => remove cache entries matching all given tags + * ($tags can be an array of strings or a single string) + * 'notMatchingTag' => remove cache entries not matching one of the given tags + * ($tags can be an array of strings or a single string) + * 'matchingAnyTag' => remove cache entries matching any given tags + * ($tags can be an array of strings or a single string) + * + * @param string $mode + * @param array|string $tags + * @throws Zend_Cache_Exception + * @return boolean True if ok + */ + public function clean($mode = 'all', $tags = array()) + { + if (!$this->_options['caching']) { + return true; + } + if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL, + Zend_Cache::CLEANING_MODE_OLD, + Zend_Cache::CLEANING_MODE_MATCHING_TAG, + Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG, + Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) { + Zend_Cache::throwException('Invalid cleaning mode'); + } + self::_validateTagsArray($tags); + + return $this->_backend->clean($mode, $tags); + } + + /** + * Return an array of stored cache ids which match given tags + * + * In case of multiple tags, a logical AND is made between tags + * + * @param array $tags array of tags + * @return array array of matching cache ids (string) + */ + public function getIdsMatchingTags($tags = array()) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + + $ids = $this->_backend->getIdsMatchingTags($tags); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored cache ids which don't match given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of not matching cache ids (string) + */ + public function getIdsNotMatchingTags($tags = array()) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + + $ids = $this->_backend->getIdsNotMatchingTags($tags); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored cache ids which match any given tags + * + * In case of multiple tags, a logical OR is made between tags + * + * @param array $tags array of tags + * @return array array of matching any cache ids (string) + */ + public function getIdsMatchingAnyTags($tags = array()) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + + $ids = $this->_backend->getIdsMatchingAnyTags($tags); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored cache ids + * + * @return array array of stored cache ids (string) + */ + public function getIds() + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + + $ids = $this->_backend->getIds(); + + // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600) + if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') { + $prefix = & $this->_options['cache_id_prefix']; + $prefixLen = strlen($prefix); + foreach ($ids as &$id) { + if (strpos($id, $prefix) === 0) { + $id = substr($id, $prefixLen); + } + } + } + + return $ids; + } + + /** + * Return an array of stored tags + * + * @return array array of stored tags (string) + */ + public function getTags() + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + if (!($this->_backendCapabilities['tags'])) { + Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG); + } + return $this->_backend->getTags(); + } + + /** + * Return the filling percentage of the backend storage + * + * @return int integer between 0 and 100 + */ + public function getFillingPercentage() + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + return $this->_backend->getFillingPercentage(); + } + + /** + * Return an array of metadatas for the given cache id + * + * The array will include these keys : + * - expire : the expire timestamp + * - tags : a string array of tags + * - mtime : timestamp of last modification time + * + * @param string $id cache id + * @return array array of metadatas (false if the cache id is not found) + */ + public function getMetadatas($id) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + $id = $this->_id($id); // cache id may need prefix + return $this->_backend->getMetadatas($id); + } + + /** + * Give (if possible) an extra lifetime to the given cache id + * + * @param string $id cache id + * @param int $extraLifetime + * @return boolean true if ok + */ + public function touch($id, $extraLifetime) + { + if (!$this->_extendedBackend) { + Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF); + } + $id = $this->_id($id); // cache id may need prefix + + $this->_log("Zend_Cache_Core: touch item '{$id}'", 7); + return $this->_backend->touch($id, $extraLifetime); + } + + /** + * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...) + * + * Throw an exception if a problem is found + * + * @param string $string Cache id or tag + * @throws Zend_Cache_Exception + * @return void + */ + protected static function _validateIdOrTag($string) + { + if (!is_string($string)) { + Zend_Cache::throwException('Invalid id or tag : must be a string'); + } + if (substr($string, 0, 9) == 'internal-') { + Zend_Cache::throwException('"internal-*" ids or tags are reserved'); + } + if (!preg_match('~^[a-zA-Z0-9_]+$~D', $string)) { + Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]"); + } + } + + /** + * Validate a tags array (security, reliable filenames, reserved prefixes...) + * + * Throw an exception if a problem is found + * + * @param array $tags Array of tags + * @throws Zend_Cache_Exception + * @return void + */ + protected static function _validateTagsArray($tags) + { + if (!is_array($tags)) { + Zend_Cache::throwException('Invalid tags array : must be an array'); + } + foreach($tags as $tag) { + self::_validateIdOrTag($tag); + } + reset($tags); + } + + /** + * Make sure if we enable logging that the Zend_Log class + * is available. + * Create a default log object if none is set. + * + * @throws Zend_Cache_Exception + * @return void + */ + protected function _loggerSanity() + { + if (!isset($this->_options['logging']) || !$this->_options['logging']) { + return; + } + + if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) { + return; + } + + // Create a default logger to the standard output stream + $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output')); + $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<=')); + $this->_options['logger'] = $logger; + } + + /** + * Log a message at the WARN (4) priority. + * + * @param string $message + * @throws Zend_Cache_Exception + * @return void + */ + protected function _log($message, $priority = 4) + { + if (!$this->_options['logging']) { + return; + } + if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) { + Zend_Cache::throwException('Logging is enabled but logger is not set'); + } + $logger = $this->_options['logger']; + $logger->log($message, $priority); + } + + /** + * Make and return a cache id + * + * Checks 'cache_id_prefix' and returns new id with prefix or simply the id if null + * + * @param string $id Cache id + * @return string Cache id (with or without prefix) + */ + protected function _id($id) + { + if (($id !== null) && isset($this->_options['cache_id_prefix'])) { + return $this->_options['cache_id_prefix'] . $id; // return with prefix + } + return $id; // no prefix, just return the $id passed + } + +} diff --git a/library/vendor/Zend/Cache/Exception.php b/library/vendor/Zend/Cache/Exception.php new file mode 100644 index 000000000..3a0fde23f --- /dev/null +++ b/library/vendor/Zend/Cache/Exception.php @@ -0,0 +1,31 @@ +_tags = $tags; + $this->_extension = $extension; + ob_start(array($this, '_flush')); + ob_implicit_flush(false); + $this->_idStack[] = $id; + return false; + } + + /** + * callback for output buffering + * (shouldn't really be called manually) + * + * @param string $data Buffered output + * @return string Data to send to browser + */ + public function _flush($data) + { + $id = array_pop($this->_idStack); + if ($id === null) { + Zend_Cache::throwException('use of _flush() without a start()'); + } + if ($this->_extension) { + $this->save(serialize(array($data, $this->_extension)), $id, $this->_tags); + } else { + $this->save($data, $id, $this->_tags); + } + return $data; + } +} diff --git a/library/vendor/Zend/Cache/Frontend/Class.php b/library/vendor/Zend/Cache/Frontend/Class.php new file mode 100644 index 000000000..af584d17e --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Class.php @@ -0,0 +1,274 @@ + (mixed) cached_entity : + * - if set to a class name, we will cache an abstract class and will use only static calls + * - if set to an object, we will cache this object methods + * + * ====> (boolean) cache_by_default : + * - if true, method calls will be cached by default + * + * ====> (array) cached_methods : + * - an array of method names which will be cached (even if cache_by_default = false) + * + * ====> (array) non_cached_methods : + * - an array of method names which won't be cached (even if cache_by_default = true) + * + * @var array available options + */ + protected $_specificOptions = array( + 'cached_entity' => null, + 'cache_by_default' => true, + 'cached_methods' => array(), + 'non_cached_methods' => array() + ); + + /** + * Tags array + * + * @var array + */ + protected $_tags = array(); + + /** + * SpecificLifetime value + * + * false => no specific life time + * + * @var bool|int + */ + protected $_specificLifetime = false; + + /** + * The cached object or the name of the cached abstract class + * + * @var mixed + */ + protected $_cachedEntity = null; + + /** + * The class name of the cached object or cached abstract class + * + * Used to differentiate between different classes with the same method calls. + * + * @var string + */ + protected $_cachedEntityLabel = ''; + + /** + * Priority (used by some particular backends) + * + * @var int + */ + protected $_priority = 8; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_Cache_Exception + */ + public function __construct(array $options = array()) + { + while (list($name, $value) = each($options)) { + $this->setOption($name, $value); + } + if ($this->_specificOptions['cached_entity'] === null) { + Zend_Cache::throwException('cached_entity must be set !'); + } + $this->setCachedEntity($this->_specificOptions['cached_entity']); + $this->setOption('automatic_serialization', true); + } + + /** + * Set a specific life time + * + * @param bool|int $specificLifetime + * @return void + */ + public function setSpecificLifetime($specificLifetime = false) + { + $this->_specificLifetime = $specificLifetime; + } + + /** + * Set the priority (used by some particular backends) + * + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) + */ + public function setPriority($priority) + { + $this->_priority = $priority; + } + + /** + * Public frontend to set an option + * + * Just a wrapper to get a specific behaviour for cached_entity + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if ($name == 'cached_entity') { + $this->setCachedEntity($value); + } else { + parent::setOption($name, $value); + } + } + + /** + * Specific method to set the cachedEntity + * + * if set to a class name, we will cache an abstract class and will use only static calls + * if set to an object, we will cache this object methods + * + * @param mixed $cachedEntity + */ + public function setCachedEntity($cachedEntity) + { + if (!is_string($cachedEntity) && !is_object($cachedEntity)) { + Zend_Cache::throwException( + 'cached_entity must be an object or a class name' + ); + } + + $this->_cachedEntity = $cachedEntity; + $this->_specificOptions['cached_entity'] = $cachedEntity; + + if (is_string($this->_cachedEntity)) { + $this->_cachedEntityLabel = $this->_cachedEntity; + } else { + $ro = new ReflectionObject($this->_cachedEntity); + $this->_cachedEntityLabel = $ro->getName(); + } + } + + /** + * Set the cache array + * + * @param array $tags + * @return void + */ + public function setTagsArray($tags = array()) + { + $this->_tags = $tags; + } + + /** + * Main method : call the specified method or get the result from cache + * + * @param string $name Method name + * @param array $parameters Method parameters + * @return mixed Result + * @throws Exception + */ + public function __call($name, $parameters) + { + $callback = array($this->_cachedEntity, $name); + + if (!is_callable($callback, false)) { + Zend_Cache::throwException('Invalid callback'); + } + + $cacheBool1 = $this->_specificOptions['cache_by_default']; + $cacheBool2 = in_array($name, $this->_specificOptions['cached_methods']); + $cacheBool3 = in_array($name, $this->_specificOptions['non_cached_methods']); + $cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3)); + + if (!$cache) { + // We do not have not cache + return call_user_func_array($callback, $parameters); + } + + $id = $this->makeId($name, $parameters); + if (($rs = $this->load($id)) && (array_key_exists(0, $rs)) + && (array_key_exists(1, $rs)) + ) { + // A cache is available + $output = $rs[0]; + $return = $rs[1]; + } else { + // A cache is not available (or not valid for this frontend) + ob_start(); + ob_implicit_flush(false); + + try { + $return = call_user_func_array($callback, $parameters); + $output = ob_get_clean(); + $data = array($output, $return); + + $this->save( + $data, $id, $this->_tags, $this->_specificLifetime, + $this->_priority + ); + } catch (Exception $e) { + ob_end_clean(); + throw $e; + } + } + + echo $output; + return $return; + } + + /** + * ZF-9970 + * + * @deprecated + */ + private function _makeId($name, $args) + { + return $this->makeId($name, $args); + } + + /** + * Make a cache id from the method name and parameters + * + * @param string $name Method name + * @param array $args Method parameters + * @return string Cache id + */ + public function makeId($name, array $args = array()) + { + return md5($this->_cachedEntityLabel . '__' . $name . '__' . serialize($args)); + } +} diff --git a/library/vendor/Zend/Cache/Frontend/File.php b/library/vendor/Zend/Cache/Frontend/File.php new file mode 100644 index 000000000..31edc38b2 --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/File.php @@ -0,0 +1,221 @@ + (string) master_file : + * - a complete path of the master file + * - deprecated (see master_files) + * + * ====> (array) master_files : + * - an array of complete path of master files + * - this option has to be set ! + * + * ====> (string) master_files_mode : + * - Zend_Cache_Frontend_File::MODE_AND or Zend_Cache_Frontend_File::MODE_OR + * - if MODE_AND, then all master files have to be touched to get a cache invalidation + * - if MODE_OR (default), then a single touched master file is enough to get a cache invalidation + * + * ====> (boolean) ignore_missing_master_files + * - if set to true, missing master files are ignored silently + * - if set to false (default), an exception is thrown if there is a missing master file + * @var array available options + */ + protected $_specificOptions = array( + 'master_file' => null, + 'master_files' => null, + 'master_files_mode' => 'OR', + 'ignore_missing_master_files' => false + ); + + /** + * Master file mtimes + * + * Array of int + * + * @var array + */ + private $_masterFile_mtimes = null; + + /** + * Constructor + * + * @param array $options Associative array of options + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + while (list($name, $value) = each($options)) { + $this->setOption($name, $value); + } + if (!isset($this->_specificOptions['master_files'])) { + Zend_Cache::throwException('master_files option must be set'); + } + } + + /** + * Change the master_files option + * + * @param array $masterFiles the complete paths and name of the master files + */ + public function setMasterFiles(array $masterFiles) + { + $this->_specificOptions['master_file'] = null; // to keep a compatibility + $this->_specificOptions['master_files'] = null; + $this->_masterFile_mtimes = array(); + + clearstatcache(); + $i = 0; + foreach ($masterFiles as $masterFile) { + if (file_exists($masterFile)) { + $mtime = filemtime($masterFile); + } else { + $mtime = false; + } + + if (!$this->_specificOptions['ignore_missing_master_files'] && !$mtime) { + Zend_Cache::throwException('Unable to read master_file : ' . $masterFile); + } + + $this->_masterFile_mtimes[$i] = $mtime; + $this->_specificOptions['master_files'][$i] = $masterFile; + if ($i === 0) { // to keep a compatibility + $this->_specificOptions['master_file'] = $masterFile; + } + + $i++; + } + } + + /** + * Change the master_file option + * + * To keep the compatibility + * + * @deprecated + * @param string $masterFile the complete path and name of the master file + */ + public function setMasterFile($masterFile) + { + $this->setMasterFiles(array($masterFile)); + } + + /** + * Public frontend to set an option + * + * Just a wrapper to get a specific behaviour for master_file + * + * @param string $name Name of the option + * @param mixed $value Value of the option + * @throws Zend_Cache_Exception + * @return void + */ + public function setOption($name, $value) + { + if ($name == 'master_file') { + $this->setMasterFile($value); + } else if ($name == 'master_files') { + $this->setMasterFiles($value); + } else { + parent::setOption($name, $value); + } + } + + /** + * Test if a cache is available for the given id and (if yes) return it (false else) + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use + * @return mixed|false Cached datas + */ + public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false) + { + if (!$doNotTestCacheValidity) { + if ($this->test($id)) { + return parent::load($id, true, $doNotUnserialize); + } + return false; + } + return parent::load($id, true, $doNotUnserialize); + } + + /** + * Test if a cache is available for the given id + * + * @param string $id Cache id + * @return int|false Last modified time of cache entry if it is available, false otherwise + */ + public function test($id) + { + $lastModified = parent::test($id); + if ($lastModified) { + if ($this->_specificOptions['master_files_mode'] == self::MODE_AND) { + // MODE_AND + foreach($this->_masterFile_mtimes as $masterFileMTime) { + if ($masterFileMTime) { + if ($lastModified > $masterFileMTime) { + return $lastModified; + } + } + } + } else { + // MODE_OR + $res = true; + foreach($this->_masterFile_mtimes as $masterFileMTime) { + if ($masterFileMTime) { + if ($lastModified <= $masterFileMTime) { + return false; + } + } + } + return $lastModified; + } + } + return false; + } + +} + diff --git a/library/vendor/Zend/Cache/Frontend/Function.php b/library/vendor/Zend/Cache/Frontend/Function.php new file mode 100644 index 000000000..ca09ee3f5 --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Function.php @@ -0,0 +1,178 @@ + (boolean) cache_by_default : + * - if true, function calls will be cached by default + * + * ====> (array) cached_functions : + * - an array of function names which will be cached (even if cache_by_default = false) + * + * ====> (array) non_cached_functions : + * - an array of function names which won't be cached (even if cache_by_default = true) + * + * @var array options + */ + protected $_specificOptions = array( + 'cache_by_default' => true, + 'cached_functions' => array(), + 'non_cached_functions' => array() + ); + + /** + * Constructor + * + * @param array $options Associative array of options + * @return void + */ + public function __construct(array $options = array()) + { + while (list($name, $value) = each($options)) { + $this->setOption($name, $value); + } + $this->setOption('automatic_serialization', true); + } + + /** + * Main method : call the specified function or get the result from cache + * + * @param callback $callback A valid callback + * @param array $parameters Function parameters + * @param array $tags Cache tags + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @return mixed Result + */ + public function call($callback, array $parameters = array(), $tags = array(), $specificLifetime = false, $priority = 8) + { + if (!is_callable($callback, true, $name)) { + Zend_Cache::throwException('Invalid callback'); + } + + $cacheBool1 = $this->_specificOptions['cache_by_default']; + $cacheBool2 = in_array($name, $this->_specificOptions['cached_functions']); + $cacheBool3 = in_array($name, $this->_specificOptions['non_cached_functions']); + $cache = (($cacheBool1 || $cacheBool2) && (!$cacheBool3)); + if (!$cache) { + // Caching of this callback is disabled + return call_user_func_array($callback, $parameters); + } + + $id = $this->_makeId($callback, $parameters); + if ( ($rs = $this->load($id)) && isset($rs[0], $rs[1])) { + // A cache is available + $output = $rs[0]; + $return = $rs[1]; + } else { + // A cache is not available (or not valid for this frontend) + ob_start(); + ob_implicit_flush(false); + $return = call_user_func_array($callback, $parameters); + $output = ob_get_clean(); + $data = array($output, $return); + $this->save($data, $id, $tags, $specificLifetime, $priority); + } + + echo $output; + return $return; + } + + /** + * ZF-9970 + * + * @deprecated + */ + private function _makeId($callback, array $args) + { + return $this->makeId($callback, $args); + } + + /** + * Make a cache id from the function name and parameters + * + * @param callback $callback A valid callback + * @param array $args Function parameters + * @throws Zend_Cache_Exception + * @return string Cache id + */ + public function makeId($callback, array $args = array()) + { + if (!is_callable($callback, true, $name)) { + Zend_Cache::throwException('Invalid callback'); + } + + // functions, methods and classnames are case-insensitive + $name = strtolower($name); + + // generate a unique id for object callbacks + if (is_object($callback)) { // Closures & __invoke + $object = $callback; + } elseif (isset($callback[0])) { // array($object, 'method') + $object = $callback[0]; + } + if (isset($object)) { + try { + $tmp = @serialize($callback); + } catch (Exception $e) { + Zend_Cache::throwException($e->getMessage()); + } + if (!$tmp) { + $lastErr = error_get_last(); + Zend_Cache::throwException("Can't serialize callback object to generate id: {$lastErr['message']}"); + } + $name.= '__' . $tmp; + } + + // generate a unique id for arguments + $argsStr = ''; + if ($args) { + try { + $argsStr = @serialize(array_values($args)); + } catch (Exception $e) { + Zend_Cache::throwException($e->getMessage()); + } + if (!$argsStr) { + $lastErr = error_get_last(); + throw Zend_Cache::throwException("Can't serialize arguments to generate id: {$lastErr['message']}"); + } + } + + return md5($name . $argsStr); + } + +} diff --git a/library/vendor/Zend/Cache/Frontend/Output.php b/library/vendor/Zend/Cache/Frontend/Output.php new file mode 100644 index 000000000..115b5dd1c --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Output.php @@ -0,0 +1,104 @@ +_idStack = array(); + } + + /** + * Start the cache + * + * @param string $id Cache id + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @param boolean $echoData If set to true, datas are sent to the browser if the cache is hit (simply returned else) + * @return mixed True if the cache is hit (false else) with $echoData=true (default) ; string else (datas) + */ + public function start($id, $doNotTestCacheValidity = false, $echoData = true) + { + $data = $this->load($id, $doNotTestCacheValidity); + if ($data !== false) { + if ( $echoData ) { + echo($data); + return true; + } else { + return $data; + } + } + ob_start(); + ob_implicit_flush(false); + $this->_idStack[] = $id; + return false; + } + + /** + * Stop the cache + * + * @param array $tags Tags array + * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) + * @param string $forcedDatas If not null, force written datas with this + * @param boolean $echoData If set to true, datas are sent to the browser + * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends + * @return void + */ + public function end($tags = array(), $specificLifetime = false, $forcedDatas = null, $echoData = true, $priority = 8) + { + if ($forcedDatas === null) { + $data = ob_get_clean(); + } else { + $data =& $forcedDatas; + } + $id = array_pop($this->_idStack); + if ($id === null) { + Zend_Cache::throwException('use of end() without a start()'); + } + $this->save($data, $id, $tags, $specificLifetime, $priority); + if ($echoData) { + echo($data); + } + } + +} diff --git a/library/vendor/Zend/Cache/Frontend/Page.php b/library/vendor/Zend/Cache/Frontend/Page.php new file mode 100644 index 000000000..f08595dbb --- /dev/null +++ b/library/vendor/Zend/Cache/Frontend/Page.php @@ -0,0 +1,403 @@ + (boolean) http_conditional : + * - if true, http conditional mode is on + * WARNING : http_conditional OPTION IS NOT IMPLEMENTED FOR THE MOMENT (TODO) + * + * ====> (boolean) debug_header : + * - if true, a debug text is added before each cached pages + * + * ====> (boolean) content_type_memorization : + * - deprecated => use memorize_headers instead + * - if the Content-Type header is sent after the cache was started, the + * corresponding value can be memorized and replayed when the cache is hit + * (if false (default), the frontend doesn't take care of Content-Type header) + * + * ====> (array) memorize_headers : + * - an array of strings corresponding to some HTTP headers name. Listed headers + * will be stored with cache datas and "replayed" when the cache is hit + * + * ====> (array) default_options : + * - an associative array of default options : + * - (boolean) cache : cache is on by default if true + * - (boolean) cacheWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') : + * if true, cache is still on even if there are some variables in this superglobal array + * if false, cache is off if there are some variables in this superglobal array + * - (boolean) makeIdWithXXXVariables (XXXX = 'Get', 'Post', 'Session', 'Files' or 'Cookie') : + * if true, we have to use the content of this superglobal array to make a cache id + * if false, the cache id won't be dependent of the content of this superglobal array + * - (int) specific_lifetime : cache specific lifetime + * (false => global lifetime is used, null => infinite lifetime, + * integer => this lifetime is used), this "lifetime" is probably only + * usefull when used with "regexps" array + * - (array) tags : array of tags (strings) + * - (int) priority : integer between 0 (very low priority) and 10 (maximum priority) used by + * some particular backends + * + * ====> (array) regexps : + * - an associative array to set options only for some REQUEST_URI + * - keys are (pcre) regexps + * - values are associative array with specific options to set if the regexp matchs on $_SERVER['REQUEST_URI'] + * (see default_options for the list of available options) + * - if several regexps match the $_SERVER['REQUEST_URI'], only the last one will be used + * + * @var array options + */ + protected $_specificOptions = array( + 'http_conditional' => false, + 'debug_header' => false, + 'content_type_memorization' => false, + 'memorize_headers' => array(), + 'default_options' => array( + 'cache_with_get_variables' => false, + 'cache_with_post_variables' => false, + 'cache_with_session_variables' => false, + 'cache_with_files_variables' => false, + 'cache_with_cookie_variables' => false, + 'make_id_with_get_variables' => true, + 'make_id_with_post_variables' => true, + 'make_id_with_session_variables' => true, + 'make_id_with_files_variables' => true, + 'make_id_with_cookie_variables' => true, + 'cache' => true, + 'specific_lifetime' => false, + 'tags' => array(), + 'priority' => null + ), + 'regexps' => array() + ); + + /** + * Internal array to store some options + * + * @var array associative array of options + */ + protected $_activeOptions = array(); + + /** + * If true, the page won't be cached + * + * @var boolean + */ + protected $_cancel = false; + + /** + * Constructor + * + * @param array $options Associative array of options + * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested + * @throws Zend_Cache_Exception + * @return void + */ + public function __construct(array $options = array()) + { + while (list($name, $value) = each($options)) { + $name = strtolower($name); + switch ($name) { + case 'regexps': + $this->_setRegexps($value); + break; + case 'default_options': + $this->_setDefaultOptions($value); + break; + case 'content_type_memorization': + $this->_setContentTypeMemorization($value); + break; + default: + $this->setOption($name, $value); + } + } + if (isset($this->_specificOptions['http_conditional'])) { + if ($this->_specificOptions['http_conditional']) { + Zend_Cache::throwException('http_conditional is not implemented for the moment !'); + } + } + $this->setOption('automatic_serialization', true); + } + + /** + * Specific setter for the 'default_options' option (with some additional tests) + * + * @param array $options Associative array + * @throws Zend_Cache_Exception + * @return void + */ + protected function _setDefaultOptions($options) + { + if (!is_array($options)) { + Zend_Cache::throwException('default_options must be an array !'); + } + foreach ($options as $key=>$value) { + if (!is_string($key)) { + Zend_Cache::throwException("invalid option [$key] !"); + } + $key = strtolower($key); + if (isset($this->_specificOptions['default_options'][$key])) { + $this->_specificOptions['default_options'][$key] = $value; + } + } + } + + /** + * Set the deprecated contentTypeMemorization option + * + * @param boolean $value value + * @return void + * @deprecated + */ + protected function _setContentTypeMemorization($value) + { + $found = null; + foreach ($this->_specificOptions['memorize_headers'] as $key => $value) { + if (strtolower($value) == 'content-type') { + $found = $key; + } + } + if ($value) { + if (!$found) { + $this->_specificOptions['memorize_headers'][] = 'Content-Type'; + } + } else { + if ($found) { + unset($this->_specificOptions['memorize_headers'][$found]); + } + } + } + + /** + * Specific setter for the 'regexps' option (with some additional tests) + * + * @param array $options Associative array + * @throws Zend_Cache_Exception + * @return void + */ + protected function _setRegexps($regexps) + { + if (!is_array($regexps)) { + Zend_Cache::throwException('regexps option must be an array !'); + } + foreach ($regexps as $regexp=>$conf) { + if (!is_array($conf)) { + Zend_Cache::throwException('regexps option must be an array of arrays !'); + } + $validKeys = array_keys($this->_specificOptions['default_options']); + foreach ($conf as $key=>$value) { + if (!is_string($key)) { + Zend_Cache::throwException("unknown option [$key] !"); + } + $key = strtolower($key); + if (!in_array($key, $validKeys)) { + unset($regexps[$regexp][$key]); + } + } + } + $this->setOption('regexps', $regexps); + } + + /** + * Start the cache + * + * @param string $id (optional) A cache id (if you set a value here, maybe you have to use Output frontend instead) + * @param boolean $doNotDie For unit testing only ! + * @return boolean True if the cache is hit (false else) + */ + public function start($id = false, $doNotDie = false) + { + $this->_cancel = false; + $lastMatchingRegexp = null; + if (isset($_SERVER['REQUEST_URI'])) { + foreach ($this->_specificOptions['regexps'] as $regexp => $conf) { + if (preg_match("`$regexp`", $_SERVER['REQUEST_URI'])) { + $lastMatchingRegexp = $regexp; + } + } + } + $this->_activeOptions = $this->_specificOptions['default_options']; + if ($lastMatchingRegexp !== null) { + $conf = $this->_specificOptions['regexps'][$lastMatchingRegexp]; + foreach ($conf as $key=>$value) { + $this->_activeOptions[$key] = $value; + } + } + if (!($this->_activeOptions['cache'])) { + return false; + } + if (!$id) { + $id = $this->_makeId(); + if (!$id) { + return false; + } + } + $array = $this->load($id); + if ($array !== false) { + $data = $array['data']; + $headers = $array['headers']; + if (!headers_sent()) { + foreach ($headers as $key=>$headerCouple) { + $name = $headerCouple[0]; + $value = $headerCouple[1]; + header("$name: $value"); + } + } + if ($this->_specificOptions['debug_header']) { + echo 'DEBUG HEADER : This is a cached page !'; + } + echo $data; + if ($doNotDie) { + return true; + } + die(); + } + ob_start(array($this, '_flush')); + ob_implicit_flush(false); + return false; + } + + /** + * Cancel the current caching process + */ + public function cancel() + { + $this->_cancel = true; + } + + /** + * callback for output buffering + * (shouldn't really be called manually) + * + * @param string $data Buffered output + * @return string Data to send to browser + */ + public function _flush($data) + { + if ($this->_cancel) { + return $data; + } + $contentType = null; + $storedHeaders = array(); + $headersList = headers_list(); + foreach($this->_specificOptions['memorize_headers'] as $key=>$headerName) { + foreach ($headersList as $headerSent) { + $tmp = explode(':', $headerSent); + $headerSentName = trim(array_shift($tmp)); + if (strtolower($headerName) == strtolower($headerSentName)) { + $headerSentValue = trim(implode(':', $tmp)); + $storedHeaders[] = array($headerSentName, $headerSentValue); + } + } + } + $array = array( + 'data' => $data, + 'headers' => $storedHeaders + ); + $this->save($array, null, $this->_activeOptions['tags'], $this->_activeOptions['specific_lifetime'], $this->_activeOptions['priority']); + return $data; + } + + /** + * Make an id depending on REQUEST_URI and superglobal arrays (depending on options) + * + * @return mixed|false a cache id (string), false if the cache should have not to be used + */ + protected function _makeId() + { + $tmp = $_SERVER['REQUEST_URI']; + $array = explode('?', $tmp, 2); + $tmp = $array[0]; + foreach (array('Get', 'Post', 'Session', 'Files', 'Cookie') as $arrayName) { + $tmp2 = $this->_makePartialId($arrayName, $this->_activeOptions['cache_with_' . strtolower($arrayName) . '_variables'], $this->_activeOptions['make_id_with_' . strtolower($arrayName) . '_variables']); + if ($tmp2===false) { + return false; + } + $tmp = $tmp . $tmp2; + } + return md5($tmp); + } + + /** + * Make a partial id depending on options + * + * @param string $arrayName Superglobal array name + * @param bool $bool1 If true, cache is still on even if there are some variables in the superglobal array + * @param bool $bool2 If true, we have to use the content of the superglobal array to make a partial id + * @return mixed|false Partial id (string) or false if the cache should have not to be used + */ + protected function _makePartialId($arrayName, $bool1, $bool2) + { + switch ($arrayName) { + case 'Get': + $var = $_GET; + break; + case 'Post': + $var = $_POST; + break; + case 'Session': + if (isset($_SESSION)) { + $var = $_SESSION; + } else { + $var = null; + } + break; + case 'Cookie': + if (isset($_COOKIE)) { + $var = $_COOKIE; + } else { + $var = null; + } + break; + case 'Files': + $var = $_FILES; + break; + default: + return false; + } + if ($bool1) { + if ($bool2) { + return serialize($var); + } + return ''; + } + if (count($var) > 0) { + return false; + } + return ''; + } + +} diff --git a/library/vendor/Zend/Cache/Manager.php b/library/vendor/Zend/Cache/Manager.php new file mode 100644 index 000000000..b7af8cf98 --- /dev/null +++ b/library/vendor/Zend/Cache/Manager.php @@ -0,0 +1,304 @@ + array( + 'frontend' => array( + 'name' => 'Core', + 'options' => array( + 'automatic_serialization' => true, + ), + ), + 'backend' => array( + 'name' => 'File', + 'options' => array( + // use system temp dir by default of file backend + // 'cache_dir' => '../cache', + ), + ), + ), + + // Static Page HTML Cache + 'page' => array( + 'frontend' => array( + 'name' => 'Capture', + 'options' => array( + 'ignore_user_abort' => true, + ), + ), + 'backend' => array( + 'name' => 'Static', + 'options' => array( + 'public_dir' => '../public', + ), + ), + ), + + // Tag Cache + 'pagetag' => array( + 'frontend' => array( + 'name' => 'Core', + 'options' => array( + 'automatic_serialization' => true, + 'lifetime' => null + ), + ), + 'backend' => array( + 'name' => 'File', + 'options' => array( + // use system temp dir by default of file backend + // 'cache_dir' => '../cache', + // use default umask of file backend + // 'cache_file_umask' => 0644 + ), + ), + ), + ); + + /** + * Set a new cache for the Cache Manager to contain + * + * @param string $name + * @param Zend_Cache_Core $cache + * @return Zend_Cache_Manager + */ + public function setCache($name, Zend_Cache_Core $cache) + { + $this->_caches[$name] = $cache; + return $this; + } + + /** + * Check if the Cache Manager contains the named cache object, or a named + * configuration template to lazy load the cache object + * + * @param string $name + * @return bool + */ + public function hasCache($name) + { + if (isset($this->_caches[$name]) + || $this->hasCacheTemplate($name) + ) { + return true; + } + return false; + } + + /** + * Fetch the named cache object, or instantiate and return a cache object + * using a named configuration template + * + * @param string $name + * @return Zend_Cache_Core + */ + public function getCache($name) + { + if (isset($this->_caches[$name])) { + return $this->_caches[$name]; + } + if (isset($this->_optionTemplates[$name])) { + if ($name == self::PAGECACHE + && (!isset($this->_optionTemplates[$name]['backend']['options']['tag_cache']) + || !$this->_optionTemplates[$name]['backend']['options']['tag_cache'] instanceof Zend_Cache_Core) + ) { + $this->_optionTemplates[$name]['backend']['options']['tag_cache'] + = $this->getCache(self::PAGETAGCACHE); + } + + $this->_caches[$name] = Zend_Cache::factory( + $this->_optionTemplates[$name]['frontend']['name'], + $this->_optionTemplates[$name]['backend']['name'], + isset($this->_optionTemplates[$name]['frontend']['options']) ? $this->_optionTemplates[$name]['frontend']['options'] : array(), + isset($this->_optionTemplates[$name]['backend']['options']) ? $this->_optionTemplates[$name]['backend']['options'] : array(), + isset($this->_optionTemplates[$name]['frontend']['customFrontendNaming']) ? $this->_optionTemplates[$name]['frontend']['customFrontendNaming'] : false, + isset($this->_optionTemplates[$name]['backend']['customBackendNaming']) ? $this->_optionTemplates[$name]['backend']['customBackendNaming'] : false, + isset($this->_optionTemplates[$name]['frontendBackendAutoload']) ? $this->_optionTemplates[$name]['frontendBackendAutoload'] : false + ); + + return $this->_caches[$name]; + } + } + + /** + * Fetch all available caches + * + * @return array An array of all available caches with it's names as key + */ + public function getCaches() + { + $caches = $this->_caches; + foreach ($this->_optionTemplates as $name => $tmp) { + if (!isset($caches[$name])) { + $caches[$name] = $this->getCache($name); + } + } + return $caches; + } + + /** + * Set a named configuration template from which a cache object can later + * be lazy loaded + * + * @param string $name + * @param array $options + * @return Zend_Cache_Manager + * @throws Zend_Cache_Exception + */ + public function setCacheTemplate($name, $options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + throw new Zend_Cache_Exception('Options passed must be in' + . ' an associative array or instance of Zend_Config'); + } + $this->_optionTemplates[$name] = $options; + return $this; + } + + /** + * Check if the named configuration template + * + * @param string $name + * @return bool + */ + public function hasCacheTemplate($name) + { + if (isset($this->_optionTemplates[$name])) { + return true; + } + return false; + } + + /** + * Get the named configuration template + * + * @param string $name + * @return array + */ + public function getCacheTemplate($name) + { + if (isset($this->_optionTemplates[$name])) { + return $this->_optionTemplates[$name]; + } + } + + /** + * Pass an array containing changes to be applied to a named + * configuration + * template + * + * @param string $name + * @param array $options + * @return Zend_Cache_Manager + * @throws Zend_Cache_Exception for invalid options format or if option templates do not have $name + */ + public function setTemplateOptions($name, $options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + throw new Zend_Cache_Exception('Options passed must be in' + . ' an associative array or instance of Zend_Config'); + } + if (!isset($this->_optionTemplates[$name])) { + throw new Zend_Cache_Exception('A cache configuration template' + . 'does not exist with the name "' . $name . '"'); + } + $this->_optionTemplates[$name] + = $this->_mergeOptions($this->_optionTemplates[$name], $options); + return $this; + } + + /** + * Simple method to merge two configuration arrays + * + * @param array $current + * @param array $options + * @return array + */ + protected function _mergeOptions(array $current, array $options) + { + if (isset($options['frontend']['name'])) { + $current['frontend']['name'] = $options['frontend']['name']; + } + if (isset($options['backend']['name'])) { + $current['backend']['name'] = $options['backend']['name']; + } + if (isset($options['frontend']['options'])) { + foreach ($options['frontend']['options'] as $key => $value) { + $current['frontend']['options'][$key] = $value; + } + } + if (isset($options['backend']['options'])) { + foreach ($options['backend']['options'] as $key => $value) { + $current['backend']['options'][$key] = $value; + } + } + if (isset($options['frontend']['customFrontendNaming'])) { + $current['frontend']['customFrontendNaming'] = $options['frontend']['customFrontendNaming']; + } + if (isset($options['backend']['customBackendNaming'])) { + $current['backend']['customBackendNaming'] = $options['backend']['customBackendNaming']; + } + if (isset($options['frontendBackendAutoload'])) { + $current['frontendBackendAutoload'] = $options['frontendBackendAutoload']; + } + return $current; + } +} diff --git a/library/vendor/Zend/Cloud/AbstractFactory.php b/library/vendor/Zend/Cloud/AbstractFactory.php new file mode 100755 index 000000000..aaf02a01d --- /dev/null +++ b/library/vendor/Zend/Cloud/AbstractFactory.php @@ -0,0 +1,66 @@ +toArray(); + } + + if (!isset($options[$adapterOption])) { + return null; + } + + $classname = $options[$adapterOption]; + unset($options[$adapterOption]); + if (!class_exists($classname)) { + Zend_Loader::loadClass($classname); + } + + return new $classname($options); + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/Adapter.php b/library/vendor/Zend/Cloud/DocumentService/Adapter.php new file mode 100644 index 000000000..756f662d0 --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Adapter.php @@ -0,0 +1,155 @@ +_documentClass = (string) $class; + return $this; + } + + /** + * Get the class for document objects + * + * @return string + */ + public function getDocumentClass() + { + return $this->_documentClass; + } + + /** + * Set the class for document set objects + * + * @param string $class + * @return Zend_Cloud_DocumentService_Adapter_AbstractAdapter + */ + public function setDocumentSetClass($class) + { + $this->_documentSetClass = (string) $class; + return $this; + } + + /** + * Get the class for document set objects + * + * @return string + */ + public function getDocumentSetClass() + { + return $this->_documentSetClass; + } + + /** + * Set the query class for query objects + * + * @param string $class + * @return Zend_Cloud_DocumentService_Adapter_AbstractAdapter + */ + public function setQueryClass($class) + { + $this->_queryClass = (string) $class; + return $this; + } + + /** + * Get the class for query objects + * + * @return string + */ + public function getQueryClass() + { + return $this->_queryClass; + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/Adapter/SimpleDb.php b/library/vendor/Zend/Cloud/DocumentService/Adapter/SimpleDb.php new file mode 100644 index 000000000..af96c917e --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Adapter/SimpleDb.php @@ -0,0 +1,462 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid options provided to constructor'); + } + + $this->_simpleDb = new Zend_Service_Amazon_SimpleDb( + $options[self::AWS_ACCESS_KEY], $options[self::AWS_SECRET_KEY] + ); + + if (isset($options[self::HTTP_ADAPTER])) { + $this->_simpleDb->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + + if (isset($options[self::DOCUMENT_CLASS])) { + $this->setDocumentClass($options[self::DOCUMENT_CLASS]); + } + + if (isset($options[self::DOCUMENTSET_CLASS])) { + $this->setDocumentSetClass($options[self::DOCUMENTSET_CLASS]); + } + + if (isset($options[self::QUERY_CLASS])) { + $this->setQueryClass($options[self::QUERY_CLASS]); + } + } + + /** + * Create collection. + * + * @param string $name + * @param array $options + * @return void + */ + public function createCollection($name, $options = null) + { + try { + $this->_simpleDb->createDomain($name); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on domain creation: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Delete collection. + * + * @param string $name + * @param array $options + * @return void + */ + public function deleteCollection($name, $options = null) + { + try { + $this->_simpleDb->deleteDomain($name); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on collection deletion: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * List collections. + * + * @param array $options + * @return array + */ + public function listCollections($options = null) + { + try { + // TODO package this in Pages + $domains = $this->_simpleDb->listDomains()->getData(); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on collection deletion: '.$e->getMessage(), $e->getCode(), $e); + } + + return $domains; + } + + /** + * List documents + * + * Returns a key/value array of document names to document objects. + * + * @param string $collectionName Name of collection for which to list documents + * @param array|null $options + * @return Zend_Cloud_DocumentService_DocumentSet + */ + public function listDocuments($collectionName, array $options = null) + { + $query = $this->select('*')->from($collectionName); + $items = $this->query($collectionName, $query, $options); + return $items; + } + + /** + * Insert document + * + * @param string $collectionName Collection into which to insert document + * @param array|Zend_Cloud_DocumentService_Document $document + * @param array $options + * @return void + */ + public function insertDocument($collectionName, $document, $options = null) + { + if (is_array($document)) { + $document = $this->_getDocumentFromArray($document); + } + + if (!$document instanceof Zend_Cloud_DocumentService_Document) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document supplied'); + } + + try { + $this->_simpleDb->putAttributes( + $collectionName, + $document->getID(), + $this->_makeAttributes($document->getID(), $document->getFields()) + ); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document insertion: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Replace an existing document with a new version + * + * @param string $collectionName + * @param array|Zend_Cloud_DocumentService_Document $document + * @param array $options + * @return void + */ + public function replaceDocument($collectionName, $document, $options = null) + { + if (is_array($document)) { + $document = $this->_getDocumentFromArray($document); + } + + if (!$document instanceof Zend_Cloud_DocumentService_Document) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document supplied'); + } + + // Delete document first, then insert. PutAttributes always keeps any + // fields not referenced in the payload, but present in the document + $documentId = $document->getId(); + $fields = $document->getFields(); + $docClass = get_class($document); + $this->deleteDocument($collectionName, $document, $options); + + $document = new $docClass($fields, $documentId); + $this->insertDocument($collectionName, $document); + } + + /** + * Update document. The new document replaces the existing document. + * + * Option 'merge' specifies to add all attributes (if true) or + * specific attributes ("attr" => true) instead of replacing them. + * By default, attributes are replaced. + * + * @param string $collectionName + * @param mixed|Zend_Cloud_DocumentService_Document $documentId Document ID, adapter-dependent + * @param array|Zend_Cloud_DocumentService_Document $fieldset Set of fields to update + * @param array $options + * @return boolean + */ + public function updateDocument($collectionName, $documentId, $fieldset = null, $options = null) + { + if (null === $fieldset && $documentId instanceof Zend_Cloud_DocumentService_Document) { + $fieldset = $documentId->getFields(); + if (empty($documentId)) { + $documentId = $documentId->getId(); + } + } elseif ($fieldset instanceof Zend_Cloud_DocumentService_Document) { + if (empty($documentId)) { + $documentId = $fieldset->getId(); + } + $fieldset = $fieldset->getFields(); + } + + $replace = array(); + if (empty($options[self::MERGE_OPTION])) { + // no merge option - we replace all + foreach ($fieldset as $key => $value) { + $replace[$key] = true; + } + } elseif (is_array($options[self::MERGE_OPTION])) { + foreach ($fieldset as $key => $value) { + if (empty($options[self::MERGE_OPTION][$key])) { + // if there's merge key, we add it, otherwise we replace it + $replace[$key] = true; + } + } + } // otherwise $replace is empty - all is merged + + try { + $this->_simpleDb->putAttributes( + $collectionName, + $documentId, + $this->_makeAttributes($documentId, $fieldset), + $replace + ); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document update: '.$e->getMessage(), $e->getCode(), $e); + } + return true; + } + + /** + * Delete document. + * + * @param string $collectionName Collection from which to delete document + * @param mixed $document Document ID or Document object. + * @param array $options + * @return boolean + */ + public function deleteDocument($collectionName, $document, $options = null) + { + if ($document instanceof Zend_Cloud_DocumentService_Document) { + $document = $document->getId(); + } + try { + $this->_simpleDb->deleteAttributes($collectionName, $document); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document deletion: '.$e->getMessage(), $e->getCode(), $e); + } + return true; + } + + /** + * Fetch single document by ID + * + * @param string $collectionName Collection name + * @param mixed $documentId Document ID, adapter-dependent + * @param array $options + * @return Zend_Cloud_DocumentService_Document + */ + public function fetchDocument($collectionName, $documentId, $options = null) + { + try { + $attributes = $this->_simpleDb->getAttributes($collectionName, $documentId); + if ($attributes == false || count($attributes) == 0) { + return false; + } + return $this->_resolveAttributes($attributes, true); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on fetching document: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Query for documents stored in the document service. If a string is passed in + * $query, the query string will be passed directly to the service. + * + * @param string $collectionName Collection name + * @param string $query + * @param array $options + * @return array Zend_Cloud_DocumentService_DocumentSet + */ + public function query($collectionName, $query, $options = null) + { + $returnDocs = isset($options[self::RETURN_DOCUMENTS]) + ? (bool) $options[self::RETURN_DOCUMENTS] + : true; + + try { + if ($query instanceof Zend_Cloud_DocumentService_Adapter_SimpleDb_Query) { + $query = $query->assemble($collectionName); + } + $result = $this->_simpleDb->select($query); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document query: '.$e->getMessage(), $e->getCode(), $e); + } + + return $this->_getDocumentSetFromResultSet($result, $returnDocs); + } + + /** + * Create query statement + * + * @param string $fields + * @return Zend_Cloud_DocumentService_Adapter_SimpleDb_Query + */ + public function select($fields = null) + { + $queryClass = $this->getQueryClass(); + if (!class_exists($queryClass)) { + Zend_Loader::loadClass($queryClass); + } + + $query = new $queryClass($this); + $defaultClass = self::DEFAULT_QUERY_CLASS; + if (!$query instanceof $defaultClass) { + throw new Zend_Cloud_DocumentService_Exception('Query class must extend ' . self::DEFAULT_QUERY_CLASS); + } + + $query->select($fields); + return $query; + } + + /** + * Get the concrete service client + * + * @return Zend_Service_Amazon_SimpleDb + */ + public function getClient() + { + return $this->_simpleDb; + } + + /** + * Convert array of key-value pairs to array of Amazon attributes + * + * @param string $name + * @param array $attributes + * @return array + */ + protected function _makeAttributes($name, $attributes) + { + $result = array(); + foreach ($attributes as $key => $attr) { + $result[] = new Zend_Service_Amazon_SimpleDb_Attribute($name, $key, $attr); + } + return $result; + } + + /** + * Convert array of Amazon attributes to array of key-value pairs + * + * @param array $attributes + * @return array + */ + protected function _resolveAttributes($attributes, $returnDocument = false) + { + $result = array(); + foreach ($attributes as $attr) { + $value = $attr->getValues(); + if (count($value) == 0) { + $value = null; + } elseif (count($value) == 1) { + $value = $value[0]; + } + $result[$attr->getName()] = $value; + } + + // Return as document object? + if ($returnDocument) { + $documentClass = $this->getDocumentClass(); + return new $documentClass($result, $attr->getItemName()); + } + + return $result; + } + + /** + * Create suitable document from array of fields + * + * @param array $document + * @return Zend_Cloud_DocumentService_Document + */ + protected function _getDocumentFromArray($document) + { + if (!isset($document[Zend_Cloud_DocumentService_Document::KEY_FIELD])) { + if (isset($document[self::ITEM_NAME])) { + $key = $document[self::ITEM_NAME]; + unset($document[self::ITEM_NAME]); + } else { + throw new Zend_Cloud_DocumentService_Exception('Fields array should contain the key field '.Zend_Cloud_DocumentService_Document::KEY_FIELD); + } + } else { + $key = $document[Zend_Cloud_DocumentService_Document::KEY_FIELD]; + unset($document[Zend_Cloud_DocumentService_Document::KEY_FIELD]); + } + + $documentClass = $this->getDocumentClass(); + return new $documentClass($document, $key); + } + + /** + * Create a DocumentSet from a SimpleDb resultset + * + * @param Zend_Service_Amazon_SimpleDb_Page $resultSet + * @param bool $returnDocs + * @return Zend_Cloud_DocumentService_DocumentSet + */ + protected function _getDocumentSetFromResultSet(Zend_Service_Amazon_SimpleDb_Page $resultSet, $returnDocs = true) + { + $docs = array(); + foreach ($resultSet->getData() as $item) { + $docs[] = $this->_resolveAttributes($item, $returnDocs); + } + + $setClass = $this->getDocumentSetClass(); + return new $setClass($docs); + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/Adapter/SimpleDb/Query.php b/library/vendor/Zend/Cloud/DocumentService/Adapter/SimpleDb/Query.php new file mode 100644 index 000000000..eadb0b877 --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Adapter/SimpleDb/Query.php @@ -0,0 +1,173 @@ +_adapter = $adapter; + if (null !== $collectionName) { + $this->from($collectionName); + } + } + + /** + * Get adapter + * + * @return Zend_Cloud_DocumentService_Adapter_SimpleDb + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Assemble the query into a format the adapter can utilize + * + * @var string $collectionName Name of collection from which to select + * @return string + */ + public function assemble($collectionName = null) + { + $adapter = $this->getAdapter()->getClient(); + $select = null; + $from = null; + $where = null; + $order = null; + $limit = null; + foreach ($this->getClauses() as $clause) { + list($name, $args) = $clause; + + switch ($name) { + case self::QUERY_SELECT: + $select = $args[0]; + break; + case self::QUERY_FROM: + if (null === $from) { + // Only allow setting FROM clause once + $from = $adapter->quoteName($args); + } + break; + case self::QUERY_WHERE: + $statement = $this->_parseWhere($args[0], $args[1]); + if (null === $where) { + $where = $statement; + } else { + $operator = empty($args[2]) ? 'AND' : $args[2]; + $where .= ' ' . $operator . ' ' . $statement; + } + break; + case self::QUERY_WHEREID: + $statement = $this->_parseWhere('ItemName() = ?', array($args)); + if (null === $where) { + $where = $statement; + } else { + $operator = empty($args[2]) ? 'AND' : $args[2]; + $where .= ' ' . $operator . ' ' . $statement; + } + break; + case self::QUERY_ORDER: + $order = $adapter->quoteName($args[0]); + if (isset($args[1])) { + $order .= ' ' . $args[1]; + } + break; + case self::QUERY_LIMIT: + $limit = $args; + break; + default: + // Ignore unknown clauses + break; + } + } + + if (empty($select)) { + $select = "*"; + } + if (empty($from)) { + if (null === $collectionName) { + throw new Zend_Cloud_DocumentService_Exception("Query requires a FROM clause"); + } + $from = $adapter->quoteName($collectionName); + } + $query = "select $select from $from"; + if (!empty($where)) { + $query .= " where $where"; + } + if (!empty($order)) { + $query .= " order by $order"; + } + if (!empty($limit)) { + $query .= " limit $limit"; + } + return $query; + } + + /** + * Parse a where statement into service-specific language + * + * @todo Ensure this fulfills the entire SimpleDB query specification for WHERE + * @param string $where + * @param array $args + * @return string + */ + protected function _parseWhere($where, $args) + { + if (!is_array($args)) { + $args = (array) $args; + } + $adapter = $this->getAdapter()->getClient(); + $i = 0; + while (false !== ($pos = strpos($where, '?'))) { + $where = substr_replace($where, $adapter->quote($args[$i]), $pos); + ++$i; + } + if (('(' != $where[0]) || (')' != $where[strlen($where) - 1])) { + $where = '(' . $where . ')'; + } + return $where; + } + } diff --git a/library/vendor/Zend/Cloud/DocumentService/Adapter/WindowsAzure.php b/library/vendor/Zend/Cloud/DocumentService/Adapter/WindowsAzure.php new file mode 100755 index 000000000..ae8577e19 --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Adapter/WindowsAzure.php @@ -0,0 +1,622 @@ +toArray(); + } + + if (empty($options)) { + $options = array(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid options provided'); + } + + if (isset($options[self::DOCUMENT_CLASS])) { + $this->setDocumentClass($options[self::DOCUMENT_CLASS]); + } + + if (isset($options[self::DOCUMENTSET_CLASS])) { + $this->setDocumentSetClass($options[self::DOCUMENTSET_CLASS]); + } + + if (isset($options[self::QUERY_CLASS])) { + $this->setQueryClass($options[self::QUERY_CLASS]); + } + + // Build Zend_Service_WindowsAzure_Storage_Blob instance + if (!isset($options[self::HOST])) { + $host = self::DEFAULT_HOST; + } else { + $host = $options[self::HOST]; + } + + if (! isset($options[self::ACCOUNT_NAME])) { + throw new Zend_Cloud_DocumentService_Exception('No Windows Azure account name provided.'); + } + + if (! isset($options[self::ACCOUNT_KEY])) { + throw new Zend_Cloud_DocumentService_Exception('No Windows Azure account key provided.'); + } + + // TODO: support $usePathStyleUri and $retryPolicy + try { + $this->_storageClient = new Zend_Service_WindowsAzure_Storage_Table( + $host, $options[self::ACCOUNT_NAME], $options[self::ACCOUNT_KEY]); + // Parse other options + if (! empty($options[self::PROXY_HOST])) { + $proxyHost = $options[self::PROXY_HOST]; + $proxyPort = isset($options[self::PROXY_PORT]) ? $options[self::PROXY_PORT] : 8080; + $proxyCredentials = isset($options[self::PROXY_CREDENTIALS]) ? $options[self::PROXY_CREDENTIALS] : ''; + $this->_storageClient->setProxy(true, $proxyHost, $proxyPort, $proxyCredentials); + } + if (isset($options[self::HTTP_ADAPTER])) { + $this->_storageClient->setHttpClientChannel($options[self::HTTP_ADAPTER]); + } + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document service creation: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Set the default partition key + * + * @param string $key + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure + */ + public function setDefaultPartitionKey($key) + { + $this->_validateKey($key); + $this->_defaultPartitionKey = $key; + return $this; + } + + /** + * Retrieve default partition key + * + * @return null|string + */ + public function getDefaultPartitionKey() + { + return $this->_defaultPartitionKey; + } + + /** + * Create collection. + * + * @param string $name + * @param array $options + * @return boolean + */ + public function createCollection($name, $options = null) + { + if (!preg_match('/^[A-Za-z][A-Za-z0-9]{2,}$/', $name)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid collection name; Windows Azure collection names must consist of alphanumeric characters only, and be at least 3 characters long'); + } + try { + $this->_storageClient->createTable($name); + } catch(Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "table specified already exists") === false) { + throw new Zend_Cloud_DocumentService_Exception('Error on collection creation: '.$e->getMessage(), $e->getCode(), $e); + } + } + return true; + } + + /** + * Delete collection. + * + * @param string $name + * @param array $options + * @return boolean + */ + public function deleteCollection($name, $options = null) + { + try { + $this->_storageClient->deleteTable($name); + } catch(Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "does not exist") === false) { + throw new Zend_Cloud_DocumentService_Exception('Error on collection deletion: '.$e->getMessage(), $e->getCode(), $e); + } + } + return true; + } + + /** + * List collections. + * + * @param array $options + * @return array + */ + public function listCollections($options = null) + { + try { + $tables = $this->_storageClient->listTables(); + $restables = array(); + foreach ($tables as $table) { + $restables[] = $table->name; + } + return $restables; + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on collection list: '.$e->getMessage(), $e->getCode(), $e); + } + + return $tables; + } + + /** + * Create suitable document from array of fields + * + * @param array $document + * @param null|string $collectionName Collection to which this document belongs + * @return Zend_Cloud_DocumentService_Document + */ + protected function _getDocumentFromArray($document, $collectionName = null) + { + $key = null; + if (!isset($document[Zend_Cloud_DocumentService_Document::KEY_FIELD])) { + if (isset($document[self::ROW_KEY])) { + $rowKey = $document[self::ROW_KEY]; + unset($document[self::ROW_KEY]); + if (isset($document[self::PARTITION_KEY])) { + $key = array($document[self::PARTITION_KEY], $rowKey); + unset($document[self::PARTITION_KEY]); + } elseif (null !== ($partitionKey = $this->getDefaultPartitionKey())) { + $key = array($partitionKey, $rowKey); + } elseif (null !== $collectionName) { + $key = array($collectionName, $rowKey); + } + } + } else { + $key = $document[Zend_Cloud_DocumentService_Document::KEY_FIELD]; + unset($document[Zend_Cloud_DocumentService_Document::KEY_FIELD]); + } + + $documentClass = $this->getDocumentClass(); + return new $documentClass($document, $key); + } + + /** + * List all documents in a collection + * + * @param string $collectionName + * @param null|array $options + * @return Zend_Cloud_DocumentService_DocumentSet + */ + public function listDocuments($collectionName, array $options = null) + { + $select = $this->select()->from($collectionName); + return $this->query($collectionName, $select); + } + + /** + * Insert document + * + * @param array|Zend_Cloud_DocumentService_Document $document + * @param array $options + * @return boolean + */ + public function insertDocument($collectionName, $document, $options = null) + { + if (is_array($document)) { + $document = $this->_getDocumentFromArray($document, $collectionName); + } + + if (!$document instanceof Zend_Cloud_DocumentService_Document) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document supplied'); + } + + $key = $this->_validateDocumentId($document->getId(), $collectionName); + $document->setId($key); + + $this->_validateCompositeKey($key); + $this->_validateFields($document); + try { + + $entity = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($key[0], $key[1]); + $entity->setAzureValues($document->getFields(), true); + $this->_storageClient->insertEntity($collectionName, $entity); + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document insertion: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Replace document. + * + * The new document replaces the existing document. + * + * @param Zend_Cloud_DocumentService_Document $document + * @param array $options + * @return boolean + */ + public function replaceDocument($collectionName, $document, $options = null) + { + if (is_array($document)) { + $document = $this->_getDocumentFromArray($document, $collectionName); + } + + if (!$document instanceof Zend_Cloud_DocumentService_Document) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document supplied'); + } + + $key = $this->_validateDocumentId($document->getId(), $collectionName); + $this->_validateFields($document); + try { + $entity = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($key[0], $key[1]); + $entity->setAzureValues($document->getFields(), true); + if (isset($options[self::VERIFY_ETAG])) { + $entity->setEtag($options[self::VERIFY_ETAG]); + } + + $this->_storageClient->updateEntity($collectionName, $entity, isset($options[self::VERIFY_ETAG])); + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document replace: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Update document. + * + * The new document is merged the existing document. + * + * @param string $collectionName + * @param mixed|Zend_Cloud_DocumentService_Document $documentId Document identifier or document contaiing updates + * @param null|array|Zend_Cloud_DocumentService_Document Fields to update (or new fields)) + * @param array $options + * @return boolean + */ + public function updateDocument($collectionName, $documentId, $fieldset = null, $options = null) + { + if (null === $fieldset && $documentId instanceof Zend_Cloud_DocumentService_Document) { + $fieldset = $documentId->getFields(); + $documentId = $documentId->getId(); + } elseif ($fieldset instanceof Zend_Cloud_DocumentService_Document) { + if ($documentId == null) { + $documentId = $fieldset->getId(); + } + $fieldset = $fieldset->getFields(); + } + + $this->_validateCompositeKey($documentId, $collectionName); + $this->_validateFields($fieldset); + try { + $entity = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($documentId[0], $documentId[1]); + + // Ensure timestamp is set correctly + if (isset($fieldset[self::TIMESTAMP_KEY])) { + $entity->setTimestamp($fieldset[self::TIMESTAMP_KEY]); + unset($fieldset[self::TIMESTAMP_KEY]); + } + + $entity->setAzureValues($fieldset, true); + if (isset($options[self::VERIFY_ETAG])) { + $entity->setEtag($options[self::VERIFY_ETAG]); + } + + $this->_storageClient->mergeEntity($collectionName, $entity, isset($options[self::VERIFY_ETAG])); + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document update: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Delete document. + * + * @param mixed $document Document ID or Document object. + * @param array $options + * @return void + */ + public function deleteDocument($collectionName, $documentId, $options = null) + { + if ($documentId instanceof Zend_Cloud_DocumentService_Document) { + $documentId = $documentId->getId(); + } + + $documentId = $this->_validateDocumentId($documentId, $collectionName); + + try { + $entity = new Zend_Service_WindowsAzure_Storage_DynamicTableEntity($documentId[0], $documentId[1]); + if (isset($options[self::VERIFY_ETAG])) { + $entity->setEtag($options[self::VERIFY_ETAG]); + } + $this->_storageClient->deleteEntity($collectionName, $entity, isset($options[self::VERIFY_ETAG])); + } catch(Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "does not exist") === false) { + throw new Zend_Cloud_DocumentService_Exception('Error on document deletion: '.$e->getMessage(), $e->getCode(), $e); + } + } + } + + /** + * Fetch single document by ID + * + * @param string $collectionName Collection name + * @param mixed $documentId Document ID, adapter-dependent + * @param array $options + * @return Zend_Cloud_DocumentService_Document + */ + public function fetchDocument($collectionName, $documentId, $options = null) + { + $documentId = $this->_validateDocumentId($documentId, $collectionName); + try { + $entity = $this->_storageClient->retrieveEntityById($collectionName, $documentId[0], $documentId[1]); + $documentClass = $this->getDocumentClass(); + return new $documentClass($this->_resolveAttributes($entity), array($entity->getPartitionKey(), $entity->getRowKey())); + } catch (Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "does not exist") !== false) { + return false; + } + throw new Zend_Cloud_DocumentService_Exception('Error on document fetch: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Query for documents stored in the document service. If a string is passed in + * $query, the query string will be passed directly to the service. + * + * @param string $collectionName Collection name + * @param string|Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query $query + * @param array $options + * @return array Zend_Cloud_DocumentService_DocumentSet + */ + public function query($collectionName, $query, $options = null) + { + try { + if ($query instanceof Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query) { + $entities = $this->_storageClient->retrieveEntities($query->assemble()); + } else { + $entities = $this->_storageClient->retrieveEntities($collectionName, $query); + } + + $documentClass = $this->getDocumentClass(); + $resultSet = array(); + foreach ($entities as $entity) { + $resultSet[] = new $documentClass( + $this->_resolveAttributes($entity), + array($entity->getPartitionKey(), $entity->getRowKey()) + ); + } + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_DocumentService_Exception('Error on document query: '.$e->getMessage(), $e->getCode(), $e); + } + + $setClass = $this->getDocumentSetClass(); + return new $setClass($resultSet); + } + + /** + * Create query statement + * + * @return Zend_Cloud_DocumentService_Query + */ + public function select($fields = null) + { + $queryClass = $this->getQueryClass(); + if (!class_exists($queryClass)) { + Zend_Loader::loadClass($queryClass); + } + + $query = new $queryClass(); + $defaultClass = self::DEFAULT_QUERY_CLASS; + if (!$query instanceof $defaultClass) { + throw new Zend_Cloud_DocumentService_Exception('Query class must extend ' . self::DEFAULT_QUERY_CLASS); + } + + $query->select($fields); + return $query; + } + + /** + * Get the concrete service client + * + * @return Zend_Service_WindowsAzure_Storage_Table + */ + public function getClient() + { + return $this->_storageClient; + } + + /** + * Resolve table values to attributes + * + * @param Zend_Service_WindowsAzure_Storage_TableEntity $entity + * @return array + */ + protected function _resolveAttributes(Zend_Service_WindowsAzure_Storage_TableEntity $entity) + { + $result = array(); + foreach ($entity->getAzureValues() as $attr) { + $result[$attr->Name] = $attr->Value; + } + return $result; + } + + + /** + * Validate a partition or row key + * + * @param string $key + * @return void + * @throws Zend_Cloud_DocumentService_Exception + */ + protected function _validateKey($key) + { + if (preg_match('@[/#?' . preg_quote('\\') . ']@', $key)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid partition or row key provided; must not contain /, \\, #, or ? characters'); + } + } + + /** + * Validate a composite key + * + * @param array $key + * @return throws Zend_Cloud_DocumentService_Exception + */ + protected function _validateCompositeKey(array $key) + { + if (2 != count($key)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document key provided; must contain exactly two elements: a PartitionKey and a RowKey'); + } + foreach ($key as $k) { + $this->_validateKey($k); + } + } + + /** + * Validate a document identifier + * + * If the identifier is an array containing a valid partition and row key, + * returns it. If the identifier is a string: + * - if a default partition key is present, it creates an identifier using + * that and the provided document ID + * - if a collection name is provided, it will use that for the partition key + * - otherwise, it's invalid + * + * @param array|string $documentId + * @param null|string $collectionName + * @return array + * @throws Zend_Cloud_DocumentService_Exception + */ + protected function _validateDocumentId($documentId, $collectionName = false) + { + if (is_array($documentId)) { + $this->_validateCompositeKey($documentId); + return $documentId; + } + if (!is_string($documentId)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document identifier; must be a string or an array'); + } + + $this->_validateKey($documentId); + + if (null !== ($partitionKey = $this->getDefaultPartitionKey())) { + return array($partitionKey, $documentId); + } + if (null !== $collectionName) { + return array($collectionName, $documentId); + } + throw new Zend_Cloud_DocumentService_Exception('Cannot determine partition name; invalid document identifier'); + } + + /** + * Validate a document's fields for well-formedness + * + * Since Azure uses Atom, and fieldnames are included as part of XML + * element tag names, the field names must be valid XML names. + * + * @param Zend_Cloud_DocumentService_Document|array $document + * @return void + * @throws Zend_Cloud_DocumentService_Exception + */ + public function _validateFields($document) + { + if ($document instanceof Zend_Cloud_DocumentService_Document) { + $document = $document->getFields(); + } elseif (!is_array($document)) { + throw new Zend_Cloud_DocumentService_Exception('Cannot inspect fields; invalid type provided'); + } + + foreach (array_keys($document) as $key) { + $this->_validateFieldKey($key); + } + } + + /** + * Validate an individual field name for well-formedness + * + * Since Azure uses Atom, and fieldnames are included as part of XML + * element tag names, the field names must be valid XML names. + * + * While we could potentially normalize names, this could also lead to + * conflict with other field names -- which we should avoid. As such, + * invalid field names will raise an exception. + * + * @param string $key + * @return void + * @throws Zend_Cloud_DocumentService_Exception + */ + public function _validateFieldKey($key) + { + if (!preg_match('/^[_A-Za-z][-._A-Za-z0-9]*$/', $key)) { + throw new Zend_Cloud_DocumentService_Exception('Field keys must conform to XML names (^[_A-Za-z][-._A-Za-z0-9]*$); key "' . $key . '" does not match'); + } + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/Adapter/WindowsAzure/Query.php b/library/vendor/Zend/Cloud/DocumentService/Adapter/WindowsAzure/Query.php new file mode 100755 index 000000000..aefefb73d --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Adapter/WindowsAzure/Query.php @@ -0,0 +1,167 @@ +_azureSelect = $select; + } + + /** + * SELECT clause (fields to be selected) + * + * Does nothing for Azure. + * + * @param string $select + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query + */ + public function select($select) + { + return $this; + } + + /** + * FROM clause (table name) + * + * @param string $from + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query + */ + public function from($from) + { + $this->_azureSelect->from($from); + return $this; + } + + /** + * WHERE clause (conditions to be used) + * + * @param string $where + * @param mixed $value Value or array of values to be inserted instead of ? + * @param string $op Operation to use to join where clauses (AND/OR) + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query + */ + public function where($where, $value = null, $op = 'and') + { + if (!empty($value) && !is_array($value)) { + // fix buglet in Azure - numeric values are quoted unless passed as an array + $value = array($value); + } + $this->_azureSelect->where($where, $value, $op); + return $this; + } + + /** + * WHERE clause for item ID + * + * This one should be used when fetching specific rows since some adapters + * have special syntax for primary keys + * + * @param array $value Row ID for the document (PartitionKey, RowKey) + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query + */ + public function whereId($value) + { + if (!is_array($value)) { + throw new Zend_Cloud_DocumentService_Exception('Invalid document key'); + } + $this->_azureSelect->wherePartitionKey($value[0])->whereRowKey($value[1]); + return $this; + } + + /** + * LIMIT clause (how many rows to return) + * + * @param int $limit + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query + */ + public function limit($limit) + { + $this->_azureSelect->top($limit); + return $this; + } + + /** + * ORDER BY clause (sorting) + * + * @todo Azure service doesn't seem to support this yet; emulate? + * @param string $sort Column to sort by + * @param string $direction Direction - asc/desc + * @return Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query + * @throws Zend_Cloud_OperationNotAvailableException + */ + public function order($sort, $direction = 'asc') + { + throw new Zend_Cloud_OperationNotAvailableException('No support for sorting for Azure yet'); + } + + /** + * Get Azure select query + * + * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery + */ + public function getAzureSelect() + { + return $this->_azureSelect; + } + + /** + * Assemble query + * + * Simply return the WindowsAzure table entity query object + * + * @return Zend_Service_WindowsAzure_Storage_TableEntityQuery + */ + public function assemble() + { + return $this->getAzureSelect(); + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/Document.php b/library/vendor/Zend/Cloud/DocumentService/Document.php new file mode 100644 index 000000000..559d9f10f --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Document.php @@ -0,0 +1,246 @@ +_fields = $fields; + $this->setId($id); + } + + /** + * Set document identifier + * + * @param mixed $id + * @return Zend_Cloud_DocumentService_Document + */ + public function setId($id) + { + $this->_id = $id; + return $this; + } + + /** + * Get ID name. + * + * @return string + */ + public function getId() + { + return $this->_id; + } + + /** + * Get fields as array. + * + * @return array + */ + public function getFields() + { + return $this->_fields; + } + + /** + * Get field by name. + * + * @param string $name + * @return mixed + */ + public function getField($name) + { + if (isset($this->_fields[$name])) { + return $this->_fields[$name]; + } + return null; + } + + /** + * Set field by name. + * + * @param string $name + * @param mixed $value + * @return Zend_Cloud_DocumentService_Document + */ + public function setField($name, $value) + { + $this->_fields[$name] = $value; + return $this; + } + + /** + * Overloading: get value + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->getField($name); + } + + /** + * Overloading: set field + * + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value) + { + $this->setField($name, $value); + } + + /** + * ArrayAccess: does field exist? + * + * @param string $name + * @return bool + */ + public function offsetExists($name) + { + return isset($this->_fields[$name]); + } + + /** + * ArrayAccess: get field by name + * + * @param string $name + * @return mixed + */ + public function offsetGet($name) + { + return $this->getField($name); + } + + /** + * ArrayAccess: set field to value + * + * @param string $name + * @param mixed $value + * @return void + */ + public function offsetSet($name, $value) + { + $this->setField($name, $value); + } + + /** + * ArrayAccess: remove field from document + * + * @param string $name + * @return void + */ + public function offsetUnset($name) + { + if ($this->offsetExists($name)) { + unset($this->_fields[$name]); + } + } + + /** + * Overloading: retrieve and set fields by name + * + * @param string $name + * @param mixed $args + * @return mixed + */ + public function __call($name, $args) + { + $prefix = substr($name, 0, 3); + if ($prefix == 'get') { + // Get value + $option = substr($name, 3); + return $this->getField($option); + } elseif ($prefix == 'set') { + // set value + $option = substr($name, 3); + return $this->setField($option, $args[0]); + } + + throw new Zend_Cloud_OperationNotAvailableException("Unknown operation $name"); + } + + /** + * Countable: return count of fields in document + * + * @return int + */ + public function count() + { + return count($this->_fields); + } + + /** + * IteratorAggregate: return iterator for iterating over fields + * + * @return Iterator + */ + public function getIterator() + { + return new ArrayIterator($this->_fields); + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/DocumentSet.php b/library/vendor/Zend/Cloud/DocumentService/DocumentSet.php new file mode 100644 index 000000000..1bf4dfbcc --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/DocumentSet.php @@ -0,0 +1,68 @@ +_documentCount = count($documents); + $this->_documents = new ArrayIterator($documents); + } + + /** + * Countable: number of documents in set + * + * @return int + */ + public function count() + { + return $this->_documentCount; + } + + /** + * IteratorAggregate: retrieve iterator + * + * @return Traversable + */ + public function getIterator() + { + return $this->_documents; + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/Exception.php b/library/vendor/Zend/Cloud/DocumentService/Exception.php new file mode 100644 index 000000000..3d170d250 --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/Exception.php @@ -0,0 +1,37 @@ +foo('bar') + * but concrete adapters should be able to recognise it + * + * The call will be iterpreted as clause 'foo' with argument 'bar' + * + * @param string $name Clause/method name + * @param mixed $args + * @return Zend_Cloud_DocumentService_Query + */ + public function __call($name, $args) + { + $this->_clauses[] = array(strtolower($name), $args); + return $this; + } + + /** + * SELECT clause (fields to be selected) + * + * @param null|string|array $select + * @return Zend_Cloud_DocumentService_Query + */ + public function select($select) + { + if (empty($select)) { + return $this; + } + if (!is_string($select) && !is_array($select)) { + throw new Zend_Cloud_DocumentService_Exception("SELECT argument must be a string or an array of strings"); + } + $this->_clauses[] = array(self::QUERY_SELECT, $select); + return $this; + } + + /** + * FROM clause + * + * @param string $name Field names + * @return Zend_Cloud_DocumentService_Query + */ + public function from($name) + { + if(!is_string($name)) { + throw new Zend_Cloud_DocumentService_Exception("FROM argument must be a string"); + } + $this->_clauses[] = array(self::QUERY_FROM, $name); + return $this; + } + + /** + * WHERE query + * + * @param string $cond Condition + * @param array $args Arguments to substitute instead of ?'s in condition + * @param string $op relation to other clauses - and/or + * @return Zend_Cloud_DocumentService_Query + */ + public function where($cond, $value = null, $op = 'and') + { + if (!is_string($cond)) { + throw new Zend_Cloud_DocumentService_Exception("WHERE argument must be a string"); + } + $this->_clauses[] = array(self::QUERY_WHERE, array($cond, $value, $op)); + return $this; + } + + /** + * Select record or fields by ID + * + * @param string|int $value Identifier to select by + * @return Zend_Cloud_DocumentService_Query + */ + public function whereId($value) + { + if (!is_scalar($value)) { + throw new Zend_Cloud_DocumentService_Exception("WHEREID argument must be a scalar"); + } + $this->_clauses[] = array(self::QUERY_WHEREID, $value); + return $this; + } + + /** + * LIMIT clause (how many items to return) + * + * @param int $limit + * @return Zend_Cloud_DocumentService_Query + */ + public function limit($limit) + { + if ($limit != (int) $limit) { + throw new Zend_Cloud_DocumentService_Exception("LIMIT argument must be an integer"); + } + $this->_clauses[] = array(self::QUERY_LIMIT, $limit); + return $this; + } + + /** + * ORDER clause; field or fields to sort by, and direction to sort + * + * @param string|int|array $sort + * @param string $direction + * @return Zend_Cloud_DocumentService_Query + */ + public function order($sort, $direction = 'asc') + { + $this->_clauses[] = array(self::QUERY_ORDER, array($sort, $direction)); + return $this; + } + + /** + * "Assemble" the query + * + * Simply returns the clauses present. + * + * @return array + */ + public function assemble() + { + return $this->getClauses(); + } + + /** + * Return query clauses as an array + * + * @return array Clauses in the query + */ + public function getClauses() + { + return $this->_clauses; + } +} diff --git a/library/vendor/Zend/Cloud/DocumentService/QueryAdapter.php b/library/vendor/Zend/Cloud/DocumentService/QueryAdapter.php new file mode 100644 index 000000000..54cf4d18f --- /dev/null +++ b/library/vendor/Zend/Cloud/DocumentService/QueryAdapter.php @@ -0,0 +1,102 @@ +_clientException = $clientException; + parent::__construct($message, $code, $clientException); + } + + public function getClientException() { + return $this->_getPrevious(); + } +} + diff --git a/library/vendor/Zend/Cloud/Infrastructure/Adapter.php b/library/vendor/Zend/Cloud/Infrastructure/Adapter.php new file mode 100644 index 000000000..826015491 --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/Adapter.php @@ -0,0 +1,167 @@ +adapterResult; + } + + /** + * Wait for status $status with a timeout of $timeout seconds + * + * @param string $id + * @param string $status + * @param integer $timeout + * @return boolean + */ + public function waitStatusInstance($id, $status, $timeout = self::TIMEOUT_STATUS_CHANGE) + { + if (empty($id) || empty($status)) { + return false; + } + + $num = 0; + while (($num<$timeout) && ($this->statusInstance($id) != $status)) { + sleep(self::TIME_STEP_STATUS_CHANGE); + $num += self::TIME_STEP_STATUS_CHANGE; + } + return ($num < $timeout); + } + + /** + * Run arbitrary shell script on an instance + * + * @param string $id + * @param array $param + * @param string|array $cmd + * @return string|array + */ + public function deployInstance($id, $params, $cmd) + { + if (!function_exists("ssh2_connect")) { + throw new Zend_Cloud_Infrastructure_Exception('Deployment requires the PHP "SSH" extension (ext/ssh2)'); + } + + if (empty($id)) { + throw new Zend_Cloud_Infrastructure_Exception('You must specify the instance where to deploy'); + } + + if (empty($cmd)) { + throw new Zend_Cloud_Infrastructure_Exception('You must specify the shell commands to run on the instance'); + } + + if (empty($params) + || empty($params[Zend_Cloud_Infrastructure_Instance::SSH_USERNAME]) + || (empty($params[Zend_Cloud_Infrastructure_Instance::SSH_PASSWORD]) + && empty($params[Zend_Cloud_Infrastructure_Instance::SSH_KEY])) + ) { + throw new Zend_Cloud_Infrastructure_Exception('You must specify the params for the SSH connection'); + } + + $host = $this->publicDnsInstance($id); + if (empty($host)) { + throw new Zend_Cloud_Infrastructure_Exception(sprintf( + 'The instance identified by "%s" does not exist', + $id + )); + } + + $conn = ssh2_connect($host); + if (!ssh2_auth_password($conn, $params[Zend_Cloud_Infrastructure_Instance::SSH_USERNAME], + $params[Zend_Cloud_Infrastructure_Instance::SSH_PASSWORD])) { + throw new Zend_Cloud_Infrastructure_Exception('SSH authentication failed'); + } + + if (is_array($cmd)) { + $result = array(); + foreach ($cmd as $command) { + $stream = ssh2_exec($conn, $command); + $errorStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR); + + stream_set_blocking($errorStream, true); + stream_set_blocking($stream, true); + + $output = stream_get_contents($stream); + $error = stream_get_contents($errorStream); + + if (empty($error)) { + $result[$command] = $output; + } else { + $result[$command] = $error; + } + } + } else { + $stream = ssh2_exec($conn, $cmd); + $result = stream_set_blocking($stream, true); + $errorStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR); + + stream_set_blocking($errorStream, true); + stream_set_blocking($stream, true); + + $output = stream_get_contents($stream); + $error = stream_get_contents($errorStream); + + if (empty($error)) { + $result = $output; + } else { + $result = $error; + } + } + return $result; + } +} diff --git a/library/vendor/Zend/Cloud/Infrastructure/Adapter/Ec2.php b/library/vendor/Zend/Cloud/Infrastructure/Adapter/Ec2.php new file mode 100644 index 000000000..3088a4c72 --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/Adapter/Ec2.php @@ -0,0 +1,479 @@ + Zend_Cloud_Infrastructure_Instance::STATUS_RUNNING, + 'terminated' => Zend_Cloud_Infrastructure_Instance::STATUS_TERMINATED, + 'pending' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'shutting-down' => Zend_Cloud_Infrastructure_Instance::STATUS_SHUTTING_DOWN, + 'stopping' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'stopped' => Zend_Cloud_Infrastructure_Instance::STATUS_STOPPED, + 'rebooting' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, + ); + + /** + * Map monitor metrics between Infrastructure and EC2 + * + * @var array + */ + protected $mapMetrics= array ( + Zend_Cloud_Infrastructure_Instance::MONITOR_CPU => 'CPUUtilization', + Zend_Cloud_Infrastructure_Instance::MONITOR_DISK_READ => 'DiskReadBytes', + Zend_Cloud_Infrastructure_Instance::MONITOR_DISK_WRITE => 'DiskWriteBytes', + Zend_Cloud_Infrastructure_Instance::MONITOR_NETWORK_IN => 'NetworkIn', + Zend_Cloud_Infrastructure_Instance::MONITOR_NETWORK_OUT => 'NetworkOut', + ); + + /** + * Constructor + * + * @param array|Zend_Config $options + * @return void + */ + public function __construct($options = array()) + { + if (is_object($options)) { + if (method_exists($options, 'toArray')) { + $options= $options->toArray(); + } elseif ($options instanceof Traversable) { + $options = iterator_to_array($options); + } + } + + if (empty($options) || !is_array($options)) { + throw new Zend_Cloud_Infrastructure_Exception('Invalid options provided'); + } + + if (!isset($options[self::AWS_ACCESS_KEY]) + || !isset($options[self::AWS_SECRET_KEY]) + ) { + throw new Zend_Cloud_Infrastructure_Exception('AWS keys not specified!'); + } + + $this->accessKey = $options[self::AWS_ACCESS_KEY]; + $this->accessSecret = $options[self::AWS_SECRET_KEY]; + $this->region = ''; + + if (isset($options[self::AWS_REGION])) { + $this->region= $options[self::AWS_REGION]; + } + + try { + $this->ec2 = new Zend_Service_Amazon_Ec2_Instance($options[self::AWS_ACCESS_KEY], $options[self::AWS_SECRET_KEY], $this->region); + } catch (Exception $e) { + throw new Zend_Cloud_Infrastructure_Exception('Error on create: ' . $e->getMessage(), $e->getCode(), $e); + } + + if (isset($options[self::HTTP_ADAPTER])) { + $this->ec2->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + } + + /** + * Convert the attributes of EC2 into attributes of Infrastructure + * + * @param array $attr + * @return array|boolean + */ + private function convertAttributes($attr) + { + $result = array(); + if (!empty($attr) && is_array($attr)) { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ID] = $attr['instanceId']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STATUS] = $this->mapStatus[$attr['instanceState']['name']]; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_IMAGEID] = $attr['imageId']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = $attr['availabilityZone']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_LAUNCHTIME] = $attr['launchTime']; + + switch ($attr['instanceType']) { + case Zend_Service_Amazon_Ec2_Instance::MICRO: + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU] = '1 virtual core'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = '613MB'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '0GB'; + break; + case Zend_Service_Amazon_Ec2_Instance::SMALL: + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU] = '1 virtual core'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = '1.7GB'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '160GB'; + break; + case Zend_Service_Amazon_Ec2_Instance::LARGE: + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU] = '2 virtual core'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = '7.5GB'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '850GB'; + break; + case Zend_Service_Amazon_Ec2_Instance::XLARGE: + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU] = '4 virtual core'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = '15GB'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '1690GB'; + break; + case Zend_Service_Amazon_Ec2_Instance::HCPU_MEDIUM: + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU] = '2 virtual core'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = '1.7GB'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '350GB'; + break; + case Zend_Service_Amazon_Ec2_Instance::HCPU_XLARGE: + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_CPU] = '8 virtual core'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = '7GB'; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = '1690GB'; + break; + } + } + return $result; + } + + /** + * Return a list of the available instancies + * + * @return Zend_Cloud_Infrastructure_InstanceList + */ + public function listInstances() + { + $this->adapterResult = $this->ec2->describe(); + + $result = array(); + foreach ($this->adapterResult['instances'] as $instance) { + $result[]= $this->convertAttributes($instance); + } + return new Zend_Cloud_Infrastructure_InstanceList($this, $result); + } + + /** + * Return the status of an instance + * + * @param string + * @return string|boolean + */ + public function statusInstance($id) + { + $this->adapterResult = $this->ec2->describe($id); + if (empty($this->adapterResult['instances'])) { + return false; + } + $result = $this->adapterResult['instances'][0]; + return $this->mapStatus[$result['instanceState']['name']]; + } + + /** + * Return the public DNS name of the instance + * + * @param string $id + * @return string|boolean + */ + public function publicDnsInstance($id) + { + $this->adapterResult = $this->ec2->describe($id); + if (empty($this->adapterResult['instances'])) { + return false; + } + $result = $this->adapterResult['instances'][0]; + return $result['dnsName']; + } + + /** + * Reboot an instance + * + * @param string $id + * @return boolean + */ + public function rebootInstance($id) + { + $this->adapterResult= $this->ec2->reboot($id); + return $this->adapterResult; + } + + /** + * Create a new instance + * + * @param string $name + * @param array $options + * @return Instance|boolean + */ + public function createInstance($name, $options) + { + // @todo instance's name management? + $this->adapterResult = $this->ec2->run($options); + if (empty($this->adapterResult['instances'])) { + return false; + } + $this->error= false; + return new Zend_Cloud_Infrastructure_Instance($this, $this->convertAttributes($this->adapterResult['instances'][0])); + } + + /** + * Stop an instance + * + * @param string $id + * @return boolean + */ + public function stopInstance($id) + { + throw new Zend_Cloud_Infrastructure_Exception('The stopInstance method is not implemented in the adapter'); + } + + /** + * Start an instance + * + * @param string $id + * @return boolean + */ + public function startInstance($id) + { + throw new Zend_Cloud_Infrastructure_Exception('The startInstance method is not implemented in the adapter'); + } + + /** + * Destroy an instance + * + * @param string $id + * @return boolean + */ + public function destroyInstance($id) + { + $this->adapterResult = $this->ec2->terminate($id); + return (!empty($this->adapterResult)); + } + + /** + * Return a list of all the available instance images + * + * @return ImageList + */ + public function imagesInstance() + { + if (!isset($this->ec2Image)) { + $this->ec2Image = new Zend_Service_Amazon_Ec2_Image($this->accessKey, $this->accessSecret, $this->region); + } + + $this->adapterResult = $this->ec2Image->describe(); + + $images = array(); + + foreach ($this->adapterResult as $result) { + switch (strtolower($result['platform'])) { + case 'windows' : + $platform = Zend_Cloud_Infrastructure_Image::IMAGE_WINDOWS; + break; + default: + $platform = Zend_Cloud_Infrastructure_Image::IMAGE_LINUX; + break; + } + + $images[]= array ( + Zend_Cloud_Infrastructure_Image::IMAGE_ID => $result['imageId'], + Zend_Cloud_Infrastructure_Image::IMAGE_NAME => '', + Zend_Cloud_Infrastructure_Image::IMAGE_DESCRIPTION => $result['imageLocation'], + Zend_Cloud_Infrastructure_Image::IMAGE_OWNERID => $result['imageOwnerId'], + Zend_Cloud_Infrastructure_Image::IMAGE_ARCHITECTURE => $result['architecture'], + Zend_Cloud_Infrastructure_Image::IMAGE_PLATFORM => $platform, + ); + } + return new Zend_Cloud_Infrastructure_ImageList($images,$this->ec2Image); + } + + /** + * Return all the available zones + * + * @return array + */ + public function zonesInstance() + { + if (!isset($this->ec2Zone)) { + $this->ec2Zone = new Zend_Service_Amazon_Ec2_AvailabilityZones($this->accessKey,$this->accessSecret,$this->region); + } + $this->adapterResult = $this->ec2Zone->describe(); + + $zones = array(); + foreach ($this->adapterResult as $zone) { + if (strtolower($zone['zoneState']) === 'available') { + $zones[] = array ( + Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE => $zone['zoneName'], + ); + } + } + return $zones; + } + + /** + * Return the system information about the $metric of an instance + * + * @param string $id + * @param string $metric + * @param null|array $options + * @return array + */ + public function monitorInstance($id, $metric, $options = null) + { + if (empty($id) || empty($metric)) { + return false; + } + + if (!in_array($metric,$this->validMetrics)) { + throw new Zend_Cloud_Infrastructure_Exception(sprintf( + 'The metric "%s" is not valid', + $metric + )); + } + + if (!empty($options) && !is_array($options)) { + throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); + } + + if (!empty($options) + && (empty($options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME]) + || empty($options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME])) + ) { + throw new Zend_Cloud_Infrastructure_Exception(sprintf( + 'The options array must contain: "%s" and "%s"', + $options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME], + $options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME] + )); + } + + if (!isset($this->ec2Monitor)) { + $this->ec2Monitor = new Zend_Service_Amazon_Ec2_CloudWatch($this->accessKey, $this->accessSecret, $this->region); + } + + $param = array( + 'MeasureName' => $this->mapMetrics[$metric], + 'Statistics' => array('Average'), + 'Dimensions' => array('InstanceId' => $id), + ); + + if (!empty($options)) { + $param['StartTime'] = $options[Zend_Cloud_Infrastructure_Instance::MONITOR_START_TIME]; + $param['EndTime'] = $options[Zend_Cloud_Infrastructure_Instance::MONITOR_END_TIME]; + } + + $this->adapterResult = $this->ec2Monitor->getMetricStatistics($param); + + $monitor = array(); + $num = 0; + $average = 0; + + if (!empty($this->adapterResult['datapoints'])) { + foreach ($this->adapterResult['datapoints'] as $result) { + $monitor['series'][] = array ( + 'timestamp' => $result['Timestamp'], + 'value' => $result['Average'], + ); + $average += $result['Average']; + $num++; + } + } + + if ($num > 0) { + $monitor['average'] = $average / $num; + } + + return $monitor; + } + + /** + * Get the adapter + * + * @return Zend_Service_Amazon_Ec2_Instance + */ + public function getAdapter() + { + return $this->ec2; + } + + /** + * Get last HTTP request + * + * @return string + */ + public function getLastHttpRequest() + { + return $this->ec2->getHttpClient()->getLastRequest(); + } + + /** + * Get the last HTTP response + * + * @return Zend_Http_Response + */ + public function getLastHttpResponse() + { + return $this->ec2->getHttpClient()->getLastResponse(); + } +} diff --git a/library/vendor/Zend/Cloud/Infrastructure/Adapter/Rackspace.php b/library/vendor/Zend/Cloud/Infrastructure/Adapter/Rackspace.php new file mode 100644 index 000000000..2386a4503 --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/Adapter/Rackspace.php @@ -0,0 +1,462 @@ + Zend_Cloud_Infrastructure_Instance::STATUS_RUNNING, + 'SUSPENDED' => Zend_Cloud_Infrastructure_Instance::STATUS_STOPPED, + 'BUILD' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'REBUILD' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'QUEUE_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'PREP_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'VERIFY_RESIZE' => Zend_Cloud_Infrastructure_Instance::STATUS_REBUILD, + 'PASSWORD' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'RESCUE' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'REBOOT' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, + 'HARD_REBOOT' => Zend_Cloud_Infrastructure_Instance::STATUS_REBOOTING, + 'SHARE_IP' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'SHARE_IP_NO_CONFIG' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'DELETE_IP' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING, + 'UNKNOWN' => Zend_Cloud_Infrastructure_Instance::STATUS_PENDING + ); + /** + * Constructor + * + * @param array|Zend_Config $options + * @return void + */ + public function __construct($options = array()) + { + if (is_object($options)) { + if (method_exists($options, 'toArray')) { + $options= $options->toArray(); + } elseif ($options instanceof Traversable) { + $options = iterator_to_array($options); + } + } + + if (empty($options) || !is_array($options)) { + throw new Zend_Cloud_Infrastructure_Exception('Invalid options provided'); + } + + if (!isset($options[self::RACKSPACE_USER])) { + throw new Zend_Cloud_Infrastructure_Exception('Rackspace access user not specified!'); + } + + if (!isset($options[self::RACKSPACE_KEY])) { + throw new Zend_Cloud_Infrastructure_Exception('Rackspace access key not specified!'); + } + + $this->accessUser = $options[self::RACKSPACE_USER]; + $this->accessKey = $options[self::RACKSPACE_KEY]; + + if (isset($options[self::RACKSPACE_REGION])) { + switch ($options[self::RACKSPACE_REGION]) { + case self::RACKSPACE_ZONE_UK: + $this->region= Zend_Service_Rackspace_Servers::UK_AUTH_URL; + break; + case self::RACKSPACE_ZONE_USA: + $this->region = Zend_Service_Rackspace_Servers::US_AUTH_URL; + break; + default: + throw new Zend_Cloud_Infrastructure_Exception('The region is not valid'); + } + } else { + $this->region = Zend_Service_Rackspace_Servers::US_AUTH_URL; + } + + try { + $this->rackspace = new Zend_Service_Rackspace_Servers($this->accessUser,$this->accessKey, $this->region); + } catch (Exception $e) { + throw new Zend_Cloud_Infrastructure_Exception('Error on create: ' . $e->getMessage(), $e->getCode(), $e); + } + + if (isset($options[self::HTTP_ADAPTER])) { + $this->rackspace->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + + } + /** + * Convert the attributes of Rackspace server into attributes of Infrastructure + * + * @param array $attr + * @return array|boolean + */ + protected function convertAttributes($attr) + { + $result = array(); + if (!empty($attr) && is_array($attr)) { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ID] = $attr['id']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_NAME] = $attr['name']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STATUS] = $this->mapStatus[$attr['status']]; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_IMAGEID] = $attr['imageId']; + if ($this->region==Zend_Service_Rackspace_Servers::US_AUTH_URL) { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = self::RACKSPACE_ZONE_USA; + } else { + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_ZONE] = self::RACKSPACE_ZONE_UK; + } + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_RAM] = $this->flavors[$attr['flavorId']]['ram']; + $result[Zend_Cloud_Infrastructure_Instance::INSTANCE_STORAGE] = $this->flavors[$attr['flavorId']]['disk']; + } + return $result; + } + /** + * Return a list of the available instancies + * + * @return InstanceList|boolean + */ + public function listInstances() + { + $this->adapterResult = $this->rackspace->listServers(true); + if ($this->adapterResult===false) { + return false; + } + $array= $this->adapterResult->toArray(); + $result = array(); + foreach ($array as $instance) { + $result[]= $this->convertAttributes($instance); + } + return new Zend_Cloud_Infrastructure_InstanceList($this, $result); + } + /** + * Return the status of an instance + * + * @param string + * @return string|boolean + */ + public function statusInstance($id) + { + $this->adapterResult = $this->rackspace->getServer($id); + if ($this->adapterResult===false) { + return false; + } + $array= $this->adapterResult->toArray(); + return $this->mapStatus[$array['status']]; + } + /** + * Return the public DNS name/Ip address of the instance + * + * @param string $id + * @return string|boolean + */ + public function publicDnsInstance($id) + { + $this->adapterResult = $this->rackspace->getServerPublicIp($id); + if (empty($this->adapterResult)) { + return false; + } + return $this->adapterResult[0]; + } + /** + * Reboot an instance + * + * @param string $id + * @return boolean + */ + public function rebootInstance($id) + { + return $this->rackspace->rebootServer($id,true); + } + /** + * Create a new instance + * + * @param string $name + * @param array $options + * @return Instance|boolean + */ + public function createInstance($name, $options) + { + if (empty($name)) { + throw new Zend_Cloud_Infrastructure_Exception('You must specify the name of the instance'); + } + if (empty($options) || !is_array($options)) { + throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); + } + // @todo create an generic abstract definition for an instance? + $metadata= array(); + if (isset($options['metadata'])) { + $metadata= $options['metadata']; + unset($options['metadata']); + } + $files= array(); + if (isset($options['files'])) { + $files= $options['files']; + unset($options['files']); + } + $options['name']= $name; + $this->adapterResult = $this->rackspace->createServer($options,$metadata,$files); + if ($this->adapterResult===false) { + return false; + } + return new Zend_Cloud_Infrastructure_Instance($this, $this->convertAttributes($this->adapterResult->toArray())); + } + /** + * Stop an instance + * + * @param string $id + * @return boolean + */ + public function stopInstance($id) + { + throw new Zend_Cloud_Infrastructure_Exception('The stopInstance method is not implemented in the adapter'); + } + + /** + * Start an instance + * + * @param string $id + * @return boolean + */ + public function startInstance($id) + { + throw new Zend_Cloud_Infrastructure_Exception('The startInstance method is not implemented in the adapter'); + } + + /** + * Destroy an instance + * + * @param string $id + * @return boolean + */ + public function destroyInstance($id) + { + $this->adapterResult= $this->rackspace->deleteServer($id); + return $this->adapterResult; + } + /** + * Return a list of all the available instance images + * + * @return ImageList|boolean + */ + public function imagesInstance() + { + $this->adapterResult = $this->rackspace->listImages(true); + if ($this->adapterResult===false) { + return false; + } + + $images= $this->adapterResult->toArray(); + $result= array(); + + foreach ($images as $image) { + if (strtolower($image['status'])==='active') { + if (strpos($image['name'],'Windows')!==false) { + $platform = Zend_Cloud_Infrastructure_Image::IMAGE_WINDOWS; + } else { + $platform = Zend_Cloud_Infrastructure_Image::IMAGE_LINUX; + } + if (strpos($image['name'],'x64')!==false) { + $arch = Zend_Cloud_Infrastructure_Image::ARCH_64BIT; + } else { + $arch = Zend_Cloud_Infrastructure_Image::ARCH_32BIT; + } + $result[]= array ( + Zend_Cloud_Infrastructure_Image::IMAGE_ID => $image['id'], + Zend_Cloud_Infrastructure_Image::IMAGE_NAME => $image['name'], + Zend_Cloud_Infrastructure_Image::IMAGE_DESCRIPTION => $image['name'], + Zend_Cloud_Infrastructure_Image::IMAGE_ARCHITECTURE => $arch, + Zend_Cloud_Infrastructure_Image::IMAGE_PLATFORM => $platform, + ); + } + } + return new Zend_Cloud_Infrastructure_ImageList($result,$this->adapterResult); + } + /** + * Return all the available zones + * + * @return array + */ + public function zonesInstance() + { + return array(self::RACKSPACE_ZONE_USA,self::RACKSPACE_ZONE_UK); + } + /** + * Return the system information about the $metric of an instance + * NOTE: it works only for Linux servers + * + * @param string $id + * @param string $metric + * @param null|array $options + * @return array|boolean + */ + public function monitorInstance($id, $metric, $options = null) + { + if (!function_exists("ssh2_connect")) { + throw new Zend_Cloud_Infrastructure_Exception('Monitor requires the PHP "SSH" extension (ext/ssh2)'); + } + if (empty($id)) { + throw new Zend_Cloud_Infrastructure_Exception('You must specify the id of the instance to monitor'); + } + if (empty($metric)) { + throw new Zend_Cloud_Infrastructure_Exception('You must specify the metric to monitor'); + } + if (!in_array($metric,$this->validMetrics)) { + throw new Zend_Cloud_Infrastructure_Exception(sprintf('The metric "%s" is not valid', $metric)); + } + if (!empty($options) && !is_array($options)) { + throw new Zend_Cloud_Infrastructure_Exception('The options must be an array'); + } + + switch ($metric) { + case Zend_Cloud_Infrastructure_Instance::MONITOR_CPU: + $cmd= 'top -b -n '.self::MONITOR_CPU_SAMPLES.' | grep \'Cpu\''; + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_RAM: + $cmd= 'top -b -n 1 | grep \'Mem\''; + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_DISK: + $cmd= 'df --total | grep total'; + break; + } + if (empty($cmd)) { + throw new Zend_Cloud_Infrastructure_Exception('The metric specified is not supported by the adapter'); + } + + $params= array( + Zend_Cloud_Infrastructure_Instance::SSH_USERNAME => $options['username'], + Zend_Cloud_Infrastructure_Instance::SSH_PASSWORD => $options['password'] + ); + $exec_time= time(); + $result= $this->deployInstance($id,$params,$cmd); + + if (empty($result)) { + return false; + } + + $monitor = array(); + $num = 0; + $average = 0; + + $outputs= explode("\n",$result); + foreach ($outputs as $output) { + if (!empty($output)) { + switch ($metric) { + case Zend_Cloud_Infrastructure_Instance::MONITOR_CPU: + if (preg_match('/(\d+\.\d)%us/', $output,$match)) { + $usage = (float) $match[1]; + } + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_RAM: + if (preg_match('/(\d+)k total/', $output,$match)) { + $total = (integer) $match[1]; + } + if (preg_match('/(\d+)k used/', $output,$match)) { + $used = (integer) $match[1]; + } + if ($total>0) { + $usage= (float) $used/$total; + } + break; + case Zend_Cloud_Infrastructure_Instance::MONITOR_DISK: + if (preg_match('/(\d+)%/', $output,$match)) { + $usage = (float) $match[1]; + } + break; + } + + $monitor['series'][] = array ( + 'timestamp' => $exec_time, + 'value' => number_format($usage,2).'%' + ); + + $average += $usage; + $exec_time+= 60; // seconds + $num++; + } + } + + if ($num>0) { + $monitor['average'] = number_format($average/$num,2).'%'; + } + return $monitor; + } + /** + * Get the adapter + * + * @return Zend_Service_Rackspace_Servers + */ + public function getAdapter() + { + return $this->rackspace; + } + /** + * Get last HTTP request + * + * @return string + */ + public function getLastHttpRequest() + { + return $this->rackspace->getHttpClient()->getLastRequest(); + } + /** + * Get the last HTTP response + * + * @return Zend_Http_Response + */ + public function getLastHttpResponse() + { + return $this->rackspace->getHttpClient()->getLastResponse(); + } +} diff --git a/library/vendor/Zend/Cloud/Infrastructure/Exception.php b/library/vendor/Zend/Cloud/Infrastructure/Exception.php new file mode 100644 index 000000000..1b251fb0e --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/Exception.php @@ -0,0 +1,24 @@ +toArray(); + } elseif ($data instanceof Traversable) { + $data = iterator_to_array($data); + } + } + + if (empty($data) || !is_array($data)) { + throw new Zend_Cloud_Infrastructure_Exception('You must pass an array of parameters'); + } + + foreach ($this->attributeRequired as $key) { + if (empty($data[$key])) { + throw new Zend_Cloud_Infrastructure_Exception(sprintf( + 'The param "%s" is a required parameter for class %s', + $key, + __CLASS__ + )); + } + } + + $this->attributes = $data; + $this->adapter = $adapter; + } + + /** + * Get Attribute with a specific key + * + * @param array $data + * @return misc|boolean + */ + public function getAttribute($key) + { + if (!empty($this->attributes[$key])) { + return $this->attributes[$key]; + } + return false; + } + + /** + * Get all the attributes + * + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Get the image ID + * + * @return string + */ + public function getId() + { + return $this->attributes[self::IMAGE_ID]; + } + + /** + * Get the Owner ID + * + * @return string + */ + public function getOwnerId() + { + return $this->attributes[self::IMAGE_OWNERID]; + } + + /** + * Get the name + * + * @return string + */ + public function getName() + { + return $this->attributes[self::IMAGE_NAME]; + } + + /** + * Get the description + * + * @return string + */ + public function getDescription() + { + return $this->attributes[self::IMAGE_DESCRIPTION]; + } + + /** + * Get the platform + * + * @return string + */ + public function getPlatform() + { + return $this->attributes[self::IMAGE_PLATFORM]; + } + + /** + * Get the architecture + * + * @return string + */ + public function getArchitecture() + { + return $this->attributes[self::IMAGE_ARCHITECTURE]; + } +} diff --git a/library/vendor/Zend/Cloud/Infrastructure/ImageList.php b/library/vendor/Zend/Cloud/Infrastructure/ImageList.php new file mode 100644 index 000000000..c80c2c29a --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/ImageList.php @@ -0,0 +1,213 @@ +adapter = $adapter; + $this->constructFromArray($images); + } + + /** + * Transforms the Array to array of Instances + * + * @param array $list + * @return void + */ + protected function constructFromArray(array $list) + { + foreach ($list as $image) { + $this->addImage(new Zend_Cloud_Infrastructure_Image($image, $this->adapter)); + } + } + + /** + * Add an image + * + * @param Image + * @return ImageList + */ + protected function addImage(Zend_Cloud_Infrastructure_Image $image) + { + $this->images[] = $image; + return $this; + } + + /** + * Return number of images + * + * Implement Countable::count() + * + * @return int + */ + public function count() + { + return count($this->images); + } + + /** + * Return the current element + * + * Implement Iterator::current() + * + * @return Image + */ + public function current() + { + return $this->images[$this->iteratorKey]; + } + + /** + * Return the key of the current element + * + * Implement Iterator::key() + * + * @return int + */ + public function key() + { + return $this->iteratorKey; + } + + /** + * Move forward to next element + * + * Implement Iterator::next() + * + * @return void + */ + public function next() + { + $this->iteratorKey++; + } + + /** + * Rewind the Iterator to the first element + * + * Implement Iterator::rewind() + * + * @return void + */ + public function rewind() + { + $this->iteratorKey = 0; + } + + /** + * Check if there is a current element after calls to rewind() or next() + * + * Implement Iterator::valid() + * + * @return bool + */ + public function valid() + { + $numItems = $this->count(); + if ($numItems > 0 && $this->iteratorKey < $numItems) { + return true; + } + return false; + } + + /** + * Whether the offset exists + * + * Implement ArrayAccess::offsetExists() + * + * @param int $offset + * @return bool + */ + public function offsetExists($offset) + { + return ($offset < $this->count()); + } + + /** + * Return value at given offset + * + * Implement ArrayAccess::offsetGet() + * + * @param int $offset + * @throws Zend_Cloud_Infrastructure_Exception + * @return Image + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + throw new Zend_Cloud_Infrastructure_Exception('Illegal index'); + } + return $this->images[$offset]; + } + + /** + * Throws exception because all values are read-only + * + * Implement ArrayAccess::offsetSet() + * + * @param int $offset + * @param string $value + * @throws Zend_Cloud_Infrastructure_Exception + */ + public function offsetSet($offset, $value) + { + throw new Zend_Cloud_Infrastructure_Exception('You are trying to set read-only property'); + } + + /** + * Throws exception because all values are read-only + * + * Implement ArrayAccess::offsetUnset() + * + * @param int $offset + * @throws Zend_Cloud_Infrastructure_Exception + */ + public function offsetUnset($offset) + { + throw new Zend_Cloud_Infrastructure_Exception('You are trying to unset read-only property'); + } +} diff --git a/library/vendor/Zend/Cloud/Infrastructure/Instance.php b/library/vendor/Zend/Cloud/Infrastructure/Instance.php new file mode 100644 index 000000000..3a1caaa48 --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/Instance.php @@ -0,0 +1,317 @@ +toArray(); + } elseif ($data instanceof Traversable) { + $data = iterator_to_array($data); + } + } + + if (empty($data) || !is_array($data)) { + throw new Zend_Cloud_Infrastructure_Exception("You must pass an array of parameters"); + } + + foreach ($this->attributeRequired as $key) { + if (empty($data[$key])) { + throw new Zend_Cloud_Infrastructure_Exception(sprintf( + 'The param "%s" is a required param for %s', + $key, + __CLASS__ + )); + } + } + + $this->adapter = $adapter; + $this->attributes = $data; + } + + /** + * Get Attribute with a specific key + * + * @param array $data + * @return misc|false + */ + public function getAttribute($key) + { + if (!empty($this->attributes[$key])) { + return $this->attributes[$key]; + } + return false; + } + + /** + * Get all the attributes + * + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Get the instance's id + * + * @return string + */ + public function getId() + { + return $this->attributes[self::INSTANCE_ID]; + } + + /** + * Get the instance's image id + * + * @return string + */ + public function getImageId() + { + return $this->attributes[self::INSTANCE_IMAGEID]; + } + + /** + * Get the instance's name + * + * @return string + */ + public function getName() + { + return $this->attributes[self::INSTANCE_NAME]; + } + + /** + * Get the status of the instance + * + * @return string|boolean + */ + public function getStatus() + { + return $this->adapter->statusInstance($this->attributes[self::INSTANCE_ID]); + } + + /** + * Wait for status $status with a timeout of $timeout seconds + * + * @param string $status + * @param integer $timeout + * @return boolean + */ + public function waitStatus($status, $timeout = Adapter::TIMEOUT_STATUS_CHANGE) + { + return $this->adapter->waitStatusInstance($this->attributes[self::INSTANCE_ID], $status, $timeout); + } + + /** + * Get the public DNS of the instance + * + * @return string + */ + public function getPublicDns() + { + if (!isset($this->attributes[self::INSTANCE_PUBLICDNS])) { + $this->attributes[self::INSTANCE_PUBLICDNS] = $this->adapter->publicDnsInstance($this->attributes[self::INSTANCE_ID]); + } + return $this->attributes[self::INSTANCE_PUBLICDNS]; + } + + /** + * Get the instance's CPU + * + * @return string + */ + public function getCpu() + { + return $this->attributes[self::INSTANCE_CPU]; + } + + /** + * Get the instance's RAM size + * + * @return string + */ + public function getRamSize() + { + return $this->attributes[self::INSTANCE_RAM]; + } + + /** + * Get the instance's storage size + * + * @return string + */ + public function getStorageSize() + { + return $this->attributes[self::INSTANCE_STORAGE]; + } + + /** + * Get the instance's zone + * + * @return string + */ + public function getZone() + { + return $this->attributes[self::INSTANCE_ZONE]; + } + + /** + * Get the instance's launch time + * + * @return string + */ + public function getLaunchTime() + { + return $this->attributes[self::INSTANCE_LAUNCHTIME]; + } + + /** + * Reboot the instance + * + * @return boolean + */ + public function reboot() + { + return $this->adapter->rebootInstance($this->attributes[self::INSTANCE_ID]); + } + + /** + * Stop the instance + * + * @return boolean + */ + public function stop() + { + return $this->adapter->stopInstance($this->attributes[self::INSTANCE_ID]); + } + + /** + * Start the instance + * + * @return boolean + */ + public function start() + { + return $this->adapter->startInstance($this->attributes[self::INSTANCE_ID]); + } + + /** + * Destroy the instance + * + * @return boolean + */ + public function destroy() + { + return $this->adapter->destroyInstance($this->attributes[self::INSTANCE_ID]); + } + + /** + * Return the system informations about the $metric of an instance + * + * @param string $metric + * @param null|array $options + * @return array|boolean + */ + public function monitor($metric, $options = null) + { + return $this->adapter->monitorInstance($this->attributes[self::INSTANCE_ID], $metric, $options); + } + + /** + * Run arbitrary shell script on the instance + * + * @param array $param + * @param string|array $cmd + * @return string|array + */ + public function deploy($params, $cmd) + { + return $this->adapter->deployInstance($this->attributes[self::INSTANCE_ID], $params, $cmd); + } +} diff --git a/library/vendor/Zend/Cloud/Infrastructure/InstanceList.php b/library/vendor/Zend/Cloud/Infrastructure/InstanceList.php new file mode 100644 index 000000000..40edf0635 --- /dev/null +++ b/library/vendor/Zend/Cloud/Infrastructure/InstanceList.php @@ -0,0 +1,213 @@ +adapter = $adapter; + $this->constructFromArray($instances); + } + + /** + * Transforms the Array to array of Instances + * + * @param array $list + * @return void + */ + protected function constructFromArray(array $list) + { + foreach ($list as $instance) { + $this->addInstance(new Zend_Cloud_Infrastructure_Instance($this->adapter,$instance)); + } + } + + /** + * Add an instance + * + * @param Instance + * @return InstanceList + */ + protected function addInstance(Zend_Cloud_Infrastructure_Instance $instance) + { + $this->instances[] = $instance; + return $this; + } + + /** + * Return number of instances + * + * Implement Countable::count() + * + * @return int + */ + public function count() + { + return count($this->instances); + } + + /** + * Return the current element + * + * Implement Iterator::current() + * + * @return Instance + */ + public function current() + { + return $this->instances[$this->iteratorKey]; + } + + /** + * Return the key of the current element + * + * Implement Iterator::key() + * + * @return int + */ + public function key() + { + return $this->iteratorKey; + } + + /** + * Move forward to next element + * + * Implement Iterator::next() + * + * @return void + */ + public function next() + { + $this->iteratorKey++; + } + + /** + * Rewind the Iterator to the first element + * + * Implement Iterator::rewind() + * + * @return void + */ + public function rewind() + { + $this->iteratorKey = 0; + } + + /** + * Check if there is a current element after calls to rewind() or next() + * + * Implement Iterator::valid() + * + * @return bool + */ + public function valid() + { + $numItems = $this->count(); + if ($numItems > 0 && $this->iteratorKey < $numItems) { + return true; + } + return false; + } + + /** + * Whether the offset exists + * + * Implement ArrayAccess::offsetExists() + * + * @param int $offset + * @return bool + */ + public function offsetExists($offset) + { + return ($offset < $this->count()); + } + + /** + * Return value at given offset + * + * Implement ArrayAccess::offsetGet() + * + * @param int $offset + * @return Instance + * @throws Zend_Cloud_Infrastructure_Exception + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + throw new Zend_Cloud_Infrastructure_Exception('Illegal index'); + } + return $this->instances[$offset]; + } + + /** + * Throws exception because all values are read-only + * + * Implement ArrayAccess::offsetSet() + * + * @param int $offset + * @param string $value + * @throws Zend_Cloud_Infrastructure_Exception + */ + public function offsetSet($offset, $value) + { + throw new Zend_Cloud_Infrastructure_Exception('You are trying to set read-only property'); + } + + /** + * Throws exception because all values are read-only + * + * Implement ArrayAccess::offsetUnset() + * + * @param int $offset + * @throws Zend_Cloud_Infrastructure_Exception + */ + public function offsetUnset($offset) + { + throw new Zend_Cloud_Infrastructure_Exception('You are trying to unset read-only property'); + } +} diff --git a/library/vendor/Zend/Cloud/OperationNotAvailableException.php b/library/vendor/Zend/Cloud/OperationNotAvailableException.php new file mode 100644 index 000000000..953c29507 --- /dev/null +++ b/library/vendor/Zend/Cloud/OperationNotAvailableException.php @@ -0,0 +1,33 @@ +_messageClass = (string) $class; + return $this; + } + + /** + * Get class to use for message objects + * + * @return string + */ + public function getMessageClass() + { + return $this->_messageClass; + } + + /** + * Set class to use for message collection objects + * + * @param string $class + * @return Zend_Cloud_QueueService_Adapter_AbstractAdapter + */ + public function setMessageSetClass($class) + { + $this->_messageSetClass = (string) $class; + return $this; + } + + /** + * Get class to use for message collection objects + * + * @return string + */ + public function getMessageSetClass() + { + return $this->_messageSetClass; + } +} diff --git a/library/vendor/Zend/Cloud/QueueService/Adapter/Sqs.php b/library/vendor/Zend/Cloud/QueueService/Adapter/Sqs.php new file mode 100644 index 000000000..df778ade2 --- /dev/null +++ b/library/vendor/Zend/Cloud/QueueService/Adapter/Sqs.php @@ -0,0 +1,273 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_QueueService_Exception('Invalid options provided'); + } + + if (isset($options[self::MESSAGE_CLASS])) { + $this->setMessageClass($options[self::MESSAGE_CLASS]); + } + + if (isset($options[self::MESSAGESET_CLASS])) { + $this->setMessageSetClass($options[self::MESSAGESET_CLASS]); + } + + try { + $this->_sqs = new Zend_Service_Amazon_Sqs( + $options[self::AWS_ACCESS_KEY], $options[self::AWS_SECRET_KEY] + ); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); + } + + if(isset($options[self::HTTP_ADAPTER])) { + $this->_sqs->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + } + + /** + * Create a queue. Returns the ID of the created queue (typically the URL). + * It may take some time to create the queue. Check your vendor's + * documentation for details. + * + * @param string $name + * @param array $options + * @return string Queue ID (typically URL) + */ + public function createQueue($name, $options = null) + { + try { + return $this->_sqs->create($name, $options[self::CREATE_TIMEOUT]); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on queue creation: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Delete a queue. All messages in the queue will also be deleted. + * + * @param string $queueId + * @param array $options + * @return boolean true if successful, false otherwise + */ + public function deleteQueue($queueId, $options = null) +{ + try { + return $this->_sqs->delete($queueId); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on queue deletion: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * List all queues. + * + * @param array $options + * @return array Queue IDs + */ + public function listQueues($options = null) + { + try { + return $this->_sqs->getQueues(); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on listing queues: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get a key/value array of metadata for the given queue. + * + * @param string $queueId + * @param array $options + * @return array + */ + public function fetchQueueMetadata($queueId, $options = null) + { + try { + // TODO: ZF-9050 Fix the SQS client library in trunk to return all attribute values + $attributes = $this->_sqs->getAttribute($queueId, 'All'); + if(is_array($attributes)) { + return $attributes; + } else { + return array('All' => $this->_sqs->getAttribute($queueId, 'All')); + } + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on fetching queue metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Store a key/value array of metadata for the specified queue. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. Some adapters may not support this method. + * + * @param array $metadata + * @param string $queueId + * @param array $options + * @return void + */ + public function storeQueueMetadata($queueId, $metadata, $options = null) + { + // TODO Add support for SetQueueAttributes to client library + throw new Zend_Cloud_OperationNotAvailableException('Amazon SQS doesn\'t currently support storing metadata'); + } + + /** + * Send a message to the specified queue. + * + * @param string $message + * @param string $queueId + * @param array $options + * @return string Message ID + */ + public function sendMessage($queueId, $message, $options = null) + { + try { + return $this->_sqs->send($queueId, $message); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on sending message: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Recieve at most $max messages from the specified queue and return the + * message IDs for messages recieved. + * + * @param string $queueId + * @param int $max + * @param array $options + * @return array + */ + public function receiveMessages($queueId, $max = 1, $options = null) + { + try { + return $this->_makeMessages($this->_sqs->receive($queueId, $max, $options[self::VISIBILITY_TIMEOUT])); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on recieving messages: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Create Zend_Cloud_QueueService_Message array for + * Sqs messages. + * + * @param array $messages + * @return Zend_Cloud_QueueService_Message[] + */ + protected function _makeMessages($messages) + { + $messageClass = $this->getMessageClass(); + $setClass = $this->getMessageSetClass(); + $result = array(); + foreach($messages as $message) { + $result[] = new $messageClass($message['body'], $message); + } + return new $setClass($result); + } + + /** + * Delete the specified message from the specified queue. + * + * @param string $queueId + * @param Zend_Cloud_QueueService_Message $message + * @param array $options + * @return void + */ + public function deleteMessage($queueId, $message, $options = null) + { + try { + if($message instanceof Zend_Cloud_QueueService_Message) { + $message = $message->getMessage(); + } + $messageId = $message['handle']; + return $this->_sqs->deleteMessage($queueId, $messageId); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on deleting a message: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Peek at the messages from the specified queue without removing them. + * + * @param string $queueId + * @param int $num How many messages + * @param array $options + * @return Zend_Cloud_QueueService_Message[] + */ + public function peekMessages($queueId, $num = 1, $options = null) + { + try { + return $this->_makeMessages($this->_sqs->receive($queueId, $num, 0)); + } catch(Zend_Service_Amazon_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on peeking messages: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get SQS implementation + * @return Zend_Service_Amazon_Sqs + */ + public function getClient() + { + return $this->_sqs; + } +} diff --git a/library/vendor/Zend/Cloud/QueueService/Adapter/WindowsAzure.php b/library/vendor/Zend/Cloud/QueueService/Adapter/WindowsAzure.php new file mode 100755 index 000000000..0c3919f73 --- /dev/null +++ b/library/vendor/Zend/Cloud/QueueService/Adapter/WindowsAzure.php @@ -0,0 +1,340 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_QueueService_Exception('Invalid options provided'); + } + + if (isset($options[self::MESSAGE_CLASS])) { + $this->setMessageClass($options[self::MESSAGE_CLASS]); + } + + if (isset($options[self::MESSAGESET_CLASS])) { + $this->setMessageSetClass($options[self::MESSAGESET_CLASS]); + } + + // Build Zend_Service_WindowsAzure_Storage_Blob instance + if (!isset($options[self::HOST])) { + $host = self::DEFAULT_HOST; + } else { + $host = $options[self::HOST]; + } + if (! isset($options[self::ACCOUNT_NAME])) { + throw new Zend_Cloud_Storage_Exception('No Windows Azure account name provided.'); + } + if (! isset($options[self::ACCOUNT_KEY])) { + throw new Zend_Cloud_Storage_Exception('No Windows Azure account key provided.'); + } + try { + // TODO: support $usePathStyleUri and $retryPolicy + $this->_storageClient = new Zend_Service_WindowsAzure_Storage_Queue( + $host, $options[self::ACCOUNT_NAME], $options[self::ACCOUNT_KEY]); + // Parse other options + if (! empty($options[self::PROXY_HOST])) { + $proxyHost = $options[self::PROXY_HOST]; + $proxyPort = isset($options[self::PROXY_PORT]) ? $options[self::PROXY_PORT] : 8080; + $proxyCredentials = isset($options[self::PROXY_CREDENTIALS]) ? $options[self::PROXY_CREDENTIALS] : ''; + $this->_storageClient->setProxy(true, $proxyHost, $proxyPort, $proxyCredentials); + } + if (isset($options[self::HTTP_ADAPTER])) { + $this->_storageClient->setHttpClientChannel($httpAdapter); + } + } catch(Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); + } + + } + + /** + * Create a queue. Returns the ID of the created queue (typically the URL). + * It may take some time to create the queue. Check your vendor's + * documentation for details. + * + * @param string $name + * @param array $options + * @return string Queue ID (typically URL) + */ + public function createQueue($name, $options = null) + { + try { + $queue = $this->_storageClient->createQueue($name, $options); + return $queue->Name; + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on queue creation: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Delete a queue. All messages in the queue will also be deleted. + * + * @param string $queueId + * @param array $options + * @return boolean true if successful, false otherwise + */ + public function deleteQueue($queueId, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + return $this->_storageClient->deleteQueue($queueId); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on queue deletion: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * List all queues. + * + * @param array $options + * @return array Queue IDs + */ + public function listQueues($options = null) + { + $prefix = $maxResults = null; + if (is_array($options)) { + isset($options[self::LIST_PREFIX]) ? $prefix = $options[self::LIST_PREFIX] : null; + isset($options[self::LIST_MAX_RESULTS]) ? $maxResults = $options[self::LIST_MAX_RESULTS] : null; + } + try { + $queues = $this->_storageClient->listQueues($prefix, $maxResults); + $result = array(); + foreach ($queues as $queue) { + $result[] = $queue->Name; + } + return $result; + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on listing queues: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get a key/value array of metadata for the given queue. + * + * @param string $queueId + * @param array $options + * @return array + */ + public function fetchQueueMetadata($queueId, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + return $this->_storageClient->getQueueMetadata($queueId); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on fetching queue metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Store a key/value array of metadata for the specified queue. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. Some adapters may not support this method. + * + * @param string $queueId + * @param array $metadata + * @param array $options + * @return void + */ + public function storeQueueMetadata($queueId, $metadata, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + return $this->_storageClient->setQueueMetadata($queueId, $metadata); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on setting queue metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Send a message to the specified queue. + * + * @param string $queueId + * @param string $message + * @param array $options + * @return string Message ID + */ + public function sendMessage($queueId, $message, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + return $this->_storageClient->putMessage( + $queueId, $message, $options[self::MESSAGE_TTL] + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on sending message: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Recieve at most $max messages from the specified queue and return the + * message IDs for messages recieved. + * + * @param string $queueId + * @param int $max + * @param array $options + * @return Zend_Cloud_QueueService_Message[] + */ + public function receiveMessages($queueId, $max = 1, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + if (isset($options[self::VISIBILITY_TIMEOUT])) { + $visibility = $options[self::VISIBILITY_TIMEOUT]; + } else { + $visibility = self::DEFAULT_TIMEOUT; + } + return $this->_makeMessages($this->_storageClient->getMessages($queueId, $max, $visibility, false)); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on recieving messages: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Create Zend_Cloud_QueueService_Message array for + * Azure messages. + * + * @param array $messages + * @return Zend_Cloud_QueueService_Message[] + */ + protected function _makeMessages($messages) + { + $messageClass = $this->getMessageClass(); + $setClass = $this->getMessageSetClass(); + $result = array(); + foreach ($messages as $message) { + $result[] = new $messageClass($message->MessageText, $message); + } + return new $setClass($result); + } + + /** + * Delete the specified message from the specified queue. + * + * @param string $queueId + * @param Zend_Cloud_QueueService_Message $message Message ID or message + * @param array $options + * @return void + */ + public function deleteMessage($queueId, $message, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + if ($message instanceof Zend_Cloud_QueueService_Message) { + $message = $message->getMessage(); + } + if ($message instanceof Zend_Service_WindowsAzure_Storage_QueueMessage) { + return $this->_storageClient->deleteMessage($queueId, $message); + } else { + throw new Zend_Cloud_QueueService_Exception('Cannot delete the message: message object required'); + } + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on deleting a message: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Peek at the messages from the specified queue without removing them. + * + * @param string $queueId + * @param int $num How many messages + * @param array $options + * @return Zend_Cloud_QueueService_Message[] + */ + public function peekMessages($queueId, $num = 1, $options = null) + { + try { + if ($queueId instanceof Zend_Service_WindowsAzure_Storage_QueueInstance) { + $queueId = $queueId->Name; + } + return $this->_makeMessages($this->_storageClient->peekMessages($queueId, $num)); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on peeking messages: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get Azure implementation + * @return Zend_Service_Azure_Storage_Queue + */ + public function getClient() + { + return $this->_storageClient; + } +} diff --git a/library/vendor/Zend/Cloud/QueueService/Adapter/ZendQueue.php b/library/vendor/Zend/Cloud/QueueService/Adapter/ZendQueue.php new file mode 100755 index 000000000..d2b94784d --- /dev/null +++ b/library/vendor/Zend/Cloud/QueueService/Adapter/ZendQueue.php @@ -0,0 +1,297 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_QueueService_Exception('Invalid options provided'); + } + + if (isset($options[self::MESSAGE_CLASS])) { + $this->setMessageClass($options[self::MESSAGE_CLASS]); + } + + if (isset($options[self::MESSAGESET_CLASS])) { + $this->setMessageSetClass($options[self::MESSAGESET_CLASS]); + } + + // Build Zend_Service_WindowsAzure_Storage_Blob instance + if (!isset($options[self::ADAPTER])) { + throw new Zend_Cloud_QueueService_Exception('No Zend_Queue adapter provided'); + } else { + $adapter = $options[self::ADAPTER]; + unset($options[self::ADAPTER]); + } + try { + $this->_queue = new Zend_Queue($adapter, $options); + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Create a queue. Returns the ID of the created queue (typically the URL). + * It may take some time to create the queue. Check your vendor's + * documentation for details. + * + * @param string $name + * @param array $options + * @return string Queue ID (typically URL) + */ + public function createQueue($name, $options = null) + { + try { + $this->_queues[$name] = $this->_queue->createQueue($name, isset($options[Zend_Queue::TIMEOUT])?$options[Zend_Queue::TIMEOUT]:null); + return $name; + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on queue creation: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Delete a queue. All messages in the queue will also be deleted. + * + * @param string $queueId + * @param array $options + * @return boolean true if successful, false otherwise + */ + public function deleteQueue($queueId, $options = null) + { + if (!isset($this->_queues[$queueId])) { + return false; + } + try { + if ($this->_queues[$queueId]->deleteQueue()) { + unset($this->_queues[$queueId]); + return true; + } + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on queue deletion: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * List all queues. + * + * @param array $options + * @return array Queue IDs + */ + public function listQueues($options = null) + { + try { + return $this->_queue->getQueues(); + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on listing queues: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get a key/value array of metadata for the given queue. + * + * @param string $queueId + * @param array $options + * @return array + */ + public function fetchQueueMetadata($queueId, $options = null) + { + if (!isset($this->_queues[$queueId])) { + return false; + } + try { + return $this->_queues[$queueId]->getOptions(); + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on fetching queue metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Store a key/value array of metadata for the specified queue. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. Some adapters may not support this method. + * + * @param string $queueId + * @param array $metadata + * @param array $options + * @return void + */ + public function storeQueueMetadata($queueId, $metadata, $options = null) + { + if (!isset($this->_queues[$queueId])) { + throw new Zend_Cloud_QueueService_Exception("No such queue: $queueId"); + } + try { + return $this->_queues[$queueId]->setOptions($metadata); + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on setting queue metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Send a message to the specified queue. + * + * @param string $queueId + * @param string $message + * @param array $options + * @return string Message ID + */ + public function sendMessage($queueId, $message, $options = null) + { + if (!isset($this->_queues[$queueId])) { + throw new Zend_Cloud_QueueService_Exception("No such queue: $queueId"); + } + try { + return $this->_queues[$queueId]->send($message); + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on sending message: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Recieve at most $max messages from the specified queue and return the + * message IDs for messages recieved. + * + * @param string $queueId + * @param int $max + * @param array $options + * @return array + */ + public function receiveMessages($queueId, $max = 1, $options = null) + { + if (!isset($this->_queues[$queueId])) { + throw new Zend_Cloud_QueueService_Exception("No such queue: $queueId"); + } + try { + $res = $this->_queues[$queueId]->receive($max, isset($options[Zend_Queue::TIMEOUT])?$options[Zend_Queue::TIMEOUT]:null); + if ($res instanceof Iterator) { + return $this->_makeMessages($res); + } else { + return $this->_makeMessages(array($res)); + } + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on recieving messages: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Create Zend_Cloud_QueueService_Message array for + * Azure messages. + * + * @param array $messages + * @return Zend_Cloud_QueueService_Message[] + */ + protected function _makeMessages($messages) + { + $messageClass = $this->getMessageClass(); + $setClass = $this->getMessageSetClass(); + $result = array(); + foreach ($messages as $message) { + $result[] = new $messageClass($message->body, $message); + } + return new $setClass($result); + } + + /** + * Delete the specified message from the specified queue. + * + * @param string $queueId + * @param Zend_Cloud_QueueService_Message $message Message ID or message + * @param array $options + * @return void + */ + public function deleteMessage($queueId, $message, $options = null) + { + if (!isset($this->_queues[$queueId])) { + throw new Zend_Cloud_QueueService_Exception("No such queue: $queueId"); + } + try { + if ($message instanceof Zend_Cloud_QueueService_Message) { + $message = $message->getMessage(); + } + if (!($message instanceof Zend_Queue_Message)) { + throw new Zend_Cloud_QueueService_Exception('Cannot delete the message: Zend_Queue_Message object required'); + } + + return $this->_queues[$queueId]->deleteMessage($message); + } catch (Zend_Queue_Exception $e) { + throw new Zend_Cloud_QueueService_Exception('Error on deleting a message: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Peek at the messages from the specified queue without removing them. + * + * @param string $queueId + * @param int $num How many messages + * @param array $options + * @return Zend_Cloud_QueueService_Message[] + */ + public function peekMessages($queueId, $num = 1, $options = null) + { + throw new Zend_Cloud_OperationNotAvailableException('ZendQueue doesn\'t currently support message peeking'); + } + + /** + * Get Azure implementation + * @return Zend_Queue + */ + public function getClient() + { + return $this->_queue; + } +} diff --git a/library/vendor/Zend/Cloud/QueueService/Exception.php b/library/vendor/Zend/Cloud/QueueService/Exception.php new file mode 100644 index 000000000..9e30d8e49 --- /dev/null +++ b/library/vendor/Zend/Cloud/QueueService/Exception.php @@ -0,0 +1,36 @@ +_body = $body; + $this->_clientMessage = $message; + } + + /** + * Get the message body + * @return string + */ + public function getBody() + { + return $this->_body; + } + + /** + * Get the original adapter-specific message + */ + public function getMessage() + { + return $this->_clientMessage; + } +} diff --git a/library/vendor/Zend/Cloud/QueueService/MessageSet.php b/library/vendor/Zend/Cloud/QueueService/MessageSet.php new file mode 100644 index 000000000..20765b3d9 --- /dev/null +++ b/library/vendor/Zend/Cloud/QueueService/MessageSet.php @@ -0,0 +1,68 @@ +_messageCount = count($messages); + $this->_messages = new ArrayIterator($messages); + } + + /** + * Countable: number of messages in collection + * + * @return int + */ + public function count() + { + return $this->_messageCount; + } + + /** + * IteratorAggregate: return iterable object + * + * @return Traversable + */ + public function getIterator() + { + return $this->_messages; + } +} diff --git a/library/vendor/Zend/Cloud/StorageService/Adapter.php b/library/vendor/Zend/Cloud/StorageService/Adapter.php new file mode 100644 index 000000000..c64cca3c7 --- /dev/null +++ b/library/vendor/Zend/Cloud/StorageService/Adapter.php @@ -0,0 +1,145 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_StorageService_Exception('Invalid options provided'); + } + + if (isset($options[self::LOCAL_DIRECTORY])) { + $this->_directory = $options[self::LOCAL_DIRECTORY]; + } else { + $this->_directory = realpath(sys_get_temp_dir()); + } + } + + /** + * Get an item from the storage service. + * + * TODO: Support streaming + * + * @param string $path + * @param array $options + * @return false|string + */ + public function fetchItem($path, $options = array()) + { + $filepath = $this->_getFullPath($path); + $path = realpath($filepath); + + if (!$path || !file_exists($path)) { + return false; + } + + return file_get_contents($path); + } + + /** + * Store an item in the storage service. + * + * WARNING: This operation overwrites any item that is located at + * $destinationPath. + * + * @TODO Support streams + * + * @param string $destinationPath + * @param mixed $data + * @param array $options + * @return void + */ + public function storeItem($destinationPath, $data, $options = array()) + { + $path = $this->_getFullPath($destinationPath); + file_put_contents($path, $data); + chmod($path, 0777); + } + + /** + * Delete an item in the storage service. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteItem($path, $options = array()) + { + if (!isset($path)) { + return; + } + + $filepath = $this->_getFullPath($path); + if (file_exists($filepath)) { + unlink($filepath); + } + } + + /** + * Copy an item in the storage service to a given path. + * + * WARNING: This operation is *very* expensive for services that do not + * support copying an item natively. + * + * @TODO Support streams for those services that don't support natively + * + * @param string $sourcePath + * @param string $destination path + * @param array $options + * @return void + */ + public function copyItem($sourcePath, $destinationPath, $options = array()) + { + copy($this->_getFullPath($sourcePath), $this->_getFullPath($destinationPath)); + } + + /** + * Move an item in the storage service to a given path. + * + * WARNING: This operation is *very* expensive for services that do not + * support moving an item natively. + * + * @TODO Support streams for those services that don't support natively + * + * @param string $sourcePath + * @param string $destination path + * @param array $options + * @return void + */ + public function moveItem($sourcePath, $destinationPath, $options = array()) + { + rename($this->_getFullPath($sourcePath), $this->_getFullPath($destinationPath)); + } + + /** + * Rename an item in the storage service to a given name. + * + * + * @param string $path + * @param string $name + * @param array $options + * @return void + */ + public function renameItem($path, $name, $options = null) + { + rename( + $this->_getFullPath($path), + dirname($this->_getFullPath($path)) . DIRECTORY_SEPARATOR . $name + ); + } + + /** + * List items in the given directory in the storage service + * + * The $path must be a directory + * + * + * @param string $path Must be a directory + * @param array $options + * @return array A list of item names + */ + public function listItems($path, $options = null) + { + $listing = scandir($this->_getFullPath($path)); + + // Remove the hidden navigation directories + $listing = array_diff($listing, array('.', '..')); + + return $listing; + } + + /** + * Get a key/value array of metadata for the given path. + * + * @param string $path + * @param array $options + * @return array + */ + public function fetchMetadata($path, $options = array()) + { + $fullPath = $this->_getFullPath($path); + $metadata = null; + if (file_exists($fullPath)) { + $metadata = stat(realpath($fullPath)); + } + + return isset($metadata) ? $metadata : false; + } + + /** + * Store a key/value array of metadata at the given path. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. + * + * @param string $destinationPath + * @param array $options + * @return void + */ + public function storeMetadata($destinationPath, $metadata, $options = array()) + { + throw new Zend_Cloud_OperationNotAvailableException('Storing metadata not implemented'); + } + + /** + * Delete a key/value array of metadata at the given path. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteMetadata($path) + { + throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not implemented'); + } + + /** + * Return the full path for the file. + * + * @param string $path + * @return string + */ + private function _getFullPath($path) + { + return $this->_directory . DIRECTORY_SEPARATOR . $path; + } + + /** + * Get the concrete client. + * @return strings + */ + public function getClient() + { + return $this->_directory; + } +} diff --git a/library/vendor/Zend/Cloud/StorageService/Adapter/Rackspace.php b/library/vendor/Zend/Cloud/StorageService/Adapter/Rackspace.php new file mode 100644 index 000000000..c1cc8e7a2 --- /dev/null +++ b/library/vendor/Zend/Cloud/StorageService/Adapter/Rackspace.php @@ -0,0 +1,327 @@ +toArray(); + } + + if (!is_array($options) || empty($options)) { + throw new Zend_Cloud_StorageService_Exception('Invalid options provided'); + } + + try { + $this->_rackspace = new Zend_Service_Rackspace_Files($options[self::USER], $options[self::API_KEY]); + } catch (Zend_Service_Rackspace_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); + } + + if (isset($options[self::HTTP_ADAPTER])) { + $this->_rackspace->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + if (!empty($options[self::REMOTE_CONTAINER])) { + $this->_container = $options[self::REMOTE_CONTAINER]; + } + } + + /** + * Get an item from the storage service. + * + * @param string $path + * @param array $options + * @return mixed + */ + public function fetchItem($path, $options = null) + { + $item = $this->_rackspace->getObject($this->_container,$path, $options); + if (!$this->_rackspace->isSuccessful() && ($this->_rackspace->getErrorCode()!='404')) { + throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$this->_rackspace->getErrorMsg()); + } + if (!empty($item)) { + return $item->getContent(); + } else { + return false; + } + } + + /** + * Store an item in the storage service. + * + * @param string $destinationPath + * @param mixed $data + * @param array $options + * @return void + */ + public function storeItem($destinationPath, $data, $options = null) + { + $this->_rackspace->storeObject($this->_container,$destinationPath,$data,$options); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on store: '.$this->_rackspace->getErrorMsg()); + } + } + + /** + * Delete an item in the storage service. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteItem($path, $options = null) + { + $this->_rackspace->deleteObject($this->_container,$path); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$this->_rackspace->getErrorMsg()); + } + } + + /** + * Copy an item in the storage service to a given path. + * + * @param string $sourcePath + * @param string $destination path + * @param array $options + * @return void + */ + public function copyItem($sourcePath, $destinationPath, $options = null) + { + $this->_rackspace->copyObject($this->_container,$sourcePath,$this->_container,$destinationPath,$options); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$this->_rackspace->getErrorMsg()); + } + } + + /** + * Move an item in the storage service to a given path. + * WARNING: This operation is *very* expensive for services that do not + * support moving an item natively. + * + * @param string $sourcePath + * @param string $destination path + * @param array $options + * @return void + */ + public function moveItem($sourcePath, $destinationPath, $options = null) + { + try { + $this->copyItem($sourcePath, $destinationPath, $options); + } catch (Zend_Service_Rackspace_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage()); + } + try { + $this->deleteItem($sourcePath); + } catch (Zend_Service_Rackspace_Exception $e) { + $this->deleteItem($destinationPath); + throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage()); + } + } + + /** + * Rename an item in the storage service to a given name. + * + * @param string $path + * @param string $name + * @param array $options + * @return void + */ + public function renameItem($path, $name, $options = null) + { + throw new Zend_Cloud_OperationNotAvailableException('Renaming not implemented'); + } + + /** + * Get a key/value array of metadata for the given path. + * + * @param string $path + * @param array $options + * @return array An associative array of key/value pairs specifying the metadata for this object. + * If no metadata exists, an empty array is returned. + */ + public function fetchMetadata($path, $options = null) + { + $result = $this->_rackspace->getMetadataObject($this->_container,$path); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on fetch metadata: '.$this->_rackspace->getErrorMsg()); + } + $metadata = array(); + if (isset($result['metadata'])) { + $metadata = $result['metadata']; + } + // delete the self::DELETE_METADATA_KEY - this is a trick to remove all + // the metadata information of an object (see deleteMetadata). + // Rackspace doesn't have an API to remove the metadata of an object + unset($metadata[self::DELETE_METADATA_KEY]); + return $metadata; + } + + /** + * Store a key/value array of metadata at the given path. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. + * + * @param string $destinationPath + * @param array $metadata associative array specifying the key/value pairs for the metadata. + * @param array $options + * @return void + */ + public function storeMetadata($destinationPath, $metadata, $options = null) + { + $this->_rackspace->setMetadataObject($this->_container, $destinationPath, $metadata); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on store metadata: '.$this->_rackspace->getErrorMsg()); + } + } + + /** + * Delete a key/value array of metadata at the given path. + * + * @param string $path + * @param array $metadata - An associative array specifying the key/value pairs for the metadata + * to be deleted. If null, all metadata associated with the object will + * be deleted. + * @param array $options + * @return void + */ + public function deleteMetadata($path, $metadata = null, $options = null) + { + if (empty($metadata)) { + $newMetadata = array(self::DELETE_METADATA_KEY => true); + try { + $this->storeMetadata($path, $newMetadata); + } catch (Zend_Service_Rackspace_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on delete metadata: '.$e->getMessage()); + } + } else { + try { + $oldMetadata = $this->fetchMetadata($path); + } catch (Zend_Service_Rackspace_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on delete metadata: '.$e->getMessage()); + } + $newMetadata = array_diff_assoc($oldMetadata, $metadata); + try { + $this->storeMetadata($path, $newMetadata); + } catch (Zend_Service_Rackspace_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on delete metadata: '.$e->getMessage()); + } + } + } + + /* + * Recursively traverse all the folders and build an array that contains + * the path names for each folder. + * + * @param string $path folder path to get the list of folders from. + * @param array& $resultArray reference to the array that contains the path names + * for each folder. + * @return void + */ + private function getAllFolders($path, &$resultArray) + { + if (!empty($path)) { + $options = array ( + 'prefix' => $path + ); + } + $files = $this->_rackspace->getObjects($this->_container,$options); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on get all folders: '.$this->_rackspace->getErrorMsg()); + } + $resultArray = array(); + foreach ($files as $file) { + $resultArray[dirname($file->getName())] = true; + } + $resultArray = array_keys($resultArray); + } + + /** + * Return an array of the items contained in the given path. The items + * returned are the files or objects that in the specified path. + * + * @param string $path + * @param array $options + * @return array + */ + public function listItems($path, $options = null) + { + if (!empty($path)) { + $options = array ( + 'prefix' => $path + ); + } + + $files = $this->_rackspace->getObjects($this->_container,$options); + if (!$this->_rackspace->isSuccessful()) { + throw new Zend_Cloud_StorageService_Exception('Error on list items: '.$this->_rackspace->getErrorMsg()); + } + $resultArray = array(); + if (!empty($files)) { + foreach ($files as $file) { + $resultArray[] = $file->getName(); + } + } + return $resultArray; + } + + /** + * Get the concrete client. + * + * @return Zend_Service_Rackspace_File + */ + public function getClient() + { + return $this->_rackspace; + } +} diff --git a/library/vendor/Zend/Cloud/StorageService/Adapter/S3.php b/library/vendor/Zend/Cloud/StorageService/Adapter/S3.php new file mode 100644 index 000000000..1b394792a --- /dev/null +++ b/library/vendor/Zend/Cloud/StorageService/Adapter/S3.php @@ -0,0 +1,324 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_StorageService_Exception('Invalid options provided'); + } + + if (!isset($options[self::AWS_ACCESS_KEY]) || !isset($options[self::AWS_SECRET_KEY])) { + throw new Zend_Cloud_StorageService_Exception('AWS keys not specified!'); + } + + try { + $this->_s3 = new Zend_Service_Amazon_S3($options[self::AWS_ACCESS_KEY], + $options[self::AWS_SECRET_KEY]); + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); + } + + if (isset($options[self::HTTP_ADAPTER])) { + $this->_s3->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); + } + + if (isset($options[self::BUCKET_NAME])) { + $this->_defaultBucketName = $options[self::BUCKET_NAME]; + } + + if (isset($options[self::BUCKET_AS_DOMAIN])) { + $this->_defaultBucketAsDomain = $options[self::BUCKET_AS_DOMAIN]; + } + } + + /** + * Get an item from the storage service. + * + * @TODO Support streams + * + * @param string $path + * @param array $options + * @return string + */ + public function fetchItem($path, $options = array()) + { + $fullPath = $this->_getFullPath($path, $options); + try { + if (!empty($options[self::FETCH_STREAM])) { + return $this->_s3->getObjectStream($fullPath, $options[self::FETCH_STREAM]); + } else { + return $this->_s3->getObject($fullPath); + } + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Store an item in the storage service. + * + * WARNING: This operation overwrites any item that is located at + * $destinationPath. + * + * @TODO Support streams + * + * @param string $destinationPath + * @param string|resource $data + * @param array $options + * @return void + */ + public function storeItem($destinationPath, $data, $options = array()) + { + try { + $fullPath = $this->_getFullPath($destinationPath, $options); + return $this->_s3->putObject( + $fullPath, + $data, + empty($options[self::METADATA]) ? null : $options[self::METADATA] + ); + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on store: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Delete an item in the storage service. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteItem($path, $options = array()) + { + try { + $this->_s3->removeObject($this->_getFullPath($path, $options)); + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Copy an item in the storage service to a given path. + * + * WARNING: This operation is *very* expensive for services that do not + * support copying an item natively. + * + * @TODO Support streams for those services that don't support natively + * + * @param string $sourcePath + * @param string $destination path + * @param array $options + * @return void + */ + public function copyItem($sourcePath, $destinationPath, $options = array()) + { + try { + $fullSourcePath = $this->_getFullPath($sourcePath, $options); + $fullDestPath = $this->_getFullPath($destinationPath, $options); + return $this->_s3->copyObject( + $fullSourcePath, + $fullDestPath, + empty($options[self::METADATA]) ? null : $options[self::METADATA] + ); + + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Move an item in the storage service to a given path. + * + * @TODO Support streams for those services that don't support natively + * + * @param string $sourcePath + * @param string $destination path + * @param array $options + * @return void + */ + public function moveItem($sourcePath, $destinationPath, $options = array()) + { + try { + $fullSourcePath = $this->_getFullPath($sourcePath, $options); + $fullDestPath = $this->_getFullPath($destinationPath, $options); + return $this->_s3->moveObject( + $fullSourcePath, + $fullDestPath, + empty($options[self::METADATA]) ? null : $options[self::METADATA] + ); + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Rename an item in the storage service to a given name. + * + * + * @param string $path + * @param string $name + * @param array $options + * @return void + */ + public function renameItem($path, $name, $options = null) + { + throw new Zend_Cloud_OperationNotAvailableException('Rename not implemented'); + } + + /** + * List items in the given directory in the storage service + * + * The $path must be a directory + * + * + * @param string $path Must be a directory + * @param array $options + * @return array A list of item names + */ + public function listItems($path, $options = null) + { + try { + // TODO Support 'prefix' parameter for Zend_Service_Amazon_S3::getObjectsByBucket() + return $this->_s3->getObjectsByBucket($this->_defaultBucketName); + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on list: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get a key/value array of metadata for the given path. + * + * @param string $path + * @param array $options + * @return array + */ + public function fetchMetadata($path, $options = array()) + { + try { + return $this->_s3->getInfo($this->_getFullPath($path, $options)); + } catch (Zend_Service_Amazon_S3_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Store a key/value array of metadata at the given path. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. + * + * @param string $destinationPath + * @param array $options + * @return void + */ + public function storeMetadata($destinationPath, $metadata, $options = array()) + { + throw new Zend_Cloud_OperationNotAvailableException('Storing separate metadata is not supported, use storeItem() with \'metadata\' option key'); + } + + /** + * Delete a key/value array of metadata at the given path. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteMetadata($path) + { + throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not supported'); + } + + /** + * Get full path, including bucket, for an object + * + * @param string $path + * @param array $options + * @return void + */ + protected function _getFullPath($path, $options) + { + if (isset($options[self::BUCKET_NAME])) { + $bucket = $options[self::BUCKET_NAME]; + } else if (isset($this->_defaultBucketName)) { + $bucket = $this->_defaultBucketName; + } else { + throw new Zend_Cloud_StorageService_Exception('Bucket name must be specified for S3 adapter.'); + } + + if (isset($options[self::BUCKET_AS_DOMAIN])) { + // TODO: support bucket domain names + throw new Zend_Cloud_StorageService_Exception('The S3 adapter does not currently support buckets in domain names.'); + } + + return trim($bucket) . '/' . trim($path); + } + + /** + * Get the concrete client. + * @return Zend_Service_Amazon_S3 + */ + public function getClient() + { + return $this->_s3; + } +} diff --git a/library/vendor/Zend/Cloud/StorageService/Adapter/WindowsAzure.php b/library/vendor/Zend/Cloud/StorageService/Adapter/WindowsAzure.php new file mode 100644 index 000000000..734439f20 --- /dev/null +++ b/library/vendor/Zend/Cloud/StorageService/Adapter/WindowsAzure.php @@ -0,0 +1,440 @@ +toArray(); + } + + if (!is_array($options)) { + throw new Zend_Cloud_StorageService_Exception('Invalid options provided'); + } + + // Build Zend_Service_WindowsAzure_Storage_Blob instance + if (!isset($options[self::HOST])) { + $host = self::DEFAULT_HOST; + } else { + $host = $options[self::HOST]; + } + + if (!isset($options[self::ACCOUNT_NAME])) { + throw new Zend_Cloud_StorageService_Exception('No Windows Azure account name provided.'); + } + if (!isset($options[self::ACCOUNT_KEY])) { + throw new Zend_Cloud_StorageService_Exception('No Windows Azure account key provided.'); + } + + $this->_storageClient = new Zend_Service_WindowsAzure_Storage_Blob($host, + $options[self::ACCOUNT_NAME], $options[self::ACCOUNT_KEY]); + + // Parse other options + if (!empty($options[self::PROXY_HOST])) { + $proxyHost = $options[self::PROXY_HOST]; + $proxyPort = isset($options[self::PROXY_PORT]) ? $options[self::PROXY_PORT] : 8080; + $proxyCredentials = isset($options[self::PROXY_CREDENTIALS]) ? $options[self::PROXY_CREDENTIALS] : ''; + + $this->_storageClient->setProxy(true, $proxyHost, $proxyPort, $proxyCredentials); + } + + if (isset($options[self::HTTP_ADAPTER])) { + $this->_storageClient->setHttpClientChannel($options[self::HTTP_ADAPTER]); + } + + // Set container + $this->_container = $options[self::CONTAINER]; + + // Make sure the container exists + if (!$this->_storageClient->containerExists($this->_container)) { + $this->_storageClient->createContainer($this->_container); + } + } + + /** + * Get an item from the storage service. + * + * @param string $path + * @param array $options + * @return mixed + */ + public function fetchItem($path, $options = null) + { + // Options + $returnType = self::RETURN_STRING; + $returnPath = tempnam('', 'azr'); + $openMode = 'r'; + + // Parse options + if (is_array($options)) { + if (isset($options[self::RETURN_TYPE])) { + $returnType = $options[self::RETURN_TYPE]; + } + + if (isset($options[self::RETURN_PATHNAME])) { + $returnPath = $options[self::RETURN_PATHNAME]; + } + + if (isset($options[self::RETURN_OPENMODE])) { + $openMode = $options[self::RETURN_OPENMODE]; + } + } + + // Fetch the blob + try { + $this->_storageClient->getBlob( + $this->_container, + $path, + $returnPath + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "does not exist") !== false) { + return false; + } + throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); + } + + // Return value + if ($returnType == self::RETURN_PATH) { + return $returnPath; + } + if ($returnType == self::RETURN_STRING) { + return file_get_contents($returnPath); + } + if ($returnType == self::RETURN_STREAM) { + return fopen($returnPath, $openMode); + } + } + + /** + * Store an item in the storage service. + * WARNING: This operation overwrites any item that is located at + * $destinationPath. + * @param string $destinationPath + * @param mixed $data + * @param array $options + * @return boolean + */ + public function storeItem($destinationPath, $data, $options = null) + { + // Create a temporary file that will be uploaded + $temporaryFilePath = ''; + $removeTemporaryFilePath = false; + + if (is_resource($data)) { + $temporaryFilePath = tempnam('', 'azr'); + $fpDestination = fopen($temporaryFilePath, 'w'); + + $fpSource = $data; + rewind($fpSource); + while (!feof($fpSource)) { + fwrite($fpDestination, fread($fpSource, 8192)); + } + + fclose($fpDestination); + + $removeTemporaryFilePath = true; + } elseif (file_exists($data)) { + $temporaryFilePath = $data; + $removeTemporaryFilePath = false; + } else { + $temporaryFilePath = tempnam('', 'azr'); + file_put_contents($temporaryFilePath, $data); + $removeTemporaryFilePath = true; + } + + try { + // Upload data + $this->_storageClient->putBlob( + $this->_container, + $destinationPath, + $temporaryFilePath + ); + } catch(Zend_Service_WindowsAzure_Exception $e) { + @unlink($temporaryFilePath); + throw new Zend_Cloud_StorageService_Exception('Error on store: '.$e->getMessage(), $e->getCode(), $e); + } + if ($removeTemporaryFilePath) { + @unlink($temporaryFilePath); + } + } + + /** + * Delete an item in the storage service. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteItem($path, $options = null) + { + try { + $this->_storageClient->deleteBlob( + $this->_container, + $path + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Copy an item in the storage service to a given path. + * + * @param string $sourcePath + * @param string $destinationPath + * @param array $options + * @return void + */ + public function copyItem($sourcePath, $destinationPath, $options = null) + { + try { + $this->_storageClient->copyBlob( + $this->_container, + $sourcePath, + $this->_container, + $destinationPath + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Move an item in the storage service to a given path. + * + * @param string $sourcePath + * @param string $destinationPath + * @param array $options + * @return void + */ + public function moveItem($sourcePath, $destinationPath, $options = null) + { + try { + $this->_storageClient->copyBlob( + $this->_container, + $sourcePath, + $this->_container, + $destinationPath + ); + + $this->_storageClient->deleteBlob( + $this->_container, + $sourcePath + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage(), $e->getCode(), $e); + } + + } + + /** + * Rename an item in the storage service to a given name. + * + * + * @param string $path + * @param string $name + * @param array $options + * @return void + */ + public function renameItem($path, $name, $options = null) + { + return $this->moveItem($path, $name, $options); + } + + /** + * List items in the given directory in the storage service + * + * The $path must be a directory + * + * + * @param string $path Must be a directory + * @param array $options + * @return array A list of item names + */ + public function listItems($path, $options = null) + { + // Options + $returnType = self::RETURN_NAMES; // 1: return list of paths, 2: return raw output from underlying provider + + // Parse options + if (is_array($options)&& isset($options[self::RETURN_TYPE])) { + $returnType = $options[self::RETURN_TYPE]; + } + + try { + // Fetch list + $blobList = $this->_storageClient->listBlobs( + $this->_container, + $path + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on list: '.$e->getMessage(), $e->getCode(), $e); + } + + // Return + if ($returnType == self::RETURN_LIST) { + return $blobList; + } + + $returnValue = array(); + foreach ($blobList as $blob) { + $returnValue[] = $blob->Name; + } + + return $returnValue; + } + + /** + * Get a key/value array of metadata for the given path. + * + * @param string $path + * @param array $options + * @return array + */ + public function fetchMetadata($path, $options = null) + { + try { + return $this->_storageClient->getBlobMetaData( + $this->_container, + $path + ); + } catch (Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "could not be accessed") !== false) { + return false; + } + throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Store a key/value array of metadata at the given path. + * WARNING: This operation overwrites any metadata that is located at + * $destinationPath. + * + * @param string $destinationPath + * @param array $options + * @return void + */ + public function storeMetadata($destinationPath, $metadata, $options = null) + { + try { + $this->_storageClient->setBlobMetadata($this->_container, $destinationPath, $metadata); + } catch (Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "could not be accessed") === false) { + throw new Zend_Cloud_StorageService_Exception('Error on store metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + } + + /** + * Delete a key/value array of metadata at the given path. + * + * @param string $path + * @param array $options + * @return void + */ + public function deleteMetadata($path, $options = null) + { + try { + $this->_storageClient->setBlobMetadata($this->_container, $destinationPath, array()); + } catch (Zend_Service_WindowsAzure_Exception $e) { + if (strpos($e->getMessage(), "could not be accessed") === false) { + throw new Zend_Cloud_StorageService_Exception('Error on delete metadata: '.$e->getMessage(), $e->getCode(), $e); + } + } + } + + /** + * Delete container + * + * @return void + */ + public function deleteContainer() + { + try { + $this->_storageClient->deleteContainer($this->_container); + } catch (Zend_Service_WindowsAzure_Exception $e) { + throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Get the concrete adapter. + * @return Zend_Service_Azure_Storage_Blob + */ + public function getClient() + { + return $this->_storageClient; + } +} diff --git a/library/vendor/Zend/Cloud/StorageService/Exception.php b/library/vendor/Zend/Cloud/StorageService/Exception.php new file mode 100644 index 000000000..e444cc0bb --- /dev/null +++ b/library/vendor/Zend/Cloud/StorageService/Exception.php @@ -0,0 +1,37 @@ +_init(); + if ($options != null) { + // use Zend_Config objects if provided + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + // pass arrays to setOptions + if (is_array($options)) { + $this->setOptions($options); + } + } + $this->_prepare(); + } + + /** + * setConfig() + * + * @param Zend_Config $config + * @return Zend_CodeGenerator_Abstract + */ + public function setConfig(Zend_Config $config) + { + $this->setOptions($config->toArray()); + return $this; + } + + /** + * setOptions() + * + * @param array $options + * @return Zend_CodeGenerator_Abstract + */ + public function setOptions(Array $options) + { + foreach ($options as $optionName => $optionValue) { + $methodName = 'set' . $optionName; + if (method_exists($this, $methodName)) { + $this->{$methodName}($optionValue); + } + } + return $this; + } + + /** + * setSourceContent() + * + * @param string $sourceContent + */ + public function setSourceContent($sourceContent) + { + $this->_sourceContent = $sourceContent; + return; + } + + /** + * getSourceContent() + * + * @return string + */ + public function getSourceContent() + { + return $this->_sourceContent; + } + + /** + * _init() - this is called before the constuctor + * + */ + protected function _init() + { + + } + + /** + * _prepare() - this is called at construction completion + * + */ + protected function _prepare() + { + + } + + /** + * generate() - must be implemented by the child + * + */ + abstract public function generate(); + + /** + * __toString() - casting to a string will in turn call generate() + * + * @return string + */ + final public function __toString() + { + return $this->generate(); + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Exception.php b/library/vendor/Zend/CodeGenerator/Exception.php new file mode 100644 index 000000000..3b8ae25ba --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Exception.php @@ -0,0 +1,34 @@ +_isSourceDirty = ($isSourceDirty) ? true : false; + return $this; + } + + /** + * isSourceDirty() + * + * @return bool + */ + public function isSourceDirty() + { + return $this->_isSourceDirty; + } + + /** + * setIndentation() + * + * @param string|int $indentation + * @return Zend_CodeGenerator_Php_Abstract + */ + public function setIndentation($indentation) + { + $this->_indentation = $indentation; + return $this; + } + + /** + * getIndentation() + * + * @return string|int + */ + public function getIndentation() + { + return $this->_indentation; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Body.php b/library/vendor/Zend/CodeGenerator/Php/Body.php new file mode 100644 index 000000000..2779580bd --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Body.php @@ -0,0 +1,72 @@ +_content = $content; + return $this; + } + + /** + * getContent() + * + * @return string + */ + public function getContent() + { + return (string) $this->_content; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + return $this->getContent(); + } +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Class.php b/library/vendor/Zend/CodeGenerator/Php/Class.php new file mode 100644 index 000000000..58bd6f8fa --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Class.php @@ -0,0 +1,605 @@ +setSourceContent($class->getSourceContent()); + $class->setSourceDirty(false); + + if ($reflectionClass->getDocComment() != '') { + $class->setDocblock(Zend_CodeGenerator_Php_Docblock::fromReflection($reflectionClass->getDocblock())); + } + + $class->setAbstract($reflectionClass->isAbstract()); + $class->setName($reflectionClass->getName()); + + if ($parentClass = $reflectionClass->getParentClass()) { + $class->setExtendedClass($parentClass->getName()); + $interfaces = array_diff($reflectionClass->getInterfaces(), $parentClass->getInterfaces()); + } else { + $interfaces = $reflectionClass->getInterfaces(); + } + + $interfaceNames = array(); + foreach($interfaces AS $interface) { + $interfaceNames[] = $interface->getName(); + } + + $class->setImplementedInterfaces($interfaceNames); + + $properties = array(); + foreach ($reflectionClass->getProperties() as $reflectionProperty) { + if ($reflectionProperty->getDeclaringClass()->getName() == $class->getName()) { + $properties[] = Zend_CodeGenerator_Php_Property::fromReflection($reflectionProperty); + } + } + $class->setProperties($properties); + + $methods = array(); + foreach ($reflectionClass->getMethods() as $reflectionMethod) { + if ($reflectionMethod->getDeclaringClass()->getName() == $class->getName()) { + $methods[] = Zend_CodeGenerator_Php_Method::fromReflection($reflectionMethod); + } + } + $class->setMethods($methods); + + return $class; + } + + /** + * setDocblock() Set the docblock + * + * @param Zend_CodeGenerator_Php_Docblock|array|string $docblock + * @return Zend_CodeGenerator_Php_File + */ + public function setDocblock($docblock) + { + if (is_string($docblock)) { + $docblock = array('shortDescription' => $docblock); + } + + if (is_array($docblock)) { + $docblock = new Zend_CodeGenerator_Php_Docblock($docblock); + } elseif ((!is_null($docblock)) && (!$docblock instanceof Zend_CodeGenerator_Php_Docblock)) { + throw new Zend_CodeGenerator_Php_Exception('setDocblock() is expecting either a string, array or an instance of Zend_CodeGenerator_Php_Docblock'); + } + + $this->_docblock = $docblock; + return $this; + } + + /** + * getDocblock() + * + * @return Zend_CodeGenerator_Php_Docblock + */ + public function getDocblock() + { + return $this->_docblock; + } + + /** + * setName() + * + * @param string $name + * @return Zend_CodeGenerator_Php_Class + */ + public function setName($name) + { + $this->_name = $name; + return $this; + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * setAbstract() + * + * @param bool $isAbstract + * @return Zend_CodeGenerator_Php_Class + */ + public function setAbstract($isAbstract) + { + $this->_isAbstract = ($isAbstract) ? true : false; + return $this; + } + + /** + * isAbstract() + * + * @return bool + */ + public function isAbstract() + { + return $this->_isAbstract; + } + + /** + * setExtendedClass() + * + * @param string $extendedClass + * @return Zend_CodeGenerator_Php_Class + */ + public function setExtendedClass($extendedClass) + { + $this->_extendedClass = $extendedClass; + return $this; + } + + /** + * getExtendedClass() + * + * @return string + */ + public function getExtendedClass() + { + return $this->_extendedClass; + } + + /** + * setImplementedInterfaces() + * + * @param array $implementedInterfaces + * @return Zend_CodeGenerator_Php_Class + */ + public function setImplementedInterfaces(Array $implementedInterfaces) + { + $this->_implementedInterfaces = $implementedInterfaces; + return $this; + } + + /** + * getImplementedInterfaces + * + * @return array + */ + public function getImplementedInterfaces() + { + return $this->_implementedInterfaces; + } + + /** + * setProperties() + * + * @param array $properties + * @return Zend_CodeGenerator_Php_Class + */ + public function setProperties(Array $properties) + { + foreach ($properties as $property) { + $this->setProperty($property); + } + + return $this; + } + + /** + * setConstants() + * + * @param array $constants + * @return Zend_CodeGenerator_Php_Class + */ + public function setConstants(Array $constants) + { + foreach ($constants as $const) { + $this->setConstant($const); + } + + return $this; + } + + /** + * setProperty() + * + * @param array|Zend_CodeGenerator_Php_Property $property + * @return Zend_CodeGenerator_Php_Class + */ + public function setProperty($property) + { + if (is_array($property)) { + $property = new Zend_CodeGenerator_Php_Property($property); + $propertyName = $property->getName(); + } elseif ($property instanceof Zend_CodeGenerator_Php_Property) { + $propertyName = $property->getName(); + } else { + throw new Zend_CodeGenerator_Php_Exception('setProperty() expects either an array of property options or an instance of Zend_CodeGenerator_Php_Property'); + } + + if ($property->isConst()) { + return $this->setConstant($property); + } + if (isset($this->_properties[$propertyName])) { + throw new Zend_CodeGenerator_Php_Exception('A property by name ' . $propertyName . ' already exists in this class.'); + } + + $this->_properties[$propertyName] = $property; + return $this; + } + + /** + * setConstant() + * + * @param array|Zend_CodeGenerator_Php_Property $const + * @return Zend_CodeGenerator_Php_Class + */ + public function setConstant($const) + { + if (is_array($const)) { + $const = new Zend_CodeGenerator_Php_Property($const); + $constName = $const->getName(); + } elseif ($const instanceof Zend_CodeGenerator_Php_Property) { + $constName = $const->getName(); + } else { + throw new Zend_CodeGenerator_Php_Exception('setConstant() expects either an array of property options or an instance of Zend_CodeGenerator_Php_Property'); + } + + if (!$const->isConst()) { + throw new Zend_CodeGenerator_Php_Exception('setProperty() expects argument to define a constant'); + } + if (isset($this->_constants[$constName])) { + throw new Zend_CodeGenerator_Php_Exception('A constant by name ' . $constName . ' already exists in this class.'); + } + + $this->_constants[$constName] = $const; + return $this; + } + + /** + * getProperties() + * + * @return array + */ + public function getProperties() + { + return $this->_properties; + } + + /** + * getConstants() + * + * @return array + */ + public function getConstants() + { + return $this->_constants; + } + + /** + * getProperty() + * + * @param string $propertyName + * @return Zend_CodeGenerator_Php_Property + */ + public function getProperty($propertyName) + { + foreach ($this->_properties as $property) { + if ($property->getName() == $propertyName) { + return $property; + } + } + return false; + } + + /** + * getConstant() + * + * @param string $constName + * @return Zend_CodeGenerator_Php_Property + */ + public function getConstant($constName) + { + foreach ($this->_constants as $const) { + if ($const->getName() == $constName) { + return $const; + } + } + return false; + } + + /** + * hasProperty() + * + * @param string $propertyName + * @return bool + */ + public function hasProperty($propertyName) + { + return isset($this->_properties[$propertyName]); + } + + /** + * hasConstant() + * + * @param string $constName + * @return bool + */ + public function hasConstant($constName) + { + return isset($this->_constants[$constName]); + } + + /** + * setMethods() + * + * @param array $methods + * @return Zend_CodeGenerator_Php_Class + */ + public function setMethods(Array $methods) + { + foreach ($methods as $method) { + $this->setMethod($method); + } + return $this; + } + + /** + * setMethod() + * + * @param array|Zend_CodeGenerator_Php_Method $method + * @return Zend_CodeGenerator_Php_Class + */ + public function setMethod($method) + { + if (is_array($method)) { + $method = new Zend_CodeGenerator_Php_Method($method); + $methodName = $method->getName(); + } elseif ($method instanceof Zend_CodeGenerator_Php_Method) { + $methodName = $method->getName(); + } else { + throw new Zend_CodeGenerator_Php_Exception('setMethod() expects either an array of method options or an instance of Zend_CodeGenerator_Php_Method'); + } + + if (isset($this->_methods[$methodName])) { + throw new Zend_CodeGenerator_Php_Exception('A method by name ' . $methodName . ' already exists in this class.'); + } + + $this->_methods[$methodName] = $method; + return $this; + } + + /** + * getMethods() + * + * @return array + */ + public function getMethods() + { + return $this->_methods; + } + + /** + * getMethod() + * + * @param string $methodName + * @return Zend_CodeGenerator_Php_Method + */ + public function getMethod($methodName) + { + foreach ($this->_methods as $method) { + if ($method->getName() == $methodName) { + return $method; + } + } + return false; + } + + /** + * hasMethod() + * + * @param string $methodName + * @return bool + */ + public function hasMethod($methodName) + { + return isset($this->_methods[$methodName]); + } + + /** + * isSourceDirty() + * + * @return bool + */ + public function isSourceDirty() + { + if (($docblock = $this->getDocblock()) && $docblock->isSourceDirty()) { + return true; + } + + foreach ($this->_properties as $property) { + if ($property->isSourceDirty()) { + return true; + } + } + + foreach ($this->_constants as $constant) { + if ($constant->isSourceDirty()) { + return true; + } + } + + foreach ($this->_methods as $method) { + if ($method->isSourceDirty()) { + return true; + } + } + + return parent::isSourceDirty(); + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + if (!$this->isSourceDirty()) { + return $this->getSourceContent(); + } + + $output = ''; + + if (null !== ($docblock = $this->getDocblock())) { + $docblock->setIndentation(''); + $output .= $docblock->generate(); + } + + if ($this->isAbstract()) { + $output .= 'abstract '; + } + + $output .= 'class ' . $this->getName(); + + if ( !empty( $this->_extendedClass) ) { + $output .= ' extends ' . $this->_extendedClass; + } + + $implemented = $this->getImplementedInterfaces(); + if (!empty($implemented)) { + $output .= ' implements ' . implode(', ', $implemented); + } + + $output .= self::LINE_FEED . '{' . self::LINE_FEED . self::LINE_FEED; + + $constants = $this->getConstants(); + if (!empty($constants)) { + foreach ($constants as $const) { + $output .= $const->generate() . self::LINE_FEED . self::LINE_FEED; + } + } + + $properties = $this->getProperties(); + if (!empty($properties)) { + foreach ($properties as $property) { + $output .= $property->generate() . self::LINE_FEED . self::LINE_FEED; + } + } + + $methods = $this->getMethods(); + if (!empty($methods)) { + foreach ($methods as $method) { + $output .= $method->generate() . self::LINE_FEED; + } + } + + $output .= self::LINE_FEED . '}' . self::LINE_FEED; + + return $output; + } + + /** + * _init() - is called at construction time + * + */ + protected function _init() + { + $this->_properties = new Zend_CodeGenerator_Php_Member_Container(Zend_CodeGenerator_Php_Member_Container::TYPE_PROPERTY); + $this->_constants = new Zend_CodeGenerator_Php_Member_Container(Zend_CodeGenerator_Php_Member_Container::TYPE_PROPERTY); + $this->_methods = new Zend_CodeGenerator_Php_Member_Container(Zend_CodeGenerator_Php_Member_Container::TYPE_METHOD); + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Docblock.php b/library/vendor/Zend/CodeGenerator/Php/Docblock.php new file mode 100644 index 000000000..a65253fba --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Docblock.php @@ -0,0 +1,224 @@ +setSourceContent($reflectionDocblock->getContents()); + $docblock->setSourceDirty(false); + + $docblock->setShortDescription($reflectionDocblock->getShortDescription()); + $docblock->setLongDescription($reflectionDocblock->getLongDescription()); + + foreach ($reflectionDocblock->getTags() as $tag) { + $docblock->setTag(Zend_CodeGenerator_Php_Docblock_Tag::fromReflection($tag)); + } + + return $docblock; + } + + /** + * setShortDescription() + * + * @param string $shortDescription + * @return Zend_CodeGenerator_Php_Docblock + */ + public function setShortDescription($shortDescription) + { + $this->_shortDescription = $shortDescription; + return $this; + } + + /** + * getShortDescription() + * + * @return string + */ + public function getShortDescription() + { + return $this->_shortDescription; + } + + /** + * setLongDescription() + * + * @param string $longDescription + * @return Zend_CodeGenerator_Php_Docblock + */ + public function setLongDescription($longDescription) + { + $this->_longDescription = $longDescription; + return $this; + } + + /** + * getLongDescription() + * + * @return string + */ + public function getLongDescription() + { + return $this->_longDescription; + } + + /** + * setTags() + * + * @param array $tags + * @return Zend_CodeGenerator_Php_Docblock + */ + public function setTags(Array $tags) + { + foreach ($tags as $tag) { + $this->setTag($tag); + } + + return $this; + } + + /** + * setTag() + * + * @param array|Zend_CodeGenerator_Php_Docblock_Tag $tag + * @return Zend_CodeGenerator_Php_Docblock + */ + public function setTag($tag) + { + if (is_array($tag)) { + $tag = new Zend_CodeGenerator_Php_Docblock_Tag($tag); + } elseif (!$tag instanceof Zend_CodeGenerator_Php_Docblock_Tag) { + throw new Zend_CodeGenerator_Php_Exception( + 'setTag() expects either an array of method options or an ' + . 'instance of Zend_CodeGenerator_Php_Docblock_Tag' + ); + } + + $this->_tags[] = $tag; + return $this; + } + + /** + * getTags + * + * @return array Array of Zend_CodeGenerator_Php_Docblock_Tag + */ + public function getTags() + { + return $this->_tags; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + if (!$this->isSourceDirty()) { + return $this->_docCommentize($this->getSourceContent()); + } + + $output = ''; + if (null !== ($sd = $this->getShortDescription())) { + $output .= $sd . self::LINE_FEED . self::LINE_FEED; + } + if (null !== ($ld = $this->getLongDescription())) { + $output .= $ld . self::LINE_FEED . self::LINE_FEED; + } + + foreach ($this->getTags() as $tag) { + $output .= $tag->generate() . self::LINE_FEED; + } + + return $this->_docCommentize(trim($output)); + } + + /** + * _docCommentize() + * + * @param string $content + * @return string + */ + protected function _docCommentize($content) + { + $indent = $this->getIndentation(); + $output = $indent . '/**' . self::LINE_FEED; + $content = wordwrap($content, 80, self::LINE_FEED); + $lines = explode(self::LINE_FEED, $content); + + foreach ($lines as $line) { + $output .= $indent . ' *'; + if ($line) { + $output .= " $line"; + } + $output .= self::LINE_FEED; + } + + $output = rtrim($output, ' *' . self::LINE_FEED) . self::LINE_FEED; + + $output .= $indent . ' */' . self::LINE_FEED; + return $output; + } +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag.php b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag.php new file mode 100644 index 000000000..a05d97d5a --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag.php @@ -0,0 +1,176 @@ +getName(); + + $codeGenDocblockTag = self::factory($tagName); + + // transport any properties via accessors and mutators from reflection to codegen object + $reflectionClass = new ReflectionClass($reflectionTag); + foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + if (substr($method->getName(), 0, 3) == 'get') { + $propertyName = substr($method->getName(), 3); + if (method_exists($codeGenDocblockTag, 'set' . $propertyName)) { + $codeGenDocblockTag->{'set' . $propertyName}($reflectionTag->{'get' . $propertyName}()); + } + } + } + + return $codeGenDocblockTag; + } + + /** + * setPluginLoader() + * + * @param Zend_Loader_PluginLoader $pluginLoader + */ + public static function setPluginLoader(Zend_Loader_PluginLoader $pluginLoader) + { + self::$_pluginLoader = $pluginLoader; + return; + } + + /** + * getPluginLoader() + * + * @return Zend_Loader_PluginLoader + */ + public static function getPluginLoader() + { + if (self::$_pluginLoader == null) { + self::setPluginLoader(new Zend_Loader_PluginLoader(array( + 'Zend_CodeGenerator_Php_Docblock_Tag' => dirname(__FILE__) . '/Tag/')) + ); + } + + return self::$_pluginLoader; + } + + public static function factory($tagName) + { + $pluginLoader = self::getPluginLoader(); + + try { + $tagClass = $pluginLoader->load($tagName); + } catch (Zend_Loader_Exception $exception) { + $tagClass = 'Zend_CodeGenerator_Php_Docblock_Tag'; + } + + $tag = new $tagClass(array('name' => $tagName)); + return $tag; + } + + /** + * setName() + * + * @param string $name + * @return Zend_CodeGenerator_Php_Docblock_Tag + */ + public function setName($name) + { + $this->_name = ltrim($name, '@'); + return $this; + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * setDescription() + * + * @param string $description + * @return Zend_CodeGenerator_Php_Docblock_Tag + */ + public function setDescription($description) + { + $this->_description = $description; + return $this; + } + + /** + * getDescription() + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + $tag = '@' . $this->_name; + if ($this->_description) { + $tag .= ' ' . $this->_description; + } + return $tag; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/License.php b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/License.php new file mode 100644 index 000000000..0cb4ad062 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/License.php @@ -0,0 +1,97 @@ +setName('license'); + $returnTag->setUrl($reflectionTagLicense->getUrl()); + $returnTag->setDescription($reflectionTagLicense->getDescription()); + + return $returnTag; + } + + /** + * setUrl() + * + * @param string $url + * @return Zend_CodeGenerator_Php_Docblock_Tag_License + */ + public function setUrl($url) + { + $this->_url = $url; + return $this; + } + + /** + * getUrl() + * + * @return string + */ + public function getUrl() + { + return $this->_url; + } + + + /** + * generate() + * + * @return string + */ + public function generate() + { + $output = '@license ' . $this->_url . ' ' . $this->_description . self::LINE_FEED; + return $output; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/Param.php b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/Param.php new file mode 100644 index 000000000..d479f550c --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/Param.php @@ -0,0 +1,127 @@ +setName('param'); + $paramTag->setDatatype($reflectionTagParam->getType()); // @todo rename + $paramTag->setParamName($reflectionTagParam->getVariableName()); + $paramTag->setDescription($reflectionTagParam->getDescription()); + + return $paramTag; + } + + /** + * setDatatype() + * + * @param string $datatype + * @return Zend_CodeGenerator_Php_Docblock_Tag_Param + */ + public function setDatatype($datatype) + { + $this->_datatype = $datatype; + return $this; + } + + /** + * getDatatype + * + * @return string + */ + public function getDatatype() + { + return $this->_datatype; + } + + /** + * setParamName() + * + * @param string $paramName + * @return Zend_CodeGenerator_Php_Docblock_Tag_Param + */ + public function setParamName($paramName) + { + $this->_paramName = $paramName; + return $this; + } + + /** + * getParamName() + * + * @return string + */ + public function getParamName() + { + return $this->_paramName; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + $output = '@param ' + . (($this->_datatype != null) ? $this->_datatype : 'unknown') + . (($this->_paramName != null) ? ' $' . $this->_paramName : '') + . (($this->_description != null) ? ' ' . $this->_description : ''); + return $output; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/Return.php b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/Return.php new file mode 100644 index 000000000..04eba0bda --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Docblock/Tag/Return.php @@ -0,0 +1,97 @@ +setName('return'); + $returnTag->setDatatype($reflectionTagReturn->getType()); // @todo rename + $returnTag->setDescription($reflectionTagReturn->getDescription()); + + return $returnTag; + } + + /** + * setDatatype() + * + * @param string $datatype + * @return Zend_CodeGenerator_Php_Docblock_Tag_Return + */ + public function setDatatype($datatype) + { + $this->_datatype = $datatype; + return $this; + } + + /** + * getDatatype() + * + * @return string + */ + public function getDatatype() + { + return $this->_datatype; + } + + + /** + * generate() + * + * @return string + */ + public function generate() + { + $output = '@return ' . $this->_datatype . ' ' . $this->_description; + return $output; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Exception.php b/library/vendor/Zend/CodeGenerator/Php/Exception.php new file mode 100644 index 000000000..8843be7e8 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Exception.php @@ -0,0 +1,36 @@ +getFilename(); + } + + if ($fileName == '') { + throw new Zend_CodeGenerator_Php_Exception('FileName does not exist.'); + } + + // cannot use realpath since the file might not exist, but we do need to have the index + // in the same DIRECTORY_SEPARATOR that realpath would use: + $fileName = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $fileName); + + self::$_fileCodeGenerators[$fileName] = $fileCodeGenerator; + + } + + /** + * fromReflectedFileName() - use this if you intend on generating code generation objects based on the same file. + * This will keep previous changes to the file in tact during the same PHP process + * + * @param string $filePath + * @param bool $usePreviousCodeGeneratorIfItExists + * @param bool $includeIfNotAlreadyIncluded + * @return Zend_CodeGenerator_Php_File + */ + public static function fromReflectedFileName($filePath, $usePreviousCodeGeneratorIfItExists = true, $includeIfNotAlreadyIncluded = true) + { + $realpath = realpath($filePath); + + if ($realpath === false) { + if ( ($realpath = Zend_Reflection_File::findRealpathInIncludePath($filePath)) === false) { + throw new Zend_CodeGenerator_Php_Exception('No file for ' . $realpath . ' was found.'); + } + } + + if ($usePreviousCodeGeneratorIfItExists && isset(self::$_fileCodeGenerators[$realpath])) { + return self::$_fileCodeGenerators[$realpath]; + } + + if ($includeIfNotAlreadyIncluded && !in_array($realpath, get_included_files())) { + include $realpath; + } + + $codeGenerator = self::fromReflection(($fileReflector = new Zend_Reflection_File($realpath))); + + if (!isset(self::$_fileCodeGenerators[$fileReflector->getFileName()])) { + self::$_fileCodeGenerators[$fileReflector->getFileName()] = $codeGenerator; + } + + return $codeGenerator; + } + + /** + * fromReflection() + * + * @param Zend_Reflection_File $reflectionFile + * @return Zend_CodeGenerator_Php_File + */ + public static function fromReflection(Zend_Reflection_File $reflectionFile) + { + $file = new self(); + + $file->setSourceContent($reflectionFile->getContents()); + $file->setSourceDirty(false); + + $body = $reflectionFile->getContents(); + + // @todo this whole area needs to be reworked with respect to how body lines are processed + foreach ($reflectionFile->getClasses() as $class) { + $file->setClass(Zend_CodeGenerator_Php_Class::fromReflection($class)); + $classStartLine = $class->getStartLine(true); + $classEndLine = $class->getEndLine(); + + $bodyLines = explode("\n", $body); + $bodyReturn = array(); + for ($lineNum = 1; $lineNum <= count($bodyLines); $lineNum++) { + if ($lineNum == $classStartLine) { + $bodyReturn[] = str_replace('?', $class->getName(), self::$_markerClass); //'/* Zend_CodeGenerator_Php_File-ClassMarker: {' . $class->getName() . '} */'; + $lineNum = $classEndLine; + } else { + $bodyReturn[] = $bodyLines[$lineNum - 1]; // adjust for index -> line conversion + } + } + $body = implode("\n", $bodyReturn); + unset($bodyLines, $bodyReturn, $classStartLine, $classEndLine); + } + + if (($reflectionFile->getDocComment() != '')) { + $docblock = $reflectionFile->getDocblock(); + $file->setDocblock(Zend_CodeGenerator_Php_Docblock::fromReflection($docblock)); + + $bodyLines = explode("\n", $body); + $bodyReturn = array(); + for ($lineNum = 1; $lineNum <= count($bodyLines); $lineNum++) { + if ($lineNum == $docblock->getStartLine()) { + $bodyReturn[] = str_replace('?', $class->getName(), self::$_markerDocblock); //'/* Zend_CodeGenerator_Php_File-ClassMarker: {' . $class->getName() . '} */'; + $lineNum = $docblock->getEndLine(); + } else { + $bodyReturn[] = $bodyLines[$lineNum - 1]; // adjust for index -> line conversion + } + } + $body = implode("\n", $bodyReturn); + unset($bodyLines, $bodyReturn, $classStartLine, $classEndLine); + } + + $file->setBody($body); + + return $file; + } + + /** + * setDocblock() Set the docblock + * + * @param Zend_CodeGenerator_Php_Docblock|array|string $docblock + * @return Zend_CodeGenerator_Php_File + */ + public function setDocblock($docblock) + { + if (is_string($docblock)) { + $docblock = array('shortDescription' => $docblock); + } + + if (is_array($docblock)) { + $docblock = new Zend_CodeGenerator_Php_Docblock($docblock); + } elseif (!$docblock instanceof Zend_CodeGenerator_Php_Docblock) { + throw new Zend_CodeGenerator_Php_Exception('setDocblock() is expecting either a string, array or an instance of Zend_CodeGenerator_Php_Docblock'); + } + + $this->_docblock = $docblock; + return $this; + } + + /** + * Get docblock + * + * @return Zend_CodeGenerator_Php_Docblock + */ + public function getDocblock() + { + return $this->_docblock; + } + + /** + * setRequiredFiles + * + * @param array $requiredFiles + * @return Zend_CodeGenerator_Php_File + */ + public function setRequiredFiles($requiredFiles) + { + $this->_requiredFiles = $requiredFiles; + return $this; + } + + /** + * getRequiredFiles() + * + * @return array + */ + public function getRequiredFiles() + { + return $this->_requiredFiles; + } + + /** + * setClasses() + * + * @param array $classes + * @return Zend_CodeGenerator_Php_File + */ + public function setClasses(Array $classes) + { + foreach ($classes as $class) { + $this->setClass($class); + } + return $this; + } + + /** + * getClass() + * + * @param string $name + * @return Zend_CodeGenerator_Php_Class + */ + public function getClass($name = null) + { + if ($name == null) { + reset($this->_classes); + return current($this->_classes); + } + + return $this->_classes[$name]; + } + + /** + * setClass() + * + * @param Zend_CodeGenerator_Php_Class|array $class + * @return Zend_CodeGenerator_Php_File + */ + public function setClass($class) + { + if (is_array($class)) { + $class = new Zend_CodeGenerator_Php_Class($class); + $className = $class->getName(); + } elseif ($class instanceof Zend_CodeGenerator_Php_Class) { + $className = $class->getName(); + } else { + throw new Zend_CodeGenerator_Php_Exception('Expecting either an array or an instance of Zend_CodeGenerator_Php_Class'); + } + + // @todo check for dup here + + $this->_classes[$className] = $class; + return $this; + } + + /** + * setFilename() + * + * @param string $filename + * @return Zend_CodeGenerator_Php_File + */ + public function setFilename($filename) + { + $this->_filename = $filename; + return $this; + } + + /** + * getFilename() + * + * @return string + */ + public function getFilename() + { + return $this->_filename; + } + + /** + * getClasses() + * + * @return array Array of Zend_CodeGenerator_Php_Class + */ + public function getClasses() + { + return $this->_classes; + } + + /** + * setBody() + * + * @param string $body + * @return Zend_CodeGenerator_Php_File + */ + public function setBody($body) + { + $this->_body = $body; + return $this; + } + + /** + * getBody() + * + * @return string + */ + public function getBody() + { + return $this->_body; + } + + /** + * isSourceDirty() + * + * @return bool + */ + public function isSourceDirty() + { + if (($docblock = $this->getDocblock()) && $docblock->isSourceDirty()) { + return true; + } + + foreach ($this->_classes as $class) { + if ($class->isSourceDirty()) { + return true; + } + } + + return parent::isSourceDirty(); + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + if ($this->isSourceDirty() === false) { + return $this->_sourceContent; + } + + $output = ''; + + // start with the body (if there), or open tag + if (preg_match('#(?:\s*)<\?php#', $this->getBody()) == false) { + $output = 'getBody(); + if (preg_match('#/\* Zend_CodeGenerator_Php_File-(.*?)Marker#', $body)) { + $output .= $body; + $body = ''; + } + + // Add file docblock, if any + if (null !== ($docblock = $this->getDocblock())) { + $docblock->setIndentation(''); + $regex = preg_quote(self::$_markerDocblock, '#'); + if (preg_match('#'.$regex.'#', $output)) { + $output = preg_replace('#'.$regex.'#', $docblock->generate(), $output, 1); + } else { + $output .= $docblock->generate() . self::LINE_FEED; + } + } + + // newline + $output .= self::LINE_FEED; + + // process required files + // @todo marker replacement for required files + $requiredFiles = $this->getRequiredFiles(); + if (!empty($requiredFiles)) { + foreach ($requiredFiles as $requiredFile) { + } + + $output .= self::LINE_FEED; + } + + // process classes + $classes = $this->getClasses(); + if (!empty($classes)) { + foreach ($classes as $class) { + if($this->getDocblock() == $class->getDocblock()) { + $class->setDocblock(null); + } + $regex = str_replace('?', $class->getName(), self::$_markerClass); + $regex = preg_quote($regex, '#'); + if (preg_match('#'.$regex.'#', $output)) { + $output = preg_replace('#'.$regex.'#', $class->generate(), $output, 1); + } else { + $output .= $class->generate() . self::LINE_FEED; + } + } + + } + + if (!empty($body)) { + + // add an extra space betwee clsses and + if (!empty($classes)) { + $output .= self::LINE_FEED; + } + + $output .= $body; + } + + return $output; + } + + public function write() + { + if ($this->_filename == '' || !is_writable(dirname($this->_filename))) { + throw new Zend_CodeGenerator_Php_Exception('This code generator object is not writable.'); + } + file_put_contents($this->_filename, $this->generate()); + return $this; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Member/Abstract.php b/library/vendor/Zend/CodeGenerator/Php/Member/Abstract.php new file mode 100644 index 000000000..4006e7151 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Member/Abstract.php @@ -0,0 +1,219 @@ + $docblock); + } + + if (is_array($docblock)) { + $docblock = new Zend_CodeGenerator_Php_Docblock($docblock); + } elseif (!$docblock instanceof Zend_CodeGenerator_Php_Docblock) { + throw new Zend_CodeGenerator_Php_Exception('setDocblock() is expecting either a string, array or an instance of Zend_CodeGenerator_Php_Docblock'); + } + + $this->_docblock = $docblock; + return $this; + } + + /** + * getDocblock() + * + * @return Zend_CodeGenerator_Php_Docblock + */ + public function getDocblock() + { + return $this->_docblock; + } + + /** + * setAbstract() + * + * @param bool $isAbstract + * @return Zend_CodeGenerator_Php_Member_Abstract + */ + public function setAbstract($isAbstract) + { + $this->_isAbstract = ($isAbstract) ? true : false; + return $this; + } + + /** + * isAbstract() + * + * @return bool + */ + public function isAbstract() + { + return $this->_isAbstract; + } + + /** + * setFinal() + * + * @param bool $isFinal + * @return Zend_CodeGenerator_Php_Member_Abstract + */ + public function setFinal($isFinal) + { + $this->_isFinal = ($isFinal) ? true : false; + return $this; + } + + /** + * isFinal() + * + * @return bool + */ + public function isFinal() + { + return $this->_isFinal; + } + + /** + * setStatic() + * + * @param bool $isStatic + * @return Zend_CodeGenerator_Php_Member_Abstract + */ + public function setStatic($isStatic) + { + $this->_isStatic = ($isStatic) ? true : false; + return $this; + } + + /** + * isStatic() + * + * @return bool + */ + public function isStatic() + { + return $this->_isStatic; + } + + /** + * setVisitibility() + * + * @param const $visibility + * @return Zend_CodeGenerator_Php_Member_Abstract + */ + public function setVisibility($visibility) + { + $this->_visibility = $visibility; + return $this; + } + + /** + * getVisibility() + * + * @return const + */ + public function getVisibility() + { + return $this->_visibility; + } + + /** + * setName() + * + * @param string $name + * @return Zend_CodeGenerator_Php_Member_Abstract + */ + public function setName($name) + { + $this->_name = $name; + return $this; + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + return $this->_name; + } +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Member/Container.php b/library/vendor/Zend/CodeGenerator/Php/Member/Container.php new file mode 100644 index 000000000..7658ae167 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Member/Container.php @@ -0,0 +1,55 @@ +_type = $type; + parent::__construct(array(), self::ARRAY_AS_PROPS); + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Method.php b/library/vendor/Zend/CodeGenerator/Php/Method.php new file mode 100644 index 000000000..b8a0aa7c7 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Method.php @@ -0,0 +1,232 @@ +setSourceContent($reflectionMethod->getContents(false)); + $method->setSourceDirty(false); + + if ($reflectionMethod->getDocComment() != '') { + $method->setDocblock(Zend_CodeGenerator_Php_Docblock::fromReflection($reflectionMethod->getDocblock())); + } + + $method->setFinal($reflectionMethod->isFinal()); + + if ($reflectionMethod->isPrivate()) { + $method->setVisibility(self::VISIBILITY_PRIVATE); + } elseif ($reflectionMethod->isProtected()) { + $method->setVisibility(self::VISIBILITY_PROTECTED); + } else { + $method->setVisibility(self::VISIBILITY_PUBLIC); + } + + $method->setStatic($reflectionMethod->isStatic()); + + $method->setName($reflectionMethod->getName()); + + foreach ($reflectionMethod->getParameters() as $reflectionParameter) { + $method->setParameter(Zend_CodeGenerator_Php_Parameter::fromReflection($reflectionParameter)); + } + + $method->setBody($reflectionMethod->getBody()); + + return $method; + } + + /** + * setFinal() + * + * @param bool $isFinal + */ + public function setFinal($isFinal) + { + $this->_isFinal = ($isFinal) ? true : false; + } + + /** + * setParameters() + * + * @param array $parameters + * @return Zend_CodeGenerator_Php_Method + */ + public function setParameters(Array $parameters) + { + foreach ($parameters as $parameter) { + $this->setParameter($parameter); + } + return $this; + } + + /** + * setParameter() + * + * @param Zend_CodeGenerator_Php_Parameter|array $parameter + * @return Zend_CodeGenerator_Php_Method + */ + public function setParameter($parameter) + { + if (is_array($parameter)) { + $parameter = new Zend_CodeGenerator_Php_Parameter($parameter); + $parameterName = $parameter->getName(); + } elseif ($parameter instanceof Zend_CodeGenerator_Php_Parameter) { + $parameterName = $parameter->getName(); + } else { + throw new Zend_CodeGenerator_Php_Exception('setParameter() expects either an array of method options or an instance of Zend_CodeGenerator_Php_Parameter'); + } + + $this->_parameters[$parameterName] = $parameter; + return $this; + } + + /** + * getParameters() + * + * @return array Array of Zend_CodeGenerator_Php_Parameter + */ + public function getParameters() + { + return $this->_parameters; + } + + /** + * setBody() + * + * @param string $body + * @return Zend_CodeGenerator_Php_Method + */ + public function setBody($body) + { + $this->_body = $body; + return $this; + } + + /** + * getBody() + * + * @return string + */ + public function getBody() + { + return $this->_body; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + $output = ''; + + $indent = $this->getIndentation(); + + if (($docblock = $this->getDocblock()) !== null) { + $docblock->setIndentation($indent); + $output .= $docblock->generate(); + } + + $output .= $indent; + + if ($this->isAbstract()) { + $output .= 'abstract '; + } else { + $output .= (($this->isFinal()) ? 'final ' : ''); + } + + $output .= $this->getVisibility() + . (($this->isStatic()) ? ' static' : '') + . ' function ' . $this->getName() . '('; + + $parameters = $this->getParameters(); + if (!empty($parameters)) { + foreach ($parameters as $parameter) { + $parameterOuput[] = $parameter->generate(); + } + + $output .= implode(', ', $parameterOuput); + } + + $output .= ')' . self::LINE_FEED . $indent . '{' . self::LINE_FEED; + + if ($this->_body && $this->isSourceDirty()) { + $output .= ' ' + . str_replace(self::LINE_FEED, self::LINE_FEED . $indent . $indent, trim($this->_body)) + . self::LINE_FEED; + } elseif ($this->_body) { + $output .= $this->_body . self::LINE_FEED; + } + + $output .= $indent . '}' . self::LINE_FEED; + + return $output; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Parameter.php b/library/vendor/Zend/CodeGenerator/Php/Parameter.php new file mode 100644 index 000000000..20d3ecb1f --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Parameter.php @@ -0,0 +1,248 @@ +setName($reflectionParameter->getName()); + + if($reflectionParameter->isArray()) { + $param->setType('array'); + } else { + $typeClass = $reflectionParameter->getClass(); + if($typeClass !== null) { + $param->setType($typeClass->getName()); + } + } + + $param->setPosition($reflectionParameter->getPosition()); + + if($reflectionParameter->isOptional()) { + $param->setDefaultValue($reflectionParameter->getDefaultValue()); + } + $param->setPassedByReference($reflectionParameter->isPassedByReference()); + + return $param; + } + + /** + * setType() + * + * @param string $type + * @return Zend_CodeGenerator_Php_Parameter + */ + public function setType($type) + { + $this->_type = $type; + return $this; + } + + /** + * getType() + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * setName() + * + * @param string $name + * @return Zend_CodeGenerator_Php_Parameter + */ + public function setName($name) + { + $this->_name = $name; + return $this; + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Set the default value of the parameter. + * + * Certain variables are difficult to expres + * + * @param null|bool|string|int|float|Zend_CodeGenerator_Php_Parameter_DefaultValue $defaultValue + * @return Zend_CodeGenerator_Php_Parameter + */ + public function setDefaultValue($defaultValue) + { + if($defaultValue === null) { + $this->_defaultValue = new Zend_CodeGenerator_Php_Parameter_DefaultValue("null"); + } else if(is_array($defaultValue)) { + $defaultValue = str_replace(array("\r", "\n"), "", var_export($defaultValue, true)); + $this->_defaultValue = new Zend_CodeGenerator_Php_Parameter_DefaultValue($defaultValue); + } else if(is_bool($defaultValue)) { + if($defaultValue == true) { + $this->_defaultValue = new Zend_CodeGenerator_Php_Parameter_DefaultValue("true"); + } else { + $this->_defaultValue = new Zend_CodeGenerator_Php_Parameter_DefaultValue("false"); + } + } else { + $this->_defaultValue = $defaultValue; + } + return $this; + } + + /** + * getDefaultValue() + * + * @return string + */ + public function getDefaultValue() + { + return $this->_defaultValue; + } + + /** + * setPosition() + * + * @param int $position + * @return Zend_CodeGenerator_Php_Parameter + */ + public function setPosition($position) + { + $this->_position = $position; + return $this; + } + + /** + * getPosition() + * + * @return int + */ + public function getPosition() + { + return $this->_position; + } + + /** + * @return bool + */ + public function getPassedByReference() + { + return $this->_passedByReference; + } + + /** + * @param bool $passedByReference + * @return Zend_CodeGenerator_Php_Parameter + */ + public function setPassedByReference($passedByReference) + { + $this->_passedByReference = $passedByReference; + return $this; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + $output = ''; + + if ($this->_type) { + $output .= $this->_type . ' '; + } + + if($this->_passedByReference === true) { + $output .= '&'; + } + + $output .= '$' . $this->_name; + + if ($this->_defaultValue !== null) { + $output .= ' = '; + if (is_string($this->_defaultValue)) { + $output .= '\'' . $this->_defaultValue . '\''; + } else if($this->_defaultValue instanceof Zend_CodeGenerator_Php_Parameter_DefaultValue) { + $output .= (string)$this->_defaultValue; + } else { + $output .= $this->_defaultValue; + } + } + + return $output; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Parameter/DefaultValue.php b/library/vendor/Zend/CodeGenerator/Php/Parameter/DefaultValue.php new file mode 100644 index 000000000..03085c6fa --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Parameter/DefaultValue.php @@ -0,0 +1,59 @@ +_defaultValue = $defaultValue; + } + + public function __toString() + { + return $this->_defaultValue; + } +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Property.php b/library/vendor/Zend/CodeGenerator/Php/Property.php new file mode 100644 index 000000000..98aa53903 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Property.php @@ -0,0 +1,176 @@ +setName($reflectionProperty->getName()); + + $allDefaultProperties = $reflectionProperty->getDeclaringClass()->getDefaultProperties(); + + $property->setDefaultValue($allDefaultProperties[$reflectionProperty->getName()]); + + if ($reflectionProperty->getDocComment() != '') { + $property->setDocblock(Zend_CodeGenerator_Php_Docblock::fromReflection($reflectionProperty->getDocComment())); + } + + if ($reflectionProperty->isStatic()) { + $property->setStatic(true); + } + + if ($reflectionProperty->isPrivate()) { + $property->setVisibility(self::VISIBILITY_PRIVATE); + } elseif ($reflectionProperty->isProtected()) { + $property->setVisibility(self::VISIBILITY_PROTECTED); + } else { + $property->setVisibility(self::VISIBILITY_PUBLIC); + } + + $property->setSourceDirty(false); + + return $property; + } + + /** + * setConst() + * + * @param bool $const + * @return Zend_CodeGenerator_Php_Property + */ + public function setConst($const) + { + $this->_isConst = $const; + return $this; + } + + /** + * isConst() + * + * @return bool + */ + public function isConst() + { + return ($this->_isConst) ? true : false; + } + + /** + * setDefaultValue() + * + * @param Zend_CodeGenerator_Php_Property_DefaultValue|string|array $defaultValue + * @return Zend_CodeGenerator_Php_Property + */ + public function setDefaultValue($defaultValue) + { + // if it looks like + if (is_array($defaultValue) + && array_key_exists('value', $defaultValue) + && array_key_exists('type', $defaultValue)) { + $defaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue($defaultValue); + } + + if (!($defaultValue instanceof Zend_CodeGenerator_Php_Property_DefaultValue)) { + $defaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue(array('value' => $defaultValue)); + } + + $this->_defaultValue = $defaultValue; + return $this; + } + + /** + * getDefaultValue() + * + * @return Zend_CodeGenerator_Php_Property_DefaultValue + */ + public function getDefaultValue() + { + return $this->_defaultValue; + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + $name = $this->getName(); + $defaultValue = $this->getDefaultValue(); + + $output = ''; + + if (($docblock = $this->getDocblock()) !== null) { + $docblock->setIndentation(' '); + $output .= $docblock->generate(); + } + + if ($this->isConst()) { + if ($defaultValue != null && !$defaultValue->isValidConstantType()) { + throw new Zend_CodeGenerator_Php_Exception('The property ' . $this->_name . ' is said to be ' + . 'constant but does not have a valid constant value.'); + } + $output .= $this->_indentation . 'const ' . $name . ' = ' + . (($defaultValue !== null) ? $defaultValue->generate() : 'null;'); + } else { + $output .= $this->_indentation + . $this->getVisibility() + . (($this->isStatic()) ? ' static' : '') + . ' $' . $name . ' = ' + . (($defaultValue !== null) ? $defaultValue->generate() : 'null;'); + } + return $output; + } + +} diff --git a/library/vendor/Zend/CodeGenerator/Php/Property/DefaultValue.php b/library/vendor/Zend/CodeGenerator/Php/Property/DefaultValue.php new file mode 100644 index 000000000..84881e187 --- /dev/null +++ b/library/vendor/Zend/CodeGenerator/Php/Property/DefaultValue.php @@ -0,0 +1,323 @@ +getConstants(); + unset($reflect); + } + } + + /** + * isValidConstantType() + * + * @return bool + */ + public function isValidConstantType() + { + if ($this->_type == self::TYPE_AUTO) { + $type = $this->_getAutoDeterminedType($this->_value); + } else { + $type = $this->_type; + } + + // valid types for constants + $scalarTypes = array( + self::TYPE_BOOLEAN, + self::TYPE_BOOL, + self::TYPE_NUMBER, + self::TYPE_INTEGER, + self::TYPE_INT, + self::TYPE_FLOAT, + self::TYPE_DOUBLE, + self::TYPE_STRING, + self::TYPE_CONSTANT, + self::TYPE_NULL + ); + + return in_array($type, $scalarTypes); + } + + /** + * setValue() + * + * @param mixed $value + * @return Zend_CodeGenerator_Php_Property_DefaultValue + */ + public function setValue($value) + { + $this->_value = $value; + return $this; + } + + /** + * getValue() + * + * @return mixed + */ + public function getValue() + { + return $this->_value; + } + + /** + * setType() + * + * @param string $type + * @return Zend_CodeGenerator_Php_Property_DefaultValue + */ + public function setType($type) + { + $this->_type = $type; + return $this; + } + + /** + * getType() + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * setArrayDepth() + * + * @param int $arrayDepth + * @return Zend_CodeGenerator_Php_Property_DefaultValue + */ + public function setArrayDepth($arrayDepth) + { + $this->_arrayDepth = $arrayDepth; + return $this; + } + + /** + * getArrayDepth() + * + * @return int + */ + public function getArrayDepth() + { + return $this->_arrayDepth; + } + + /** + * _getValidatedType() + * + * @param string $type + * @return string + */ + protected function _getValidatedType($type) + { + if (($constName = array_search($type, self::$_constants)) !== false) { + return $type; + } + + return self::TYPE_AUTO; + } + + /** + * _getAutoDeterminedType() + * + * @param mixed $value + * @return string + */ + public function _getAutoDeterminedType($value) + { + switch (gettype($value)) { + case 'boolean': + return self::TYPE_BOOLEAN; + case 'integer': + return self::TYPE_INT; + case 'string': + return self::TYPE_STRING; + case 'double': + case 'float': + case 'integer': + return self::TYPE_NUMBER; + case 'array': + return self::TYPE_ARRAY; + case 'NULL': + return self::TYPE_NULL; + case 'object': + case 'resource': + case 'unknown type': + default: + return self::TYPE_OTHER; + } + } + + /** + * generate() + * + * @return string + */ + public function generate() + { + $type = $this->_type; + + if ($type != self::TYPE_AUTO) { + $type = $this->_getValidatedType($type); + } + + $value = $this->_value; + + if ($type == self::TYPE_AUTO) { + $type = $this->_getAutoDeterminedType($value); + + if ($type == self::TYPE_ARRAY) { + $rii = new RecursiveIteratorIterator( + $it = new RecursiveArrayIterator($value), + RecursiveIteratorIterator::SELF_FIRST + ); + foreach ($rii as $curKey => $curValue) { + if (!$curValue instanceof Zend_CodeGenerator_Php_Property_DefaultValue) { + $curValue = new self(array('value' => $curValue)); + $rii->getSubIterator()->offsetSet($curKey, $curValue); + } + $curValue->setArrayDepth($rii->getDepth()); + } + $value = $rii->getSubIterator()->getArrayCopy(); + } + + } + + $output = ''; + + switch ($type) { + case self::TYPE_BOOLEAN: + case self::TYPE_BOOL: + $output .= ( $value ? 'true' : 'false' ); + break; + case self::TYPE_STRING: + $output .= "'" . addcslashes($value, "'") . "'"; + break; + case self::TYPE_NULL: + $output .= 'null'; + break; + case self::TYPE_NUMBER: + case self::TYPE_INTEGER: + case self::TYPE_INT: + case self::TYPE_FLOAT: + case self::TYPE_DOUBLE: + case self::TYPE_CONSTANT: + $output .= $value; + break; + case self::TYPE_ARRAY: + $output .= 'array('; + $curArrayMultiblock = false; + if (count($value) > 1) { + $curArrayMultiblock = true; + $output .= PHP_EOL . str_repeat($this->_indentation, $this->_arrayDepth+1); + } + $outputParts = array(); + $noKeyIndex = 0; + foreach ($value as $n => $v) { + $v->setArrayDepth($this->_arrayDepth + 1); + $partV = $v->generate(); + $partV = substr($partV, 0, strlen($partV)-1); + if ($n === $noKeyIndex) { + $outputParts[] = $partV; + $noKeyIndex++; + } else { + $outputParts[] = (is_int($n) ? $n : "'" . addcslashes($n, "'") . "'") . ' => ' . $partV; + } + + } + $output .= implode(',' . PHP_EOL . str_repeat($this->_indentation, $this->_arrayDepth+1), $outputParts); + if ($curArrayMultiblock == true) { + $output .= PHP_EOL . str_repeat($this->_indentation, $this->_arrayDepth+1); + } + $output .= ')'; + break; + case self::TYPE_OTHER: + default: + throw new Zend_CodeGenerator_Php_Exception( + "Type '".get_class($value)."' is unknown or cannot be used as property default value." + ); + } + + $output .= ';'; + + return $output; + } +} diff --git a/library/vendor/Zend/Config.php b/library/vendor/Zend/Config.php new file mode 100644 index 000000000..199dcbe31 --- /dev/null +++ b/library/vendor/Zend/Config.php @@ -0,0 +1,481 @@ +_allowModifications = (boolean) $allowModifications; + $this->_loadedSection = null; + $this->_index = 0; + $this->_data = array(); + foreach ($array as $key => $value) { + if (is_array($value)) { + $this->_data[$key] = new self($value, $this->_allowModifications); + } else { + $this->_data[$key] = $value; + } + } + $this->_count = count($this->_data); + } + + /** + * Retrieve a value and return $default if there is no element set. + * + * @param string $name + * @param mixed $default + * @return mixed + */ + public function get($name, $default = null) + { + $result = $default; + if (array_key_exists($name, $this->_data)) { + $result = $this->_data[$name]; + } + return $result; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->get($name); + } + + /** + * Only allow setting of a property if $allowModifications + * was set to true on construction. Otherwise, throw an exception. + * + * @param string $name + * @param mixed $value + * @throws Zend_Config_Exception + * @return void + */ + public function __set($name, $value) + { + if ($this->_allowModifications) { + if (is_array($value)) { + $this->_data[$name] = new self($value, true); + } else { + $this->_data[$name] = $value; + } + $this->_count = count($this->_data); + } else { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Zend_Config is read only'); + } + } + + /** + * Deep clone of this instance to ensure that nested Zend_Configs + * are also cloned. + * + * @return void + */ + public function __clone() + { + $array = array(); + foreach ($this->_data as $key => $value) { + if ($value instanceof Zend_Config) { + $array[$key] = clone $value; + } else { + $array[$key] = $value; + } + } + $this->_data = $array; + } + + /** + * Return an associative array of the stored data. + * + * @return array + */ + public function toArray() + { + $array = array(); + $data = $this->_data; + foreach ($data as $key => $value) { + if ($value instanceof Zend_Config) { + $array[$key] = $value->toArray(); + } else { + $array[$key] = $value; + } + } + return $array; + } + + /** + * Support isset() overloading on PHP 5.1 + * + * @param string $name + * @return boolean + */ + public function __isset($name) + { + return isset($this->_data[$name]); + } + + /** + * Support unset() overloading on PHP 5.1 + * + * @param string $name + * @throws Zend_Config_Exception + * @return void + */ + public function __unset($name) + { + if ($this->_allowModifications) { + unset($this->_data[$name]); + $this->_count = count($this->_data); + $this->_skipNextIteration = true; + } else { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Zend_Config is read only'); + } + + } + + /** + * Defined by Countable interface + * + * @return int + */ + public function count() + { + return $this->_count; + } + + /** + * Defined by Iterator interface + * + * @return mixed + */ + public function current() + { + $this->_skipNextIteration = false; + return current($this->_data); + } + + /** + * Defined by Iterator interface + * + * @return mixed + */ + public function key() + { + return key($this->_data); + } + + /** + * Defined by Iterator interface + * + */ + public function next() + { + if ($this->_skipNextIteration) { + $this->_skipNextIteration = false; + return; + } + next($this->_data); + $this->_index++; + } + + /** + * Defined by Iterator interface + * + */ + public function rewind() + { + $this->_skipNextIteration = false; + reset($this->_data); + $this->_index = 0; + } + + /** + * Defined by Iterator interface + * + * @return boolean + */ + public function valid() + { + return $this->_index < $this->_count; + } + + /** + * Returns the section name(s) loaded. + * + * @return mixed + */ + public function getSectionName() + { + if(is_array($this->_loadedSection) && count($this->_loadedSection) == 1) { + $this->_loadedSection = $this->_loadedSection[0]; + } + return $this->_loadedSection; + } + + /** + * Returns true if all sections were loaded + * + * @return boolean + */ + public function areAllSectionsLoaded() + { + return $this->_loadedSection === null; + } + + + /** + * Merge another Zend_Config with this one. The items + * in $merge will override the same named items in + * the current config. + * + * @param Zend_Config $merge + * @return Zend_Config + */ + public function merge(Zend_Config $merge) + { + foreach($merge as $key => $item) { + if(array_key_exists($key, $this->_data)) { + if($item instanceof Zend_Config && $this->$key instanceof Zend_Config) { + $this->$key = $this->$key->merge(new Zend_Config($item->toArray(), !$this->readOnly())); + } else { + $this->$key = $item; + } + } else { + if($item instanceof Zend_Config) { + $this->$key = new Zend_Config($item->toArray(), !$this->readOnly()); + } else { + $this->$key = $item; + } + } + } + + return $this; + } + + /** + * Prevent any more modifications being made to this instance. Useful + * after merge() has been used to merge multiple Zend_Config objects + * into one object which should then not be modified again. + * + */ + public function setReadOnly() + { + $this->_allowModifications = false; + foreach ($this->_data as $key => $value) { + if ($value instanceof Zend_Config) { + $value->setReadOnly(); + } + } + } + + /** + * Returns if this Zend_Config object is read only or not. + * + * @return boolean + */ + public function readOnly() + { + return !$this->_allowModifications; + } + + /** + * Get the current extends + * + * @return array + */ + public function getExtends() + { + return $this->_extends; + } + + /** + * Set an extend for Zend_Config_Writer + * + * @param string $extendingSection + * @param string $extendedSection + * @return void + */ + public function setExtend($extendingSection, $extendedSection = null) + { + if ($extendedSection === null && isset($this->_extends[$extendingSection])) { + unset($this->_extends[$extendingSection]); + } else if ($extendedSection !== null) { + $this->_extends[$extendingSection] = $extendedSection; + } + } + + /** + * Throws an exception if $extendingSection may not extend $extendedSection, + * and tracks the section extension if it is valid. + * + * @param string $extendingSection + * @param string $extendedSection + * @throws Zend_Config_Exception + * @return void + */ + protected function _assertValidExtend($extendingSection, $extendedSection) + { + // detect circular section inheritance + $extendedSectionCurrent = $extendedSection; + while (array_key_exists($extendedSectionCurrent, $this->_extends)) { + if ($this->_extends[$extendedSectionCurrent] == $extendingSection) { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Illegal circular inheritance detected'); + } + $extendedSectionCurrent = $this->_extends[$extendedSectionCurrent]; + } + // remember that this section extends another section + $this->_extends[$extendingSection] = $extendedSection; + } + + /** + * Handle any errors from simplexml_load_file or parse_ini_file + * + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + */ + public function _loadFileErrorHandler($errno, $errstr, $errfile, $errline) + { + if ($this->_loadFileErrorStr === null) { + $this->_loadFileErrorStr = $errstr; + } else { + $this->_loadFileErrorStr .= (PHP_EOL . $errstr); + } + } + + /** + * Merge two arrays recursively, overwriting keys of the same name + * in $firstArray with the value in $secondArray. + * + * @param mixed $firstArray First array + * @param mixed $secondArray Second array to merge into first array + * @return array + */ + protected function _arrayMergeRecursive($firstArray, $secondArray) + { + if (is_array($firstArray) && is_array($secondArray)) { + foreach ($secondArray as $key => $value) { + if (isset($firstArray[$key])) { + $firstArray[$key] = $this->_arrayMergeRecursive($firstArray[$key], $value); + } else { + if($key === 0) { + $firstArray= array(0=>$this->_arrayMergeRecursive($firstArray, $value)); + } else { + $firstArray[$key] = $value; + } + } + } + } else { + $firstArray = $secondArray; + } + + return $firstArray; + } +} diff --git a/library/vendor/Zend/Config/Exception.php b/library/vendor/Zend/Config/Exception.php new file mode 100644 index 000000000..28e6ff964 --- /dev/null +++ b/library/vendor/Zend/Config/Exception.php @@ -0,0 +1,32 @@ +hostname === "staging" + * $data->db->connection === "database" + * + * The $options parameter may be provided as either a boolean or an array. + * If provided as a boolean, this sets the $allowModifications option of + * Zend_Config. If provided as an array, there are three configuration + * directives that may be set. For example: + * + * $options = array( + * 'allowModifications' => false, + * 'nestSeparator' => ':', + * 'skipExtends' => false, + * ); + * + * @param string $filename + * @param mixed $section + * @param boolean|array $options + * @throws Zend_Config_Exception + * @return void + */ + public function __construct($filename, $section = null, $options = false) + { + if (empty($filename)) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception('Filename is not set'); + } + + $allowModifications = false; + if (is_bool($options)) { + $allowModifications = $options; + } elseif (is_array($options)) { + if (isset($options['allowModifications'])) { + $allowModifications = (bool) $options['allowModifications']; + } + if (isset($options['nestSeparator'])) { + $this->_nestSeparator = (string) $options['nestSeparator']; + } + if (isset($options['skipExtends'])) { + $this->_skipExtends = (bool) $options['skipExtends']; + } + } + + $iniArray = $this->_loadIniFile($filename); + + if (null === $section) { + // Load entire file + $dataArray = array(); + foreach ($iniArray as $sectionName => $sectionData) { + if(!is_array($sectionData)) { + $dataArray = $this->_arrayMergeRecursive($dataArray, $this->_processKey(array(), $sectionName, $sectionData)); + } else { + $dataArray[$sectionName] = $this->_processSection($iniArray, $sectionName); + } + } + parent::__construct($dataArray, $allowModifications); + } else { + // Load one or more sections + if (!is_array($section)) { + $section = array($section); + } + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($iniArray[$sectionName])) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $filename"); + } + $dataArray = $this->_arrayMergeRecursive($this->_processSection($iniArray, $sectionName), $dataArray); + + } + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Load the INI file from disk using parse_ini_file(). Use a private error + * handler to convert any loading errors into a Zend_Config_Exception + * + * @param string $filename + * @throws Zend_Config_Exception + * @return array + */ + protected function _parseIniFile($filename) + { + set_error_handler(array($this, '_loadFileErrorHandler')); + $iniArray = parse_ini_file($filename, true); // Warnings and errors are suppressed + restore_error_handler(); + + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception($this->_loadFileErrorStr); + } + + return $iniArray; + } + + /** + * Load the ini file and preprocess the section separator (':' in the + * section name (that is used for section extension) so that the resultant + * array has the correct section names and the extension information is + * stored in a sub-key called ';extends'. We use ';extends' as this can + * never be a valid key name in an INI file that has been loaded using + * parse_ini_file(). + * + * @param string $filename + * @throws Zend_Config_Exception + * @return array + */ + protected function _loadIniFile($filename) + { + $loaded = $this->_parseIniFile($filename); + $iniArray = array(); + foreach ($loaded as $key => $data) + { + $pieces = explode($this->_sectionSeparator, $key); + $thisSection = trim($pieces[0]); + switch (count($pieces)) { + case 1: + $iniArray[$thisSection] = $data; + break; + + case 2: + $extendedSection = trim($pieces[1]); + $iniArray[$thisSection] = array_merge(array(';extends'=>$extendedSection), $data); + break; + + default: + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Section '$thisSection' may not extend multiple sections in $filename"); + } + } + + return $iniArray; + } + + /** + * Process each element in the section and handle the ";extends" inheritance + * key. Passes control to _processKey() to handle the nest separator + * sub-property syntax that may be used within the key name. + * + * @param array $iniArray + * @param string $section + * @param array $config + * @throws Zend_Config_Exception + * @return array + */ + protected function _processSection($iniArray, $section, $config = array()) + { + $thisSection = $iniArray[$section]; + + foreach ($thisSection as $key => $value) { + if (strtolower($key) == ';extends') { + if (isset($iniArray[$value])) { + $this->_assertValidExtend($section, $value); + + if (!$this->_skipExtends) { + $config = $this->_processSection($iniArray, $value, $config); + } + } else { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Parent section '$section' cannot be found"); + } + } else { + $config = $this->_processKey($config, $key, $value); + } + } + return $config; + } + + /** + * Assign the key's value to the property list. Handles the + * nest separator for sub-properties. + * + * @param array $config + * @param string $key + * @param string $value + * @throws Zend_Config_Exception + * @return array + */ + protected function _processKey($config, $key, $value) + { + if (strpos($key, $this->_nestSeparator) !== false) { + $pieces = explode($this->_nestSeparator, $key, 2); + if (strlen($pieces[0]) && strlen($pieces[1])) { + if (!isset($config[$pieces[0]])) { + if ($pieces[0] === '0' && !empty($config)) { + // convert the current values in $config into an array + $config = array($pieces[0] => $config); + } else { + $config[$pieces[0]] = array(); + } + } elseif (!is_array($config[$pieces[0]])) { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Cannot create sub-key for '{$pieces[0]}' as key already exists"); + } + $config[$pieces[0]] = $this->_processKey($config[$pieces[0]], $pieces[1], $value); + } else { + /** + * @see Zend_Config_Exception + */ + throw new Zend_Config_Exception("Invalid key '$key'"); + } + } else { + $config[$key] = $value; + } + return $config; + } +} diff --git a/library/vendor/Zend/Config/Json.php b/library/vendor/Zend/Config/Json.php new file mode 100755 index 000000000..cd9533917 --- /dev/null +++ b/library/vendor/Zend/Config/Json.php @@ -0,0 +1,233 @@ + $value) { + switch (strtolower($key)) { + case 'allow_modifications': + case 'allowmodifications': + $allowModifications = (bool) $value; + break; + case 'skip_extends': + case 'skipextends': + $this->_skipExtends = (bool) $value; + break; + case 'ignore_constants': + case 'ignoreconstants': + $this->_ignoreConstants = (bool) $value; + break; + default: + break; + } + } + } + + set_error_handler(array($this, '_loadFileErrorHandler')); // Warnings and errors are suppressed + if ($json[0] != '{') { + $json = file_get_contents($json); + } + restore_error_handler(); + + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + throw new Zend_Config_Exception($this->_loadFileErrorStr); + } + + // Replace constants + if (!$this->_ignoreConstants) { + $json = $this->_replaceConstants($json); + } + + // Parse/decode + try { + $config = Zend_Json::decode($json); + } catch (Zend_Json_Exception $e) { + // decode failed + throw new Zend_Config_Exception("Error parsing JSON data"); + } + + if ($section === null) { + $dataArray = array(); + foreach ($config as $sectionName => $sectionData) { + $dataArray[$sectionName] = $this->_processExtends($config, $sectionName); + } + + parent::__construct($dataArray, $allowModifications); + } elseif (is_array($section)) { + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($config[$sectionName])) { + throw new Zend_Config_Exception(sprintf('Section "%s" cannot be found', $sectionName)); + } + + $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray); + } + + parent::__construct($dataArray, $allowModifications); + } else { + if (!isset($config[$section])) { + throw new Zend_Config_Exception(sprintf('Section "%s" cannot be found', $section)); + } + + $dataArray = $this->_processExtends($config, $section); + if (!is_array($dataArray)) { + // Section in the JSON data contains just one top level string + $dataArray = array($section => $dataArray); + } + + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Helper function to process each element in the section and handle + * the "_extends" inheritance attribute. + * + * @param array $data Data array to process + * @param string $section Section to process + * @param array $config Configuration which was parsed yet + * @throws Zend_Config_Exception When $section cannot be found + * @return array + */ + protected function _processExtends(array $data, $section, array $config = array()) + { + if (!isset($data[$section])) { + throw new Zend_Config_Exception(sprintf('Section "%s" cannot be found', $section)); + } + + $thisSection = $data[$section]; + + if (is_array($thisSection) && isset($thisSection[self::EXTENDS_NAME])) { + if (is_array($thisSection[self::EXTENDS_NAME])) { + throw new Zend_Config_Exception('Invalid extends clause: must be a string; array received'); + } + $this->_assertValidExtend($section, $thisSection[self::EXTENDS_NAME]); + + if (!$this->_skipExtends) { + $config = $this->_processExtends($data, $thisSection[self::EXTENDS_NAME], $config); + } + unset($thisSection[self::EXTENDS_NAME]); + } + + $config = $this->_arrayMergeRecursive($config, $thisSection); + + return $config; + } + + /** + * Replace any constants referenced in a string with their values + * + * @param string $value + * @return string + */ + protected function _replaceConstants($value) + { + foreach ($this->_getConstants() as $constant) { + if (strstr($value, $constant)) { + // handle backslashes that may represent windows path names for instance + $replacement = str_replace('\\', '\\\\', constant($constant)); + $value = str_replace($constant, $replacement, $value); + } + } + return $value; + } + + /** + * Get (reverse) sorted list of defined constant names + * + * @return array + */ + protected function _getConstants() + { + $constants = array_keys(get_defined_constants()); + rsort($constants, SORT_STRING); + return $constants; + } +} diff --git a/library/vendor/Zend/Config/Writer.php b/library/vendor/Zend/Config/Writer.php new file mode 100644 index 000000000..6bbf4c6d4 --- /dev/null +++ b/library/vendor/Zend/Config/Writer.php @@ -0,0 +1,101 @@ +setOptions($options); + } + } + + /** + * Set options via a Zend_Config instance + * + * @param Zend_Config $config + * @return Zend_Config_Writer + */ + public function setConfig(Zend_Config $config) + { + $this->_config = $config; + + return $this; + } + + /** + * Set options via an array + * + * @param array $options + * @return Zend_Config_Writer + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + if (in_array(strtolower($key), $this->_skipOptions)) { + continue; + } + + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + + return $this; + } + + /** + * Write a Zend_Config object to it's target + * + * @return void + */ + abstract public function write(); +} diff --git a/library/vendor/Zend/Config/Writer/Array.php b/library/vendor/Zend/Config/Writer/Array.php new file mode 100644 index 000000000..7e497f5ad --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Array.php @@ -0,0 +1,54 @@ +_config->toArray(); + $sectionName = $this->_config->getSectionName(); + + if (is_string($sectionName)) { + $data = array($sectionName => $data); + } + + $arrayString = "_filename = $filename; + + return $this; + } + + /** + * Set wether to exclusively lock the file or not + * + * @param boolean $exclusiveLock + * @return Zend_Config_Writer_Array + */ + public function setExclusiveLock($exclusiveLock) + { + $this->_exclusiveLock = $exclusiveLock; + + return $this; + } + + /** + * Write configuration to file. + * + * @param string $filename + * @param Zend_Config $config + * @param bool $exclusiveLock + * @return void + */ + public function write($filename = null, Zend_Config $config = null, $exclusiveLock = null) + { + if ($filename !== null) { + $this->setFilename($filename); + } + + if ($config !== null) { + $this->setConfig($config); + } + + if ($exclusiveLock !== null) { + $this->setExclusiveLock($exclusiveLock); + } + + if ($this->_filename === null) { + throw new Zend_Config_Exception('No filename was set'); + } + + if ($this->_config === null) { + throw new Zend_Config_Exception('No config was set'); + } + + $configString = $this->render(); + + $flags = 0; + + if ($this->_exclusiveLock) { + $flags |= LOCK_EX; + } + + $result = @file_put_contents($this->_filename, $configString, $flags); + + if ($result === false) { + throw new Zend_Config_Exception('Could not write to file "' . $this->_filename . '"'); + } + } + + /** + * Render a Zend_Config into a config file string. + * + * @since 1.10 + * @todo For 2.0 this should be redone into an abstract method. + * @return string + */ + public function render() + { + return ""; + } +} diff --git a/library/vendor/Zend/Config/Writer/Ini.php b/library/vendor/Zend/Config/Writer/Ini.php new file mode 100644 index 000000000..e270039ec --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Ini.php @@ -0,0 +1,191 @@ +_nestSeparator = $separator; + + return $this; + } + + /** + * Set if rendering should occour without sections or not. + * + * If set to true, the INI file is rendered without sections completely + * into the global namespace of the INI file. + * + * @param bool $withoutSections + * @return Zend_Config_Writer_Ini + */ + public function setRenderWithoutSections($withoutSections=true) + { + $this->_renderWithoutSections = (bool)$withoutSections; + return $this; + } + + /** + * Render a Zend_Config into a INI config string. + * + * @since 1.10 + * @return string + */ + public function render() + { + $iniString = ''; + $extends = $this->_config->getExtends(); + $sectionName = $this->_config->getSectionName(); + + if($this->_renderWithoutSections == true) { + $iniString .= $this->_addBranch($this->_config); + } else if (is_string($sectionName)) { + $iniString .= '[' . $sectionName . ']' . "\n" + . $this->_addBranch($this->_config) + . "\n"; + } else { + $config = $this->_sortRootElements($this->_config); + foreach ($config as $sectionName => $data) { + if (!($data instanceof Zend_Config)) { + $iniString .= $sectionName + . ' = ' + . $this->_prepareValue($data) + . "\n"; + } else { + if (isset($extends[$sectionName])) { + $sectionName .= ' : ' . $extends[$sectionName]; + } + + $iniString .= '[' . $sectionName . ']' . "\n" + . $this->_addBranch($data) + . "\n"; + } + } + } + + return $iniString; + } + + /** + * Add a branch to an INI string recursively + * + * @param Zend_Config $config + * @return void + */ + protected function _addBranch(Zend_Config $config, $parents = array()) + { + $iniString = ''; + + foreach ($config as $key => $value) { + $group = array_merge($parents, array($key)); + + if ($value instanceof Zend_Config) { + $iniString .= $this->_addBranch($value, $group); + } else { + $iniString .= implode($this->_nestSeparator, $group) + . ' = ' + . $this->_prepareValue($value) + . "\n"; + } + } + + return $iniString; + } + + /** + * Prepare a value for INI + * + * @param mixed $value + * @return string + */ + protected function _prepareValue($value) + { + if (is_integer($value) || is_float($value)) { + return $value; + } elseif (is_bool($value)) { + return ($value ? 'true' : 'false'); + } elseif (strpos($value, '"') === false) { + return '"' . $value . '"'; + } else { + /** @see Zend_Config_Exception */ + throw new Zend_Config_Exception('Value can not contain double quotes "'); + } + } + + /** + * Root elements that are not assigned to any section needs to be + * on the top of config. + * + * @see http://framework.zend.com/issues/browse/ZF-6289 + * @param Zend_Config + * @return Zend_Config + */ + protected function _sortRootElements(Zend_Config $config) + { + $configArray = $config->toArray(); + $sections = array(); + + // remove sections from config array + foreach ($configArray as $key => $value) { + if (is_array($value)) { + $sections[$key] = $value; + unset($configArray[$key]); + } + } + + // readd sections to the end + foreach ($sections as $key => $value) { + $configArray[$key] = $value; + } + + return new Zend_Config($configArray); + } +} diff --git a/library/vendor/Zend/Config/Writer/Json.php b/library/vendor/Zend/Config/Writer/Json.php new file mode 100755 index 000000000..ec5dedb25 --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Json.php @@ -0,0 +1,104 @@ +_prettyPrint; + } + + /** + * Set prettyPrint flag + * + * @param bool $prettyPrint PrettyPrint flag + * @return Zend_Config_Writer_Json + */ + public function setPrettyPrint($flag) + { + $this->_prettyPrint = (bool) $flag; + return $this; + } + + /** + * Render a Zend_Config into a JSON config string. + * + * @since 1.10 + * @return string + */ + public function render() + { + $data = $this->_config->toArray(); + $sectionName = $this->_config->getSectionName(); + $extends = $this->_config->getExtends(); + + if (is_string($sectionName)) { + $data = array($sectionName => $data); + } + + foreach ($extends as $section => $parentSection) { + $data[$section][Zend_Config_Json::EXTENDS_NAME] = $parentSection; + } + + // Ensure that each "extends" section actually exists + foreach ($data as $section => $sectionData) { + if (is_array($sectionData) && isset($sectionData[Zend_Config_Json::EXTENDS_NAME])) { + $sectionExtends = $sectionData[Zend_Config_Json::EXTENDS_NAME]; + if (!isset($data[$sectionExtends])) { + // Remove "extends" declaration if section does not exist + unset($data[$section][Zend_Config_Json::EXTENDS_NAME]); + } + } + } + + $out = Zend_Json::encode($data); + if ($this->prettyPrint()) { + $out = Zend_Json::prettyPrint($out); + } + return $out; + } +} diff --git a/library/vendor/Zend/Config/Writer/Xml.php b/library/vendor/Zend/Config/Writer/Xml.php new file mode 100644 index 000000000..7ef7bf4e2 --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Xml.php @@ -0,0 +1,124 @@ +'); + $extends = $this->_config->getExtends(); + $sectionName = $this->_config->getSectionName(); + + if (is_string($sectionName)) { + $child = $xml->addChild($sectionName); + + $this->_addBranch($this->_config, $child, $xml); + } else { + foreach ($this->_config as $sectionName => $data) { + if (!($data instanceof Zend_Config)) { + $xml->addChild($sectionName, (string) $data); + } else { + $child = $xml->addChild($sectionName); + + if (isset($extends[$sectionName])) { + $child->addAttribute('zf:extends', $extends[$sectionName], Zend_Config_Xml::XML_NAMESPACE); + } + + $this->_addBranch($data, $child, $xml); + } + } + } + + $dom = dom_import_simplexml($xml)->ownerDocument; + $dom->formatOutput = true; + + $xmlString = $dom->saveXML(); + + return $xmlString; + } + + /** + * Add a branch to an XML object recursively + * + * @param Zend_Config $config + * @param SimpleXMLElement $xml + * @param SimpleXMLElement $parent + * @return void + */ + protected function _addBranch(Zend_Config $config, SimpleXMLElement $xml, SimpleXMLElement $parent) + { + $branchType = null; + + foreach ($config as $key => $value) { + if ($branchType === null) { + if (is_numeric($key)) { + $branchType = 'numeric'; + $branchName = $xml->getName(); + $xml = $parent; + + unset($parent->{$branchName}); + } else { + $branchType = 'string'; + } + } else if ($branchType !== (is_numeric($key) ? 'numeric' : 'string')) { + throw new Zend_Config_Exception('Mixing of string and numeric keys is not allowed'); + } + + if ($branchType === 'numeric') { + if ($value instanceof Zend_Config) { + $child = $parent->addChild($branchName); + + $this->_addBranch($value, $child, $parent); + } else { + $parent->addChild($branchName, (string) $value); + } + } else { + if ($value instanceof Zend_Config) { + $child = $xml->addChild($key); + + $this->_addBranch($value, $child, $xml); + } else { + $xml->addChild($key, (string) $value); + } + } + } + } +} diff --git a/library/vendor/Zend/Config/Writer/Yaml.php b/library/vendor/Zend/Config/Writer/Yaml.php new file mode 100755 index 000000000..197bfbfeb --- /dev/null +++ b/library/vendor/Zend/Config/Writer/Yaml.php @@ -0,0 +1,141 @@ +_yamlEncoder; + } + + /** + * Set callback for decoding YAML + * + * @param callable $yamlEncoder the decoder to set + * @return Zend_Config_Yaml + */ + public function setYamlEncoder($yamlEncoder) + { + if (!is_callable($yamlEncoder)) { + throw new Zend_Config_Exception('Invalid parameter to setYamlEncoder - must be callable'); + } + + $this->_yamlEncoder = $yamlEncoder; + return $this; + } + + /** + * Render a Zend_Config into a YAML config string. + * + * @since 1.10 + * @return string + */ + public function render() + { + $data = $this->_config->toArray(); + $sectionName = $this->_config->getSectionName(); + $extends = $this->_config->getExtends(); + + if (is_string($sectionName)) { + $data = array($sectionName => $data); + } + + foreach ($extends as $section => $parentSection) { + $data[$section][Zend_Config_Yaml::EXTENDS_NAME] = $parentSection; + } + + // Ensure that each "extends" section actually exists + foreach ($data as $section => $sectionData) { + if (is_array($sectionData) && isset($sectionData[Zend_Config_Yaml::EXTENDS_NAME])) { + $sectionExtends = $sectionData[Zend_Config_Yaml::EXTENDS_NAME]; + if (!isset($data[$sectionExtends])) { + // Remove "extends" declaration if section does not exist + unset($data[$section][Zend_Config_Yaml::EXTENDS_NAME]); + } + } + } + + return call_user_func($this->getYamlEncoder(), $data); + } + + /** + * Very dumb YAML encoder + * + * Until we have Zend_Yaml... + * + * @param array $data YAML data + * @return string + */ + public static function encode($data) + { + return self::_encodeYaml(0, $data); + } + + /** + * Service function for encoding YAML + * + * @param int $indent Current indent level + * @param array $data Data to encode + * @return string + */ + protected static function _encodeYaml($indent, $data) + { + reset($data); + $result = ""; + $numeric = is_numeric(key($data)); + + foreach($data as $key => $value) { + if(is_array($value)) { + $encoded = "\n".self::_encodeYaml($indent+1, $value); + } else { + $encoded = (string)$value."\n"; + } + $result .= str_repeat(" ", $indent).($numeric?"- ":"$key: ").$encoded; + } + return $result; + } +} diff --git a/library/vendor/Zend/Config/Xml.php b/library/vendor/Zend/Config/Xml.php new file mode 100644 index 000000000..116ba3fd1 --- /dev/null +++ b/library/vendor/Zend/Config/Xml.php @@ -0,0 +1,300 @@ + false, + * 'skipExtends' => false + * ); + * + * @param string $xml XML file or string to process + * @param mixed $section Section to process + * @param array|boolean $options + * @throws Zend_Config_Exception When xml is not set or cannot be loaded + * @throws Zend_Config_Exception When section $sectionName cannot be found in $xml + */ + public function __construct($xml, $section = null, $options = false) + { + if (empty($xml)) { + throw new Zend_Config_Exception('Filename is not set'); + } + + $allowModifications = false; + if (is_bool($options)) { + $allowModifications = $options; + } elseif (is_array($options)) { + if (isset($options['allowModifications'])) { + $allowModifications = (bool) $options['allowModifications']; + } + if (isset($options['skipExtends'])) { + $this->_skipExtends = (bool) $options['skipExtends']; + } + } + + set_error_handler(array($this, '_loadFileErrorHandler')); // Warnings and errors are suppressed + if (strstr($xml, 'getMessage() + ); + } + } + + restore_error_handler(); + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + throw new Zend_Config_Exception($this->_loadFileErrorStr); + } + + if ($section === null) { + $dataArray = array(); + foreach ($config as $sectionName => $sectionData) { + $dataArray[$sectionName] = $this->_processExtends($config, $sectionName); + } + + parent::__construct($dataArray, $allowModifications); + } else if (is_array($section)) { + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($config->$sectionName)) { + throw new Zend_Config_Exception("Section '$sectionName' cannot be found in $xml"); + } + + $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray); + } + + parent::__construct($dataArray, $allowModifications); + } else { + if (!isset($config->$section)) { + throw new Zend_Config_Exception("Section '$section' cannot be found in $xml"); + } + + $dataArray = $this->_processExtends($config, $section); + if (!is_array($dataArray)) { + // Section in the XML file contains just one top level string + $dataArray = array($section => $dataArray); + } + + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Helper function to process each element in the section and handle + * the "extends" inheritance attribute. + * + * @param SimpleXMLElement $element XML Element to process + * @param string $section Section to process + * @param array $config Configuration which was parsed yet + * @throws Zend_Config_Exception When $section cannot be found + * @return array + */ + protected function _processExtends(SimpleXMLElement $element, $section, array $config = array()) + { + if (!isset($element->$section)) { + throw new Zend_Config_Exception("Section '$section' cannot be found"); + } + + $thisSection = $element->$section; + $nsAttributes = $thisSection->attributes(self::XML_NAMESPACE); + + if (isset($thisSection['extends']) || isset($nsAttributes['extends'])) { + $extendedSection = (string) (isset($nsAttributes['extends']) ? $nsAttributes['extends'] : $thisSection['extends']); + $this->_assertValidExtend($section, $extendedSection); + + if (!$this->_skipExtends) { + $config = $this->_processExtends($element, $extendedSection, $config); + } + } + + $config = $this->_arrayMergeRecursive($config, $this->_toArray($thisSection)); + + return $config; + } + + /** + * Returns a string or an associative and possibly multidimensional array from + * a SimpleXMLElement. + * + * @param SimpleXMLElement $xmlObject Convert a SimpleXMLElement into an array + * @return array|string + */ + protected function _toArray(SimpleXMLElement $xmlObject) + { + $config = array(); + $nsAttributes = $xmlObject->attributes(self::XML_NAMESPACE); + + // Search for parent node values + if (count($xmlObject->attributes()) > 0) { + foreach ($xmlObject->attributes() as $key => $value) { + if ($key === 'extends') { + continue; + } + + $value = (string) $value; + + if (array_key_exists($key, $config)) { + if (!is_array($config[$key])) { + $config[$key] = array($config[$key]); + } + + $config[$key][] = $value; + } else { + $config[$key] = $value; + } + } + } + + // Search for local 'const' nodes and replace them + if (count($xmlObject->children(self::XML_NAMESPACE)) > 0) { + if (count($xmlObject->children()) > 0) { + throw new Zend_Config_Exception("A node with a 'const' childnode may not have any other children"); + } + + $dom = dom_import_simplexml($xmlObject); + $namespaceChildNodes = array(); + + // We have to store them in an array, as replacing nodes will + // confuse the DOMNodeList later + foreach ($dom->childNodes as $node) { + if ($node instanceof DOMElement && $node->namespaceURI === self::XML_NAMESPACE) { + $namespaceChildNodes[] = $node; + } + } + + foreach ($namespaceChildNodes as $node) { + switch ($node->localName) { + case 'const': + if (!$node->hasAttributeNS(self::XML_NAMESPACE, 'name')) { + throw new Zend_Config_Exception("Misssing 'name' attribute in 'const' node"); + } + + $constantName = $node->getAttributeNS(self::XML_NAMESPACE, 'name'); + + if (!defined($constantName)) { + throw new Zend_Config_Exception("Constant with name '$constantName' was not defined"); + } + + $constantValue = constant($constantName); + + $dom->replaceChild($dom->ownerDocument->createTextNode($constantValue), $node); + break; + + default: + throw new Zend_Config_Exception("Unknown node with name '$node->localName' found"); + } + } + + return (string) simplexml_import_dom($dom); + } + + // Search for children + if (count($xmlObject->children()) > 0) { + foreach ($xmlObject->children() as $key => $value) { + if (count($value->children()) > 0 || count($value->children(self::XML_NAMESPACE)) > 0) { + $value = $this->_toArray($value); + } else if (count($value->attributes()) > 0) { + $attributes = $value->attributes(); + if (isset($attributes['value'])) { + $value = (string) $attributes['value']; + } else { + $value = $this->_toArray($value); + } + } else { + $value = (string) $value; + } + + if (array_key_exists($key, $config)) { + if (!is_array($config[$key]) || !array_key_exists(0, $config[$key])) { + $config[$key] = array($config[$key]); + } + + $config[$key][] = $value; + } else { + $config[$key] = $value; + } + } + } else if (!isset($xmlObject['extends']) && !isset($nsAttributes['extends']) && (count($config) === 0)) { + // Object has no children nor attributes and doesn't use the extends + // attribute: it's a string + $config = (string) $xmlObject; + } + + return $config; + } +} diff --git a/library/vendor/Zend/Config/Yaml.php b/library/vendor/Zend/Config/Yaml.php new file mode 100755 index 000000000..9f4dd6bf5 --- /dev/null +++ b/library/vendor/Zend/Config/Yaml.php @@ -0,0 +1,406 @@ +_yamlDecoder; + } + + /** + * Set callback for decoding YAML + * + * @param callable $yamlDecoder the decoder to set + * @return Zend_Config_Yaml + */ + public function setYamlDecoder($yamlDecoder) + { + if (!is_callable($yamlDecoder)) { + throw new Zend_Config_Exception('Invalid parameter to setYamlDecoder() - must be callable'); + } + + $this->_yamlDecoder = $yamlDecoder; + return $this; + } + + /** + * Loads the section $section from the config file encoded as YAML + * + * Sections are defined as properties of the main object + * + * In order to extend another section, a section defines the "_extends" + * property having a value of the section name from which the extending + * section inherits values. + * + * Note that the keys in $section will override any keys of the same + * name in the sections that have been included via "_extends". + * + * Options may include: + * - allow_modifications: whether or not the config object is mutable + * - skip_extends: whether or not to skip processing of parent configuration + * - yaml_decoder: a callback to use to decode the Yaml source + * + * @param string $yaml YAML file to process + * @param mixed $section Section to process + * @param array|boolean $options + */ + public function __construct($yaml, $section = null, $options = false) + { + if (empty($yaml)) { + throw new Zend_Config_Exception('Filename is not set'); + } + + $ignoreConstants = $staticIgnoreConstants = self::ignoreConstants(); + $allowModifications = false; + if (is_bool($options)) { + $allowModifications = $options; + } elseif (is_array($options)) { + foreach ($options as $key => $value) { + switch (strtolower($key)) { + case 'allow_modifications': + case 'allowmodifications': + $allowModifications = (bool) $value; + break; + case 'skip_extends': + case 'skipextends': + $this->_skipExtends = (bool) $value; + break; + case 'ignore_constants': + case 'ignoreconstants': + $ignoreConstants = (bool) $value; + break; + case 'yaml_decoder': + case 'yamldecoder': + $this->setYamlDecoder($value); + break; + default: + break; + } + } + } + + // Suppress warnings and errors while loading file + set_error_handler(array($this, '_loadFileErrorHandler')); + $yaml = file_get_contents($yaml); + restore_error_handler(); + + // Check if there was a error while loading file + if ($this->_loadFileErrorStr !== null) { + throw new Zend_Config_Exception($this->_loadFileErrorStr); + } + + // Override static value for ignore_constants if provided in $options + self::setIgnoreConstants($ignoreConstants); + + // Parse YAML + $config = call_user_func($this->getYamlDecoder(), $yaml); + + // Reset original static state of ignore_constants + self::setIgnoreConstants($staticIgnoreConstants); + + if (null === $config) { + // decode failed + throw new Zend_Config_Exception("Error parsing YAML data"); + } + + if (null === $section) { + $dataArray = array(); + foreach ($config as $sectionName => $sectionData) { + $dataArray[$sectionName] = $this->_processExtends($config, $sectionName); + } + parent::__construct($dataArray, $allowModifications); + } elseif (is_array($section)) { + $dataArray = array(); + foreach ($section as $sectionName) { + if (!isset($config[$sectionName])) { + throw new Zend_Config_Exception(sprintf( + 'Section "%s" cannot be found', + implode(' ', (array)$section) + )); + } + + $dataArray = array_merge($this->_processExtends($config, $sectionName), $dataArray); + } + parent::__construct($dataArray, $allowModifications); + } else { + if (!isset($config[$section])) { + throw new Zend_Config_Exception(sprintf( + 'Section "%s" cannot be found', + implode(' ', (array)$section) + )); + } + + $dataArray = $this->_processExtends($config, $section); + if (!is_array($dataArray)) { + // Section in the yaml data contains just one top level string + $dataArray = array($section => $dataArray); + } + parent::__construct($dataArray, $allowModifications); + } + + $this->_loadedSection = $section; + } + + /** + * Helper function to process each element in the section and handle + * the "_extends" inheritance attribute. + * + * @param array $data Data array to process + * @param string $section Section to process + * @param array $config Configuration which was parsed yet + * @return array + * @throws Zend_Config_Exception When $section cannot be found + */ + protected function _processExtends(array $data, $section, array $config = array()) + { + if (!isset($data[$section])) { + throw new Zend_Config_Exception(sprintf('Section "%s" cannot be found', $section)); + } + + $thisSection = $data[$section]; + + if (is_array($thisSection) && isset($thisSection[self::EXTENDS_NAME])) { + $this->_assertValidExtend($section, $thisSection[self::EXTENDS_NAME]); + + if (!$this->_skipExtends) { + $config = $this->_processExtends($data, $thisSection[self::EXTENDS_NAME], $config); + } + unset($thisSection[self::EXTENDS_NAME]); + } + + $config = $this->_arrayMergeRecursive($config, $thisSection); + + return $config; + } + + /** + * Very dumb YAML parser + * + * Until we have Zend_Yaml... + * + * @param string $yaml YAML source + * @return array Decoded data + */ + public static function decode($yaml) + { + $lines = explode("\n", $yaml); + reset($lines); + return self::_decodeYaml(0, $lines); + } + + /** + * Service function to decode YAML + * + * @param int $currentIndent Current indent level + * @param array $lines YAML lines + * @return array|string + */ + protected static function _decodeYaml($currentIndent, &$lines) + { + $config = array(); + $inIndent = false; + while (list($n, $line) = each($lines)) { + $lineno = $n + 1; + + $line = rtrim(preg_replace("/#.*$/", "", $line)); + if (strlen($line) == 0) { + continue; + } + + $indent = strspn($line, " "); + + // line without the spaces + $line = trim($line); + if (strlen($line) == 0) { + continue; + } + + if ($indent < $currentIndent) { + // this level is done + prev($lines); + return $config; + } + + if (!$inIndent) { + $currentIndent = $indent; + $inIndent = true; + } + + if (preg_match("/(?!-)([\w\-]+):\s*(.*)/", $line, $m)) { + // key: value + if (strlen($m[2])) { + // simple key: value + $value = preg_replace("/#.*$/", "", $m[2]); + $value = self::_parseValue($value); + } else { + // key: and then values on new lines + $value = self::_decodeYaml($currentIndent + 1, $lines); + if (is_array($value) && !count($value)) { + $value = ""; + } + } + $config[$m[1]] = $value; + } elseif ($line[0] == "-") { + // item in the list: + // - FOO + if (strlen($line) > 2) { + $value = substr($line, 2); + + $config[] = self::_parseValue($value); + } else { + $config[] = self::_decodeYaml($currentIndent + 1, $lines); + } + } else { + throw new Zend_Config_Exception(sprintf( + 'Error parsing YAML at line %d - unsupported syntax: "%s"', + $lineno, $line + )); + } + } + return $config; + } + + /** + * Parse values + * + * @param string $value + * @return string + */ + protected static function _parseValue($value) + { + $value = trim($value); + + // remove quotes from string. + if ('"' == $value['0']) { + if ('"' == $value[count($value) -1]) { + $value = substr($value, 1, -1); + } + } elseif ('\'' == $value['0'] && '\'' == $value[count($value) -1]) { + $value = strtr($value, array("''" => "'", "'" => '')); + } + + // Check for booleans and constants + if (preg_match('/^(t(rue)?|on|y(es)?)$/i', $value)) { + $value = true; + } elseif (preg_match('/^(f(alse)?|off|n(o)?)$/i', $value)) { + $value = false; + } elseif (strcasecmp($value, 'null') === 0) { + $value = null; + } elseif (!self::$_ignoreConstants) { + // test for constants + $value = self::_replaceConstants($value); + } + + return $value; + } + + /** + * Replace any constants referenced in a string with their values + * + * @param string $value + * @return string + */ + protected static function _replaceConstants($value) + { + foreach (self::_getConstants() as $constant) { + if (strstr($value, $constant)) { + $value = str_replace($constant, constant($constant), $value); + } + } + return $value; + } + + /** + * Get (reverse) sorted list of defined constant names + * + * @return array + */ + protected static function _getConstants() + { + $constants = array_keys(get_defined_constants()); + rsort($constants, SORT_STRING); + return $constants; + } +} diff --git a/library/vendor/Zend/Console/Getopt.php b/library/vendor/Zend/Console/Getopt.php new file mode 100644 index 000000000..84f8f746d --- /dev/null +++ b/library/vendor/Zend/Console/Getopt.php @@ -0,0 +1,958 @@ + self::MODE_ZEND, + self::CONFIG_DASHDASH => true, + self::CONFIG_IGNORECASE => false, + self::CONFIG_PARSEALL => true, + ); + + /** + * Stores the command-line arguments for the calling applicaion. + * + * @var array + */ + protected $_argv = array(); + + /** + * Stores the name of the calling applicaion. + * + * @var string + */ + protected $_progname = ''; + + /** + * Stores the list of legal options for this application. + * + * @var array + */ + protected $_rules = array(); + + /** + * Stores alternate spellings of legal options. + * + * @var array + */ + protected $_ruleMap = array(); + + /** + * Stores options given by the user in the current invocation + * of the application, as well as parameters given in options. + * + * @var array + */ + protected $_options = array(); + + /** + * Stores the command-line arguments other than options. + * + * @var array + */ + protected $_remainingArgs = array(); + + /** + * State of the options: parsed or not yet parsed? + * + * @var boolean + */ + protected $_parsed = false; + + /** + * The constructor takes one to three parameters. + * + * The first parameter is $rules, which may be a string for + * gnu-style format, or a structured array for Zend-style format. + * + * The second parameter is $argv, and it is optional. If not + * specified, $argv is inferred from the global argv. + * + * The third parameter is an array of configuration parameters + * to control the behavior of this instance of Getopt; it is optional. + * + * @param array $rules + * @param array $argv + * @param array $getoptConfig + * @return void + */ + public function __construct($rules, $argv = null, $getoptConfig = array()) + { + if (!isset($_SERVER['argv'])) { + if (ini_get('register_argc_argv') == false) { + throw new Zend_Console_Getopt_Exception( + "argv is not available, because ini option 'register_argc_argv' is set Off" + ); + } else { + throw new Zend_Console_Getopt_Exception( + '$_SERVER["argv"] is not set, but Zend_Console_Getopt cannot work without this information.' + ); + } + } + + $this->_progname = $_SERVER['argv'][0]; + $this->setOptions($getoptConfig); + $this->addRules($rules); + if (!is_array($argv)) { + $argv = array_slice($_SERVER['argv'], 1); + } + if (isset($argv)) { + $this->addArguments((array)$argv); + } + } + + /** + * Return the state of the option seen on the command line of the + * current application invocation. This function returns true, or the + * parameter to the option, if any. If the option was not given, + * this function returns null. + * + * The magic __get method works in the context of naming the option + * as a virtual member of this class. + * + * @param string $key + * @return string + */ + public function __get($key) + { + return $this->getOption($key); + } + + /** + * Test whether a given option has been seen. + * + * @param string $key + * @return boolean + */ + public function __isset($key) + { + $this->parse(); + if (isset($this->_ruleMap[$key])) { + $key = $this->_ruleMap[$key]; + return isset($this->_options[$key]); + } + return false; + } + + /** + * Set the value for a given option. + * + * @param string $key + * @param string $value + * @return void + */ + public function __set($key, $value) + { + $this->parse(); + if (isset($this->_ruleMap[$key])) { + $key = $this->_ruleMap[$key]; + $this->_options[$key] = $value; + } + } + + /** + * Return the current set of options and parameters seen as a string. + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Unset an option. + * + * @param string $key + * @return void + */ + public function __unset($key) + { + $this->parse(); + if (isset($this->_ruleMap[$key])) { + $key = $this->_ruleMap[$key]; + unset($this->_options[$key]); + } + } + + /** + * Define additional command-line arguments. + * These are appended to those defined when the constructor was called. + * + * @param array $argv + * @throws Zend_Console_Getopt_Exception When not given an array as parameter + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function addArguments($argv) + { + if(!is_array($argv)) { + throw new Zend_Console_Getopt_Exception( + "Parameter #1 to addArguments should be an array"); + } + $this->_argv = array_merge($this->_argv, $argv); + $this->_parsed = false; + return $this; + } + + /** + * Define full set of command-line arguments. + * These replace any currently defined. + * + * @param array $argv + * @throws Zend_Console_Getopt_Exception When not given an array as parameter + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setArguments($argv) + { + if(!is_array($argv)) { + throw new Zend_Console_Getopt_Exception( + "Parameter #1 to setArguments should be an array"); + } + $this->_argv = $argv; + $this->_parsed = false; + return $this; + } + + /** + * Define multiple configuration options from an associative array. + * These are not program options, but properties to configure + * the behavior of Zend_Console_Getopt. + * + * @param array $getoptConfig + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setOptions($getoptConfig) + { + if (isset($getoptConfig)) { + foreach ($getoptConfig as $key => $value) { + $this->setOption($key, $value); + } + } + return $this; + } + + /** + * Define one configuration option as a key/value pair. + * These are not program options, but properties to configure + * the behavior of Zend_Console_Getopt. + * + * @param string $configKey + * @param string $configValue + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setOption($configKey, $configValue) + { + if ($configKey !== null) { + $this->_getoptConfig[$configKey] = $configValue; + } + return $this; + } + + /** + * Define additional option rules. + * These are appended to the rules defined when the constructor was called. + * + * @param array $rules + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function addRules($rules) + { + $ruleMode = $this->_getoptConfig['ruleMode']; + switch ($this->_getoptConfig['ruleMode']) { + case self::MODE_ZEND: + if (is_array($rules)) { + $this->_addRulesModeZend($rules); + break; + } + // intentional fallthrough + case self::MODE_GNU: + $this->_addRulesModeGnu($rules); + break; + default: + /** + * Call addRulesModeFoo() for ruleMode 'foo'. + * The developer should subclass Getopt and + * provide this method. + */ + $method = '_addRulesMode' . ucfirst($ruleMode); + $this->$method($rules); + } + $this->_parsed = false; + return $this; + } + + /** + * Return the current set of options and parameters seen as a string. + * + * @return string + */ + public function toString() + { + $this->parse(); + $s = array(); + foreach ($this->_options as $flag => $value) { + $s[] = $flag . '=' . ($value === true ? 'true' : $value); + } + return implode(' ', $s); + } + + /** + * Return the current set of options and parameters seen + * as an array of canonical options and parameters. + * + * Clusters have been expanded, and option aliases + * have been mapped to their primary option names. + * + * @return array + */ + public function toArray() + { + $this->parse(); + $s = array(); + foreach ($this->_options as $flag => $value) { + $s[] = $flag; + if ($value !== true) { + $s[] = $value; + } + } + return $s; + } + + /** + * Return the current set of options and parameters seen in Json format. + * + * @return string + */ + public function toJson() + { + $this->parse(); + $j = array(); + foreach ($this->_options as $flag => $value) { + $j['options'][] = array( + 'option' => array( + 'flag' => $flag, + 'parameter' => $value + ) + ); + } + + /** + * @see Zend_Json + */ + $json = Zend_Json::encode($j); + + return $json; + } + + /** + * Return the current set of options and parameters seen in XML format. + * + * @return string + */ + public function toXml() + { + $this->parse(); + $doc = new DomDocument('1.0', 'utf-8'); + $optionsNode = $doc->createElement('options'); + $doc->appendChild($optionsNode); + foreach ($this->_options as $flag => $value) { + $optionNode = $doc->createElement('option'); + $optionNode->setAttribute('flag', utf8_encode($flag)); + if ($value !== true) { + $optionNode->setAttribute('parameter', utf8_encode($value)); + } + $optionsNode->appendChild($optionNode); + } + $xml = $doc->saveXML(); + return $xml; + } + + /** + * Return a list of options that have been seen in the current argv. + * + * @return array + */ + public function getOptions() + { + $this->parse(); + return array_keys($this->_options); + } + + /** + * Return the state of the option seen on the command line of the + * current application invocation. + * + * This function returns true, or the parameter value to the option, if any. + * If the option was not given, this function returns false. + * + * @param string $flag + * @return mixed + */ + public function getOption($flag) + { + $this->parse(); + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + } + if (isset($this->_ruleMap[$flag])) { + $flag = $this->_ruleMap[$flag]; + if (isset($this->_options[$flag])) { + return $this->_options[$flag]; + } + } + return null; + } + + /** + * Return the arguments from the command-line following all options found. + * + * @return array + */ + public function getRemainingArgs() + { + $this->parse(); + return $this->_remainingArgs; + } + + /** + * Return a useful option reference, formatted for display in an + * error message. + * + * Note that this usage information is provided in most Exceptions + * generated by this class. + * + * @return string + */ + public function getUsageMessage() + { + $usage = "Usage: {$this->_progname} [ options ]\n"; + $maxLen = 20; + $lines = array(); + foreach ($this->_rules as $rule) { + $flags = array(); + if (is_array($rule['alias'])) { + foreach ($rule['alias'] as $flag) { + $flags[] = (strlen($flag) == 1 ? '-' : '--') . $flag; + } + } + $linepart['name'] = implode('|', $flags); + if (isset($rule['param']) && $rule['param'] != 'none') { + $linepart['name'] .= ' '; + switch ($rule['param']) { + case 'optional': + $linepart['name'] .= "[ <{$rule['paramType']}> ]"; + break; + case 'required': + $linepart['name'] .= "<{$rule['paramType']}>"; + break; + } + } + if (strlen($linepart['name']) > $maxLen) { + $maxLen = strlen($linepart['name']); + } + $linepart['help'] = ''; + if (isset($rule['help'])) { + $linepart['help'] .= $rule['help']; + } + $lines[] = $linepart; + } + foreach ($lines as $linepart) { + $usage .= sprintf("%s %s\n", + str_pad($linepart['name'], $maxLen), + $linepart['help']); + } + return $usage; + } + + /** + * Define aliases for options. + * + * The parameter $aliasMap is an associative array + * mapping option name (short or long) to an alias. + * + * @param array $aliasMap + * @throws Zend_Console_Getopt_Exception + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setAliases($aliasMap) + { + foreach ($aliasMap as $flag => $alias) + { + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + $alias = strtolower($alias); + } + if (!isset($this->_ruleMap[$flag])) { + continue; + } + $flag = $this->_ruleMap[$flag]; + if (isset($this->_rules[$alias]) || isset($this->_ruleMap[$alias])) { + $o = (strlen($alias) == 1 ? '-' : '--') . $alias; + throw new Zend_Console_Getopt_Exception( + "Option \"$o\" is being defined more than once."); + } + $this->_rules[$flag]['alias'][] = $alias; + $this->_ruleMap[$alias] = $flag; + } + return $this; + } + + /** + * Define help messages for options. + * + * The parameter $help_map is an associative array + * mapping option name (short or long) to the help string. + * + * @param array $helpMap + * @return Zend_Console_Getopt Provides a fluent interface + */ + public function setHelp($helpMap) + { + foreach ($helpMap as $flag => $help) + { + if (!isset($this->_ruleMap[$flag])) { + continue; + } + $flag = $this->_ruleMap[$flag]; + $this->_rules[$flag]['help'] = $help; + } + return $this; + } + + /** + * Parse command-line arguments and find both long and short + * options. + * + * Also find option parameters, and remaining arguments after + * all options have been parsed. + * + * @return Zend_Console_Getopt|null Provides a fluent interface + */ + public function parse() + { + if ($this->_parsed === true) { + return; + } + $argv = $this->_argv; + $this->_options = array(); + $this->_remainingArgs = array(); + while (count($argv) > 0) { + if ($argv[0] == '--') { + array_shift($argv); + if ($this->_getoptConfig[self::CONFIG_DASHDASH]) { + $this->_remainingArgs = array_merge($this->_remainingArgs, $argv); + break; + } + } + if (substr($argv[0], 0, 2) == '--') { + $this->_parseLongOption($argv); + } else if (substr($argv[0], 0, 1) == '-' && ('-' != $argv[0] || count($argv) >1)) { + $this->_parseShortOptionCluster($argv); + } else if($this->_getoptConfig[self::CONFIG_PARSEALL]) { + $this->_remainingArgs[] = array_shift($argv); + } else { + /* + * We should put all other arguments in _remainingArgs and stop parsing + * since CONFIG_PARSEALL is false. + */ + $this->_remainingArgs = array_merge($this->_remainingArgs, $argv); + break; + } + } + $this->_parsed = true; + return $this; + } + + /** + * Parse command-line arguments for a single long option. + * A long option is preceded by a double '--' character. + * Long options may not be clustered. + * + * @param mixed &$argv + * @return void + */ + protected function _parseLongOption(&$argv) + { + $optionWithParam = ltrim(array_shift($argv), '-'); + $l = explode('=', $optionWithParam, 2); + $flag = array_shift($l); + $param = array_shift($l); + if (isset($param)) { + array_unshift($argv, $param); + } + $this->_parseSingleOption($flag, $argv); + } + + /** + * Parse command-line arguments for short options. + * Short options are those preceded by a single '-' character. + * Short options may be clustered. + * + * @param mixed &$argv + * @return void + */ + protected function _parseShortOptionCluster(&$argv) + { + $flagCluster = ltrim(array_shift($argv), '-'); + foreach (str_split($flagCluster) as $flag) { + $this->_parseSingleOption($flag, $argv); + } + } + + /** + * Parse command-line arguments for a single option. + * + * @param string $flag + * @param mixed $argv + * @throws Zend_Console_Getopt_Exception + * @return void + */ + protected function _parseSingleOption($flag, &$argv) + { + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + } + if (!isset($this->_ruleMap[$flag])) { + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" is not recognized.", + $this->getUsageMessage()); + } + $realFlag = $this->_ruleMap[$flag]; + switch ($this->_rules[$realFlag]['param']) { + case 'required': + if (count($argv) > 0) { + $param = array_shift($argv); + $this->_checkParameterType($realFlag, $param); + } else { + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" requires a parameter.", + $this->getUsageMessage()); + } + break; + case 'optional': + if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') { + $param = array_shift($argv); + $this->_checkParameterType($realFlag, $param); + } else { + $param = true; + } + break; + default: + $param = true; + } + $this->_options[$realFlag] = $param; + } + + /** + * Return true if the parameter is in a valid format for + * the option $flag. + * Throw an exception in most other cases. + * + * @param string $flag + * @param string $param + * @throws Zend_Console_Getopt_Exception + * @return bool + */ + protected function _checkParameterType($flag, $param) + { + $type = 'string'; + if (isset($this->_rules[$flag]['paramType'])) { + $type = $this->_rules[$flag]['paramType']; + } + switch ($type) { + case 'word': + if (preg_match('/\W/', $param)) { + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" requires a single-word parameter, but was given \"$param\".", + $this->getUsageMessage()); + } + break; + case 'integer': + if (preg_match('/\D/', $param)) { + throw new Zend_Console_Getopt_Exception( + "Option \"$flag\" requires an integer parameter, but was given \"$param\".", + $this->getUsageMessage()); + } + break; + case 'string': + default: + break; + } + return true; + } + + /** + * Define legal options using the gnu-style format. + * + * @param string $rules + * @return void + */ + protected function _addRulesModeGnu($rules) + { + $ruleArray = array(); + + /** + * Options may be single alphanumeric characters. + * Options may have a ':' which indicates a required string parameter. + * No long options or option aliases are supported in GNU style. + */ + preg_match_all('/([a-zA-Z0-9]:?)/', $rules, $ruleArray); + foreach ($ruleArray[1] as $rule) { + $r = array(); + $flag = substr($rule, 0, 1); + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flag = strtolower($flag); + } + $r['alias'][] = $flag; + if (substr($rule, 1, 1) == ':') { + $r['param'] = 'required'; + $r['paramType'] = 'string'; + } else { + $r['param'] = 'none'; + } + $this->_rules[$flag] = $r; + $this->_ruleMap[$flag] = $flag; + } + } + + /** + * Define legal options using the Zend-style format. + * + * @param array $rules + * @throws Zend_Console_Getopt_Exception + * @return void + */ + protected function _addRulesModeZend($rules) + { + foreach ($rules as $ruleCode => $helpMessage) + { + // this may have to translate the long parm type if there + // are any complaints that =string will not work (even though that use + // case is not documented) + if (in_array(substr($ruleCode, -2, 1), array('-', '='))) { + $flagList = substr($ruleCode, 0, -2); + $delimiter = substr($ruleCode, -2, 1); + $paramType = substr($ruleCode, -1); + } else { + $flagList = $ruleCode; + $delimiter = $paramType = null; + } + if ($this->_getoptConfig[self::CONFIG_IGNORECASE]) { + $flagList = strtolower($flagList); + } + $flags = explode('|', $flagList); + $rule = array(); + $mainFlag = $flags[0]; + foreach ($flags as $flag) { + if (empty($flag)) { + throw new Zend_Console_Getopt_Exception( + "Blank flag not allowed in rule \"$ruleCode\"."); + } + if (strlen($flag) == 1) { + if (isset($this->_ruleMap[$flag])) { + throw new Zend_Console_Getopt_Exception( + "Option \"-$flag\" is being defined more than once."); + } + $this->_ruleMap[$flag] = $mainFlag; + $rule['alias'][] = $flag; + } else { + if (isset($this->_rules[$flag]) || isset($this->_ruleMap[$flag])) { + throw new Zend_Console_Getopt_Exception( + "Option \"--$flag\" is being defined more than once."); + } + $this->_ruleMap[$flag] = $mainFlag; + $rule['alias'][] = $flag; + } + } + if (isset($delimiter)) { + switch ($delimiter) { + case self::PARAM_REQUIRED: + $rule['param'] = 'required'; + break; + case self::PARAM_OPTIONAL: + default: + $rule['param'] = 'optional'; + } + switch (substr($paramType, 0, 1)) { + case self::TYPE_WORD: + $rule['paramType'] = 'word'; + break; + case self::TYPE_INTEGER: + $rule['paramType'] = 'integer'; + break; + case self::TYPE_STRING: + default: + $rule['paramType'] = 'string'; + } + } else { + $rule['param'] = 'none'; + } + $rule['help'] = $helpMessage; + $this->_rules[$mainFlag] = $rule; + } + } + +} diff --git a/library/vendor/Zend/Console/Getopt/Exception.php b/library/vendor/Zend/Console/Getopt/Exception.php new file mode 100644 index 000000000..4ceeb6628 --- /dev/null +++ b/library/vendor/Zend/Console/Getopt/Exception.php @@ -0,0 +1,65 @@ +usage = $usage; + parent::__construct($message); + } + + /** + * Returns the usage + * + * @return string + */ + public function getUsageMessage() + { + return $this->usage; + } +} diff --git a/library/vendor/Zend/Controller/Action.php b/library/vendor/Zend/Controller/Action.php new file mode 100644 index 000000000..7b78901a8 --- /dev/null +++ b/library/vendor/Zend/Controller/Action.php @@ -0,0 +1,789 @@ +setRequest($request) + ->setResponse($response) + ->_setInvokeArgs($invokeArgs); + $this->_helper = new Zend_Controller_Action_HelperBroker($this); + $this->init(); + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Initialize View object + * + * Initializes {@link $view} if not otherwise a Zend_View_Interface. + * + * If {@link $view} is not otherwise set, instantiates a new Zend_View + * object, using the 'views' subdirectory at the same level as the + * controller directory for the current module as the base directory. + * It uses this to set the following: + * - script path = views/scripts/ + * - helper path = views/helpers/ + * - filter path = views/filters/ + * + * @return Zend_View_Interface + * @throws Zend_Controller_Exception if base view directory does not exist + */ + public function initView() + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + return $this->view; + } + + if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) { + return $this->view; + } + + $request = $this->getRequest(); + $module = $request->getModuleName(); + $dirs = $this->getFrontController()->getControllerDirectory(); + if (empty($module) || !isset($dirs[$module])) { + $module = $this->getFrontController()->getDispatcher()->getDefaultModule(); + } + $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views'; + if (!file_exists($baseDir) || !is_dir($baseDir)) { + throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")'); + } + + $this->view = new Zend_View(array('basePath' => $baseDir)); + + return $this->view; + } + + /** + * Render a view + * + * Renders a view. By default, views are found in the view script path as + * /.phtml. You may change the script suffix by + * resetting {@link $viewSuffix}. You may omit the controller directory + * prefix by specifying boolean true for $noController. + * + * By default, the rendered contents are appended to the response. You may + * specify the named body content segment to set by specifying a $name. + * + * @see Zend_Controller_Response_Abstract::appendBody() + * @param string|null $action Defaults to action registered in request object + * @param string|null $name Response object named path segment to use; defaults to null + * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script + * @return void + */ + public function render($action = null, $name = null, $noController = false) + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + return $this->_helper->viewRenderer->render($action, $name, $noController); + } + + $view = $this->initView(); + $script = $this->getViewScript($action, $noController); + + $this->getResponse()->appendBody( + $view->render($script), + $name + ); + } + + /** + * Render a given view script + * + * Similar to {@link render()}, this method renders a view script. Unlike render(), + * however, it does not autodetermine the view script via {@link getViewScript()}, + * but instead renders the script passed to it. Use this if you know the + * exact view script name and path you wish to use, or if using paths that do not + * conform to the spec defined with getViewScript(). + * + * By default, the rendered contents are appended to the response. You may + * specify the named body content segment to set by specifying a $name. + * + * @param string $script + * @param string $name + * @return void + */ + public function renderScript($script, $name = null) + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + return $this->_helper->viewRenderer->renderScript($script, $name); + } + + $view = $this->initView(); + $this->getResponse()->appendBody( + $view->render($script), + $name + ); + } + + /** + * Construct view script path + * + * Used by render() to determine the path to the view script. + * + * @param string $action Defaults to action registered in request object + * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script + * @return string + * @throws Zend_Controller_Exception with bad $action + */ + public function getViewScript($action = null, $noController = null) + { + if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) { + $viewRenderer = $this->_helper->getHelper('viewRenderer'); + if (null !== $noController) { + $viewRenderer->setNoController($noController); + } + return $viewRenderer->getViewScript($action); + } + + $request = $this->getRequest(); + if (null === $action) { + $action = $request->getActionName(); + } elseif (!is_string($action)) { + throw new Zend_Controller_Exception('Invalid action specifier for view render'); + } + + if (null === $this->_delimiters) { + $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher(); + $wordDelimiters = $dispatcher->getWordDelimiter(); + $pathDelimiters = $dispatcher->getPathDelimiter(); + $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters)); + } + + $action = str_replace($this->_delimiters, '-', $action); + $script = $action . '.' . $this->viewSuffix; + + if (!$noController) { + $controller = $request->getControllerName(); + $controller = str_replace($this->_delimiters, '-', $controller); + $script = $controller . DIRECTORY_SEPARATOR . $script; + } + + return $script; + } + + /** + * Return the Request object + * + * @return Zend_Controller_Request_Abstract + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set the Request object + * + * @param Zend_Controller_Request_Abstract $request + * @return Zend_Controller_Action + */ + public function setRequest(Zend_Controller_Request_Abstract $request) + { + $this->_request = $request; + return $this; + } + + /** + * Return the Response object + * + * @return Zend_Controller_Response_Abstract + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Set the Response object + * + * @param Zend_Controller_Response_Abstract $response + * @return Zend_Controller_Action + */ + public function setResponse(Zend_Controller_Response_Abstract $response) + { + $this->_response = $response; + return $this; + } + + /** + * Set invocation arguments + * + * @param array $args + * @return Zend_Controller_Action + */ + protected function _setInvokeArgs(array $args = array()) + { + $this->_invokeArgs = $args; + return $this; + } + + /** + * Return the array of constructor arguments (minus the Request object) + * + * @return array + */ + public function getInvokeArgs() + { + return $this->_invokeArgs; + } + + /** + * Return a single invocation argument + * + * @param string $key + * @return mixed + */ + public function getInvokeArg($key) + { + if (isset($this->_invokeArgs[$key])) { + return $this->_invokeArgs[$key]; + } + + return null; + } + + /** + * Get a helper by name + * + * @param string $helperName + * @return Zend_Controller_Action_Helper_Abstract + */ + public function getHelper($helperName) + { + return $this->_helper->{$helperName}; + } + + /** + * Get a clone of a helper by name + * + * @param string $helperName + * @return Zend_Controller_Action_Helper_Abstract + */ + public function getHelperCopy($helperName) + { + return clone $this->_helper->{$helperName}; + } + + /** + * Set the front controller instance + * + * @param Zend_Controller_Front $front + * @return Zend_Controller_Action + */ + public function setFrontController(Zend_Controller_Front $front) + { + $this->_frontController = $front; + return $this; + } + + /** + * Retrieve Front Controller + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + // Used cache version if found + if (null !== $this->_frontController) { + return $this->_frontController; + } + + // Grab singleton instance, if class has been loaded + if (class_exists('Zend_Controller_Front')) { + $this->_frontController = Zend_Controller_Front::getInstance(); + return $this->_frontController; + } + + // Throw exception in all other cases + throw new Zend_Controller_Exception('Front controller class has not been loaded'); + } + + /** + * Pre-dispatch routines + * + * Called before action method. If using class with + * {@link Zend_Controller_Front}, it may modify the + * {@link $_request Request object} and reset its dispatched flag in order + * to skip processing the current action. + * + * @return void + */ + public function preDispatch() + { + } + + /** + * Post-dispatch routines + * + * Called after action method execution. If using class with + * {@link Zend_Controller_Front}, it may modify the + * {@link $_request Request object} and reset its dispatched flag in order + * to process an additional action. + * + * Common usages for postDispatch() include rendering content in a sitewide + * template, link url correction, setting headers, etc. + * + * @return void + */ + public function postDispatch() + { + } + + /** + * Proxy for undefined methods. Default behavior is to throw an + * exception on undefined methods, however this function can be + * overridden to implement magic (dynamic) actions, or provide run-time + * dispatching. + * + * @param string $methodName + * @param array $args + * @return void + * @throws Zend_Controller_Action_Exception + */ + public function __call($methodName, $args) + { + if ('Action' == substr($methodName, -6)) { + $action = substr($methodName, 0, strlen($methodName) - 6); + throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404); + } + + throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500); + } + + /** + * Dispatch the requested action + * + * @param string $action Method name of action + * @return void + */ + public function dispatch($action) + { + // Notify helpers of action preDispatch state + $this->_helper->notifyPreDispatch(); + + $this->preDispatch(); + if ($this->getRequest()->isDispatched()) { + if (null === $this->_classMethods) { + $this->_classMethods = get_class_methods($this); + } + + // If pre-dispatch hooks introduced a redirect then stop dispatch + // @see ZF-7496 + if (!($this->getResponse()->isRedirect())) { + // preDispatch() didn't change the action, so we can continue + if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) { + if ($this->getInvokeArg('useCaseSensitiveActions')) { + trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"'); + } + $this->$action(); + } else { + $this->__call($action, array()); + } + } + $this->postDispatch(); + } + + // whats actually important here is that this action controller is + // shutting down, regardless of dispatching; notify the helpers of this + // state + $this->_helper->notifyPostDispatch(); + } + + /** + * Call the action specified in the request object, and return a response + * + * Not used in the Action Controller implementation, but left for usage in + * Page Controller implementations. Dispatches a method based on the + * request. + * + * Returns a Zend_Controller_Response_Abstract object, instantiating one + * prior to execution if none exists in the controller. + * + * {@link preDispatch()} is called prior to the action, + * {@link postDispatch()} is called following it. + * + * @param null|Zend_Controller_Request_Abstract $request Optional request + * object to use + * @param null|Zend_Controller_Response_Abstract $response Optional response + * object to use + * @return Zend_Controller_Response_Abstract + */ + public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) + { + if (null !== $request) { + $this->setRequest($request); + } else { + $request = $this->getRequest(); + } + + if (null !== $response) { + $this->setResponse($response); + } + + $action = $request->getActionName(); + if (empty($action)) { + $action = 'index'; + } + $action = $action . 'Action'; + + $request->setDispatched(true); + $this->dispatch($action); + + return $this->getResponse(); + } + + /** + * Gets a parameter from the {@link $_request Request object}. If the + * parameter does not exist, NULL will be returned. + * + * If the parameter does not exist and $default is set, then + * $default will be returned instead of NULL. + * + * @param string $paramName + * @param mixed $default + * @return mixed + */ + protected function _getParam($paramName, $default = null) + { + return $this->getParam($paramName, $default); + } + + /** + * Gets a parameter from the {@link $_request Request object}. If the + * parameter does not exist, NULL will be returned. + * + * If the parameter does not exist and $default is set, then + * $default will be returned instead of NULL. + * + * @param string $paramName + * @param mixed $default + * @return mixed + */ + public function getParam($paramName, $default = null) + { + $value = $this->getRequest()->getParam($paramName); + if ((null === $value || '' === $value) && (null !== $default)) { + $value = $default; + } + + return $value; + } + + /** + * Set a parameter in the {@link $_request Request object}. + * + * @param string $paramName + * @param mixed $value + * @return Zend_Controller_Action + * @deprecated Deprecated as of Zend Framework 1.7. Use + * setParam() instead. + */ + protected function _setParam($paramName, $value) + { + return $this->setParam($paramName, $value); + } + + /** + * Set a parameter in the {@link $_request Request object}. + * + * @param string $paramName + * @param mixed $value + * @return Zend_Controller_Action + */ + public function setParam($paramName, $value) + { + $this->getRequest()->setParam($paramName, $value); + + return $this; + } + + /** + * Determine whether a given parameter exists in the + * {@link $_request Request object}. + * + * @param string $paramName + * @return boolean + * @deprecated Deprecated as of Zend Framework 1.7. Use + * hasParam() instead. + */ + protected function _hasParam($paramName) + { + return $this->hasParam($paramName); + } + + /** + * Determine whether a given parameter exists in the + * {@link $_request Request object}. + * + * @param string $paramName + * @return boolean + */ + public function hasParam($paramName) + { + return null !== $this->getRequest()->getParam($paramName); + } + + /** + * Return all parameters in the {@link $_request Request object} + * as an associative array. + * + * @return array + * @deprecated Deprecated as of Zend Framework 1.7. Use + * getAllParams() instead. + */ + protected function _getAllParams() + { + return $this->getAllParams(); + } + + /** + * Return all parameters in the {@link $_request Request object} + * as an associative array. + * + * @return array + */ + public function getAllParams() + { + return $this->getRequest()->getParams(); + } + + + /** + * Forward to another controller/action. + * + * It is important to supply the unformatted names, i.e. "article" + * rather than "ArticleController". The dispatcher will do the + * appropriate formatting when the request is received. + * + * If only an action name is provided, forwards to that action in this + * controller. + * + * If an action and controller are specified, forwards to that action and + * controller in this module. + * + * Specifying an action, controller, and module is the most specific way to + * forward. + * + * A fourth argument, $params, will be used to set the request parameters. + * If either the controller or module are unnecessary for forwarding, + * simply pass null values for them before specifying the parameters. + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + * @deprecated Deprecated as of Zend Framework 1.7. Use + * forward() instead. + */ + final protected function _forward($action, $controller = null, $module = null, array $params = null) + { + $this->forward($action, $controller, $module, $params); + } + + /** + * Forward to another controller/action. + * + * It is important to supply the unformatted names, i.e. "article" + * rather than "ArticleController". The dispatcher will do the + * appropriate formatting when the request is received. + * + * If only an action name is provided, forwards to that action in this + * controller. + * + * If an action and controller are specified, forwards to that action and + * controller in this module. + * + * Specifying an action, controller, and module is the most specific way to + * forward. + * + * A fourth argument, $params, will be used to set the request parameters. + * If either the controller or module are unnecessary for forwarding, + * simply pass null values for them before specifying the parameters. + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + final public function forward($action, $controller = null, $module = null, array $params = null) + { + $request = $this->getRequest(); + + if (null !== $params) { + $request->setParams($params); + } + + if (null !== $controller) { + $request->setControllerName($controller); + + // Module should only be reset if controller has been specified + if (null !== $module) { + $request->setModuleName($module); + } + } + + $request->setActionName($action) + ->setDispatched(false); + } + + /** + * Redirect to another URL + * + * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}. + * + * @param string $url + * @param array $options Options to be used when redirecting + * @return void + * @deprecated Deprecated as of Zend Framework 1.7. Use + * redirect() instead. + */ + protected function _redirect($url, array $options = array()) + { + $this->redirect($url, $options); + } + + /** + * Redirect to another URL + * + * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}. + * + * @param string $url + * @param array $options Options to be used when redirecting + * @return void + */ + public function redirect($url, array $options = array()) + { + $this->_helper->redirector->gotoUrl($url, $options); + } +} diff --git a/library/vendor/Zend/Controller/Action/Exception.php b/library/vendor/Zend/Controller/Action/Exception.php new file mode 100644 index 000000000..538cf1021 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Exception.php @@ -0,0 +1,37 @@ +_actionController = $actionController; + return $this; + } + + /** + * Retrieve current action controller + * + * @return Zend_Controller_Action + */ + public function getActionController() + { + return $this->_actionController; + } + + /** + * Retrieve front controller instance + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + return Zend_Controller_Front::getInstance(); + } + + /** + * Hook into action controller initialization + * + * @return void + */ + public function init() + { + } + + /** + * Hook into action controller preDispatch() workflow + * + * @return void + */ + public function preDispatch() + { + } + + /** + * Hook into action controller postDispatch() workflow + * + * @return void + */ + public function postDispatch() + { + } + + /** + * getRequest() - + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + $controller = $this->getActionController(); + if (null === $controller) { + $controller = $this->getFrontController(); + } + + return $controller->getRequest(); + } + + /** + * getResponse() - + * + * @return Zend_Controller_Response_Abstract $response + */ + public function getResponse() + { + $controller = $this->getActionController(); + if (null === $controller) { + $controller = $this->getFrontController(); + } + + return $controller->getResponse(); + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + $fullClassName = get_class($this); + if (strpos($fullClassName, '_') !== false) { + $helperName = strrchr($fullClassName, '_'); + return ltrim($helperName, '_'); + } elseif (strpos($fullClassName, '\\') !== false) { + $helperName = strrchr($fullClassName, '\\'); + return ltrim($helperName, '\\'); + } else { + return $fullClassName; + } + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/ActionStack.php b/library/vendor/Zend/Controller/Action/Helper/ActionStack.php new file mode 100644 index 000000000..9c38f8cff --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/ActionStack.php @@ -0,0 +1,133 @@ +hasPlugin('Zend_Controller_Plugin_ActionStack')) { + /** + * @see Zend_Controller_Plugin_ActionStack + */ + $this->_actionStack = new Zend_Controller_Plugin_ActionStack(); + $front->registerPlugin($this->_actionStack, 97); + } else { + $this->_actionStack = $front->getPlugin('Zend_Controller_Plugin_ActionStack'); + } + } + + /** + * Push onto the stack + * + * @param Zend_Controller_Request_Abstract $next + * @return Zend_Controller_Action_Helper_ActionStack Provides a fluent interface + */ + public function pushStack(Zend_Controller_Request_Abstract $next) + { + $this->_actionStack->pushStack($next); + return $this; + } + + /** + * Push a new action onto the stack + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ActionStack + */ + public function actionToStack($action, $controller = null, $module = null, array $params = array()) + { + if ($action instanceof Zend_Controller_Request_Abstract) { + return $this->pushStack($action); + } elseif (!is_string($action)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('ActionStack requires either a request object or minimally a string action'); + } + + $request = $this->getRequest(); + + if ($request instanceof Zend_Controller_Request_Abstract === false){ + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Request object not set yet'); + } + + $controller = (null === $controller) ? $request->getControllerName() : $controller; + $module = (null === $module) ? $request->getModuleName() : $module; + + /** + * @see Zend_Controller_Request_Simple + */ + $newRequest = new Zend_Controller_Request_Simple($action, $controller, $module, $params); + + return $this->pushStack($newRequest); + } + + /** + * Perform helper when called as $this->_helper->actionStack() from an action controller + * + * Proxies to {@link simple()} + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return boolean + */ + public function direct($action, $controller = null, $module = null, array $params = array()) + { + return $this->actionToStack($action, $controller, $module, $params); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/AjaxContext.php b/library/vendor/Zend/Controller/Action/Helper/AjaxContext.php new file mode 100644 index 000000000..42233cf44 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/AjaxContext.php @@ -0,0 +1,79 @@ +addContext('html', array('suffix' => 'ajax')); + } + + /** + * Initialize AJAX context switching + * + * Checks for XHR requests; if detected, attempts to perform context switch. + * + * @param string $format + * @return void + */ + public function initContext($format = null) + { + $this->_currentContext = null; + + $request = $this->getRequest(); + if (!method_exists($request, 'isXmlHttpRequest') || + !$this->getRequest()->isXmlHttpRequest()) + { + return; + } + + return parent::initContext($format); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php b/library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php new file mode 100644 index 000000000..7664379bf --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/AutoComplete/Abstract.php @@ -0,0 +1,146 @@ +disableLayout(); + } + + Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true); + + return $this; + } + + /** + * Encode data to JSON + * + * @param mixed $data + * @param bool $keepLayouts + * @throws Zend_Controller_Action_Exception + * @return string + */ + public function encodeJson($data, $keepLayouts = false) + { + if ($this->validateData($data)) { + return Zend_Controller_Action_HelperBroker::getStaticHelper('Json')->encodeJson($data, $keepLayouts); + } + + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid data passed for autocompletion'); + } + + /** + * Send autocompletion data + * + * Calls prepareAutoCompletion, populates response body with this + * information, and sends response. + * + * @param mixed $data + * @param bool $keepLayouts + * @return string|void + */ + public function sendAutoCompletion($data, $keepLayouts = false) + { + $data = $this->prepareAutoCompletion($data, $keepLayouts); + + $response = $this->getResponse(); + $response->setBody($data); + + if (!$this->suppressExit) { + $response->sendResponse(); + exit; + } + + return $data; + } + + /** + * Strategy pattern: allow calling helper as broker method + * + * Prepares autocompletion data and, if $sendNow is true, immediately sends + * response. + * + * @param mixed $data + * @param bool $sendNow + * @param bool $keepLayouts + * @return string|void + */ + public function direct($data, $sendNow = true, $keepLayouts = false) + { + if ($sendNow) { + return $this->sendAutoCompletion($data, $keepLayouts); + } + + return $this->prepareAutoCompletion($data, $keepLayouts); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/AutoCompleteDojo.php b/library/vendor/Zend/Controller/Action/Helper/AutoCompleteDojo.php new file mode 100644 index 000000000..17f8844b3 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/AutoCompleteDojo.php @@ -0,0 +1,83 @@ + $value) { + $items[] = array('label' => $value, 'name' => $value); + } + $data = new Zend_Dojo_Data('name', $items); + } + + if (!$keepLayouts) { + Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true); + + $layout = Zend_Layout::getMvcInstance(); + if ($layout instanceof Zend_Layout) { + $layout->disableLayout(); + } + } + + $response = Zend_Controller_Front::getInstance()->getResponse(); + $response->setHeader('Content-Type', 'application/json'); + + return $data->toJson(); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/AutoCompleteScriptaculous.php b/library/vendor/Zend/Controller/Action/Helper/AutoCompleteScriptaculous.php new file mode 100644 index 000000000..d7b25fc10 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/AutoCompleteScriptaculous.php @@ -0,0 +1,80 @@ +validateData($data)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid data passed for autocompletion'); + } + + $data = (array) $data; + $data = '
              • ' . implode('
              • ', $data) . '
              '; + + if (!$keepLayouts) { + $this->disableLayouts(); + } + + return $data; + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Cache.php b/library/vendor/Zend/Controller/Action/Helper/Cache.php new file mode 100644 index 000000000..fecd0080b --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Cache.php @@ -0,0 +1,286 @@ +getRequest()->getControllerName(); + $actions = array_unique($actions); + if (!isset($this->_caching[$controller])) { + $this->_caching[$controller] = array(); + } + if (!empty($tags)) { + $tags = array_unique($tags); + if (!isset($this->_tags[$controller])) { + $this->_tags[$controller] = array(); + } + } + foreach ($actions as $action) { + $this->_caching[$controller][] = $action; + if (!empty($tags)) { + $this->_tags[$controller][$action] = array(); + foreach ($tags as $tag) { + $this->_tags[$controller][$action][] = $tag; + } + } + } + if ($extension) { + if (!isset($this->_extensions[$controller])) { + $this->_extensions[$controller] = array(); + } + foreach ($actions as $action) { + $this->_extensions[$controller][$action] = $extension; + } + } + } + + /** + * Remove a specific page cache static file based on its + * relative URL from the application's public directory. + * The file extension is not required here; usually matches + * the original REQUEST_URI that was cached. + * + * @param string $relativeUrl + * @param bool $recursive + * @return mixed + */ + public function removePage($relativeUrl, $recursive = false) + { + $cache = $this->getCache(Zend_Cache_Manager::PAGECACHE); + $encodedCacheId = $this->_encodeCacheId($relativeUrl); + + if ($recursive) { + $backend = $cache->getBackend(); + if (($backend instanceof Zend_Cache_Backend) + && method_exists($backend, 'removeRecursively') + ) { + $result = $backend->removeRecursively($encodedCacheId); + if (is_null($result) ) { + $result = $backend->removeRecursively($relativeUrl); + } + return $result; + } + } + + $result = $cache->remove($encodedCacheId); + if (is_null($result) ) { + $result = $cache->remove($relativeUrl); + } + return $result; + } + + /** + * Remove a specific page cache static file based on its + * relative URL from the application's public directory. + * The file extension is not required here; usually matches + * the original REQUEST_URI that was cached. + * + * @param array $tags + * @return mixed + */ + public function removePagesTagged(array $tags) + { + return $this->getCache(Zend_Cache_Manager::PAGECACHE) + ->clean(Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, $tags); + } + + /** + * Commence page caching for any cacheable actions + * + * @return void + */ + public function preDispatch() + { + $controller = $this->getRequest()->getControllerName(); + $action = $this->getRequest()->getActionName(); + $stats = ob_get_status(true); + foreach ($stats as $status) { + if ($status['name'] == 'Zend_Cache_Frontend_Page::_flush' + || $status['name'] == 'Zend_Cache_Frontend_Capture::_flush') { + $obStarted = true; + } + } + if (!isset($obStarted) && isset($this->_caching[$controller]) && + in_array($action, $this->_caching[$controller])) { + $reqUri = $this->getRequest()->getRequestUri(); + $tags = array(); + if (isset($this->_tags[$controller][$action]) + && !empty($this->_tags[$controller][$action])) { + $tags = array_unique($this->_tags[$controller][$action]); + } + $extension = null; + if (isset($this->_extensions[$controller][$action])) { + $extension = $this->_extensions[$controller][$action]; + } + $this->getCache(Zend_Cache_Manager::PAGECACHE) + ->start($this->_encodeCacheId($reqUri), $tags, $extension); + } + } + + /** + * Encode a Cache ID as hexadecimal. This is a workaround because Backend ID validation + * is trapped in the Frontend classes. Will try to get this reversed for ZF 2.0 + * because it's a major annoyance to have IDs so restricted! + * + * @return string + * @param string $requestUri + */ + protected function _encodeCacheId($requestUri) + { + return bin2hex($requestUri); + } + + /** + * Set an instance of the Cache Manager for this helper + * + * @param Zend_Cache_Manager $manager + * @return void + */ + public function setManager(Zend_Cache_Manager $manager) + { + $this->_manager = $manager; + return $this; + } + + /** + * Get the Cache Manager instance or instantiate the object if not + * exists. Attempts to load from bootstrap if available. + * + * @return Zend_Cache_Manager + */ + public function getManager() + { + if ($this->_manager !== null) { + return $this->_manager; + } + $front = Zend_Controller_Front::getInstance(); + if ($front->getParam('bootstrap') + && $front->getParam('bootstrap')->getResource('CacheManager')) { + return $front->getParam('bootstrap') + ->getResource('CacheManager'); + } + $this->_manager = new Zend_Cache_Manager; + return $this->_manager; + } + + /** + * Return a list of actions for the current Controller marked for + * caching + * + * @return array + */ + public function getCacheableActions() + { + return $this->_caching; + } + + /** + * Return a list of tags set for all cacheable actions + * + * @return array + */ + public function getCacheableTags() + { + return $this->_tags; + } + + /** + * Proxy non-matched methods back to Zend_Cache_Manager where + * appropriate + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if (method_exists($this->getManager(), $method)) { + return call_user_func_array( + array($this->getManager(), $method), $args + ); + } + throw new Zend_Controller_Action_Exception('Method does not exist:' + . $method); + } + +} diff --git a/library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php b/library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php new file mode 100644 index 000000000..576f98e07 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/ContextSwitch.php @@ -0,0 +1,1377 @@ +setConfig($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + + if (empty($this->_contexts)) { + $this->addContexts(array( + 'json' => array( + 'suffix' => 'json', + 'headers' => array('Content-Type' => 'application/json'), + 'callbacks' => array( + 'init' => 'initJsonContext', + 'post' => 'postJsonContext' + ) + ), + 'xml' => array( + 'suffix' => 'xml', + 'headers' => array('Content-Type' => 'application/xml'), + ) + )); + } + + $this->init(); + } + + /** + * Initialize at start of action controller + * + * Reset the view script suffix to the original state, or store the + * original state. + * + * @return void + */ + public function init() + { + if (null === $this->_viewSuffixOrig) { + $this->_viewSuffixOrig = $this->_getViewRenderer()->getViewSuffix(); + } else { + $this->_getViewRenderer()->setViewSuffix($this->_viewSuffixOrig); + } + } + + /** + * Configure object from array of options + * + * @param array $options + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setOptions(array $options) + { + if (isset($options['contexts'])) { + $this->setContexts($options['contexts']); + unset($options['contexts']); + } + + foreach ($options as $key => $value) { + $method = 'set' . ucfirst($key); + if (in_array($method, $this->_unconfigurable)) { + continue; + } + + if (in_array($method, $this->_specialConfig)) { + $method = '_' . $method; + } + + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Set object state from config object + * + * @param Zend_Config $config + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config->toArray()); + } + + /** + * Strategy pattern: return object + * + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function direct() + { + return $this; + } + + /** + * Initialize context detection and switching + * + * @param mixed $format + * @throws Zend_Controller_Action_Exception + * @return void + */ + public function initContext($format = null) + { + $this->_currentContext = null; + + $controller = $this->getActionController(); + $request = $this->getRequest(); + $action = $request->getActionName(); + + // Return if no context switching enabled, or no context switching + // enabled for this action + $contexts = $this->getActionContexts($action); + if (empty($contexts)) { + return; + } + + // Return if no context parameter provided + if (!$context = $request->getParam($this->getContextParam())) { + if ($format === null) { + return; + } + $context = $format; + $format = null; + } + + // Check if context allowed by action controller + if (!$this->hasActionContext($action, $context)) { + return; + } + + // Return if invalid context parameter provided and no format or invalid + // format provided + if (!$this->hasContext($context)) { + if (empty($format) || !$this->hasContext($format)) { + + return; + } + } + + // Use provided format if passed + if (!empty($format) && $this->hasContext($format)) { + $context = $format; + } + + $suffix = $this->getSuffix($context); + + $this->_getViewRenderer()->setViewSuffix($suffix); + + $headers = $this->getHeaders($context); + if (!empty($headers)) { + $response = $this->getResponse(); + foreach ($headers as $header => $content) { + $response->setHeader($header, $content); + } + } + + if ($this->getAutoDisableLayout()) { + /** + * @see Zend_Layout + */ + $layout = Zend_Layout::getMvcInstance(); + if (null !== $layout) { + $layout->disableLayout(); + } + } + + if (null !== ($callback = $this->getCallback($context, self::TRIGGER_INIT))) { + if (is_string($callback) && method_exists($this, $callback)) { + $this->$callback(); + } elseif (is_string($callback) && function_exists($callback)) { + $callback(); + } elseif (is_array($callback)) { + call_user_func($callback); + } else { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Invalid context callback registered for context "%s"', $context)); + } + } + + $this->_currentContext = $context; + } + + /** + * JSON context extra initialization + * + * Turns off viewRenderer auto-rendering + * + * @return void + */ + public function initJsonContext() + { + if (!$this->getAutoJsonSerialization()) { + return; + } + + $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + $view = $viewRenderer->view; + if ($view instanceof Zend_View_Interface) { + $viewRenderer->setNoRender(true); + } + } + + /** + * Should JSON contexts auto-serialize? + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setAutoJsonSerialization($flag) + { + $this->_autoJsonSerialization = (bool) $flag; + return $this; + } + + /** + * Get JSON context auto-serialization flag + * + * @return boolean + */ + public function getAutoJsonSerialization() + { + return $this->_autoJsonSerialization; + } + + /** + * Set suffix from array + * + * @param array $spec + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + protected function _setSuffix(array $spec) + { + foreach ($spec as $context => $suffixInfo) { + if (!is_string($context)) { + $context = null; + } + + if (is_string($suffixInfo)) { + $this->setSuffix($context, $suffixInfo); + continue; + } elseif (is_array($suffixInfo)) { + if (isset($suffixInfo['suffix'])) { + $suffix = $suffixInfo['suffix']; + $prependViewRendererSuffix = true; + + if ((null === $context) && isset($suffixInfo['context'])) { + $context = $suffixInfo['context']; + } + + if (isset($suffixInfo['prependViewRendererSuffix'])) { + $prependViewRendererSuffix = $suffixInfo['prependViewRendererSuffix']; + } + + $this->setSuffix($context, $suffix, $prependViewRendererSuffix); + continue; + } + + $count = count($suffixInfo); + switch (true) { + case (($count < 2) && (null === $context)): + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid suffix information provided in config'); + case ($count < 2): + $suffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix); + break; + case (($count < 3) && (null === $context)): + $context = array_shift($suffixInfo); + $suffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix); + break; + case (($count == 3) && (null === $context)): + $context = array_shift($suffixInfo); + $suffix = array_shift($suffixInfo); + $prependViewRendererSuffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix, $prependViewRendererSuffix); + break; + case ($count >= 2): + $suffix = array_shift($suffixInfo); + $prependViewRendererSuffix = array_shift($suffixInfo); + $this->setSuffix($context, $suffix, $prependViewRendererSuffix); + break; + } + } + } + return $this; + } + + /** + * Customize view script suffix to use when switching context. + * + * Passing an empty suffix value to the setters disables the view script + * suffix change. + * + * @param string $context Context type for which to set suffix + * @param string $suffix Suffix to use + * @param boolean $prependViewRendererSuffix Whether or not to prepend the new suffix to the viewrenderer suffix + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setSuffix($context, $suffix, $prependViewRendererSuffix = true) + { + if (!isset($this->_contexts[$context])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot set suffix; invalid context type "%s"', $context)); + } + + if (empty($suffix)) { + $suffix = ''; + } + + if (is_array($suffix)) { + if (isset($suffix['prependViewRendererSuffix'])) { + $prependViewRendererSuffix = $suffix['prependViewRendererSuffix']; + } + if (isset($suffix['suffix'])) { + $suffix = $suffix['suffix']; + } else { + $suffix = ''; + } + } + + $suffix = (string) $suffix; + + if ($prependViewRendererSuffix) { + if (empty($suffix)) { + $suffix = $this->_getViewRenderer()->getViewSuffix(); + } else { + $suffix .= '.' . $this->_getViewRenderer()->getViewSuffix(); + } + } + + $this->_contexts[$context]['suffix'] = $suffix; + return $this; + } + + /** + * Retrieve suffix for given context type + * + * @param string $type Context type + * @throws Zend_Controller_Action_Exception + * @return string + */ + public function getSuffix($type) + { + if (!isset($this->_contexts[$type])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot retrieve suffix; invalid context type "%s"', $type)); + } + + return $this->_contexts[$type]['suffix']; + } + + /** + * Does the given context exist? + * + * @param string $context + * @param boolean $throwException + * @throws Zend_Controller_Action_Exception if context does not exist and throwException is true + * @return bool + */ + public function hasContext($context, $throwException = false) + { + if (is_string($context)) { + if (isset($this->_contexts[$context])) { + return true; + } + } elseif (is_array($context)) { + $error = false; + foreach ($context as $test) { + if (!isset($this->_contexts[$test])) { + $error = (string) $test; + break; + } + } + if (false === $error) { + return true; + } + $context = $error; + } elseif (true === $context) { + return true; + } + + if ($throwException) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Context "%s" does not exist', $context)); + } + + return false; + } + + /** + * Add header to context + * + * @param string $context + * @param string $header + * @param string $content + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addHeader($context, $header, $content) + { + $context = (string) $context; + $this->hasContext($context, true); + + $header = (string) $header; + $content = (string) $content; + + if (isset($this->_contexts[$context]['headers'][$header])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot add "%s" header to context "%s": already exists', $header, $context)); + } + + $this->_contexts[$context]['headers'][$header] = $content; + return $this; + } + + /** + * Customize response header to use when switching context + * + * Passing an empty header value to the setters disables the response + * header. + * + * @param string $type Context type for which to set suffix + * @param string $header Header to set + * @param string $content Header content + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setHeader($context, $header, $content) + { + $this->hasContext($context, true); + $context = (string) $context; + $header = (string) $header; + $content = (string) $content; + + $this->_contexts[$context]['headers'][$header] = $content; + return $this; + } + + /** + * Add multiple headers at once for a given context + * + * @param string $context + * @param array $headers + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addHeaders($context, array $headers) + { + foreach ($headers as $header => $content) { + $this->addHeader($context, $header, $content); + } + + return $this; + } + + /** + * Set headers from context => headers pairs + * + * @param array $options + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + protected function _setHeaders(array $options) + { + foreach ($options as $context => $headers) { + if (!is_array($headers)) { + continue; + } + $this->setHeaders($context, $headers); + } + + return $this; + } + + /** + * Set multiple headers at once for a given context + * + * @param string $context + * @param array $headers + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setHeaders($context, array $headers) + { + $this->clearHeaders($context); + foreach ($headers as $header => $content) { + $this->setHeader($context, $header, $content); + } + + return $this; + } + + /** + * Retrieve context header + * + * Returns the value of a given header for a given context type + * + * @param string $context + * @param string $header + * @return string|null + */ + public function getHeader($context, $header) + { + $this->hasContext($context, true); + $context = (string) $context; + $header = (string) $header; + if (isset($this->_contexts[$context]['headers'][$header])) { + return $this->_contexts[$context]['headers'][$header]; + } + + return null; + } + + /** + * Retrieve context headers + * + * Returns all headers for a context as key/value pairs + * + * @param string $context + * @return array + */ + public function getHeaders($context) + { + $this->hasContext($context, true); + $context = (string) $context; + return $this->_contexts[$context]['headers']; + } + + /** + * Remove a single header from a context + * + * @param string $context + * @param string $header + * @return boolean + */ + public function removeHeader($context, $header) + { + $this->hasContext($context, true); + $context = (string) $context; + $header = (string) $header; + if (isset($this->_contexts[$context]['headers'][$header])) { + unset($this->_contexts[$context]['headers'][$header]); + return true; + } + + return false; + } + + /** + * Clear all headers for a given context + * + * @param string $context + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearHeaders($context) + { + $this->hasContext($context, true); + $context = (string) $context; + $this->_contexts[$context]['headers'] = array(); + return $this; + } + + /** + * Validate trigger and return in normalized form + * + * @param string $trigger + * @throws Zend_Controller_Action_Exception + * @return string + */ + protected function _validateTrigger($trigger) + { + $trigger = strtoupper($trigger); + if ('TRIGGER_' !== substr($trigger, 0, 8)) { + $trigger = 'TRIGGER_' . $trigger; + } + + if (!in_array($trigger, array(self::TRIGGER_INIT, self::TRIGGER_POST))) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Invalid trigger "%s"', $trigger)); + } + + return $trigger; + } + + /** + * Set a callback for a given context and trigger + * + * @param string $context + * @param string $trigger + * @param string|array $callback + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setCallback($context, $trigger, $callback) + { + $this->hasContext($context, true); + $trigger = $this->_validateTrigger($trigger); + + if (!is_string($callback)) { + if (!is_array($callback) || (2 != count($callback))) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('Invalid callback specified'); + } + } + + $this->_contexts[$context]['callbacks'][$trigger] = $callback; + return $this; + } + + /** + * Set callbacks from array of context => callbacks pairs + * + * @param array $options + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + protected function _setCallbacks(array $options) + { + foreach ($options as $context => $callbacks) { + if (!is_array($callbacks)) { + continue; + } + + $this->setCallbacks($context, $callbacks); + } + return $this; + } + + /** + * Set callbacks for a given context + * + * Callbacks should be in trigger/callback pairs. + * + * @param string $context + * @param array $callbacks + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setCallbacks($context, array $callbacks) + { + $this->hasContext($context, true); + $context = (string) $context; + if (!isset($this->_contexts[$context]['callbacks'])) { + $this->_contexts[$context]['callbacks'] = array(); + } + + foreach ($callbacks as $trigger => $callback) { + $this->setCallback($context, $trigger, $callback); + } + return $this; + } + + /** + * Get a single callback for a given context and trigger + * + * @param string $context + * @param string $trigger + * @return string|array|null + */ + public function getCallback($context, $trigger) + { + $this->hasContext($context, true); + $trigger = $this->_validateTrigger($trigger); + if (isset($this->_contexts[$context]['callbacks'][$trigger])) { + return $this->_contexts[$context]['callbacks'][$trigger]; + } + + return null; + } + + /** + * Get all callbacks for a given context + * + * @param string $context + * @return array + */ + public function getCallbacks($context) + { + $this->hasContext($context, true); + return $this->_contexts[$context]['callbacks']; + } + + /** + * Clear a callback for a given context and trigger + * + * @param string $context + * @param string $trigger + * @return boolean + */ + public function removeCallback($context, $trigger) + { + $this->hasContext($context, true); + $trigger = $this->_validateTrigger($trigger); + if (isset($this->_contexts[$context]['callbacks'][$trigger])) { + unset($this->_contexts[$context]['callbacks'][$trigger]); + return true; + } + + return false; + } + + /** + * Clear all callbacks for a given context + * + * @param string $context + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearCallbacks($context) + { + $this->hasContext($context, true); + $this->_contexts[$context]['callbacks'] = array(); + return $this; + } + + /** + * Set name of parameter to use when determining context format + * + * @param string $name + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setContextParam($name) + { + $this->_contextParam = (string) $name; + return $this; + } + + /** + * Return context format request parameter name + * + * @return string + */ + public function getContextParam() + { + return $this->_contextParam; + } + + /** + * Indicate default context to use when no context format provided + * + * @param string $type + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setDefaultContext($type) + { + if (!isset($this->_contexts[$type])) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot set default context; invalid context type "%s"', $type)); + } + + $this->_defaultContext = $type; + return $this; + } + + /** + * Return default context + * + * @return string + */ + public function getDefaultContext() + { + return $this->_defaultContext; + } + + /** + * Set flag indicating if layout should be disabled + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setAutoDisableLayout($flag) + { + $this->_disableLayout = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve auto layout disable flag + * + * @return boolean + */ + public function getAutoDisableLayout() + { + return $this->_disableLayout; + } + + /** + * Add new context + * + * @param string $context Context type + * @param array $spec Context specification + * @throws Zend_Controller_Action_Exception + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addContext($context, array $spec) + { + if ($this->hasContext($context)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Cannot add context "%s"; already exists', $context)); + } + $context = (string) $context; + + $this->_contexts[$context] = array(); + + $this->setSuffix($context, (isset($spec['suffix']) ? $spec['suffix'] : '')) + ->setHeaders($context, (isset($spec['headers']) ? $spec['headers'] : array())) + ->setCallbacks($context, (isset($spec['callbacks']) ? $spec['callbacks'] : array())); + return $this; + } + + /** + * Overwrite existing context + * + * @param string $context Context type + * @param array $spec Context specification + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setContext($context, array $spec) + { + $this->removeContext($context); + return $this->addContext($context, $spec); + } + + /** + * Add multiple contexts + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addContexts(array $contexts) + { + foreach ($contexts as $context => $spec) { + $this->addContext($context, $spec); + } + return $this; + } + + /** + * Set multiple contexts, after first removing all + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setContexts(array $contexts) + { + $this->clearContexts(); + foreach ($contexts as $context => $spec) { + $this->addContext($context, $spec); + } + return $this; + } + + /** + * Retrieve context specification + * + * @param string $context + * @return array|null + */ + public function getContext($context) + { + if ($this->hasContext($context)) { + return $this->_contexts[(string) $context]; + } + return null; + } + + /** + * Retrieve context definitions + * + * @return array + */ + public function getContexts() + { + return $this->_contexts; + } + + /** + * Remove a context + * + * @param string $context + * @return boolean + */ + public function removeContext($context) + { + if ($this->hasContext($context)) { + unset($this->_contexts[(string) $context]); + return true; + } + return false; + } + + /** + * Remove all contexts + * + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearContexts() + { + $this->_contexts = array(); + return $this; + } + + /** + * Return current context, if any + * + * @return null|string + */ + public function getCurrentContext() + { + return $this->_currentContext; + } + + /** + * Post dispatch processing + * + * Execute postDispatch callback for current context, if available + * + * @throws Zend_Controller_Action_Exception + * @return void + */ + public function postDispatch() + { + $context = $this->getCurrentContext(); + if (null !== $context) { + if (null !== ($callback = $this->getCallback($context, self::TRIGGER_POST))) { + if (is_string($callback) && method_exists($this, $callback)) { + $this->$callback(); + } elseif (is_string($callback) && function_exists($callback)) { + $callback(); + } elseif (is_array($callback)) { + call_user_func($callback); + } else { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf('Invalid postDispatch context callback registered for context "%s"', $context)); + } + } + } + } + + /** + * JSON post processing + * + * JSON serialize view variables to response body + * + * @return void + */ + public function postJsonContext() + { + if (!$this->getAutoJsonSerialization()) { + return; + } + + $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + $view = $viewRenderer->view; + if ($view instanceof Zend_View_Interface) { + /** + * @see Zend_Json + */ + if(method_exists($view, 'getVars')) { + $vars = Zend_Json::encode($view->getVars()); + $this->getResponse()->setBody($vars); + } else { + throw new Zend_Controller_Action_Exception('View does not implement the getVars() method needed to encode the view into JSON'); + } + } + } + + /** + * Add one or more contexts to an action + * + * @param string $action + * @param string|array $context + * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface + */ + public function addActionContext($action, $context) + { + $this->hasContext($context, true); + $controller = $this->getActionController(); + if (null === $controller) { + return; + } + $action = (string) $action; + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey)) { + $controller->$contextKey = array(); + } + + if (true === $context) { + $contexts = $this->getContexts(); + $controller->{$contextKey}[$action] = array_keys($contexts); + return $this; + } + + $context = (array) $context; + if (!isset($controller->{$contextKey}[$action])) { + $controller->{$contextKey}[$action] = $context; + } else { + $controller->{$contextKey}[$action] = array_merge( + $controller->{$contextKey}[$action], + $context + ); + } + + return $this; + } + + /** + * Set a context as available for a given controller action + * + * @param string $action + * @param string|array $context + * @return Zend_Controller_Action_Helper_ContextSwitch|void Provides a fluent interface + */ + public function setActionContext($action, $context) + { + $this->hasContext($context, true); + $controller = $this->getActionController(); + if (null === $controller) { + return; + } + $action = (string) $action; + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey)) { + $controller->$contextKey = array(); + } + + if (true === $context) { + $contexts = $this->getContexts(); + $controller->{$contextKey}[$action] = array_keys($contexts); + } else { + $controller->{$contextKey}[$action] = (array) $context; + } + + return $this; + } + + /** + * Add multiple action/context pairs at once + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function addActionContexts(array $contexts) + { + foreach ($contexts as $action => $context) { + $this->addActionContext($action, $context); + } + return $this; + } + + /** + * Overwrite and set multiple action contexts at once + * + * @param array $contexts + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function setActionContexts(array $contexts) + { + foreach ($contexts as $action => $context) { + $this->setActionContext($action, $context); + } + return $this; + } + + /** + * Does a particular controller action have the given context(s)? + * + * @param string $action + * @param string|array $context + * @throws Zend_Controller_Action_Exception + * @return boolean + */ + public function hasActionContext($action, $context) + { + $this->hasContext($context, true); + $controller = $this->getActionController(); + if (null === $controller) { + return false; + } + $action = (string) $action; + $contextKey = $this->_contextKey; + + if (!isset($controller->{$contextKey})) { + return false; + } + + $allContexts = $controller->{$contextKey}; + + if (!is_array($allContexts)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception("Invalid contexts found for controller"); + } + + if (!isset($allContexts[$action])) { + return false; + } + + if (true === $allContexts[$action]) { + return true; + } + + $contexts = $allContexts[$action]; + + if (!is_array($contexts)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception(sprintf("Invalid contexts found for action '%s'", $action)); + } + + if (is_string($context) && in_array($context, $contexts)) { + return true; + } elseif (is_array($context)) { + $found = true; + foreach ($context as $test) { + if (!in_array($test, $contexts)) { + $found = false; + break; + } + } + return $found; + } + + return false; + } + + /** + * Get contexts for a given action or all actions in the controller + * + * @param string $action + * @return array + */ + public function getActionContexts($action = null) + { + $controller = $this->getActionController(); + if (null === $controller) { + return array(); + } + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey)) { + return array(); + } + + if (null !== $action) { + $action = (string) $action; + if (isset($controller->{$contextKey}[$action])) { + return $controller->{$contextKey}[$action]; + } else { + return array(); + } + } + + return $controller->$contextKey; + } + + /** + * Remove one or more contexts for a given controller action + * + * @param string $action + * @param string|array $context + * @return boolean + */ + public function removeActionContext($action, $context) + { + if ($this->hasActionContext($action, $context)) { + $controller = $this->getActionController(); + $contextKey = $this->_contextKey; + $action = (string) $action; + $contexts = $controller->$contextKey; + $actionContexts = $contexts[$action]; + $contexts = (array) $context; + foreach ($contexts as $context) { + $index = array_search($context, $actionContexts); + if (false !== $index) { + unset($controller->{$contextKey}[$action][$index]); + } + } + return true; + } + return false; + } + + /** + * Clear all contexts for a given controller action or all actions + * + * @param string $action + * @return Zend_Controller_Action_Helper_ContextSwitch Provides a fluent interface + */ + public function clearActionContexts($action = null) + { + $controller = $this->getActionController(); + $contextKey = $this->_contextKey; + + if (!isset($controller->$contextKey) || empty($controller->$contextKey)) { + return $this; + } + + if (null === $action) { + $controller->$contextKey = array(); + return $this; + } + + $action = (string) $action; + if (isset($controller->{$contextKey}[$action])) { + unset($controller->{$contextKey}[$action]); + } + + return $this; + } + + /** + * Retrieve ViewRenderer + * + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + protected function _getViewRenderer() + { + if (null === $this->_viewRenderer) { + $this->_viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + } + + return $this->_viewRenderer; + } +} + diff --git a/library/vendor/Zend/Controller/Action/Helper/FlashMessenger.php b/library/vendor/Zend/Controller/Action/Helper/FlashMessenger.php new file mode 100644 index 000000000..a630f2873 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/FlashMessenger.php @@ -0,0 +1,311 @@ +getName()); + foreach (self::$_session as $namespace => $messages) { + self::$_messages[$namespace] = $messages; + unset(self::$_session->{$namespace}); + } + } + } + + /** + * postDispatch() - runs after action is dispatched, in this + * case, it is resetting the namespace in case we have forwarded to a different + * action, Flashmessage will be 'clean' (default namespace) + * + * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface + */ + public function postDispatch() + { + $this->resetNamespace(); + return $this; + } + + /** + * setNamespace() - change the namespace messages are added to, useful for + * per action controller messaging between requests + * + * @param string $namespace + * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface + */ + public function setNamespace($namespace = 'default') + { + $this->_namespace = $namespace; + return $this; + } + + /** + * getNamespace() - return the current namepsace + * + * @return string + */ + public function getNamespace() + { + return $this->_namespace; + } + + /** + * resetNamespace() - reset the namespace to the default + * + * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface + */ + public function resetNamespace() + { + $this->setNamespace(); + return $this; + } + + /** + * addMessage() - Add a message to flash message + * + * @param string $message + * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface + */ + public function addMessage($message, $namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if (self::$_messageAdded === false) { + self::$_session->setExpirationHops(1, null, true); + } + + if (!is_array(self::$_session->{$namespace})) { + self::$_session->{$namespace} = array(); + } + + self::$_session->{$namespace}[] = $message; + self::$_messageAdded = true; + + return $this; + } + + /** + * hasMessages() - Wether a specific namespace has messages + * + * @return boolean + */ + public function hasMessages($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + return isset(self::$_messages[$namespace]); + } + + /** + * getMessages() - Get messages from a specific namespace + * + * @return array + */ + public function getMessages($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if ($this->hasMessages($namespace)) { + return self::$_messages[$namespace]; + } + + return array(); + } + + /** + * Clear all messages from the previous request & current namespace + * + * @return boolean True if messages were cleared, false if none existed + */ + public function clearMessages($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if ($this->hasMessages($namespace)) { + unset(self::$_messages[$namespace]); + return true; + } + + return false; + } + + /** + * hasCurrentMessages() - check to see if messages have been added to current + * namespace within this request + * + * @return boolean + */ + public function hasCurrentMessages($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + return isset(self::$_session->{$namespace}); + } + + /** + * getCurrentMessages() - get messages that have been added to the current + * namespace within this request + * + * @return array + */ + public function getCurrentMessages($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if ($this->hasCurrentMessages($namespace)) { + return self::$_session->{$namespace}; + } + + return array(); + } + + /** + * clear messages from the current request & current namespace + * + * @return boolean + */ + public function clearCurrentMessages($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if ($this->hasCurrentMessages($namespace)) { + unset(self::$_session->{$namespace}); + return true; + } + + return false; + } + + /** + * getIterator() - complete the IteratorAggregate interface, for iterating + * + * @return ArrayObject + */ + public function getIterator($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if ($this->hasMessages($namespace)) { + return new ArrayObject($this->getMessages($namespace)); + } + + return new ArrayObject(); + } + + /** + * count() - Complete the countable interface + * + * @return int + */ + public function count($namespace = null) + { + if (!is_string($namespace) || $namespace == '') { + $namespace = $this->getNamespace(); + } + + if ($this->hasMessages($namespace)) { + return count($this->getMessages($namespace)); + } + + return 0; + } + + /** + * Strategy pattern: proxy to addMessage() + * + * @param string $message + * @return void + */ + public function direct($message, $namespace=NULL) + { + return $this->addMessage($message, $namespace); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Json.php b/library/vendor/Zend/Controller/Action/Helper/Json.php new file mode 100644 index 000000000..32f5da930 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Json.php @@ -0,0 +1,130 @@ +true|false + * if $keepLayouts and parmas for Zend_Json::encode are required + * then, the array can contains a 'keepLayout'=>true|false and/or 'encodeData'=>true|false + * that will not be passed to Zend_Json::encode method but will be passed + * to Zend_View_Helper_Json + * @throws Zend_Controller_Action_Helper_Json + * @return string + */ + public function encodeJson($data, $keepLayouts = false, $encodeData = true) + { + /** + * @see Zend_View_Helper_Json + */ + $jsonHelper = new Zend_View_Helper_Json(); + $data = $jsonHelper->json($data, $keepLayouts, $encodeData); + + if (!$keepLayouts) { + /** + * @see Zend_Controller_Action_HelperBroker + */ + Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->setNoRender(true); + } + + return $data; + } + + /** + * Encode JSON response and immediately send + * + * @param mixed $data + * @param boolean|array $keepLayouts + * @param $encodeData Encode $data as JSON? + * NOTE: if boolean, establish $keepLayouts to true|false + * if array, admit params for Zend_Json::encode as enableJsonExprFinder=>true|false + * if $keepLayouts and parmas for Zend_Json::encode are required + * then, the array can contains a 'keepLayout'=>true|false and/or 'encodeData'=>true|false + * that will not be passed to Zend_Json::encode method but will be passed + * to Zend_View_Helper_Json + * @return string|void + */ + public function sendJson($data, $keepLayouts = false, $encodeData = true) + { + $data = $this->encodeJson($data, $keepLayouts, $encodeData); + $response = $this->getResponse(); + $response->setBody($data); + + if (!$this->suppressExit) { + $response->sendResponse(); + exit; + } + + return $data; + } + + /** + * Strategy pattern: call helper as helper broker method + * + * Allows encoding JSON. If $sendNow is true, immediately sends JSON + * response. + * + * @param mixed $data + * @param boolean $sendNow + * @param boolean $keepLayouts + * @param boolean $encodeData Encode $data as JSON? + * @return string|void + */ + public function direct($data, $sendNow = true, $keepLayouts = false, $encodeData = true) + { + if ($sendNow) { + return $this->sendJson($data, $keepLayouts, $encodeData); + } + return $this->encodeJson($data, $keepLayouts, $encodeData); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Redirector.php b/library/vendor/Zend/Controller/Action/Helper/Redirector.php new file mode 100644 index 000000000..1a3c6d78f --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Redirector.php @@ -0,0 +1,531 @@ +_code; + } + + /** + * Validate HTTP status redirect code + * + * @param int $code + * @throws Zend_Controller_Action_Exception on invalid HTTP status code + * @return true + */ + protected function _checkCode($code) + { + $code = (int)$code; + if ((300 > $code) || (307 < $code) || (304 == $code) || (306 == $code)) { + throw new Zend_Controller_Action_Exception('Invalid redirect HTTP status code (' . $code . ')'); + } + + return true; + } + + /** + * Set HTTP status code for {@link _redirect()} behaviour + * + * @param int $code + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setCode($code) + { + $this->_checkCode($code); + $this->_code = $code; + return $this; + } + + /** + * Retrieve flag for whether or not {@link _redirect()} will exit when finished. + * + * @return boolean + */ + public function getExit() + { + return $this->_exit; + } + + /** + * Set exit flag for {@link _redirect()} behaviour + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setExit($flag) + { + $this->_exit = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve flag for whether or not {@link _redirect()} will prepend the + * base URL on relative URLs + * + * @return boolean + */ + public function getPrependBase() + { + return $this->_prependBase; + } + + /** + * Set 'prepend base' flag for {@link _redirect()} behaviour + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setPrependBase($flag) + { + $this->_prependBase = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve flag for whether or not {@link redirectAndExit()} shall close the session before + * exiting. + * + * @return boolean + */ + public function getCloseSessionOnExit() + { + return $this->_closeSessionOnExit; + } + + /** + * Set flag for whether or not {@link redirectAndExit()} shall close the session before exiting. + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setCloseSessionOnExit($flag) + { + $this->_closeSessionOnExit = ($flag) ? true : false; + return $this; + } + + /** + * Return use absolute URI flag + * + * @return boolean + */ + public function getUseAbsoluteUri() + { + return $this->_useAbsoluteUri; + } + + /** + * Set use absolute URI flag + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface + */ + public function setUseAbsoluteUri($flag = true) + { + $this->_useAbsoluteUri = ($flag) ? true : false; + return $this; + } + + /** + * Set redirect in response object + * + * @return void + */ + protected function _redirect($url) + { + if ($this->getUseAbsoluteUri() && !preg_match('#^(https?|ftp)://#', $url)) { + $host = (isset($_SERVER['HTTP_HOST'])?$_SERVER['HTTP_HOST']:''); + $proto = (isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=="off") ? 'https' : 'http'; + $port = (isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:80); + $uri = $proto . '://' . $host; + if ((('http' == $proto) && (80 != $port)) || (('https' == $proto) && (443 != $port))) { + // do not append if HTTP_HOST already contains port + if (strrchr($host, ':') === false) { + $uri .= ':' . $port; + } + } + $url = $uri . '/' . ltrim($url, '/'); + } + $this->_redirectUrl = $url; + $this->getResponse()->setRedirect($url, $this->getCode()); + } + + /** + * Retrieve currently set URL for redirect + * + * @return string + */ + public function getRedirectUrl() + { + return $this->_redirectUrl; + } + + /** + * Determine if the baseUrl should be prepended, and prepend if necessary + * + * @param string $url + * @return string + */ + protected function _prependBase($url) + { + if ($this->getPrependBase()) { + $request = $this->getRequest(); + if ($request instanceof Zend_Controller_Request_Http) { + $base = rtrim($request->getBaseUrl(), '/'); + if (!empty($base) && ('/' != $base)) { + $url = $base . '/' . ltrim($url, '/'); + } else { + $url = '/' . ltrim($url, '/'); + } + } + } + + return $url; + } + + /** + * Set a redirect URL of the form /module/controller/action/params + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + public function setGotoSimple($action, $controller = null, $module = null, array $params = array()) + { + $dispatcher = $this->getFrontController()->getDispatcher(); + $request = $this->getRequest(); + $curModule = $request->getModuleName(); + $useDefaultController = false; + + if (null === $controller && null !== $module) { + $useDefaultController = true; + } + + if (null === $module) { + $module = $curModule; + } + + if ($module == $dispatcher->getDefaultModule()) { + $module = ''; + } + + if (null === $controller && !$useDefaultController) { + $controller = $request->getControllerName(); + if (empty($controller)) { + $controller = $dispatcher->getDefaultControllerName(); + } + } + + $params[$request->getModuleKey()] = $module; + $params[$request->getControllerKey()] = $controller; + $params[$request->getActionKey()] = $action; + + $router = $this->getFrontController()->getRouter(); + $url = $router->assemble($params, 'default', true); + + $this->_redirect($url); + } + + /** + * Build a URL based on a route + * + * @param array $urlOptions + * @param string $name Route name + * @param boolean $reset + * @param boolean $encode + * @return void + */ + public function setGotoRoute(array $urlOptions = array(), $name = null, $reset = false, $encode = true) + { + $router = $this->getFrontController()->getRouter(); + $url = $router->assemble($urlOptions, $name, $reset, $encode); + + $this->_redirect($url); + } + + /** + * Set a redirect URL string + * + * By default, emits a 302 HTTP status header, prepends base URL as defined + * in request object if url is relative, and halts script execution by + * calling exit(). + * + * $options is an optional associative array that can be used to control + * redirect behaviour. The available option keys are: + * - exit: boolean flag indicating whether or not to halt script execution when done + * - prependBase: boolean flag indicating whether or not to prepend the base URL when a relative URL is provided + * - code: integer HTTP status code to use with redirect. Should be between 300 and 307. + * + * _redirect() sets the Location header in the response object. If you set + * the exit flag to false, you can override this header later in code + * execution. + * + * If the exit flag is true (true by default), _redirect() will write and + * close the current session, if any. + * + * @param string $url + * @param array $options + * @return void + */ + public function setGotoUrl($url, array $options = array()) + { + // prevent header injections + $url = str_replace(array("\n", "\r"), '', $url); + + if (null !== $options) { + if (isset($options['exit'])) { + $this->setExit(($options['exit']) ? true : false); + } + if (isset($options['prependBase'])) { + $this->setPrependBase(($options['prependBase']) ? true : false); + } + if (isset($options['code'])) { + $this->setCode($options['code']); + } + } + + // If relative URL, decide if we should prepend base URL + if (!preg_match('|^[a-z]+://|', $url)) { + $url = $this->_prependBase($url); + } + + $this->_redirect($url); + } + + /** + * Perform a redirect to an action/controller/module with params + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + public function gotoSimple($action, $controller = null, $module = null, array $params = array()) + { + $this->setGotoSimple($action, $controller, $module, $params); + + if ($this->getExit()) { + $this->redirectAndExit(); + } + } + + /** + * Perform a redirect to an action/controller/module with params, forcing an immdiate exit + * + * @param mixed $action + * @param mixed $controller + * @param mixed $module + * @param array $params + * @return void + */ + public function gotoSimpleAndExit($action, $controller = null, $module = null, array $params = array()) + { + $this->setGotoSimple($action, $controller, $module, $params); + $this->redirectAndExit(); + } + + /** + * Redirect to a route-based URL + * + * Uses route's assemble method tobuild the URL; route is specified by $name; + * default route is used if none provided. + * + * @param array $urlOptions Array of key/value pairs used to assemble URL + * @param string $name + * @param boolean $reset + * @param boolean $encode + * @return void + */ + public function gotoRoute(array $urlOptions = array(), $name = null, $reset = false, $encode = true) + { + $this->setGotoRoute($urlOptions, $name, $reset, $encode); + + if ($this->getExit()) { + $this->redirectAndExit(); + } + } + + /** + * Redirect to a route-based URL, and immediately exit + * + * Uses route's assemble method tobuild the URL; route is specified by $name; + * default route is used if none provided. + * + * @param array $urlOptions Array of key/value pairs used to assemble URL + * @param string $name + * @param boolean $reset + * @return void + */ + public function gotoRouteAndExit(array $urlOptions = array(), $name = null, $reset = false) + { + $this->setGotoRoute($urlOptions, $name, $reset); + $this->redirectAndExit(); + } + + /** + * Perform a redirect to a url + * + * @param string $url + * @param array $options + * @return void + */ + public function gotoUrl($url, array $options = array()) + { + $this->setGotoUrl($url, $options); + + if ($this->getExit()) { + $this->redirectAndExit(); + } + } + + /** + * Set a URL string for a redirect, perform redirect, and immediately exit + * + * @param string $url + * @param array $options + * @return void + */ + public function gotoUrlAndExit($url, array $options = array()) + { + $this->setGotoUrl($url, $options); + $this->redirectAndExit(); + } + + /** + * exit(): Perform exit for redirector + * + * @return void + */ + public function redirectAndExit() + { + if ($this->getCloseSessionOnExit()) { + // Close session, if started + if (class_exists('Zend_Session', false) && Zend_Session::isStarted()) { + Zend_Session::writeClose(); + } elseif (isset($_SESSION)) { + session_write_close(); + } + } + + $this->getResponse()->sendHeaders(); + exit(); + } + + /** + * direct(): Perform helper when called as + * $this->_helper->redirector($action, $controller, $module, $params) + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return void + */ + public function direct($action, $controller = null, $module = null, array $params = array()) + { + $this->gotoSimple($action, $controller, $module, $params); + } + + /** + * Overloading + * + * Overloading for old 'goto', 'setGoto', and 'gotoAndExit' methods + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Controller_Action_Exception for invalid methods + */ + public function __call($method, $args) + { + $method = strtolower($method); + if ('goto' == $method) { + return call_user_func_array(array($this, 'gotoSimple'), $args); + } + if ('setgoto' == $method) { + return call_user_func_array(array($this, 'setGotoSimple'), $args); + } + if ('gotoandexit' == $method) { + return call_user_func_array(array($this, 'gotoSimpleAndExit'), $args); + } + + throw new Zend_Controller_Action_Exception(sprintf('Invalid method "%s" called on redirector', $method)); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/Url.php b/library/vendor/Zend/Controller/Action/Helper/Url.php new file mode 100644 index 000000000..c6aafe0c9 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/Url.php @@ -0,0 +1,116 @@ +getRequest(); + + if (null === $controller) { + $controller = $request->getControllerName(); + } + + if (null === $module) { + $module = $request->getModuleName(); + } + + $url = $controller . '/' . $action; + if ($module != $this->getFrontController()->getDispatcher()->getDefaultModule()) { + $url = $module . '/' . $url; + } + + if ('' !== ($baseUrl = $this->getFrontController()->getBaseUrl())) { + $url = $baseUrl . '/' . $url; + } + + if (null !== $params) { + $paramPairs = array(); + foreach ($params as $key => $value) { + $paramPairs[] = urlencode($key) . '/' . urlencode($value); + } + $paramString = implode('/', $paramPairs); + $url .= '/' . $paramString; + } + + $url = '/' . ltrim($url, '/'); + + return $url; + } + + /** + * Assembles a URL based on a given route + * + * This method will typically be used for more complex operations, as it + * ties into the route objects registered with the router. + * + * @param array $urlOptions Options passed to the assemble method of the Route object. + * @param mixed $name The name of a Route to use. If null it will use the current Route + * @param boolean $reset + * @param boolean $encode + * @return string Url for the link href attribute. + */ + public function url($urlOptions = array(), $name = null, $reset = false, $encode = true) + { + $router = $this->getFrontController()->getRouter(); + return $router->assemble($urlOptions, $name, $reset, $encode); + } + + /** + * Perform helper when called as $this->_helper->url() from an action controller + * + * Proxies to {@link simple()} + * + * @param string $action + * @param string $controller + * @param string $module + * @param array $params + * @return string + */ + public function direct($action, $controller = null, $module = null, array $params = null) + { + return $this->simple($action, $controller, $module, $params); + } +} diff --git a/library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php b/library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php new file mode 100644 index 000000000..0e3fc3237 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Helper/ViewRenderer.php @@ -0,0 +1,985 @@ + + * // In your bootstrap: + * Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_ViewRenderer()); + * + * // In your action controller methods: + * $viewHelper = $this->_helper->getHelper('view'); + * + * // Don't use controller subdirectories + * $viewHelper->setNoController(true); + * + * // Specify a different script to render: + * $this->_helper->viewRenderer('form'); + * + * + * + * @uses Zend_Controller_Action_Helper_Abstract + * @package Zend_Controller + * @subpackage Zend_Controller_Action_Helper + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Controller_Action_Helper_ViewRenderer extends Zend_Controller_Action_Helper_Abstract +{ + /** + * @var Zend_View_Interface + */ + public $view; + + /** + * Word delimiters + * @var array + */ + protected $_delimiters; + + /** + * @var Zend_Filter_Inflector + */ + protected $_inflector; + + /** + * Inflector target + * @var string + */ + protected $_inflectorTarget = ''; + + /** + * Current module directory + * @var string + */ + protected $_moduleDir = ''; + + /** + * Whether or not to autorender using controller name as subdirectory; + * global setting (not reset at next invocation) + * @var boolean + */ + protected $_neverController = false; + + /** + * Whether or not to autorender postDispatch; global setting (not reset at + * next invocation) + * @var boolean + */ + protected $_neverRender = false; + + /** + * Whether or not to use a controller name as a subdirectory when rendering + * @var boolean + */ + protected $_noController = false; + + /** + * Whether or not to autorender postDispatch; per controller/action setting (reset + * at next invocation) + * @var boolean + */ + protected $_noRender = false; + + /** + * Characters representing path delimiters in the controller + * @var string|array + */ + protected $_pathDelimiters; + + /** + * Which named segment of the response to utilize + * @var string + */ + protected $_responseSegment = null; + + /** + * Which action view script to render + * @var string + */ + protected $_scriptAction = null; + + /** + * View object basePath + * @var string + */ + protected $_viewBasePathSpec = ':moduleDir/views'; + + /** + * View script path specification string + * @var string + */ + protected $_viewScriptPathSpec = ':controller/:action.:suffix'; + + /** + * View script path specification string, minus controller segment + * @var string + */ + protected $_viewScriptPathNoControllerSpec = ':action.:suffix'; + + /** + * View script suffix + * @var string + */ + protected $_viewSuffix = 'phtml'; + + /** + * Constructor + * + * Optionally set view object and options. + * + * @param Zend_View_Interface $view + * @param array $options + * @return void + */ + public function __construct(Zend_View_Interface $view = null, array $options = array()) + { + if (null !== $view) { + $this->setView($view); + } + + if (!empty($options)) { + $this->_setOptions($options); + } + } + + /** + * Clone - also make sure the view is cloned. + * + * @return void + */ + public function __clone() + { + if (isset($this->view) && $this->view instanceof Zend_View_Interface) { + $this->view = clone $this->view; + + } + } + + /** + * Set the view object + * + * @param Zend_View_Interface $view + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setView(Zend_View_Interface $view) + { + $this->view = $view; + return $this; + } + + /** + * Get current module name + * + * @return string + */ + public function getModule() + { + $request = $this->getRequest(); + $module = $request->getModuleName(); + if (null === $module) { + $module = $this->getFrontController()->getDispatcher()->getDefaultModule(); + } + + return $module; + } + + /** + * Get module directory + * + * @throws Zend_Controller_Action_Exception + * @return string + */ + public function getModuleDirectory() + { + $module = $this->getModule(); + $moduleDir = $this->getFrontController()->getControllerDirectory($module); + if ((null === $moduleDir) || is_array($moduleDir)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('ViewRenderer cannot locate module directory for module "' . $module . '"'); + } + $this->_moduleDir = dirname($moduleDir); + return $this->_moduleDir; + } + + /** + * Get inflector + * + * @return Zend_Filter_Inflector + */ + public function getInflector() + { + if (null === $this->_inflector) { + /** + * @see Zend_Filter_Inflector + */ + /** + * @see Zend_Filter_PregReplace + */ + /** + * @see Zend_Filter_Word_UnderscoreToSeparator + */ + $this->_inflector = new Zend_Filter_Inflector(); + $this->_inflector->setStaticRuleReference('moduleDir', $this->_moduleDir) // moduleDir must be specified before the less specific 'module' + ->addRules(array( + ':module' => array('Word_CamelCaseToDash', 'StringToLower'), + ':controller' => array('Word_CamelCaseToDash', new Zend_Filter_Word_UnderscoreToSeparator('/'), 'StringToLower', new Zend_Filter_PregReplace('/\./', '-')), + ':action' => array('Word_CamelCaseToDash', new Zend_Filter_PregReplace('#[^a-z0-9' . preg_quote('/', '#') . ']+#i', '-'), 'StringToLower'), + )) + ->setStaticRuleReference('suffix', $this->_viewSuffix) + ->setTargetReference($this->_inflectorTarget); + } + + // Ensure that module directory is current + $this->getModuleDirectory(); + + return $this->_inflector; + } + + /** + * Set inflector + * + * @param Zend_Filter_Inflector $inflector + * @param boolean $reference Whether the moduleDir, target, and suffix should be set as references to ViewRenderer properties + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setInflector(Zend_Filter_Inflector $inflector, $reference = false) + { + $this->_inflector = $inflector; + if ($reference) { + $this->_inflector->setStaticRuleReference('suffix', $this->_viewSuffix) + ->setStaticRuleReference('moduleDir', $this->_moduleDir) + ->setTargetReference($this->_inflectorTarget); + } + return $this; + } + + /** + * Set inflector target + * + * @param string $target + * @return void + */ + protected function _setInflectorTarget($target) + { + $this->_inflectorTarget = (string) $target; + } + + /** + * Set internal module directory representation + * + * @param string $dir + * @return void + */ + protected function _setModuleDir($dir) + { + $this->_moduleDir = (string) $dir; + } + + /** + * Get internal module directory representation + * + * @return string + */ + protected function _getModuleDir() + { + return $this->_moduleDir; + } + + /** + * Generate a class prefix for helper and filter classes + * + * @return string + */ + protected function _generateDefaultPrefix() + { + $default = 'Zend_View'; + if (null === $this->_actionController) { + return $default; + } + + $class = get_class($this->_actionController); + + if (!strstr($class, '_')) { + return $default; + } + + $module = $this->getModule(); + if ('default' == $module) { + return $default; + } + + $prefix = substr($class, 0, strpos($class, '_')) . '_View'; + + return $prefix; + } + + /** + * Retrieve base path based on location of current action controller + * + * @return string + */ + protected function _getBasePath() + { + if (null === $this->_actionController) { + return './views'; + } + + $inflector = $this->getInflector(); + $this->_setInflectorTarget($this->getViewBasePathSpec()); + + $dispatcher = $this->getFrontController()->getDispatcher(); + $request = $this->getRequest(); + + $parts = array( + 'module' => (($moduleName = $request->getModuleName()) != '') ? $dispatcher->formatModuleName($moduleName) : $moduleName, + 'controller' => $request->getControllerName(), + 'action' => $dispatcher->formatActionName($request->getActionName()) + ); + + $path = $inflector->filter($parts); + return $path; + } + + /** + * Set options + * + * @param array $options + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + protected function _setOptions(array $options) + { + foreach ($options as $key => $value) + { + switch ($key) { + case 'neverRender': + case 'neverController': + case 'noController': + case 'noRender': + $property = '_' . $key; + $this->{$property} = ($value) ? true : false; + break; + case 'responseSegment': + case 'scriptAction': + case 'viewBasePathSpec': + case 'viewScriptPathSpec': + case 'viewScriptPathNoControllerSpec': + case 'viewSuffix': + $property = '_' . $key; + $this->{$property} = (string) $value; + break; + default: + break; + } + } + + return $this; + } + + /** + * Initialize the view object + * + * $options may contain the following keys: + * - neverRender - flag dis/enabling postDispatch() autorender (affects all subsequent calls) + * - noController - flag indicating whether or not to look for view scripts in subdirectories named after the controller + * - noRender - flag indicating whether or not to autorender postDispatch() + * - responseSegment - which named response segment to render a view script to + * - scriptAction - what action script to render + * - viewBasePathSpec - specification to use for determining view base path + * - viewScriptPathSpec - specification to use for determining view script paths + * - viewScriptPathNoControllerSpec - specification to use for determining view script paths when noController flag is set + * - viewSuffix - what view script filename suffix to use + * + * @param string $path + * @param string $prefix + * @param array $options + * @throws Zend_Controller_Action_Exception + * @return void + */ + public function initView($path = null, $prefix = null, array $options = array()) + { + if (null === $this->view) { + $this->setView(new Zend_View()); + } + + // Reset some flags every time + $options['noController'] = (isset($options['noController'])) ? $options['noController'] : false; + $options['noRender'] = (isset($options['noRender'])) ? $options['noRender'] : false; + $this->_scriptAction = null; + $this->_responseSegment = null; + + // Set options first; may be used to determine other initializations + $this->_setOptions($options); + + // Get base view path + if (empty($path)) { + $path = $this->_getBasePath(); + if (empty($path)) { + /** + * @see Zend_Controller_Action_Exception + */ + throw new Zend_Controller_Action_Exception('ViewRenderer initialization failed: retrieved view base path is empty'); + } + } + + if (null === $prefix) { + $prefix = $this->_generateDefaultPrefix(); + } + + // Determine if this path has already been registered + $currentPaths = $this->view->getScriptPaths(); + $path = str_replace(array('/', '\\'), '/', $path); + $pathExists = false; + foreach ($currentPaths as $tmpPath) { + $tmpPath = str_replace(array('/', '\\'), '/', $tmpPath); + if (strstr($tmpPath, $path)) { + $pathExists = true; + break; + } + } + if (!$pathExists) { + $this->view->addBasePath($path, $prefix); + } + + // Register view with action controller (unless already registered) + if ((null !== $this->_actionController) && (null === $this->_actionController->view)) { + $this->_actionController->view = $this->view; + $this->_actionController->viewSuffix = $this->_viewSuffix; + } + } + + /** + * init - initialize view + * + * @return void + */ + public function init() + { + if ($this->getFrontController()->getParam('noViewRenderer')) { + return; + } + + $this->initView(); + } + + /** + * Set view basePath specification + * + * Specification can contain one or more of the following: + * - :moduleDir - current module directory + * - :controller - name of current controller in the request + * - :action - name of current action in the request + * - :module - name of current module in the request + * + * @param string $path + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewBasePathSpec($path) + { + $this->_viewBasePathSpec = (string) $path; + return $this; + } + + /** + * Retrieve the current view basePath specification string + * + * @return string + */ + public function getViewBasePathSpec() + { + return $this->_viewBasePathSpec; + } + + /** + * Set view script path specification + * + * Specification can contain one or more of the following: + * - :moduleDir - current module directory + * - :controller - name of current controller in the request + * - :action - name of current action in the request + * - :module - name of current module in the request + * + * @param string $path + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewScriptPathSpec($path) + { + $this->_viewScriptPathSpec = (string) $path; + return $this; + } + + /** + * Retrieve the current view script path specification string + * + * @return string + */ + public function getViewScriptPathSpec() + { + return $this->_viewScriptPathSpec; + } + + /** + * Set view script path specification (no controller variant) + * + * Specification can contain one or more of the following: + * - :moduleDir - current module directory + * - :controller - name of current controller in the request + * - :action - name of current action in the request + * - :module - name of current module in the request + * + * :controller will likely be ignored in this variant. + * + * @param string $path + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewScriptPathNoControllerSpec($path) + { + $this->_viewScriptPathNoControllerSpec = (string) $path; + return $this; + } + + /** + * Retrieve the current view script path specification string (no controller variant) + * + * @return string + */ + public function getViewScriptPathNoControllerSpec() + { + return $this->_viewScriptPathNoControllerSpec; + } + + /** + * Get a view script based on an action and/or other variables + * + * Uses values found in current request if no values passed in $vars. + * + * If {@link $_noController} is set, uses {@link $_viewScriptPathNoControllerSpec}; + * otherwise, uses {@link $_viewScriptPathSpec}. + * + * @param string $action + * @param array $vars + * @return string + */ + public function getViewScript($action = null, array $vars = array()) + { + $request = $this->getRequest(); + if ((null === $action) && (!isset($vars['action']))) { + $action = $this->getScriptAction(); + if (null === $action) { + $action = $request->getActionName(); + } + $vars['action'] = $action; + } elseif (null !== $action) { + $vars['action'] = $action; + } + + $replacePattern = array('/[^a-z0-9]+$/i', '/^[^a-z0-9]+/i'); + $vars['action'] = preg_replace($replacePattern, '', $vars['action']); + + $inflector = $this->getInflector(); + if ($this->getNoController() || $this->getNeverController()) { + $this->_setInflectorTarget($this->getViewScriptPathNoControllerSpec()); + } else { + $this->_setInflectorTarget($this->getViewScriptPathSpec()); + } + return $this->_translateSpec($vars); + } + + /** + * Set the neverRender flag (i.e., globally dis/enable autorendering) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNeverRender($flag = true) + { + $this->_neverRender = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve neverRender flag value + * + * @return boolean + */ + public function getNeverRender() + { + return $this->_neverRender; + } + + /** + * Set the noRender flag (i.e., whether or not to autorender) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNoRender($flag = true) + { + $this->_noRender = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve noRender flag value + * + * @return boolean + */ + public function getNoRender() + { + return $this->_noRender; + } + + /** + * Set the view script to use + * + * @param string $name + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setScriptAction($name) + { + $this->_scriptAction = (string) $name; + return $this; + } + + /** + * Retrieve view script name + * + * @return string + */ + public function getScriptAction() + { + return $this->_scriptAction; + } + + /** + * Set the response segment name + * + * @param string $name + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setResponseSegment($name) + { + if (null === $name) { + $this->_responseSegment = null; + } else { + $this->_responseSegment = (string) $name; + } + + return $this; + } + + /** + * Retrieve named response segment name + * + * @return string + */ + public function getResponseSegment() + { + return $this->_responseSegment; + } + + /** + * Set the noController flag (i.e., whether or not to render into controller subdirectories) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNoController($flag = true) + { + $this->_noController = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve noController flag value + * + * @return boolean + */ + public function getNoController() + { + return $this->_noController; + } + + /** + * Set the neverController flag (i.e., whether or not to render into controller subdirectories) + * + * @param boolean $flag + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setNeverController($flag = true) + { + $this->_neverController = ($flag) ? true : false; + return $this; + } + + /** + * Retrieve neverController flag value + * + * @return boolean + */ + public function getNeverController() + { + return $this->_neverController; + } + + /** + * Set view script suffix + * + * @param string $suffix + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setViewSuffix($suffix) + { + $this->_viewSuffix = (string) $suffix; + return $this; + } + + /** + * Get view script suffix + * + * @return string + */ + public function getViewSuffix() + { + return $this->_viewSuffix; + } + + /** + * Set options for rendering a view script + * + * @param string $action View script to render + * @param string $name Response named segment to render to + * @param boolean $noController Whether or not to render within a subdirectory named after the controller + * @return Zend_Controller_Action_Helper_ViewRenderer Provides a fluent interface + */ + public function setRender($action = null, $name = null, $noController = null) + { + if (null !== $action) { + $this->setScriptAction($action); + } + + if (null !== $name) { + $this->setResponseSegment($name); + } + + if (null !== $noController) { + $this->setNoController($noController); + } + + return $this; + } + + /** + * Inflect based on provided vars + * + * Allowed variables are: + * - :moduleDir - current module directory + * - :module - current module name + * - :controller - current controller name + * - :action - current action name + * - :suffix - view script file suffix + * + * @param array $vars + * @return string + */ + protected function _translateSpec(array $vars = array()) + { + $inflector = $this->getInflector(); + $request = $this->getRequest(); + $dispatcher = $this->getFrontController()->getDispatcher(); + $module = $dispatcher->formatModuleName($request->getModuleName()); + $controller = $request->getControllerName(); + $action = $dispatcher->formatActionName($request->getActionName()); + + $params = compact('module', 'controller', 'action'); + foreach ($vars as $key => $value) { + switch ($key) { + case 'module': + case 'controller': + case 'action': + case 'moduleDir': + case 'suffix': + $params[$key] = (string) $value; + break; + default: + break; + } + } + + if (isset($params['suffix'])) { + $origSuffix = $this->getViewSuffix(); + $this->setViewSuffix($params['suffix']); + } + if (isset($params['moduleDir'])) { + $origModuleDir = $this->_getModuleDir(); + $this->_setModuleDir($params['moduleDir']); + } + + $filtered = $inflector->filter($params); + + if (isset($params['suffix'])) { + $this->setViewSuffix($origSuffix); + } + if (isset($params['moduleDir'])) { + $this->_setModuleDir($origModuleDir); + } + + return $filtered; + } + + /** + * Render a view script (optionally to a named response segment) + * + * Sets the noRender flag to true when called. + * + * @param string $script + * @param string $name + * @return void + */ + public function renderScript($script, $name = null) + { + if (null === $name) { + $name = $this->getResponseSegment(); + } + + $this->getResponse()->appendBody( + $this->view->render($script), + $name + ); + + $this->setNoRender(); + } + + /** + * Render a view based on path specifications + * + * Renders a view based on the view script path specifications. + * + * @param string $action + * @param string $name + * @param boolean $noController + * @return void + */ + public function render($action = null, $name = null, $noController = null) + { + $this->setRender($action, $name, $noController); + $path = $this->getViewScript(); + $this->renderScript($path, $name); + } + + /** + * Render a script based on specification variables + * + * Pass an action, and one or more specification variables (view script suffix) + * to determine the view script path, and render that script. + * + * @param string $action + * @param array $vars + * @param string $name + * @return void + */ + public function renderBySpec($action = null, array $vars = array(), $name = null) + { + if (null !== $name) { + $this->setResponseSegment($name); + } + + $path = $this->getViewScript($action, $vars); + + $this->renderScript($path); + } + + /** + * postDispatch - auto render a view + * + * Only autorenders if: + * - _noRender is false + * - action controller is present + * - request has not been re-dispatched (i.e., _forward() has not been called) + * - response is not a redirect + * + * @return void + */ + public function postDispatch() + { + if ($this->_shouldRender()) { + $this->render(); + } + } + + /** + * Should the ViewRenderer render a view script? + * + * @return boolean + */ + protected function _shouldRender() + { + return (!$this->getFrontController()->getParam('noViewRenderer') + && !$this->_neverRender + && !$this->_noRender + && (null !== $this->_actionController) + && $this->getRequest()->isDispatched() + && !$this->getResponse()->isRedirect() + ); + } + + /** + * Use this helper as a method; proxies to setRender() + * + * @param string $action + * @param string $name + * @param boolean $noController + * @return void + */ + public function direct($action = null, $name = null, $noController = null) + { + $this->setRender($action, $name, $noController); + } +} diff --git a/library/vendor/Zend/Controller/Action/HelperBroker.php b/library/vendor/Zend/Controller/Action/HelperBroker.php new file mode 100644 index 000000000..40fabe372 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/HelperBroker.php @@ -0,0 +1,373 @@ + 'Zend/Controller/Action/Helper/', + )); + } + return self::$_pluginLoader; + } + + /** + * addPrefix() - Add repository of helpers by prefix + * + * @param string $prefix + */ + static public function addPrefix($prefix) + { + $prefix = rtrim($prefix, '_'); + $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix); + self::getPluginLoader()->addPrefixPath($prefix, $path); + } + + /** + * addPath() - Add path to repositories where Action_Helpers could be found. + * + * @param string $path + * @param string $prefix Optional; defaults to 'Zend_Controller_Action_Helper' + * @return void + */ + static public function addPath($path, $prefix = 'Zend_Controller_Action_Helper') + { + self::getPluginLoader()->addPrefixPath($prefix, $path); + } + + /** + * addHelper() - Add helper objects + * + * @param Zend_Controller_Action_Helper_Abstract $helper + * @return void + */ + static public function addHelper(Zend_Controller_Action_Helper_Abstract $helper) + { + self::getStack()->push($helper); + return; + } + + /** + * resetHelpers() + * + * @return void + */ + static public function resetHelpers() + { + self::$_stack = null; + return; + } + + /** + * Retrieve or initialize a helper statically + * + * Retrieves a helper object statically, loading on-demand if the helper + * does not already exist in the stack. Always returns a helper, unless + * the helper class cannot be found. + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + */ + public static function getStaticHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + + if (!isset($stack->{$name})) { + self::_loadHelper($name); + } + + return $stack->{$name}; + } + + /** + * getExistingHelper() - get helper by name + * + * Static method to retrieve helper object. Only retrieves helpers already + * initialized with the broker (either via addHelper() or on-demand loading + * via getHelper()). + * + * Throws an exception if the referenced helper does not exist in the + * stack; use {@link hasHelper()} to check if the helper is registered + * prior to retrieving it. + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + * @throws Zend_Controller_Action_Exception + */ + public static function getExistingHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + + if (!isset($stack->{$name})) { + throw new Zend_Controller_Action_Exception('Action helper "' . $name . '" has not been registered with the helper broker'); + } + + return $stack->{$name}; + } + + /** + * Return all registered helpers as helper => object pairs + * + * @return array + */ + public static function getExistingHelpers() + { + return self::getStack()->getHelpersByName(); + } + + /** + * Is a particular helper loaded in the broker? + * + * @param string $name + * @return boolean + */ + public static function hasHelper($name) + { + $name = self::_normalizeHelperName($name); + return isset(self::getStack()->{$name}); + } + + /** + * Remove a particular helper from the broker + * + * @param string $name + * @return boolean + */ + public static function removeHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + if (isset($stack->{$name})) { + unset($stack->{$name}); + } + + return false; + } + + /** + * Lazy load the priority stack and return it + * + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public static function getStack() + { + if (self::$_stack == null) { + self::$_stack = new Zend_Controller_Action_HelperBroker_PriorityStack(); + } + + return self::$_stack; + } + + /** + * Constructor + * + * @param Zend_Controller_Action $actionController + * @return void + */ + public function __construct(Zend_Controller_Action $actionController) + { + $this->_actionController = $actionController; + foreach (self::getStack() as $helper) { + $helper->setActionController($actionController); + $helper->init(); + } + } + + /** + * notifyPreDispatch() - called by action controller dispatch method + * + * @return void + */ + public function notifyPreDispatch() + { + foreach (self::getStack() as $helper) { + $helper->preDispatch(); + } + } + + /** + * notifyPostDispatch() - called by action controller dispatch method + * + * @return void + */ + public function notifyPostDispatch() + { + foreach (self::getStack() as $helper) { + $helper->postDispatch(); + } + } + + /** + * getHelper() - get helper by name + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function getHelper($name) + { + $name = self::_normalizeHelperName($name); + $stack = self::getStack(); + + if (!isset($stack->{$name})) { + self::_loadHelper($name); + } + + $helper = $stack->{$name}; + + $initialize = false; + if (null === ($actionController = $helper->getActionController())) { + $initialize = true; + } elseif ($actionController !== $this->_actionController) { + $initialize = true; + } + + if ($initialize) { + $helper->setActionController($this->_actionController) + ->init(); + } + + return $helper; + } + + /** + * Method overloading + * + * @param string $method + * @param array $args + * @return mixed + * @throws Zend_Controller_Action_Exception if helper does not have a direct() method + */ + public function __call($method, $args) + { + $helper = $this->getHelper($method); + if (!method_exists($helper, 'direct')) { + throw new Zend_Controller_Action_Exception('Helper "' . $method . '" does not support overloading via direct()'); + } + return call_user_func_array(array($helper, 'direct'), $args); + } + + /** + * Retrieve helper by name as object property + * + * @param string $name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function __get($name) + { + return $this->getHelper($name); + } + + /** + * Normalize helper name for lookups + * + * @param string $name + * @return string + */ + protected static function _normalizeHelperName($name) + { + if (strpos($name, '_') !== false) { + $name = str_replace(' ', '', ucwords(str_replace('_', ' ', $name))); + } + + return ucfirst($name); + } + + /** + * Load a helper + * + * @param string $name + * @return void + */ + protected static function _loadHelper($name) + { + try { + $class = self::getPluginLoader()->load($name); + } catch (Zend_Loader_PluginLoader_Exception $e) { + throw new Zend_Controller_Action_Exception('Action Helper by name ' . $name . ' not found', 0, $e); + } + + $helper = new $class(); + + if (!$helper instanceof Zend_Controller_Action_Helper_Abstract) { + throw new Zend_Controller_Action_Exception('Helper name ' . $name . ' -> class ' . $class . ' is not of type Zend_Controller_Action_Helper_Abstract'); + } + + self::getStack()->push($helper); + } +} diff --git a/library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php b/library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php new file mode 100644 index 000000000..7f7f6bc15 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/HelperBroker/PriorityStack.php @@ -0,0 +1,277 @@ +_helpersByNameRef)) { + return false; + } + + return $this->_helpersByNameRef[$helperName]; + } + + /** + * Magic property overloading for returning if helper is set by name + * + * @param string $helperName The helper name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function __isset($helperName) + { + return array_key_exists($helperName, $this->_helpersByNameRef); + } + + /** + * Magic property overloading for unsetting if helper is exists by name + * + * @param string $helperName The helper name + * @return Zend_Controller_Action_Helper_Abstract + */ + public function __unset($helperName) + { + return $this->offsetUnset($helperName); + } + + /** + * push helper onto the stack + * + * @param Zend_Controller_Action_Helper_Abstract $helper + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public function push(Zend_Controller_Action_Helper_Abstract $helper) + { + $this->offsetSet($this->getNextFreeHigherPriority(), $helper); + return $this; + } + + /** + * Return something iterable + * + * @return array + */ + public function getIterator() + { + return new ArrayObject($this->_helpersByPriority); + } + + /** + * offsetExists() + * + * @param int|string $priorityOrHelperName + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public function offsetExists($priorityOrHelperName) + { + if (is_string($priorityOrHelperName)) { + return array_key_exists($priorityOrHelperName, $this->_helpersByNameRef); + } else { + return array_key_exists($priorityOrHelperName, $this->_helpersByPriority); + } + } + + /** + * offsetGet() + * + * @param int|string $priorityOrHelperName + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public function offsetGet($priorityOrHelperName) + { + if (!$this->offsetExists($priorityOrHelperName)) { + throw new Zend_Controller_Action_Exception('A helper with priority ' . $priorityOrHelperName . ' does not exist.'); + } + + if (is_string($priorityOrHelperName)) { + return $this->_helpersByNameRef[$priorityOrHelperName]; + } else { + return $this->_helpersByPriority[$priorityOrHelperName]; + } + } + + /** + * offsetSet() + * + * @param int $priority + * @param Zend_Controller_Action_Helper_Abstract $helper + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public function offsetSet($priority, $helper) + { + $priority = (int) $priority; + + if (!$helper instanceof Zend_Controller_Action_Helper_Abstract) { + throw new Zend_Controller_Action_Exception('$helper must extend Zend_Controller_Action_Helper_Abstract.'); + } + + if (array_key_exists($helper->getName(), $this->_helpersByNameRef)) { + // remove any object with the same name to retain BC compailitbility + // @todo At ZF 2.0 time throw an exception here. + $this->offsetUnset($helper->getName()); + } + + if (array_key_exists($priority, $this->_helpersByPriority)) { + $priority = $this->getNextFreeHigherPriority($priority); // ensures LIFO + trigger_error("A helper with the same priority already exists, reassigning to $priority", E_USER_WARNING); + } + + $this->_helpersByPriority[$priority] = $helper; + $this->_helpersByNameRef[$helper->getName()] = $helper; + + if ($priority == ($nextFreeDefault = $this->getNextFreeHigherPriority($this->_nextDefaultPriority))) { + $this->_nextDefaultPriority = $nextFreeDefault; + } + + krsort($this->_helpersByPriority); // always make sure priority and LIFO are both enforced + return $this; + } + + /** + * offsetUnset() + * + * @param int|string $priorityOrHelperName Priority integer or the helper name + * @return Zend_Controller_Action_HelperBroker_PriorityStack + */ + public function offsetUnset($priorityOrHelperName) + { + if (!$this->offsetExists($priorityOrHelperName)) { + throw new Zend_Controller_Action_Exception('A helper with priority or name ' . $priorityOrHelperName . ' does not exist.'); + } + + if (is_string($priorityOrHelperName)) { + $helperName = $priorityOrHelperName; + $helper = $this->_helpersByNameRef[$helperName]; + $priority = array_search($helper, $this->_helpersByPriority, true); + } else { + $priority = $priorityOrHelperName; + $helperName = $this->_helpersByPriority[$priorityOrHelperName]->getName(); + } + + unset($this->_helpersByNameRef[$helperName]); + unset($this->_helpersByPriority[$priority]); + return $this; + } + + /** + * return the count of helpers + * + * @return int + */ + public function count() + { + return count($this->_helpersByPriority); + } + + /** + * Find the next free higher priority. If an index is given, it will + * find the next free highest priority after it. + * + * @param int $indexPriority OPTIONAL + * @return int + */ + public function getNextFreeHigherPriority($indexPriority = null) + { + if ($indexPriority == null) { + $indexPriority = $this->_nextDefaultPriority; + } + + $priorities = array_keys($this->_helpersByPriority); + + while (in_array($indexPriority, $priorities)) { + $indexPriority++; + } + + return $indexPriority; + } + + /** + * Find the next free lower priority. If an index is given, it will + * find the next free lower priority before it. + * + * @param int $indexPriority + * @return int + */ + public function getNextFreeLowerPriority($indexPriority = null) + { + if ($indexPriority == null) { + $indexPriority = $this->_nextDefaultPriority; + } + + $priorities = array_keys($this->_helpersByPriority); + + while (in_array($indexPriority, $priorities)) { + $indexPriority--; + } + + return $indexPriority; + } + + /** + * return the highest priority + * + * @return int + */ + public function getHighestPriority() + { + return max(array_keys($this->_helpersByPriority)); + } + + /** + * return the lowest priority + * + * @return int + */ + public function getLowestPriority() + { + return min(array_keys($this->_helpersByPriority)); + } + + /** + * return the helpers referenced by name + * + * @return array + */ + public function getHelpersByName() + { + return $this->_helpersByNameRef; + } + +} diff --git a/library/vendor/Zend/Controller/Action/Interface.php b/library/vendor/Zend/Controller/Action/Interface.php new file mode 100644 index 000000000..a69cfaca3 --- /dev/null +++ b/library/vendor/Zend/Controller/Action/Interface.php @@ -0,0 +1,69 @@ +setParams($params); + } + + /** + * Formats a string into a controller name. This is used to take a raw + * controller name, such as one stored inside a Zend_Controller_Request_Abstract + * object, and reformat it to a proper class name that a class extending + * Zend_Controller_Action would use. + * + * @param string $unformatted + * @return string + */ + public function formatControllerName($unformatted) + { + return ucfirst($this->_formatName($unformatted)) . 'Controller'; + } + + /** + * Formats a string into an action name. This is used to take a raw + * action name, such as one that would be stored inside a Zend_Controller_Request_Abstract + * object, and reformat into a proper method name that would be found + * inside a class extending Zend_Controller_Action. + * + * @param string $unformatted + * @return string + */ + public function formatActionName($unformatted) + { + $formatted = $this->_formatName($unformatted, true); + return strtolower(substr($formatted, 0, 1)) . substr($formatted, 1) . 'Action'; + } + + /** + * Verify delimiter + * + * Verify a delimiter to use in controllers or actions. May be a single + * string or an array of strings. + * + * @param string|array $spec + * @return array + * @throws Zend_Controller_Dispatcher_Exception with invalid delimiters + */ + public function _verifyDelimiter($spec) + { + if (is_string($spec)) { + return (array) $spec; + } elseif (is_array($spec)) { + $allStrings = true; + foreach ($spec as $delim) { + if (!is_string($delim)) { + $allStrings = false; + break; + } + } + + if (!$allStrings) { + throw new Zend_Controller_Dispatcher_Exception('Word delimiter array must contain only strings'); + } + + return $spec; + } + + throw new Zend_Controller_Dispatcher_Exception('Invalid word delimiter'); + } + + /** + * Retrieve the word delimiter character(s) used in + * controller or action names + * + * @return array + */ + public function getWordDelimiter() + { + return $this->_wordDelimiter; + } + + /** + * Set word delimiter + * + * Set the word delimiter to use in controllers and actions. May be a + * single string or an array of strings. + * + * @param string|array $spec + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setWordDelimiter($spec) + { + $spec = $this->_verifyDelimiter($spec); + $this->_wordDelimiter = $spec; + + return $this; + } + + /** + * Retrieve the path delimiter character(s) used in + * controller names + * + * @return array + */ + public function getPathDelimiter() + { + return $this->_pathDelimiter; + } + + /** + * Set path delimiter + * + * Set the path delimiter to use in controllers. May be a single string or + * an array of strings. + * + * @param string $spec + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setPathDelimiter($spec) + { + if (!is_string($spec)) { + throw new Zend_Controller_Dispatcher_Exception('Invalid path delimiter'); + } + $this->_pathDelimiter = $spec; + + return $this; + } + + /** + * Formats a string from a URI into a PHP-friendly name. + * + * By default, replaces words separated by the word separator character(s) + * with camelCaps. If $isAction is false, it also preserves replaces words + * separated by the path separation character with an underscore, making + * the following word Title cased. All non-alphanumeric characters are + * removed. + * + * @param string $unformatted + * @param boolean $isAction Defaults to false + * @return string + */ + protected function _formatName($unformatted, $isAction = false) + { + // preserve directories + if (!$isAction) { + $segments = explode($this->getPathDelimiter(), $unformatted); + } else { + $segments = (array) $unformatted; + } + + foreach ($segments as $key => $segment) { + $segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment)); + $segment = preg_replace('/[^a-z0-9 ]/', '', $segment); + $segments[$key] = str_replace(' ', '', ucwords($segment)); + } + + return implode('_', $segments); + } + + /** + * Retrieve front controller instance + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + if (null === $this->_frontController) { + $this->_frontController = Zend_Controller_Front::getInstance(); + } + + return $this->_frontController; + } + + /** + * Set front controller instance + * + * @param Zend_Controller_Front $controller + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setFrontController(Zend_Controller_Front $controller) + { + $this->_frontController = $controller; + return $this; + } + + /** + * Add or modify a parameter to use when instantiating an action controller + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setParam($name, $value) + { + $name = (string) $name; + $this->_invokeParams[$name] = $value; + return $this; + } + + /** + * Set parameters to pass to action controller constructors + * + * @param array $params + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setParams(array $params) + { + $this->_invokeParams = array_merge($this->_invokeParams, $params); + return $this; + } + + /** + * Retrieve a single parameter from the controller parameter stack + * + * @param string $name + * @return mixed + */ + public function getParam($name) + { + if(isset($this->_invokeParams[$name])) { + return $this->_invokeParams[$name]; + } + + return null; + } + + /** + * Retrieve action controller instantiation parameters + * + * @return array + */ + public function getParams() + { + return $this->_invokeParams; + } + + /** + * Clear the controller parameter stack + * + * By default, clears all parameters. If a parameter name is given, clears + * only that parameter; if an array of parameter names is provided, clears + * each. + * + * @param null|string|array single key or array of keys for params to clear + * @return Zend_Controller_Dispatcher_Abstract + */ + public function clearParams($name = null) + { + if (null === $name) { + $this->_invokeParams = array(); + } elseif (is_string($name) && isset($this->_invokeParams[$name])) { + unset($this->_invokeParams[$name]); + } elseif (is_array($name)) { + foreach ($name as $key) { + if (is_string($key) && isset($this->_invokeParams[$key])) { + unset($this->_invokeParams[$key]); + } + } + } + + return $this; + } + + /** + * Set response object to pass to action controllers + * + * @param Zend_Controller_Response_Abstract|null $response + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setResponse(Zend_Controller_Response_Abstract $response = null) + { + $this->_response = $response; + return $this; + } + + /** + * Return the registered response object + * + * @return Zend_Controller_Response_Abstract|null + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Set the default controller (minus any formatting) + * + * @param string $controller + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setDefaultControllerName($controller) + { + $this->_defaultController = (string) $controller; + return $this; + } + + /** + * Retrieve the default controller name (minus formatting) + * + * @return string + */ + public function getDefaultControllerName() + { + return $this->_defaultController; + } + + /** + * Set the default action (minus any formatting) + * + * @param string $action + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setDefaultAction($action) + { + $this->_defaultAction = (string) $action; + return $this; + } + + /** + * Retrieve the default action name (minus formatting) + * + * @return string + */ + public function getDefaultAction() + { + return $this->_defaultAction; + } + + /** + * Set the default module + * + * @param string $module + * @return Zend_Controller_Dispatcher_Abstract + */ + public function setDefaultModule($module) + { + $this->_defaultModule = (string) $module; + return $this; + } + + /** + * Retrieve the default module + * + * @return string + */ + public function getDefaultModule() + { + return $this->_defaultModule; + } +} diff --git a/library/vendor/Zend/Controller/Dispatcher/Exception.php b/library/vendor/Zend/Controller/Dispatcher/Exception.php new file mode 100644 index 000000000..88fec2f5b --- /dev/null +++ b/library/vendor/Zend/Controller/Dispatcher/Exception.php @@ -0,0 +1,36 @@ +_curModule = $this->getDefaultModule(); + } + + /** + * Add a single path to the controller directory stack + * + * @param string $path + * @param string $module + * @return Zend_Controller_Dispatcher_Standard + */ + public function addControllerDirectory($path, $module = null) + { + if (null === $module) { + $module = $this->_defaultModule; + } + + $module = (string) $module; + $path = rtrim((string) $path, '/\\'); + + $this->_controllerDirectory[$module] = $path; + return $this; + } + + /** + * Set controller directory + * + * @param array|string $directory + * @return Zend_Controller_Dispatcher_Standard + */ + public function setControllerDirectory($directory, $module = null) + { + $this->_controllerDirectory = array(); + + if (is_string($directory)) { + $this->addControllerDirectory($directory, $module); + } elseif (is_array($directory)) { + foreach ((array) $directory as $module => $path) { + $this->addControllerDirectory($path, $module); + } + } else { + throw new Zend_Controller_Exception('Controller directory spec must be either a string or an array'); + } + + return $this; + } + + /** + * Return the currently set directories for Zend_Controller_Action class + * lookup + * + * If a module is specified, returns just that directory. + * + * @param string $module Module name + * @return array|string Returns array of all directories by default, single + * module directory if module argument provided + */ + public function getControllerDirectory($module = null) + { + if (null === $module) { + return $this->_controllerDirectory; + } + + $module = (string) $module; + if (array_key_exists($module, $this->_controllerDirectory)) { + return $this->_controllerDirectory[$module]; + } + + return null; + } + + /** + * Remove a controller directory by module name + * + * @param string $module + * @return bool + */ + public function removeControllerDirectory($module) + { + $module = (string) $module; + if (array_key_exists($module, $this->_controllerDirectory)) { + unset($this->_controllerDirectory[$module]); + return true; + } + return false; + } + + /** + * Format the module name. + * + * @param string $unformatted + * @return string + */ + public function formatModuleName($unformatted) + { + if (($this->_defaultModule == $unformatted) && !$this->getParam('prefixDefaultModule')) { + return $unformatted; + } + + return ucfirst($this->_formatName($unformatted)); + } + + /** + * Format action class name + * + * @param string $moduleName Name of the current module + * @param string $className Name of the action class + * @return string Formatted class name + */ + public function formatClassName($moduleName, $className) + { + return $this->formatModuleName($moduleName) . '_' . $className; + } + + /** + * Convert a class name to a filename + * + * @param string $class + * @return string + */ + public function classToFilename($class) + { + return str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; + } + + /** + * Returns TRUE if the Zend_Controller_Request_Abstract object can be + * dispatched to a controller. + * + * Use this method wisely. By default, the dispatcher will fall back to the + * default controller (either in the module specified or the global default) + * if a given controller does not exist. This method returning false does + * not necessarily indicate the dispatcher will not still dispatch the call. + * + * @param Zend_Controller_Request_Abstract $action + * @return boolean + */ + public function isDispatchable(Zend_Controller_Request_Abstract $request) + { + $className = $this->getControllerClass($request); + if (!$className) { + return false; + } + + $finalClass = $className; + if (($this->_defaultModule != $this->_curModule) + || $this->getParam('prefixDefaultModule')) + { + $finalClass = $this->formatClassName($this->_curModule, $className); + } + if (class_exists($finalClass, false)) { + return true; + } + + $fileSpec = $this->classToFilename($className); + $dispatchDir = $this->getDispatchDirectory(); + $test = $dispatchDir . DIRECTORY_SEPARATOR . $fileSpec; + return Zend_Loader::isReadable($test); + } + + /** + * Dispatch to a controller/action + * + * By default, if a controller is not dispatchable, dispatch() will throw + * an exception. If you wish to use the default controller instead, set the + * param 'useDefaultControllerAlways' via {@link setParam()}. + * + * @param Zend_Controller_Request_Abstract $request + * @param Zend_Controller_Response_Abstract $response + * @return void + * @throws Zend_Controller_Dispatcher_Exception + */ + public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response) + { + $this->setResponse($response); + + /** + * Get controller class + */ + if (!$this->isDispatchable($request)) { + $controller = $request->getControllerName(); + if (!$this->getParam('useDefaultControllerAlways') && !empty($controller)) { + throw new Zend_Controller_Dispatcher_Exception('Invalid controller specified (' . $request->getControllerName() . ')'); + } + + $className = $this->getDefaultControllerClass($request); + } else { + $className = $this->getControllerClass($request); + if (!$className) { + $className = $this->getDefaultControllerClass($request); + } + } + + /** + * If we're in a module or prefixDefaultModule is on, we must add the module name + * prefix to the contents of $className, as getControllerClass does not do that automatically. + * We must keep a separate variable because modules are not strictly PSR-0: We need the no-module-prefix + * class name to do the class->file mapping, but the full class name to insantiate the controller + */ + $moduleClassName = $className; + if (($this->_defaultModule != $this->_curModule) + || $this->getParam('prefixDefaultModule')) + { + $moduleClassName = $this->formatClassName($this->_curModule, $className); + } + + /** + * Load the controller class file + */ + $className = $this->loadClass($className); + + /** + * Instantiate controller with request, response, and invocation + * arguments; throw exception if it's not an action controller + */ + $controller = new $moduleClassName($request, $this->getResponse(), $this->getParams()); + if (!($controller instanceof Zend_Controller_Action_Interface) && + !($controller instanceof Zend_Controller_Action)) { + throw new Zend_Controller_Dispatcher_Exception( + 'Controller "' . $moduleClassName . '" is not an instance of Zend_Controller_Action_Interface' + ); + } + + /** + * Retrieve the action name + */ + $action = $this->getActionMethod($request); + + /** + * Dispatch the method call + */ + $request->setDispatched(true); + + // by default, buffer output + $disableOb = $this->getParam('disableOutputBuffering'); + $obLevel = ob_get_level(); + if (empty($disableOb)) { + ob_start(); + } + + try { + $controller->dispatch($action); + } catch (Exception $e) { + // Clean output buffer on error + $curObLevel = ob_get_level(); + if ($curObLevel > $obLevel) { + do { + ob_get_clean(); + $curObLevel = ob_get_level(); + } while ($curObLevel > $obLevel); + } + throw $e; + } + + if (empty($disableOb)) { + $content = ob_get_clean(); + $response->appendBody($content); + } + + // Destroy the page controller instance and reflection objects + $controller = null; + } + + /** + * Load a controller class + * + * Attempts to load the controller class file from + * {@link getControllerDirectory()}. If the controller belongs to a + * module, looks for the module prefix to the controller class. + * + * @param string $className + * @return string Class name loaded + * @throws Zend_Controller_Dispatcher_Exception if class not loaded + */ + public function loadClass($className) + { + $finalClass = $className; + if (($this->_defaultModule != $this->_curModule) + || $this->getParam('prefixDefaultModule')) + { + $finalClass = $this->formatClassName($this->_curModule, $className); + } + if (class_exists($finalClass, false)) { + return $finalClass; + } + + $dispatchDir = $this->getDispatchDirectory(); + $loadFile = $dispatchDir . DIRECTORY_SEPARATOR . $this->classToFilename($className); + + if (Zend_Loader::isReadable($loadFile)) { + include_once $loadFile; + } else { + throw new Zend_Controller_Dispatcher_Exception('Cannot load controller class "' . $className . '" from file "' . $loadFile . "'"); + } + + if (!class_exists($finalClass, false)) { + throw new Zend_Controller_Dispatcher_Exception('Invalid controller class ("' . $finalClass . '")'); + } + + return $finalClass; + } + + /** + * Get controller class name + * + * Try request first; if not found, try pulling from request parameter; + * if still not found, fallback to default + * + * @param Zend_Controller_Request_Abstract $request + * @return string|false Returns class name on success + */ + public function getControllerClass(Zend_Controller_Request_Abstract $request) + { + $controllerName = $request->getControllerName(); + if (empty($controllerName)) { + if (!$this->getParam('useDefaultControllerAlways')) { + return false; + } + $controllerName = $this->getDefaultControllerName(); + $request->setControllerName($controllerName); + } + + $className = $this->formatControllerName($controllerName); + + $controllerDirs = $this->getControllerDirectory(); + $module = $request->getModuleName(); + if ($this->isValidModule($module)) { + $this->_curModule = $module; + $this->_curDirectory = $controllerDirs[$module]; + } elseif ($this->isValidModule($this->_defaultModule)) { + $request->setModuleName($this->_defaultModule); + $this->_curModule = $this->_defaultModule; + $this->_curDirectory = $controllerDirs[$this->_defaultModule]; + } else { + throw new Zend_Controller_Exception('No default module defined for this application'); + } + + return $className; + } + + /** + * Determine if a given module is valid + * + * @param string $module + * @return bool + */ + public function isValidModule($module) + { + if (!is_string($module)) { + return false; + } + + $module = strtolower($module); + $controllerDir = $this->getControllerDirectory(); + foreach (array_keys($controllerDir) as $moduleName) { + if ($module == strtolower($moduleName)) { + return true; + } + } + + return false; + } + + /** + * Retrieve default controller class + * + * Determines whether the default controller to use lies within the + * requested module, or if the global default should be used. + * + * By default, will only use the module default unless that controller does + * not exist; if this is the case, it falls back to the default controller + * in the default module. + * + * @param Zend_Controller_Request_Abstract $request + * @return string + */ + public function getDefaultControllerClass(Zend_Controller_Request_Abstract $request) + { + $controller = $this->getDefaultControllerName(); + $default = $this->formatControllerName($controller); + $request->setControllerName($controller) + ->setActionName(null); + + $module = $request->getModuleName(); + $controllerDirs = $this->getControllerDirectory(); + $this->_curModule = $this->_defaultModule; + $this->_curDirectory = $controllerDirs[$this->_defaultModule]; + if ($this->isValidModule($module)) { + $found = false; + if (class_exists($default, false)) { + $found = true; + } else { + $moduleDir = $controllerDirs[$module]; + $fileSpec = $moduleDir . DIRECTORY_SEPARATOR . $this->classToFilename($default); + if (Zend_Loader::isReadable($fileSpec)) { + $found = true; + $this->_curDirectory = $moduleDir; + } + } + if ($found) { + $request->setModuleName($module); + $this->_curModule = $this->formatModuleName($module); + } + } else { + $request->setModuleName($this->_defaultModule); + } + + return $default; + } + + /** + * Return the value of the currently selected dispatch directory (as set by + * {@link getController()}) + * + * @return string + */ + public function getDispatchDirectory() + { + return $this->_curDirectory; + } + + /** + * Determine the action name + * + * First attempt to retrieve from request; then from request params + * using action key; default to default action + * + * Returns formatted action name + * + * @param Zend_Controller_Request_Abstract $request + * @return string + */ + public function getActionMethod(Zend_Controller_Request_Abstract $request) + { + $action = $request->getActionName(); + if (empty($action)) { + $action = $this->getDefaultAction(); + $request->setActionName($action); + } + + return $this->formatActionName($action); + } +} diff --git a/library/vendor/Zend/Controller/Exception.php b/library/vendor/Zend/Controller/Exception.php new file mode 100644 index 000000000..181e2d583 --- /dev/null +++ b/library/vendor/Zend/Controller/Exception.php @@ -0,0 +1,34 @@ +_plugins = new Zend_Controller_Plugin_Broker(); + } + + /** + * Enforce singleton; disallow cloning + * + * @return void + */ + private function __clone() + { + } + + /** + * Singleton instance + * + * @return Zend_Controller_Front + */ + public static function getInstance() + { + if (null === self::$_instance) { + self::$_instance = new self(); + } + + return self::$_instance; + } + + /** + * Resets all object properties of the singleton instance + * + * Primarily used for testing; could be used to chain front controllers. + * + * Also resets action helper broker, clearing all registered helpers. + * + * @return void + */ + public function resetInstance() + { + $reflection = new ReflectionObject($this); + foreach ($reflection->getProperties() as $property) { + $name = $property->getName(); + switch ($name) { + case '_instance': + break; + case '_controllerDir': + case '_invokeParams': + $this->{$name} = array(); + break; + case '_plugins': + $this->{$name} = new Zend_Controller_Plugin_Broker(); + break; + case '_throwExceptions': + case '_returnResponse': + $this->{$name} = false; + break; + case '_moduleControllerDirectoryName': + $this->{$name} = 'controllers'; + break; + default: + $this->{$name} = null; + break; + } + } + Zend_Controller_Action_HelperBroker::resetHelpers(); + } + + /** + * Convenience feature, calls setControllerDirectory()->setRouter()->dispatch() + * + * In PHP 5.1.x, a call to a static method never populates $this -- so run() + * may actually be called after setting up your front controller. + * + * @param string|array $controllerDirectory Path to Zend_Controller_Action + * controller classes or array of such paths + * @return void + * @throws Zend_Controller_Exception if called from an object instance + */ + public static function run($controllerDirectory) + { + self::getInstance() + ->setControllerDirectory($controllerDirectory) + ->dispatch(); + } + + /** + * Add a controller directory to the controller directory stack + * + * If $args is presented and is a string, uses it for the array key mapping + * to the directory specified. + * + * @param string $directory + * @param string $module Optional argument; module with which to associate directory. If none provided, assumes 'default' + * @return Zend_Controller_Front + * @throws Zend_Controller_Exception if directory not found or readable + */ + public function addControllerDirectory($directory, $module = null) + { + $this->getDispatcher()->addControllerDirectory($directory, $module); + return $this; + } + + /** + * Set controller directory + * + * Stores controller directory(ies) in dispatcher. May be an array of + * directories or a string containing a single directory. + * + * @param string|array $directory Path to Zend_Controller_Action controller + * classes or array of such paths + * @param string $module Optional module name to use with string $directory + * @return Zend_Controller_Front + */ + public function setControllerDirectory($directory, $module = null) + { + $this->getDispatcher()->setControllerDirectory($directory, $module); + return $this; + } + + /** + * Retrieve controller directory + * + * Retrieves: + * - Array of all controller directories if no $name passed + * - String path if $name passed and exists as a key in controller directory array + * - null if $name passed but does not exist in controller directory keys + * + * @param string $name Default null + * @return array|string|null + */ + public function getControllerDirectory($name = null) + { + return $this->getDispatcher()->getControllerDirectory($name); + } + + /** + * Remove a controller directory by module name + * + * @param string $module + * @return bool + */ + public function removeControllerDirectory($module) + { + return $this->getDispatcher()->removeControllerDirectory($module); + } + + /** + * Specify a directory as containing modules + * + * Iterates through the directory, adding any subdirectories as modules; + * the subdirectory within each module named after {@link $_moduleControllerDirectoryName} + * will be used as the controller directory path. + * + * @param string $path + * @return Zend_Controller_Front + */ + public function addModuleDirectory($path) + { + try{ + $dir = new DirectoryIterator($path); + } catch(Exception $e) { + throw new Zend_Controller_Exception("Directory $path not readable", 0, $e); + } + foreach ($dir as $file) { + if ($file->isDot() || !$file->isDir()) { + continue; + } + + $module = $file->getFilename(); + + // Don't use SCCS directories as modules + if (preg_match('/^[^a-z]/i', $module) || ('CVS' == $module)) { + continue; + } + + $moduleDir = $file->getPathname() . DIRECTORY_SEPARATOR . $this->getModuleControllerDirectoryName(); + $this->addControllerDirectory($moduleDir, $module); + } + + return $this; + } + + /** + * Return the path to a module directory (but not the controllers directory within) + * + * @param string $module + * @return string|null + */ + public function getModuleDirectory($module = null) + { + if (null === $module) { + $request = $this->getRequest(); + if (null !== $request) { + $module = $this->getRequest()->getModuleName(); + } + if (empty($module)) { + $module = $this->getDispatcher()->getDefaultModule(); + } + } + + $controllerDir = $this->getControllerDirectory($module); + + if ((null === $controllerDir) || !is_string($controllerDir)) { + return null; + } + + return dirname($controllerDir); + } + + /** + * Set the directory name within a module containing controllers + * + * @param string $name + * @return Zend_Controller_Front + */ + public function setModuleControllerDirectoryName($name = 'controllers') + { + $this->_moduleControllerDirectoryName = (string) $name; + + return $this; + } + + /** + * Return the directory name within a module containing controllers + * + * @return string + */ + public function getModuleControllerDirectoryName() + { + return $this->_moduleControllerDirectoryName; + } + + /** + * Set the default controller (unformatted string) + * + * @param string $controller + * @return Zend_Controller_Front + */ + public function setDefaultControllerName($controller) + { + $dispatcher = $this->getDispatcher(); + $dispatcher->setDefaultControllerName($controller); + return $this; + } + + /** + * Retrieve the default controller (unformatted string) + * + * @return string + */ + public function getDefaultControllerName() + { + return $this->getDispatcher()->getDefaultControllerName(); + } + + /** + * Set the default action (unformatted string) + * + * @param string $action + * @return Zend_Controller_Front + */ + public function setDefaultAction($action) + { + $dispatcher = $this->getDispatcher(); + $dispatcher->setDefaultAction($action); + return $this; + } + + /** + * Retrieve the default action (unformatted string) + * + * @return string + */ + public function getDefaultAction() + { + return $this->getDispatcher()->getDefaultAction(); + } + + /** + * Set the default module name + * + * @param string $module + * @return Zend_Controller_Front + */ + public function setDefaultModule($module) + { + $dispatcher = $this->getDispatcher(); + $dispatcher->setDefaultModule($module); + return $this; + } + + /** + * Retrieve the default module + * + * @return string + */ + public function getDefaultModule() + { + return $this->getDispatcher()->getDefaultModule(); + } + + /** + * Set request class/object + * + * Set the request object. The request holds the request environment. + * + * If a class name is provided, it will instantiate it + * + * @param string|Zend_Controller_Request_Abstract $request + * @throws Zend_Controller_Exception if invalid request class + * @return Zend_Controller_Front + */ + public function setRequest($request) + { + if (is_string($request)) { + if (!class_exists($request)) { + Zend_Loader::loadClass($request); + } + $request = new $request(); + } + if (!$request instanceof Zend_Controller_Request_Abstract) { + throw new Zend_Controller_Exception('Invalid request class'); + } + + $this->_request = $request; + + return $this; + } + + /** + * Return the request object. + * + * @return null|Zend_Controller_Request_Abstract + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set router class/object + * + * Set the router object. The router is responsible for mapping + * the request to a controller and action. + * + * If a class name is provided, instantiates router with any parameters + * registered via {@link setParam()} or {@link setParams()}. + * + * @param string|Zend_Controller_Router_Interface $router + * @throws Zend_Controller_Exception if invalid router class + * @return Zend_Controller_Front + */ + public function setRouter($router) + { + if (is_string($router)) { + if (!class_exists($router)) { + Zend_Loader::loadClass($router); + } + $router = new $router(); + } + + if (!$router instanceof Zend_Controller_Router_Interface) { + throw new Zend_Controller_Exception('Invalid router class'); + } + + $router->setFrontController($this); + $this->_router = $router; + + return $this; + } + + /** + * Return the router object. + * + * Instantiates a Zend_Controller_Router_Rewrite object if no router currently set. + * + * @return Zend_Controller_Router_Interface + */ + public function getRouter() + { + if (null == $this->_router) { + $this->setRouter(new Zend_Controller_Router_Rewrite()); + } + + return $this->_router; + } + + /** + * Set the base URL used for requests + * + * Use to set the base URL segment of the REQUEST_URI to use when + * determining PATH_INFO, etc. Examples: + * - /admin + * - /myapp + * - /subdir/index.php + * + * Note that the URL should not include the full URI. Do not use: + * - http://example.com/admin + * - http://example.com/myapp + * - http://example.com/subdir/index.php + * + * If a null value is passed, this can be used as well for autodiscovery (default). + * + * @param string $base + * @return Zend_Controller_Front + * @throws Zend_Controller_Exception for non-string $base + */ + public function setBaseUrl($base = null) + { + if (!is_string($base) && (null !== $base)) { + throw new Zend_Controller_Exception('Rewrite base must be a string'); + } + + $this->_baseUrl = $base; + + if ((null !== ($request = $this->getRequest())) && (method_exists($request, 'setBaseUrl'))) { + $request->setBaseUrl($base); + } + + return $this; + } + + /** + * Retrieve the currently set base URL + * + * @return string + */ + public function getBaseUrl() + { + $request = $this->getRequest(); + if ((null !== $request) && method_exists($request, 'getBaseUrl')) { + return $request->getBaseUrl(); + } + + return $this->_baseUrl; + } + + /** + * Set the dispatcher object. The dispatcher is responsible for + * taking a Zend_Controller_Dispatcher_Token object, instantiating the controller, and + * call the action method of the controller. + * + * @param Zend_Controller_Dispatcher_Interface $dispatcher + * @return Zend_Controller_Front + */ + public function setDispatcher(Zend_Controller_Dispatcher_Interface $dispatcher) + { + $this->_dispatcher = $dispatcher; + return $this; + } + + /** + * Return the dispatcher object. + * + * @return Zend_Controller_Dispatcher_Interface + */ + public function getDispatcher() + { + /** + * Instantiate the default dispatcher if one was not set. + */ + if (!$this->_dispatcher instanceof Zend_Controller_Dispatcher_Interface) { + $this->_dispatcher = new Zend_Controller_Dispatcher_Standard(); + } + return $this->_dispatcher; + } + + /** + * Set response class/object + * + * Set the response object. The response is a container for action + * responses and headers. Usage is optional. + * + * If a class name is provided, instantiates a response object. + * + * @param string|Zend_Controller_Response_Abstract $response + * @throws Zend_Controller_Exception if invalid response class + * @return Zend_Controller_Front + */ + public function setResponse($response) + { + if (is_string($response)) { + if (!class_exists($response)) { + Zend_Loader::loadClass($response); + } + $response = new $response(); + } + if (!$response instanceof Zend_Controller_Response_Abstract) { + throw new Zend_Controller_Exception('Invalid response class'); + } + + $this->_response = $response; + + return $this; + } + + /** + * Return the response object. + * + * @return null|Zend_Controller_Response_Abstract + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Add or modify a parameter to use when instantiating an action controller + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Front + */ + public function setParam($name, $value) + { + $name = (string) $name; + $this->_invokeParams[$name] = $value; + return $this; + } + + /** + * Set parameters to pass to action controller constructors + * + * @param array $params + * @return Zend_Controller_Front + */ + public function setParams(array $params) + { + $this->_invokeParams = array_merge($this->_invokeParams, $params); + return $this; + } + + /** + * Retrieve a single parameter from the controller parameter stack + * + * @param string $name + * @return mixed + */ + public function getParam($name) + { + if(isset($this->_invokeParams[$name])) { + return $this->_invokeParams[$name]; + } + + return null; + } + + /** + * Retrieve action controller instantiation parameters + * + * @return array + */ + public function getParams() + { + return $this->_invokeParams; + } + + /** + * Clear the controller parameter stack + * + * By default, clears all parameters. If a parameter name is given, clears + * only that parameter; if an array of parameter names is provided, clears + * each. + * + * @param null|string|array single key or array of keys for params to clear + * @return Zend_Controller_Front + */ + public function clearParams($name = null) + { + if (null === $name) { + $this->_invokeParams = array(); + } elseif (is_string($name) && isset($this->_invokeParams[$name])) { + unset($this->_invokeParams[$name]); + } elseif (is_array($name)) { + foreach ($name as $key) { + if (is_string($key) && isset($this->_invokeParams[$key])) { + unset($this->_invokeParams[$key]); + } + } + } + + return $this; + } + + /** + * Register a plugin. + * + * @param Zend_Controller_Plugin_Abstract $plugin + * @param int $stackIndex Optional; stack index for plugin + * @return Zend_Controller_Front + */ + public function registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null) + { + $this->_plugins->registerPlugin($plugin, $stackIndex); + return $this; + } + + /** + * Unregister a plugin. + * + * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin class or object to unregister + * @return Zend_Controller_Front + */ + public function unregisterPlugin($plugin) + { + $this->_plugins->unregisterPlugin($plugin); + return $this; + } + + /** + * Is a particular plugin registered? + * + * @param string $class + * @return bool + */ + public function hasPlugin($class) + { + return $this->_plugins->hasPlugin($class); + } + + /** + * Retrieve a plugin or plugins by class + * + * @param string $class + * @return false|Zend_Controller_Plugin_Abstract|array + */ + public function getPlugin($class) + { + return $this->_plugins->getPlugin($class); + } + + /** + * Retrieve all plugins + * + * @return array + */ + public function getPlugins() + { + return $this->_plugins->getPlugins(); + } + + /** + * Set the throwExceptions flag and retrieve current status + * + * Set whether exceptions encounted in the dispatch loop should be thrown + * or caught and trapped in the response object. + * + * Default behaviour is to trap them in the response object; call this + * method to have them thrown. + * + * Passing no value will return the current value of the flag; passing a + * boolean true or false value will set the flag and return the current + * object instance. + * + * @param boolean $flag Defaults to null (return flag state) + * @return boolean|Zend_Controller_Front Used as a setter, returns object; as a getter, returns boolean + */ + public function throwExceptions($flag = null) + { + if ($flag !== null) { + $this->_throwExceptions = (bool) $flag; + return $this; + } + + return $this->_throwExceptions; + } + + /** + * Set whether {@link dispatch()} should return the response without first + * rendering output. By default, output is rendered and dispatch() returns + * nothing. + * + * @param boolean $flag + * @return boolean|Zend_Controller_Front Used as a setter, returns object; as a getter, returns boolean + */ + public function returnResponse($flag = null) + { + if (true === $flag) { + $this->_returnResponse = true; + return $this; + } elseif (false === $flag) { + $this->_returnResponse = false; + return $this; + } + + return $this->_returnResponse; + } + + /** + * Dispatch an HTTP request to a controller/action. + * + * @param Zend_Controller_Request_Abstract|null $request + * @param Zend_Controller_Response_Abstract|null $response + * @return void|Zend_Controller_Response_Abstract Returns response object if returnResponse() is true + */ + public function dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null) + { + if (!$this->getParam('noErrorHandler') && !$this->_plugins->hasPlugin('Zend_Controller_Plugin_ErrorHandler')) { + // Register with stack index of 100 + $this->_plugins->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(), 100); + } + + if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) { + Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-80, new Zend_Controller_Action_Helper_ViewRenderer()); + } + + /** + * Instantiate default request object (HTTP version) if none provided + */ + if (null !== $request) { + $this->setRequest($request); + } elseif ((null === $request) && (null === ($request = $this->getRequest()))) { + $request = new Zend_Controller_Request_Http(); + $this->setRequest($request); + } + + /** + * Set base URL of request object, if available + */ + if (is_callable(array($this->_request, 'setBaseUrl'))) { + if (null !== $this->_baseUrl) { + $this->_request->setBaseUrl($this->_baseUrl); + } + } + + /** + * Instantiate default response object (HTTP version) if none provided + */ + if (null !== $response) { + $this->setResponse($response); + } elseif ((null === $this->_response) && (null === ($this->_response = $this->getResponse()))) { + $response = new Zend_Controller_Response_Http(); + $this->setResponse($response); + } + + /** + * Register request and response objects with plugin broker + */ + $this->_plugins + ->setRequest($this->_request) + ->setResponse($this->_response); + + /** + * Initialize router + */ + $router = $this->getRouter(); + $router->setParams($this->getParams()); + + /** + * Initialize dispatcher + */ + $dispatcher = $this->getDispatcher(); + $dispatcher->setParams($this->getParams()) + ->setResponse($this->_response); + + // Begin dispatch + try { + /** + * Route request to controller/action, if a router is provided + */ + + /** + * Notify plugins of router startup + */ + $this->_plugins->routeStartup($this->_request); + + try { + $router->route($this->_request); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + + $this->_response->setException($e); + } + + /** + * Notify plugins of router completion + */ + $this->_plugins->routeShutdown($this->_request); + + /** + * Notify plugins of dispatch loop startup + */ + $this->_plugins->dispatchLoopStartup($this->_request); + + /** + * Attempt to dispatch the controller/action. If the $this->_request + * indicates that it needs to be dispatched, move to the next + * action in the request. + */ + do { + $this->_request->setDispatched(true); + + /** + * Notify plugins of dispatch startup + */ + $this->_plugins->preDispatch($this->_request); + + /** + * Skip requested action if preDispatch() has reset it + */ + if (!$this->_request->isDispatched()) { + continue; + } + + /** + * Dispatch request + */ + try { + $dispatcher->dispatch($this->_request, $this->_response); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + $this->_response->setException($e); + } + + /** + * Notify plugins of dispatch completion + */ + $this->_plugins->postDispatch($this->_request); + } while (!$this->_request->isDispatched()); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + + $this->_response->setException($e); + } + + /** + * Notify plugins of dispatch loop completion + */ + try { + $this->_plugins->dispatchLoopShutdown(); + } catch (Exception $e) { + if ($this->throwExceptions()) { + throw $e; + } + + $this->_response->setException($e); + } + + if ($this->returnResponse()) { + return $this->_response; + } + + $this->_response->sendResponse(); + } +} diff --git a/library/vendor/Zend/Controller/Plugin/Abstract.php b/library/vendor/Zend/Controller/Plugin/Abstract.php new file mode 100644 index 000000000..71ca167e9 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/Abstract.php @@ -0,0 +1,151 @@ +_request = $request; + return $this; + } + + /** + * Get request object + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set response object + * + * @param Zend_Controller_Response_Abstract $response + * @return Zend_Controller_Plugin_Abstract + */ + public function setResponse(Zend_Controller_Response_Abstract $response) + { + $this->_response = $response; + return $this; + } + + /** + * Get response object + * + * @return Zend_Controller_Response_Abstract $response + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Called before Zend_Controller_Front begins evaluating the + * request against its routes. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeStartup(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called after Zend_Controller_Router exits. + * + * Called after Zend_Controller_Front exits from the router. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeShutdown(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called before Zend_Controller_Front enters its dispatch loop. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called before an action is dispatched by Zend_Controller_Dispatcher. + * + * This callback allows for proxy or filter behavior. By altering the + * request and resetting its dispatched flag (via + * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}), + * the current action may be skipped. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function preDispatch(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called after an action is dispatched by Zend_Controller_Dispatcher. + * + * This callback allows for proxy or filter behavior. By altering the + * request and resetting its dispatched flag (via + * {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}), + * a new action may be specified for dispatching. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + {} + + /** + * Called before Zend_Controller_Front exits its dispatch loop. + * + * @return void + */ + public function dispatchLoopShutdown() + {} +} diff --git a/library/vendor/Zend/Controller/Plugin/ActionStack.php b/library/vendor/Zend/Controller/Plugin/ActionStack.php new file mode 100644 index 000000000..1d1df1cd9 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/ActionStack.php @@ -0,0 +1,277 @@ +setRegistry($registry); + + if (null !== $key) { + $this->setRegistryKey($key); + } else { + $key = $this->getRegistryKey(); + } + + $registry[$key] = array(); + } + + /** + * Set registry object + * + * @param Zend_Registry $registry + * @return Zend_Controller_Plugin_ActionStack + */ + public function setRegistry(Zend_Registry $registry) + { + $this->_registry = $registry; + return $this; + } + + /** + * Retrieve registry object + * + * @return Zend_Registry + */ + public function getRegistry() + { + return $this->_registry; + } + + /** + * Retrieve registry key + * + * @return string + */ + public function getRegistryKey() + { + return $this->_registryKey; + } + + /** + * Set registry key + * + * @param string $key + * @return Zend_Controller_Plugin_ActionStack + */ + public function setRegistryKey($key) + { + $this->_registryKey = (string) $key; + return $this; + } + + /** + * Set clearRequestParams flag + * + * @param bool $clearRequestParams + * @return Zend_Controller_Plugin_ActionStack + */ + public function setClearRequestParams($clearRequestParams) + { + $this->_clearRequestParams = (bool) $clearRequestParams; + return $this; + } + + /** + * Retrieve clearRequestParams flag + * + * @return bool + */ + public function getClearRequestParams() + { + return $this->_clearRequestParams; + } + + /** + * Retrieve action stack + * + * @return array + */ + public function getStack() + { + $registry = $this->getRegistry(); + $stack = $registry[$this->getRegistryKey()]; + return $stack; + } + + /** + * Save stack to registry + * + * @param array $stack + * @return Zend_Controller_Plugin_ActionStack + */ + protected function _saveStack(array $stack) + { + $registry = $this->getRegistry(); + $registry[$this->getRegistryKey()] = $stack; + return $this; + } + + /** + * Push an item onto the stack + * + * @param Zend_Controller_Request_Abstract $next + * @return Zend_Controller_Plugin_ActionStack + */ + public function pushStack(Zend_Controller_Request_Abstract $next) + { + $stack = $this->getStack(); + array_push($stack, $next); + return $this->_saveStack($stack); + } + + /** + * Pop an item off the action stack + * + * @return false|Zend_Controller_Request_Abstract + */ + public function popStack() + { + $stack = $this->getStack(); + if (0 == count($stack)) { + return false; + } + + $next = array_pop($stack); + $this->_saveStack($stack); + + if (!$next instanceof Zend_Controller_Request_Abstract) { + throw new Zend_Controller_Exception('ArrayStack should only contain request objects'); + } + $action = $next->getActionName(); + if (empty($action)) { + return $this->popStack($stack); + } + + $request = $this->getRequest(); + $controller = $next->getControllerName(); + if (empty($controller)) { + $next->setControllerName($request->getControllerName()); + } + + $module = $next->getModuleName(); + if (empty($module)) { + $next->setModuleName($request->getModuleName()); + } + + return $next; + } + + /** + * postDispatch() plugin hook -- check for actions in stack, and dispatch if any found + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + { + // Don't move on to next request if this is already an attempt to + // forward + if (!$request->isDispatched()) { + return; + } + + $this->setRequest($request); + $stack = $this->getStack(); + if (empty($stack)) { + return; + } + $next = $this->popStack(); + if (!$next) { + return; + } + + $this->forward($next); + } + + /** + * Forward request with next action + * + * @param array $next + * @return void + */ + public function forward(Zend_Controller_Request_Abstract $next) + { + $request = $this->getRequest(); + if ($this->getClearRequestParams()) { + $request->clearParams(); + } + + $request->setModuleName($next->getModuleName()) + ->setControllerName($next->getControllerName()) + ->setActionName($next->getActionName()) + ->setParams($next->getParams()) + ->setDispatched(false); + } +} diff --git a/library/vendor/Zend/Controller/Plugin/Broker.php b/library/vendor/Zend/Controller/Plugin/Broker.php new file mode 100644 index 000000000..64bbdae3d --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/Broker.php @@ -0,0 +1,361 @@ +_plugins, true)) { + throw new Zend_Controller_Exception('Plugin already registered'); + } + + $stackIndex = (int) $stackIndex; + + if ($stackIndex) { + if (isset($this->_plugins[$stackIndex])) { + throw new Zend_Controller_Exception('Plugin with stackIndex "' . $stackIndex . '" already registered'); + } + $this->_plugins[$stackIndex] = $plugin; + } else { + $stackIndex = count($this->_plugins); + while (isset($this->_plugins[$stackIndex])) { + ++$stackIndex; + } + $this->_plugins[$stackIndex] = $plugin; + } + + $request = $this->getRequest(); + if ($request) { + $this->_plugins[$stackIndex]->setRequest($request); + } + $response = $this->getResponse(); + if ($response) { + $this->_plugins[$stackIndex]->setResponse($response); + } + + ksort($this->_plugins); + + return $this; + } + + /** + * Unregister a plugin. + * + * @param string|Zend_Controller_Plugin_Abstract $plugin Plugin object or class name + * @return Zend_Controller_Plugin_Broker + */ + public function unregisterPlugin($plugin) + { + if ($plugin instanceof Zend_Controller_Plugin_Abstract) { + // Given a plugin object, find it in the array + $key = array_search($plugin, $this->_plugins, true); + if (false === $key) { + throw new Zend_Controller_Exception('Plugin never registered.'); + } + unset($this->_plugins[$key]); + } elseif (is_string($plugin)) { + // Given a plugin class, find all plugins of that class and unset them + foreach ($this->_plugins as $key => $_plugin) { + $type = get_class($_plugin); + if ($plugin == $type) { + unset($this->_plugins[$key]); + } + } + } + return $this; + } + + /** + * Is a plugin of a particular class registered? + * + * @param string $class + * @return bool + */ + public function hasPlugin($class) + { + foreach ($this->_plugins as $plugin) { + $type = get_class($plugin); + if ($class == $type) { + return true; + } + } + + return false; + } + + /** + * Retrieve a plugin or plugins by class + * + * @param string $class Class name of plugin(s) desired + * @return false|Zend_Controller_Plugin_Abstract|array Returns false if none found, plugin if only one found, and array of plugins if multiple plugins of same class found + */ + public function getPlugin($class) + { + $found = array(); + foreach ($this->_plugins as $plugin) { + $type = get_class($plugin); + if ($class == $type) { + $found[] = $plugin; + } + } + + switch (count($found)) { + case 0: + return false; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Retrieve all plugins + * + * @return array + */ + public function getPlugins() + { + return $this->_plugins; + } + + /** + * Set request object, and register with each plugin + * + * @param Zend_Controller_Request_Abstract $request + * @return Zend_Controller_Plugin_Broker + */ + public function setRequest(Zend_Controller_Request_Abstract $request) + { + $this->_request = $request; + + foreach ($this->_plugins as $plugin) { + $plugin->setRequest($request); + } + + return $this; + } + + /** + * Get request object + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set response object + * + * @param Zend_Controller_Response_Abstract $response + * @return Zend_Controller_Plugin_Broker + */ + public function setResponse(Zend_Controller_Response_Abstract $response) + { + $this->_response = $response; + + foreach ($this->_plugins as $plugin) { + $plugin->setResponse($response); + } + + + return $this; + } + + /** + * Get response object + * + * @return Zend_Controller_Response_Abstract $response + */ + public function getResponse() + { + return $this->_response; + } + + + /** + * Called before Zend_Controller_Front begins evaluating the + * request against its routes. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeStartup(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->routeStartup($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before Zend_Controller_Front exits its iterations over + * the route set. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function routeShutdown(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->routeShutdown($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before Zend_Controller_Front enters its dispatch loop. + * + * During the dispatch loop, Zend_Controller_Front keeps a + * Zend_Controller_Request_Abstract object, and uses + * Zend_Controller_Dispatcher to dispatch the + * Zend_Controller_Request_Abstract object to controllers/actions. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->dispatchLoopStartup($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before an action is dispatched by Zend_Controller_Dispatcher. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function preDispatch(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->preDispatch($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + // skip rendering of normal dispatch give the error handler a try + $this->getRequest()->setDispatched(false); + } + } + } + } + + + /** + * Called after an action is dispatched by Zend_Controller_Dispatcher. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->postDispatch($request); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } + + + /** + * Called before Zend_Controller_Front exits its dispatch loop. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + public function dispatchLoopShutdown() + { + foreach ($this->_plugins as $plugin) { + try { + $plugin->dispatchLoopShutdown(); + } catch (Exception $e) { + if (Zend_Controller_Front::getInstance()->throwExceptions()) { + throw new Zend_Controller_Exception($e->getMessage() . $e->getTraceAsString(), $e->getCode(), $e); + } else { + $this->getResponse()->setException($e); + } + } + } + } +} diff --git a/library/vendor/Zend/Controller/Plugin/ErrorHandler.php b/library/vendor/Zend/Controller/Plugin/ErrorHandler.php new file mode 100644 index 000000000..9f850d3e2 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/ErrorHandler.php @@ -0,0 +1,299 @@ +setErrorHandler($options); + } + + /** + * setErrorHandler() - setup the error handling options + * + * @param array $options + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandler(Array $options = array()) + { + if (isset($options['module'])) { + $this->setErrorHandlerModule($options['module']); + } + if (isset($options['controller'])) { + $this->setErrorHandlerController($options['controller']); + } + if (isset($options['action'])) { + $this->setErrorHandlerAction($options['action']); + } + return $this; + } + + /** + * Set the module name for the error handler + * + * @param string $module + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandlerModule($module) + { + $this->_errorModule = (string) $module; + return $this; + } + + /** + * Retrieve the current error handler module + * + * @return string + */ + public function getErrorHandlerModule() + { + if (null === $this->_errorModule) { + $this->_errorModule = Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule(); + } + return $this->_errorModule; + } + + /** + * Set the controller name for the error handler + * + * @param string $controller + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandlerController($controller) + { + $this->_errorController = (string) $controller; + return $this; + } + + /** + * Retrieve the current error handler controller + * + * @return string + */ + public function getErrorHandlerController() + { + return $this->_errorController; + } + + /** + * Set the action name for the error handler + * + * @param string $action + * @return Zend_Controller_Plugin_ErrorHandler + */ + public function setErrorHandlerAction($action) + { + $this->_errorAction = (string) $action; + return $this; + } + + /** + * Retrieve the current error handler action + * + * @return string + */ + public function getErrorHandlerAction() + { + return $this->_errorAction; + } + + /** + * Route shutdown hook -- Ccheck for router exceptions + * + * @param Zend_Controller_Request_Abstract $request + */ + public function routeShutdown(Zend_Controller_Request_Abstract $request) + { + $this->_handleError($request); + } + + /** + * Pre dispatch hook -- check for exceptions and dispatch error handler if + * necessary + * + * @param Zend_Controller_Request_Abstract $request + */ + public function preDispatch(Zend_Controller_Request_Abstract $request) + { + $this->_handleError($request); + } + + /** + * Post dispatch hook -- check for exceptions and dispatch error handler if + * necessary + * + * @param Zend_Controller_Request_Abstract $request + */ + public function postDispatch(Zend_Controller_Request_Abstract $request) + { + $this->_handleError($request); + } + + /** + * Handle errors and exceptions + * + * If the 'noErrorHandler' front controller flag has been set, + * returns early. + * + * @param Zend_Controller_Request_Abstract $request + * @return void + */ + protected function _handleError(Zend_Controller_Request_Abstract $request) + { + $frontController = Zend_Controller_Front::getInstance(); + if ($frontController->getParam('noErrorHandler')) { + return; + } + + $response = $this->getResponse(); + + if ($this->_isInsideErrorHandlerLoop) { + $exceptions = $response->getException(); + if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) { + // Exception thrown by error handler; tell the front controller to throw it + $frontController->throwExceptions(true); + throw array_pop($exceptions); + } + } + + // check for an exception AND allow the error handler controller the option to forward + if (($response->isException()) && (!$this->_isInsideErrorHandlerLoop)) { + $this->_isInsideErrorHandlerLoop = true; + + // Get exception information + $error = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); + $exceptions = $response->getException(); + $exception = $exceptions[0]; + $exceptionType = get_class($exception); + $error->exception = $exception; + switch ($exceptionType) { + case 'Zend_Controller_Router_Exception': + if (404 == $exception->getCode()) { + $error->type = self::EXCEPTION_NO_ROUTE; + } else { + $error->type = self::EXCEPTION_OTHER; + } + break; + case 'Zend_Controller_Dispatcher_Exception': + $error->type = self::EXCEPTION_NO_CONTROLLER; + break; + case 'Zend_Controller_Action_Exception': + if (404 == $exception->getCode()) { + $error->type = self::EXCEPTION_NO_ACTION; + } else { + $error->type = self::EXCEPTION_OTHER; + } + break; + default: + $error->type = self::EXCEPTION_OTHER; + break; + } + + // Keep a copy of the original request + $error->request = clone $request; + + // get a count of the number of exceptions encountered + $this->_exceptionCountAtFirstEncounter = count($exceptions); + + // Forward to the error handler + $request->setParam('error_handler', $error) + ->setModuleName($this->getErrorHandlerModule()) + ->setControllerName($this->getErrorHandlerController()) + ->setActionName($this->getErrorHandlerAction()) + ->setDispatched(false); + } + } +} diff --git a/library/vendor/Zend/Controller/Plugin/PutHandler.php b/library/vendor/Zend/Controller/Plugin/PutHandler.php new file mode 100644 index 000000000..8bda14094 --- /dev/null +++ b/library/vendor/Zend/Controller/Plugin/PutHandler.php @@ -0,0 +1,58 @@ +_request->isPut()) { + $putParams = array(); + parse_str($this->_request->getRawBody(), $putParams); + $request->setParams($putParams); + } + } +} diff --git a/library/vendor/Zend/Controller/Request/Abstract.php b/library/vendor/Zend/Controller/Request/Abstract.php new file mode 100644 index 000000000..68a8bd73a --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Abstract.php @@ -0,0 +1,356 @@ +_module) { + $this->_module = $this->getParam($this->getModuleKey()); + } + + return $this->_module; + } + + /** + * Set the module name to use + * + * @param string $value + * @return Zend_Controller_Request_Abstract + */ + public function setModuleName($value) + { + $this->_module = $value; + return $this; + } + + /** + * Retrieve the controller name + * + * @return string + */ + public function getControllerName() + { + if (null === $this->_controller) { + $this->_controller = $this->getParam($this->getControllerKey()); + } + + return $this->_controller; + } + + /** + * Set the controller name to use + * + * @param string $value + * @return Zend_Controller_Request_Abstract + */ + public function setControllerName($value) + { + $this->_controller = $value; + return $this; + } + + /** + * Retrieve the action name + * + * @return string + */ + public function getActionName() + { + if (null === $this->_action) { + $this->_action = $this->getParam($this->getActionKey()); + } + + return $this->_action; + } + + /** + * Set the action name + * + * @param string $value + * @return Zend_Controller_Request_Abstract + */ + public function setActionName($value) + { + $this->_action = $value; + /** + * @see ZF-3465 + */ + if (null === $value) { + $this->setParam($this->getActionKey(), $value); + } + return $this; + } + + /** + * Retrieve the module key + * + * @return string + */ + public function getModuleKey() + { + return $this->_moduleKey; + } + + /** + * Set the module key + * + * @param string $key + * @return Zend_Controller_Request_Abstract + */ + public function setModuleKey($key) + { + $this->_moduleKey = (string) $key; + return $this; + } + + /** + * Retrieve the controller key + * + * @return string + */ + public function getControllerKey() + { + return $this->_controllerKey; + } + + /** + * Set the controller key + * + * @param string $key + * @return Zend_Controller_Request_Abstract + */ + public function setControllerKey($key) + { + $this->_controllerKey = (string) $key; + return $this; + } + + /** + * Retrieve the action key + * + * @return string + */ + public function getActionKey() + { + return $this->_actionKey; + } + + /** + * Set the action key + * + * @param string $key + * @return Zend_Controller_Request_Abstract + */ + public function setActionKey($key) + { + $this->_actionKey = (string) $key; + return $this; + } + + /** + * Get an action parameter + * + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed + */ + public function getParam($key, $default = null) + { + $key = (string) $key; + if (isset($this->_params[$key])) { + return $this->_params[$key]; + } + + return $default; + } + + /** + * Retrieve only user params (i.e, any param specific to the object and not the environment) + * + * @return array + */ + public function getUserParams() + { + return $this->_params; + } + + /** + * Retrieve a single user param (i.e, a param specific to the object and not the environment) + * + * @param string $key + * @param string $default Default value to use if key not found + * @return mixed + */ + public function getUserParam($key, $default = null) + { + if (isset($this->_params[$key])) { + return $this->_params[$key]; + } + + return $default; + } + + /** + * Set an action parameter + * + * A $value of null will unset the $key if it exists + * + * @param string $key + * @param mixed $value + * @return Zend_Controller_Request_Abstract + */ + public function setParam($key, $value) + { + $key = (string) $key; + + if ((null === $value) && isset($this->_params[$key])) { + unset($this->_params[$key]); + } elseif (null !== $value) { + $this->_params[$key] = $value; + } + + return $this; + } + + /** + * Get all action parameters + * + * @return array + */ + public function getParams() + { + return $this->_params; + } + + /** + * Set action parameters en masse; does not overwrite + * + * Null values will unset the associated key. + * + * @param array $array + * @return Zend_Controller_Request_Abstract + */ + public function setParams(array $array) + { + $this->_params = $this->_params + (array) $array; + + foreach ($array as $key => $value) { + if (null === $value) { + unset($this->_params[$key]); + } + } + + return $this; + } + + /** + * Unset all user parameters + * + * @return Zend_Controller_Request_Abstract + */ + public function clearParams() + { + $this->_params = array(); + return $this; + } + + /** + * Set flag indicating whether or not request has been dispatched + * + * @param boolean $flag + * @return Zend_Controller_Request_Abstract + */ + public function setDispatched($flag = true) + { + $this->_dispatched = $flag ? true : false; + return $this; + } + + /** + * Determine if the request has been dispatched + * + * @return boolean + */ + public function isDispatched() + { + return $this->_dispatched; + } +} diff --git a/library/vendor/Zend/Controller/Request/Apache404.php b/library/vendor/Zend/Controller/Request/Apache404.php new file mode 100644 index 000000000..f2015da04 --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Apache404.php @@ -0,0 +1,80 @@ +_requestUri = $requestUri; + return $this; + } +} diff --git a/library/vendor/Zend/Controller/Request/Exception.php b/library/vendor/Zend/Controller/Request/Exception.php new file mode 100644 index 000000000..9cbbdf693 --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Exception.php @@ -0,0 +1,36 @@ +valid()) { + $path = $uri->getPath(); + $query = $uri->getQuery(); + if (!empty($query)) { + $path .= '?' . $query; + } + + $this->setRequestUri($path); + } else { + throw new Zend_Controller_Request_Exception('Invalid URI provided to constructor'); + } + } else { + $this->setRequestUri(); + } + } + + /** + * Access values contained in the superglobals as public members + * Order of precedence: 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV + * + * @see http://msdn.microsoft.com/en-us/library/system.web.httprequest.item.aspx + * @param string $key + * @return mixed + */ + public function __get($key) + { + switch (true) { + case isset($this->_params[$key]): + return $this->_params[$key]; + case isset($_GET[$key]): + return $_GET[$key]; + case isset($_POST[$key]): + return $_POST[$key]; + case isset($_COOKIE[$key]): + return $_COOKIE[$key]; + case ($key == 'REQUEST_URI'): + return $this->getRequestUri(); + case ($key == 'PATH_INFO'): + return $this->getPathInfo(); + case isset($_SERVER[$key]): + return $_SERVER[$key]; + case isset($_ENV[$key]): + return $_ENV[$key]; + default: + return null; + } + } + + /** + * Alias to __get + * + * @param string $key + * @return mixed + */ + public function get($key) + { + return $this->__get($key); + } + + /** + * Set values + * + * In order to follow {@link __get()}, which operates on a number of + * superglobals, setting values through overloading is not allowed and will + * raise an exception. Use setParam() instead. + * + * @param string $key + * @param mixed $value + * @return void + * @throws Zend_Controller_Request_Exception + */ + public function __set($key, $value) + { + throw new Zend_Controller_Request_Exception('Setting values in superglobals not allowed; please use setParam()'); + } + + /** + * Alias to __set() + * + * @param string $key + * @param mixed $value + * @return void + */ + public function set($key, $value) + { + return $this->__set($key, $value); + } + + /** + * Check to see if a property is set + * + * @param string $key + * @return boolean + */ + public function __isset($key) + { + switch (true) { + case isset($this->_params[$key]): + return true; + case isset($_GET[$key]): + return true; + case isset($_POST[$key]): + return true; + case isset($_COOKIE[$key]): + return true; + case isset($_SERVER[$key]): + return true; + case isset($_ENV[$key]): + return true; + default: + return false; + } + } + + /** + * Alias to __isset() + * + * @param string $key + * @return boolean + */ + public function has($key) + { + return $this->__isset($key); + } + + /** + * Set GET values + * + * @param string|array $spec + * @param null|mixed $value + * @return Zend_Controller_Request_Http + */ + public function setQuery($spec, $value = null) + { + if ((null === $value) && !is_array($spec)) { + throw new Zend_Controller_Exception('Invalid value passed to setQuery(); must be either array of values or key/value pair'); + } + if ((null === $value) && is_array($spec)) { + foreach ($spec as $key => $value) { + $this->setQuery($key, $value); + } + return $this; + } + $_GET[(string) $spec] = $value; + return $this; + } + + /** + * Retrieve a member of the $_GET superglobal + * + * If no $key is passed, returns the entire $_GET array. + * + * @todo How to retrieve from nested arrays + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getQuery($key = null, $default = null) + { + if (null === $key) { + return $_GET; + } + + return (isset($_GET[$key])) ? $_GET[$key] : $default; + } + + /** + * Set POST values + * + * @param string|array $spec + * @param null|mixed $value + * @return Zend_Controller_Request_Http + */ + public function setPost($spec, $value = null) + { + if ((null === $value) && !is_array($spec)) { + throw new Zend_Controller_Exception('Invalid value passed to setPost(); must be either array of values or key/value pair'); + } + if ((null === $value) && is_array($spec)) { + foreach ($spec as $key => $value) { + $this->setPost($key, $value); + } + return $this; + } + $_POST[(string) $spec] = $value; + return $this; + } + + /** + * Retrieve a member of the $_POST superglobal + * + * If no $key is passed, returns the entire $_POST array. + * + * @todo How to retrieve from nested arrays + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getPost($key = null, $default = null) + { + if (null === $key) { + return $_POST; + } + + return (isset($_POST[$key])) ? $_POST[$key] : $default; + } + + /** + * Retrieve a member of the $_COOKIE superglobal + * + * If no $key is passed, returns the entire $_COOKIE array. + * + * @todo How to retrieve from nested arrays + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getCookie($key = null, $default = null) + { + if (null === $key) { + return $_COOKIE; + } + + return (isset($_COOKIE[$key])) ? $_COOKIE[$key] : $default; + } + + /** + * Retrieve a member of the $_SERVER superglobal + * + * If no $key is passed, returns the entire $_SERVER array. + * + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getServer($key = null, $default = null) + { + if (null === $key) { + return $_SERVER; + } + + return (isset($_SERVER[$key])) ? $_SERVER[$key] : $default; + } + + /** + * Retrieve a member of the $_ENV superglobal + * + * If no $key is passed, returns the entire $_ENV array. + * + * @param string $key + * @param mixed $default Default value to use if key not found + * @return mixed Returns null if key does not exist + */ + public function getEnv($key = null, $default = null) + { + if (null === $key) { + return $_ENV; + } + + return (isset($_ENV[$key])) ? $_ENV[$key] : $default; + } + + /** + * Set the REQUEST_URI on which the instance operates + * + * If no request URI is passed, uses the value in $_SERVER['REQUEST_URI'], + * $_SERVER['HTTP_X_REWRITE_URL'], or $_SERVER['ORIG_PATH_INFO'] + $_SERVER['QUERY_STRING']. + * + * @param string $requestUri + * @return Zend_Controller_Request_Http + */ + public function setRequestUri($requestUri = null) + { + if ($requestUri === null) { + if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) { + // IIS with Microsoft Rewrite Module + $requestUri = $_SERVER['HTTP_X_ORIGINAL_URL']; + } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { + // IIS with ISAPI_Rewrite + $requestUri = $_SERVER['HTTP_X_REWRITE_URL']; + } elseif ( + // IIS7 with URL Rewrite: make sure we get the unencoded url (double slash problem) + isset($_SERVER['IIS_WasUrlRewritten']) + && $_SERVER['IIS_WasUrlRewritten'] == '1' + && isset($_SERVER['UNENCODED_URL']) + && $_SERVER['UNENCODED_URL'] != '' + ) { + $requestUri = $_SERVER['UNENCODED_URL']; + } elseif (isset($_SERVER['REQUEST_URI'])) { + $requestUri = $_SERVER['REQUEST_URI']; + // Http proxy reqs setup request uri with scheme and host [and port] + the url path, only use url path + $schemeAndHttpHost = $this->getScheme() . '://' . $this->getHttpHost(); + if (strpos($requestUri, $schemeAndHttpHost) === 0) { + $requestUri = substr($requestUri, strlen($schemeAndHttpHost)); + } + } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI + $requestUri = $_SERVER['ORIG_PATH_INFO']; + if (!empty($_SERVER['QUERY_STRING'])) { + $requestUri .= '?' . $_SERVER['QUERY_STRING']; + } + } else { + return $this; + } + } elseif (!is_string($requestUri)) { + return $this; + } else { + // Set GET items, if available + if (false !== ($pos = strpos($requestUri, '?'))) { + // Get key => value pairs and set $_GET + $query = substr($requestUri, $pos + 1); + parse_str($query, $vars); + $this->setQuery($vars); + } + } + + $this->_requestUri = $requestUri; + return $this; + } + + /** + * Returns the REQUEST_URI taking into account + * platform differences between Apache and IIS + * + * @return string + */ + public function getRequestUri() + { + if (empty($this->_requestUri)) { + $this->setRequestUri(); + } + + return $this->_requestUri; + } + + /** + * Set the base URL of the request; i.e., the segment leading to the script name + * + * E.g.: + * - /admin + * - /myapp + * - /subdir/index.php + * + * Do not use the full URI when providing the base. The following are + * examples of what not to use: + * - http://example.com/admin (should be just /admin) + * - http://example.com/subdir/index.php (should be just /subdir/index.php) + * + * If no $baseUrl is provided, attempts to determine the base URL from the + * environment, using SCRIPT_FILENAME, SCRIPT_NAME, PHP_SELF, and + * ORIG_SCRIPT_NAME in its determination. + * + * @param mixed $baseUrl + * @return Zend_Controller_Request_Http + */ + public function setBaseUrl($baseUrl = null) + { + if ((null !== $baseUrl) && !is_string($baseUrl)) { + return $this; + } + + if ($baseUrl === null) { + $filename = (isset($_SERVER['SCRIPT_FILENAME'])) ? basename($_SERVER['SCRIPT_FILENAME']) : ''; + + if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $filename) { + $baseUrl = $_SERVER['SCRIPT_NAME']; + } elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $filename) { + $baseUrl = $_SERVER['PHP_SELF']; + } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) { + $baseUrl = $_SERVER['ORIG_SCRIPT_NAME']; // 1and1 shared hosting compatibility + } else { + // Backtrack up the script_filename to find the portion matching + // php_self + $path = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : ''; + $file = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : ''; + $segs = explode('/', trim($file, '/')); + $segs = array_reverse($segs); + $index = 0; + $last = count($segs); + $baseUrl = ''; + do { + $seg = $segs[$index]; + $baseUrl = '/' . $seg . $baseUrl; + ++$index; + } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos)); + } + + // Does the baseUrl have anything in common with the request_uri? + $requestUri = $this->getRequestUri(); + + if (0 === strpos($requestUri, $baseUrl)) { + // full $baseUrl matches + $this->_baseUrl = $baseUrl; + return $this; + } + + if (0 === strpos($requestUri, dirname($baseUrl))) { + // directory portion of $baseUrl matches + $this->_baseUrl = rtrim(dirname($baseUrl), '/'); + return $this; + } + + $truncatedRequestUri = $requestUri; + if (($pos = strpos($requestUri, '?')) !== false) { + $truncatedRequestUri = substr($requestUri, 0, $pos); + } + + $basename = basename($baseUrl); + if (empty($basename) || !strpos($truncatedRequestUri, $basename)) { + // no match whatsoever; set it blank + $this->_baseUrl = ''; + return $this; + } + + // If using mod_rewrite or ISAPI_Rewrite strip the script filename + // out of baseUrl. $pos !== 0 makes sure it is not matching a value + // from PATH_INFO or QUERY_STRING + if ((strlen($requestUri) >= strlen($baseUrl)) + && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0))) + { + $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl)); + } + } + + $this->_baseUrl = rtrim($baseUrl, '/'); + return $this; + } + + /** + * Everything in REQUEST_URI before PATH_INFO + *
              + * + * @return string + */ + public function getBaseUrl($raw = false) + { + if (null === $this->_baseUrl) { + $this->setBaseUrl(); + } + + return (($raw == false) ? urldecode($this->_baseUrl) : $this->_baseUrl); + } + + /** + * Set the base path for the URL + * + * @param string|null $basePath + * @return Zend_Controller_Request_Http + */ + public function setBasePath($basePath = null) + { + if ($basePath === null) { + $filename = (isset($_SERVER['SCRIPT_FILENAME'])) + ? basename($_SERVER['SCRIPT_FILENAME']) + : ''; + + $baseUrl = $this->getBaseUrl(); + if (empty($baseUrl)) { + $this->_basePath = ''; + return $this; + } + + if (basename($baseUrl) === $filename) { + $basePath = dirname($baseUrl); + } else { + $basePath = $baseUrl; + } + } + + if (substr(PHP_OS, 0, 3) === 'WIN') { + $basePath = str_replace('\\', '/', $basePath); + } + + $this->_basePath = rtrim($basePath, '/'); + return $this; + } + + /** + * Everything in REQUEST_URI before PATH_INFO not including the filename + * + * + * @return string + */ + public function getBasePath() + { + if (null === $this->_basePath) { + $this->setBasePath(); + } + + return $this->_basePath; + } + + /** + * Set the PATH_INFO string + * + * @param string|null $pathInfo + * @return Zend_Controller_Request_Http + */ + public function setPathInfo($pathInfo = null) + { + if ($pathInfo === null) { + $baseUrl = $this->getBaseUrl(); // this actually calls setBaseUrl() & setRequestUri() + $baseUrlRaw = $this->getBaseUrl(false); + $baseUrlEncoded = urlencode($baseUrlRaw); + + if (null === ($requestUri = $this->getRequestUri())) { + return $this; + } + + // Remove the query string from REQUEST_URI + if ($pos = strpos($requestUri, '?')) { + $requestUri = substr($requestUri, 0, $pos); + } + + if (!empty($baseUrl) || !empty($baseUrlRaw)) { + if (strpos($requestUri, $baseUrl) === 0) { + $pathInfo = substr($requestUri, strlen($baseUrl)); + } elseif (strpos($requestUri, $baseUrlRaw) === 0) { + $pathInfo = substr($requestUri, strlen($baseUrlRaw)); + } elseif (strpos($requestUri, $baseUrlEncoded) === 0) { + $pathInfo = substr($requestUri, strlen($baseUrlEncoded)); + } else { + $pathInfo = $requestUri; + } + } else { + $pathInfo = $requestUri; + } + + } + + $this->_pathInfo = (string) $pathInfo; + return $this; + } + + /** + * Returns everything between the BaseUrl and QueryString. + * This value is calculated instead of reading PATH_INFO + * directly from $_SERVER due to cross-platform differences. + * + * @return string + */ + public function getPathInfo() + { + if (empty($this->_pathInfo)) { + $this->setPathInfo(); + } + + return $this->_pathInfo; + } + + /** + * Set allowed parameter sources + * + * Can be empty array, or contain one or more of '_GET' or '_POST'. + * + * @param array $paramSoures + * @return Zend_Controller_Request_Http + */ + public function setParamSources(array $paramSources = array()) + { + $this->_paramSources = $paramSources; + return $this; + } + + /** + * Get list of allowed parameter sources + * + * @return array + */ + public function getParamSources() + { + return $this->_paramSources; + } + + /** + * Set a userland parameter + * + * Uses $key to set a userland parameter. If $key is an alias, the actual + * key will be retrieved and used to set the parameter. + * + * @param mixed $key + * @param mixed $value + * @return Zend_Controller_Request_Http + */ + public function setParam($key, $value) + { + $key = (null !== ($alias = $this->getAlias($key))) ? $alias : $key; + parent::setParam($key, $value); + return $this; + } + + /** + * Retrieve a parameter + * + * Retrieves a parameter from the instance. Priority is in the order of + * userland parameters (see {@link setParam()}), $_GET, $_POST. If a + * parameter matching the $key is not found, null is returned. + * + * If the $key is an alias, the actual key aliased will be used. + * + * @param mixed $key + * @param mixed $default Default value to use if key not found + * @return mixed + */ + public function getParam($key, $default = null) + { + $keyName = (null !== ($alias = $this->getAlias($key))) ? $alias : $key; + + $paramSources = $this->getParamSources(); + if (isset($this->_params[$keyName])) { + return $this->_params[$keyName]; + } elseif (in_array('_GET', $paramSources) && (isset($_GET[$keyName]))) { + return $_GET[$keyName]; + } elseif (in_array('_POST', $paramSources) && (isset($_POST[$keyName]))) { + return $_POST[$keyName]; + } + + return $default; + } + + /** + * Retrieve an array of parameters + * + * Retrieves a merged array of parameters, with precedence of userland + * params (see {@link setParam()}), $_GET, $_POST (i.e., values in the + * userland params will take precedence over all others). + * + * @return array + */ + public function getParams() + { + $return = $this->_params; + $paramSources = $this->getParamSources(); + if (in_array('_GET', $paramSources) + && isset($_GET) + && is_array($_GET) + ) { + $return += $_GET; + } + if (in_array('_POST', $paramSources) + && isset($_POST) + && is_array($_POST) + ) { + $return += $_POST; + } + return $return; + } + + /** + * Set parameters + * + * Set one or more parameters. Parameters are set as userland parameters, + * using the keys specified in the array. + * + * @param array $params + * @return Zend_Controller_Request_Http + */ + public function setParams(array $params) + { + foreach ($params as $key => $value) { + $this->setParam($key, $value); + } + return $this; + } + + /** + * Set a key alias + * + * Set an alias used for key lookups. $name specifies the alias, $target + * specifies the actual key to use. + * + * @param string $name + * @param string $target + * @return Zend_Controller_Request_Http + */ + public function setAlias($name, $target) + { + $this->_aliases[$name] = $target; + return $this; + } + + /** + * Retrieve an alias + * + * Retrieve the actual key represented by the alias $name. + * + * @param string $name + * @return string|null Returns null when no alias exists + */ + public function getAlias($name) + { + if (isset($this->_aliases[$name])) { + return $this->_aliases[$name]; + } + + return null; + } + + /** + * Retrieve the list of all aliases + * + * @return array + */ + public function getAliases() + { + return $this->_aliases; + } + + /** + * Return the method by which the request was made + * + * @return string + */ + public function getMethod() + { + return $this->getServer('REQUEST_METHOD'); + } + + /** + * Was the request made by POST? + * + * @return boolean + */ + public function isPost() + { + if ('POST' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by GET? + * + * @return boolean + */ + public function isGet() + { + if ('GET' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by PUT? + * + * @return boolean + */ + public function isPut() + { + if ('PUT' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by DELETE? + * + * @return boolean + */ + public function isDelete() + { + if ('DELETE' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by HEAD? + * + * @return boolean + */ + public function isHead() + { + if ('HEAD' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Was the request made by OPTIONS? + * + * @return boolean + */ + public function isOptions() + { + if ('OPTIONS' == $this->getMethod()) { + return true; + } + + return false; + } + + /** + * Is the request a Javascript XMLHttpRequest? + * + * Should work with Prototype/Script.aculo.us, possibly others. + * + * @return boolean + */ + public function isXmlHttpRequest() + { + return ($this->getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest'); + } + + /** + * Is this a Flash request? + * + * @return boolean + */ + public function isFlashRequest() + { + $header = strtolower($this->getHeader('USER_AGENT')); + return (strstr($header, ' flash')) ? true : false; + } + + /** + * Is https secure request + * + * @return boolean + */ + public function isSecure() + { + return ($this->getScheme() === self::SCHEME_HTTPS); + } + + /** + * Return the raw body of the request, if present + * + * @return string|false Raw body, or false if not present + */ + public function getRawBody() + { + if (null === $this->_rawBody) { + $body = file_get_contents('php://input'); + + if (strlen(trim($body)) > 0) { + $this->_rawBody = $body; + } else { + $this->_rawBody = false; + } + } + return $this->_rawBody; + } + + /** + * Return the value of the given HTTP header. Pass the header name as the + * plain, HTTP-specified header name. Ex.: Ask for 'Accept' to get the + * Accept header, 'Accept-Encoding' to get the Accept-Encoding header. + * + * @param string $header HTTP header name + * @return string|false HTTP header value, or false if not found + * @throws Zend_Controller_Request_Exception + */ + public function getHeader($header) + { + if (empty($header)) { + throw new Zend_Controller_Request_Exception('An HTTP header name is required'); + } + + // Try to get it from the $_SERVER array first + $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header)); + if (isset($_SERVER[$temp])) { + return $_SERVER[$temp]; + } + + // This seems to be the only way to get the Authorization header on + // Apache + if (function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + if (isset($headers[$header])) { + return $headers[$header]; + } + $header = strtolower($header); + foreach ($headers as $key => $value) { + if (strtolower($key) == $header) { + return $value; + } + } + } + + return false; + } + + /** + * Get the request URI scheme + * + * @return string + */ + public function getScheme() + { + return ($this->getServer('HTTPS') == 'on') ? self::SCHEME_HTTPS : self::SCHEME_HTTP; + } + + /** + * Get the HTTP host. + * + * "Host" ":" host [ ":" port ] ; Section 3.2.2 + * Note the HTTP Host header is not the same as the URI host. + * It includes the port while the URI host doesn't. + * + * @return string + */ + public function getHttpHost() + { + $host = $this->getServer('HTTP_HOST'); + if (!empty($host)) { + return $host; + } + + $scheme = $this->getScheme(); + $name = $this->getServer('SERVER_NAME'); + $port = $this->getServer('SERVER_PORT'); + + if(null === $name) { + return ''; + } + elseif (($scheme == self::SCHEME_HTTP && $port == 80) || ($scheme == self::SCHEME_HTTPS && $port == 443)) { + return $name; + } else { + return $name . ':' . $port; + } + } + + /** + * Get the client's IP addres + * + * @param boolean $checkProxy + * @return string + */ + public function getClientIp($checkProxy = true) + { + if ($checkProxy && $this->getServer('HTTP_CLIENT_IP') != null) { + $ip = $this->getServer('HTTP_CLIENT_IP'); + } else if ($checkProxy && $this->getServer('HTTP_X_FORWARDED_FOR') != null) { + $ip = $this->getServer('HTTP_X_FORWARDED_FOR'); + } else { + $ip = $this->getServer('REMOTE_ADDR'); + } + + return $ip; + } +} diff --git a/library/vendor/Zend/Controller/Request/HttpTestCase.php b/library/vendor/Zend/Controller/Request/HttpTestCase.php new file mode 100644 index 000000000..a95e4598e --- /dev/null +++ b/library/vendor/Zend/Controller/Request/HttpTestCase.php @@ -0,0 +1,274 @@ +_rawBody = (string) $content; + return $this; + } + + /** + * Get RAW POST body + * + * @return string|null + */ + public function getRawBody() + { + return $this->_rawBody; + } + + /** + * Clear raw POST body + * + * @return Zend_Controller_Request_HttpTestCase + */ + public function clearRawBody() + { + $this->_rawBody = null; + return $this; + } + + /** + * Set a cookie + * + * @param string $key + * @param mixed $value + * @return Zend_Controller_Request_HttpTestCase + */ + public function setCookie($key, $value) + { + $_COOKIE[(string) $key] = $value; + return $this; + } + + /** + * Set multiple cookies at once + * + * @param array $cookies + * @return void + */ + public function setCookies(array $cookies) + { + foreach ($cookies as $key => $value) { + $_COOKIE[$key] = $value; + } + return $this; + } + + /** + * Clear all cookies + * + * @return Zend_Controller_Request_HttpTestCase + */ + public function clearCookies() + { + $_COOKIE = array(); + return $this; + } + + /** + * Set request method + * + * @param string $type + * @return Zend_Controller_Request_HttpTestCase + */ + public function setMethod($type) + { + $type = strtoupper(trim((string) $type)); + if (!in_array($type, $this->_validMethodTypes)) { + throw new Zend_Controller_Exception('Invalid request method specified'); + } + $this->_method = $type; + return $this; + } + + /** + * Get request method + * + * @return string|null + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Set a request header + * + * @param string $key + * @param string $value + * @return Zend_Controller_Request_HttpTestCase + */ + public function setHeader($key, $value) + { + $key = $this->_normalizeHeaderName($key); + $this->_headers[$key] = (string) $value; + return $this; + } + + /** + * Set request headers + * + * @param array $headers + * @return Zend_Controller_Request_HttpTestCase + */ + public function setHeaders(array $headers) + { + foreach ($headers as $key => $value) { + $this->setHeader($key, $value); + } + return $this; + } + + /** + * Get request header + * + * @param string $header + * @param mixed $default + * @return string|null + */ + public function getHeader($header, $default = null) + { + $header = $this->_normalizeHeaderName($header); + if (array_key_exists($header, $this->_headers)) { + return $this->_headers[$header]; + } + return $default; + } + + /** + * Get all request headers + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Clear request headers + * + * @return Zend_Controller_Request_HttpTestCase + */ + public function clearHeaders() + { + $this->_headers = array(); + return $this; + } + + /** + * Get REQUEST_URI + * + * @return null|string + */ + public function getRequestUri() + { + return $this->_requestUri; + } + + /** + * Normalize a header name for setting and retrieval + * + * @param string $name + * @return string + */ + protected function _normalizeHeaderName($name) + { + $name = strtoupper((string) $name); + $name = str_replace('-', '_', $name); + return $name; + } +} diff --git a/library/vendor/Zend/Controller/Request/Simple.php b/library/vendor/Zend/Controller/Request/Simple.php new file mode 100644 index 000000000..bc61cbfad --- /dev/null +++ b/library/vendor/Zend/Controller/Request/Simple.php @@ -0,0 +1,54 @@ +setActionName($action); + } + + if ($controller) { + $this->setControllerName($controller); + } + + if ($module) { + $this->setModuleName($module); + } + + if ($params) { + $this->setParams($params); + } + } + +} diff --git a/library/vendor/Zend/Controller/Response/Abstract.php b/library/vendor/Zend/Controller/Response/Abstract.php new file mode 100644 index 000000000..c6df02321 --- /dev/null +++ b/library/vendor/Zend/Controller/Response/Abstract.php @@ -0,0 +1,790 @@ +canSendHeaders(true); + $name = $this->_normalizeHeader($name); + $value = (string) $value; + + if ($replace) { + foreach ($this->_headers as $key => $header) { + if ($name == $header['name']) { + unset($this->_headers[$key]); + } + } + } + + $this->_headers[] = array( + 'name' => $name, + 'value' => $value, + 'replace' => $replace + ); + + return $this; + } + + /** + * Set redirect URL + * + * Sets Location header and response code. Forces replacement of any prior + * redirects. + * + * @param string $url + * @param int $code + * @return Zend_Controller_Response_Abstract + */ + public function setRedirect($url, $code = 302) + { + $this->canSendHeaders(true); + $this->setHeader('Location', $url, true) + ->setHttpResponseCode($code); + + return $this; + } + + /** + * Is this a redirect? + * + * @return boolean + */ + public function isRedirect() + { + return $this->_isRedirect; + } + + /** + * Return array of headers; see {@link $_headers} for format + * + * @return array + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Clear headers + * + * @return Zend_Controller_Response_Abstract + */ + public function clearHeaders() + { + $this->_headers = array(); + + return $this; + } + + /** + * Clears the specified HTTP header + * + * @param string $name + * @return Zend_Controller_Response_Abstract + */ + public function clearHeader($name) + { + if (! count($this->_headers)) { + return $this; + } + + foreach ($this->_headers as $index => $header) { + if ($name == $header['name']) { + unset($this->_headers[$index]); + } + } + + return $this; + } + + /** + * Set raw HTTP header + * + * Allows setting non key => value headers, such as status codes + * + * @param string $value + * @return Zend_Controller_Response_Abstract + */ + public function setRawHeader($value) + { + $this->canSendHeaders(true); + if ('Location' == substr($value, 0, 8)) { + $this->_isRedirect = true; + } + $this->_headersRaw[] = (string) $value; + return $this; + } + + /** + * Retrieve all {@link setRawHeader() raw HTTP headers} + * + * @return array + */ + public function getRawHeaders() + { + return $this->_headersRaw; + } + + /** + * Clear all {@link setRawHeader() raw HTTP headers} + * + * @return Zend_Controller_Response_Abstract + */ + public function clearRawHeaders() + { + $this->_headersRaw = array(); + return $this; + } + + /** + * Clears the specified raw HTTP header + * + * @param string $headerRaw + * @return Zend_Controller_Response_Abstract + */ + public function clearRawHeader($headerRaw) + { + if (! count($this->_headersRaw)) { + return $this; + } + + $key = array_search($headerRaw, $this->_headersRaw); + if ($key !== false) { + unset($this->_headersRaw[$key]); + } + + return $this; + } + + /** + * Clear all headers, normal and raw + * + * @return Zend_Controller_Response_Abstract + */ + public function clearAllHeaders() + { + return $this->clearHeaders() + ->clearRawHeaders(); + } + + /** + * Set HTTP response code to use with headers + * + * @param int $code + * @return Zend_Controller_Response_Abstract + */ + public function setHttpResponseCode($code) + { + if (!is_int($code) || (100 > $code) || (599 < $code)) { + throw new Zend_Controller_Response_Exception('Invalid HTTP response code'); + } + + if ((300 <= $code) && (307 >= $code)) { + $this->_isRedirect = true; + } else { + $this->_isRedirect = false; + } + + $this->_httpResponseCode = $code; + return $this; + } + + /** + * Retrieve HTTP response code + * + * @return int + */ + public function getHttpResponseCode() + { + return $this->_httpResponseCode; + } + + /** + * Can we send headers? + * + * @param boolean $throw Whether or not to throw an exception if headers have been sent; defaults to false + * @return boolean + * @throws Zend_Controller_Response_Exception + */ + public function canSendHeaders($throw = false) + { + $ok = headers_sent($file, $line); + if ($ok && $throw && $this->headersSentThrowsException) { + throw new Zend_Controller_Response_Exception('Cannot send headers; headers already sent in ' . $file . ', line ' . $line); + } + + return !$ok; + } + + /** + * Send all headers + * + * Sends any headers specified. If an {@link setHttpResponseCode() HTTP response code} + * has been specified, it is sent with the first header. + * + * @return Zend_Controller_Response_Abstract + */ + public function sendHeaders() + { + // Only check if we can send headers if we have headers to send + if (count($this->_headersRaw) || count($this->_headers) || (200 != $this->_httpResponseCode)) { + $this->canSendHeaders(true); + } elseif (200 == $this->_httpResponseCode) { + // Haven't changed the response code, and we have no headers + return $this; + } + + $httpCodeSent = false; + + foreach ($this->_headersRaw as $header) { + if (!$httpCodeSent && $this->_httpResponseCode) { + header($header, true, $this->_httpResponseCode); + $httpCodeSent = true; + } else { + header($header); + } + } + + foreach ($this->_headers as $header) { + if (!$httpCodeSent && $this->_httpResponseCode) { + header($header['name'] . ': ' . $header['value'], $header['replace'], $this->_httpResponseCode); + $httpCodeSent = true; + } else { + header($header['name'] . ': ' . $header['value'], $header['replace']); + } + } + + if (!$httpCodeSent) { + header('HTTP/1.1 ' . $this->_httpResponseCode); + $httpCodeSent = true; + } + + return $this; + } + + /** + * Set body content + * + * If $name is not passed, or is not a string, resets the entire body and + * sets the 'default' key to $content. + * + * If $name is a string, sets the named segment in the body array to + * $content. + * + * @param string $content + * @param null|string $name + * @return Zend_Controller_Response_Abstract + */ + public function setBody($content, $name = null) + { + if ((null === $name) || !is_string($name)) { + $this->_body = array('default' => (string) $content); + } else { + $this->_body[$name] = (string) $content; + } + + return $this; + } + + /** + * Append content to the body content + * + * @param string $content + * @param null|string $name + * @return Zend_Controller_Response_Abstract + */ + public function appendBody($content, $name = null) + { + if ((null === $name) || !is_string($name)) { + if (isset($this->_body['default'])) { + $this->_body['default'] .= (string) $content; + } else { + return $this->append('default', $content); + } + } elseif (isset($this->_body[$name])) { + $this->_body[$name] .= (string) $content; + } else { + return $this->append($name, $content); + } + + return $this; + } + + /** + * Clear body array + * + * With no arguments, clears the entire body array. Given a $name, clears + * just that named segment; if no segment matching $name exists, returns + * false to indicate an error. + * + * @param string $name Named segment to clear + * @return boolean + */ + public function clearBody($name = null) + { + if (null !== $name) { + $name = (string) $name; + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + return true; + } + + return false; + } + + $this->_body = array(); + return true; + } + + /** + * Return the body content + * + * If $spec is false, returns the concatenated values of the body content + * array. If $spec is boolean true, returns the body content array. If + * $spec is a string and matches a named segment, returns the contents of + * that segment; otherwise, returns null. + * + * @param boolean $spec + * @return string|array|null + */ + public function getBody($spec = false) + { + if (false === $spec) { + ob_start(); + $this->outputBody(); + return ob_get_clean(); + } elseif (true === $spec) { + return $this->_body; + } elseif (is_string($spec) && isset($this->_body[$spec])) { + return $this->_body[$spec]; + } + + return null; + } + + /** + * Append a named body segment to the body content array + * + * If segment already exists, replaces with $content and places at end of + * array. + * + * @param string $name + * @param string $content + * @return Zend_Controller_Response_Abstract + */ + public function append($name, $content) + { + if (!is_string($name)) { + throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")'); + } + + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + } + $this->_body[$name] = (string) $content; + return $this; + } + + /** + * Prepend a named body segment to the body content array + * + * If segment already exists, replaces with $content and places at top of + * array. + * + * @param string $name + * @param string $content + * @return void + */ + public function prepend($name, $content) + { + if (!is_string($name)) { + throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")'); + } + + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + } + + $new = array($name => (string) $content); + $this->_body = $new + $this->_body; + + return $this; + } + + /** + * Insert a named segment into the body content array + * + * @param string $name + * @param string $content + * @param string $parent + * @param boolean $before Whether to insert the new segment before or + * after the parent. Defaults to false (after) + * @return Zend_Controller_Response_Abstract + */ + public function insert($name, $content, $parent = null, $before = false) + { + if (!is_string($name)) { + throw new Zend_Controller_Response_Exception('Invalid body segment key ("' . gettype($name) . '")'); + } + + if ((null !== $parent) && !is_string($parent)) { + throw new Zend_Controller_Response_Exception('Invalid body segment parent key ("' . gettype($parent) . '")'); + } + + if (isset($this->_body[$name])) { + unset($this->_body[$name]); + } + + if ((null === $parent) || !isset($this->_body[$parent])) { + return $this->append($name, $content); + } + + $ins = array($name => (string) $content); + $keys = array_keys($this->_body); + $loc = array_search($parent, $keys); + if (!$before) { + // Increment location if not inserting before + ++$loc; + } + + if (0 === $loc) { + // If location of key is 0, we're prepending + $this->_body = $ins + $this->_body; + } elseif ($loc >= (count($this->_body))) { + // If location of key is maximal, we're appending + $this->_body = $this->_body + $ins; + } else { + // Otherwise, insert at location specified + $pre = array_slice($this->_body, 0, $loc); + $post = array_slice($this->_body, $loc); + $this->_body = $pre + $ins + $post; + } + + return $this; + } + + /** + * Echo the body segments + * + * @return void + */ + public function outputBody() + { + $body = implode('', $this->_body); + echo $body; + } + + /** + * Register an exception with the response + * + * @param Exception $e + * @return Zend_Controller_Response_Abstract + */ + public function setException(Exception $e) + { + $this->_exceptions[] = $e; + return $this; + } + + /** + * Retrieve the exception stack + * + * @return array + */ + public function getException() + { + return $this->_exceptions; + } + + /** + * Has an exception been registered with the response? + * + * @return boolean + */ + public function isException() + { + return !empty($this->_exceptions); + } + + /** + * Does the response object contain an exception of a given type? + * + * @param string $type + * @return boolean + */ + public function hasExceptionOfType($type) + { + foreach ($this->_exceptions as $e) { + if ($e instanceof $type) { + return true; + } + } + + return false; + } + + /** + * Does the response object contain an exception with a given message? + * + * @param string $message + * @return boolean + */ + public function hasExceptionOfMessage($message) + { + foreach ($this->_exceptions as $e) { + if ($message == $e->getMessage()) { + return true; + } + } + + return false; + } + + /** + * Does the response object contain an exception with a given code? + * + * @param int $code + * @return boolean + */ + public function hasExceptionOfCode($code) + { + $code = (int) $code; + foreach ($this->_exceptions as $e) { + if ($code == $e->getCode()) { + return true; + } + } + + return false; + } + + /** + * Retrieve all exceptions of a given type + * + * @param string $type + * @return false|array + */ + public function getExceptionByType($type) + { + $exceptions = array(); + foreach ($this->_exceptions as $e) { + if ($e instanceof $type) { + $exceptions[] = $e; + } + } + + if (empty($exceptions)) { + $exceptions = false; + } + + return $exceptions; + } + + /** + * Retrieve all exceptions of a given message + * + * @param string $message + * @return false|array + */ + public function getExceptionByMessage($message) + { + $exceptions = array(); + foreach ($this->_exceptions as $e) { + if ($message == $e->getMessage()) { + $exceptions[] = $e; + } + } + + if (empty($exceptions)) { + $exceptions = false; + } + + return $exceptions; + } + + /** + * Retrieve all exceptions of a given code + * + * @param mixed $code + * @return void + */ + public function getExceptionByCode($code) + { + $code = (int) $code; + $exceptions = array(); + foreach ($this->_exceptions as $e) { + if ($code == $e->getCode()) { + $exceptions[] = $e; + } + } + + if (empty($exceptions)) { + $exceptions = false; + } + + return $exceptions; + } + + /** + * Whether or not to render exceptions (off by default) + * + * If called with no arguments or a null argument, returns the value of the + * flag; otherwise, sets it and returns the current value. + * + * @param boolean $flag Optional + * @return boolean + */ + public function renderExceptions($flag = null) + { + if (null !== $flag) { + $this->_renderExceptions = $flag ? true : false; + } + + return $this->_renderExceptions; + } + + /** + * Send the response, including all headers, rendering exceptions if so + * requested. + * + * @return void + */ + public function sendResponse() + { + $this->sendHeaders(); + + if ($this->isException() && $this->renderExceptions()) { + $exceptions = ''; + foreach ($this->getException() as $e) { + $exceptions .= $e->__toString() . "\n"; + } + echo $exceptions; + return; + } + + $this->outputBody(); + } + + /** + * Magic __toString functionality + * + * Proxies to {@link sendResponse()} and returns response value as string + * using output buffering. + * + * @return string + */ + public function __toString() + { + ob_start(); + $this->sendResponse(); + return ob_get_clean(); + } +} diff --git a/library/vendor/Zend/Controller/Response/Cli.php b/library/vendor/Zend/Controller/Response/Cli.php new file mode 100644 index 000000000..5a2fab4e5 --- /dev/null +++ b/library/vendor/Zend/Controller/Response/Cli.php @@ -0,0 +1,67 @@ +isException() && $this->renderExceptions()) { + $exceptions = ''; + foreach ($this->getException() as $e) { + $exceptions .= $e->__toString() . "\n"; + } + return $exceptions; + } + + return $this->_body; + } +} diff --git a/library/vendor/Zend/Controller/Response/Exception.php b/library/vendor/Zend/Controller/Response/Exception.php new file mode 100644 index 000000000..9f1d424ce --- /dev/null +++ b/library/vendor/Zend/Controller/Response/Exception.php @@ -0,0 +1,35 @@ +_headersRaw as $header) { + $headers[] = $header; + } + foreach ($this->_headers as $header) { + $name = $header['name']; + $key = strtolower($name); + if (array_key_exists($name, $headers)) { + if ($header['replace']) { + $headers[$key] = $header['name'] . ': ' . $header['value']; + } + } else { + $headers[$key] = $header['name'] . ': ' . $header['value']; + } + } + return $headers; + } + + /** + * Can we send headers? + * + * @param bool $throw + * @return void + */ + public function canSendHeaders($throw = false) + { + return true; + } + + /** + * Return the concatenated body segments + * + * @return string + */ + public function outputBody() + { + $fullContent = ''; + foreach ($this->_body as $content) { + $fullContent .= $content; + } + return $fullContent; + } + + /** + * Get body and/or body segments + * + * @param bool|string $spec + * @return string|array|null + */ + public function getBody($spec = false) + { + if (false === $spec) { + return $this->outputBody(); + } elseif (true === $spec) { + return $this->_body; + } elseif (is_string($spec) && isset($this->_body[$spec])) { + return $this->_body[$spec]; + } + + return null; + } + + /** + * "send" Response + * + * Concats all response headers, and then final body (separated by two + * newlines) + * + * @return string + */ + public function sendResponse() + { + $headers = $this->sendHeaders(); + $content = implode("\n", $headers) . "\n\n"; + + if ($this->isException() && $this->renderExceptions()) { + $exceptions = ''; + foreach ($this->getException() as $e) { + $exceptions .= $e->__toString() . "\n"; + } + $content .= $exceptions; + } else { + $content .= $this->outputBody(); + } + + return $content; + } +} diff --git a/library/vendor/Zend/Controller/Router/Abstract.php b/library/vendor/Zend/Controller/Router/Abstract.php new file mode 100644 index 000000000..19681ce12 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Abstract.php @@ -0,0 +1,173 @@ +setParams($params); + } + + /** + * Add or modify a parameter to use when instantiating an action controller + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Router + */ + public function setParam($name, $value) + { + $name = (string) $name; + $this->_invokeParams[$name] = $value; + return $this; + } + + /** + * Set parameters to pass to action controller constructors + * + * @param array $params + * @return Zend_Controller_Router + */ + public function setParams(array $params) + { + $this->_invokeParams = array_merge($this->_invokeParams, $params); + return $this; + } + + /** + * Retrieve a single parameter from the controller parameter stack + * + * @param string $name + * @return mixed + */ + public function getParam($name) + { + if(isset($this->_invokeParams[$name])) { + return $this->_invokeParams[$name]; + } + + return null; + } + + /** + * Retrieve action controller instantiation parameters + * + * @return array + */ + public function getParams() + { + return $this->_invokeParams; + } + + /** + * Clear the controller parameter stack + * + * By default, clears all parameters. If a parameter name is given, clears + * only that parameter; if an array of parameter names is provided, clears + * each. + * + * @param null|string|array single key or array of keys for params to clear + * @return Zend_Controller_Router + */ + public function clearParams($name = null) + { + if (null === $name) { + $this->_invokeParams = array(); + } elseif (is_string($name) && isset($this->_invokeParams[$name])) { + unset($this->_invokeParams[$name]); + } elseif (is_array($name)) { + foreach ($name as $key) { + if (is_string($key) && isset($this->_invokeParams[$key])) { + unset($this->_invokeParams[$key]); + } + } + } + + return $this; + } + + /** + * Retrieve Front Controller + * + * @return Zend_Controller_Front + */ + public function getFrontController() + { + // Used cache version if found + if (null !== $this->_frontController) { + return $this->_frontController; + } + + $this->_frontController = Zend_Controller_Front::getInstance(); + return $this->_frontController; + } + + /** + * Set Front Controller + * + * @param Zend_Controller_Front $controller + * @return Zend_Controller_Router_Interface + */ + public function setFrontController(Zend_Controller_Front $controller) + { + $this->_frontController = $controller; + return $this; + } + +} diff --git a/library/vendor/Zend/Controller/Router/Exception.php b/library/vendor/Zend/Controller/Router/Exception.php new file mode 100644 index 000000000..cb11aa430 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Exception.php @@ -0,0 +1,35 @@ +hasRoute('default')) { + $dispatcher = $this->getFrontController()->getDispatcher(); + $request = $this->getFrontController()->getRequest(); + + $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request); + + $this->_routes = array('default' => $compat) + $this->_routes; + } + + return $this; + } + + /** + * Add route to the route chain + * + * If route contains method setRequest(), it is initialized with a request object + * + * @param string $name Name of the route + * @param Zend_Controller_Router_Route_Interface $route Instance of the route + * @return Zend_Controller_Router_Rewrite + */ + public function addRoute($name, Zend_Controller_Router_Route_Interface $route) + { + if (method_exists($route, 'setRequest')) { + $route->setRequest($this->getFrontController()->getRequest()); + } + + $this->_routes[$name] = $route; + + return $this; + } + + /** + * Add routes to the route chain + * + * @param array $routes Array of routes with names as keys and routes as values + * @return Zend_Controller_Router_Rewrite + */ + public function addRoutes($routes) { + foreach ($routes as $name => $route) { + $this->addRoute($name, $route); + } + + return $this; + } + + /** + * Create routes out of Zend_Config configuration + * + * Example INI: + * routes.archive.route = "archive/:year/*" + * routes.archive.defaults.controller = archive + * routes.archive.defaults.action = show + * routes.archive.defaults.year = 2000 + * routes.archive.reqs.year = "\d+" + * + * routes.news.type = "Zend_Controller_Router_Route_Static" + * routes.news.route = "news" + * routes.news.defaults.controller = "news" + * routes.news.defaults.action = "list" + * + * And finally after you have created a Zend_Config with above ini: + * $router = new Zend_Controller_Router_Rewrite(); + * $router->addConfig($config, 'routes'); + * + * @param Zend_Config $config Configuration object + * @param string $section Name of the config section containing route's definitions + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Rewrite + */ + public function addConfig(Zend_Config $config, $section = null) + { + if ($section !== null) { + if ($config->{$section} === null) { + throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'"); + } + + $config = $config->{$section}; + } + + foreach ($config as $name => $info) { + $route = $this->_getRouteFromConfig($info); + + if ($route instanceof Zend_Controller_Router_Route_Chain) { + if (!isset($info->chain)) { + throw new Zend_Controller_Router_Exception("No chain defined"); + } + + if ($info->chain instanceof Zend_Config) { + $childRouteNames = $info->chain; + } else { + $childRouteNames = explode(',', $info->chain); + } + + foreach ($childRouteNames as $childRouteName) { + $childRoute = $this->getRoute(trim($childRouteName)); + $route->chain($childRoute); + } + + $this->addRoute($name, $route); + } elseif (isset($info->chains) && $info->chains instanceof Zend_Config) { + $this->_addChainRoutesFromConfig($name, $route, $info->chains); + } else { + $this->addRoute($name, $route); + } + } + + return $this; + } + + /** + * Get a route frm a config instance + * + * @param Zend_Config $info + * @return Zend_Controller_Router_Route_Interface + */ + protected function _getRouteFromConfig(Zend_Config $info) + { + $class = (isset($info->type)) ? $info->type : 'Zend_Controller_Router_Route'; + if (!class_exists($class)) { + Zend_Loader::loadClass($class); + } + + $route = call_user_func(array($class, 'getInstance'), $info); + + if (isset($info->abstract) && $info->abstract && method_exists($route, 'isAbstract')) { + $route->isAbstract(true); + } + + return $route; + } + + /** + * Add chain routes from a config route + * + * @param string $name + * @param Zend_Controller_Router_Route_Interface $route + * @param Zend_Config $childRoutesInfo + * @return void + */ + protected function _addChainRoutesFromConfig($name, + Zend_Controller_Router_Route_Interface $route, + Zend_Config $childRoutesInfo) + { + foreach ($childRoutesInfo as $childRouteName => $childRouteInfo) { + if (is_string($childRouteInfo)) { + $childRouteName = $childRouteInfo; + $childRoute = $this->getRoute($childRouteName); + } else { + $childRoute = $this->_getRouteFromConfig($childRouteInfo); + } + + if ($route instanceof Zend_Controller_Router_Route_Chain) { + $chainRoute = clone $route; + $chainRoute->chain($childRoute); + } else { + $chainRoute = $route->chain($childRoute); + } + + $chainName = $name . $this->_chainNameSeparator . $childRouteName; + + if (isset($childRouteInfo->chains)) { + $this->_addChainRoutesFromConfig($chainName, $chainRoute, $childRouteInfo->chains); + } else { + $this->addRoute($chainName, $chainRoute); + } + } + } + + /** + * Remove a route from the route chain + * + * @param string $name Name of the route + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Rewrite + */ + public function removeRoute($name) + { + if (!isset($this->_routes[$name])) { + throw new Zend_Controller_Router_Exception("Route $name is not defined"); + } + + unset($this->_routes[$name]); + + return $this; + } + + /** + * Remove all standard default routes + * + * @param Zend_Controller_Router_Route_Interface Route + * @return Zend_Controller_Router_Rewrite + */ + public function removeDefaultRoutes() + { + $this->_useDefaultRoutes = false; + + return $this; + } + + /** + * Check if named route exists + * + * @param string $name Name of the route + * @return boolean + */ + public function hasRoute($name) + { + return isset($this->_routes[$name]); + } + + /** + * Retrieve a named route + * + * @param string $name Name of the route + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Route_Interface Route object + */ + public function getRoute($name) + { + if (!isset($this->_routes[$name])) { + throw new Zend_Controller_Router_Exception("Route $name is not defined"); + } + + return $this->_routes[$name]; + } + + /** + * Retrieve a currently matched route + * + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Route_Interface Route object + */ + public function getCurrentRoute() + { + if (!isset($this->_currentRoute)) { + throw new Zend_Controller_Router_Exception("Current route is not defined"); + } + return $this->getRoute($this->_currentRoute); + } + + /** + * Retrieve a name of currently matched route + * + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Router_Route_Interface Route object + */ + public function getCurrentRouteName() + { + if (!isset($this->_currentRoute)) { + throw new Zend_Controller_Router_Exception("Current route is not defined"); + } + return $this->_currentRoute; + } + + /** + * Retrieve an array of routes added to the route chain + * + * @return array All of the defined routes + */ + public function getRoutes() + { + return $this->_routes; + } + + /** + * Find a matching route to the current PATH_INFO and inject + * returning values to the Request object. + * + * @throws Zend_Controller_Router_Exception + * @return Zend_Controller_Request_Abstract Request object + */ + public function route(Zend_Controller_Request_Abstract $request) + { + if (!$request instanceof Zend_Controller_Request_Http) { + throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object'); + } + + if ($this->_useDefaultRoutes) { + $this->addDefaultRoutes(); + } + + // Find the matching route + $routeMatched = false; + + foreach (array_reverse($this->_routes, true) as $name => $route) { + // TODO: Should be an interface method. Hack for 1.0 BC + if (method_exists($route, 'isAbstract') && $route->isAbstract()) { + continue; + } + + // TODO: Should be an interface method. Hack for 1.0 BC + if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) { + $match = $request->getPathInfo(); + } else { + $match = $request; + } + + if ($params = $route->match($match)) { + $this->_setRequestParams($request, $params); + $this->_currentRoute = $name; + $routeMatched = true; + break; + } + } + + if (!$routeMatched) { + throw new Zend_Controller_Router_Exception('No route matched the request', 404); + } + + if($this->_useCurrentParamsAsGlobal) { + $params = $request->getParams(); + foreach($params as $param => $value) { + $this->setGlobalParam($param, $value); + } + } + + return $request; + + } + + protected function _setRequestParams($request, $params) + { + foreach ($params as $param => $value) { + + $request->setParam($param, $value); + + if ($param === $request->getModuleKey()) { + $request->setModuleName($value); + } + if ($param === $request->getControllerKey()) { + $request->setControllerName($value); + } + if ($param === $request->getActionKey()) { + $request->setActionName($value); + } + + } + } + + /** + * Generates a URL path that can be used in URL creation, redirection, etc. + * + * @param array $userParams Options passed by a user used to override parameters + * @param mixed $name The name of a Route to use + * @param bool $reset Whether to reset to the route defaults ignoring URL params + * @param bool $encode Tells to encode URL parts on output + * @throws Zend_Controller_Router_Exception + * @return string Resulting absolute URL path + */ + public function assemble($userParams, $name = null, $reset = false, $encode = true) + { + if (!is_array($userParams)) { + throw new Zend_Controller_Router_Exception('userParams must be an array'); + } + + if ($name == null) { + try { + $name = $this->getCurrentRouteName(); + } catch (Zend_Controller_Router_Exception $e) { + $name = 'default'; + } + } + + // Use UNION (+) in order to preserve numeric keys + $params = $userParams + $this->_globalParams; + + $route = $this->getRoute($name); + $url = $route->assemble($params, $reset, $encode); + + if (!preg_match('|^[a-z]+://|', $url)) { + $url = rtrim($this->getFrontController()->getBaseUrl(), self::URI_DELIMITER) . self::URI_DELIMITER . $url; + } + + return $url; + } + + /** + * Set a global parameter + * + * @param string $name + * @param mixed $value + * @return Zend_Controller_Router_Rewrite + */ + public function setGlobalParam($name, $value) + { + $this->_globalParams[$name] = $value; + + return $this; + } + + /** + * Set the separator to use with chain names + * + * @param string $separator The separator to use + * @return Zend_Controller_Router_Rewrite + */ + public function setChainNameSeparator($separator) { + $this->_chainNameSeparator = $separator; + + return $this; + } + + /** + * Get the separator to use for chain names + * + * @return string + */ + public function getChainNameSeparator() { + return $this->_chainNameSeparator; + } + + /** + * Determines/returns whether to use the request parameters as global parameters. + * + * @param boolean|null $use + * Null/unset when you want to retrieve the current state. + * True when request parameters should be global, false otherwise + * @return boolean|Zend_Controller_Router_Rewrite + * Returns a boolean if first param isn't set, returns an + * instance of Zend_Controller_Router_Rewrite otherwise. + * + */ + public function useRequestParametersAsGlobal($use = null) { + if($use === null) { + return $this->_useCurrentParamsAsGlobal; + } + + $this->_useCurrentParamsAsGlobal = (bool) $use; + + return $this; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route.php b/library/vendor/Zend/Controller/Router/Route.php new file mode 100644 index 000000000..602077e1a --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route.php @@ -0,0 +1,559 @@ +reqs instanceof Zend_Config) ? $config->reqs->toArray() : array(); + $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + return new self($config->route, $defs, $reqs); + } + + /** + * Prepares the route for mapping by splitting (exploding) it + * to a corresponding atomic parts. These parts are assigned + * a position which is later used for matching and preparing values. + * + * @param string $route Map used to match with later submitted URL path + * @param array $defaults Defaults for map variables with keys as variable names + * @param array $reqs Regular expression requirements for variables (keys as variable names) + * @param Zend_Translate $translator Translator to use for this instance + */ + public function __construct($route, $defaults = array(), $reqs = array(), Zend_Translate $translator = null, $locale = null) + { + $route = trim($route, $this->_urlDelimiter); + $this->_defaults = (array) $defaults; + $this->_requirements = (array) $reqs; + $this->_translator = $translator; + $this->_locale = $locale; + + if ($route !== '') { + foreach (explode($this->_urlDelimiter, $route) as $pos => $part) { + if (substr($part, 0, 1) == $this->_urlVariable && substr($part, 1, 1) != $this->_urlVariable) { + $name = substr($part, 1); + + if (substr($name, 0, 1) === '@' && substr($name, 1, 1) !== '@') { + $name = substr($name, 1); + $this->_translatable[] = $name; + $this->_isTranslated = true; + } + + $this->_parts[$pos] = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex); + $this->_variables[$pos] = $name; + } else { + if (substr($part, 0, 1) == $this->_urlVariable) { + $part = substr($part, 1); + } + + if (substr($part, 0, 1) === '@' && substr($part, 1, 1) !== '@') { + $this->_isTranslated = true; + } + + $this->_parts[$pos] = $part; + + if ($part !== '*') { + $this->_staticCount++; + } + } + } + } + } + + /** + * Matches a user submitted path with parts defined by a map. Assigns and + * returns an array of variables on a successful match. + * + * @param string $path Path used to match against this routing map + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + if ($this->_isTranslated) { + $translateMessages = $this->getTranslator()->getMessages(); + } + + $pathStaticCount = 0; + $values = array(); + $matchedPath = ''; + + if (!$partial) { + $path = trim($path, $this->_urlDelimiter); + } + + if ($path !== '') { + $path = explode($this->_urlDelimiter, $path); + + foreach ($path as $pos => $pathPart) { + // Path is longer than a route, it's not a match + if (!array_key_exists($pos, $this->_parts)) { + if ($partial) { + break; + } else { + return false; + } + } + + $matchedPath .= $pathPart . $this->_urlDelimiter; + + // If it's a wildcard, get the rest of URL as wildcard data and stop matching + if ($this->_parts[$pos] == '*') { + $count = count($path); + for($i = $pos; $i < $count; $i+=2) { + $var = urldecode($path[$i]); + if (!isset($this->_wildcardData[$var]) && !isset($this->_defaults[$var]) && !isset($values[$var])) { + $this->_wildcardData[$var] = (isset($path[$i+1])) ? urldecode($path[$i+1]) : null; + } + } + + $matchedPath = implode($this->_urlDelimiter, $path); + break; + } + + $name = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null; + $pathPart = urldecode($pathPart); + + // Translate value if required + $part = $this->_parts[$pos]; + if ($this->_isTranslated && (substr($part, 0, 1) === '@' && substr($part, 1, 1) !== '@' && $name === null) || $name !== null && in_array($name, $this->_translatable)) { + if (substr($part, 0, 1) === '@') { + $part = substr($part, 1); + } + + if (($originalPathPart = array_search($pathPart, $translateMessages)) !== false) { + $pathPart = $originalPathPart; + } + } + + if (substr($part, 0, 2) === '@@') { + $part = substr($part, 1); + } + + // If it's a static part, match directly + if ($name === null && $part != $pathPart) { + return false; + } + + // If it's a variable with requirement, match a regex. If not - everything matches + if ($part !== null && !preg_match($this->_regexDelimiter . '^' . $part . '$' . $this->_regexDelimiter . 'iu', $pathPart)) { + return false; + } + + // If it's a variable store it's value for later + if ($name !== null) { + $values[$name] = $pathPart; + } else { + $pathStaticCount++; + } + } + } + + // Check if all static mappings have been matched + if ($this->_staticCount != $pathStaticCount) { + return false; + } + + $return = $values + $this->_wildcardData + $this->_defaults; + + // Check if all map variables have been initialized + foreach ($this->_variables as $var) { + if (!array_key_exists($var, $return)) { + return false; + } elseif ($return[$var] == '' || $return[$var] === null) { + // Empty variable? Replace with the default value. + $return[$var] = $this->_defaults[$var]; + } + } + + $this->setMatchedPath(rtrim($matchedPath, $this->_urlDelimiter)); + + $this->_values = $values; + + return $return; + + } + + /** + * Assembles user submitted parameters forming a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param boolean $reset Whether or not to set route defaults with those provided in $data + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + if ($this->_isTranslated) { + $translator = $this->getTranslator(); + + if (isset($data['@locale'])) { + $locale = $data['@locale']; + unset($data['@locale']); + } else { + $locale = $this->getLocale(); + } + } + + $url = array(); + $flag = false; + + foreach ($this->_parts as $key => $part) { + $name = isset($this->_variables[$key]) ? $this->_variables[$key] : null; + + $useDefault = false; + if (isset($name) && array_key_exists($name, $data) && $data[$name] === null) { + $useDefault = true; + } + + if (isset($name)) { + if (isset($data[$name]) && !$useDefault) { + $value = $data[$name]; + unset($data[$name]); + } elseif (!$reset && !$useDefault && isset($this->_values[$name])) { + $value = $this->_values[$name]; + } elseif (!$reset && !$useDefault && isset($this->_wildcardData[$name])) { + $value = $this->_wildcardData[$name]; + } elseif (array_key_exists($name, $this->_defaults)) { + $value = $this->_defaults[$name]; + } else { + throw new Zend_Controller_Router_Exception($name . ' is not specified'); + } + + if ($this->_isTranslated && in_array($name, $this->_translatable)) { + $url[$key] = $translator->translate($value, $locale); + } else { + $url[$key] = $value; + } + } elseif ($part != '*') { + if ($this->_isTranslated && substr($part, 0, 1) === '@') { + if (substr($part, 1, 1) !== '@') { + $url[$key] = $translator->translate(substr($part, 1), $locale); + } else { + $url[$key] = substr($part, 1); + } + } else { + if (substr($part, 0, 2) === '@@') { + $part = substr($part, 1); + } + + $url[$key] = $part; + } + } else { + if (!$reset) $data += $this->_wildcardData; + $defaults = $this->getDefaults(); + foreach ($data as $var => $value) { + if ($value !== null && (!isset($defaults[$var]) || $value != $defaults[$var])) { + $url[$key++] = $var; + $url[$key++] = $value; + $flag = true; + } + } + } + } + + $return = ''; + + foreach (array_reverse($url, true) as $key => $value) { + $defaultValue = null; + + if (isset($this->_variables[$key])) { + $defaultValue = $this->getDefault($this->_variables[$key]); + + if ($this->_isTranslated && $defaultValue !== null && isset($this->_translatable[$this->_variables[$key]])) { + $defaultValue = $translator->translate($defaultValue, $locale); + } + } + + if ($flag || $value !== $defaultValue || $partial) { + if ($encode) $value = urlencode($value); + $return = $this->_urlDelimiter . $value . $return; + $flag = true; + } + } + + return trim($return, $this->_urlDelimiter); + + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + return null; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() { + return $this->_defaults; + } + + /** + * Get all variables which are used by the route + * + * @return array + */ + public function getVariables() + { + return $this->_variables; + } + + /** + * Set a default translator + * + * @param Zend_Translate $translator + * @return void + */ + public static function setDefaultTranslator(Zend_Translate $translator = null) + { + self::$_defaultTranslator = $translator; + } + + /** + * Get the default translator + * + * @return Zend_Translate + */ + public static function getDefaultTranslator() + { + return self::$_defaultTranslator; + } + + /** + * Set a translator + * + * @param Zend_Translate $translator + * @return void + */ + public function setTranslator(Zend_Translate $translator) + { + $this->_translator = $translator; + } + + /** + * Get the translator + * + * @throws Zend_Controller_Router_Exception When no translator can be found + * @return Zend_Translate + */ + public function getTranslator() + { + if ($this->_translator !== null) { + return $this->_translator; + } else if (($translator = self::getDefaultTranslator()) !== null) { + return $translator; + } else { + try { + $translator = Zend_Registry::get('Zend_Translate'); + } catch (Zend_Exception $e) { + $translator = null; + } + + if ($translator instanceof Zend_Translate) { + return $translator; + } + } + + throw new Zend_Controller_Router_Exception('Could not find a translator'); + } + + /** + * Set a default locale + * + * @param mixed $locale + * @return void + */ + public static function setDefaultLocale($locale = null) + { + self::$_defaultLocale = $locale; + } + + /** + * Get the default locale + * + * @return mixed + */ + public static function getDefaultLocale() + { + return self::$_defaultLocale; + } + + /** + * Set a locale + * + * @param mixed $locale + * @return void + */ + public function setLocale($locale) + { + $this->_locale = $locale; + } + + /** + * Get the locale + * + * @return mixed + */ + public function getLocale() + { + if ($this->_locale !== null) { + return $this->_locale; + } else if (($locale = self::getDefaultLocale()) !== null) { + return $locale; + } else { + try { + $locale = Zend_Registry::get('Zend_Locale'); + } catch (Zend_Exception $e) { + $locale = null; + } + + if ($locale !== null) { + return $locale; + } + } + + return null; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Abstract.php b/library/vendor/Zend/Controller/Router/Route/Abstract.php new file mode 100644 index 000000000..f5dde64f8 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Abstract.php @@ -0,0 +1,120 @@ +_matchedPath = $path; + } + + /** + * Get partially matched path + * + * @return string + */ + public function getMatchedPath() + { + return $this->_matchedPath; + } + + /** + * Check or set wether this is an abstract route or not + * + * @param boolean $flag + * @return boolean + */ + public function isAbstract($flag = null) + { + if ($flag !== null) { + $this->_isAbstract = $flag; + } + + return $this->_isAbstract; + } + + /** + * Create a new chain + * + * @param Zend_Controller_Router_Route_Abstract $route + * @param string $separator + * @return Zend_Controller_Router_Route_Chain + */ + public function chain(Zend_Controller_Router_Route_Abstract $route, $separator = '/') + { + + $chain = new Zend_Controller_Router_Route_Chain(); + $chain->chain($this)->chain($route, $separator); + + return $chain; + } + +} diff --git a/library/vendor/Zend/Controller/Router/Route/Chain.php b/library/vendor/Zend/Controller/Router/Route/Chain.php new file mode 100644 index 000000000..cb115ab06 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Chain.php @@ -0,0 +1,215 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + return new self($config->route, $defs); + } + + /** + * Add a route to this chain + * + * @param Zend_Controller_Router_Route_Abstract $route + * @param string $separator + * @return Zend_Controller_Router_Route_Chain + */ + public function chain(Zend_Controller_Router_Route_Abstract $route, $separator = self::URI_DELIMITER) + { + $this->_routes[] = $route; + $this->_separators[] = $separator; + + return $this; + + } + + /** + * Matches a user submitted path with a previously defined route. + * Assigns and returns an array of defaults on a successful match. + * + * @param Zend_Controller_Request_Http $request Request to get the path info from + * @param null $partial + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($request, $partial = null) + { + $path = trim($request->getPathInfo(), self::URI_DELIMITER); + $subPath = $path; + $values = array(); + $numRoutes = count($this->_routes); + $matchedPath = null; + + foreach ($this->_routes as $key => $route) { + if ($key > 0 + && $matchedPath !== null + && $subPath !== '' + && $subPath !== false + ) { + $separator = substr($subPath, 0, strlen($this->_separators[$key])); + + if ($separator !== $this->_separators[$key]) { + return false; + } + + $subPath = substr($subPath, strlen($separator)); + } + + // TODO: Should be an interface method. Hack for 1.0 BC + if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) { + $match = $subPath; + } else { + $request->setPathInfo($subPath); + $match = $request; + } + + $res = $route->match($match, true, ($key == $numRoutes - 1)); + if ($res === false) { + return false; + } + + $matchedPath = $route->getMatchedPath(); + + if ($matchedPath !== null) { + $subPath = substr($subPath, strlen($matchedPath)); + $separator = substr($subPath, 0, strlen($this->_separators[$key])); + } + + $values = $res + $values; + } + + $request->setPathInfo($path); + + if ($subPath !== '' && $subPath !== false) { + return false; + } + + return $values; + } + + /** + * Assembles a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param bool $reset + * @param bool $encode + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false) + { + $value = ''; + $numRoutes = count($this->_routes); + + foreach ($this->_routes as $key => $route) { + if ($key > 0) { + $value .= $this->_separators[$key]; + } + + $value .= $route->assemble($data, $reset, $encode, (($numRoutes - 1) > $key)); + + if (method_exists($route, 'getVariables')) { + $variables = $route->getVariables(); + + foreach ($variables as $variable) { + $data[$variable] = null; + } + } + } + + return $value; + } + + /** + * Set the request object for this and the child routes + * + * @param Zend_Controller_Request_Abstract|null $request + * @return void + */ + public function setRequest(Zend_Controller_Request_Abstract $request = null) + { + $this->_request = $request; + + foreach ($this->_routes as $route) { + if (method_exists($route, 'setRequest')) { + $route->setRequest($request); + } + } + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) + { + $default = null; + foreach ($this->_routes as $route) { + if (method_exists($route, 'getDefault')) { + $current = $route->getDefault($name); + if (null !== $current) { + $default = $current; + } + } + } + + return $default; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() + { + $defaults = array(); + foreach ($this->_routes as $route) { + if (method_exists($route, 'getDefaults')) { + $defaults = array_merge($defaults, $route->getDefaults()); + } + } + + return $defaults; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Hostname.php b/library/vendor/Zend/Controller/Router/Route/Hostname.php new file mode 100644 index 000000000..2884bc27f --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Hostname.php @@ -0,0 +1,338 @@ +_request = $request; + } + + /** + * Get the request object + * + * @return Zend_Controller_Request_Abstract $request + */ + public function getRequest() + { + if ($this->_request === null) { + $this->_request = Zend_Controller_Front::getInstance()->getRequest(); + } + + return $this->_request; + } + + /** + * Instantiates route based on passed Zend_Config structure + * + * @param Zend_Config $config Configuration object + */ + public static function getInstance(Zend_Config $config) + { + $reqs = ($config->reqs instanceof Zend_Config) ? $config->reqs->toArray() : array(); + $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + $scheme = (isset($config->scheme)) ? $config->scheme : null; + return new self($config->route, $defs, $reqs, $scheme); + } + + /** + * Prepares the route for mapping by splitting (exploding) it + * to a corresponding atomic parts. These parts are assigned + * a position which is later used for matching and preparing values. + * + * @param string $route Map used to match with later submitted hostname + * @param array $defaults Defaults for map variables with keys as variable names + * @param array $reqs Regular expression requirements for variables (keys as variable names) + * @param string $scheme + */ + public function __construct($route, $defaults = array(), $reqs = array(), $scheme = null) + { + $route = trim($route, '.'); + $this->_defaults = (array) $defaults; + $this->_requirements = (array) $reqs; + $this->_scheme = $scheme; + + if ($route != '') { + foreach (explode('.', $route) as $pos => $part) { + if (substr($part, 0, 1) == $this->_hostVariable) { + $name = substr($part, 1); + $this->_parts[$pos] = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex); + $this->_variables[$pos] = $name; + } else { + $this->_parts[$pos] = $part; + $this->_staticCount++; + } + } + } + } + + /** + * Matches a user submitted path with parts defined by a map. Assigns and + * returns an array of variables on a successful match. + * + * @param Zend_Controller_Request_Http $request Request to get the host from + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($request) + { + // Check the scheme if required + if ($this->_scheme !== null) { + $scheme = $request->getScheme(); + + if ($scheme !== $this->_scheme) { + return false; + } + } + + // Get the host and remove unnecessary port information + $host = $request->getHttpHost(); + if (preg_match('#:\d+$#', $host, $result) === 1) { + $host = substr($host, 0, -strlen($result[0])); + } + + $hostStaticCount = 0; + $values = array(); + + $host = trim($host, '.'); + + if ($host != '') { + $host = explode('.', $host); + + foreach ($host as $pos => $hostPart) { + // Host is longer than a route, it's not a match + if (!array_key_exists($pos, $this->_parts)) { + return false; + } + + $name = isset($this->_variables[$pos]) ? $this->_variables[$pos] : null; + $hostPart = urldecode($hostPart); + + // If it's a static part, match directly + if ($name === null && $this->_parts[$pos] != $hostPart) { + return false; + } + + // If it's a variable with requirement, match a regex. If not - everything matches + if ($this->_parts[$pos] !== null && !preg_match($this->_regexDelimiter . '^' . $this->_parts[$pos] . '$' . $this->_regexDelimiter . 'iu', $hostPart)) { + return false; + } + + // If it's a variable store it's value for later + if ($name !== null) { + $values[$name] = $hostPart; + } else { + $hostStaticCount++; + } + } + } + + // Check if all static mappings have been matched + if ($this->_staticCount != $hostStaticCount) { + return false; + } + + $return = $values + $this->_defaults; + + // Check if all map variables have been initialized + foreach ($this->_variables as $var) { + if (!array_key_exists($var, $return)) { + return false; + } + } + + $this->_values = $values; + + return $return; + + } + + /** + * Assembles user submitted parameters forming a hostname defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param boolean $reset Whether or not to set route defaults with those provided in $data + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + $host = array(); + $flag = false; + + foreach ($this->_parts as $key => $part) { + $name = isset($this->_variables[$key]) ? $this->_variables[$key] : null; + + $useDefault = false; + if (isset($name) && array_key_exists($name, $data) && $data[$name] === null) { + $useDefault = true; + } + + if (isset($name)) { + if (isset($data[$name]) && !$useDefault) { + $host[$key] = $data[$name]; + unset($data[$name]); + } elseif (!$reset && !$useDefault && isset($this->_values[$name])) { + $host[$key] = $this->_values[$name]; + } elseif (isset($this->_defaults[$name])) { + $host[$key] = $this->_defaults[$name]; + } else { + throw new Zend_Controller_Router_Exception($name . ' is not specified'); + } + } else { + $host[$key] = $part; + } + } + + $return = ''; + + foreach (array_reverse($host, true) as $key => $value) { + if ($flag || !isset($this->_variables[$key]) || $value !== $this->getDefault($this->_variables[$key]) || $partial) { + if ($encode) $value = urlencode($value); + $return = '.' . $value . $return; + $flag = true; + } + } + + $url = trim($return, '.'); + + if ($this->_scheme !== null) { + $scheme = $this->_scheme; + } else { + $request = $this->getRequest(); + if ($request instanceof Zend_Controller_Request_Http) { + $scheme = $request->getScheme(); + } else { + $scheme = 'http'; + } + } + + $url = $scheme . '://' . $url; + + return $url; + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + return null; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() { + return $this->_defaults; + } + + /** + * Get all variables which are used by the route + * + * @return array + */ + public function getVariables() + { + return $this->_variables; + } +} diff --git a/library/vendor/Zend/Controller/Router/Route/Interface.php b/library/vendor/Zend/Controller/Router/Route/Interface.php new file mode 100644 index 000000000..cc2117fed --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Interface.php @@ -0,0 +1,36 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + $dispatcher = $frontController->getDispatcher(); + $request = $frontController->getRequest(); + + return new self($defs, $dispatcher, $request); + } + + /** + * Constructor + * + * @param array $defaults Defaults for map variables with keys as variable names + * @param Zend_Controller_Dispatcher_Interface $dispatcher Dispatcher object + * @param Zend_Controller_Request_Abstract $request Request object + */ + public function __construct(array $defaults = array(), + Zend_Controller_Dispatcher_Interface $dispatcher = null, + Zend_Controller_Request_Abstract $request = null) + { + $this->_defaults = $defaults; + + if (isset($request)) { + $this->_request = $request; + } + + if (isset($dispatcher)) { + $this->_dispatcher = $dispatcher; + } + } + + /** + * Set request keys based on values in request object + * + * @return void + */ + protected function _setRequestKeys() + { + if (null !== $this->_request) { + $this->_moduleKey = $this->_request->getModuleKey(); + $this->_controllerKey = $this->_request->getControllerKey(); + $this->_actionKey = $this->_request->getActionKey(); + } + + if (null !== $this->_dispatcher) { + $this->_defaults += array( + $this->_controllerKey => $this->_dispatcher->getDefaultControllerName(), + $this->_actionKey => $this->_dispatcher->getDefaultAction(), + $this->_moduleKey => $this->_dispatcher->getDefaultModule() + ); + } + + $this->_keysSet = true; + } + + /** + * Matches a user submitted path. Assigns and returns an array of variables + * on a successful match. + * + * If a request object is registered, it uses its setModuleName(), + * setControllerName(), and setActionName() accessors to set those values. + * Always returns the values as an array. + * + * @param string $path Path used to match against this routing map + * @return array An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + $this->_setRequestKeys(); + + $values = array(); + $params = array(); + + if (!$partial) { + $path = trim($path, self::URI_DELIMITER); + } else { + $matchedPath = $path; + } + + if ($path != '') { + $path = explode(self::URI_DELIMITER, $path); + + if ($this->_dispatcher && $this->_dispatcher->isValidModule($path[0])) { + $values[$this->_moduleKey] = array_shift($path); + $this->_moduleValid = true; + } + + if (count($path) && !empty($path[0])) { + $values[$this->_controllerKey] = array_shift($path); + } + + if (count($path) && !empty($path[0])) { + $values[$this->_actionKey] = array_shift($path); + } + + if ($numSegs = count($path)) { + for ($i = 0; $i < $numSegs; $i = $i + 2) { + $key = urldecode($path[$i]); + $val = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null; + $params[$key] = (isset($params[$key]) ? (array_merge((array) $params[$key], array($val))): $val); + } + } + } + + if ($partial) { + $this->setMatchedPath($matchedPath); + } + + $this->_values = $values + $params; + + return $this->_values + $this->_defaults; + } + + /** + * Assembles user submitted parameters forming a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @param bool $reset Weither to reset the current params + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = true, $partial = false) + { + if (!$this->_keysSet) { + $this->_setRequestKeys(); + } + + $params = (!$reset) ? $this->_values : array(); + + foreach ($data as $key => $value) { + if ($value !== null) { + $params[$key] = $value; + } elseif (isset($params[$key])) { + unset($params[$key]); + } + } + + $params += $this->_defaults; + + $url = ''; + + if ($this->_moduleValid || array_key_exists($this->_moduleKey, $data)) { + if ($params[$this->_moduleKey] != $this->_defaults[$this->_moduleKey]) { + $module = $params[$this->_moduleKey]; + } + } + unset($params[$this->_moduleKey]); + + $controller = $params[$this->_controllerKey]; + unset($params[$this->_controllerKey]); + + $action = $params[$this->_actionKey]; + unset($params[$this->_actionKey]); + + foreach ($params as $key => $value) { + $key = ($encode) ? urlencode($key) : $key; + if (is_array($value)) { + foreach ($value as $arrayValue) { + $arrayValue = ($encode) ? urlencode($arrayValue) : $arrayValue; + $url .= self::URI_DELIMITER . $key; + $url .= self::URI_DELIMITER . $arrayValue; + } + } else { + if ($encode) $value = urlencode($value); + $url .= self::URI_DELIMITER . $key; + $url .= self::URI_DELIMITER . $value; + } + } + + if (!empty($url) || $action !== $this->_defaults[$this->_actionKey]) { + if ($encode) $action = urlencode($action); + $url = self::URI_DELIMITER . $action . $url; + } + + if (!empty($url) || $controller !== $this->_defaults[$this->_controllerKey]) { + if ($encode) $controller = urlencode($controller); + $url = self::URI_DELIMITER . $controller . $url; + } + + if (isset($module)) { + if ($encode) $module = urlencode($module); + $url = self::URI_DELIMITER . $module . $url; + } + + return ltrim($url, self::URI_DELIMITER); + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() { + return $this->_defaults; + } + +} diff --git a/library/vendor/Zend/Controller/Router/Route/Regex.php b/library/vendor/Zend/Controller/Router/Route/Regex.php new file mode 100644 index 000000000..ec3dfcee9 --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Regex.php @@ -0,0 +1,266 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + $map = ($config->map instanceof Zend_Config) ? $config->map->toArray() : array(); + $reverse = (isset($config->reverse)) ? $config->reverse : null; + return new self($config->route, $defs, $map, $reverse); + } + + public function __construct($route, $defaults = array(), $map = array(), $reverse = null) + { + $this->_regex = $route; + $this->_defaults = (array) $defaults; + $this->_map = (array) $map; + $this->_reverse = $reverse; + } + + public function getVersion() { + return 1; + } + + /** + * Matches a user submitted path with a previously defined route. + * Assigns and returns an array of defaults on a successful match. + * + * @param string $path Path used to match against this routing map + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + if (!$partial) { + $path = trim(urldecode($path), self::URI_DELIMITER); + $regex = '#^' . $this->_regex . '$#i'; + } else { + $regex = '#^' . $this->_regex . '#i'; + } + + $res = preg_match($regex, $path, $values); + + if ($res === 0) { + return false; + } + + if ($partial) { + $this->setMatchedPath($values[0]); + } + + // array_filter_key()? Why isn't this in a standard PHP function set yet? :) + foreach ($values as $i => $value) { + if (!is_int($i) || $i === 0) { + unset($values[$i]); + } + } + + $this->_values = $values; + + $values = $this->_getMappedValues($values); + $defaults = $this->_getMappedValues($this->_defaults, false, true); + $return = $values + $defaults; + + return $return; + } + + /** + * Maps numerically indexed array values to it's associative mapped counterpart. + * Or vice versa. Uses user provided map array which consists of index => name + * parameter mapping. If map is not found, it returns original array. + * + * Method strips destination type of keys form source array. Ie. if source array is + * indexed numerically then every associative key will be stripped. Vice versa if reversed + * is set to true. + * + * @param array $values Indexed or associative array of values to map + * @param boolean $reversed False means translation of index to association. True means reverse. + * @param boolean $preserve Should wrong type of keys be preserved or stripped. + * @return array An array of mapped values + */ + protected function _getMappedValues($values, $reversed = false, $preserve = false) + { + if (count($this->_map) == 0) { + return $values; + } + + $return = array(); + + foreach ($values as $key => $value) { + if (is_int($key) && !$reversed) { + if (array_key_exists($key, $this->_map)) { + $index = $this->_map[$key]; + } elseif (false === ($index = array_search($key, $this->_map))) { + $index = $key; + } + $return[$index] = $values[$key]; + } elseif ($reversed) { + $index = $key; + if (!is_int($key)) { + if (array_key_exists($key, $this->_map)) { + $index = $this->_map[$key]; + } else { + $index = array_search($key, $this->_map, true); + } + } + if (false !== $index) { + $return[$index] = $values[$key]; + } + } elseif ($preserve) { + $return[$key] = $value; + } + } + + return $return; + } + + /** + * Assembles a URL path defined by this route + * + * @param array $data An array of name (or index) and value pairs used as parameters + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + if ($this->_reverse === null) { + throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.'); + } + + $defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false); + $matchedValuesMapped = $this->_getMappedValues($this->_values, true, false); + $dataValuesMapped = $this->_getMappedValues($data, true, false); + + // handle resets, if so requested (By null value) to do so + if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) { + foreach ((array) $resetKeys as $resetKey) { + if (isset($matchedValuesMapped[$resetKey])) { + unset($matchedValuesMapped[$resetKey]); + unset($dataValuesMapped[$resetKey]); + } + } + } + + // merge all the data together, first defaults, then values matched, then supplied + $mergedData = $defaultValuesMapped; + $mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped); + $mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped); + + if ($encode) { + foreach ($mergedData as $key => &$value) { + $value = urlencode($value); + } + } + + ksort($mergedData); + + $return = @vsprintf($this->_reverse, $mergedData); + + if ($return === false) { + throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?'); + } + + return $return; + + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() { + return $this->_defaults; + } + + /** + * Get all variables which are used by the route + * + * @return array + */ + public function getVariables() + { + $variables = array(); + + foreach ($this->_map as $key => $value) { + if (is_numeric($key)) { + $variables[] = $value; + } else { + $variables[] = $key; + } + } + + return $variables; + } + + /** + * _arrayMergeNumericKeys() - allows for a strict key (numeric's included) array_merge. + * php's array_merge() lacks the ability to merge with numeric keys. + * + * @param array $array1 + * @param array $array2 + * @return array + */ + protected function _arrayMergeNumericKeys(Array $array1, Array $array2) + { + $returnArray = $array1; + foreach ($array2 as $array2Index => $array2Value) { + $returnArray[$array2Index] = $array2Value; + } + return $returnArray; + } + + +} diff --git a/library/vendor/Zend/Controller/Router/Route/Static.php b/library/vendor/Zend/Controller/Router/Route/Static.php new file mode 100644 index 000000000..1bab7252e --- /dev/null +++ b/library/vendor/Zend/Controller/Router/Route/Static.php @@ -0,0 +1,126 @@ +defaults instanceof Zend_Config) ? $config->defaults->toArray() : array(); + return new self($config->route, $defs); + } + + /** + * Prepares the route for mapping. + * + * @param string $route Map used to match with later submitted URL path + * @param array $defaults Defaults for map variables with keys as variable names + */ + public function __construct($route, $defaults = array()) + { + $this->_route = trim($route, self::URI_DELIMITER); + $this->_defaults = (array) $defaults; + } + + /** + * Matches a user submitted path with a previously defined route. + * Assigns and returns an array of defaults on a successful match. + * + * @param string $path Path used to match against this routing map + * @return array|false An array of assigned values or a false on a mismatch + */ + public function match($path, $partial = false) + { + if ($partial) { + if ((empty($path) && empty($this->_route)) + || (substr($path, 0, strlen($this->_route)) === $this->_route) + ) { + $this->setMatchedPath($this->_route); + return $this->_defaults; + } + } else { + if (trim($path, self::URI_DELIMITER) == $this->_route) { + return $this->_defaults; + } + } + + return false; + } + + /** + * Assembles a URL path defined by this route + * + * @param array $data An array of variable and value pairs used as parameters + * @return string Route path with user submitted parameters + */ + public function assemble($data = array(), $reset = false, $encode = false, $partial = false) + { + return $this->_route; + } + + /** + * Return a single parameter of route's defaults + * + * @param string $name Array key of the parameter + * @return string Previously set default + */ + public function getDefault($name) { + if (isset($this->_defaults[$name])) { + return $this->_defaults[$name]; + } + return null; + } + + /** + * Return an array of defaults + * + * @return array Route defaults + */ + public function getDefaults() { + return $this->_defaults; + } + +} diff --git a/library/vendor/Zend/Crypt.php b/library/vendor/Zend/Crypt.php new file mode 100644 index 000000000..6ad56b7d6 --- /dev/null +++ b/library/vendor/Zend/Crypt.php @@ -0,0 +1,167 @@ +setPrime($prime); + $this->setGenerator($generator); + if ($privateKey !== null) { + $this->setPrivateKey($privateKey, $privateKeyType); + } + $this->setBigIntegerMath(); + } + + /** + * Generate own public key. If a private number has not already been + * set, one will be generated at this stage. + * + * @return Zend_Crypt_DiffieHellman + */ + public function generateKeys() + { + if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { + $details = array(); + $details['p'] = $this->getPrime(); + $details['g'] = $this->getGenerator(); + if ($this->hasPrivateKey()) { + $details['priv_key'] = $this->getPrivateKey(); + } + $opensslKeyResource = openssl_pkey_new( array('dh' => $details) ); + $data = openssl_pkey_get_details($opensslKeyResource); + $this->setPrivateKey($data['dh']['priv_key'], self::BINARY); + $this->setPublicKey($data['dh']['pub_key'], self::BINARY); + } else { + // Private key is lazy generated in the absence of PHP 5.3's ext/openssl + $publicKey = $this->_math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime()); + $this->setPublicKey($publicKey); + } + return $this; + } + + /** + * Setter for the value of the public number + * + * @param string $number + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setPublicKey($number, $type = self::NUMBER) + { + if ($type == self::BINARY) { + $number = $this->_math->fromBinary($number); + } + if (!preg_match("/^\d+$/", $number)) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + $this->_publicKey = (string) $number; + return $this; + } + + /** + * Returns own public key for communication to the second party to this + * transaction. + * + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getPublicKey($type = self::NUMBER) + { + if ($this->_publicKey === null) { + throw new Zend_Crypt_DiffieHellman_Exception('A public key has not yet been generated using a prior call to generateKeys()'); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_publicKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_publicKey)); + } + return $this->_publicKey; + } + + /** + * Compute the shared secret key based on the public key received from the + * the second party to this transaction. This should agree to the secret + * key the second party computes on our own public key. + * Once in agreement, the key is known to only to both parties. + * By default, the function expects the public key to be in binary form + * which is the typical format when being transmitted. + * + * If you need the binary form of the shared secret key, call + * getSharedSecretKey() with the optional parameter for Binary output. + * + * @param string $publicKey + * @param string $type + * @param string $output + * @throws Zend_Crypt_DiffieHellman_Exception + * @return mixed + */ + public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER) + { + if ($type == self::BINARY) { + $publicKey = $this->_math->fromBinary($publicKey); + } + if (!preg_match("/^\d+$/", $publicKey)) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { + $this->_secretKey = openssl_dh_compute_key($publicKey, $this->getPublicKey()); + } else { + $this->_secretKey = $this->_math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime()); + } + return $this->getSharedSecretKey($output); + } + + /** + * Return the computed shared secret key from the DiffieHellman transaction + * + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getSharedSecretKey($type = self::NUMBER) + { + if (!isset($this->_secretKey)) { + throw new Zend_Crypt_DiffieHellman_Exception('A secret key has not yet been computed; call computeSecretKey()'); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_secretKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_secretKey)); + } + return $this->_secretKey; + } + + /** + * Setter for the value of the prime number + * + * @param string $number + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setPrime($number) + { + if (!preg_match("/^\d+$/", $number) || $number < 11) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number or too small: should be a large natural number prime'); + } + $this->_prime = (string) $number; + return $this; + } + + /** + * Getter for the value of the prime number + * + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getPrime() + { + if (!isset($this->_prime)) { + throw new Zend_Crypt_DiffieHellman_Exception('No prime number has been set'); + } + return $this->_prime; + } + + /** + * Setter for the value of the generator number + * + * @param string $number + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setGenerator($number) + { + if (!preg_match("/^\d+$/", $number) || $number < 2) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number greater than 1'); + } + $this->_generator = (string) $number; + return $this; + } + + /** + * Getter for the value of the generator number + * + * @throws Zend_Crypt_DiffieHellman_Exception + * @return string + */ + public function getGenerator() + { + if (!isset($this->_generator)) { + throw new Zend_Crypt_DiffieHellman_Exception('No generator number has been set'); + } + return $this->_generator; + } + + /** + * Setter for the value of the private number + * + * @param string $number + * @param string $type + * @throws Zend_Crypt_DiffieHellman_Exception + * @return Zend_Crypt_DiffieHellman + */ + public function setPrivateKey($number, $type = self::NUMBER) + { + if ($type == self::BINARY) { + $number = $this->_math->fromBinary($number); + } + if (!preg_match("/^\d+$/", $number)) { + throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); + } + $this->_privateKey = (string) $number; + return $this; + } + + /** + * Getter for the value of the private number + * + * @param string $type + * @return string + */ + public function getPrivateKey($type = self::NUMBER) + { + if (!$this->hasPrivateKey()) { + $this->setPrivateKey($this->_generatePrivateKey(), self::BINARY); + } + if ($type == self::BINARY) { + return $this->_math->toBinary($this->_privateKey); + } elseif ($type == self::BTWOC) { + return $this->_math->btwoc($this->_math->toBinary($this->_privateKey)); + } + return $this->_privateKey; + } + + /** + * Check whether a private key currently exists. + * + * @return boolean + */ + public function hasPrivateKey() + { + return isset($this->_privateKey); + } + + /** + * Setter to pass an extension parameter which is used to create + * a specific BigInteger instance for a specific extension type. + * Allows manual setting of the class in case of an extension + * problem or bug. + * + * @param string $extension + * @return void + */ + public function setBigIntegerMath($extension = null) + { + /** + * @see Zend_Crypt_Math + */ + $this->_math = new Zend_Crypt_Math($extension); + } + + /** + * In the event a private number/key has not been set by the user, + * or generated by ext/openssl, a best attempt will be made to + * generate a random key. Having a random number generator installed + * on linux/bsd is highly recommended! The alternative is not recommended + * for production unless without any other option. + * + * @return string + */ + protected function _generatePrivateKey() + { + $rand = $this->_math->rand($this->getGenerator(), $this->getPrime()); + return $rand; + } + +} diff --git a/library/vendor/Zend/Crypt/DiffieHellman/Exception.php b/library/vendor/Zend/Crypt/DiffieHellman/Exception.php new file mode 100644 index 000000000..1a9f4a524 --- /dev/null +++ b/library/vendor/Zend/Crypt/DiffieHellman/Exception.php @@ -0,0 +1,35 @@ +80 using internal algo) + * @todo Check if mhash() is a required alternative (will be PECL-only soon) + * @category Zend + * @package Zend_Crypt + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Crypt_Hmac extends Zend_Crypt +{ + + /** + * The key to use for the hash + * + * @var string + */ + protected static $_key = null; + + /** + * pack() format to be used for current hashing method + * + * @var string + */ + protected static $_packFormat = null; + + /** + * Hashing algorithm; can be the md5/sha1 functions or any algorithm name + * listed in the output of PHP 5.1.2+ hash_algos(). + * + * @var string + */ + protected static $_hashAlgorithm = 'md5'; + + /** + * List of algorithms supported my mhash() + * + * @var array + */ + protected static $_supportedMhashAlgorithms = array('adler32',' crc32', 'crc32b', 'gost', + 'haval128', 'haval160', 'haval192', 'haval256', 'md4', 'md5', 'ripemd160', + 'sha1', 'sha256', 'tiger', 'tiger128', 'tiger160'); + + /** + * Constants representing the output mode of the hash algorithm + */ + const STRING = 'string'; + const BINARY = 'binary'; + + /** + * Performs a HMAC computation given relevant details such as Key, Hashing + * algorithm, the data to compute MAC of, and an output format of String, + * Binary notation or BTWOC. + * + * @param string $key + * @param string $hash + * @param string $data + * @param string $output + * @throws Zend_Crypt_Hmac_Exception + * @return string + */ + public static function compute($key, $hash, $data, $output = self::STRING) + { + // set the key + if (!isset($key) || empty($key)) { + throw new Zend_Crypt_Hmac_Exception('provided key is null or empty'); + } + self::$_key = $key; + + // set the hash + self::_setHashAlgorithm($hash); + + // perform hashing and return + return self::_hash($data, $output); + } + + /** + * Setter for the hash method. + * + * @param string $hash + * @throws Zend_Crypt_Hmac_Exception + * @return Zend_Crypt_Hmac + */ + protected static function _setHashAlgorithm($hash) + { + if (!isset($hash) || empty($hash)) { + throw new Zend_Crypt_Hmac_Exception('provided hash string is null or empty'); + } + + $hash = strtolower($hash); + $hashSupported = false; + + if (function_exists('hash_algos') && in_array($hash, hash_algos())) { + $hashSupported = true; + } + + if ($hashSupported === false && function_exists('mhash') && in_array($hash, self::$_supportedAlgosMhash)) { + $hashSupported = true; + } + + if ($hashSupported === false) { + throw new Zend_Crypt_Hmac_Exception('hash algorithm provided is not supported on this PHP installation; please enable the hash or mhash extensions'); + } + self::$_hashAlgorithm = $hash; + } + + /** + * Perform HMAC and return the keyed data + * + * @param string $data + * @param string $output + * @param bool $internal Option to not use hash() functions for testing + * @return string + */ + protected static function _hash($data, $output = self::STRING, $internal = false) + { + if (function_exists('hash_hmac')) { + if ($output == self::BINARY) { + return hash_hmac(self::$_hashAlgorithm, $data, self::$_key, true); + } + return hash_hmac(self::$_hashAlgorithm, $data, self::$_key); + } + + if (function_exists('mhash')) { + if ($output == self::BINARY) { + return mhash(self::_getMhashDefinition(self::$_hashAlgorithm), $data, self::$_key); + } + $bin = mhash(self::_getMhashDefinition(self::$_hashAlgorithm), $data, self::$_key); + return bin2hex($bin); + } + } + + /** + * Since MHASH accepts an integer constant representing the hash algorithm + * we need to make a small detour to get the correct integer matching our + * algorithm's name. + * + * @param string $hashAlgorithm + * @return integer + */ + protected static function _getMhashDefinition($hashAlgorithm) + { + for ($i = 0; $i <= mhash_count(); $i++) + { + $types[mhash_get_hash_name($i)] = $i; + } + return $types[strtoupper($hashAlgorithm)]; + } + +} diff --git a/library/vendor/Zend/Crypt/Hmac/Exception.php b/library/vendor/Zend/Crypt/Hmac/Exception.php new file mode 100644 index 000000000..a3d2efcbd --- /dev/null +++ b/library/vendor/Zend/Crypt/Hmac/Exception.php @@ -0,0 +1,35 @@ + 127) { + return "\x00" . $long; + } + return $long; + } + + /** + * Translate a binary form into a big integer string + * + * @param string $binary + * @return string + */ + public function fromBinary($binary) { + return $this->_math->binaryToInteger($binary); + } + + /** + * Translate a big integer string into a binary form + * + * @param string $integer + * @return string + */ + public function toBinary($integer) + { + return $this->_math->integerToBinary($integer); + } + +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger.php b/library/vendor/Zend/Crypt/Math/BigInteger.php new file mode 100644 index 000000000..9af7f1822 --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger.php @@ -0,0 +1,112 @@ +_loadAdapter($extension); + } + + /** + * Redirect all public method calls to the wrapped extension object. + * + * @param string $methodName + * @param array $args + * @return mixed + * @throws Zend_Crypt_Math_BigInteger_Exception + */ + public function __call($methodName, $args) + { + if(!method_exists($this->_math, $methodName)) { + throw new Zend_Crypt_Math_BigInteger_Exception('invalid method call: ' . get_class($this->_math) . '::' . $methodName . '() does not exist'); + } + return call_user_func_array(array($this->_math, $methodName), $args); + } + + /** + * @param string $extension + * @throws Zend_Crypt_Math_BigInteger_Exception + */ + protected function _loadAdapter($extension = null) + { + if ($extension === null) { + if (extension_loaded('gmp')) { + $extension = 'gmp'; + //} elseif (extension_loaded('big_int')) { + // $extension = 'big_int'; + } else { + $extension = 'bcmath'; + } + } + if($extension == 'gmp' && extension_loaded('gmp')) { + $this->_math = new Zend_Crypt_Math_BigInteger_Gmp(); + //} elseif($extension == 'bigint' && extension_loaded('big_int')) { + // $this->_math = new Zend_Crypt_Math_BigInteger_Bigint(); + } elseif ($extension == 'bcmath' && extension_loaded('bcmath')) { + $this->_math = new Zend_Crypt_Math_BigInteger_Bcmath(); + } else { + throw new Zend_Crypt_Math_BigInteger_Exception($extension . ' big integer precision math support not detected'); + } + } + +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php b/library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php new file mode 100644 index 000000000..2d6def83c --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger/Bcmath.php @@ -0,0 +1,226 @@ + 0) { + $return = chr(bcmod($operand, 256)) . $return; + $operand = bcdiv($operand, 256); + } + if (ord($return[0]) > 127) { + $return = "\0" . $return; + } + return $return; + } + + /**public function integerToBinary($operand) + { + $return = ''; + while(bccomp($operand, '0')) { + $return .= chr(bcmod($operand, '256')); + $operand = bcdiv($operand, '256'); + } + return $return; + }**/ // Prior version for referenced offset + + /** + * @param string $operand + * @return string + */ + public function hexToDecimal($operand) + { + $return = '0'; + while(strlen($hex)) { + $hex = hexdec(substr($operand, 0, 4)); + $dec = bcadd(bcmul($return, 65536), $hex); + $operand = substr($operand, 4); + } + return $return; + } +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger/Exception.php b/library/vendor/Zend/Crypt/Math/BigInteger/Exception.php new file mode 100644 index 000000000..f5db754a8 --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger/Exception.php @@ -0,0 +1,35 @@ + '7') { + $bigInt = '00' . $bigInt; + } + $return = pack("H*", $bigInt); + return $return; + } + + /** + * @param string $operand + * @return string + */ + public function hexToDecimal($operand) + { + $return = '0'; + while(strlen($hex)) { + $hex = hexdec(substr($operand, 0, 4)); + $dec = gmp_add(gmp_mul($return, 65536), $hex); + $operand = substr($operand, 4); + } + return $return; + } + +} diff --git a/library/vendor/Zend/Crypt/Math/BigInteger/Interface.php b/library/vendor/Zend/Crypt/Math/BigInteger/Interface.php new file mode 100644 index 000000000..02a830eb7 --- /dev/null +++ b/library/vendor/Zend/Crypt/Math/BigInteger/Interface.php @@ -0,0 +1,51 @@ +_hashAlgorithm = OPENSSL_ALGO_SHA1; + + if (isset($options)) { + $this->setOptions($options); + } + } + + public function setOptions(array $options) + { + if (isset($options['passPhrase'])) { + $this->_passPhrase = $options['passPhrase']; + } + foreach ($options as $option=>$value) { + switch ($option) { + case 'pemString': + $this->setPemString($value); + break; + case 'pemPath': + $this->setPemPath($value); + break; + case 'certificateString': + $this->setCertificateString($value); + break; + case 'certificatePath': + $this->setCertificatePath($value); + break; + case 'hashAlgorithm': + $this->setHashAlgorithm($value); + break; + } + } + } + + public function getPrivateKey() + { + return $this->_privateKey; + } + + public function getPublicKey() + { + return $this->_publicKey; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key_Private $privateKey + * @param string $format + * @return string + */ + public function sign($data, Zend_Crypt_Rsa_Key_Private $privateKey = null, $format = null) + { + $signature = ''; + if (isset($privateKey)) { + $opensslKeyResource = $privateKey->getOpensslKeyResource(); + } else { + $opensslKeyResource = $this->_privateKey->getOpensslKeyResource(); + } + $result = openssl_sign( + $data, $signature, + $opensslKeyResource, + $this->getHashAlgorithm() + ); + if ($format == self::BASE64) { + return base64_encode($signature); + } + return $signature; + } + + /** + * @param string $data + * @param string $signature + * @param string $format + * @return string + */ + public function verifySignature($data, $signature, $format = null) + { + if ($format == self::BASE64) { + $signature = base64_decode($signature); + } + $result = openssl_verify($data, $signature, + $this->getPublicKey()->getOpensslKeyResource(), + $this->getHashAlgorithm()); + return $result; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key $key + * @param string $format + * @return string + */ + public function encrypt($data, Zend_Crypt_Rsa_Key $key, $format = null) + { + $encrypted = ''; + $function = 'openssl_public_encrypt'; + if ($key instanceof Zend_Crypt_Rsa_Key_Private) { + $function = 'openssl_private_encrypt'; + } + $function($data, $encrypted, $key->getOpensslKeyResource()); + if ($format == self::BASE64) { + return base64_encode($encrypted); + } + return $encrypted; + } + + /** + * @param string $data + * @param Zend_Crypt_Rsa_Key $key + * @param string $format + * @return string + */ + public function decrypt($data, Zend_Crypt_Rsa_Key $key, $format = null) + { + $decrypted = ''; + if ($format == self::BASE64) { + $data = base64_decode($data); + } + $function = 'openssl_private_decrypt'; + if ($key instanceof Zend_Crypt_Rsa_Key_Public) { + $function = 'openssl_public_decrypt'; + } + $function($data, $decrypted, $key->getOpensslKeyResource()); + return $decrypted; + } + + /** + * @param array $configargs + * + * @throws Zend_Crypt_Rsa_Exception + * + * @return ArrayObject + */ + public function generateKeys(array $configargs = null) + { + $config = null; + $passPhrase = null; + if ($configargs !== null) { + if (isset($configargs['passPhrase'])) { + $passPhrase = $configargs['passPhrase']; + unset($configargs['passPhrase']); + } + $config = $this->_parseConfigArgs($configargs); + } + $privateKey = null; + $publicKey = null; + $resource = openssl_pkey_new($config); + if (!$resource) { + throw new Zend_Crypt_Rsa_Exception('Failed to generate a new private key'); + } + // above fails on PHP 5.3 + openssl_pkey_export($resource, $private, $passPhrase); + $privateKey = new Zend_Crypt_Rsa_Key_Private($private, $passPhrase); + $details = openssl_pkey_get_details($resource); + $publicKey = new Zend_Crypt_Rsa_Key_Public($details['key']); + $return = new ArrayObject(array( + 'privateKey'=>$privateKey, + 'publicKey'=>$publicKey + ), ArrayObject::ARRAY_AS_PROPS); + return $return; + } + + /** + * @param string $value + */ + public function setPemString($value) + { + $this->_pemString = $value; + try { + $this->_privateKey = new Zend_Crypt_Rsa_Key_Private($this->_pemString, $this->_passPhrase); + $this->_publicKey = $this->_privateKey->getPublicKey(); + } catch (Zend_Crypt_Exception $e) { + $this->_privateKey = null; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_pemString); + } + } + + public function setPemPath($value) + { + $this->_pemPath = $value; + $this->setPemString(file_get_contents($this->_pemPath)); + } + + public function setCertificateString($value) + { + $this->_certificateString = $value; + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_certificateString, $this->_passPhrase); + } + + public function setCertificatePath($value) + { + $this->_certificatePath = $value; + $this->setCertificateString(file_get_contents($this->_certificatePath)); + } + + public function setHashAlgorithm($name) + { + switch (strtolower($name)) { + case 'md2': + $this->_hashAlgorithm = OPENSSL_ALGO_MD2; + break; + case 'md4': + $this->_hashAlgorithm = OPENSSL_ALGO_MD4; + break; + case 'md5': + $this->_hashAlgorithm = OPENSSL_ALGO_MD5; + break; + case 'sha1': + $this->_hashAlgorithm = OPENSSL_ALGO_SHA1; + break; + case 'dss1': + $this->_hashAlgorithm = OPENSSL_ALGO_DSS1; + break; + } + } + + /** + * @return string + */ + public function getPemString() + { + return $this->_pemString; + } + + public function getPemPath() + { + return $this->_pemPath; + } + + public function getCertificateString() + { + return $this->_certificateString; + } + + public function getCertificatePath() + { + return $this->_certificatePath; + } + + public function getHashAlgorithm() + { + return $this->_hashAlgorithm; + } + + protected function _parseConfigArgs(array $config = null) + { + $configs = array(); + if (isset($config['private_key_bits'])) { + $configs['private_key_bits'] = $config['private_key_bits']; + } + if (isset($config['privateKeyBits'])) { + $configs['private_key_bits'] = $config['privateKeyBits']; + } + if (!empty($configs)) { + return $configs; + } + return null; + } + +} diff --git a/library/vendor/Zend/Crypt/Rsa/Exception.php b/library/vendor/Zend/Crypt/Rsa/Exception.php new file mode 100644 index 000000000..a0f1fbb03 --- /dev/null +++ b/library/vendor/Zend/Crypt/Rsa/Exception.php @@ -0,0 +1,35 @@ +_opensslKeyResource; + } + + /** + * @return string + * @throws Zend_Crypt_Exception + */ + public function toString() + { + if (!empty($this->_pemString)) { + return $this->_pemString; + } elseif (!empty($this->_certificateString)) { + return $this->_certificateString; + } + /** + * @see Zend_Crypt_Exception + */ + throw new Zend_Crypt_Exception('No public key string representation is available'); + } + + /** + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + public function count() + { + return $this->_details['bits']; + } + + public function getType() + { + return $this->_details['type']; + } +} diff --git a/library/vendor/Zend/Crypt/Rsa/Key/Private.php b/library/vendor/Zend/Crypt/Rsa/Key/Private.php new file mode 100644 index 000000000..47b7a8773 --- /dev/null +++ b/library/vendor/Zend/Crypt/Rsa/Key/Private.php @@ -0,0 +1,72 @@ +_pemString = $pemString; + $this->_parse($passPhrase); + } + + /** + * @param string $passPhrase + * @throws Zend_Crypt_Exception + */ + protected function _parse($passPhrase) + { + $result = openssl_get_privatekey($this->_pemString, $passPhrase); + if (!$result) { + /** + * @see Zend_Crypt_Exception + */ + throw new Zend_Crypt_Exception('Unable to load private key'); + } + $this->_opensslKeyResource = $result; + $this->_details = openssl_pkey_get_details($this->_opensslKeyResource); + } + + public function getPublicKey() + { + if ($this->_publicKey === null) { + /** + * @see Zend_Crypt_Rsa_Key_Public + */ + $this->_publicKey = new Zend_Crypt_Rsa_Key_Public($this->_details['key']); + } + return $this->_publicKey; + } + +} diff --git a/library/vendor/Zend/Crypt/Rsa/Key/Public.php b/library/vendor/Zend/Crypt/Rsa/Key/Public.php new file mode 100644 index 000000000..439787a07 --- /dev/null +++ b/library/vendor/Zend/Crypt/Rsa/Key/Public.php @@ -0,0 +1,72 @@ +_parse($string); + } + + /** + * @param string $string + * @throws Zend_Crypt_Exception + */ + protected function _parse($string) + { + if (preg_match("/^-----BEGIN CERTIFICATE-----/", $string)) { + $this->_certificateString = $string; + } else { + $this->_pemString = $string; + } + $result = openssl_get_publickey($string); + if (!$result) { + /** + * @see Zend_Crypt_Exception + */ + throw new Zend_Crypt_Exception('Unable to load public key'); + } + //openssl_pkey_export($result, $public); + //$this->_pemString = $public; + $this->_opensslKeyResource = $result; + $this->_details = openssl_pkey_get_details($this->_opensslKeyResource); + } + + public function getCertificate() + { + return $this->_certificateString; + } + +} diff --git a/library/vendor/Zend/Currency.php b/library/vendor/Zend/Currency.php new file mode 100644 index 000000000..15f26a70c --- /dev/null +++ b/library/vendor/Zend/Currency.php @@ -0,0 +1,884 @@ + Position for the currency sign + * 'script' => Script for the output + * 'format' => Locale for numeric output + * 'display' => Currency detail to show + * 'precision' => Precision for the currency + * 'name' => Name for this currency + * 'currency' => 3 lettered international abbreviation + * 'symbol' => Currency symbol + * 'locale' => Locale for this currency + * 'value' => Money value + * 'service' => Exchange service to use + * + * @var array + * @see Zend_Locale + */ + protected $_options = array( + 'position' => self::STANDARD, + 'script' => null, + 'format' => null, + 'display' => self::NO_SYMBOL, + 'precision' => 2, + 'name' => null, + 'currency' => null, + 'symbol' => null, + 'locale' => null, + 'value' => 0, + 'service' => null, + 'tag' => 'Zend_Locale' + ); + + /** + * Creates a currency instance. Every supressed parameter is used from the actual or the given locale. + * + * @param string|array $options OPTIONAL Options array or currency short name + * when string is given + * @param string|Zend_Locale $locale OPTIONAL locale name + * @throws Zend_Currency_Exception When currency is invalid + */ + public function __construct($options = null, $locale = null) + { + $calloptions = $options; + if (is_array($options) && isset($options['display'])) { + $this->_options['display'] = $options['display']; + } + + if (is_array($options)) { + $this->setLocale($locale); + $this->setFormat($options); + } else if (Zend_Locale::isLocale($options, false, false)) { + $this->setLocale($options); + $options = $locale; + } else { + $this->setLocale($locale); + } + + // Get currency details + if (!isset($this->_options['currency']) || !is_array($options)) { + $this->_options['currency'] = self::getShortName($options, $this->_options['locale']); + } + + if (!isset($this->_options['name']) || !is_array($options)) { + $this->_options['name'] = self::getName($options, $this->_options['locale']); + } + + if (!isset($this->_options['symbol']) || !is_array($options)) { + $this->_options['symbol'] = self::getSymbol($options, $this->_options['locale']); + } + + if (($this->_options['currency'] === null) and ($this->_options['name'] === null)) { + throw new Zend_Currency_Exception("Currency '$options' not found"); + } + + // Get the format + if ((is_array($calloptions) && !isset($calloptions['display'])) + || (!is_array($calloptions) && $this->_options['display'] == self::NO_SYMBOL)) { + if (!empty($this->_options['symbol'])) { + $this->_options['display'] = self::USE_SYMBOL; + } else if (!empty($this->_options['currency'])) { + $this->_options['display'] = self::USE_SHORTNAME; + } + } + } + + /** + * Returns a localized currency string + * + * @param integer|float $value OPTIONAL Currency value + * @param array $options OPTIONAL options to set temporary + * @throws Zend_Currency_Exception When the value is not a number + * @return string + */ + public function toCurrency($value = null, array $options = array()) + { + if ($value === null) { + if (is_array($options) && isset($options['value'])) { + $value = $options['value']; + } else { + $value = $this->_options['value']; + } + } + + if (is_array($value)) { + $options += $value; + if (isset($options['value'])) { + $value = $options['value']; + } + } + + // Validate the passed number + if (!(isset($value)) or (is_numeric($value) === false)) { + throw new Zend_Currency_Exception("Value '$value' has to be numeric"); + } + + if (isset($options['currency'])) { + if (!isset($options['locale'])) { + $options['locale'] = $this->_options['locale']; + } + + $options['currency'] = self::getShortName($options['currency'], $options['locale']); + $options['name'] = self::getName($options['currency'], $options['locale']); + $options['symbol'] = self::getSymbol($options['currency'], $options['locale']); + } + + $options = $this->_checkOptions($options) + $this->_options; + + // Format the number + $format = $options['format']; + $locale = $options['locale']; + if (empty($format)) { + $format = Zend_Locale_Data::getContent($locale, 'currencynumber'); + } else if (Zend_Locale::isLocale($format, true, false)) { + $locale = $format; + $format = Zend_Locale_Data::getContent($format, 'currencynumber'); + } + + $original = $value; + $value = Zend_Locale_Format::toNumber($value, array('locale' => $locale, + 'number_format' => $format, + 'precision' => $options['precision'])); + + if ($options['position'] !== self::STANDARD) { + $value = str_replace('¤', '', $value); + $space = ''; + if (iconv_strpos($value, ' ') !== false) { + $value = str_replace(' ', '', $value); + $space = ' '; + } + + if ($options['position'] == self::LEFT) { + $value = '¤' . $space . $value; + } else { + $value = $value . $space . '¤'; + } + } + + // Localize the number digits + if (empty($options['script']) === false) { + $value = Zend_Locale_Format::convertNumerals($value, 'Latn', $options['script']); + } + + // Get the sign to be placed next to the number + if (is_numeric($options['display']) === false) { + $sign = $options['display']; + } else { + switch($options['display']) { + case self::USE_SYMBOL: + $sign = $this->_extractPattern($options['symbol'], $original); + break; + + case self::USE_SHORTNAME: + $sign = $options['currency']; + break; + + case self::USE_NAME: + $sign = $options['name']; + break; + + default: + $sign = ''; + $value = str_replace(' ', '', $value); + break; + } + } + + $value = str_replace('¤', $sign, $value); + return $value; + } + + /** + * Internal method to extract the currency pattern + * when a choice is given based on the given value + * + * @param string $pattern + * @param float|integer $value + * @return string + */ + private function _extractPattern($pattern, $value) + { + if (strpos($pattern, '|') === false) { + return $pattern; + } + + $patterns = explode('|', $pattern); + $token = $pattern; + $value = trim(str_replace('¤', '', $value)); + krsort($patterns); + foreach($patterns as $content) { + if (strpos($content, '<') !== false) { + $check = iconv_substr($content, 0, iconv_strpos($content, '<')); + $token = iconv_substr($content, iconv_strpos($content, '<') + 1); + if ($check < $value) { + return $token; + } + } else { + $check = iconv_substr($content, 0, iconv_strpos($content, '≤')); + $token = iconv_substr($content, iconv_strpos($content, '≤') + 1); + if ($check <= $value) { + return $token; + } + } + + } + + return $token; + } + + /** + * Sets the formating options of the localized currency string + * If no parameter is passed, the standard setting of the + * actual set locale will be used + * + * @param array $options (Optional) Options to set + * @return Zend_Currency + */ + public function setFormat(array $options = array()) + { + $this->_options = $this->_checkOptions($options) + $this->_options; + return $this; + } + + /** + * Internal function for checking static given locale parameter + * + * @param string $currency (Optional) Currency name + * @param string|Zend_Locale $locale (Optional) Locale to display informations + * @throws Zend_Currency_Exception When locale contains no region + * @return string The extracted locale representation as string + */ + private function _checkParams($currency = null, $locale = null) + { + // Manage the params + if ((empty($locale)) and (!empty($currency)) and + (Zend_Locale::isLocale($currency, true, false))) { + $locale = $currency; + $currency = null; + } + + // Validate the locale and get the country short name + $country = null; + if ((Zend_Locale::isLocale($locale, true, false)) and (strlen($locale) > 4)) { + $country = substr($locale, (strpos($locale, '_') + 1)); + } else { + throw new Zend_Currency_Exception("No region found within the locale '" . (string) $locale . "'"); + } + + // Get the available currencies for this country + $data = Zend_Locale_Data::getContent($locale, 'currencytoregion', $country); + if ((empty($currency) === false) and (empty($data) === false)) { + $abbreviation = $currency; + } else { + $abbreviation = $data; + } + + return array('locale' => $locale, 'currency' => $currency, 'name' => $abbreviation, 'country' => $country); + } + + /** + * Returns the actual or details of other currency symbols, + * when no symbol is available it returns the currency shortname (f.e. FIM for Finnian Mark) + * + * @param string $currency (Optional) Currency name + * @param string|Zend_Locale $locale (Optional) Locale to display informations + * @return string + */ + public function getSymbol($currency = null, $locale = null) + { + if (($currency === null) and ($locale === null)) { + return $this->_options['symbol']; + } + + $params = self::_checkParams($currency, $locale); + + // Get the symbol + $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['currency']); + if (empty($symbol) === true) { + $symbol = Zend_Locale_Data::getContent($params['locale'], 'currencysymbol', $params['name']); + } + + if (empty($symbol) === true) { + return null; + } + + return $symbol; + } + + /** + * Returns the actual or details of other currency shortnames + * + * @param string $currency OPTIONAL Currency's name + * @param string|Zend_Locale $locale OPTIONAL The locale + * @return string + */ + public function getShortName($currency = null, $locale = null) + { + if (($currency === null) and ($locale === null)) { + return $this->_options['currency']; + } + + $params = self::_checkParams($currency, $locale); + + // Get the shortname + if (empty($params['currency']) === true) { + return $params['name']; + } + + $list = Zend_Locale_Data::getContent($params['locale'], 'currencytoname', $params['currency']); + if (empty($list) === true) { + $list = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']); + if (empty($list) === false) { + $list = $params['currency']; + } + } + + if (empty($list) === true) { + return null; + } + + return $list; + } + + /** + * Returns the actual or details of other currency names + * + * @param string $currency (Optional) Currency's short name + * @param string|Zend_Locale $locale (Optional) The locale + * @return string + */ + public function getName($currency = null, $locale = null) + { + if (($currency === null) and ($locale === null)) { + return $this->_options['name']; + } + + $params = self::_checkParams($currency, $locale); + + // Get the name + $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['currency']); + if (empty($name) === true) { + $name = Zend_Locale_Data::getContent($params['locale'], 'nametocurrency', $params['name']); + } + + if (empty($name) === true) { + return null; + } + + return $name; + } + + /** + * Returns a list of regions where this currency is or was known + * + * @param string $currency OPTIONAL Currency's short name + * @throws Zend_Currency_Exception When no currency was defined + * @return array List of regions + */ + public function getRegionList($currency = null) + { + if ($currency === null) { + $currency = $this->_options['currency']; + } + + if (empty($currency) === true) { + throw new Zend_Currency_Exception('No currency defined'); + } + + $data = Zend_Locale_Data::getContent($this->_options['locale'], 'regiontocurrency', $currency); + + $result = explode(' ', $data); + return $result; + } + + /** + * Returns a list of currencies which are used in this region + * a region name should be 2 charachters only (f.e. EG, DE, US) + * If no region is given, the actual region is used + * + * @param string $region OPTIONAL Region to return the currencies for + * @return array List of currencies + */ + public function getCurrencyList($region = null) + { + if (empty($region) === true) { + if (strlen($this->_options['locale']) > 4) { + $region = substr($this->_options['locale'], (strpos($this->_options['locale'], '_') + 1)); + } + } + + $data = Zend_Locale_Data::getContent($this->_options['locale'], 'currencytoregion', $region); + + $result = explode(' ', $data); + return $result; + } + + /** + * Returns the actual currency name + * + * @return string + */ + public function toString() + { + return $this->toCurrency(); + } + + /** + * Returns the currency name + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Returns the set cache + * + * @return Zend_Cache_Core The set cache + */ + public static function getCache() + { + return Zend_Locale_Data::getCache(); + } + + /** + * Sets a cache for Zend_Currency + * + * @param Zend_Cache_Core $cache Cache to set + * @return void + */ + public static function setCache(Zend_Cache_Core $cache) + { + Zend_Locale_Data::setCache($cache); + } + + /** + * Returns true when a cache is set + * + * @return boolean + */ + public static function hasCache() + { + return Zend_Locale_Data::hasCache(); + } + + /** + * Removes any set cache + * + * @return void + */ + public static function removeCache() + { + Zend_Locale_Data::removeCache(); + } + + /** + * Clears all set cache data + * + * @param string $tag Tag to clear when the default tag name is not used + * @return void + */ + public static function clearCache($tag = null) + { + Zend_Locale_Data::clearCache($tag); + } + + /** + * Sets a new locale for data retreivement + * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist + * 'xx_YY' will be set to 'root' because 'xx' does not exist + * + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @throws Zend_Currency_Exception When the given locale does not exist + * @return Zend_Currency Provides fluent interface + */ + public function setLocale($locale = null) + { + try { + $locale = Zend_Locale::findLocale($locale); + if (strlen($locale) > 4) { + $this->_options['locale'] = $locale; + } else { + throw new Zend_Currency_Exception("No region found within the locale '" . (string) $locale . "'"); + } + } catch (Zend_Locale_Exception $e) { + throw new Zend_Currency_Exception($e->getMessage()); + } + + // Get currency details + $this->_options['currency'] = $this->getShortName(null, $this->_options['locale']); + $this->_options['name'] = $this->getName(null, $this->_options['locale']); + $this->_options['symbol'] = $this->getSymbol(null, $this->_options['locale']); + + return $this; + } + + /** + * Returns the actual set locale + * + * @return string + */ + public function getLocale() + { + return $this->_options['locale']; + } + + /** + * Returns the value + * + * @return float + */ + public function getValue() + { + return $this->_options['value']; + } + + /** + * Adds a currency + * + * @param float|integer|Zend_Currency $value Add this value to currency + * @param string|Zend_Currency $currency The currency to add + * @return Zend_Currency + */ + public function setValue($value, $currency = null) + { + $this->_options['value'] = $this->_exchangeCurrency($value, $currency); + return $this; + } + + /** + * Adds a currency + * + * @param float|integer|Zend_Currency $value Add this value to currency + * @param string|Zend_Currency $currency The currency to add + * @return Zend_Currency + */ + public function add($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + $this->_options['value'] += (float) $value; + return $this; + } + + /** + * Substracts a currency + * + * @param float|integer|Zend_Currency $value Substracts this value from currency + * @param string|Zend_Currency $currency The currency to substract + * @return Zend_Currency + */ + public function sub($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + $this->_options['value'] -= (float) $value; + return $this; + } + + /** + * Divides a currency + * + * @param float|integer|Zend_Currency $value Divides this value from currency + * @param string|Zend_Currency $currency The currency to divide + * @return Zend_Currency + */ + public function div($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + $this->_options['value'] /= (float) $value; + return $this; + } + + /** + * Multiplies a currency + * + * @param float|integer|Zend_Currency $value Multiplies this value from currency + * @param string|Zend_Currency $currency The currency to multiply + * @return Zend_Currency + */ + public function mul($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + $this->_options['value'] *= (float) $value; + return $this; + } + + /** + * Calculates the modulo from a currency + * + * @param float|integer|Zend_Currency $value Calculate modulo from this value + * @param string|Zend_Currency $currency The currency to calculate the modulo + * @return Zend_Currency + */ + public function mod($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + $this->_options['value'] %= (float) $value; + return $this; + } + + /** + * Compares two currencies + * + * @param float|integer|Zend_Currency $value Compares the currency with this value + * @param string|Zend_Currency $currency The currency to compare this value from + * @return Zend_Currency + */ + public function compare($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + $value = $this->_options['value'] - $value; + if ($value < 0) { + return -1; + } else if ($value > 0) { + return 1; + } + + return 0; + } + + /** + * Returns true when the two currencies are equal + * + * @param float|integer|Zend_Currency $value Compares the currency with this value + * @param string|Zend_Currency $currency The currency to compare this value from + * @return boolean + */ + public function equals($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + if ($this->_options['value'] == $value) { + return true; + } + + return false; + } + + /** + * Returns true when the currency is more than the given value + * + * @param float|integer|Zend_Currency $value Compares the currency with this value + * @param string|Zend_Currency $currency The currency to compare this value from + * @return boolean + */ + public function isMore($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + if ($this->_options['value'] > $value) { + return true; + } + + return false; + } + + /** + * Returns true when the currency is less than the given value + * + * @param float|integer|Zend_Currency $value Compares the currency with this value + * @param string|Zend_Currency $currency The currency to compare this value from + * @return boolean + */ + public function isLess($value, $currency = null) + { + $value = $this->_exchangeCurrency($value, $currency); + if ($this->_options['value'] < $value) { + return true; + } + + return false; + + } + + /** + * Internal method which calculates the exchanges currency + * + * @param float|integer|Zend_Currency $value Compares the currency with this value + * @param string|Zend_Currency $currency The currency to compare this value from + * @return unknown + */ + protected function _exchangeCurrency($value, $currency) + { + if ($value instanceof Zend_Currency) { + $currency = $value->getShortName(); + $value = $value->getValue(); + } else { + $currency = $this->getShortName($currency, $this->getLocale()); + } + + $rate = 1; + if ($currency !== $this->getShortName()) { + $service = $this->getService(); + if (!($service instanceof Zend_Currency_CurrencyInterface)) { + throw new Zend_Currency_Exception('No exchange service applied'); + } + + $rate = $service->getRate($currency, $this->getShortName()); + } + + $value *= $rate; + return $value; + } + + /** + * Returns the set service class + * + * @return Zend_Service + */ + public function getService() + { + return $this->_options['service']; + } + + /** + * Sets a new exchange service + * + * @param string|Zend_Currency_CurrencyInterface $service Service class + * @return Zend_Currency + */ + public function setService($service) + { + if (is_string($service)) { + if (!class_exists($service)) { + $file = str_replace('_', DIRECTORY_SEPARATOR, $service) . '.php'; + if (Zend_Loader::isReadable($file)) { + Zend_Loader::loadClass($service); + } + } + + $service = new $service; + } + + if (!($service instanceof Zend_Currency_CurrencyInterface)) { + throw new Zend_Currency_Exception('A currency service must implement Zend_Currency_CurrencyInterface'); + } + + $this->_options['service'] = $service; + return $this; + } + + /** + * Internal method for checking the options array + * + * @param array $options Options to check + * @throws Zend_Currency_Exception On unknown position + * @throws Zend_Currency_Exception On unknown locale + * @throws Zend_Currency_Exception On unknown display + * @throws Zend_Currency_Exception On precision not between -1 and 30 + * @throws Zend_Currency_Exception On problem with script conversion + * @throws Zend_Currency_Exception On unknown options + * @return array + */ + protected function _checkOptions(array $options = array()) + { + if (count($options) === 0) { + return $this->_options; + } + + foreach ($options as $name => $value) { + $name = strtolower($name); + if ($name !== 'format') { + if (gettype($value) === 'string') { + $value = strtolower($value); + } + } + + switch($name) { + case 'position': + if (($value !== self::STANDARD) and ($value !== self::RIGHT) and ($value !== self::LEFT)) { + throw new Zend_Currency_Exception("Unknown position '" . $value . "'"); + } + + break; + + case 'format': + if ((empty($value) === false) and (Zend_Locale::isLocale($value, null, false) === false)) { + if (!is_string($value) || (strpos($value, '0') === false)) { + throw new Zend_Currency_Exception("'" . + ((gettype($value) === 'object') ? get_class($value) : $value) + . "' is no format token"); + } + } + break; + + case 'display': + if (is_numeric($value) and ($value !== self::NO_SYMBOL) and ($value !== self::USE_SYMBOL) and + ($value !== self::USE_SHORTNAME) and ($value !== self::USE_NAME)) { + throw new Zend_Currency_Exception("Unknown display '$value'"); + } + break; + + case 'precision': + if ($value === null) { + $value = -1; + } + + if (($value < -1) or ($value > 30)) { + throw new Zend_Currency_Exception("'$value' precision has to be between -1 and 30."); + } + break; + + case 'script': + try { + Zend_Locale_Format::convertNumerals(0, $options['script']); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Currency_Exception($e->getMessage()); + } + break; + + default: + break; + } + } + + return $options; + } +} diff --git a/library/vendor/Zend/Currency/CurrencyInterface.php b/library/vendor/Zend/Currency/CurrencyInterface.php new file mode 100644 index 000000000..9d14e266c --- /dev/null +++ b/library/vendor/Zend/Currency/CurrencyInterface.php @@ -0,0 +1,39 @@ + 'iso', // format for date strings 'iso' or 'php' + 'fix_dst' => true, // fix dst on summer/winter time change + 'extend_month' => false, // false - addMonth like SQL, true like excel + 'cache' => null, // cache to set + 'timesync' => null // timesync server to set + ); + + // Class wide Date Constants + const DAY = 'dd'; + const DAY_SHORT = 'd'; + const DAY_SUFFIX = 'SS'; + const DAY_OF_YEAR = 'D'; + const WEEKDAY = 'EEEE'; + const WEEKDAY_SHORT = 'EEE'; + const WEEKDAY_NARROW = 'E'; + const WEEKDAY_NAME = 'EE'; + const WEEKDAY_8601 = 'eee'; + const WEEKDAY_DIGIT = 'e'; + const WEEK = 'ww'; + const MONTH = 'MM'; + const MONTH_SHORT = 'M'; + const MONTH_DAYS = 'ddd'; + const MONTH_NAME = 'MMMM'; + const MONTH_NAME_SHORT = 'MMM'; + const MONTH_NAME_NARROW = 'MMMMM'; + const YEAR = 'y'; + const YEAR_SHORT = 'yy'; + const YEAR_8601 = 'Y'; + const YEAR_SHORT_8601 = 'YY'; + const LEAPYEAR = 'l'; + const MERIDIEM = 'a'; + const SWATCH = 'B'; + const HOUR = 'HH'; + const HOUR_SHORT = 'H'; + const HOUR_AM = 'hh'; + const HOUR_SHORT_AM = 'h'; + const MINUTE = 'mm'; + const MINUTE_SHORT = 'm'; + const SECOND = 'ss'; + const SECOND_SHORT = 's'; + const MILLISECOND = 'S'; + const TIMEZONE_NAME = 'zzzz'; + const DAYLIGHT = 'I'; + const GMT_DIFF = 'Z'; + const GMT_DIFF_SEP = 'ZZZZ'; + const TIMEZONE = 'z'; + const TIMEZONE_SECS = 'X'; + const ISO_8601 = 'c'; + const RFC_2822 = 'r'; + const TIMESTAMP = 'U'; + const ERA = 'G'; + const ERA_NAME = 'GGGG'; + const ERA_NARROW = 'GGGGG'; + const DATES = 'F'; + const DATE_FULL = 'FFFFF'; + const DATE_LONG = 'FFFF'; + const DATE_MEDIUM = 'FFF'; + const DATE_SHORT = 'FF'; + const TIMES = 'WW'; + const TIME_FULL = 'TTTTT'; + const TIME_LONG = 'TTTT'; + const TIME_MEDIUM = 'TTT'; + const TIME_SHORT = 'TT'; + const DATETIME = 'K'; + const DATETIME_FULL = 'KKKKK'; + const DATETIME_LONG = 'KKKK'; + const DATETIME_MEDIUM = 'KKK'; + const DATETIME_SHORT = 'KK'; + const ATOM = 'OOO'; + const COOKIE = 'CCC'; + const RFC_822 = 'R'; + const RFC_850 = 'RR'; + const RFC_1036 = 'RRR'; + const RFC_1123 = 'RRRR'; + const RFC_3339 = 'RRRRR'; + const RSS = 'SSS'; + const W3C = 'WWW'; + + /** + * Generates the standard date object, could be a unix timestamp, localized date, + * string, integer, array and so on. Also parts of dates or time are supported + * Always set the default timezone: http://php.net/date_default_timezone_set + * For example, in your bootstrap: date_default_timezone_set('America/Los_Angeles'); + * For detailed instructions please look in the docu. + * + * @param string|integer|Zend_Date|array $date OPTIONAL Date value or value of date part to set + * ,depending on $part. If null the actual time is set + * @param string $part OPTIONAL Defines the input format of $date + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function __construct($date = null, $part = null, $locale = null) + { + if (is_object($date) and !($date instanceof Zend_TimeSync_Protocol) and + !($date instanceof Zend_Date)) { + if ($locale instanceof Zend_Locale) { + $locale = $date; + $date = null; + $part = null; + } else { + $date = (string) $date; + } + } + + if (($date !== null) and !is_array($date) and !($date instanceof Zend_TimeSync_Protocol) and + !($date instanceof Zend_Date) and !defined($date) and Zend_Locale::isLocale($date, true, false)) { + $locale = $date; + $date = null; + $part = null; + } else if (($part !== null) and !defined($part) and Zend_Locale::isLocale($part, true, false)) { + $locale = $part; + $part = null; + } + + $this->setLocale($locale); + if (is_string($date) && ($part === null) && (strlen($date) <= 5)) { + $part = $date; + $date = null; + } + + if ($date === null) { + if ($part === null) { + $date = time(); + } else if ($part !== self::TIMESTAMP) { + $date = self::now($locale); + $date = $date->get($part); + } + } + + if ($date instanceof Zend_TimeSync_Protocol) { + $date = $date->getInfo(); + $date = $this->_getTime($date['offset']); + $part = null; + } else if (parent::$_defaultOffset != 0) { + $date = $this->_getTime(parent::$_defaultOffset); + } + + // set the timezone and offset for $this + $zone = @date_default_timezone_get(); + $this->setTimezone($zone); + + // try to get timezone from date-string + if (!is_int($date)) { + $zone = $this->getTimezoneFromString($date); + $this->setTimezone($zone); + } + + // set datepart + if (($part !== null && $part !== self::TIMESTAMP) or (!is_numeric($date))) { + // switch off dst handling for value setting + $this->setUnixTimestamp($this->getGmtOffset()); + $this->set($date, $part, $this->_locale); + + // DST fix + if (is_array($date) === true) { + if (!isset($date['hour'])) { + $date['hour'] = 0; + } + + $hour = $this->toString('H', 'iso', true); + $hour = $date['hour'] - $hour; + switch ($hour) { + case 1 : + case -23 : + $this->addTimestamp(3600); + break; + case -1 : + case 23 : + $this->subTimestamp(3600); + break; + case 2 : + case -22 : + $this->addTimestamp(7200); + break; + case -2 : + case 22 : + $this->subTimestamp(7200); + break; + } + } + } else { + $this->setUnixTimestamp($date); + } + } + + /** + * Sets class wide options, if no option was given, the actual set options will be returned + * + * @param array $options Options to set + * @throws Zend_Date_Exception + * @return Options array if no option was given + */ + public static function setOptions(array $options = array()) + { + if (empty($options)) { + return self::$_options; + } + + foreach ($options as $name => $value) { + $name = strtolower($name); + + if (array_key_exists($name, self::$_options)) { + switch($name) { + case 'format_type' : + if ((strtolower($value) != 'php') && (strtolower($value) != 'iso')) { + throw new Zend_Date_Exception("Unknown format type ($value) for dates, only 'iso' and 'php' supported", 0, null, $value); + } + break; + case 'fix_dst' : + if (!is_bool($value)) { + throw new Zend_Date_Exception("'fix_dst' has to be boolean", 0, null, $value); + } + break; + case 'extend_month' : + if (!is_bool($value)) { + throw new Zend_Date_Exception("'extend_month' has to be boolean", 0, null, $value); + } + break; + case 'cache' : + if ($value === null) { + parent::$_cache = null; + } else { + if (!$value instanceof Zend_Cache_Core) { + throw new Zend_Date_Exception("Instance of Zend_Cache expected"); + } + + parent::$_cache = $value; + parent::$_cacheTags = Zend_Date_DateObject::_getTagSupportForCache(); + Zend_Locale_Data::setCache($value); + } + break; + case 'timesync' : + if ($value === null) { + parent::$_defaultOffset = 0; + } else { + if (!$value instanceof Zend_TimeSync_Protocol) { + throw new Zend_Date_Exception("Instance of Zend_TimeSync expected"); + } + + $date = $value->getInfo(); + parent::$_defaultOffset = $date['offset']; + } + break; + } + self::$_options[$name] = $value; + } + else { + throw new Zend_Date_Exception("Unknown option: $name = $value"); + } + } + } + + /** + * Returns this object's internal UNIX timestamp (equivalent to Zend_Date::TIMESTAMP). + * If the timestamp is too large for integers, then the return value will be a string. + * This function does not return the timestamp as an object. + * Use clone() or copyPart() instead. + * + * @return integer|string UNIX timestamp + */ + public function getTimestamp() + { + return $this->getUnixTimestamp(); + } + + /** + * Returns the calculated timestamp + * HINT: timestamps are always GMT + * + * @param string $calc Type of calculation to make + * @param string|integer|array|Zend_Date $stamp Timestamp to calculate, when null the actual timestamp is calculated + * @return Zend_Date|integer + * @throws Zend_Date_Exception + */ + private function _timestamp($calc, $stamp) + { + if ($stamp instanceof Zend_Date) { + // extract timestamp from object + $stamp = $stamp->getTimestamp(); + } + + if (is_array($stamp)) { + if (isset($stamp['timestamp']) === true) { + $stamp = $stamp['timestamp']; + } else { + throw new Zend_Date_Exception('no timestamp given in array'); + } + } + + if ($calc === 'set') { + $return = $this->setUnixTimestamp($stamp); + } else { + $return = $this->_calcdetail($calc, $stamp, self::TIMESTAMP, null); + } + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + /** + * Sets a new timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to set + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setTimestamp($timestamp) + { + return $this->_timestamp('set', $timestamp); + } + + /** + * Adds a timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to add + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addTimestamp($timestamp) + { + return $this->_timestamp('add', $timestamp); + } + + /** + * Subtracts a timestamp + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to sub + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subTimestamp($timestamp) + { + return $this->_timestamp('sub', $timestamp); + } + + /** + * Compares two timestamps, returning the difference as integer + * + * @param integer|string|array|Zend_Date $timestamp Timestamp to compare + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareTimestamp($timestamp) + { + return $this->_timestamp('cmp', $timestamp); + } + + /** + * Returns a string representation of the object + * Supported format tokens are: + * G - era, y - year, Y - ISO year, M - month, w - week of year, D - day of year, d - day of month + * E - day of week, e - number of weekday (1-7), h - hour 1-12, H - hour 0-23, m - minute, s - second + * A - milliseconds of day, z - timezone, Z - timezone offset, S - fractional second, a - period of day + * + * Additionally format tokens but non ISO conform are: + * SS - day suffix, eee - php number of weekday(0-6), ddd - number of days per month + * l - Leap year, B - swatch internet time, I - daylight saving time, X - timezone offset in seconds + * r - RFC2822 format, U - unix timestamp + * + * Not supported ISO tokens are + * u - extended year, Q - quarter, q - quarter, L - stand alone month, W - week of month + * F - day of week of month, g - modified julian, c - stand alone weekday, k - hour 0-11, K - hour 1-24 + * v - wall zone + * + * @param string $format OPTIONAL Rule for formatting output. If null the default date format is used + * @param string $type OPTIONAL Type for the format string which overrides the standard setting + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function toString($format = null, $type = null, $locale = null) + { + if (is_object($format)) { + if ($format instanceof Zend_Locale) { + $locale = $format; + $format = null; + } else { + $format = (string) $format; + } + } + + if (is_object($type)) { + if ($type instanceof Zend_Locale) { + $locale = $type; + $type = null; + } else { + $type = (string) $type; + } + } + + if (($format !== null) && !defined($format) + && ($format != 'ee') && ($format != 'ss') && ($format != 'GG') && ($format != 'MM') && ($format != 'EE') && ($format != 'TT') + && Zend_Locale::isLocale($format, null, false)) { + $locale = $format; + $format = null; + } + + if (($type !== null) and ($type != 'php') and ($type != 'iso') and + Zend_Locale::isLocale($type, null, false)) { + $locale = $type; + $type = null; + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($format === null) { + $format = Zend_Locale_Format::getDateFormat($locale) . ' ' . Zend_Locale_Format::getTimeFormat($locale); + } else if (((self::$_options['format_type'] == 'php') && ($type === null)) or ($type == 'php')) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + + return $this->date($this->_toToken($format, $locale), $this->getUnixTimestamp(), false); + } + + /** + * Returns a string representation of the date which is equal with the timestamp + * + * @return string + */ + public function __toString() + { + return $this->toString(null, $this->_locale); + } + + /** + * Returns a integer representation of the object + * But returns false when the given part is no value f.e. Month-Name + * + * @param string|integer|Zend_Date $part OPTIONAL Defines the date or datepart to return as integer + * @return integer|false + */ + public function toValue($part = null) + { + $result = $this->get($part); + if (is_numeric($result)) { + return intval("$result"); + } else { + return false; + } + } + + /** + * Returns an array representation of the object + * + * @return array + */ + public function toArray() + { + return array('day' => $this->toString(self::DAY_SHORT, 'iso'), + 'month' => $this->toString(self::MONTH_SHORT, 'iso'), + 'year' => $this->toString(self::YEAR, 'iso'), + 'hour' => $this->toString(self::HOUR_SHORT, 'iso'), + 'minute' => $this->toString(self::MINUTE_SHORT, 'iso'), + 'second' => $this->toString(self::SECOND_SHORT, 'iso'), + 'timezone' => $this->toString(self::TIMEZONE, 'iso'), + 'timestamp' => $this->toString(self::TIMESTAMP, 'iso'), + 'weekday' => $this->toString(self::WEEKDAY_8601, 'iso'), + 'dayofyear' => $this->toString(self::DAY_OF_YEAR, 'iso'), + 'week' => $this->toString(self::WEEK, 'iso'), + 'gmtsecs' => $this->toString(self::TIMEZONE_SECS, 'iso')); + } + + /** + * Returns a representation of a date or datepart + * This could be for example a localized monthname, the time without date, + * the era or only the fractional seconds. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * + * @param string $part OPTIONAL Part of the date to return, if null the timestamp is returned + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string date or datepart + */ + public function get($part = null, $locale = null) + { + if ($locale === null) { + $locale = $this->getLocale(); + } + + if (($part !== null) && !defined($part) + && ($part != 'ee') && ($part != 'ss') && ($part != 'GG') && ($part != 'MM') && ($part != 'EE') && ($part != 'TT') + && Zend_Locale::isLocale($part, null, false)) { + $locale = $part; + $part = null; + } + + if ($part === null) { + $part = self::TIMESTAMP; + } else if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + return $this->date($this->_toToken($part, $locale), $this->getUnixTimestamp(), false); + } + + /** + * Internal method to apply tokens + * + * @param string $part + * @param string $locale + * @return string + */ + private function _toToken($part, $locale) { + // get format tokens + $comment = false; + $format = ''; + $orig = ''; + for ($i = 0; isset($part[$i]); ++$i) { + if ($part[$i] == "'") { + $comment = $comment ? false : true; + if (isset($part[$i+1]) && ($part[$i+1] == "'")) { + $comment = $comment ? false : true; + $format .= "\\'"; + ++$i; + } + + $orig = ''; + continue; + } + + if ($comment) { + $format .= '\\' . $part[$i]; + $orig = ''; + } else { + $orig .= $part[$i]; + if (!isset($part[$i+1]) || (isset($orig[0]) && ($orig[0] != $part[$i+1]))) { + $format .= $this->_parseIsoToDate($orig, $locale); + $orig = ''; + } + } + } + + return $format; + } + + /** + * Internal parsing method + * + * @param string $token + * @param string $locale + * @return string + */ + private function _parseIsoToDate($token, $locale) { + switch($token) { + case self::DAY : + return 'd'; + break; + + case self::WEEKDAY_SHORT : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday)); + return $this->_toComment(iconv_substr($day, 0, 3, 'UTF-8')); + break; + + case self::DAY_SHORT : + return 'j'; + break; + + case self::WEEKDAY : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'wide', $weekday))); + break; + + case self::WEEKDAY_8601 : + return 'N'; + break; + + case 'ee' : + return $this->_toComment(str_pad($this->date('N', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::DAY_SUFFIX : + return 'S'; + break; + + case self::WEEKDAY_DIGIT : + return 'w'; + break; + + case self::DAY_OF_YEAR : + return 'z'; + break; + + case 'DDD' : + return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 3, '0', STR_PAD_LEFT)); + break; + + case 'DD' : + return $this->_toComment(str_pad($this->date('z', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::WEEKDAY_NARROW : + case 'EEEEE' : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + $day = Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday)); + return $this->_toComment(iconv_substr($day, 0, 1, 'UTF-8')); + break; + + case self::WEEKDAY_NAME : + $weekday = strtolower($this->date('D', $this->getUnixTimestamp(), false)); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'day', array('gregorian', 'format', 'abbreviated', $weekday))); + break; + + case 'w' : + $week = $this->date('W', $this->getUnixTimestamp(), false); + return $this->_toComment(($week[0] == '0') ? $week[1] : $week); + break; + + case self::WEEK : + return 'W'; + break; + + case self::MONTH_NAME : + $month = $this->date('n', $this->getUnixTimestamp(), false); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'wide', $month))); + break; + + case self::MONTH : + return 'm'; + break; + + case self::MONTH_NAME_SHORT : + $month = $this->date('n', $this->getUnixTimestamp(), false); + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month))); + break; + + case self::MONTH_SHORT : + return 'n'; + break; + + case self::MONTH_DAYS : + return 't'; + break; + + case self::MONTH_NAME_NARROW : + $month = $this->date('n', $this->getUnixTimestamp(), false); + $mon = Zend_Locale_Data::getContent($locale, 'month', array('gregorian', 'format', 'abbreviated', $month)); + return $this->_toComment(iconv_substr($mon, 0, 1, 'UTF-8')); + break; + + case self::LEAPYEAR : + return 'L'; + break; + + case self::YEAR_8601 : + return 'o'; + break; + + case self::YEAR : + return 'Y'; + break; + + case self::YEAR_SHORT : + return 'y'; + break; + + case self::YEAR_SHORT_8601 : + return $this->_toComment(substr($this->date('o', $this->getUnixTimestamp(), false), -2, 2)); + break; + + case self::MERIDIEM : + $am = $this->date('a', $this->getUnixTimestamp(), false); + if ($am == 'am') { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'am')); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'pm')); + break; + + case self::SWATCH : + return 'B'; + break; + + case self::HOUR_SHORT_AM : + return 'g'; + break; + + case self::HOUR_SHORT : + return 'G'; + break; + + case self::HOUR_AM : + return 'h'; + break; + + case self::HOUR : + return 'H'; + break; + + case self::MINUTE : + return $this->_toComment(str_pad($this->date('i', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::SECOND : + return $this->_toComment(str_pad($this->date('s', $this->getUnixTimestamp(), false), 2, '0', STR_PAD_LEFT)); + break; + + case self::MINUTE_SHORT : + return 'i'; + break; + + case self::SECOND_SHORT : + return 's'; + break; + + case self::MILLISECOND : + return $this->_toComment($this->getMilliSecond()); + break; + + case self::TIMEZONE_NAME : + case 'vvvv' : + return 'e'; + break; + + case self::DAYLIGHT : + return 'I'; + break; + + case self::GMT_DIFF : + case 'ZZ' : + case 'ZZZ' : + return 'O'; + break; + + case self::GMT_DIFF_SEP : + return 'P'; + break; + + case self::TIMEZONE : + case 'v' : + case 'zz' : + case 'zzz' : + return 'T'; + break; + + case self::TIMEZONE_SECS : + return 'Z'; + break; + + case self::ISO_8601 : + return 'c'; + break; + + case self::RFC_2822 : + return 'r'; + break; + + case self::TIMESTAMP : + return 'U'; + break; + + case self::ERA : + case 'GG' : + case 'GGG' : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0'))); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1'))); + break; + + case self::ERA_NARROW : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '0')), 0, 1, 'UTF-8')) . '.'; + } + + return $this->_toComment(iconv_substr(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Abbr', '1')), 0, 1, 'UTF-8')) . '.'; + break; + + case self::ERA_NAME : + $year = $this->date('Y', $this->getUnixTimestamp(), false); + if ($year < 0) { + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '0'))); + } + + return $this->_toComment(Zend_Locale_Data::getContent($locale, 'era', array('gregorian', 'Names', '1'))); + break; + + case self::DATES : + return $this->_toToken(Zend_Locale_Format::getDateFormat($locale), $locale); + break; + + case self::DATE_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')), $locale); + break; + + case self::DATE_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')), $locale); + break; + + case self::DATE_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')), $locale); + break; + + case self::DATE_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')), $locale); + break; + + case self::TIMES : + return $this->_toToken(Zend_Locale_Format::getTimeFormat($locale), $locale); + break; + + case self::TIME_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'full'), $locale); + break; + + case self::TIME_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'long'), $locale); + break; + + case self::TIME_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'medium'), $locale); + break; + + case self::TIME_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'time', 'short'), $locale); + break; + + case self::DATETIME : + return $this->_toToken(Zend_Locale_Format::getDateTimeFormat($locale), $locale); + break; + + case self::DATETIME_FULL : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')), $locale); + break; + + case self::DATETIME_LONG : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')), $locale); + break; + + case self::DATETIME_MEDIUM : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')), $locale); + break; + + case self::DATETIME_SHORT : + return $this->_toToken(Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')), $locale); + break; + + case self::ATOM : + return 'Y\-m\-d\TH\:i\:sP'; + break; + + case self::COOKIE : + return 'l\, d\-M\-y H\:i\:s e'; + break; + + case self::RFC_822 : + return 'D\, d M y H\:i\:s O'; + break; + + case self::RFC_850 : + return 'l\, d\-M\-y H\:i\:s e'; + break; + + case self::RFC_1036 : + return 'D\, d M y H\:i\:s O'; + break; + + case self::RFC_1123 : + return 'D\, d M Y H\:i\:s O'; + break; + + case self::RFC_3339 : + return 'Y\-m\-d\TH\:i\:sP'; + break; + + case self::RSS : + return 'D\, d M Y H\:i\:s O'; + break; + + case self::W3C : + return 'Y\-m\-d\TH\:i\:sP'; + break; + } + + if ($token == '') { + return ''; + } + + switch ($token[0]) { + case 'y' : + if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) { + return 'Y'; + } + + $length = iconv_strlen($token, 'UTF-8'); + return $this->_toComment(str_pad($this->date('Y', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT)); + break; + + case 'Y' : + if ((strlen($token) == 4) && (abs($this->getUnixTimestamp()) <= 0x7FFFFFFF)) { + return 'o'; + } + + $length = iconv_strlen($token, 'UTF-8'); + return $this->_toComment(str_pad($this->date('o', $this->getUnixTimestamp(), false), $length, '0', STR_PAD_LEFT)); + break; + + case 'A' : + $length = iconv_strlen($token, 'UTF-8'); + $result = substr($this->getMilliSecond(), 0, 3); + $result += $this->date('s', $this->getUnixTimestamp(), false) * 1000; + $result += $this->date('i', $this->getUnixTimestamp(), false) * 60000; + $result += $this->date('H', $this->getUnixTimestamp(), false) * 3600000; + + return $this->_toComment(str_pad($result, $length, '0', STR_PAD_LEFT)); + break; + } + + return $this->_toComment($token); + } + + /** + * Private function to make a comment of a token + * + * @param string $token + * @return string + */ + private function _toComment($token) + { + $token = str_split($token); + $result = ''; + foreach ($token as $tok) { + $result .= '\\' . $tok; + } + + return $result; + } + + /** + * Return digit from standard names (english) + * Faster implementation than locale aware searching + * + * @param string $name + * @return integer Number of this month + * @throws Zend_Date_Exception + */ + private function _getDigitFromName($name) + { + switch($name) { + case "Jan": + return 1; + + case "Feb": + return 2; + + case "Mar": + return 3; + + case "Apr": + return 4; + + case "May": + return 5; + + case "Jun": + return 6; + + case "Jul": + return 7; + + case "Aug": + return 8; + + case "Sep": + return 9; + + case "Oct": + return 10; + + case "Nov": + return 11; + + case "Dec": + return 12; + + default: + throw new Zend_Date_Exception('Month ($name) is not a known month'); + } + } + + /** + * Counts the exact year number + * < 70 - 2000 added, >70 < 100 - 1900, others just returned + * + * @param integer $value year number + * @return integer Number of year + */ + public static function getFullYear($value) + { + if ($value >= 0) { + if ($value < 70) { + $value += 2000; + } else if ($value < 100) { + $value += 1900; + } + } + return $value; + } + + /** + * Sets the given date as new date or a given datepart as new datepart returning the new datepart + * This could be for example a localized dayname, the date without time, + * the month or only the seconds. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * + * @param string|integer|array|Zend_Date $date Date or datepart to set + * @param string $part OPTIONAL Part of the date to set, if null the timestamp is set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function set($date, $part = null, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $zone = $this->getTimezoneFromString($date); + $this->setTimezone($zone); + + $this->_calculate('set', $date, $part, $locale); + return $this; + } + + /** + * Adds a date or datepart to the existing date, by extracting $part from $date, + * and modifying this object by adding that part. The $part is then extracted from + * this object and returned as an integer or numeric string (for large values, or $part's + * corresponding to pre-defined formatted date strings). + * This could be for example a ISO 8601 date, the hour the monthname or only the minute. + * There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu. + * + * @param string|integer|array|Zend_Date $date Date or datepart to add + * @param string $part OPTIONAL Part of the date to add, if null the timestamp is added + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function add($date, $part = self::TIMESTAMP, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $this->_calculate('add', $date, $part, $locale); + return $this; + } + + /** + * Subtracts a date from another date. + * This could be for example a RFC2822 date, the time, + * the year or only the timestamp. There are about 50 different supported date parts. + * For a complete list of supported datepart values look into the docu + * Be aware: Adding -2 Months is not equal to Subtracting 2 Months !!! + * + * @param string|integer|array|Zend_Date $date Date or datepart to subtract + * @param string $part OPTIONAL Part of the date to sub, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function sub($date, $part = self::TIMESTAMP, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $this->_calculate('sub', $date, $part, $locale); + return $this; + } + + /** + * Compares a date or datepart with the existing one. + * Returns -1 if earlier, 0 if equal and 1 if later. + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with the date object + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compare($date, $part = self::TIMESTAMP, $locale = null) + { + if (self::$_options['format_type'] == 'php') { + $part = Zend_Locale_Format::convertPhpToIsoFormat($part); + } + + $compare = $this->_calculate('cmp', $date, $part, $locale); + + if ($compare > 0) { + return 1; + } else if ($compare < 0) { + return -1; + } + return 0; + } + + /** + * Returns a new instance of Zend_Date with the selected part copied. + * To make an exact copy, use PHP's clone keyword. + * For a complete list of supported date part values look into the docu. + * If a date part is copied, all other date parts are set to standard values. + * For example: If only YEAR is copied, the returned date object is equal to + * 01-01-YEAR 00:00:00 (01-01-1970 00:00:00 is equal to timestamp 0) + * If only HOUR is copied, the returned date object is equal to + * 01-01-1970 HOUR:00:00 (so $this contains a timestamp equal to a timestamp of 0 plus HOUR). + * + * @param string $part Part of the date to compare, if null the timestamp is subtracted + * @param string|Zend_Locale $locale OPTIONAL New object's locale. No adjustments to timezone are made. + * @return Zend_Date New clone with requested part + */ + public function copyPart($part, $locale = null) + { + $clone = clone $this; // copy all instance variables + $clone->setUnixTimestamp(0); // except the timestamp + if ($locale != null) { + $clone->setLocale($locale); // set an other locale if selected + } + $clone->set($this, $part); + return $clone; + } + + /** + * Internal function, returns the offset of a given timezone + * + * @param string $zone + * @return integer + */ + public function getTimezoneFromString($zone) + { + if (is_array($zone)) { + return $this->getTimezone(); + } + + if ($zone instanceof Zend_Date) { + return $zone->getTimezone(); + } + + $match = array(); + preg_match('/\dZ$/', $zone, $match); + if (!empty($match)) { + return "Etc/UTC"; + } + + preg_match('/([+-]\d{2}):{0,1}\d{2}/', $zone, $match); + if (!empty($match) and ($match[count($match) - 1] <= 14) and ($match[count($match) - 1] >= -12)) { + $zone = "Etc/GMT"; + $zone .= ($match[count($match) - 1] < 0) ? "+" : "-"; + $zone .= (int) abs($match[count($match) - 1]); + return $zone; + } + + preg_match('/([[:alpha:]\/_]{3,30})(?!.*([[:alpha:]\/]{3,30}))/', $zone, $match); + try { + if (!empty($match) and (!is_int($match[count($match) - 1]))) { + $oldzone = $this->getTimezone(); + $this->setTimezone($match[count($match) - 1]); + $result = $this->getTimezone(); + $this->setTimezone($oldzone); + if ($result !== $oldzone) { + return $match[count($match) - 1]; + } + } + } catch (Exception $e) { + // fall through + } + + return $this->getTimezone(); + } + + /** + * Calculates the date or object + * + * @param string $calc Calculation to make + * @param string|integer $date Date for calculation + * @param string|integer $comp Second date for calculation + * @param boolean|integer $dst Use dst correction if option is set + * @return integer|string|Zend_Date new timestamp or Zend_Date depending on calculation + */ + private function _assign($calc, $date, $comp = 0, $dst = false) + { + switch ($calc) { + case 'set' : + if (!empty($comp)) { + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $comp)); + } + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + case 'add' : + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$add, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + case 'sub' : + $this->setUnixTimestamp(call_user_func(Zend_Locale_Math::$sub, $this->getUnixTimestamp(), $date)); + $value = $this->getUnixTimestamp(); + break; + default : + // cmp - compare + return call_user_func(Zend_Locale_Math::$comp, $comp, $date); + break; + } + + // dst-correction if 'fix_dst' = true and dst !== false but only for non UTC and non GMT + if ((self::$_options['fix_dst'] === true) and ($dst !== false) and ($this->_dst === true)) { + $hour = $this->toString(self::HOUR, 'iso'); + if ($hour != $dst) { + if (($dst == ($hour + 1)) or ($dst == ($hour - 23))) { + $value += 3600; + } else if (($dst == ($hour - 1)) or ($dst == ($hour + 23))) { + $value -= 3600; + } + $this->setUnixTimestamp($value); + } + } + return $this->getUnixTimestamp(); + } + + + /** + * Calculates the date or object + * + * @param string $calc Calculation to make, one of: 'add'|'sub'|'cmp'|'copy'|'set' + * @param string|integer|array|Zend_Date $date Date or datepart to calculate with + * @param string $part Part of the date to calculate, if null the timestamp is used + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|string|Zend_Date new timestamp + * @throws Zend_Date_Exception + */ + private function _calculate($calc, $date, $part, $locale) + { + if ($date === null) { + throw new Zend_Date_Exception('parameter $date must be set, null is not allowed'); + } + + if (($part !== null) && (strlen($part) !== 2) && (Zend_Locale::isLocale($part, null, false))) { + $locale = $part; + $part = null; + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + $locale = (string) $locale; + + // Create date parts + $year = $this->toString(self::YEAR, 'iso'); + $month = $this->toString(self::MONTH_SHORT, 'iso'); + $day = $this->toString(self::DAY_SHORT, 'iso'); + $hour = $this->toString(self::HOUR_SHORT, 'iso'); + $minute = $this->toString(self::MINUTE_SHORT, 'iso'); + $second = $this->toString(self::SECOND_SHORT, 'iso'); + // If object extract value + if ($date instanceof Zend_Date) { + $date = $date->toString($part, 'iso', $locale); + } + + if (is_array($date) === true) { + if (empty($part) === false) { + switch($part) { + // Fall through + case self::DAY: + case self::DAY_SHORT: + if (isset($date['day']) === true) { + $date = $date['day']; + } + break; + // Fall through + case self::WEEKDAY_SHORT: + case self::WEEKDAY: + case self::WEEKDAY_8601: + case self::WEEKDAY_DIGIT: + case self::WEEKDAY_NARROW: + case self::WEEKDAY_NAME: + if (isset($date['weekday']) === true) { + $date = $date['weekday']; + $part = self::WEEKDAY_DIGIT; + } + break; + case self::DAY_OF_YEAR: + if (isset($date['day_of_year']) === true) { + $date = $date['day_of_year']; + } + break; + // Fall through + case self::MONTH: + case self::MONTH_SHORT: + case self::MONTH_NAME: + case self::MONTH_NAME_SHORT: + case self::MONTH_NAME_NARROW: + if (isset($date['month']) === true) { + $date = $date['month']; + } + break; + // Fall through + case self::YEAR: + case self::YEAR_SHORT: + case self::YEAR_8601: + case self::YEAR_SHORT_8601: + if (isset($date['year']) === true) { + $date = $date['year']; + } + break; + // Fall through + case self::HOUR: + case self::HOUR_AM: + case self::HOUR_SHORT: + case self::HOUR_SHORT_AM: + if (isset($date['hour']) === true) { + $date = $date['hour']; + } + break; + // Fall through + case self::MINUTE: + case self::MINUTE_SHORT: + if (isset($date['minute']) === true) { + $date = $date['minute']; + } + break; + // Fall through + case self::SECOND: + case self::SECOND_SHORT: + if (isset($date['second']) === true) { + $date = $date['second']; + } + break; + // Fall through + case self::TIMEZONE: + case self::TIMEZONE_NAME: + if (isset($date['timezone']) === true) { + $date = $date['timezone']; + } + break; + case self::TIMESTAMP: + if (isset($date['timestamp']) === true) { + $date = $date['timestamp']; + } + break; + case self::WEEK: + if (isset($date['week']) === true) { + $date = $date['week']; + } + break; + case self::TIMEZONE_SECS: + if (isset($date['gmtsecs']) === true) { + $date = $date['gmtsecs']; + } + break; + default: + throw new Zend_Date_Exception("datepart for part ($part) not found in array"); + break; + } + } else { + $hours = 0; + if (isset($date['hour']) === true) { + $hours = $date['hour']; + } + $minutes = 0; + if (isset($date['minute']) === true) { + $minutes = $date['minute']; + } + $seconds = 0; + if (isset($date['second']) === true) { + $seconds = $date['second']; + } + $months = 0; + if (isset($date['month']) === true) { + $months = $date['month']; + } + $days = 0; + if (isset($date['day']) === true) { + $days = $date['day']; + } + $years = 0; + if (isset($date['year']) === true) { + $years = $date['year']; + } + return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, $months, $days, $years, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), $hour); + } + } + + // $date as object, part of foreign date as own date + switch($part) { + + // day formats + case self::DAY: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date); + break; + + case self::WEEKDAY_SHORT: + $daylist = Zend_Locale_Data::getList($locale, 'day'); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + + foreach ($daylist as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 3, 'UTF-8')) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::DAY_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + intval($day), 1970, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date); + break; + + case self::WEEKDAY: + $daylist = Zend_Locale_Data::getList($locale, 'day'); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + + foreach ($daylist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::WEEKDAY_8601: + $weekday = (int) $this->toString(self::WEEKDAY_8601, 'iso', $locale); + if ((intval($date) > 0) and (intval($date) < 8)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + intval($date), 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::DAY_SUFFIX: + throw new Zend_Date_Exception('day suffix not supported', 0, null, $date); + break; + + case self::WEEKDAY_DIGIT: + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + if (is_numeric($date) and (intval($date) >= 0) and (intval($date) < 7)) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $date, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::DAY_OF_YEAR: + if (is_numeric($date)) { + if (($calc == 'add') || ($calc == 'sub')) { + $year = 1970; + ++$date; + ++$day; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, $date, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, day expected", 0, null, $date); + break; + + case self::WEEKDAY_NARROW: + $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated')); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + foreach ($daylist as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + case self::WEEKDAY_NAME: + $daylist = Zend_Locale_Data::getList($locale, 'day', array('gregorian', 'format', 'abbreviated')); + $weekday = (int) $this->toString(self::WEEKDAY_DIGIT, 'iso', $locale); + $cnt = 0; + foreach ($daylist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $cnt; + break; + } + ++$cnt; + } + + // Weekday found + if ($cnt < 7) { + return $this->_assign($calc, $this->mktime(0, 0, 0, 1, 1 + $found, 1970, true), + $this->mktime(0, 0, 0, 1, 1 + $weekday, 1970, true), $hour); + } + + // Weekday not found + throw new Zend_Date_Exception("invalid date ($date) operand, weekday expected", 0, null, $date); + break; + + // week formats + case self::WEEK: + if (is_numeric($date)) { + $week = (int) $this->toString(self::WEEK, 'iso', $locale); + return $this->_assign($calc, parent::mktime(0, 0, 0, 1, 1 + ($date * 7), 1970, true), + parent::mktime(0, 0, 0, 1, 1 + ($week * 7), 1970, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, week expected", 0, null, $date); + break; + + // month formats + case self::MONTH_NAME: + $monthlist = Zend_Locale_Data::getList($locale, 'month'); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc == 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH: + if (is_numeric($date)) { + $fixday = 0; + if ($calc == 'add') { + $date += $month; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $date; + $calc = 'set'; + if (self::$_options['extend_month'] == false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH_NAME_SHORT: + $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated')); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc == 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc == 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH_SHORT: + if (is_numeric($date) === true) { + $fixday = 0; + if ($calc === 'add') { + $date += $month; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc === 'sub') { + $date = $month - $date; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + case self::MONTH_DAYS: + throw new Zend_Date_Exception('month days not supported', 0, null, $date); + break; + + case self::MONTH_NAME_NARROW: + $monthlist = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'stand-alone', 'narrow')); + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) === strtoupper($date)) { + $found = $key; + break; + } + ++$cnt; + } + $date = array_search($date, $monthlist); + + // Monthname found + if ($cnt < 12) { + $fixday = 0; + if ($calc === 'add') { + $date += $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } else if ($calc === 'sub') { + $date = $month - $found; + $calc = 'set'; + if (self::$_options['extend_month'] === false) { + $parts = $this->getDateParts($this->mktime($hour, $minute, $second, $date, $day, $year, false)); + if ($parts['mday'] != $day) { + $fixday = ($parts['mday'] < $day) ? -$parts['mday'] : ($parts['mday'] - $day); + } + } + } + return $this->_assign($calc, $this->mktime(0, 0, 0, $date, $day + $fixday, $year, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), $hour); + } + + // Monthname not found + throw new Zend_Date_Exception("invalid date ($date) operand, month expected", 0, null, $date); + break; + + // year formats + case self::LEAPYEAR: + throw new Zend_Date_Exception('leap year not supported', 0, null, $date); + break; + + case self::YEAR_8601: + if (is_numeric($date)) { + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + case self::YEAR: + if (is_numeric($date)) { + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, intval($date), true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + case self::YEAR_SHORT: + if (is_numeric($date)) { + $date = intval($date); + if (($calc == 'set') || ($calc == 'cmp')) { + $date = self::getFullYear($date); + } + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + case self::YEAR_SHORT_8601: + if (is_numeric($date)) { + $date = intval($date); + if (($calc === 'set') || ($calc === 'cmp')) { + $date = self::getFullYear($date); + } + if ($calc === 'add') { + $date += $year; + $calc = 'set'; + } else if ($calc === 'sub') { + $date = $year - $date; + $calc = 'set'; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, $month, $day, $date, true), + $this->mktime(0, 0, 0, $month, $day, $year, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, year expected", 0, null, $date); + break; + + // time formats + case self::MERIDIEM: + throw new Zend_Date_Exception('meridiem not supported', 0, null, $date); + break; + + case self::SWATCH: + if (is_numeric($date)) { + $rest = intval($date); + $hours = floor($rest * 24 / 1000); + $rest = $rest - ($hours * 1000 / 24); + $minutes = floor($rest * 1440 / 1000); + $rest = $rest - ($minutes * 1000 / 1440); + $seconds = floor($rest * 86400 / 1000); + return $this->_assign($calc, $this->mktime($hours, $minutes, $seconds, 1, 1, 1970, true), + $this->mktime($hour, $minute, $second, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, swatchstamp expected", 0, null, $date); + break; + + case self::HOUR_SHORT_AM: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::HOUR_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::HOUR_AM: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::HOUR: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(intval($date), 0, 0, 1, 1, 1970, true), + $this->mktime($hour, 0, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, hour expected", 0, null, $date); + break; + + case self::MINUTE: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true), + $this->mktime(0, $minute, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", 0, null, $date); + break; + + case self::SECOND: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true), + $this->mktime(0, 0, $second, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, second expected", 0, null, $date); + break; + + case self::MILLISECOND: + if (is_numeric($date)) { + switch($calc) { + case 'set' : + return $this->setMillisecond($date); + break; + case 'add' : + return $this->addMillisecond($date); + break; + case 'sub' : + return $this->subMillisecond($date); + break; + } + + return $this->compareMillisecond($date); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, milliseconds expected", 0, null, $date); + break; + + case self::MINUTE_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, intval($date), 0, 1, 1, 1970, true), + $this->mktime(0, $minute, 0, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, minute expected", 0, null, $date); + break; + + case self::SECOND_SHORT: + if (is_numeric($date)) { + return $this->_assign($calc, $this->mktime(0, 0, intval($date), 1, 1, 1970, true), + $this->mktime(0, 0, $second, 1, 1, 1970, true), false); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, second expected", 0, null, $date); + break; + + // timezone formats + // break intentionally omitted + case self::TIMEZONE_NAME: + case self::TIMEZONE: + case self::TIMEZONE_SECS: + throw new Zend_Date_Exception('timezone not supported', 0, null, $date); + break; + + case self::DAYLIGHT: + throw new Zend_Date_Exception('daylight not supported', 0, null, $date); + break; + + case self::GMT_DIFF: + case self::GMT_DIFF_SEP: + throw new Zend_Date_Exception('gmtdiff not supported', 0, null, $date); + break; + + // date strings + case self::ISO_8601: + // (-)YYYY-MM-dd + preg_match('/^(-{0,1}\d{4})-(\d{2})-(\d{2})/', $date, $datematch); + // (-)YY-MM-dd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{2})-(\d{2})-(\d{2})/', $date, $datematch); + } + // (-)YYYYMMdd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{4})(\d{2})(\d{2})/', $date, $datematch); + } + // (-)YYMMdd + if (empty($datematch)) { + preg_match('/^(-{0,1}\d{2})(\d{2})(\d{2})/', $date, $datematch); + } + $tmpdate = $date; + if (!empty($datematch)) { + $dateMatchCharCount = iconv_strlen($datematch[0], 'UTF-8'); + $tmpdate = iconv_substr($date, + $dateMatchCharCount, + iconv_strlen($date, 'UTF-8') - $dateMatchCharCount, + 'UTF-8'); + } + // (T)hh:mm:ss + preg_match('/[T,\s]{0,1}(\d{2}):(\d{2}):(\d{2})/', $tmpdate, $timematch); + if (empty($timematch)) { + preg_match('/[T,\s]{0,1}(\d{2})(\d{2})(\d{2})/', $tmpdate, $timematch); + } + if (empty($datematch) and empty($timematch)) { + throw new Zend_Date_Exception("unsupported ISO8601 format ($date)", 0, null, $date); + } + if (!empty($timematch)) { + $timeMatchCharCount = iconv_strlen($timematch[0], 'UTF-8'); + $tmpdate = iconv_substr($tmpdate, + $timeMatchCharCount, + iconv_strlen($tmpdate, 'UTF-8') - $timeMatchCharCount, + 'UTF-8'); + } + if (empty($datematch)) { + $datematch[1] = 1970; + $datematch[2] = 1; + $datematch[3] = 1; + } else if (iconv_strlen($datematch[1], 'UTF-8') == 2) { + $datematch[1] = self::getFullYear($datematch[1]); + } + if (empty($timematch)) { + $timematch[1] = 0; + $timematch[2] = 0; + $timematch[3] = 0; + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$datematch[2]; + --$month; + --$datematch[3]; + --$day; + $datematch[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($timematch[1], $timematch[2], $timematch[3], 1 + $datematch[2], 1 + $datematch[3], 1970 + $datematch[1], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::RFC_2822: + $result = preg_match('/^\w{3},\s(\d{1,2})\s(\w{3})\s(\d{4})\s' + . '(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]' + . '{1}\d{4}|\w{1,20})$/', $date, $match); + + if (!$result) { + throw new Zend_Date_Exception("no RFC 2822 format ($date)", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::TIMESTAMP: + if (is_numeric($date)) { + return $this->_assign($calc, $date, $this->getUnixTimestamp()); + } + + throw new Zend_Date_Exception("invalid date ($date) operand, timestamp expected", 0, null, $date); + break; + + // additional formats + // break intentionally omitted + case self::ERA: + case self::ERA_NAME: + throw new Zend_Date_Exception('era not supported', 0, null, $date); + break; + + case self::DATES: + try { + $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')){ + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATE_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + $parsed['year'] = self::getFullYear($parsed['year']); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime(0, 0, 0, 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime(0, 0, 0, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIMES: + try { + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + $parsed = Zend_Locale_Format::getTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::TIME_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if ($calc != 'set') { + $month = 1; + $day = 1; + $year = 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], $month, $day, $year, true), + $this->mktime($hour, $minute, $second, $month, $day, $year, true), false); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME: + try { + $parsed = Zend_Locale_Format::getDateTime($date, array('locale' => $locale, 'format_type' => 'iso', 'fix_date' => true)); + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_FULL: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_LONG: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + if (($calc == 'set') || ($calc == 'cmp')){ + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_MEDIUM: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + case self::DATETIME_SHORT: + try { + $format = Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')); + $parsed = Zend_Locale_Format::getDateTime($date, array('date_format' => $format, 'format_type' => 'iso', 'locale' => $locale)); + + $parsed['year'] = self::getFullYear($parsed['year']); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$parsed['month']; + --$month; + --$parsed['day']; + --$day; + $parsed['year'] -= 1970; + $year -= 1970; + } + + if (!isset($parsed['second'])) { + $parsed['second'] = 0; + } + + return $this->_assign($calc, $this->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], 1 + $parsed['month'], 1 + $parsed['day'], 1970 + $parsed['year'], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), $hour); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + break; + + // ATOM and RFC_3339 are identical + case self::ATOM: + case self::RFC_3339: + $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\d{0,4}([+-]{1}\d{2}:\d{2}|Z)$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, ATOM format expected", 0, null, $date); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$match[2]; + --$month; + --$match[3]; + --$day; + $match[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::COOKIE: + $result = preg_match("/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,20}$/", $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, COOKIE format expected", 0, null, $date); + } + $matchStartPos = iconv_strpos($match[0], ' ', 0, 'UTF-8') + 1; + $match[0] = iconv_substr($match[0], + $matchStartPos, + iconv_strlen($match[0], 'UTF-8') - $matchStartPos, + 'UTF-8'); + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RFC_822: + case self::RFC_1036: + // new RFC 822 format, identical to RFC 1036 standard + $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 822 date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], false), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, false), false); + break; + + case self::RFC_850: + $result = preg_match('/^\w{6,9},\s(\d{2})-(\w{3})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s.{3,21}$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 850 date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RFC_1123: + $result = preg_match('/^\w{0,3},{0,1}\s{0,1}(\d{1,2})\s(\w{3})\s(\d{2,4})\s(\d{2}):(\d{2}):{0,1}(\d{0,2})\s([+-]{1}\d{4}|\w{1,20})$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RFC 1123 date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::RSS: + $result = preg_match('/^\w{3},\s(\d{2})\s(\w{3})\s(\d{2,4})\s(\d{1,2}):(\d{2}):(\d{2})\s.{1,21}$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, RSS date format expected", 0, null, $date); + } + + $months = $this->_getDigitFromName($match[2]); + $match[3] = self::getFullYear($match[3]); + + if (($calc == 'set') || ($calc == 'cmp')) { + --$months; + --$month; + --$match[1]; + --$day; + $match[3] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $months, 1 + $match[1], 1970 + $match[3], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + case self::W3C: + $result = preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})[+-]{1}\d{2}:\d{2}$/', $date, $match); + if (!$result) { + throw new Zend_Date_Exception("invalid date ($date) operand, W3C date format expected", 0, null, $date); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + --$match[2]; + --$month; + --$match[3]; + --$day; + $match[1] -= 1970; + $year -= 1970; + } + return $this->_assign($calc, $this->mktime($match[4], $match[5], $match[6], 1 + $match[2], 1 + $match[3], 1970 + $match[1], true), + $this->mktime($hour, $minute, $second, 1 + $month, 1 + $day, 1970 + $year, true), false); + break; + + default: + if (!is_numeric($date) || !empty($part)) { + try { + if (empty($part)) { + $part = Zend_Locale_Format::getDateFormat($locale) . " "; + $part .= Zend_Locale_Format::getTimeFormat($locale); + } + + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $part, 'locale' => $locale, 'fix_date' => true, 'format_type' => 'iso')); + if ((strpos(strtoupper($part), 'YY') !== false) and (strpos(strtoupper($part), 'YYYY') === false)) { + $parsed['year'] = self::getFullYear($parsed['year']); + } + + if (($calc == 'set') || ($calc == 'cmp')) { + if (isset($parsed['month'])) { + --$parsed['month']; + } else { + $parsed['month'] = 0; + } + + if (isset($parsed['day'])) { + --$parsed['day']; + } else { + $parsed['day'] = 0; + } + + if (!isset($parsed['year'])) { + $parsed['year'] = 1970; + } + } + + return $this->_assign($calc, $this->mktime( + isset($parsed['hour']) ? $parsed['hour'] : 0, + isset($parsed['minute']) ? $parsed['minute'] : 0, + isset($parsed['second']) ? $parsed['second'] : 0, + isset($parsed['month']) ? (1 + $parsed['month']) : 1, + isset($parsed['day']) ? (1 + $parsed['day']) : 1, + $parsed['year'], + false), $this->getUnixTimestamp(), false); + } catch (Zend_Locale_Exception $e) { + if (!is_numeric($date)) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e, $date); + } + } + } + + return $this->_assign($calc, $date, $this->getUnixTimestamp(), false); + break; + } + } + + /** + * Returns true when both date objects or date parts are equal. + * For example: + * 15.May.2000 <-> 15.June.2000 Equals only for Day or Year... all other will return false + * + * @param string|integer|array|Zend_Date $date Date or datepart to equal with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function equals($date, $part = self::TIMESTAMP, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == 0) { + return true; + } + + return false; + } + + /** + * Returns if the given date or datepart is earlier + * For example: + * 15.May.2000 <-> 13.June.1999 will return true for day, year and date, but not for month + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function isEarlier($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == -1) { + return true; + } + + return false; + } + + /** + * Returns if the given date or datepart is later + * For example: + * 15.May.2000 <-> 13.June.1999 will return true for month but false for day, year and date + * Returns if the given date is later + * + * @param string|integer|array|Zend_Date $date Date or datepart to compare with + * @param string $part OPTIONAL Part of the date to compare, if null the timestamp is used + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return boolean + * @throws Zend_Date_Exception + */ + public function isLater($date, $part = null, $locale = null) + { + $result = $this->compare($date, $part, $locale); + + if ($result == 1) { + return true; + } + + return false; + } + + /** + * Returns only the time of the date as new Zend_Date object + * For example: + * 15.May.2000 10:11:23 will return a dateobject equal to 01.Jan.1970 10:11:23 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getTime($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'H:i:s'; + } else { + $format = self::TIME_MEDIUM; + } + + return $this->copyPart($format, $locale); + } + + /** + * Returns the calculated time + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $time Time to calculate with, if null the actual time is taken + * @param string $format Timeformat for parsing input + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new time + * @throws Zend_Date_Exception + */ + private function _time($calc, $time, $format, $locale) + { + if ($time === null) { + throw new Zend_Date_Exception('parameter $time must be set, null is not allowed'); + } + + if ($time instanceof Zend_Date) { + // extract time from object + $time = $time->toString('HH:mm:ss', 'iso'); + } else { + if (is_array($time)) { + if ((isset($time['hour']) === true) or (isset($time['minute']) === true) or + (isset($time['second']) === true)) { + $parsed = $time; + } else { + throw new Zend_Date_Exception("no hour, minute or second given in array"); + } + } else { + if (self::$_options['format_type'] == 'php') { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + try { + if ($locale === null) { + $locale = $this->getLocale(); + } + + $parsed = Zend_Locale_Format::getTime($time, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso')); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e); + } + } + + if (!array_key_exists('hour', $parsed)) { + $parsed['hour'] = 0; + } + + if (!array_key_exists('minute', $parsed)) { + $parsed['minute'] = 0; + } + + if (!array_key_exists('second', $parsed)) { + $parsed['second'] = 0; + } + + $time = str_pad($parsed['hour'], 2, '0', STR_PAD_LEFT) . ":"; + $time .= str_pad($parsed['minute'], 2, '0', STR_PAD_LEFT) . ":"; + $time .= str_pad($parsed['second'], 2, '0', STR_PAD_LEFT); + } + + $return = $this->_calcdetail($calc, $time, self::TIMES, 'de'); + if ($calc != 'cmp') { + return $this; + } + + return $return; + } + + + /** + * Sets a new time for the date object. Format defines how to parse the time string. + * Also a complete date can be given, but only the time is used for setting. + * For example: dd.MMMM.yyTHH:mm' and 'ss sec'-> 10.May.07T25:11 and 44 sec => 1h11min44sec + 1 day + * Returned is the new date object and the existing date is left as it was before + * + * @param string|integer|array|Zend_Date $time Time to set + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setTime($time, $format = null, $locale = null) + { + return $this->_time('set', $time, $format, $locale); + } + + + /** + * Adds a time to the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> +10 hours + * + * @param string|integer|array|Zend_Date $time Time to add + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addTime($time, $format = null, $locale = null) + { + return $this->_time('add', $time, $format, $locale); + } + + + /** + * Subtracts a time from the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> -10 hours + * + * @param string|integer|array|Zend_Date $time Time to sub + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid inteface + * @throws Zend_Date_Exception + */ + public function subTime($time, $format = null, $locale = null) + { + return $this->_time('sub', $time, $format, $locale); + } + + + /** + * Compares the time from the existing date. Format defines how to parse the time string. + * If only parts are given the other parts are set to default. + * If no format us given, the standardformat of this locale is used. + * For example: HH:mm:ss -> 10 -> 10 hours + * + * @param string|integer|array|Zend_Date $time Time to compare + * @param string $format OPTIONAL Timeformat for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareTime($time, $format = null, $locale = null) + { + return $this->_time('cmp', $time, $format, $locale); + } + + /** + * Returns a clone of $this, with the time part set to 00:00:00. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDate($locale = null) + { + $orig = self::$_options['format_type']; + if (self::$_options['format_type'] == 'php') { + self::$_options['format_type'] = 'iso'; + } + + $date = $this->copyPart(self::DATE_MEDIUM, $locale); + $date->addTimestamp($this->getGmtOffset()); + self::$_options['format_type'] = $orig; + + return $date; + } + + /** + * Returns the calculated date + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $date Date to calculate with, if null the actual date is taken + * @param string $format Date format for parsing + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new date + * @throws Zend_Date_Exception + */ + private function _date($calc, $date, $format, $locale) + { + if ($date === null) { + throw new Zend_Date_Exception('parameter $date must be set, null is not allowed'); + } + + if ($date instanceof Zend_Date) { + // extract date from object + $date = $date->toString('d.M.y', 'iso'); + } else { + if (is_array($date)) { + if ((isset($date['year']) === true) or (isset($date['month']) === true) or + (isset($date['day']) === true)) { + $parsed = $date; + } else { + throw new Zend_Date_Exception("no day,month or year given in array"); + } + } else { + if ((self::$_options['format_type'] == 'php') && !defined($format)) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + try { + if ($locale === null) { + $locale = $this->getLocale(); + } + + $parsed = Zend_Locale_Format::getDate($date, array('date_format' => $format, 'locale' => $locale, 'format_type' => 'iso')); + if ((strpos(strtoupper($format), 'YY') !== false) and (strpos(strtoupper($format), 'YYYY') === false)) { + $parsed['year'] = self::getFullYear($parsed['year']); + } + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e); + } + } + + if (!array_key_exists('day', $parsed)) { + $parsed['day'] = 1; + } + + if (!array_key_exists('month', $parsed)) { + $parsed['month'] = 1; + } + + if (!array_key_exists('year', $parsed)) { + $parsed['year'] = 0; + } + + $date = $parsed['day'] . "." . $parsed['month'] . "." . $parsed['year']; + } + + $return = $this->_calcdetail($calc, $date, self::DATE_MEDIUM, 'de'); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new date for the date object. Format defines how to parse the date string. + * Also a complete date with time can be given, but only the date is used for setting. + * For example: MMMM.yy HH:mm-> May.07 22:11 => 01.May.07 00:00 + * Returned is the new date object and the existing time is left as it was before + * + * @param string|integer|array|Zend_Date $date Date to set + * @param string $format OPTIONAL Date format for parsing + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setDate($date, $format = null, $locale = null) + { + return $this->_date('set', $date, $format, $locale); + } + + + /** + * Adds a date to the existing date object. Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: MM.dd.YYYY -> 10 -> +10 months + * + * @param string|integer|array|Zend_Date $date Date to add + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addDate($date, $format = null, $locale = null) + { + return $this->_date('add', $date, $format, $locale); + } + + + /** + * Subtracts a date from the existing date object. Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: MM.dd.YYYY -> 10 -> -10 months + * Be aware: Subtracting 2 months is not equal to Adding -2 months !!! + * + * @param string|integer|array|Zend_Date $date Date to sub + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subDate($date, $format = null, $locale = null) + { + return $this->_date('sub', $date, $format, $locale); + } + + + /** + * Compares the date from the existing date object, ignoring the time. + * Format defines how to parse the date string. + * If only parts are given the other parts are set to 0. + * If no format is given, the standardformat of this locale is used. + * For example: 10.01.2000 => 10.02.1999 -> false + * + * @param string|integer|array|Zend_Date $date Date to compare + * @param string $format OPTIONAL Date format for parsing input + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDate($date, $format = null, $locale = null) + { + return $this->_date('cmp', $date, $format, $locale); + } + + + /** + * Returns the full ISO 8601 date from the date object. + * Always the complete ISO 8601 specifiction is used. If an other ISO date is needed + * (ISO 8601 defines several formats) use toString() instead. + * This function does not return the ISO date as object. Use copy() instead. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function getIso($locale = null) + { + return $this->toString(self::ISO_8601, 'iso', $locale); + } + + + /** + * Sets a new date for the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> 01.Sept.2005 00:00:00, 20050201T10:00:30 -> 01.Feb.2005 10h00m30s + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setIso($date, $locale = null) + { + return $this->_calcvalue('set', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Adds a ISO date to the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> + 01.Sept.2005 00:00:00, 10:00:00 -> +10h + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addIso($date, $locale = null) + { + return $this->_calcvalue('add', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Subtracts a ISO date from the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h + * Returned is the new date object + * + * @param string|integer|Zend_Date $date ISO Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subIso($date, $locale = null) + { + return $this->_calcvalue('sub', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Compares a ISO date with the date object. Not given parts are set to default. + * Only supported ISO 8601 formats are accepted. + * For example: 050901 -> - 01.Sept.2005 00:00:00, 10:00:00 -> -10h + * Returns if equal, earlier or later + * + * @param string|integer|Zend_Date $date ISO Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareIso($date, $locale = null) + { + return $this->_calcvalue('cmp', $date, 'iso', self::ISO_8601, $locale); + } + + + /** + * Returns a RFC 822 compilant datestring from the date object. + * This function does not return the RFC date as object. Use copy() instead. + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return string + */ + public function getArpa($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'D\, d M y H\:i\:s O'; + } else { + $format = self::RFC_822; + } + + return $this->toString($format, 'iso', $locale); + } + + + /** + * Sets a RFC 822 date as new date for the date object. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setArpa($date, $locale = null) + { + return $this->_calcvalue('set', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Adds a RFC 822 date to the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 Date to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addArpa($date, $locale = null) + { + return $this->_calcvalue('add', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Subtracts a RFC 822 date from the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returned is the new date object + * + * @param string|integer|Zend_Date $date RFC 822 Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subArpa($date, $locale = null) + { + return $this->_calcvalue('sub', $date, 'arpa', self::RFC_822, $locale); + } + + + /** + * Compares a RFC 822 compilant date with the date object. + * ARPA messages are used in emails or HTTP Headers. + * Only RFC 822 compilant date strings are accepted. + * For example: Sat, 14 Feb 09 00:31:30 +0100 + * Returns if equal, earlier or later + * + * @param string|integer|Zend_Date $date RFC 822 Date to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareArpa($date, $locale = null) + { + return $this->_calcvalue('cmp', $date, 'arpa', self::RFC_822, $locale); + } + + /** + * Check if location is supported + * + * @param array $location locations array + * @throws Zend_Date_Exception + * @return float $horizon float + */ + private function _checkLocation($location) + { + if (!isset($location['longitude']) or !isset($location['latitude'])) { + throw new Zend_Date_Exception('Location must include \'longitude\' and \'latitude\'', 0, null, $location); + } + if (($location['longitude'] > 180) or ($location['longitude'] < -180)) { + throw new Zend_Date_Exception('Longitude must be between -180 and 180', 0, null, $location); + } + if (($location['latitude'] > 90) or ($location['latitude'] < -90)) { + throw new Zend_Date_Exception('Latitude must be between -90 and 90', 0, null, $location); + } + + if (!isset($location['horizon'])){ + $location['horizon'] = 'effective'; + } + + switch ($location['horizon']) { + case 'civil' : + return -0.104528; + break; + case 'nautic' : + return -0.207912; + break; + case 'astronomic' : + return -0.309017; + break; + default : + return -0.0145439; + break; + } + } + + + /** + * Returns the time of sunrise for this date and a given location as new date object + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param array $location location of sunrise + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function getSunrise($location) + { + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP); + return $result; + } + + + /** + * Returns the time of sunset for this date and a given location as new date object + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param array $location location of sunset + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return Zend_Date + * @throws Zend_Date_Exception + */ + public function getSunset($location) + { + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP); + return $result; + } + + + /** + * Returns an array with the sunset and sunrise dates for all horizon types + * For a list of cities and correct locations use the class Zend_Date_Cities + * + * @param array $location location of suninfo + * ['horizon'] -> civil, nautic, astronomical, effective (default) + * ['longitude'] -> longitude of location + * ['latitude'] -> latitude of location + * @return array - [sunset|sunrise][effective|civil|nautic|astronomic] + * @throws Zend_Date_Exception + */ + public function getSunInfo($location) + { + $suninfo = array(); + for ($i = 0; $i < 4; ++$i) { + switch ($i) { + case 0 : + $location['horizon'] = 'effective'; + break; + case 1 : + $location['horizon'] = 'civil'; + break; + case 2 : + $location['horizon'] = 'nautic'; + break; + case 3 : + $location['horizon'] = 'astronomic'; + break; + } + $horizon = $this->_checkLocation($location); + $result = clone $this; + $result->set($this->calcSun($location, $horizon, true), self::TIMESTAMP); + $suninfo['sunrise'][$location['horizon']] = $result; + $result = clone $this; + $result->set($this->calcSun($location, $horizon, false), self::TIMESTAMP); + $suninfo['sunset'][$location['horizon']] = $result; + } + return $suninfo; + } + + /** + * Check a given year for leap year. + * + * @param integer|array|Zend_Date $year Year to check + * @throws Zend_Date_Exception + * @return boolean + */ + public static function checkLeapYear($year) + { + if ($year instanceof Zend_Date) { + $year = (int) $year->toString(self::YEAR, 'iso'); + } + + if (is_array($year)) { + if (isset($year['year']) === true) { + $year = $year['year']; + } else { + throw new Zend_Date_Exception("no year given in array"); + } + } + + if (!is_numeric($year)) { + throw new Zend_Date_Exception("year ($year) has to be integer for checkLeapYear()", 0, null, $year); + } + + return (bool) parent::isYearLeapYear($year); + } + + + /** + * Returns true, if the year is a leap year. + * + * @return boolean + */ + public function isLeapYear() + { + return self::checkLeapYear($this); + } + + + /** + * Returns if the set date is todays date + * + * @return boolean + */ + public function isToday() + { + $today = $this->date('Ymd', $this->_getTime()); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return ($today == $day); + } + + + /** + * Returns if the set date is yesterdays date + * + * @return boolean + */ + public function isYesterday() + { + list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime())); + // adjusts for leap days and DST changes that are timezone specific + $yesterday = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day -1, $year)); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return $day == $yesterday; + } + + + /** + * Returns if the set date is tomorrows date + * + * @return boolean + */ + public function isTomorrow() + { + list($year, $month, $day) = explode('-', $this->date('Y-m-d', $this->_getTime())); + // adjusts for leap days and DST changes that are timezone specific + $tomorrow = $this->date('Ymd', $this->mktime(0, 0, 0, $month, $day +1, $year)); + $day = $this->date('Ymd', $this->getUnixTimestamp()); + return $day == $tomorrow; + } + + /** + * Returns the actual date as new date object + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public static function now($locale = null) + { + return new Zend_Date(time(), self::TIMESTAMP, $locale); + } + + /** + * Calculate date details + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $date Date or Part to calculate + * @param string $type Datepart for Calculation + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|string new date + * @throws Zend_Date_Exception + */ + private function _calcdetail($calc, $date, $type, $locale) + { + $old = false; + if (self::$_options['format_type'] == 'php') { + self::$_options['format_type'] = 'iso'; + $old = true; + } + + switch($calc) { + case 'set' : + $return = $this->set($date, $type, $locale); + break; + case 'add' : + $return = $this->add($date, $type, $locale); + break; + case 'sub' : + $return = $this->sub($date, $type, $locale); + break; + default : + $return = $this->compare($date, $type, $locale); + break; + } + + if ($old) { + self::$_options['format_type'] = 'php'; + } + + return $return; + } + + /** + * Internal calculation, returns the requested date type + * + * @param string $calc Calculation to make + * @param string|integer|Zend_Date $value Datevalue to calculate with, if null the actual value is taken + * @param string $type + * @param string $parameter + * @param string|Zend_Locale $locale Locale for parsing input + * @throws Zend_Date_Exception + * @return integer|Zend_Date new date + */ + private function _calcvalue($calc, $value, $type, $parameter, $locale) + { + if ($value === null) { + throw new Zend_Date_Exception("parameter $type must be set, null is not allowed"); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($value instanceof Zend_Date) { + // extract value from object + $value = $value->toString($parameter, 'iso', $locale); + } else if (!is_array($value) && !is_numeric($value) && ($type != 'iso') && ($type != 'arpa')) { + throw new Zend_Date_Exception("invalid $type ($value) operand", 0, null, $value); + } + + $return = $this->_calcdetail($calc, $value, $parameter, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Returns only the year from the date object as new object. + * For example: 10.May.2000 10:30:00 -> 01.Jan.2000 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getYear($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'Y'; + } else { + $format = self::YEAR; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets a new year + * If the year is between 0 and 69, 2000 will be set (2000-2069) + * If the year if between 70 and 99, 1999 will be set (1970-1999) + * 3 or 4 digit years are set as expected. If you need to set year 0-99 + * use set() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $year Year to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setYear($year, $locale = null) + { + return $this->_calcvalue('set', $year, 'year', self::YEAR, $locale); + } + + + /** + * Adds the year to the existing date object + * If the year is between 0 and 69, 2000 will be added (2000-2069) + * If the year if between 70 and 99, 1999 will be added (1970-1999) + * 3 or 4 digit years are added as expected. If you need to add years from 0-99 + * use add() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $year Year to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addYear($year, $locale = null) + { + return $this->_calcvalue('add', $year, 'year', self::YEAR, $locale); + } + + + /** + * Subs the year from the existing date object + * If the year is between 0 and 69, 2000 will be subtracted (2000-2069) + * If the year if between 70 and 99, 1999 will be subtracted (1970-1999) + * 3 or 4 digit years are subtracted as expected. If you need to subtract years from 0-99 + * use sub() instead. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $year Year to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subYear($year, $locale = null) + { + return $this->_calcvalue('sub', $year, 'year', self::YEAR, $locale); + } + + + /** + * Compares the year with the existing date object, ignoring other date parts. + * For example: 10.03.2000 -> 15.02.2000 -> true + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $year Year to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareYear($year, $locale = null) + { + return $this->_calcvalue('cmp', $year, 'year', self::YEAR, $locale); + } + + + /** + * Returns only the month from the date object as new object. + * For example: 10.May.2000 10:30:00 -> 01.May.1970 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getMonth($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'm'; + } else { + $format = self::MONTH; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Returns the calculated month + * + * @param string $calc Calculation to make + * @param string|integer|array|Zend_Date $month Month to calculate with, if null the actual month is taken + * @param string|Zend_Locale $locale Locale for parsing input + * @return integer|Zend_Date new time + * @throws Zend_Date_Exception + */ + private function _month($calc, $month, $locale) + { + if ($month === null) { + throw new Zend_Date_Exception('parameter $month must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($month instanceof Zend_Date) { + // extract month from object + $found = $month->toString(self::MONTH_SHORT, 'iso', $locale); + } else { + if (is_numeric($month)) { + $found = $month; + } else if (is_array($month)) { + if (isset($month['month']) === true) { + $month = $month['month']; + } else { + throw new Zend_Date_Exception("no month given in array"); + } + } else { + $monthlist = Zend_Locale_Data::getList($locale, 'month'); + $monthlist2 = Zend_Locale_Data::getList($locale, 'month', array('gregorian', 'format', 'abbreviated')); + + $monthlist = array_merge($monthlist, $monthlist2); + $found = 0; + $cnt = 0; + foreach ($monthlist as $key => $value) { + if (strtoupper($value) == strtoupper($month)) { + $found = ($key % 12) + 1; + break; + } + ++$cnt; + } + if ($found == 0) { + foreach ($monthlist2 as $key => $value) { + if (strtoupper(iconv_substr($value, 0, 1, 'UTF-8')) == strtoupper($month)) { + $found = $key + 1; + break; + } + ++$cnt; + } + } + if ($found == 0) { + throw new Zend_Date_Exception("unknown month name ($month)", 0, null, $month); + } + } + } + $return = $this->_calcdetail($calc, $found, self::MONTH_SHORT, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new month + * The month can be a number or a string. Setting months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setMonth($month, $locale = null) + { + return $this->_month('set', $month, $locale); + } + + + /** + * Adds months to the existing date object. + * The month can be a number or a string. Adding months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addMonth($month, $locale = null) + { + return $this->_month('add', $month, $locale); + } + + + /** + * Subtracts months from the existing date object. + * The month can be a number or a string. Subtracting months lower then 0 and greater then 12 + * will result in adding or subtracting the relevant year. (12 months equal one year) + * If a localized monthname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * + * @param string|integer|array|Zend_Date $month Month to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subMonth($month, $locale = null) + { + return $this->_month('sub', $month, $locale); + } + + + /** + * Compares the month with the existing date object, ignoring other date parts. + * For example: 10.03.2000 -> 15.03.1950 -> true + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $month Month to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareMonth($month, $locale = null) + { + return $this->_month('cmp', $month, $locale); + } + + + /** + * Returns the day as new date object + * Example: 20.May.1986 -> 20.Jan.1970 00:00:00 + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDay($locale = null) + { + return $this->copyPart(self::DAY_SHORT, $locale); + } + + /** + * Returns the calculated day + * + * @param string $calc Type of calculation to make + * @param Zend_Date $day Day to calculate, when null the actual day is calculated + * @param Zend_Locale $locale Locale for parsing input + * @throws Zend_Date_Exception + * @return Zend_Date|integer + */ + private function _day($calc, $day, $locale) + { + if ($day === null) { + throw new Zend_Date_Exception('parameter $day must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($day instanceof Zend_Date) { + $day = $day->toString(self::DAY_SHORT, 'iso', $locale); + } + + if (is_numeric($day)) { + $type = self::DAY_SHORT; + } else if (is_array($day)) { + if (isset($day['day']) === true) { + $day = $day['day']; + $type = self::WEEKDAY; + } else { + throw new Zend_Date_Exception("no day given in array"); + } + } else { + switch (iconv_strlen($day, 'UTF-8')) { + case 1 : + $type = self::WEEKDAY_NARROW; + break; + case 2: + $type = self::WEEKDAY_NAME; + break; + case 3: + $type = self::WEEKDAY_SHORT; + break; + default: + $type = self::WEEKDAY; + break; + } + } + $return = $this->_calcdetail($calc, $day, $type, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new day + * The day can be a number or a string. Setting days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: setDay('Montag', 'de_AT'); will set the monday of this week as day. + * + * @param string|integer|array|Zend_Date $day Day to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setDay($day, $locale = null) + { + return $this->_day('set', $day, $locale); + } + + + /** + * Adds days to the existing date object. + * The day can be a number or a string. Adding days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * + * @param string|integer|array|Zend_Date $day Day to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addDay($day, $locale = null) + { + return $this->_day('add', $day, $locale); + } + + + /** + * Subtracts days from the existing date object. + * The day can be a number or a string. Subtracting days lower then 0 or greater than the number of this months days + * will result in adding or subtracting the relevant month. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * + * @param string|integer|array|Zend_Date $day Day to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subDay($day, $locale = null) + { + return $this->_day('sub', $day, $locale); + } + + + /** + * Compares the day with the existing date object, ignoring other date parts. + * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $day Day to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDay($day, $locale = null) + { + return $this->_day('cmp', $day, $locale); + } + + + /** + * Returns the weekday as new date object + * Weekday is always from 1-7 + * Example: 09-Jan-2007 -> 2 = Tuesday -> 02-Jan-1970 (when 02.01.1970 is also Tuesday) + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getWeekday($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'l'; + } else { + $format = self::WEEKDAY; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Returns the calculated weekday + * + * @param string $calc Type of calculation to make + * @param Zend_Date $weekday Weekday to calculate, when null the actual weekday is calculated + * @param Zend_Locale $locale Locale for parsing input + * @return Zend_Date|integer + * @throws Zend_Date_Exception + */ + private function _weekday($calc, $weekday, $locale) + { + if ($weekday === null) { + throw new Zend_Date_Exception('parameter $weekday must be set, null is not allowed'); + } + + if ($locale === null) { + $locale = $this->getLocale(); + } + + if ($weekday instanceof Zend_Date) { + $weekday = $weekday->toString(self::WEEKDAY_8601, 'iso', $locale); + } + + if (is_numeric($weekday)) { + $type = self::WEEKDAY_8601; + } else if (is_array($weekday)) { + if (isset($weekday['weekday']) === true) { + $weekday = $weekday['weekday']; + $type = self::WEEKDAY; + } else { + throw new Zend_Date_Exception("no weekday given in array"); + } + } else { + switch(iconv_strlen($weekday, 'UTF-8')) { + case 1: + $type = self::WEEKDAY_NARROW; + break; + case 2: + $type = self::WEEKDAY_NAME; + break; + case 3: + $type = self::WEEKDAY_SHORT; + break; + default: + $type = self::WEEKDAY; + break; + } + } + $return = $this->_calcdetail($calc, $weekday, $type, $locale); + if ($calc != 'cmp') { + return $this; + } + return $return; + } + + + /** + * Sets a new weekday + * The weekday can be a number or a string. If a localized weekday name is given, + * then it will be parsed as a date in $locale (defaults to the same locale as $this). + * Returned is the new date object. + * Example: setWeekday(3); will set the wednesday of this week as day. + * + * @param string|integer|array|Zend_Date $weekday Weekday to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setWeekday($weekday, $locale = null) + { + return $this->_weekday('set', $weekday, $locale); + } + + + /** + * Adds weekdays to the existing date object. + * The weekday can be a number or a string. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: addWeekday(3); will add the difference of days from the begining of the month until + * wednesday. + * + * @param string|integer|array|Zend_Date $weekday Weekday to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addWeekday($weekday, $locale = null) + { + return $this->_weekday('add', $weekday, $locale); + } + + + /** + * Subtracts weekdays from the existing date object. + * The weekday can be a number or a string. + * If a localized dayname is given it will be parsed with the default locale or the optional + * set locale. + * Returned is the new date object + * Example: subWeekday(3); will subtract the difference of days from the begining of the month until + * wednesday. + * + * @param string|integer|array|Zend_Date $weekday Weekday to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subWeekday($weekday, $locale = null) + { + return $this->_weekday('sub', $weekday, $locale); + } + + + /** + * Compares the weekday with the existing date object, ignoring other date parts. + * For example: 'Monday', 'en' -> 08.Jan.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $weekday Weekday to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareWeekday($weekday, $locale = null) + { + return $this->_weekday('cmp', $weekday, $locale); + } + + + /** + * Returns the day of year as new date object + * Example: 02.Feb.1986 10:00:00 -> 02.Feb.1970 00:00:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getDayOfYear($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'D'; + } else { + $format = self::DAY_OF_YEAR; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets a new day of year + * The day of year is always a number. + * Returned is the new date object + * Example: 04.May.2004 -> setDayOfYear(10) -> 10.Jan.2004 + * + * @param string|integer|array|Zend_Date $day Day of Year to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setDayOfYear($day, $locale = null) + { + return $this->_calcvalue('set', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Adds a day of year to the existing date object. + * The day of year is always a number. + * Returned is the new date object + * Example: addDayOfYear(10); will add 10 days to the existing date object. + * + * @param string|integer|array|Zend_Date $day Day of Year to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addDayOfYear($day, $locale = null) + { + return $this->_calcvalue('add', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Subtracts a day of year from the existing date object. + * The day of year is always a number. + * Returned is the new date object + * Example: subDayOfYear(10); will subtract 10 days from the existing date object. + * + * @param string|integer|array|Zend_Date $day Day of Year to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subDayOfYear($day, $locale = null) + { + return $this->_calcvalue('sub', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Compares the day of year with the existing date object. + * For example: compareDayOfYear(33) -> 02.Feb.2007 -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $day Day of Year to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareDayOfYear($day, $locale = null) + { + return $this->_calcvalue('cmp', $day, 'day of year', self::DAY_OF_YEAR, $locale); + } + + + /** + * Returns the hour as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 10:00:00 + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getHour($locale = null) + { + return $this->copyPart(self::HOUR, $locale); + } + + + /** + * Sets a new hour + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setHour(7); -> 04.May.1993 07:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setHour($hour, $locale = null) + { + return $this->_calcvalue('set', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Adds hours to the existing date object. + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addHour(12); -> 05.May.1993 01:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addHour($hour, $locale = null) + { + return $this->_calcvalue('add', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Subtracts hours from the existing date object. + * The hour is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subHour(6); -> 05.May.1993 07:07:25 + * + * @param string|integer|array|Zend_Date $hour Hour to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subHour($hour, $locale = null) + { + return $this->_calcvalue('sub', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Compares the hour with the existing date object. + * For example: 10:30:25 -> compareHour(10) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $hour Hour to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareHour($hour, $locale = null) + { + return $this->_calcvalue('cmp', $hour, 'hour', self::HOUR_SHORT, $locale); + } + + + /** + * Returns the minute as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:30:00 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getMinute($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'i'; + } else { + $format = self::MINUTE; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets a new minute + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setMinute(29); -> 04.May.1993 13:29:25 + * + * @param string|integer|array|Zend_Date $minute Minute to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setMinute($minute, $locale = null) + { + return $this->_calcvalue('set', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Adds minutes to the existing date object. + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addMinute(65); -> 04.May.1993 13:12:25 + * + * @param string|integer|array|Zend_Date $minute Minute to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addMinute($minute, $locale = null) + { + return $this->_calcvalue('add', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Subtracts minutes from the existing date object. + * The minute is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subMinute(9); -> 04.May.1993 12:58:25 + * + * @param string|integer|array|Zend_Date $minute Minute to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subMinute($minute, $locale = null) + { + return $this->_calcvalue('sub', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Compares the minute with the existing date object. + * For example: 10:30:25 -> compareMinute(30) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $minute Hour to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareMinute($minute, $locale = null) + { + return $this->_calcvalue('cmp', $minute, 'minute', self::MINUTE_SHORT, $locale); + } + + + /** + * Returns the second as new date object + * Example: 02.Feb.1986 10:30:25 -> 01.Jan.1970 00:00:25 + * + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getSecond($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 's'; + } else { + $format = self::SECOND; + } + + return $this->copyPart($format, $locale); + } + + + /** + * Sets new seconds to the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> setSecond(100); -> 04.May.1993 13:08:40 + * + * @param string|integer|array|Zend_Date $second Second to set + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setSecond($second, $locale = null) + { + return $this->_calcvalue('set', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Adds seconds to the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> addSecond(65); -> 04.May.1993 13:08:30 + * + * @param string|integer|array|Zend_Date $second Second to add + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addSecond($second, $locale = null) + { + return $this->_calcvalue('add', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Subtracts seconds from the existing date object. + * The second is always a number. + * Returned is the new date object + * Example: 04.May.1993 13:07:25 -> subSecond(10); -> 04.May.1993 13:07:15 + * + * @param string|integer|array|Zend_Date $second Second to sub + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subSecond($second, $locale = null) + { + return $this->_calcvalue('sub', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Compares the second with the existing date object. + * For example: 10:30:25 -> compareSecond(25) -> 0 + * Returns if equal, earlier or later + * + * @param string|integer|array|Zend_Date $second Second to compare + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + * @throws Zend_Date_Exception + */ + public function compareSecond($second, $locale = null) + { + return $this->_calcvalue('cmp', $second, 'second', self::SECOND_SHORT, $locale); + } + + + /** + * Returns the precision for fractional seconds + * + * @return integer + */ + public function getFractionalPrecision() + { + return $this->_precision; + } + + + /** + * Sets a new precision for fractional seconds + * + * @param integer $precision Precision for the fractional datepart 3 = milliseconds + * @throws Zend_Date_Exception + * @return Zend_Date Provides fluid interface + */ + public function setFractionalPrecision($precision) + { + if (!intval($precision) or ($precision < 0) or ($precision > 9)) { + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision); + } + + $this->_precision = (int) $precision; + if ($this->_precision < strlen($this->_fractional)) { + $this->_fractional = substr($this->_fractional, 0, $this->_precision); + } else { + $this->_fractional = str_pad($this->_fractional, $this->_precision, '0', STR_PAD_RIGHT); + } + + return $this; + } + + + /** + * Returns the milliseconds of the date object + * + * @return string + */ + public function getMilliSecond() + { + return $this->_fractional; + } + + /** + * Sets new milliseconds for the date object + * Example: setMilliSecond(550, 2) -> equals +5 Sec +50 MilliSec + * + * @param integer|Zend_Date $milli (Optional) Millisecond to set, when null the actual millisecond is set + * @param integer $precision (Optional) Fraction precision of the given milliseconds + * @throws Zend_Date_Exception + * @return Zend_Date Provides fluid interface + */ + public function setMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + $precision = 6; + } else if (!is_numeric($milli)) { + throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli); + } + + if ($precision === null) { + $precision = $this->_precision; + } + + if (!is_int($precision) || $precision < 1 || $precision > 9) { + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision); + } + + $this->_fractional = 0; + $this->addMilliSecond($milli, $precision); + return $this; + } + + /** + * Adds milliseconds to the date object + * + * @param integer|Zend_Date $milli (Optional) Millisecond to add, when null the actual millisecond is added + * @param integer $precision (Optional) Fractional precision for the given milliseconds + * @throws Zend_Date_Exception + * @return Zend_Date Provides fluid interface + */ + public function addMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + } else if (!is_numeric($milli)) { + throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli); + } + + if ($precision === null) { + // Use internal default precision + // Is not as logic as using the length of the input. But this would break tests and maybe other things + // as an input value of integer 10, which is used in tests, must be parsed as 10 milliseconds (real milliseconds, precision 3) + // but with auto-detect of precision, 100 milliseconds would be added. + $precision = $this->_precision; + } + + if (!is_int($precision) || $precision < 1 || $precision > 9) { + throw new Zend_Date_Exception( + "precision ($precision) must be a positive integer less than 10", 0, null, $precision + ); + } + + if ($this->_precision > $precision) { + $milli = $milli * pow(10, $this->_precision - $precision); + } elseif ($this->_precision < $precision) { + $milli = round($milli / pow(10, $precision - $this->_precision)); + } + + $this->_fractional += $milli; + + // Add/sub milliseconds + add/sub seconds + $max = pow(10, $this->_precision); + // Milli includes seconds + if ($this->_fractional >= $max) { + while ($this->_fractional >= $max) { + $this->addSecond(1); + $this->_fractional -= $max; + } + } + + if ($this->_fractional < 0) { + while ($this->_fractional < 0) { + $this->subSecond(1); + $this->_fractional += $max; + } + } + + if ($this->_precision > strlen($this->_fractional)) { + $this->_fractional = str_pad($this->_fractional, $this->_precision, '0', STR_PAD_LEFT); + } + + return $this; + } + + + /** + * Subtracts a millisecond + * + * @param integer|Zend_Date $milli (Optional) Millisecond to sub, when null the actual millisecond is subtracted + * @param integer $precision (Optional) Fractional precision for the given milliseconds + * @return Zend_Date Provides fluid interface + */ + public function subMilliSecond($milli = null, $precision = null) + { + $this->addMilliSecond(0 - $milli, $precision); + return $this; + } + + /** + * Compares only the millisecond part, returning the difference + * + * @param integer|Zend_Date $milli OPTIONAL Millisecond to compare, when null the actual millisecond is compared + * @param integer $precision OPTIONAL Fractional precision for the given milliseconds + * @throws Zend_Date_Exception On invalid input + * @return integer 0 = equal, 1 = later, -1 = earlier + */ + public function compareMilliSecond($milli = null, $precision = null) + { + if ($milli === null) { + list($milli, $time) = explode(" ", microtime()); + $milli = intval($milli); + } else if (is_numeric($milli) === false) { + throw new Zend_Date_Exception("invalid milli second ($milli) operand", 0, null, $milli); + } + + if ($precision === null) { + $precision = strlen($milli); + } else if (!is_int($precision) || $precision < 1 || $precision > 9) { + throw new Zend_Date_Exception("precision ($precision) must be a positive integer less than 10", 0, null, $precision); + } + + if ($precision === 0) { + throw new Zend_Date_Exception('precision is 0'); + } + + if ($precision != $this->_precision) { + if ($precision > $this->_precision) { + $diff = $precision - $this->_precision; + $milli = (int) ($milli / (10 * $diff)); + } else { + $diff = $this->_precision - $precision; + $milli = (int) ($milli * (10 * $diff)); + } + } + + $comp = $this->_fractional - $milli; + if ($comp < 0) { + return -1; + } else if ($comp > 0) { + return 1; + } + return 0; + } + + /** + * Returns the week as new date object using monday as begining of the week + * Example: 12.Jan.2007 -> 08.Jan.1970 00:00:00 + * + * @param Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date + */ + public function getWeek($locale = null) + { + if (self::$_options['format_type'] == 'php') { + $format = 'W'; + } else { + $format = self::WEEK; + } + + return $this->copyPart($format, $locale); + } + + /** + * Sets a new week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> setWeek(1); -> 02.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to set + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function setWeek($week, $locale = null) + { + return $this->_calcvalue('set', $week, 'week', self::WEEK, $locale); + } + + /** + * Adds a week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> addWeek(1); -> 16.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to add + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function addWeek($week, $locale = null) + { + return $this->_calcvalue('add', $week, 'week', self::WEEK, $locale); + } + + /** + * Subtracts a week. The week is always a number. The day of week is not changed. + * Returned is the new date object + * Example: 09.Jan.2007 13:07:25 -> subWeek(1); -> 02.Jan.2007 13:07:25 + * + * @param string|integer|array|Zend_Date $week Week to sub + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return Zend_Date Provides fluid interface + * @throws Zend_Date_Exception + */ + public function subWeek($week, $locale = null) + { + return $this->_calcvalue('sub', $week, 'week', self::WEEK, $locale); + } + + /** + * Compares only the week part, returning the difference + * Returned is the new date object + * Returns if equal, earlier or later + * Example: 09.Jan.2007 13:07:25 -> compareWeek(2); -> 0 + * + * @param string|integer|array|Zend_Date $week Week to compare + * @param string|Zend_Locale $locale OPTIONAL Locale for parsing input + * @return integer 0 = equal, 1 = later, -1 = earlier + */ + public function compareWeek($week, $locale = null) + { + return $this->_calcvalue('cmp', $week, 'week', self::WEEK, $locale); + } + + /** + * Sets a new standard locale for the date object. + * This locale will be used for all functions + * Returned is the really set locale. + * Example: 'de_XX' will be set to 'de' because 'de_XX' does not exist + * 'xx_YY' will be set to 'root' because 'xx' does not exist + * + * @param string|Zend_Locale $locale (Optional) Locale for parsing input + * @throws Zend_Date_Exception When the given locale does not exist + * @return Zend_Date Provides fluent interface + */ + public function setLocale($locale = null) + { + try { + $this->_locale = Zend_Locale::findLocale($locale); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Date_Exception($e->getMessage(), 0, $e); + } + + return $this; + } + + /** + * Returns the actual set locale + * + * @return string + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Checks if the given date is a real date or datepart. + * Returns false if a expected datepart is missing or a datepart exceeds its possible border. + * But the check will only be done for the expected dateparts which are given by format. + * If no format is given the standard dateformat for the actual locale is used. + * f.e. 30.February.2007 will return false if format is 'dd.MMMM.YYYY' + * + * @param string|array|Zend_Date $date Date to parse for correctness + * @param string $format (Optional) Format for parsing the date string + * @param string|Zend_Locale $locale (Optional) Locale for parsing date parts + * @return boolean True when all date parts are correct + */ + public static function isDate($date, $format = null, $locale = null) + { + if (!is_string($date) && !is_numeric($date) && !($date instanceof Zend_Date) && + !is_array($date)) { + return false; + } + + if (($format !== null) && ($format != 'ee') && ($format != 'ss') && ($format != 'GG') && ($format != 'MM') && ($format != 'EE') && ($format != 'TT') + && (Zend_Locale::isLocale($format, null, false))) { + $locale = $format; + $format = null; + } + + $locale = Zend_Locale::findLocale($locale); + + if ($format === null) { + $format = Zend_Locale_Format::getDateFormat($locale); + } else if ((self::$_options['format_type'] == 'php') && !defined($format)) { + $format = Zend_Locale_Format::convertPhpToIsoFormat($format); + } + + $format = self::_getLocalizedToken($format, $locale); + if (!is_array($date)) { + try { + $parsed = Zend_Locale_Format::getDate($date, array('locale' => $locale, + 'date_format' => $format, 'format_type' => 'iso', + 'fix_date' => false)); + } catch (Zend_Locale_Exception $e) { + // Date can not be parsed + return false; + } + } else { + $parsed = $date; + } + + if (((strpos($format, 'Y') !== false) or (strpos($format, 'y') !== false)) and + (!isset($parsed['year']))) { + // Year expected but not found + return false; + } + + if ((strpos($format, 'M') !== false) and (!isset($parsed['month']))) { + // Month expected but not found + return false; + } + + if ((strpos($format, 'd') !== false) and (!isset($parsed['day']))) { + // Day expected but not found + return false; + } + + if (((strpos($format, 'H') !== false) or (strpos($format, 'h') !== false)) and + (!isset($parsed['hour']))) { + // Hour expected but not found + return false; + } + + if ((strpos($format, 'm') !== false) and (!isset($parsed['minute']))) { + // Minute expected but not found + return false; + } + + if ((strpos($format, 's') !== false) and (!isset($parsed['second']))) { + // Second expected but not found + return false; + } + + // Set not given dateparts + if (isset($parsed['hour']) === false) { + $parsed['hour'] = 12; + } + + if (isset($parsed['minute']) === false) { + $parsed['minute'] = 0; + } + + if (isset($parsed['second']) === false) { + $parsed['second'] = 0; + } + + if (isset($parsed['month']) === false) { + $parsed['month'] = 1; + } + + if (isset($parsed['day']) === false) { + $parsed['day'] = 1; + } + + if (isset($parsed['year']) === false) { + $parsed['year'] = 1970; + } + + if (self::isYearLeapYear($parsed['year'])) { + $parsed['year'] = 1972; + } else { + $parsed['year'] = 1971; + } + + $date = new self($parsed, null, $locale); + $timestamp = $date->mktime($parsed['hour'], $parsed['minute'], $parsed['second'], + $parsed['month'], $parsed['day'], $parsed['year']); + + if ($parsed['year'] != $date->date('Y', $timestamp)) { + // Given year differs from parsed year + return false; + } + + if ($parsed['month'] != $date->date('n', $timestamp)) { + // Given month differs from parsed month + return false; + } + + if ($parsed['day'] != $date->date('j', $timestamp)) { + // Given day differs from parsed day + return false; + } + + if ($parsed['hour'] != $date->date('G', $timestamp)) { + // Given hour differs from parsed hour + return false; + } + + if ($parsed['minute'] != $date->date('i', $timestamp)) { + // Given minute differs from parsed minute + return false; + } + + if ($parsed['second'] != $date->date('s', $timestamp)) { + // Given second differs from parsed second + return false; + } + + return true; + } + + /** + * Returns the ISO Token for all localized constants + * + * @param string $token Token to normalize + * @param string $locale Locale to search + * @return string + */ + protected static function _getLocalizedToken($token, $locale) + { + switch($token) { + case self::ISO_8601 : + return "yyyy-MM-ddThh:mm:ss"; + break; + case self::RFC_2822 : + return "EEE, dd MMM yyyy HH:mm:ss"; + break; + case self::DATES : + return Zend_Locale_Data::getContent($locale, 'date'); + break; + case self::DATE_FULL : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'full')); + break; + case self::DATE_LONG : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'long')); + break; + case self::DATE_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'medium')); + break; + case self::DATE_SHORT : + return Zend_Locale_Data::getContent($locale, 'date', array('gregorian', 'short')); + break; + case self::TIMES : + return Zend_Locale_Data::getContent($locale, 'time'); + break; + case self::TIME_FULL : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'full')); + break; + case self::TIME_LONG : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'long')); + break; + case self::TIME_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'medium')); + break; + case self::TIME_SHORT : + return Zend_Locale_Data::getContent($locale, 'time', array('gregorian', 'short')); + break; + case self::DATETIME : + return Zend_Locale_Data::getContent($locale, 'datetime'); + break; + case self::DATETIME_FULL : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'full')); + break; + case self::DATETIME_LONG : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'long')); + break; + case self::DATETIME_MEDIUM : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'medium')); + break; + case self::DATETIME_SHORT : + return Zend_Locale_Data::getContent($locale, 'datetime', array('gregorian', 'short')); + break; + case self::ATOM : + case self::RFC_3339 : + case self::W3C : + return "yyyy-MM-DD HH:mm:ss"; + break; + case self::COOKIE : + case self::RFC_850 : + return "EEEE, dd-MM-yyyy HH:mm:ss"; + break; + case self::RFC_822 : + case self::RFC_1036 : + case self::RFC_1123 : + case self::RSS : + return "EEE, dd MM yyyy HH:mm:ss"; + break; + } + + return $token; + } +} diff --git a/library/vendor/Zend/Date/Cities.php b/library/vendor/Zend/Date/Cities.php new file mode 100644 index 000000000..b5e737eb7 --- /dev/null +++ b/library/vendor/Zend/Date/Cities.php @@ -0,0 +1,321 @@ + array('latitude' => 5.3411111, 'longitude' => -4.0280556), + 'Abu Dhabi' => array('latitude' => 24.4666667, 'longitude' => 54.3666667), + 'Abuja' => array('latitude' => 9.1758333, 'longitude' => 7.1808333), + 'Accra' => array('latitude' => 5.55, 'longitude' => -0.2166667), + 'Adamstown' => array('latitude' => -25.0666667, 'longitude' => -130.0833333), + 'Addis Ababa' => array('latitude' => 9.0333333, 'longitude' => 38.7), + 'Adelaide' => array('latitude' => -34.9333333, 'longitude' => 138.6), + 'Algiers' => array('latitude' => 36.7630556, 'longitude' => 3.0505556), + 'Alofi' => array('latitude' => -19.0166667, 'longitude' => -169.9166667), + 'Amman' => array('latitude' => 31.95, 'longitude' => 35.9333333), + 'Amsterdam' => array('latitude' => 52.35, 'longitude' => 4.9166667), + 'Andorra la Vella' => array('latitude' => 42.5, 'longitude' => 1.5166667), + 'Ankara' => array('latitude' => 39.9272222, 'longitude' => 32.8644444), + 'Antananarivo' => array('latitude' => -18.9166667, 'longitude' => 47.5166667), + 'Apia' => array('latitude' => -13.8333333, 'longitude' => -171.7333333), + 'Ashgabat' => array('latitude' => 37.95, 'longitude' => 58.3833333), + 'Asmara' => array('latitude' => 15.3333333, 'longitude' => 38.9333333), + 'Astana' => array('latitude' => 51.1811111, 'longitude' => 71.4277778), + 'Asunción' => array('latitude' => -25.2666667, 'longitude' => -57.6666667), + 'Athens' => array('latitude' => 37.9833333, 'longitude' => 23.7333333), + 'Auckland' => array('latitude' => -36.8666667, 'longitude' => 174.7666667), + 'Avarua' => array('latitude' => -21.2, 'longitude' => -159.7666667), + 'Baghdad' => array('latitude' => 33.3386111, 'longitude' => 44.3938889), + 'Baku' => array('latitude' => 40.3952778, 'longitude' => 49.8822222), + 'Bamako' => array('latitude' => 12.65, 'longitude' => -8), + 'Bandar Seri Begawan' => array('latitude' => 4.8833333, 'longitude' => 114.9333333), + 'Bankok' => array('latitude' => 13.5833333, 'longitude' => 100.2166667), + 'Bangui' => array('latitude' => 4.3666667, 'longitude' => 18.5833333), + 'Banjul' => array('latitude' => 13.4530556, 'longitude' => -16.5775), + 'Basel' => array('latitude' => 47.5666667, 'longitude' => 7.6), + 'Basseterre' => array('latitude' => 17.3, 'longitude' => -62.7166667), + 'Beijing' => array('latitude' => 39.9288889, 'longitude' => 116.3883333), + 'Beirut' => array('latitude' => 33.8719444, 'longitude' => 35.5097222), + 'Belgrade' => array('latitude' => 44.8186111, 'longitude' => 20.4680556), + 'Belmopan' => array('latitude' => 17.25, 'longitude' => -88.7666667), + 'Berlin' => array('latitude' => 52.5166667, 'longitude' => 13.4), + 'Bern' => array('latitude' => 46.9166667, 'longitude' => 7.4666667), + 'Bishkek' => array('latitude' => 42.8730556, 'longitude' => 74.6002778), + 'Bissau' => array('latitude' => 11.85, 'longitude' => -15.5833333), + 'Bloemfontein' => array('latitude' => -29.1333333, 'longitude' => 26.2), + 'Bogotá' => array('latitude' => 4.6, 'longitude' => -74.0833333), + 'Brasilia' => array('latitude' => -15.7833333, 'longitude' => -47.9166667), + 'Bratislava' => array('latitude' => 48.15, 'longitude' => 17.1166667), + 'Brazzaville' => array('latitude' => -4.2591667, 'longitude' => 15.2847222), + 'Bridgetown' => array('latitude' => 13.1, 'longitude' => -59.6166667), + 'Brisbane' => array('latitude' => -27.5, 'longitude' => 153.0166667), + 'Brussels' => array('latitude' => 50.8333333, 'longitude' => 4.3333333), + 'Bucharest' => array('latitude' => 44.4333333, 'longitude' => 26.1), + 'Budapest' => array('latitude' => 47.5, 'longitude' => 19.0833333), + 'Buenos Aires' => array('latitude' => -34.5875, 'longitude' => -58.6725), + 'Bujumbura' => array('latitude' => -3.3761111, 'longitude' => 29.36), + 'Cairo' => array('latitude' => 30.05, 'longitude' => 31.25), + 'Calgary' => array('latitude' => 51.0833333, 'longitude' => -114.0833333), + 'Canberra' => array('latitude' => -35.2833333, 'longitude' => 149.2166667), + 'Cape Town' => array('latitude' => -33.9166667, 'longitude' => 18.4166667), + 'Caracas' => array('latitude' => 10.5, 'longitude' => -66.9166667), + 'Castries' => array('latitude' => 14, 'longitude' => -61), + 'Charlotte Amalie' => array('latitude' => 18.34389, 'longitude' => -64.93111), + 'Chicago' => array('latitude' => 41.85, 'longitude' => -87.65), + 'Chisinau' => array('latitude' => 47.055556, 'longitude' => 28.8575), + 'Cockburn Town' => array('latitude' => 21.4666667, 'longitude' => -71.1333333), + 'Colombo' => array('latitude' => 6.9319444, 'longitude' => 79.8477778), + 'Conakry' => array('latitude' => 9.5091667, 'longitude' => -13.7122222), + 'Copenhagen' => array('latitude' => 55.6666667, 'longitude' => 12.5833333), + 'Cotonou' => array('latitude' => 6.35, 'longitude' => 2.4333333), + 'Dakar' => array('latitude' => 14.6708333, 'longitude' => -17.4380556), + 'Damascus' => array('latitude' => 33.5, 'longitude' => 36.3), + 'Dar es Salaam' => array('latitude' => -6.8, 'longitude' => 39.2833333), + 'Dhaka' => array('latitude' => 23.7230556, 'longitude' => 90.4086111), + 'Dili' => array('latitude' => -8.5586111, 'longitude' => 125.5736111), + 'Djibouti' => array('latitude' => 11.595, 'longitude' => 43.1480556), + 'Dodoma' => array('latitude' => -6.1833333, 'longitude' => 35.75), + 'Doha' => array('latitude' => 25.2866667, 'longitude' => 51.5333333), + 'Dubai' => array('latitude' => 25.2522222, 'longitude' => 55.28), + 'Dublin' => array('latitude' => 53.3330556, 'longitude' => -6.2488889), + 'Dushanbe' => array('latitude' => 38.56, 'longitude' => 68.7738889 ), + 'Fagatogo' => array('latitude' => -14.2825, 'longitude' => -170.69), + 'Fongafale' => array('latitude' => -8.5166667, 'longitude' => 179.2166667), + 'Freetown' => array('latitude' => 8.49, 'longitude' => -13.2341667), + 'Gaborone' => array('latitude' => -24.6463889, 'longitude' => 25.9119444), + 'Geneva' => array('latitude' => 46.2, 'longitude' => 6.1666667), + 'George Town' => array('latitude' => 19.3, 'longitude' => -81.3833333), + 'Georgetown' => array('latitude' => 6.8, 'longitude' => -58.1666667), + 'Gibraltar' => array('latitude' => 36.1333333, 'longitude' => -5.35), + 'Glasgow' => array('latitude' => 55.8333333, 'longitude' => -4.25), + 'Guatemala la Nueva' => array('latitude' => 14.6211111, 'longitude' => -90.5269444), + 'Hagatna' => array('latitude' => 13.47417, 'longitude' => 144.74778), + 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3), + 'Hamilton' => array('latitude' => 32.2941667, 'longitude' => -64.7838889), + 'Hanoi' => array('latitude' => 21.0333333, 'longitude' => 105.85), + 'Harare' => array('latitude' => -17.8177778, 'longitude' => 31.0447222), + 'Havana' => array('latitude' => 23.1319444, 'longitude' => -82.3641667), + 'Helsinki' => array('latitude' => 60.1755556, 'longitude' => 24.9341667), + 'Honiara' => array('latitude' => -9.4333333, 'longitude' => 159.95), + 'Islamabad' => array('latitude' => 30.8486111, 'longitude' => 72.4944444), + 'Istanbul' => array('latitude' => 41.0186111, 'longitude' => 28.9647222), + 'Jakarta' => array('latitude' => -6.1744444, 'longitude' => 106.8294444), + 'Jamestown' => array('latitude' => -15.9333333, 'longitude' => -5.7166667), + 'Jerusalem' => array('latitude' => 31.7666667, 'longitude' => 35.2333333), + 'Johannesburg' => array('latitude' => -26.2, 'longitude' => 28.0833333), + 'Kabul' => array('latitude' => 34.5166667, 'longitude' => 69.1833333), + 'Kampala' => array('latitude' => 0.3155556, 'longitude' => 32.5655556), + 'Kathmandu' => array('latitude' => 27.7166667, 'longitude' => 85.3166667), + 'Khartoum' => array('latitude' => 15.5880556, 'longitude' => 32.5341667), + 'Kigali' => array('latitude' => -1.9536111, 'longitude' => 30.0605556), + 'Kingston' => array('latitude' => -29.05, 'longitude' => 167.95), + 'Kingstown' => array('latitude' => 13.1333333, 'longitude' => -61.2166667), + 'Kinshasa' => array('latitude' => -4.3, 'longitude' => 15.3), + 'Kolkata' => array('latitude' => 22.5697222, 'longitude' => 88.3697222), + 'Kuala Lumpur' => array('latitude' => 3.1666667, 'longitude' => 101.7), + 'Kuwait City' => array('latitude' => 29.3697222, 'longitude' => 47.9783333), + 'Kiev' => array('latitude' => 50.4333333, 'longitude' => 30.5166667), + 'La Paz' => array('latitude' => -16.5, 'longitude' => -68.15), + 'Libreville' => array('latitude' => 0.3833333, 'longitude' => 9.45), + 'Lilongwe' => array('latitude' => -13.9833333, 'longitude' => 33.7833333), + 'Lima' => array('latitude' => -12.05, 'longitude' => -77.05), + 'Lisbon' => array('latitude' => 38.7166667, 'longitude' => -9.1333333), + 'Ljubljana' => array('latitude' => 46.0552778, 'longitude' => 14.5144444), + 'Lobamba' => array('latitude' => -26.4666667, 'longitude' => 31.2), + 'Lomé' => array('latitude' => 9.7166667, 'longitude' => 38.3), + 'London' => array('latitude' => 51.5, 'longitude' => -0.1166667), + 'Los Angeles' => array('latitude' => 34.05222, 'longitude' => -118.24278), + 'Luanda' => array('latitude' => -8.8383333, 'longitude' => 13.2344444), + 'Lusaka' => array('latitude' => -15.4166667, 'longitude' => 28.2833333), + 'Luxembourg' => array('latitude' => 49.6116667, 'longitude' => 6.13), + 'Madrid' => array('latitude' => 40.4, 'longitude' => -3.6833333), + 'Majuro' => array('latitude' => 7.1, 'longitude' => 171.3833333), + 'Malabo' => array('latitude' => 3.75, 'longitude' => 8.7833333), + 'Managua' => array('latitude' => 12.1508333, 'longitude' => -86.2683333), + 'Manama' => array('latitude' => 26.2361111, 'longitude' => 50.5830556), + 'Manila' => array('latitude' => 14.6041667, 'longitude' => 120.9822222), + 'Maputo' => array('latitude' => -25.9652778, 'longitude' => 32.5891667), + 'Maseru' => array('latitude' => -29.3166667, 'longitude' => 27.4833333), + 'Mbabane' => array('latitude' => -26.3166667, 'longitude' => 31.1333333), + 'Melbourne' => array('latitude' => -37.8166667, 'longitude' => 144.9666667), + 'Melekeok' => array('latitude' => 7.4933333, 'longitude' => 134.6341667), + 'Mexiko City' => array('latitude' => 19.4341667, 'longitude' => -99.1386111), + 'Minsk' => array('latitude' => 53.9, 'longitude' => 27.5666667), + 'Mogadishu' => array('latitude' => 2.0666667, 'longitude' => 45.3666667), + 'Monaco' => array('latitude' => 43.7333333, 'longitude' => 7.4166667), + 'Monrovia' => array('latitude' => 6.3105556, 'longitude' => -10.8047222), + 'Montevideo' => array('latitude' => -34.8580556, 'longitude' => -56.1708333), + 'Montreal' => array('latitude' => 45.5, 'longitude' => -73.5833333), + 'Moroni' => array('latitude' => -11.7041667, 'longitude' => 43.2402778), + 'Moscow' => array('latitude' => 55.7522222, 'longitude' => 37.6155556), + 'Muscat' => array('latitude' => 23.6133333, 'longitude' => 58.5933333), + 'Nairobi' => array('latitude' => -1.3166667, 'longitude' => 36.8333333), + 'Nassau' => array('latitude' => 25.0833333, 'longitude' => -77.35), + 'N´Djamena' => array('latitude' => 12.1130556, 'longitude' => 15.0491667), + 'New Dehli' => array('latitude' => 28.6, 'longitude' => 77.2), + 'New York' => array('latitude' => 40.71417, 'longitude' => -74.00639), + 'Newcastle' => array('latitude' => -32.9166667, 'longitude' => 151.75), + 'Niamey' => array('latitude' => 13.6666667, 'longitude' => 1.7833333), + 'Nicosia' => array('latitude' => 35.1666667, 'longitude' => 33.3666667), + 'Nouakchott' => array('latitude' => 18.0863889, 'longitude' => -15.9752778), + 'Noumea' => array('latitude' => -22.2666667, 'longitude' => 166.45), + 'Nuku´alofa' => array('latitude' => -21.1333333, 'longitude' => -175.2), + 'Nuuk' => array('latitude' => 64.1833333, 'longitude' => -51.75), + 'Oranjestad' => array('latitude' => 12.5166667, 'longitude' => -70.0333333), + 'Oslo' => array('latitude' => 59.9166667, 'longitude' => 10.75), + 'Ouagadougou' => array('latitude' => 12.3702778, 'longitude' => -1.5247222), + 'Palikir' => array('latitude' => 6.9166667, 'longitude' => 158.15), + 'Panama City' => array('latitude' => 8.9666667, 'longitude' => -79.5333333), + 'Papeete' => array('latitude' => -17.5333333, 'longitude' => -149.5666667), + 'Paramaribo' => array('latitude' => 5.8333333, 'longitude' => -55.1666667), + 'Paris' => array('latitude' => 48.8666667, 'longitude' => 2.3333333), + 'Perth' => array('latitude' => -31.9333333, 'longitude' => 115.8333333), + 'Phnom Penh' => array('latitude' => 11.55, 'longitude' => 104.9166667), + 'Podgorica' => array('latitude' => 43.7752778, 'longitude' => 19.6827778), + 'Port Louis' => array('latitude' => -20.1666667, 'longitude' => 57.5), + 'Port Moresby' => array('latitude' => -9.4647222, 'longitude' => 147.1925), + 'Port-au-Prince' => array('latitude' => 18.5391667, 'longitude' => -72.335), + 'Port of Spain' => array('latitude' => 10.6666667, 'longitude' => -61.5), + 'Porto-Novo' => array('latitude' => 6.4833333, 'longitude' => 2.6166667), + 'Prague' => array('latitude' => 50.0833333, 'longitude' => 14.4666667), + 'Praia' => array('latitude' => 14.9166667, 'longitude' => -23.5166667), + 'Pretoria' => array('latitude' => -25.7069444, 'longitude' => 28.2294444), + 'Pyongyang' => array('latitude' => 39.0194444, 'longitude' => 125.7547222), + 'Quito' => array('latitude' => -0.2166667, 'longitude' => -78.5), + 'Rabat' => array('latitude' => 34.0252778, 'longitude' => -6.8361111), + 'Reykjavik' => array('latitude' => 64.15, 'longitude' => -21.95), + 'Riga' => array('latitude' => 56.95, 'longitude' => 24.1), + 'Rio de Janero' => array('latitude' => -22.9, 'longitude' => -43.2333333), + 'Road Town' => array('latitude' => 18.4166667, 'longitude' => -64.6166667), + 'Rome' => array('latitude' => 41.9, 'longitude' => 12.4833333), + 'Roseau' => array('latitude' => 15.3, 'longitude' => -61.4), + 'Rotterdam' => array('latitude' => 51.9166667, 'longitude' => 4.5), + 'Salvador' => array('latitude' => -12.9833333, 'longitude' => -38.5166667), + 'San José' => array('latitude' => 9.9333333, 'longitude' => -84.0833333), + 'San Juan' => array('latitude' => 18.46833, 'longitude' => -66.10611), + 'San Marino' => array('latitude' => 43.5333333, 'longitude' => 12.9666667), + 'San Salvador' => array('latitude' => 13.7086111, 'longitude' => -89.2030556), + 'Sanaá' => array('latitude' => 15.3547222, 'longitude' => 44.2066667), + 'Santa Cruz' => array('latitude' => -17.8, 'longitude' => -63.1666667), + 'Santiago' => array('latitude' => -33.45, 'longitude' => -70.6666667), + 'Santo Domingo' => array('latitude' => 18.4666667, 'longitude' => -69.9), + 'Sao Paulo' => array('latitude' => -23.5333333, 'longitude' => -46.6166667), + 'Sarajevo' => array('latitude' => 43.85, 'longitude' => 18.3833333), + 'Seoul' => array('latitude' => 37.5663889, 'longitude' => 126.9997222), + 'Shanghai' => array('latitude' => 31.2222222, 'longitude' => 121.4580556), + 'Sydney' => array('latitude' => -33.8833333, 'longitude' => 151.2166667), + 'Singapore' => array('latitude' => 1.2930556, 'longitude' => 103.8558333), + 'Skopje' => array('latitude' => 42, 'longitude' => 21.4333333), + 'Sofia' => array('latitude' => 42.6833333, 'longitude' => 23.3166667), + 'St. George´s' => array('latitude' => 12.05, 'longitude' => -61.75), + 'St. John´s' => array('latitude' => 17.1166667, 'longitude' => -61.85), + 'Stanley' => array('latitude' => -51.7, 'longitude' => -57.85), + 'Stockholm' => array('latitude' => 59.3333333, 'longitude' => 18.05), + 'Suva' => array('latitude' => -18.1333333, 'longitude' => 178.4166667), + 'Taipei' => array('latitude' => 25.0166667, 'longitude' => 121.45), + 'Tallinn' => array('latitude' => 59.4338889, 'longitude' => 24.7280556), + 'Tashkent' => array('latitude' => 41.3166667, 'longitude' => 69.25), + 'Tbilisi' => array('latitude' => 41.725, 'longitude' => 44.7908333), + 'Tegucigalpa' => array('latitude' => 14.1, 'longitude' => -87.2166667), + 'Tehran' => array('latitude' => 35.6719444, 'longitude' => 51.4244444), + 'The Hague' => array('latitude' => 52.0833333, 'longitude' => 4.3), + 'Thimphu' => array('latitude' => 27.4833333, 'longitude' => 89.6), + 'Tirana' => array('latitude' => 41.3275, 'longitude' => 19.8188889), + 'Tiraspol' => array('latitude' => 46.8402778, 'longitude' => 29.6433333), + 'Tokyo' => array('latitude' => 35.685, 'longitude' => 139.7513889), + 'Toronto' => array('latitude' => 43.6666667, 'longitude' => -79.4166667), + 'Tórshavn' => array('latitude' => 62.0166667, 'longitude' => -6.7666667), + 'Tripoli' => array('latitude' => 32.8925, 'longitude' => 13.18), + 'Tunis' => array('latitude' => 36.8027778, 'longitude' => 10.1797222), + 'Ulaanbaatar' => array('latitude' => 47.9166667, 'longitude' => 106.9166667), + 'Vaduz' => array('latitude' => 47.1333333, 'longitude' => 9.5166667), + 'Valletta' => array('latitude' => 35.8997222, 'longitude' => 14.5147222), + 'Valparaiso' => array('latitude' => -33.0477778, 'longitude' => -71.6011111), + 'Vancouver' => array('latitude' => 49.25, 'longitude' => -123.1333333), + 'Vatican City' => array('latitude' => 41.9, 'longitude' => 12.4833333), + 'Victoria' => array('latitude' => -4.6166667, 'longitude' => 55.45), + 'Vienna' => array('latitude' => 48.2, 'longitude' => 16.3666667), + 'Vientaine' => array('latitude' => 17.9666667, 'longitude' => 102.6), + 'Vilnius' => array('latitude' => 54.6833333, 'longitude' => 25.3166667), + 'Warsaw' => array('latitude' => 52.25, 'longitude' => 21), + 'Washington dc' => array('latitude' => 38.895, 'longitude' => -77.03667), + 'Wellington' => array('latitude' => -41.3, 'longitude' => 174.7833333), + 'Willemstad' => array('latitude' => 12.1, 'longitude' => -68.9166667), + 'Windhoek' => array('latitude' => -22.57, 'longitude' => 17.0836111), + 'Yamoussoukro' => array('latitude' => 6.8166667, 'longitude' => -5.2833333), + 'Yaoundé' => array('latitude' => 3.8666667, 'longitude' => 11.5166667), + 'Yerevan' => array('latitude' => 40.1811111, 'longitude' => 44.5136111), + 'Zürich' => array('latitude' => 47.3666667, 'longitude' => 8.55), + 'Zagreb' => array('latitude' => 45.8, 'longitude' => 16) + ); + + /** + * Returns the location from the selected city + * + * @param string $city City to get location for + * @param string $horizon Horizon to use : + * default: effective + * others are civil, nautic, astronomic + * @return array + * @throws Zend_Date_Exception When city is unknown + */ + public static function City($city, $horizon = false) + { + foreach (self::$cities as $key => $value) { + if (strtolower($key) === strtolower($city)) { + $return = $value; + $return['horizon'] = $horizon; + return $return; + } + } + throw new Zend_Date_Exception('unknown city'); + } + + /** + * Return a list with all known cities + * + * @return array + */ + public static function getCityList() + { + return array_keys(self::$cities); + } +} diff --git a/library/vendor/Zend/Date/DateObject.php b/library/vendor/Zend/Date/DateObject.php new file mode 100644 index 000000000..984d11fb2 --- /dev/null +++ b/library/vendor/Zend/Date/DateObject.php @@ -0,0 +1,1094 @@ + 0, 1960 => -315619200, 1950 => -631152000, + 1940 => -946771200, 1930 => -1262304000, 1920 => -1577923200, + 1910 => -1893456000, 1900 => -2208988800, 1890 => -2524521600, + 1880 => -2840140800, 1870 => -3155673600, 1860 => -3471292800, + 1850 => -3786825600, 1840 => -4102444800, 1830 => -4417977600, + 1820 => -4733596800, 1810 => -5049129600, 1800 => -5364662400, + 1790 => -5680195200, 1780 => -5995814400, 1770 => -6311347200, + 1760 => -6626966400, 1750 => -6942499200, 1740 => -7258118400, + 1730 => -7573651200, 1720 => -7889270400, 1710 => -8204803200, + 1700 => -8520336000, 1690 => -8835868800, 1680 => -9151488000, + 1670 => -9467020800, 1660 => -9782640000, 1650 => -10098172800, + 1640 => -10413792000, 1630 => -10729324800, 1620 => -11044944000, + 1610 => -11360476800, 1600 => -11676096000); + + /** + * Set this object to have a new UNIX timestamp. + * + * @param string|integer $timestamp OPTIONAL timestamp; defaults to local time using time() + * @return string|integer old timestamp + * @throws Zend_Date_Exception + */ + protected function setUnixTimestamp($timestamp = null) + { + $old = $this->_unixTimestamp; + + if (is_numeric($timestamp)) { + $this->_unixTimestamp = $timestamp; + } else if ($timestamp === null) { + $this->_unixTimestamp = time(); + } else { + throw new Zend_Date_Exception('\'' . $timestamp . '\' is not a valid UNIX timestamp', 0, null, $timestamp); + } + + return $old; + } + + /** + * Returns this object's UNIX timestamp + * A timestamp greater then the integer range will be returned as string + * This function does not return the timestamp as object. Use copy() instead. + * + * @return integer|string timestamp + */ + protected function getUnixTimestamp() + { + if ($this->_unixTimestamp === intval($this->_unixTimestamp)) { + return (int) $this->_unixTimestamp; + } else { + return (string) $this->_unixTimestamp; + } + } + + /** + * Internal function. + * Returns time(). This method exists to allow unit tests to work-around methods that might otherwise + * be hard-coded to use time(). For example, this makes it possible to test isYesterday() in Date.php. + * + * @param integer $sync OPTIONAL time syncronisation value + * @return integer timestamp + */ + protected function _getTime($sync = null) + { + if ($sync !== null) { + $this->_syncronised = round($sync); + } + return (time() + $this->_syncronised); + } + + /** + * Internal mktime function used by Zend_Date. + * The timestamp returned by mktime() can exceed the precision of traditional UNIX timestamps, + * by allowing PHP to auto-convert to using a float value. + * + * Returns a timestamp relative to 1970/01/01 00:00:00 GMT/UTC. + * DST (Summer/Winter) is depriciated since php 5.1.0. + * Year has to be 4 digits otherwise it would be recognised as + * year 70 AD instead of 1970 AD as expected !! + * + * @param integer $hour + * @param integer $minute + * @param integer $second + * @param integer $month + * @param integer $day + * @param integer $year + * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date + * @return integer|float timestamp (number of seconds elapsed relative to 1970/01/01 00:00:00 GMT/UTC) + */ + protected function mktime($hour, $minute, $second, $month, $day, $year, $gmt = false) + { + // complete date but in 32bit timestamp - use PHP internal + if ((1901 < $year) and ($year < 2038)) { + + $oldzone = @date_default_timezone_get(); + // Timezone also includes DST settings, therefor substracting the GMT offset is not enough + // We have to set the correct timezone to get the right value + if (($this->_timezone != $oldzone) and ($gmt === false)) { + date_default_timezone_set($this->_timezone); + } + $result = ($gmt) ? @gmmktime($hour, $minute, $second, $month, $day, $year) + : @mktime($hour, $minute, $second, $month, $day, $year); + date_default_timezone_set($oldzone); + + return $result; + } + + if ($gmt !== true) { + $second += $this->_offset; + } + + if (isset(self::$_cache)) { + $id = strtr('Zend_DateObject_mkTime_' . $this->_offset . '_' . $year.$month.$day.'_'.$hour.$minute.$second . '_'.(int)$gmt, '-','_'); + if ($result = self::$_cache->load($id)) { + return unserialize($result); + } + } + + // date to integer + $day = intval($day); + $month = intval($month); + $year = intval($year); + + // correct months > 12 and months < 1 + if ($month > 12) { + $overlap = floor($month / 12); + $year += $overlap; + $month -= $overlap * 12; + } else { + $overlap = ceil((1 - $month) / 12); + $year -= $overlap; + $month += $overlap * 12; + } + + $date = 0; + if ($year >= 1970) { + + // Date is after UNIX epoch + // go through leapyears + // add months from latest given year + for ($count = 1970; $count <= $year; $count++) { + + $leapyear = self::isYearLeapYear($count); + if ($count < $year) { + + $date += 365; + if ($leapyear === true) { + $date++; + } + + } else { + + for ($mcount = 0; $mcount < ($month - 1); $mcount++) { + $date += self::$_monthTable[$mcount]; + if (($leapyear === true) and ($mcount == 1)) { + $date++; + } + + } + } + } + + $date += $day - 1; + $date = (($date * 86400) + ($hour * 3600) + ($minute * 60) + $second); + } else { + + // Date is before UNIX epoch + // go through leapyears + // add months from latest given year + for ($count = 1969; $count >= $year; $count--) { + + $leapyear = self::isYearLeapYear($count); + if ($count > $year) + { + $date += 365; + if ($leapyear === true) + $date++; + } else { + + for ($mcount = 11; $mcount > ($month - 1); $mcount--) { + $date += self::$_monthTable[$mcount]; + if (($leapyear === true) and ($mcount == 2)) { + $date++; + } + + } + } + } + + $date += (self::$_monthTable[$month - 1] - $day); + $date = -(($date * 86400) + (86400 - (($hour * 3600) + ($minute * 60) + $second))); + + // gregorian correction for 5.Oct.1582 + if ($date < -12220185600) { + $date += 864000; + } else if ($date < -12219321600) { + $date = -12219321600; + } + } + + if (isset(self::$_cache)) { + if (self::$_cacheTags) { + self::$_cache->save( serialize($date), $id, array('Zend_Date')); + } else { + self::$_cache->save( serialize($date), $id); + } + } + + return $date; + } + + /** + * Returns true, if given $year is a leap year. + * + * @param integer $year + * @return boolean true, if year is leap year + */ + protected static function isYearLeapYear($year) + { + // all leapyears can be divided through 4 + if (($year % 4) != 0) { + return false; + } + + // all leapyears can be divided through 400 + if ($year % 400 == 0) { + return true; + } else if (($year > 1582) and ($year % 100 == 0)) { + return false; + } + + return true; + } + + /** + * Internal mktime function used by Zend_Date for handling 64bit timestamps. + * + * Returns a formatted date for a given timestamp. + * + * @param string $format format for output + * @param mixed $timestamp + * @param boolean $gmt OPTIONAL true = other arguments are for UTC time, false = arguments are for local time/date + * @return string + */ + protected function date($format, $timestamp = null, $gmt = false) + { + $oldzone = @date_default_timezone_get(); + if ($this->_timezone != $oldzone) { + date_default_timezone_set($this->_timezone); + } + + if ($timestamp === null) { + $result = ($gmt) ? @gmdate($format) : @date($format); + date_default_timezone_set($oldzone); + return $result; + } + + if (abs($timestamp) <= 0x7FFFFFFF) { + // See ZF-11992 + // "o" will sometimes resolve to the previous year (see + // http://php.net/date ; it's part of the ISO 8601 + // standard). However, this is not desired, so replacing + // all occurrences of "o" not preceded by a backslash + // with "Y" + $format = preg_replace('/(?_offset . '_'. $timestamp . '_'.(int)$gmt, '-','_'); + if ($result2 = self::$_cache->load($idstamp)) { + $timestamp = unserialize($result2); + $jump = true; + } + } + + // check on false or null alone fails + if (empty($gmt) and empty($jump)) { + $tempstamp = $timestamp; + if ($tempstamp > 0) { + while (abs($tempstamp) > 0x7FFFFFFF) { + $tempstamp -= (86400 * 23376); + } + + $dst = date("I", $tempstamp); + if ($dst === 1) { + $timestamp += 3600; + } + + $temp = date('Z', $tempstamp); + $timestamp += $temp; + } + + if (isset(self::$_cache)) { + if (self::$_cacheTags) { + self::$_cache->save( serialize($timestamp), $idstamp, array('Zend_Date')); + } else { + self::$_cache->save( serialize($timestamp), $idstamp); + } + } + } + + if (($timestamp < 0) and ($gmt !== true)) { + $timestamp -= $this->_offset; + } + + date_default_timezone_set($oldzone); + $date = $this->getDateParts($timestamp, true); + $length = strlen($format); + $output = ''; + + for ($i = 0; $i < $length; $i++) { + switch($format[$i]) { + // day formats + case 'd': // day of month, 2 digits, with leading zero, 01 - 31 + $output .= (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']); + break; + + case 'D': // day of week, 3 letters, Mon - Sun + $output .= date('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))); + break; + + case 'j': // day of month, without leading zero, 1 - 31 + $output .= $date['mday']; + break; + + case 'l': // day of week, full string name, Sunday - Saturday + $output .= date('l', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))); + break; + + case 'N': // ISO 8601 numeric day of week, 1 - 7 + $day = self::dayOfWeek($date['year'], $date['mon'], $date['mday']); + if ($day == 0) { + $day = 7; + } + $output .= $day; + break; + + case 'S': // english suffix for day of month, st nd rd th + if (($date['mday'] % 10) == 1) { + $output .= 'st'; + } else if ((($date['mday'] % 10) == 2) and ($date['mday'] != 12)) { + $output .= 'nd'; + } else if (($date['mday'] % 10) == 3) { + $output .= 'rd'; + } else { + $output .= 'th'; + } + break; + + case 'w': // numeric day of week, 0 - 6 + $output .= self::dayOfWeek($date['year'], $date['mon'], $date['mday']); + break; + + case 'z': // day of year, 0 - 365 + $output .= $date['yday']; + break; + + + // week formats + case 'W': // ISO 8601, week number of year + $output .= $this->weekNumber($date['year'], $date['mon'], $date['mday']); + break; + + + // month formats + case 'F': // string month name, january - december + $output .= date('F', mktime(0, 0, 0, $date['mon'], 2, 1971)); + break; + + case 'm': // number of month, with leading zeros, 01 - 12 + $output .= (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']); + break; + + case 'M': // 3 letter month name, Jan - Dec + $output .= date('M',mktime(0, 0, 0, $date['mon'], 2, 1971)); + break; + + case 'n': // number of month, without leading zeros, 1 - 12 + $output .= $date['mon']; + break; + + case 't': // number of day in month + $output .= self::$_monthTable[$date['mon'] - 1]; + break; + + + // year formats + case 'L': // is leap year ? + $output .= (self::isYearLeapYear($date['year'])) ? '1' : '0'; + break; + + case 'o': // ISO 8601 year number + $week = $this->weekNumber($date['year'], $date['mon'], $date['mday']); + if (($week > 50) and ($date['mon'] == 1)) { + $output .= ($date['year'] - 1); + } else { + $output .= $date['year']; + } + break; + + case 'Y': // year number, 4 digits + $output .= $date['year']; + break; + + case 'y': // year number, 2 digits + $output .= substr($date['year'], strlen($date['year']) - 2, 2); + break; + + + // time formats + case 'a': // lower case am/pm + $output .= (($date['hours'] >= 12) ? 'pm' : 'am'); + break; + + case 'A': // upper case am/pm + $output .= (($date['hours'] >= 12) ? 'PM' : 'AM'); + break; + + case 'B': // swatch internet time + $dayseconds = ($date['hours'] * 3600) + ($date['minutes'] * 60) + $date['seconds']; + if ($gmt === true) { + $dayseconds += 3600; + } + $output .= (int) (($dayseconds % 86400) / 86.4); + break; + + case 'g': // hours without leading zeros, 12h format + if ($date['hours'] > 12) { + $hour = $date['hours'] - 12; + } else { + if ($date['hours'] == 0) { + $hour = '12'; + } else { + $hour = $date['hours']; + } + } + $output .= $hour; + break; + + case 'G': // hours without leading zeros, 24h format + $output .= $date['hours']; + break; + + case 'h': // hours with leading zeros, 12h format + if ($date['hours'] > 12) { + $hour = $date['hours'] - 12; + } else { + if ($date['hours'] == 0) { + $hour = '12'; + } else { + $hour = $date['hours']; + } + } + $output .= (($hour < 10) ? '0'.$hour : $hour); + break; + + case 'H': // hours with leading zeros, 24h format + $output .= (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']); + break; + + case 'i': // minutes with leading zeros + $output .= (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']); + break; + + case 's': // seconds with leading zeros + $output .= (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']); + break; + + + // timezone formats + case 'e': // timezone identifier + if ($gmt === true) { + $output .= gmdate('e', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('e', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'I': // daylight saving time or not + if ($gmt === true) { + $output .= gmdate('I', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('I', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'O': // difference to GMT in hours + $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset(); + $output .= sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36); + break; + + case 'P': // difference to GMT with colon + $gmtstr = ($gmt === true) ? 0 : $this->getGmtOffset(); + $gmtstr = sprintf('%s%04d', ($gmtstr <= 0) ? '+' : '-', abs($gmtstr) / 36); + $output = $output . substr($gmtstr, 0, 3) . ':' . substr($gmtstr, 3); + break; + + case 'T': // timezone settings + if ($gmt === true) { + $output .= gmdate('T', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } else { + $output .= date('T', mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], 2000)); + } + break; + + case 'Z': // timezone offset in seconds + $output .= ($gmt === true) ? 0 : -$this->getGmtOffset(); + break; + + + // complete time formats + case 'c': // ISO 8601 date format + $difference = $this->getGmtOffset(); + $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36); + $difference = substr($difference, 0, 3) . ':' . substr($difference, 3); + $output .= $date['year'] . '-' + . (($date['mon'] < 10) ? '0' . $date['mon'] : $date['mon']) . '-' + . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . 'T' + . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':' + . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':' + . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) + . $difference; + break; + + case 'r': // RFC 2822 date format + $difference = $this->getGmtOffset(); + $difference = sprintf('%s%04d', ($difference <= 0) ? '+' : '-', abs($difference) / 36); + $output .= gmdate('D', 86400 * (3 + self::dayOfWeek($date['year'], $date['mon'], $date['mday']))) . ', ' + . (($date['mday'] < 10) ? '0' . $date['mday'] : $date['mday']) . ' ' + . date('M', mktime(0, 0, 0, $date['mon'], 2, 1971)) . ' ' + . $date['year'] . ' ' + . (($date['hours'] < 10) ? '0' . $date['hours'] : $date['hours']) . ':' + . (($date['minutes'] < 10) ? '0' . $date['minutes'] : $date['minutes']) . ':' + . (($date['seconds'] < 10) ? '0' . $date['seconds'] : $date['seconds']) . ' ' + . $difference; + break; + + case 'U': // Unix timestamp + $output .= $origstamp; + break; + + + // special formats + case "\\": // next letter to print with no format + $i++; + if ($i < $length) { + $output .= $format[$i]; + } + break; + + default: // letter is no format so add it direct + $output .= $format[$i]; + break; + } + } + + return (string) $output; + } + + /** + * Returns the day of week for a Gregorian calendar date. + * 0 = sunday, 6 = saturday + * + * @param integer $year + * @param integer $month + * @param integer $day + * @return integer dayOfWeek + */ + protected static function dayOfWeek($year, $month, $day) + { + if ((1901 < $year) and ($year < 2038)) { + return (int) date('w', mktime(0, 0, 0, $month, $day, $year)); + } + + // gregorian correction + $correction = 0; + if (($year < 1582) or (($year == 1582) and (($month < 10) or (($month == 10) && ($day < 15))))) { + $correction = 3; + } + + if ($month > 2) { + $month -= 2; + } else { + $month += 10; + $year--; + } + + $day = floor((13 * $month - 1) / 5) + $day + ($year % 100) + floor(($year % 100) / 4); + $day += floor(($year / 100) / 4) - 2 * floor($year / 100) + 77 + $correction; + + return (int) ($day - 7 * floor($day / 7)); + } + + /** + * Internal getDateParts function for handling 64bit timestamps, similar to: + * http://www.php.net/getdate + * + * Returns an array of date parts for $timestamp, relative to 1970/01/01 00:00:00 GMT/UTC. + * + * $fast specifies ALL date parts should be returned (slower) + * Default is false, and excludes $dayofweek, weekday, month and timestamp from parts returned. + * + * @param mixed $timestamp + * @param boolean $fast OPTIONAL defaults to fast (false), resulting in fewer date parts + * @return array + */ + protected function getDateParts($timestamp = null, $fast = null) + { + + // actual timestamp + if (!is_numeric($timestamp)) { + return getdate(); + } + + // 32bit timestamp + if (abs($timestamp) <= 0x7FFFFFFF) { + return @getdate((int) $timestamp); + } + + if (isset(self::$_cache)) { + $id = strtr('Zend_DateObject_getDateParts_' . $timestamp.'_'.(int)$fast, '-','_'); + if ($result = self::$_cache->load($id)) { + return unserialize($result); + } + } + + $otimestamp = $timestamp; + $numday = 0; + $month = 0; + // gregorian correction + if ($timestamp < -12219321600) { + $timestamp -= 864000; + } + + // timestamp lower 0 + if ($timestamp < 0) { + $sec = 0; + $act = 1970; + + // iterate through 10 years table, increasing speed + foreach(self::$_yearTable as $year => $seconds) { + if ($timestamp >= $seconds) { + $i = $act; + break; + } + $sec = $seconds; + $act = $year; + } + + $timestamp -= $sec; + if (!isset($i)) { + $i = $act; + } + + // iterate the max last 10 years + do { + --$i; + $day = $timestamp; + + $timestamp += 31536000; + $leapyear = self::isYearLeapYear($i); + if ($leapyear === true) { + $timestamp += 86400; + } + + if ($timestamp >= 0) { + $year = $i; + break; + } + } while ($timestamp < 0); + + $secondsPerYear = 86400 * ($leapyear ? 366 : 365) + $day; + + $timestamp = $day; + // iterate through months + for ($i = 12; --$i >= 0;) { + $day = $timestamp; + + $timestamp += self::$_monthTable[$i] * 86400; + if (($leapyear === true) and ($i == 1)) { + $timestamp += 86400; + } + + if ($timestamp >= 0) { + $month = $i; + $numday = self::$_monthTable[$i]; + if (($leapyear === true) and ($i == 1)) { + ++$numday; + } + break; + } + } + + $timestamp = $day; + $numberdays = $numday + ceil(($timestamp + 1) / 86400); + + $timestamp += ($numday - $numberdays + 1) * 86400; + $hours = floor($timestamp / 3600); + } else { + + // iterate through years + for ($i = 1970;;$i++) { + $day = $timestamp; + + $timestamp -= 31536000; + $leapyear = self::isYearLeapYear($i); + if ($leapyear === true) { + $timestamp -= 86400; + } + + if ($timestamp < 0) { + $year = $i; + break; + } + } + + $secondsPerYear = $day; + + $timestamp = $day; + // iterate through months + for ($i = 0; $i <= 11; $i++) { + $day = $timestamp; + $timestamp -= self::$_monthTable[$i] * 86400; + + if (($leapyear === true) and ($i == 1)) { + $timestamp -= 86400; + } + + if ($timestamp < 0) { + $month = $i; + $numday = self::$_monthTable[$i]; + if (($leapyear === true) and ($i == 1)) { + ++$numday; + } + break; + } + } + + $timestamp = $day; + $numberdays = ceil(($timestamp + 1) / 86400); + $timestamp = $timestamp - ($numberdays - 1) * 86400; + $hours = floor($timestamp / 3600); + } + + $timestamp -= $hours * 3600; + + $month += 1; + $minutes = floor($timestamp / 60); + $seconds = $timestamp - $minutes * 60; + + if ($fast === true) { + $array = array( + 'seconds' => $seconds, + 'minutes' => $minutes, + 'hours' => $hours, + 'mday' => $numberdays, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secondsPerYear / 86400), + ); + } else { + + $dayofweek = self::dayOfWeek($year, $month, $numberdays); + $array = array( + 'seconds' => $seconds, + 'minutes' => $minutes, + 'hours' => $hours, + 'mday' => $numberdays, + 'wday' => $dayofweek, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secondsPerYear / 86400), + 'weekday' => gmdate('l', 86400 * (3 + $dayofweek)), + 'month' => gmdate('F', mktime(0, 0, 0, $month, 1, 1971)), + 0 => $otimestamp + ); + } + + if (isset(self::$_cache)) { + if (self::$_cacheTags) { + self::$_cache->save( serialize($array), $id, array('Zend_Date')); + } else { + self::$_cache->save( serialize($array), $id); + } + } + + return $array; + } + + /** + * Internal getWeekNumber function for handling 64bit timestamps + * + * Returns the ISO 8601 week number of a given date + * + * @param integer $year + * @param integer $month + * @param integer $day + * @return integer + */ + protected function weekNumber($year, $month, $day) + { + if ((1901 < $year) and ($year < 2038)) { + return (int) date('W', mktime(0, 0, 0, $month, $day, $year)); + } + + $dayofweek = self::dayOfWeek($year, $month, $day); + $firstday = self::dayOfWeek($year, 1, 1); + if (($month == 1) and (($firstday < 1) or ($firstday > 4)) and ($day < 4)) { + $firstday = self::dayOfWeek($year - 1, 1, 1); + $month = 12; + $day = 31; + + } else if (($month == 12) and ((self::dayOfWeek($year + 1, 1, 1) < 5) and + (self::dayOfWeek($year + 1, 1, 1) > 0))) { + return 1; + } + + return intval (((self::dayOfWeek($year, 1, 1) < 5) and (self::dayOfWeek($year, 1, 1) > 0)) + + 4 * ($month - 1) + (2 * ($month - 1) + ($day - 1) + $firstday - $dayofweek + 6) * 36 / 256); + } + + /** + * Internal _range function + * Sets the value $a to be in the range of [0, $b] + * + * @param float $a - value to correct + * @param float $b - maximum range to set + */ + private function _range($a, $b) { + while ($a < 0) { + $a += $b; + } + while ($a >= $b) { + $a -= $b; + } + return $a; + } + + /** + * Calculates the sunrise or sunset based on a location + * + * @param array $location Location for calculation MUST include 'latitude', 'longitude', 'horizon' + * @param bool $horizon true: sunrise; false: sunset + * @return mixed - false: midnight sun, integer: + */ + protected function calcSun($location, $horizon, $rise = false) + { + // timestamp within 32bit + if (abs($this->_unixTimestamp) <= 0x7FFFFFFF) { + if ($rise === false) { + return date_sunset($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'], + $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600); + } + return date_sunrise($this->_unixTimestamp, SUNFUNCS_RET_TIMESTAMP, $location['latitude'], + $location['longitude'], 90 + $horizon, $this->getGmtOffset() / 3600); + } + + // self calculation - timestamp bigger than 32bit + // fix circle values + $quarterCircle = 0.5 * M_PI; + $halfCircle = M_PI; + $threeQuarterCircle = 1.5 * M_PI; + $fullCircle = 2 * M_PI; + + // radiant conversion for coordinates + $radLatitude = $location['latitude'] * $halfCircle / 180; + $radLongitude = $location['longitude'] * $halfCircle / 180; + + // get solar coordinates + $tmpRise = $rise ? $quarterCircle : $threeQuarterCircle; + $radDay = $this->date('z',$this->_unixTimestamp) + ($tmpRise - $radLongitude) / $fullCircle; + + // solar anomoly and longitude + $solAnomoly = $radDay * 0.017202 - 0.0574039; + $solLongitude = $solAnomoly + 0.0334405 * sin($solAnomoly); + $solLongitude += 4.93289 + 3.49066E-4 * sin(2 * $solAnomoly); + + // get quadrant + $solLongitude = $this->_range($solLongitude, $fullCircle); + + if (($solLongitude / $quarterCircle) - intval($solLongitude / $quarterCircle) == 0) { + $solLongitude += 4.84814E-6; + } + + // solar ascension + $solAscension = sin($solLongitude) / cos($solLongitude); + $solAscension = atan2(0.91746 * $solAscension, 1); + + // adjust quadrant + if ($solLongitude > $threeQuarterCircle) { + $solAscension += $fullCircle; + } else if ($solLongitude > $quarterCircle) { + $solAscension += $halfCircle; + } + + // solar declination + $solDeclination = 0.39782 * sin($solLongitude); + $solDeclination /= sqrt(-$solDeclination * $solDeclination + 1); + $solDeclination = atan2($solDeclination, 1); + + $solHorizon = $horizon - sin($solDeclination) * sin($radLatitude); + $solHorizon /= cos($solDeclination) * cos($radLatitude); + + // midnight sun, always night + if (abs($solHorizon) > 1) { + return false; + } + + $solHorizon /= sqrt(-$solHorizon * $solHorizon + 1); + $solHorizon = $quarterCircle - atan2($solHorizon, 1); + + if ($rise) { + $solHorizon = $fullCircle - $solHorizon; + } + + // time calculation + $localTime = $solHorizon + $solAscension - 0.0172028 * $radDay - 1.73364; + $universalTime = $localTime - $radLongitude; + + // determinate quadrant + $universalTime = $this->_range($universalTime, $fullCircle); + + // radiant to hours + $universalTime *= 24 / $fullCircle; + + // convert to time + $hour = intval($universalTime); + $universalTime = ($universalTime - $hour) * 60; + $min = intval($universalTime); + $universalTime = ($universalTime - $min) * 60; + $sec = intval($universalTime); + + return $this->mktime($hour, $min, $sec, $this->date('m', $this->_unixTimestamp), + $this->date('j', $this->_unixTimestamp), $this->date('Y', $this->_unixTimestamp), + -1, true); + } + + /** + * Sets a new timezone for calculation of $this object's gmt offset. + * For a list of supported timezones look here: http://php.net/timezones + * If no timezone can be detected or the given timezone is wrong UTC will be set. + * + * @param string $zone OPTIONAL timezone for date calculation; defaults to date_default_timezone_get() + * @return Zend_Date_DateObject Provides fluent interface + * @throws Zend_Date_Exception + */ + public function setTimezone($zone = null) + { + $oldzone = @date_default_timezone_get(); + if ($zone === null) { + $zone = $oldzone; + } + + // throw an error on false input, but only if the new date extension is available + if (function_exists('timezone_open')) { + if (!@timezone_open($zone)) { + throw new Zend_Date_Exception("timezone ($zone) is not a known timezone", 0, null, $zone); + } + } + // this can generate an error if the date extension is not available and a false timezone is given + $result = @date_default_timezone_set($zone); + if ($result === true) { + $this->_offset = mktime(0, 0, 0, 1, 2, 1970) - gmmktime(0, 0, 0, 1, 2, 1970); + $this->_timezone = $zone; + } + date_default_timezone_set($oldzone); + + if (($zone == 'UTC') or ($zone == 'GMT')) { + $this->_dst = false; + } else { + $this->_dst = true; + } + + return $this; + } + + /** + * Return the timezone of $this object. + * The timezone is initially set when the object is instantiated. + * + * @return string actual set timezone string + */ + public function getTimezone() + { + return $this->_timezone; + } + + /** + * Return the offset to GMT of $this object's timezone. + * The offset to GMT is initially set when the object is instantiated using the currently, + * in effect, default timezone for PHP functions. + * + * @return integer seconds difference between GMT timezone and timezone when object was instantiated + */ + public function getGmtOffset() + { + $date = $this->getDateParts($this->getUnixTimestamp(), true); + $zone = @date_default_timezone_get(); + $result = @date_default_timezone_set($this->_timezone); + if ($result === true) { + $offset = $this->mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], $date['year'], false) + - $this->mktime($date['hours'], $date['minutes'], $date['seconds'], + $date['mon'], $date['mday'], $date['year'], true); + } + date_default_timezone_set($zone); + + return $offset; + } + + /** + * Internal method to check if the given cache supports tags + * + * @param Zend_Cache $cache + */ + protected static function _getTagSupportForCache() + { + $backend = self::$_cache->getBackend(); + if ($backend instanceof Zend_Cache_Backend_ExtendedInterface) { + $cacheOptions = $backend->getCapabilities(); + self::$_cacheTags = $cacheOptions['tags']; + } else { + self::$_cacheTags = false; + } + + return self::$_cacheTags; + } +} diff --git a/library/vendor/Zend/Date/Exception.php b/library/vendor/Zend/Date/Exception.php new file mode 100644 index 000000000..20914463f --- /dev/null +++ b/library/vendor/Zend/Date/Exception.php @@ -0,0 +1,48 @@ +operand = $op; + parent::__construct($message, $code, $e); + } + + public function getOperand() + { + return $this->operand; + } +} diff --git a/library/vendor/Zend/Db.php b/library/vendor/Zend/Db.php new file mode 100644 index 000000000..a6baf24e3 --- /dev/null +++ b/library/vendor/Zend/Db.php @@ -0,0 +1,282 @@ +toArray(); + } + + /* + * Convert Zend_Config argument to plain string + * adapter name and separate config object. + */ + if ($adapter instanceof Zend_Config) { + if (isset($adapter->params)) { + $config = $adapter->params->toArray(); + } + if (isset($adapter->adapter)) { + $adapter = (string) $adapter->adapter; + } else { + $adapter = null; + } + } + + /* + * Verify that adapter parameters are in an array. + */ + if (!is_array($config)) { + /** + * @see Zend_Db_Exception + */ + throw new Zend_Db_Exception('Adapter parameters must be in an array or a Zend_Config object'); + } + + /* + * Verify that an adapter name has been specified. + */ + if (!is_string($adapter) || empty($adapter)) { + /** + * @see Zend_Db_Exception + */ + throw new Zend_Db_Exception('Adapter name must be specified in a string'); + } + + /* + * Form full adapter class name + */ + $adapterNamespace = 'Zend_Db_Adapter'; + if (isset($config['adapterNamespace'])) { + if ($config['adapterNamespace'] != '') { + $adapterNamespace = $config['adapterNamespace']; + } + unset($config['adapterNamespace']); + } + + // Adapter no longer normalized- see http://framework.zend.com/issues/browse/ZF-5606 + $adapterName = $adapterNamespace . '_'; + $adapterName .= str_replace(' ', '_', ucwords(str_replace('_', ' ', strtolower($adapter)))); + + /* + * Load the adapter class. This throws an exception + * if the specified class cannot be loaded. + */ + if (!class_exists($adapterName)) { + Zend_Loader::loadClass($adapterName); + } + + /* + * Create an instance of the adapter class. + * Pass the config to the adapter class constructor. + */ + $dbAdapter = new $adapterName($config); + + /* + * Verify that the object created is a descendent of the abstract adapter type. + */ + if (! $dbAdapter instanceof Zend_Db_Adapter_Abstract) { + /** + * @see Zend_Db_Exception + */ + throw new Zend_Db_Exception("Adapter class '$adapterName' does not extend Zend_Db_Adapter_Abstract"); + } + + return $dbAdapter; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Abstract.php b/library/vendor/Zend/Db/Adapter/Abstract.php new file mode 100644 index 000000000..8879626d1 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Abstract.php @@ -0,0 +1,1273 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE + ); + + /** Weither or not that object can get serialized + * + * @var bool + */ + protected $_allowSerialization = true; + + /** + * Weither or not the database should be reconnected + * to that adapter when waking up + * + * @var bool + */ + protected $_autoReconnectOnUnserialize = false; + + /** + * Constructor. + * + * $config is an array of key/value pairs or an instance of Zend_Config + * containing configuration options. These options are common to most adapters: + * + * dbname => (string) The name of the database to user + * username => (string) Connect to the database as this username. + * password => (string) Password associated with the username. + * host => (string) What host to connect to, defaults to localhost + * + * Some options are used on a case-by-case basis by adapters: + * + * port => (string) The port of the database + * persistent => (boolean) Whether to use a persistent connection or not, defaults to false + * protocol => (string) The network protocol, defaults to TCPIP + * caseFolding => (int) style of case-alteration used for identifiers + * socket => (string) The socket or named pipe that should be used + * + * @param array|Zend_Config $config An array or instance of Zend_Config having configuration data + * @throws Zend_Db_Adapter_Exception + */ + public function __construct($config) + { + /* + * Verify that adapter parameters are in an array. + */ + if (!is_array($config)) { + /* + * Convert Zend_Config argument to a plain array. + */ + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } else { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('Adapter parameters must be in an array or a Zend_Config object'); + } + } + + $this->_checkRequiredOptions($config); + + $options = array( + Zend_Db::CASE_FOLDING => $this->_caseFolding, + Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers, + Zend_Db::FETCH_MODE => $this->_fetchMode, + ); + $driverOptions = array(); + + /* + * normalize the config and merge it with the defaults + */ + if (array_key_exists('options', $config)) { + // can't use array_merge() because keys might be integers + foreach ((array) $config['options'] as $key => $value) { + $options[$key] = $value; + } + } + if (array_key_exists('driver_options', $config)) { + if (!empty($config['driver_options'])) { + // can't use array_merge() because keys might be integers + foreach ((array) $config['driver_options'] as $key => $value) { + $driverOptions[$key] = $value; + } + } + } + + if (!isset($config['charset'])) { + $config['charset'] = null; + } + + if (!isset($config['persistent'])) { + $config['persistent'] = false; + } + + $this->_config = array_merge($this->_config, $config); + $this->_config['options'] = $options; + $this->_config['driver_options'] = $driverOptions; + + + // obtain the case setting, if there is one + if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) { + $case = (int) $options[Zend_Db::CASE_FOLDING]; + switch ($case) { + case Zend_Db::CASE_LOWER: + case Zend_Db::CASE_UPPER: + case Zend_Db::CASE_NATURAL: + $this->_caseFolding = $case; + break; + default: + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception('Case must be one of the following constants: ' + . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER'); + } + } + + if (array_key_exists(Zend_Db::FETCH_MODE, $options)) { + if (is_string($options[Zend_Db::FETCH_MODE])) { + $constant = 'Zend_Db::FETCH_' . strtoupper($options[Zend_Db::FETCH_MODE]); + if(defined($constant)) { + $options[Zend_Db::FETCH_MODE] = constant($constant); + } + } + $this->setFetchMode((int) $options[Zend_Db::FETCH_MODE]); + } + + // obtain quoting property if there is one + if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) { + $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS]; + } + + // obtain allow serialization property if there is one + if (array_key_exists(Zend_Db::ALLOW_SERIALIZATION, $options)) { + $this->_allowSerialization = (bool) $options[Zend_Db::ALLOW_SERIALIZATION]; + } + + // obtain auto reconnect on unserialize property if there is one + if (array_key_exists(Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) { + $this->_autoReconnectOnUnserialize = (bool) $options[Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE]; + } + + // create a profiler object + $profiler = false; + if (array_key_exists(Zend_Db::PROFILER, $this->_config)) { + $profiler = $this->_config[Zend_Db::PROFILER]; + unset($this->_config[Zend_Db::PROFILER]); + } + $this->setProfiler($profiler); + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + + if (! array_key_exists('password', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials"); + } + + if (! array_key_exists('username', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials"); + } + } + + /** + * Returns the underlying database connection object or resource. + * If not presently connected, this initiates the connection. + * + * @return object|resource|null + */ + public function getConnection() + { + $this->_connect(); + return $this->_connection; + } + + /** + * Returns the configuration variables in this adapter. + * + * @return array + */ + public function getConfig() + { + return $this->_config; + } + + /** + * Set the adapter's profiler object. + * + * The argument may be a boolean, an associative array, an instance of + * Zend_Db_Profiler, or an instance of Zend_Config. + * + * A boolean argument sets the profiler to enabled if true, or disabled if + * false. The profiler class is the adapter's default profiler class, + * Zend_Db_Profiler. + * + * An instance of Zend_Db_Profiler sets the adapter's instance to that + * object. The profiler is enabled and disabled separately. + * + * An associative array argument may contain any of the keys 'enabled', + * 'class', and 'instance'. The 'enabled' and 'instance' keys correspond to the + * boolean and object types documented above. The 'class' key is used to name a + * class to use for a custom profiler. The class must be Zend_Db_Profiler or a + * subclass. The class is instantiated with no constructor arguments. The 'class' + * option is ignored when the 'instance' option is supplied. + * + * An object of type Zend_Config may contain the properties 'enabled', 'class', and + * 'instance', just as if an associative array had been passed instead. + * + * @param Zend_Db_Profiler|Zend_Config|array|boolean $profiler + * @return Zend_Db_Adapter_Abstract Provides a fluent interface + * @throws Zend_Db_Profiler_Exception if the object instance or class specified + * is not Zend_Db_Profiler or an extension of that class. + */ + public function setProfiler($profiler) + { + $enabled = null; + $profilerClass = $this->_defaultProfilerClass; + $profilerInstance = null; + + if ($profilerIsObject = is_object($profiler)) { + if ($profiler instanceof Zend_Db_Profiler) { + $profilerInstance = $profiler; + } else if ($profiler instanceof Zend_Config) { + $profiler = $profiler->toArray(); + } else { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler' + . ' or Zend_Config when provided as an object'); + } + } + + if (is_array($profiler)) { + if (isset($profiler['enabled'])) { + $enabled = (bool) $profiler['enabled']; + } + if (isset($profiler['class'])) { + $profilerClass = $profiler['class']; + } + if (isset($profiler['instance'])) { + $profilerInstance = $profiler['instance']; + } + } else if (!$profilerIsObject) { + $enabled = (bool) $profiler; + } + + if ($profilerInstance === null) { + if (!class_exists($profilerClass)) { + Zend_Loader::loadClass($profilerClass); + } + $profilerInstance = new $profilerClass(); + } + + if (!$profilerInstance instanceof Zend_Db_Profiler) { + /** @see Zend_Db_Profiler_Exception */ + throw new Zend_Db_Profiler_Exception('Class ' . get_class($profilerInstance) . ' does not extend ' + . 'Zend_Db_Profiler'); + } + + if (null !== $enabled) { + $profilerInstance->setEnabled($enabled); + } + + $this->_profiler = $profilerInstance; + + return $this; + } + + + /** + * Returns the profiler for this adapter. + * + * @return Zend_Db_Profiler + */ + public function getProfiler() + { + return $this->_profiler; + } + + /** + * Get the default statement class. + * + * @return string + */ + public function getStatementClass() + { + return $this->_defaultStmtClass; + } + + /** + * Set the default statement class. + * + * @return Zend_Db_Adapter_Abstract Fluent interface + */ + public function setStatementClass($class) + { + $this->_defaultStmtClass = $class; + return $this; + } + + /** + * Prepares and executes an SQL statement with bound data. + * + * @param mixed $sql The SQL statement with placeholders. + * May be a string or Zend_Db_Select. + * @param mixed $bind An array of data to bind to the placeholders. + * @return Zend_Db_Statement_Interface + */ + public function query($sql, $bind = array()) + { + // connect to the database if needed + $this->_connect(); + + // is the $sql a Zend_Db_Select object? + if ($sql instanceof Zend_Db_Select) { + if (empty($bind)) { + $bind = $sql->getBind(); + } + + $sql = $sql->assemble(); + } + + // make sure $bind to an array; + // don't use (array) typecasting because + // because $bind may be a Zend_Db_Expr object + if (!is_array($bind)) { + $bind = array($bind); + } + + // prepare and execute the statement with profiling + $stmt = $this->prepare($sql); + $stmt->execute($bind); + + // return the results embedded in the prepared statement object + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Leave autocommit mode and begin a transaction. + * + * @return Zend_Db_Adapter_Abstract + */ + public function beginTransaction() + { + $this->_connect(); + $q = $this->_profiler->queryStart('begin', Zend_Db_Profiler::TRANSACTION); + $this->_beginTransaction(); + $this->_profiler->queryEnd($q); + return $this; + } + + /** + * Commit a transaction and return to autocommit mode. + * + * @return Zend_Db_Adapter_Abstract + */ + public function commit() + { + $this->_connect(); + $q = $this->_profiler->queryStart('commit', Zend_Db_Profiler::TRANSACTION); + $this->_commit(); + $this->_profiler->queryEnd($q); + return $this; + } + + /** + * Roll back a transaction and return to autocommit mode. + * + * @return Zend_Db_Adapter_Abstract + */ + public function rollBack() + { + $this->_connect(); + $q = $this->_profiler->queryStart('rollback', Zend_Db_Profiler::TRANSACTION); + $this->_rollBack(); + $this->_profiler->queryEnd($q); + return $this; + } + + /** + * Inserts a table row with specified data. + * + * @param mixed $table The table to insert data into. + * @param array $bind Column-value pairs. + * @return int The number of affected rows. + * @throws Zend_Db_Adapter_Exception + */ + public function insert($table, array $bind) + { + // extract and quote col names from the array keys + $cols = array(); + $vals = array(); + $i = 0; + foreach ($bind as $col => $val) { + $cols[] = $this->quoteIdentifier($col, true); + if ($val instanceof Zend_Db_Expr) { + $vals[] = $val->__toString(); + unset($bind[$col]); + } else { + if ($this->supportsParameters('positional')) { + $vals[] = '?'; + } else { + if ($this->supportsParameters('named')) { + unset($bind[$col]); + $bind[':col'.$i] = $val; + $vals[] = ':col'.$i; + $i++; + } else { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding"); + } + } + } + } + + // build the statement + $sql = "INSERT INTO " + . $this->quoteIdentifier($table, true) + . ' (' . implode(', ', $cols) . ') ' + . 'VALUES (' . implode(', ', $vals) . ')'; + + // execute the statement and return the number of affected rows + if ($this->supportsParameters('positional')) { + $bind = array_values($bind); + } + $stmt = $this->query($sql, $bind); + $result = $stmt->rowCount(); + return $result; + } + + /** + * Updates table rows with specified data based on a WHERE clause. + * + * @param mixed $table The table to update. + * @param array $bind Column-value pairs. + * @param mixed $where UPDATE WHERE clause(s). + * @return int The number of affected rows. + * @throws Zend_Db_Adapter_Exception + */ + public function update($table, array $bind, $where = '') + { + /** + * Build "col = ?" pairs for the statement, + * except for Zend_Db_Expr which is treated literally. + */ + $set = array(); + $i = 0; + foreach ($bind as $col => $val) { + if ($val instanceof Zend_Db_Expr) { + $val = $val->__toString(); + unset($bind[$col]); + } else { + if ($this->supportsParameters('positional')) { + $val = '?'; + } else { + if ($this->supportsParameters('named')) { + unset($bind[$col]); + $bind[':col'.$i] = $val; + $val = ':col'.$i; + $i++; + } else { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding"); + } + } + } + $set[] = $this->quoteIdentifier($col, true) . ' = ' . $val; + } + + $where = $this->_whereExpr($where); + + /** + * Build the UPDATE statement + */ + $sql = "UPDATE " + . $this->quoteIdentifier($table, true) + . ' SET ' . implode(', ', $set) + . (($where) ? " WHERE $where" : ''); + + /** + * Execute the statement and return the number of affected rows + */ + if ($this->supportsParameters('positional')) { + $stmt = $this->query($sql, array_values($bind)); + } else { + $stmt = $this->query($sql, $bind); + } + $result = $stmt->rowCount(); + return $result; + } + + /** + * Deletes table rows based on a WHERE clause. + * + * @param mixed $table The table to update. + * @param mixed $where DELETE WHERE clause(s). + * @return int The number of affected rows. + */ + public function delete($table, $where = '') + { + $where = $this->_whereExpr($where); + + /** + * Build the DELETE statement + */ + $sql = "DELETE FROM " + . $this->quoteIdentifier($table, true) + . (($where) ? " WHERE $where" : ''); + + /** + * Execute the statement and return the number of affected rows + */ + $stmt = $this->query($sql); + $result = $stmt->rowCount(); + return $result; + } + + /** + * Convert an array, string, or Zend_Db_Expr object + * into a string to put in a WHERE clause. + * + * @param mixed $where + * @return string + */ + protected function _whereExpr($where) + { + if (empty($where)) { + return $where; + } + if (!is_array($where)) { + $where = array($where); + } + foreach ($where as $cond => &$term) { + // is $cond an int? (i.e. Not a condition) + if (is_int($cond)) { + // $term is the full condition + if ($term instanceof Zend_Db_Expr) { + $term = $term->__toString(); + } + } else { + // $cond is the condition with placeholder, + // and $term is quoted into the condition + $term = $this->quoteInto($cond, $term); + } + $term = '(' . $term . ')'; + } + + $where = implode(' AND ', $where); + return $where; + } + + /** + * Creates and returns a new Zend_Db_Select object for this adapter. + * + * @return Zend_Db_Select + */ + public function select() + { + return new Zend_Db_Select($this); + } + + /** + * Get the fetch mode. + * + * @return int + */ + public function getFetchMode() + { + return $this->_fetchMode; + } + + /** + * Fetches all SQL result rows as a sequential array. + * Uses the current fetchMode for the adapter. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @param mixed $fetchMode Override current fetch mode. + * @return array + */ + public function fetchAll($sql, $bind = array(), $fetchMode = null) + { + if ($fetchMode === null) { + $fetchMode = $this->_fetchMode; + } + $stmt = $this->query($sql, $bind); + $result = $stmt->fetchAll($fetchMode); + return $result; + } + + /** + * Fetches the first row of the SQL result. + * Uses the current fetchMode for the adapter. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @param mixed $fetchMode Override current fetch mode. + * @return mixed Array, object, or scalar depending on fetch mode. + */ + public function fetchRow($sql, $bind = array(), $fetchMode = null) + { + if ($fetchMode === null) { + $fetchMode = $this->_fetchMode; + } + $stmt = $this->query($sql, $bind); + $result = $stmt->fetch($fetchMode); + return $result; + } + + /** + * Fetches all SQL result rows as an associative array. + * + * The first column is the key, the entire row array is the + * value. You should construct the query to be sure that + * the first column contains unique values, or else + * rows with duplicate values in the first column will + * overwrite previous data. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return array + */ + public function fetchAssoc($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $data = array(); + while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) { + $tmp = array_values(array_slice($row, 0, 1)); + $data[$tmp[0]] = $row; + } + return $data; + } + + /** + * Fetches the first column of all SQL result rows as an array. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return array + */ + public function fetchCol($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0); + return $result; + } + + /** + * Fetches all SQL result rows as an array of key-value pairs. + * + * The first column is the key, the second column is the + * value. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return array + */ + public function fetchPairs($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $data = array(); + while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) { + $data[$row[0]] = $row[1]; + } + return $data; + } + + /** + * Fetches the first column of the first row of the SQL result. + * + * @param string|Zend_Db_Select $sql An SQL SELECT statement. + * @param mixed $bind Data to bind into SELECT placeholders. + * @return string + */ + public function fetchOne($sql, $bind = array()) + { + $stmt = $this->query($sql, $bind); + $result = $stmt->fetchColumn(0); + return $result; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value)) { + return $value; + } elseif (is_float($value)) { + return sprintf('%F', $value); + } + return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'"; + } + + /** + * Safely quotes a value for an SQL statement. + * + * If an array is passed as the value, the array values are quoted + * and then returned as a comma-separated string. + * + * @param mixed $value The value to quote. + * @param mixed $type OPTIONAL the SQL datatype name, or constant, or null. + * @return mixed An SQL-safe quoted value (or string of separated values). + */ + public function quote($value, $type = null) + { + $this->_connect(); + + if ($value instanceof Zend_Db_Select) { + return '(' . $value->assemble() . ')'; + } + + if ($value instanceof Zend_Db_Expr) { + return $value->__toString(); + } + + if (is_array($value)) { + foreach ($value as &$val) { + $val = $this->quote($val, $type); + } + return implode(', ', $value); + } + + if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) { + $quotedValue = '0'; + switch ($this->_numericDataTypes[$type]) { + case Zend_Db::INT_TYPE: // 32-bit integer + $quotedValue = (string) intval($value); + break; + case Zend_Db::BIGINT_TYPE: // 64-bit integer + // ANSI SQL-style hex literals (e.g. x'[\dA-F]+') + // are not supported here, because these are string + // literals, not numeric literals. + if (preg_match('/^( + [+-]? # optional sign + (?: + 0[Xx][\da-fA-F]+ # ODBC-style hexadecimal + |\d+ # decimal or octal, or MySQL ZEROFILL decimal + (?:[eE][+-]?\d+)? # optional exponent on decimals or octals + ) + )/x', + (string) $value, $matches)) { + $quotedValue = $matches[1]; + } + break; + case Zend_Db::FLOAT_TYPE: // float or decimal + $quotedValue = sprintf('%F', $value); + } + return $quotedValue; + } + + return $this->_quote($value); + } + + /** + * Quotes a value and places into a piece of text at a placeholder. + * + * The placeholder is a question-mark; all placeholders will be replaced + * with the quoted value. For example: + * + * + * $text = "WHERE date < ?"; + * $date = "2005-01-02"; + * $safe = $sql->quoteInto($text, $date); + * // $safe = "WHERE date < '2005-01-02'" + * + * + * @param string $text The text with a placeholder. + * @param mixed $value The value to quote. + * @param string $type OPTIONAL SQL datatype + * @param integer $count OPTIONAL count of placeholders to replace + * @return string An SQL-safe quoted value placed into the original text. + */ + public function quoteInto($text, $value, $type = null, $count = null) + { + if ($count === null) { + return str_replace('?', $this->quote($value, $type), $text); + } else { + while ($count > 0) { + if (strpos($text, '?') !== false) { + $text = substr_replace($text, $this->quote($value, $type), strpos($text, '?'), 1); + } + --$count; + } + return $text; + } + } + + /** + * Quotes an identifier. + * + * Accepts a string representing a qualified indentifier. For Example: + * + * $adapter->quoteIdentifier('myschema.mytable') + * + * Returns: "myschema"."mytable" + * + * Or, an array of one or more identifiers that may form a qualified identifier: + * + * $adapter->quoteIdentifier(array('myschema','my.table')) + * + * Returns: "myschema"."my.table" + * + * The actual quote character surrounding the identifiers may vary depending on + * the adapter. + * + * @param string|array|Zend_Db_Expr $ident The identifier. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier. + */ + public function quoteIdentifier($ident, $auto=false) + { + return $this->_quoteIdentifierAs($ident, null, $auto); + } + + /** + * Quote a column identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the column. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + public function quoteColumnAs($ident, $alias, $auto=false) + { + return $this->_quoteIdentifierAs($ident, $alias, $auto); + } + + /** + * Quote a table identifier and alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An alias for the table. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + public function quoteTableAs($ident, $alias = null, $auto = false) + { + return $this->_quoteIdentifierAs($ident, $alias, $auto); + } + + /** + * Quote an identifier and an optional alias. + * + * @param string|array|Zend_Db_Expr $ident The identifier or expression. + * @param string $alias An optional alias. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @param string $as The string to add between the identifier/expression and the alias. + * @return string The quoted identifier and alias. + */ + protected function _quoteIdentifierAs($ident, $alias = null, $auto = false, $as = ' AS ') + { + if ($ident instanceof Zend_Db_Expr) { + $quoted = $ident->__toString(); + } elseif ($ident instanceof Zend_Db_Select) { + $quoted = '(' . $ident->assemble() . ')'; + } else { + if (is_string($ident)) { + $ident = explode('.', $ident); + } + if (is_array($ident)) { + $segments = array(); + foreach ($ident as $segment) { + if ($segment instanceof Zend_Db_Expr) { + $segments[] = $segment->__toString(); + } else { + $segments[] = $this->_quoteIdentifier($segment, $auto); + } + } + if ($alias !== null && end($ident) == $alias) { + $alias = null; + } + $quoted = implode('.', $segments); + } else { + $quoted = $this->_quoteIdentifier($ident, $auto); + } + } + if ($alias !== null) { + $quoted .= $as . $this->_quoteIdentifier($alias, $auto); + } + return $quoted; + } + + /** + * Quote an identifier. + * + * @param string $value The identifier or expression. + * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option. + * @return string The quoted identifier and alias. + */ + protected function _quoteIdentifier($value, $auto=false) + { + if ($auto === false || $this->_autoQuoteIdentifiers === true) { + $q = $this->getQuoteIdentifierSymbol(); + return ($q . str_replace("$q", "$q$q", $value) . $q); + } + return $value; + } + + /** + * Returns the symbol the adapter uses for delimited identifiers. + * + * @return string + */ + public function getQuoteIdentifierSymbol() + { + return '"'; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + return null; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + return null; + } + + /** + * Helper method to change the case of the strings used + * when returning result sets in FETCH_ASSOC and FETCH_BOTH + * modes. + * + * This is not intended to be used by application code, + * but the method must be public so the Statement class + * can invoke it. + * + * @param string $key + * @return string + */ + public function foldCase($key) + { + switch ($this->_caseFolding) { + case Zend_Db::CASE_LOWER: + $value = strtolower((string) $key); + break; + case Zend_Db::CASE_UPPER: + $value = strtoupper((string) $key); + break; + case Zend_Db::CASE_NATURAL: + default: + $value = (string) $key; + } + return $value; + } + + /** + * called when object is getting serialized + * This disconnects the DB object that cant be serialized + * + * @throws Zend_Db_Adapter_Exception + * @return array + */ + public function __sleep() + { + if ($this->_allowSerialization == false) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception( + get_class($this) . ' is not allowed to be serialized' + ); + } + $this->_connection = null; + + return array_keys( + array_diff_key(get_object_vars($this), array('_connection' => null)) + ); + } + + /** + * called when object is getting unserialized + * + * @return void + */ + public function __wakeup() + { + if ($this->_autoReconnectOnUnserialize == true) { + $this->getConnection(); + } + } + + /** + * Abstract Methods + */ + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + abstract public function listTables(); + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + abstract public function describeTable($tableName, $schemaName = null); + + /** + * Creates a connection to the database. + * + * @return void + */ + abstract protected function _connect(); + + /** + * Test if a connection is active + * + * @return boolean + */ + abstract public function isConnected(); + + /** + * Force the connection to close. + * + * @return void + */ + abstract public function closeConnection(); + + /** + * Prepare a statement and return a PDOStatement-like object. + * + * @param string|Zend_Db_Select $sql SQL query + * @return Zend_Db_Statement|PDOStatement + */ + abstract public function prepare($sql); + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + abstract public function lastInsertId($tableName = null, $primaryKey = null); + + /** + * Begin a transaction. + */ + abstract protected function _beginTransaction(); + + /** + * Commit a transaction. + */ + abstract protected function _commit(); + + /** + * Roll-back a transaction. + */ + abstract protected function _rollBack(); + + /** + * Set the fetch mode. + * + * @param integer $mode + * @return void + * @throws Zend_Db_Adapter_Exception + */ + abstract public function setFetchMode($mode); + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param mixed $sql + * @param integer $count + * @param integer $offset + * @return string + */ + abstract public function limit($sql, $count, $offset = 0); + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + abstract public function supportsParameters($type); + + /** + * Retrieve server version in PHP style + * + * @return string + */ + abstract public function getServerVersion(); +} diff --git a/library/vendor/Zend/Db/Adapter/Exception.php b/library/vendor/Zend/Db/Adapter/Exception.php new file mode 100644 index 000000000..f59c46df0 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Exception.php @@ -0,0 +1,56 @@ +getCode(); + } + parent::__construct($message, $code, $e); + } + + public function hasChainedException() + { + return ($this->getPrevious() !== null); + } + + public function getChainedException() + { + return $this->getPrevious(); + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php b/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php new file mode 100644 index 000000000..50991e96c --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Abstract.php @@ -0,0 +1,390 @@ +_config settings. + * + * @return string + */ + protected function _dsn() + { + // baseline of DSN parts + $dsn = $this->_config; + + // don't pass the username, password, charset, persistent and driver_options in the DSN + unset($dsn['username']); + unset($dsn['password']); + unset($dsn['options']); + unset($dsn['charset']); + unset($dsn['persistent']); + unset($dsn['driver_options']); + + // use all remaining parts in the DSN + foreach ($dsn as $key => $val) { + $dsn[$key] = "$key=$val"; + } + + return $this->_pdoType . ':' . implode(';', $dsn); + } + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + // if we already have a PDO object, no need to re-connect. + if ($this->_connection) { + return; + } + + // get the dsn first, because some adapters alter the $_pdoType + $dsn = $this->_dsn(); + + // check for PDO extension + if (!extension_loaded('pdo')) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); + } + + // check the PDO driver is available + if (!in_array($this->_pdoType, PDO::getAvailableDrivers())) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The ' . $this->_pdoType . ' driver is not currently installed'); + } + + // create PDO connection + $q = $this->_profiler->queryStart('connect', Zend_Db_Profiler::CONNECT); + + // add the persistence flag if we find it in our config array + if (isset($this->_config['persistent']) && ($this->_config['persistent'] == true)) { + $this->_config['driver_options'][PDO::ATTR_PERSISTENT] = true; + } + + try { + $this->_connection = new PDO( + $dsn, + $this->_config['username'], + $this->_config['password'], + $this->_config['driver_options'] + ); + + $this->_profiler->queryEnd($q); + + // set the PDO connection to perform case-folding on array keys, or not + $this->_connection->setAttribute(PDO::ATTR_CASE, $this->_caseFolding); + + // always use exceptions. + $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + } catch (PDOException $e) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); + } + + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return ((bool) ($this->_connection instanceof PDO)); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + $this->_connection = null; + } + + /** + * Prepares an SQL statement. + * + * @param string $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return PDOStatement + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + if (!class_exists($stmtClass)) { + Zend_Loader::loadClass($stmtClass); + } + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * On RDBMS brands that don't support sequences, $tableName and $primaryKey + * are ignored. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + $this->_connect(); + return $this->_connection->lastInsertId(); + } + + /** + * Special handling for PDO query(). + * All bind parameter names must begin with ':' + * + * @param string|Zend_Db_Select $sql The SQL statement with placeholders. + * @param array $bind An array of data to bind to the placeholders. + * @return Zend_Db_Statement_Pdo + * @throws Zend_Db_Adapter_Exception To re-throw PDOException. + */ + public function query($sql, $bind = array()) + { + if (empty($bind) && $sql instanceof Zend_Db_Select) { + $bind = $sql->getBind(); + } + + if (is_array($bind)) { + foreach ($bind as $name => $value) { + if (!is_int($name) && !preg_match('/^:/', $name)) { + $newName = ":$name"; + unset($bind[$name]); + $bind[$newName] = $value; + } + } + } + + try { + return parent::query($sql, $bind); + } catch (PDOException $e) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Executes an SQL statement and return the number of affected rows + * + * @param mixed $sql The SQL statement with placeholders. + * May be a string or Zend_Db_Select. + * @return integer Number of rows that were modified + * or deleted by the SQL statement + */ + public function exec($sql) + { + if ($sql instanceof Zend_Db_Select) { + $sql = $sql->assemble(); + } + + try { + $affected = $this->getConnection()->exec($sql); + + if ($affected === false) { + $errorInfo = $this->getConnection()->errorInfo(); + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($errorInfo[2]); + } + + return $affected; + } catch (PDOException $e) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value) || is_float($value)) { + return $value; + } + $this->_connect(); + return $this->_connection->quote($value); + } + + /** + * Begin a transaction. + */ + protected function _beginTransaction() + { + $this->_connect(); + $this->_connection->beginTransaction(); + } + + /** + * Commit a transaction. + */ + protected function _commit() + { + $this->_connect(); + $this->_connection->commit(); + } + + /** + * Roll-back a transaction. + */ + protected function _rollBack() { + $this->_connect(); + $this->_connection->rollBack(); + } + + /** + * Set the PDO fetch mode. + * + * @todo Support FETCH_CLASS and FETCH_INTO. + * + * @param int $mode A PDO fetch mode. + * @return void + * @throws Zend_Db_Adapter_Exception + */ + public function setFetchMode($mode) + { + //check for PDO extension + if (!extension_loaded('pdo')) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception('The PDO extension is required for this adapter but the extension is not loaded'); + } + switch ($mode) { + case PDO::FETCH_LAZY: + case PDO::FETCH_ASSOC: + case PDO::FETCH_NUM: + case PDO::FETCH_BOTH: + case PDO::FETCH_NAMED: + case PDO::FETCH_OBJ: + $this->_fetchMode = $mode; + break; + default: + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + switch ($type) { + case 'positional': + case 'named': + default: + return true; + } + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + try { + $version = $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION); + } catch (PDOException $e) { + // In case of the driver doesn't support getting attributes + return null; + } + $matches = null; + if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) { + return $matches[1]; + } else { + return null; + } + } +} + diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php b/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php new file mode 100644 index 000000000..b406b9a76 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Mysql.php @@ -0,0 +1,269 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'MEDIUMINT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'SERIAL' => Zend_Db::BIGINT_TYPE, + 'DEC' => Zend_Db::FLOAT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'FIXED' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE + ); + + /** + * Override _dsn() and ensure that charset is incorporated in mysql + * @see Zend_Db_Adapter_Pdo_Abstract::_dsn() + */ + protected function _dsn() + { + $dsn = parent::_dsn(); + if (isset($this->_config['charset'])) { + $dsn .= ';charset=' . $this->_config['charset']; + } + return $dsn; + } + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + if (!empty($this->_config['charset']) + && version_compare(PHP_VERSION, '5.3.6', '<') + ) { + $initCommand = "SET NAMES '" . $this->_config['charset'] . "'"; + $this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND + } + + parent::_connect(); + } + + /** + * @return string + */ + public function getQuoteIdentifierSymbol() + { + return "`"; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + return $this->fetchCol('SHOW TABLES'); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + // @todo use INFORMATION_SCHEMA someday when MySQL's + // implementation has reasonably good performance and + // the version with this improvement is in wide use. + + if ($schemaName) { + $sql = 'DESCRIBE ' . $this->quoteIdentifier("$schemaName.$tableName", true); + } else { + $sql = 'DESCRIBE ' . $this->quoteIdentifier($tableName, true); + } + $stmt = $this->query($sql); + + // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $field = 0; + $type = 1; + $null = 2; + $key = 3; + $default = 4; + $extra = 5; + + $desc = array(); + $i = 1; + $p = 1; + foreach ($result as $row) { + list($length, $scale, $precision, $unsigned, $primary, $primaryPosition, $identity) + = array(null, null, null, null, false, null, false); + if (preg_match('/unsigned/', $row[$type])) { + $unsigned = true; + } + if (preg_match('/^((?:var)?char)\((\d+)\)/', $row[$type], $matches)) { + $row[$type] = $matches[1]; + $length = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/', $row[$type], $matches)) { + $row[$type] = 'decimal'; + $precision = $matches[1]; + $scale = $matches[2]; + } else if (preg_match('/^float\((\d+),(\d+)\)/', $row[$type], $matches)) { + $row[$type] = 'float'; + $precision = $matches[1]; + $scale = $matches[2]; + } else if (preg_match('/^((?:big|medium|small|tiny)?int)\((\d+)\)/', $row[$type], $matches)) { + $row[$type] = $matches[1]; + // The optional argument of a MySQL int type is not precision + // or length; it is only a hint for display width. + } + if (strtoupper($row[$key]) == 'PRI') { + $primary = true; + $primaryPosition = $p; + if ($row[$extra] == 'auto_increment') { + $identity = true; + } else { + $identity = false; + } + ++$p; + } + $desc[$this->foldCase($row[$field])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row[$field]), + 'COLUMN_POSITION' => $i, + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $row[$default], + 'NULLABLE' => (bool) ($row[$null] == 'YES'), + 'LENGTH' => $length, + 'SCALE' => $scale, + 'PRECISION' => $precision, + 'UNSIGNED' => $unsigned, + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + ++$i; + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @throws Zend_Db_Adapter_Exception + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php b/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php new file mode 100644 index 000000000..6eeebaa65 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Pgsql.php @@ -0,0 +1,333 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::INT_TYPE, + 'SERIAL' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'BIGSERIAL' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'DOUBLE PRECISION' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE + ); + + /** + * Creates a PDO object and connects to the database. + * + * @return void + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + if ($this->_connection) { + return; + } + + parent::_connect(); + + if (!empty($this->_config['charset'])) { + $sql = "SET NAMES '" . $this->_config['charset'] . "'"; + $this->_connection->exec($sql); + } + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + // @todo use a better query with joins instead of subqueries + $sql = "SELECT c.relname AS table_name " + . "FROM pg_class c, pg_user u " + . "WHERE c.relowner = u.usesysid AND c.relkind = 'r' " + . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " + . "AND c.relname !~ '^(pg_|sql_)' " + . "UNION " + . "SELECT c.relname AS table_name " + . "FROM pg_class c " + . "WHERE c.relkind = 'r' " + . "AND NOT EXISTS (SELECT 1 FROM pg_views WHERE viewname = c.relname) " + . "AND NOT EXISTS (SELECT 1 FROM pg_user WHERE usesysid = c.relowner) " + . "AND c.relname !~ '^pg_'"; + + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = "SELECT + a.attnum, + n.nspname, + c.relname, + a.attname AS colname, + t.typname AS type, + a.atttypmod, + FORMAT_TYPE(a.atttypid, a.atttypmod) AS complete_type, + d.adsrc AS default_value, + a.attnotnull AS notnull, + a.attlen AS length, + co.contype, + ARRAY_TO_STRING(co.conkey, ',') AS conkey + FROM pg_attribute AS a + JOIN pg_class AS c ON a.attrelid = c.oid + JOIN pg_namespace AS n ON c.relnamespace = n.oid + JOIN pg_type AS t ON a.atttypid = t.oid + LEFT OUTER JOIN pg_constraint AS co ON (co.conrelid = c.oid + AND a.attnum = ANY(co.conkey) AND co.contype = 'p') + LEFT OUTER JOIN pg_attrdef AS d ON d.adrelid = c.oid AND d.adnum = a.attnum + WHERE a.attnum > 0 AND c.relname = ".$this->quote($tableName); + if ($schemaName) { + $sql .= " AND n.nspname = ".$this->quote($schemaName); + } + $sql .= ' ORDER BY a.attnum'; + + $stmt = $this->query($sql); + + // Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $attnum = 0; + $nspname = 1; + $relname = 2; + $colname = 3; + $type = 4; + $atttypemod = 5; + $complete_type = 6; + $default_value = 7; + $notnull = 8; + $length = 9; + $contype = 10; + $conkey = 11; + + $desc = array(); + foreach ($result as $key => $row) { + $defaultValue = $row[$default_value]; + if ($row[$type] == 'varchar' || $row[$type] == 'bpchar' ) { + if (preg_match('/character(?: varying)?(?:\((\d+)\))?/', $row[$complete_type], $matches)) { + if (isset($matches[1])) { + $row[$length] = $matches[1]; + } else { + $row[$length] = null; // unlimited + } + } + if (preg_match("/^'(.*?)'::(?:character varying|bpchar)$/", $defaultValue, $matches)) { + $defaultValue = $matches[1]; + } + } + list($primary, $primaryPosition, $identity) = array(false, null, false); + if ($row[$contype] == 'p') { + $primary = true; + $primaryPosition = array_search($row[$attnum], explode(',', $row[$conkey])) + 1; + $identity = (bool) (preg_match('/^nextval/', $row[$default_value])); + } + $desc[$this->foldCase($row[$colname])] = array( + 'SCHEMA_NAME' => $this->foldCase($row[$nspname]), + 'TABLE_NAME' => $this->foldCase($row[$relname]), + 'COLUMN_NAME' => $this->foldCase($row[$colname]), + 'COLUMN_POSITION' => $row[$attnum], + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $defaultValue, + 'NULLABLE' => (bool) ($row[$notnull] != 't'), + 'LENGTH' => $row[$length], + 'SCALE' => null, // @todo + 'PRECISION' => null, // @todo + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + + /** + * Return the most recent value from the specified sequence in the database. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function lastSequenceId($sequenceName) + { + $this->_connect(); + $sequenceName = str_replace($this->getQuoteIdentifierSymbol(), '', (string) $sequenceName); + $value = $this->fetchOne("SELECT CURRVAL(" + . $this->quote($this->quoteIdentifier($sequenceName, true)) + . ")"); + return $value; + } + + /** + * Generate a new value from the specified sequence in the database, and return it. + * This is supported only on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2). Other RDBMS brands return null. + * + * @param string $sequenceName + * @return string + */ + public function nextSequenceId($sequenceName) + { + $this->_connect(); + $sequenceName = str_replace($this->getQuoteIdentifierSymbol(), '', (string) $sequenceName); + $value = $this->fetchOne("SELECT NEXTVAL(" + . $this->quote($this->quoteIdentifier($sequenceName, true)) + . ")"); + return $value; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName !== null) { + $sequenceName = $tableName; + if ($primaryKey) { + $sequenceName .= "_$primaryKey"; + } + $sequenceName .= '_seq'; + return $this->lastSequenceId($sequenceName); + } + return $this->_connection->lastInsertId($tableName); + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php b/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php new file mode 100644 index 000000000..c8261fc9a --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Pdo/Sqlite.php @@ -0,0 +1,291 @@ + Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INTEGER' => Zend_Db::BIGINT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE + ); + + /** + * Constructor. + * + * $config is an array of key/value pairs containing configuration + * options. Note that the SQLite options are different than most of + * the other PDO adapters in that no username or password are needed. + * Also, an extra config key "sqlite2" specifies compatibility mode. + * + * dbname => (string) The name of the database to user (required, + * use :memory: for memory-based database) + * + * sqlite2 => (boolean) PDO_SQLITE defaults to SQLite 3. For compatibility + * with an older SQLite 2 database, set this to TRUE. + * + * @param array $config An array of configuration keys. + */ + public function __construct(array $config = array()) + { + if (isset($config['sqlite2']) && $config['sqlite2']) { + $this->_pdoType = 'sqlite2'; + } + + // SQLite uses no username/password. Stub to satisfy parent::_connect() + $this->_config['username'] = null; + $this->_config['password'] = null; + + return parent::__construct($config); + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + } + + /** + * DSN builder + */ + protected function _dsn() + { + return $this->_pdoType .':'. $this->_config['dbname']; + } + + /** + * Special configuration for SQLite behavior: make sure that result sets + * contain keys like 'column' instead of 'table.column'. + * + * @throws Zend_Db_Adapter_Exception + */ + protected function _connect() + { + /** + * if we already have a PDO object, no need to re-connect. + */ + if ($this->_connection) { + return; + } + + parent::_connect(); + + $retval = $this->_connection->exec('PRAGMA full_column_names=0'); + if ($retval === false) { + $error = $this->_connection->errorInfo(); + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception($error[2]); + } + + $retval = $this->_connection->exec('PRAGMA short_column_names=1'); + if ($retval === false) { + $error = $this->_connection->errorInfo(); + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception($error[2]); + } + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $sql = "SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"; + + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of database or schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + $sql = 'PRAGMA '; + + if ($schemaName) { + $sql .= $this->quoteIdentifier($schemaName) . '.'; + } + + $sql .= 'table_info('.$this->quoteIdentifier($tableName).')'; + + $stmt = $this->query($sql); + + /** + * Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection + */ + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + $cid = 0; + $name = 1; + $type = 2; + $notnull = 3; + $dflt_value = 4; + $pk = 5; + + $desc = array(); + + $p = 1; + foreach ($result as $key => $row) { + list($length, $scale, $precision, $primary, $primaryPosition, $identity) = + array(null, null, null, false, null, false); + if (preg_match('/^((?:var)?char)\((\d+)\)/i', $row[$type], $matches)) { + $row[$type] = $matches[1]; + $length = $matches[2]; + } else if (preg_match('/^decimal\((\d+),(\d+)\)/i', $row[$type], $matches)) { + $row[$type] = 'DECIMAL'; + $precision = $matches[1]; + $scale = $matches[2]; + } + if ((bool) $row[$pk]) { + $primary = true; + $primaryPosition = $p; + /** + * SQLite INTEGER primary key is always auto-increment. + */ + $identity = (bool) ($row[$type] == 'INTEGER'); + ++$p; + } + $desc[$this->foldCase($row[$name])] = array( + 'SCHEMA_NAME' => $this->foldCase($schemaName), + 'TABLE_NAME' => $this->foldCase($tableName), + 'COLUMN_NAME' => $this->foldCase($row[$name]), + 'COLUMN_POSITION' => $row[$cid]+1, + 'DATA_TYPE' => $row[$type], + 'DEFAULT' => $row[$dflt_value], + 'NULLABLE' => ! (bool) $row[$notnull], + 'LENGTH' => $length, + 'SCALE' => $scale, + 'PRECISION' => $precision, + 'UNSIGNED' => null, // Sqlite3 does not support unsigned data + 'PRIMARY' => $primary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity + ); + } + return $desc; + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + $sql .= " LIMIT $count"; + if ($offset > 0) { + $sql .= " OFFSET $offset"; + } + + return $sql; + } + +} diff --git a/library/vendor/Zend/Db/Adapter/Sqlsrv.php b/library/vendor/Zend/Db/Adapter/Sqlsrv.php new file mode 100644 index 000000000..28a9fe8bb --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Sqlsrv.php @@ -0,0 +1,662 @@ + (string) Connect to the database as this username. + * password => (string) Password associated with the username. + * dbname => The name of the local SQL Server instance + * + * @var array + */ + protected $_config = array( + 'dbname' => null, + 'username' => null, + 'password' => null, + ); + + /** + * Last insert id from INSERT query + * + * @var int + */ + protected $_lastInsertId; + + /** + * Query used to fetch last insert id + * + * @var string + */ + protected $_lastInsertSQL = 'SELECT SCOPE_IDENTITY() as Current_Identity'; + + /** + * Keys are UPPERCASE SQL datatypes or the constants + * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE. + * + * Values are: + * 0 = 32-bit integer + * 1 = 64-bit integer + * 2 = float or decimal + * + * @var array Associative array of datatypes to values 0, 1, or 2. + */ + protected $_numericDataTypes = array( + Zend_Db::INT_TYPE => Zend_Db::INT_TYPE, + Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE, + Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE, + 'INT' => Zend_Db::INT_TYPE, + 'SMALLINT' => Zend_Db::INT_TYPE, + 'TINYINT' => Zend_Db::INT_TYPE, + 'BIGINT' => Zend_Db::BIGINT_TYPE, + 'DECIMAL' => Zend_Db::FLOAT_TYPE, + 'FLOAT' => Zend_Db::FLOAT_TYPE, + 'MONEY' => Zend_Db::FLOAT_TYPE, + 'NUMERIC' => Zend_Db::FLOAT_TYPE, + 'REAL' => Zend_Db::FLOAT_TYPE, + 'SMALLMONEY' => Zend_Db::FLOAT_TYPE, + ); + + /** + * Default class name for a DB statement. + * + * @var string + */ + protected $_defaultStmtClass = 'Zend_Db_Statement_Sqlsrv'; + + /** + * Creates a connection resource. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _connect() + { + if (is_resource($this->_connection)) { + // connection already exists + return; + } + + if (!extension_loaded('sqlsrv')) { + /** + * @see Zend_Db_Adapter_Sqlsrv_Exception + */ + throw new Zend_Db_Adapter_Sqlsrv_Exception('The Sqlsrv extension is required for this adapter but the extension is not loaded'); + } + + $serverName = $this->_config['host']; + if (isset($this->_config['port'])) { + $port = (integer) $this->_config['port']; + $serverName .= ', ' . $port; + } + + $connectionInfo = array( + 'Database' => $this->_config['dbname'], + ); + + if (isset($this->_config['username']) && isset($this->_config['password'])) + { + $connectionInfo += array( + 'UID' => $this->_config['username'], + 'PWD' => $this->_config['password'], + ); + } + // else - windows authentication + + if (!empty($this->_config['driver_options'])) { + foreach ($this->_config['driver_options'] as $option => $value) { + // A value may be a constant. + if (is_string($value)) { + $constantName = strtoupper($value); + if (defined($constantName)) { + $connectionInfo[$option] = constant($constantName); + } else { + $connectionInfo[$option] = $value; + } + } + } + } + + $this->_connection = sqlsrv_connect($serverName, $connectionInfo); + + if (!$this->_connection) { + /** + * @see Zend_Db_Adapter_Sqlsrv_Exception + */ + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Check for config options that are mandatory. + * Throw exceptions if any are missing. + * + * @param array $config + * @throws Zend_Db_Adapter_Exception + */ + protected function _checkRequiredOptions(array $config) + { + // we need at least a dbname + if (! array_key_exists('dbname', $config)) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance"); + } + + if (! array_key_exists('password', $config) && array_key_exists('username', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials. + If Windows Authentication is desired, both keys 'username' and 'password' should be ommited from config."); + } + + if (array_key_exists('password', $config) && !array_key_exists('username', $config)) { + /** + * @see Zend_Db_Adapter_Exception + */ + throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials. + If Windows Authentication is desired, both keys 'username' and 'password' should be ommited from config."); + } + } + + /** + * Set the transaction isoltion level. + * + * @param integer|null $level A fetch mode from SQLSRV_TXN_*. + * @return true + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + public function setTransactionIsolationLevel($level = null) + { + $this->_connect(); + $sql = null; + + // Default transaction level in sql server + if ($level === null) + { + $level = SQLSRV_TXN_READ_COMMITTED; + } + + switch ($level) { + case SQLSRV_TXN_READ_UNCOMMITTED: + $sql = "READ UNCOMMITTED"; + break; + case SQLSRV_TXN_READ_COMMITTED: + $sql = "READ COMMITTED"; + break; + case SQLSRV_TXN_REPEATABLE_READ: + $sql = "REPEATABLE READ"; + break; + case SQLSRV_TXN_SNAPSHOT: + $sql = "SNAPSHOT"; + break; + case SQLSRV_TXN_SERIALIZABLE: + $sql = "SERIALIZABLE"; + break; + default: + throw new Zend_Db_Adapter_Sqlsrv_Exception("Invalid transaction isolation level mode '$level' specified"); + } + + if (!sqlsrv_query($this->_connection, "SET TRANSACTION ISOLATION LEVEL $sql;")) { + throw new Zend_Db_Adapter_Sqlsrv_Exception("Transaction cannot be changed to '$level'"); + } + + return true; + } + + /** + * Test if a connection is active + * + * @return boolean + */ + public function isConnected() + { + return (is_resource($this->_connection) + && (get_resource_type($this->_connection) == 'SQL Server Connection') + ); + } + + /** + * Force the connection to close. + * + * @return void + */ + public function closeConnection() + { + if ($this->isConnected()) { + sqlsrv_close($this->_connection); + } + $this->_connection = null; + } + + /** + * Returns an SQL statement for preparation. + * + * @param string $sql The SQL statement with placeholders. + * @return Zend_Db_Statement_Sqlsrv + */ + public function prepare($sql) + { + $this->_connect(); + $stmtClass = $this->_defaultStmtClass; + + if (!class_exists($stmtClass)) { + /** + * @see Zend_Loader + */ + Zend_Loader::loadClass($stmtClass); + } + + $stmt = new $stmtClass($this, $sql); + $stmt->setFetchMode($this->_fetchMode); + return $stmt; + } + + /** + * Quote a raw string. + * + * @param string $value Raw string + * @return string Quoted string + */ + protected function _quote($value) + { + if (is_int($value)) { + return $value; + } elseif (is_float($value)) { + return sprintf('%F', $value); + } + + $value = addcslashes($value, "\000\032"); + return "'" . str_replace("'", "''", $value) . "'"; + } + + /** + * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column. + * + * As a convention, on RDBMS brands that support sequences + * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence + * from the arguments and returns the last id generated by that sequence. + * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method + * returns the last value generated for such a column, and the table name + * argument is disregarded. + * + * @param string $tableName OPTIONAL Name of table. + * @param string $primaryKey OPTIONAL Name of primary key column. + * @return string + */ + public function lastInsertId($tableName = null, $primaryKey = null) + { + if ($tableName) { + $tableName = $this->quote($tableName); + $sql = 'SELECT IDENT_CURRENT (' . $tableName . ') as Current_Identity'; + return (string) $this->fetchOne($sql); + } + + if ($this->_lastInsertId > 0) { + return (string) $this->_lastInsertId; + } + + $sql = $this->_lastInsertSQL; + return (string) $this->fetchOne($sql); + } + + /** + * Inserts a table row with specified data. + * + * @param mixed $table The table to insert data into. + * @param array $bind Column-value pairs. + * @return int The number of affected rows. + */ + public function insert($table, array $bind) + { + // extract and quote col names from the array keys + $cols = array(); + $vals = array(); + foreach ($bind as $col => $val) { + $cols[] = $this->quoteIdentifier($col, true); + if ($val instanceof Zend_Db_Expr) { + $vals[] = $val->__toString(); + unset($bind[$col]); + } else { + $vals[] = '?'; + } + } + + // build the statement + $sql = "INSERT INTO " + . $this->quoteIdentifier($table, true) + . ' (' . implode(', ', $cols) . ') ' + . 'VALUES (' . implode(', ', $vals) . ')' + . ' ' . $this->_lastInsertSQL; + + // execute the statement and return the number of affected rows + $stmt = $this->query($sql, array_values($bind)); + $result = $stmt->rowCount(); + + $stmt->nextRowset(); + + $this->_lastInsertId = $stmt->fetchColumn(); + + return $result; + } + + /** + * Returns a list of the tables in the database. + * + * @return array + */ + public function listTables() + { + $this->_connect(); + $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + return $this->fetchCol($sql); + } + + /** + * Returns the column descriptions for a table. + * + * The return value is an associative array keyed by the column name, + * as returned by the RDBMS. + * + * The value of each array element is an associative array + * with the following keys: + * + * SCHEMA_NAME => string; name of schema + * TABLE_NAME => string; + * COLUMN_NAME => string; column name + * COLUMN_POSITION => number; ordinal position of column in table + * DATA_TYPE => string; SQL datatype name of column + * DEFAULT => string; default expression of column, null if none + * NULLABLE => boolean; true if column can have nulls + * LENGTH => number; length of CHAR/VARCHAR + * SCALE => number; scale of NUMERIC/DECIMAL + * PRECISION => number; precision of NUMERIC/DECIMAL + * UNSIGNED => boolean; unsigned property of an integer type + * PRIMARY => boolean; true if column is part of the primary key + * PRIMARY_POSITION => integer; position of column in primary key + * IDENTITY => integer; true if column is auto-generated with unique values + * + * @todo Discover integer unsigned property. + * + * @param string $tableName + * @param string $schemaName OPTIONAL + * @return array + */ + public function describeTable($tableName, $schemaName = null) + { + /** + * Discover metadata information about this table. + */ + $sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true); + $stmt = $this->query($sql); + $result = $stmt->fetchAll(Zend_Db::FETCH_NUM); + + // ZF-7698 + $stmt->closeCursor(); + + if (count($result) == 0) { + return array(); + } + + $owner = 1; + $table_name = 2; + $column_name = 3; + $type_name = 5; + $precision = 6; + $length = 7; + $scale = 8; + $nullable = 10; + $column_def = 12; + $column_position = 16; + + /** + * Discover primary key column(s) for this table. + */ + $tableOwner = $result[0][$owner]; + $sql = "exec sp_pkeys @table_owner = " . $tableOwner + . ", @table_name = " . $this->quoteIdentifier($tableName, true); + $stmt = $this->query($sql); + + $primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM); + $primaryKeyColumn = array(); + + // Per http://msdn.microsoft.com/en-us/library/ms189813.aspx, + // results from sp_keys stored procedure are: + // 0=TABLE_QUALIFIER 1=TABLE_OWNER 2=TABLE_NAME 3=COLUMN_NAME 4=KEY_SEQ 5=PK_NAME + + $pkey_column_name = 3; + $pkey_key_seq = 4; + foreach ($primaryKeysResult as $pkeysRow) { + $primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq]; + } + + $desc = array(); + $p = 1; + foreach ($result as $key => $row) { + $identity = false; + $words = explode(' ', $row[$type_name], 2); + if (isset($words[0])) { + $type = $words[0]; + if (isset($words[1])) { + $identity = (bool) preg_match('/identity/', $words[1]); + } + } + + $isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn); + if ($isPrimary) { + $primaryPosition = $primaryKeyColumn[$row[$column_name]]; + } else { + $primaryPosition = null; + } + + $desc[$this->foldCase($row[$column_name])] = array( + 'SCHEMA_NAME' => null, // @todo + 'TABLE_NAME' => $this->foldCase($row[$table_name]), + 'COLUMN_NAME' => $this->foldCase($row[$column_name]), + 'COLUMN_POSITION' => (int) $row[$column_position], + 'DATA_TYPE' => $type, + 'DEFAULT' => $row[$column_def], + 'NULLABLE' => (bool) $row[$nullable], + 'LENGTH' => $row[$length], + 'SCALE' => $row[$scale], + 'PRECISION' => $row[$precision], + 'UNSIGNED' => null, // @todo + 'PRIMARY' => $isPrimary, + 'PRIMARY_POSITION' => $primaryPosition, + 'IDENTITY' => $identity, + ); + } + + return $desc; + } + + /** + * Leave autocommit mode and begin a transaction. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _beginTransaction() + { + if (!sqlsrv_begin_transaction($this->_connection)) { + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Commit a transaction and return to autocommit mode. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _commit() + { + if (!sqlsrv_commit($this->_connection)) { + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Roll back a transaction and return to autocommit mode. + * + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + protected function _rollBack() + { + if (!sqlsrv_rollback($this->_connection)) { + throw new Zend_Db_Adapter_Sqlsrv_Exception(sqlsrv_errors()); + } + } + + /** + * Set the fetch mode. + * + * @todo Support FETCH_CLASS and FETCH_INTO. + * + * @param integer $mode A fetch mode. + * @return void + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_NUM: // seq array + case Zend_Db::FETCH_ASSOC: // assoc array + case Zend_Db::FETCH_BOTH: // seq+assoc array + case Zend_Db::FETCH_OBJ: // object + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: // bound to PHP variable + throw new Zend_Db_Adapter_Sqlsrv_Exception('FETCH_BOUND is not supported yet'); + break; + default: + throw new Zend_Db_Adapter_Sqlsrv_Exception("Invalid fetch mode '$mode' specified"); + break; + } + } + + /** + * Adds an adapter-specific LIMIT clause to the SELECT statement. + * + * @param string $sql + * @param integer $count + * @param integer $offset OPTIONAL + * @return string + * @throws Zend_Db_Adapter_Sqlsrv_Exception + */ + public function limit($sql, $count, $offset = 0) + { + $count = intval($count); + if ($count <= 0) { + throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid"); + } + + $offset = intval($offset); + if ($offset < 0) { + /** @see Zend_Db_Adapter_Exception */ + throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid"); + } + + if ($offset == 0) { + $sql = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . $count . ' ', $sql); + } else { + $orderby = stristr($sql, 'ORDER BY'); + + if (!$orderby) { + $over = 'ORDER BY (SELECT 0)'; + } else { + $over = preg_replace('/\"[^,]*\".\"([^,]*)\"/i', '"inner_tbl"."$1"', $orderby); + } + + // Remove ORDER BY clause from $sql + $sql = preg_replace('/\s+ORDER BY(.*)/', '', $sql); + + // Add ORDER BY clause as an argument for ROW_NUMBER() + $sql = "SELECT ROW_NUMBER() OVER ($over) AS \"ZEND_DB_ROWNUM\", * FROM ($sql) AS inner_tbl"; + + $start = $offset + 1; + + if ($count == PHP_INT_MAX) { + $sql = "WITH outer_tbl AS ($sql) SELECT * FROM outer_tbl WHERE \"ZEND_DB_ROWNUM\" >= $start"; + } + else { + $end = $offset + $count; + $sql = "WITH outer_tbl AS ($sql) SELECT * FROM outer_tbl WHERE \"ZEND_DB_ROWNUM\" BETWEEN $start AND $end"; + } + } + + return $sql; + } + + /** + * Check if the adapter supports real SQL parameters. + * + * @param string $type 'positional' or 'named' + * @return bool + */ + public function supportsParameters($type) + { + if ($type == 'positional') { + return true; + } + + // if its 'named' or anything else + return false; + } + + /** + * Retrieve server version in PHP style + * + * @return string + */ + public function getServerVersion() + { + $this->_connect(); + $serverInfo = sqlsrv_server_info($this->_connection); + + if ($serverInfo !== false) { + return $serverInfo['SQLServerVersion']; + } + + return null; + } +} diff --git a/library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php b/library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php new file mode 100644 index 000000000..803199825 --- /dev/null +++ b/library/vendor/Zend/Db/Adapter/Sqlsrv/Exception.php @@ -0,0 +1,62 @@ +_expression = (string) $expression; + } + + /** + * @return string The string of the SQL expression stored in this object. + */ + public function __toString() + { + return $this->_expression; + } + +} diff --git a/library/vendor/Zend/Db/Profiler.php b/library/vendor/Zend/Db/Profiler.php new file mode 100644 index 000000000..d7fe10400 --- /dev/null +++ b/library/vendor/Zend/Db/Profiler.php @@ -0,0 +1,469 @@ +setEnabled($enabled); + } + + /** + * Enable or disable the profiler. If $enable is false, the profiler + * is disabled and will not log any queries sent to it. + * + * @param boolean $enable + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setEnabled($enable) + { + $this->_enabled = (boolean) $enable; + + return $this; + } + + /** + * Get the current state of enable. If True is returned, + * the profiler is enabled. + * + * @return boolean + */ + public function getEnabled() + { + return $this->_enabled; + } + + /** + * Sets a minimum number of seconds for saving query profiles. If this + * is set, only those queries whose elapsed time is equal or greater than + * $minimumSeconds will be saved. To save all queries regardless of + * elapsed time, set $minimumSeconds to null. + * + * @param integer $minimumSeconds OPTIONAL + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setFilterElapsedSecs($minimumSeconds = null) + { + if (null === $minimumSeconds) { + $this->_filterElapsedSecs = null; + } else { + $this->_filterElapsedSecs = (integer) $minimumSeconds; + } + + return $this; + } + + /** + * Returns the minimum number of seconds for saving query profiles, or null if + * query profiles are saved regardless of elapsed time. + * + * @return integer|null + */ + public function getFilterElapsedSecs() + { + return $this->_filterElapsedSecs; + } + + /** + * Sets the types of query profiles to save. Set $queryType to one of + * the Zend_Db_Profiler::* constants to only save profiles for that type of + * query. To save more than one type, logical OR them together. To + * save all queries regardless of type, set $queryType to null. + * + * @param integer $queryTypes OPTIONAL + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setFilterQueryType($queryTypes = null) + { + $this->_filterTypes = $queryTypes; + + return $this; + } + + /** + * Returns the types of query profiles saved, or null if queries are saved regardless + * of their types. + * + * @return integer|null + * @see Zend_Db_Profiler::setFilterQueryType() + */ + public function getFilterQueryType() + { + return $this->_filterTypes; + } + + /** + * Clears the history of any past query profiles. This is relentless + * and will even clear queries that were started and may not have + * been marked as ended. + * + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function clear() + { + $this->_queryProfiles = array(); + + return $this; + } + + /** + * Clone a profiler query + * + * @param Zend_Db_Profiler_Query $query + * @return integer or null + */ + public function queryClone(Zend_Db_Profiler_Query $query) + { + $this->_queryProfiles[] = clone $query; + + end($this->_queryProfiles); + + return key($this->_queryProfiles); + } + + /** + * Starts a query. Creates a new query profile object (Zend_Db_Profiler_Query) + * and returns the "query profiler handle". Run the query, then call + * queryEnd() and pass it this handle to make the query as ended and + * record the time. If the profiler is not enabled, this takes no + * action and immediately returns null. + * + * @param string $queryText SQL statement + * @param integer $queryType OPTIONAL Type of query, one of the Zend_Db_Profiler::* constants + * @return integer|null + */ + public function queryStart($queryText, $queryType = null) + { + if (!$this->_enabled) { + return null; + } + + // make sure we have a query type + if (null === $queryType) { + switch (strtolower(substr(ltrim($queryText), 0, 6))) { + case 'insert': + $queryType = self::INSERT; + break; + case 'update': + $queryType = self::UPDATE; + break; + case 'delete': + $queryType = self::DELETE; + break; + case 'select': + $queryType = self::SELECT; + break; + default: + $queryType = self::QUERY; + break; + } + } + + /** + * @see Zend_Db_Profiler_Query + */ + $this->_queryProfiles[] = new Zend_Db_Profiler_Query($queryText, $queryType); + + end($this->_queryProfiles); + + return key($this->_queryProfiles); + } + + /** + * Ends a query. Pass it the handle that was returned by queryStart(). + * This will mark the query as ended and save the time. + * + * @param integer $queryId + * @throws Zend_Db_Profiler_Exception + * @return string Inform that a query is stored or ignored. + */ + public function queryEnd($queryId) + { + // Don't do anything if the Zend_Db_Profiler is not enabled. + if (!$this->_enabled) { + return self::IGNORED; + } + + // Check for a valid query handle. + if (!isset($this->_queryProfiles[$queryId])) { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception("Profiler has no query with handle '$queryId'."); + } + + $qp = $this->_queryProfiles[$queryId]; + + // Ensure that the query profile has not already ended + if ($qp->hasEnded()) { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception("Query with profiler handle '$queryId' has already ended."); + } + + // End the query profile so that the elapsed time can be calculated. + $qp->end(); + + /** + * If filtering by elapsed time is enabled, only keep the profile if + * it ran for the minimum time. + */ + if (null !== $this->_filterElapsedSecs && $qp->getElapsedSecs() < $this->_filterElapsedSecs) { + unset($this->_queryProfiles[$queryId]); + return self::IGNORED; + } + + /** + * If filtering by query type is enabled, only keep the query if + * it was one of the allowed types. + */ + if (null !== $this->_filterTypes && !($qp->getQueryType() & $this->_filterTypes)) { + unset($this->_queryProfiles[$queryId]); + return self::IGNORED; + } + + return self::STORED; + } + + /** + * Get a profile for a query. Pass it the same handle that was returned + * by queryStart() and it will return a Zend_Db_Profiler_Query object. + * + * @param integer $queryId + * @throws Zend_Db_Profiler_Exception + * @return Zend_Db_Profiler_Query + */ + public function getQueryProfile($queryId) + { + if (!array_key_exists($queryId, $this->_queryProfiles)) { + /** + * @see Zend_Db_Profiler_Exception + */ + throw new Zend_Db_Profiler_Exception("Query handle '$queryId' not found in profiler log."); + } + + return $this->_queryProfiles[$queryId]; + } + + /** + * Get an array of query profiles (Zend_Db_Profiler_Query objects). If $queryType + * is set to one of the Zend_Db_Profiler::* constants then only queries of that + * type will be returned. Normally, queries that have not yet ended will + * not be returned unless $showUnfinished is set to True. If no + * queries were found, False is returned. The returned array is indexed by the query + * profile handles. + * + * @param integer $queryType + * @param boolean $showUnfinished + * @return array|false + */ + public function getQueryProfiles($queryType = null, $showUnfinished = false) + { + $queryProfiles = array(); + foreach ($this->_queryProfiles as $key => $qp) { + if ($queryType === null) { + $condition = true; + } else { + $condition = ($qp->getQueryType() & $queryType); + } + + if (($qp->hasEnded() || $showUnfinished) && $condition) { + $queryProfiles[$key] = $qp; + } + } + + if (empty($queryProfiles)) { + $queryProfiles = false; + } + + return $queryProfiles; + } + + /** + * Get the total elapsed time (in seconds) of all of the profiled queries. + * Only queries that have ended will be counted. If $queryType is set to + * one or more of the Zend_Db_Profiler::* constants, the elapsed time will be calculated + * only for queries of the given type(s). + * + * @param integer $queryType OPTIONAL + * @return float + */ + public function getTotalElapsedSecs($queryType = null) + { + $elapsedSecs = 0; + foreach ($this->_queryProfiles as $key => $qp) { + if (null === $queryType) { + $condition = true; + } else { + $condition = ($qp->getQueryType() & $queryType); + } + if (($qp->hasEnded()) && $condition) { + $elapsedSecs += $qp->getElapsedSecs(); + } + } + return $elapsedSecs; + } + + /** + * Get the total number of queries that have been profiled. Only queries that have ended will + * be counted. If $queryType is set to one of the Zend_Db_Profiler::* constants, only queries of + * that type will be counted. + * + * @param integer $queryType OPTIONAL + * @return integer + */ + public function getTotalNumQueries($queryType = null) + { + if (null === $queryType) { + return count($this->_queryProfiles); + } + + $numQueries = 0; + foreach ($this->_queryProfiles as $qp) { + if ($qp->hasEnded() && ($qp->getQueryType() & $queryType)) { + $numQueries++; + } + } + + return $numQueries; + } + + /** + * Get the Zend_Db_Profiler_Query object for the last query that was run, regardless if it has + * ended or not. If the query has not ended, its end time will be null. If no queries have + * been profiled, false is returned. + * + * @return Zend_Db_Profiler_Query|false + */ + public function getLastQueryProfile() + { + if (empty($this->_queryProfiles)) { + return false; + } + + end($this->_queryProfiles); + + return current($this->_queryProfiles); + } + +} + diff --git a/library/vendor/Zend/Db/Profiler/Exception.php b/library/vendor/Zend/Db/Profiler/Exception.php new file mode 100644 index 000000000..4a3217b8e --- /dev/null +++ b/library/vendor/Zend/Db/Profiler/Exception.php @@ -0,0 +1,39 @@ +_label = $label; + if(!$this->_label) { + $this->_label = 'Zend_Db_Profiler_Firebug'; + } + } + + /** + * Enable or disable the profiler. If $enable is false, the profiler + * is disabled and will not log any queries sent to it. + * + * @param boolean $enable + * @return Zend_Db_Profiler Provides a fluent interface + */ + public function setEnabled($enable) + { + parent::setEnabled($enable); + + if ($this->getEnabled()) { + + if (!$this->_message) { + $this->_message = new Zend_Wildfire_Plugin_FirePhp_TableMessage($this->_label); + $this->_message->setBuffered(true); + $this->_message->setHeader(array('Time','Event','Parameters')); + $this->_message->setDestroy(true); + $this->_message->setOption('includeLineNumbers', false); + Zend_Wildfire_Plugin_FirePhp::getInstance()->send($this->_message); + } + + } else { + + if ($this->_message) { + $this->_message->setDestroy(true); + $this->_message = null; + } + + } + + return $this; + } + + /** + * Intercept the query end and log the profiling data. + * + * @param integer $queryId + * @throws Zend_Db_Profiler_Exception + * @return void + */ + public function queryEnd($queryId) + { + $state = parent::queryEnd($queryId); + + if (!$this->getEnabled() || $state == self::IGNORED) { + return; + } + + $this->_message->setDestroy(false); + + $profile = $this->getQueryProfile($queryId); + + $this->_totalElapsedTime += $profile->getElapsedSecs(); + + $this->_message->addRow(array((string)round($profile->getElapsedSecs(),5), + $profile->getQuery(), + ($params=$profile->getQueryParams())?$params:null)); + + $this->updateMessageLabel(); + } + + /** + * Update the label of the message holding the profile info. + * + * @return void + */ + protected function updateMessageLabel() + { + if (!$this->_message) { + return; + } + $this->_message->setLabel(str_replace(array('%label%', + '%totalCount%', + '%totalDuration%'), + array($this->_label, + $this->getTotalNumQueries(), + (string)round($this->_totalElapsedTime,5)), + $this->_label_template)); + } +} diff --git a/library/vendor/Zend/Db/Profiler/Query.php b/library/vendor/Zend/Db/Profiler/Query.php new file mode 100644 index 000000000..a41cb7066 --- /dev/null +++ b/library/vendor/Zend/Db/Profiler/Query.php @@ -0,0 +1,213 @@ +_query = $query; + $this->_queryType = $queryType; + // by default, and for backward-compatibility, start the click ticking + $this->start(); + } + + /** + * Clone handler for the query object. + * @return void + */ + public function __clone() + { + $this->_boundParams = array(); + $this->_endedMicrotime = null; + $this->start(); + } + + /** + * Starts the elapsed time click ticking. + * This can be called subsequent to object creation, + * to restart the clock. For instance, this is useful + * right before executing a prepared query. + * + * @return void + */ + public function start() + { + $this->_startedMicrotime = microtime(true); + } + + /** + * Ends the query and records the time so that the elapsed time can be determined later. + * + * @return void + */ + public function end() + { + $this->_endedMicrotime = microtime(true); + } + + /** + * Returns true if and only if the query has ended. + * + * @return boolean + */ + public function hasEnded() + { + return $this->_endedMicrotime !== null; + } + + /** + * Get the original SQL text of the query. + * + * @return string + */ + public function getQuery() + { + return $this->_query; + } + + /** + * Get the type of this query (one of the Zend_Db_Profiler::* constants) + * + * @return integer + */ + public function getQueryType() + { + return $this->_queryType; + } + + /** + * @param string $param + * @param mixed $variable + * @return void + */ + public function bindParam($param, $variable) + { + $this->_boundParams[$param] = $variable; + } + + /** + * @param array $param + * @return void + */ + public function bindParams(array $params) + { + if (array_key_exists(0, $params)) { + array_unshift($params, null); + unset($params[0]); + } + foreach ($params as $param => $value) { + $this->bindParam($param, $value); + } + } + + /** + * @return array + */ + public function getQueryParams() + { + return $this->_boundParams; + } + + /** + * Get the elapsed time (in seconds) that the query ran. + * If the query has not yet ended, false is returned. + * + * @return float|false + */ + public function getElapsedSecs() + { + if (null === $this->_endedMicrotime) { + return false; + } + + return $this->_endedMicrotime - $this->_startedMicrotime; + } + + /** + * Get the time (in seconds) when the profiler started running. + * + * @return bool|float + */ + public function getStartedMicrotime() + { + if(null === $this->_startedMicrotime) { + return false; + } + + return $this->_startedMicrotime; + } +} + diff --git a/library/vendor/Zend/Db/Select.php b/library/vendor/Zend/Db/Select.php new file mode 100644 index 000000000..d6ca37f55 --- /dev/null +++ b/library/vendor/Zend/Db/Select.php @@ -0,0 +1,1342 @@ + false, + self::COLUMNS => array(), + self::UNION => array(), + self::FROM => array(), + self::WHERE => array(), + self::GROUP => array(), + self::HAVING => array(), + self::ORDER => array(), + self::LIMIT_COUNT => null, + self::LIMIT_OFFSET => null, + self::FOR_UPDATE => false + ); + + /** + * Specify legal join types. + * + * @var array + */ + protected static $_joinTypes = array( + self::INNER_JOIN, + self::LEFT_JOIN, + self::RIGHT_JOIN, + self::FULL_JOIN, + self::CROSS_JOIN, + self::NATURAL_JOIN, + ); + + /** + * Specify legal union types. + * + * @var array + */ + protected static $_unionTypes = array( + self::SQL_UNION, + self::SQL_UNION_ALL + ); + + /** + * The component parts of a SELECT statement. + * Initialized to the $_partsInit array in the constructor. + * + * @var array + */ + protected $_parts = array(); + + /** + * Tracks which columns are being select from each table and join. + * + * @var array + */ + protected $_tableCols = array(); + + /** + * Class constructor + * + * @param Zend_Db_Adapter_Abstract $adapter + */ + public function __construct(Zend_Db_Adapter_Abstract $adapter) + { + $this->_adapter = $adapter; + $this->_parts = self::$_partsInit; + } + + /** + * Get bind variables + * + * @return array + */ + public function getBind() + { + return $this->_bind; + } + + /** + * Set bind variables + * + * @param mixed $bind + * @return Zend_Db_Select + */ + public function bind($bind) + { + $this->_bind = $bind; + + return $this; + } + + /** + * Makes the query SELECT DISTINCT. + * + * @param bool $flag Whether or not the SELECT is DISTINCT (default true). + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function distinct($flag = true) + { + $this->_parts[self::DISTINCT] = (bool) $flag; + return $this; + } + + /** + * Adds a FROM table and optional columns to the query. + * + * The first parameter $name can be a simple string, in which case the + * correlation name is generated automatically. If you want to specify + * the correlation name, the first parameter must be an associative + * array in which the key is the correlation name, and the value is + * the physical table name. For example, array('alias' => 'table'). + * The correlation name is prepended to all columns fetched for this + * table. + * + * The second parameter can be a single string or Zend_Db_Expr object, + * or else an array of strings or Zend_Db_Expr objects. + * + * The first parameter can be null or an empty string, in which case + * no correlation name is generated or prepended to the columns named + * in the second parameter. + * + * @param array|string|Zend_Db_Expr $name The table name or an associative array + * relating correlation name to table name. + * @param array|string|Zend_Db_Expr $cols The columns to select from this table. + * @param string $schema The schema name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function from($name, $cols = '*', $schema = null) + { + return $this->_join(self::FROM, $name, null, $cols, $schema); + } + + /** + * Specifies the columns used in the FROM clause. + * + * The parameter can be a single string or Zend_Db_Expr object, + * or else an array of strings or Zend_Db_Expr objects. + * + * @param array|string|Zend_Db_Expr $cols The columns to select from this table. + * @param string $correlationName Correlation name of target table. OPTIONAL + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function columns($cols = '*', $correlationName = null) + { + if ($correlationName === null && count($this->_parts[self::FROM])) { + $correlationNameKeys = array_keys($this->_parts[self::FROM]); + $correlationName = current($correlationNameKeys); + } + + if (!array_key_exists($correlationName, $this->_parts[self::FROM])) { + /** + * @see Zend_Db_Select_Exception + */ + throw new Zend_Db_Select_Exception("No table has been specified for the FROM clause"); + } + + $this->_tableCols($correlationName, $cols); + + return $this; + } + + /** + * Adds a UNION clause to the query. + * + * The first parameter has to be an array of Zend_Db_Select or + * sql query strings. + * + * + * $sql1 = $db->select(); + * $sql2 = "SELECT ..."; + * $select = $db->select() + * ->union(array($sql1, $sql2)) + * ->order("id"); + * + * + * @param array $select Array of select clauses for the union. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function union($select = array(), $type = self::SQL_UNION) + { + if (!is_array($select)) { + throw new Zend_Db_Select_Exception( + "union() only accepts an array of Zend_Db_Select instances of sql query strings." + ); + } + + if (!in_array($type, self::$_unionTypes)) { + throw new Zend_Db_Select_Exception("Invalid union type '{$type}'"); + } + + foreach ($select as $target) { + $this->_parts[self::UNION][] = array($target, $type); + } + + return $this; + } + + /** + * Adds a JOIN table and columns to the query. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function join($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->joinInner($name, $cond, $cols, $schema); + } + + /** + * Add an INNER JOIN table and colums to the query + * Rows in both tables are matched according to the expression + * in the $cond argument. The result set is comprised + * of all cases where rows from the left table match + * rows from the right table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinInner($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::INNER_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a LEFT OUTER JOIN table and colums to the query + * All rows from the left operand table are included, + * matching rows from the right operand table included, + * and the columns from the right operand table are filled + * with NULLs if no row exists matching the left table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinLeft($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::LEFT_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a RIGHT OUTER JOIN table and colums to the query. + * Right outer join is the complement of left outer join. + * All rows from the right operand table are included, + * matching rows from the left operand table included, + * and the columns from the left operand table are filled + * with NULLs if no row exists matching the right table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinRight($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::RIGHT_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a FULL OUTER JOIN table and colums to the query. + * A full outer join is like combining a left outer join + * and a right outer join. All rows from both tables are + * included, paired with each other on the same row of the + * result set if they satisfy the join condition, and otherwise + * paired with NULLs in place of columns from the other table. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param string $cond Join on this condition. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinFull($name, $cond, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::FULL_JOIN, $name, $cond, $cols, $schema); + } + + /** + * Add a CROSS JOIN table and colums to the query. + * A cross join is a cartesian product; there is no join condition. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinCross($name, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::CROSS_JOIN, $name, null, $cols, $schema); + } + + /** + * Add a NATURAL JOIN table and colums to the query. + * A natural join assumes an equi-join across any column(s) + * that appear with the same name in both tables. + * Only natural inner joins are supported by this API, + * even though SQL permits natural outer joins as well. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param array|string|Zend_Db_Expr $name The table name. + * @param array|string $cols The columns to select from the joined table. + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function joinNatural($name, $cols = self::SQL_WILDCARD, $schema = null) + { + return $this->_join(self::NATURAL_JOIN, $name, null, $cols, $schema); + } + + /** + * Adds a WHERE condition to the query by AND. + * + * If a value is passed as the second param, it will be quoted + * and replaced into the condition wherever a question-mark + * appears. Array values are quoted and comma-separated. + * + * + * // simplest but non-secure + * $select->where("id = $id"); + * + * // secure (ID is quoted but matched anyway) + * $select->where('id = ?', $id); + * + * // alternatively, with named binding + * $select->where('id = :id'); + * + * + * Note that it is more correct to use named bindings in your + * queries for values other than strings. When you use named + * bindings, don't forget to pass the values when actually + * making a query: + * + * + * $db->fetchAll($select, array('id' => 5)); + * + * + * @param string $cond The WHERE condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function where($cond, $value = null, $type = null) + { + $this->_parts[self::WHERE][] = $this->_where($cond, $value, $type, true); + + return $this; + } + + /** + * Adds a WHERE condition to the query by OR. + * + * Otherwise identical to where(). + * + * @param string $cond The WHERE condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + * + * @see where() + */ + public function orWhere($cond, $value = null, $type = null) + { + $this->_parts[self::WHERE][] = $this->_where($cond, $value, $type, false); + + return $this; + } + + /** + * Adds grouping to the query. + * + * @param array|string $spec The column(s) to group by. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function group($spec) + { + if (!is_array($spec)) { + $spec = array($spec); + } + + foreach ($spec as $val) { + if (preg_match('/^[\w]*\([^\)]*\)$/', (string) $val)) { + $val = new Zend_Db_Expr($val); + } + $this->_parts[self::GROUP][] = $val; + } + + return $this; + } + + /** + * Adds a HAVING condition to the query by AND. + * + * If a value is passed as the second param, it will be quoted + * and replaced into the condition wherever a question-mark + * appears. See {@link where()} for an example + * + * @param string $cond The HAVING condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function having($cond, $value = null, $type = null) + { + if ($value !== null) { + $cond = $this->_adapter->quoteInto($cond, $value, $type); + } + + if ($this->_parts[self::HAVING]) { + $this->_parts[self::HAVING][] = self::SQL_AND . " ($cond)"; + } else { + $this->_parts[self::HAVING][] = "($cond)"; + } + + return $this; + } + + /** + * Adds a HAVING condition to the query by OR. + * + * Otherwise identical to orHaving(). + * + * @param string $cond The HAVING condition. + * @param mixed $value OPTIONAL The value to quote into the condition. + * @param int $type OPTIONAL The type of the given value + * @return Zend_Db_Select This Zend_Db_Select object. + * + * @see having() + */ + public function orHaving($cond, $value = null, $type = null) + { + if ($value !== null) { + $cond = $this->_adapter->quoteInto($cond, $value, $type); + } + + if ($this->_parts[self::HAVING]) { + $this->_parts[self::HAVING][] = self::SQL_OR . " ($cond)"; + } else { + $this->_parts[self::HAVING][] = "($cond)"; + } + + return $this; + } + + /** + * Adds a row order to the query. + * + * @param mixed $spec The column(s) and direction to order by. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function order($spec) + { + if (!is_array($spec)) { + $spec = array($spec); + } + + // force 'ASC' or 'DESC' on each order spec, default is ASC. + foreach ($spec as $val) { + if ($val instanceof Zend_Db_Expr) { + $expr = $val->__toString(); + if (empty($expr)) { + continue; + } + $this->_parts[self::ORDER][] = $val; + } else { + if (empty($val)) { + continue; + } + $direction = self::SQL_ASC; + if (preg_match('/(.*\W)(' . self::SQL_ASC . '|' . self::SQL_DESC . ')\b/si', $val, $matches)) { + $val = trim($matches[1]); + $direction = $matches[2]; + } + if (preg_match('/^[\w]*\([^\)]*\)$/', $val)) { + $val = new Zend_Db_Expr($val); + } + $this->_parts[self::ORDER][] = array($val, $direction); + } + } + + return $this; + } + + /** + * Sets a limit count and offset to the query. + * + * @param int $count OPTIONAL The number of rows to return. + * @param int $offset OPTIONAL Start returning after this many rows. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function limit($count = null, $offset = null) + { + $this->_parts[self::LIMIT_COUNT] = (int) $count; + $this->_parts[self::LIMIT_OFFSET] = (int) $offset; + return $this; + } + + /** + * Sets the limit and count by page number. + * + * @param int $page Limit results to this page number. + * @param int $rowCount Use this many rows per page. + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function limitPage($page, $rowCount) + { + $page = ($page > 0) ? $page : 1; + $rowCount = ($rowCount > 0) ? $rowCount : 1; + $this->_parts[self::LIMIT_COUNT] = (int) $rowCount; + $this->_parts[self::LIMIT_OFFSET] = (int) $rowCount * ($page - 1); + return $this; + } + + /** + * Makes the query SELECT FOR UPDATE. + * + * @param bool $flag Whether or not the SELECT is FOR UPDATE (default true). + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function forUpdate($flag = true) + { + $this->_parts[self::FOR_UPDATE] = (bool) $flag; + return $this; + } + + /** + * Get part of the structured information for the current query. + * + * @param string $part + * @return mixed + * @throws Zend_Db_Select_Exception + */ + public function getPart($part) + { + $part = strtolower($part); + if (!array_key_exists($part, $this->_parts)) { + throw new Zend_Db_Select_Exception("Invalid Select part '$part'"); + } + return $this->_parts[$part]; + } + + /** + * Executes the current select object and returns the result + * + * @param integer $fetchMode OPTIONAL + * @param mixed $bind An array of data to bind to the placeholders. + * @return PDO_Statement|Zend_Db_Statement + */ + public function query($fetchMode = null, $bind = array()) + { + if (!empty($bind)) { + $this->bind($bind); + } + + $stmt = $this->_adapter->query($this); + if ($fetchMode == null) { + $fetchMode = $this->_adapter->getFetchMode(); + } + $stmt->setFetchMode($fetchMode); + return $stmt; + } + + /** + * Converts this object to an SQL SELECT string. + * + * @return string|null This object as a SELECT string. (or null if a string cannot be produced.) + */ + public function assemble() + { + $sql = self::SQL_SELECT; + foreach (array_keys(self::$_partsInit) as $part) { + $method = '_render' . ucfirst($part); + if (method_exists($this, $method)) { + $sql = $this->$method($sql); + } + } + return $sql; + } + + /** + * Clear parts of the Select object, or an individual part. + * + * @param string $part OPTIONAL + * @return Zend_Db_Select + */ + public function reset($part = null) + { + if ($part == null) { + $this->_parts = self::$_partsInit; + } elseif (array_key_exists($part, self::$_partsInit)) { + $this->_parts[$part] = self::$_partsInit[$part]; + } + return $this; + } + + /** + * Gets the Zend_Db_Adapter_Abstract for this + * particular Zend_Db_Select object. + * + * @return Zend_Db_Adapter_Abstract + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Populate the {@link $_parts} 'join' key + * + * Does the dirty work of populating the join key. + * + * The $name and $cols parameters follow the same logic + * as described in the from() method. + * + * @param null|string $type Type of join; inner, left, and null are currently supported + * @param array|string|Zend_Db_Expr $name Table name + * @param string $cond Join on this condition + * @param array|string $cols The columns to select from the joined table + * @param string $schema The database name to specify, if any. + * @return Zend_Db_Select This Zend_Db_Select object + * @throws Zend_Db_Select_Exception + */ + protected function _join($type, $name, $cond, $cols, $schema = null) + { + if (!in_array($type, self::$_joinTypes) && $type != self::FROM) { + /** + * @see Zend_Db_Select_Exception + */ + throw new Zend_Db_Select_Exception("Invalid join type '$type'"); + } + + if (count($this->_parts[self::UNION])) { + throw new Zend_Db_Select_Exception("Invalid use of table with " . self::SQL_UNION); + } + + if (empty($name)) { + $correlationName = $tableName = ''; + } elseif (is_array($name)) { + // Must be array($correlationName => $tableName) or array($ident, ...) + foreach ($name as $_correlationName => $_tableName) { + if (is_string($_correlationName)) { + // We assume the key is the correlation name and value is the table name + $tableName = $_tableName; + $correlationName = $_correlationName; + } else { + // We assume just an array of identifiers, with no correlation name + $tableName = $_tableName; + $correlationName = $this->_uniqueCorrelation($tableName); + } + break; + } + } elseif ($name instanceof Zend_Db_Expr|| $name instanceof Zend_Db_Select) { + $tableName = $name; + $correlationName = $this->_uniqueCorrelation('t'); + } elseif (preg_match('/^(.+)\s+AS\s+(.+)$/i', $name, $m)) { + $tableName = $m[1]; + $correlationName = $m[2]; + } else { + $tableName = $name; + $correlationName = $this->_uniqueCorrelation($tableName); + } + + // Schema from table name overrides schema argument + if (!is_object($tableName) && false !== strpos($tableName, '.')) { + list($schema, $tableName) = explode('.', $tableName); + } + + $lastFromCorrelationName = null; + if (!empty($correlationName)) { + if (array_key_exists($correlationName, $this->_parts[self::FROM])) { + /** + * @see Zend_Db_Select_Exception + */ + throw new Zend_Db_Select_Exception("You cannot define a correlation name '$correlationName' more than once"); + } + + if ($type == self::FROM) { + // append this from after the last from joinType + $tmpFromParts = $this->_parts[self::FROM]; + $this->_parts[self::FROM] = array(); + // move all the froms onto the stack + while ($tmpFromParts) { + $currentCorrelationName = key($tmpFromParts); + if ($tmpFromParts[$currentCorrelationName]['joinType'] != self::FROM) { + break; + } + $lastFromCorrelationName = $currentCorrelationName; + $this->_parts[self::FROM][$currentCorrelationName] = array_shift($tmpFromParts); + } + } else { + $tmpFromParts = array(); + } + $this->_parts[self::FROM][$correlationName] = array( + 'joinType' => $type, + 'schema' => $schema, + 'tableName' => $tableName, + 'joinCondition' => $cond + ); + while ($tmpFromParts) { + $currentCorrelationName = key($tmpFromParts); + $this->_parts[self::FROM][$currentCorrelationName] = array_shift($tmpFromParts); + } + } + + // add to the columns from this joined table + if ($type == self::FROM && $lastFromCorrelationName == null) { + $lastFromCorrelationName = true; + } + $this->_tableCols($correlationName, $cols, $lastFromCorrelationName); + + return $this; + } + + /** + * Handle JOIN... USING... syntax + * + * This is functionality identical to the existing JOIN methods, however + * the join condition can be passed as a single column name. This method + * then completes the ON condition by using the same field for the FROM + * table and the JOIN table. + * + * + * $select = $db->select()->from('table1') + * ->joinUsing('table2', 'column1'); + * + * // SELECT * FROM table1 JOIN table2 ON table1.column1 = table2.column2 + * + * + * These joins are called by the developer simply by adding 'Using' to the + * method name. E.g. + * * joinUsing + * * joinInnerUsing + * * joinFullUsing + * * joinRightUsing + * * joinLeftUsing + * + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function _joinUsing($type, $name, $cond, $cols = '*', $schema = null) + { + if (empty($this->_parts[self::FROM])) { + throw new Zend_Db_Select_Exception("You can only perform a joinUsing after specifying a FROM table"); + } + + $join = $this->_adapter->quoteIdentifier(key($this->_parts[self::FROM]), true); + $from = $this->_adapter->quoteIdentifier($this->_uniqueCorrelation($name), true); + + $joinCond = array(); + foreach ((array)$cond as $fieldName) { + $cond1 = $from . '.' . $fieldName; + $cond2 = $join . '.' . $fieldName; + $joinCond[] = $cond1 . ' = ' . $cond2; + } + $cond = implode(' '.self::SQL_AND.' ', $joinCond); + + return $this->_join($type, $name, $cond, $cols, $schema); + } + + /** + * Generate a unique correlation name + * + * @param string|array $name A qualified identifier. + * @return string A unique correlation name. + */ + private function _uniqueCorrelation($name) + { + if (is_array($name)) { + $k = key($name); + $c = is_string($k) ? $k : end($name); + } else { + // Extract just the last name of a qualified table name + $dot = strrpos($name,'.'); + $c = ($dot === false) ? $name : substr($name, $dot+1); + } + for ($i = 2; array_key_exists($c, $this->_parts[self::FROM]); ++$i) { + $c = $name . '_' . (string) $i; + } + return $c; + } + + /** + * Adds to the internal table-to-column mapping array. + * + * @param string $tbl The table/join the columns come from. + * @param array|string $cols The list of columns; preferably as + * an array, but possibly as a string containing one column. + * @param bool|string True if it should be prepended, a correlation name if it should be inserted + * @return void + */ + protected function _tableCols($correlationName, $cols, $afterCorrelationName = null) + { + if (!is_array($cols)) { + $cols = array($cols); + } + + if ($correlationName == null) { + $correlationName = ''; + } + + $columnValues = array(); + + foreach (array_filter($cols) as $alias => $col) { + $currentCorrelationName = $correlationName; + if (is_string($col)) { + // Check for a column matching " AS " and extract the alias name + if (preg_match('/^(.+)\s+' . self::SQL_AS . '\s+(.+)$/i', $col, $m)) { + $col = $m[1]; + $alias = $m[2]; + } + // Check for columns that look like functions and convert to Zend_Db_Expr + if (preg_match('/^[\w]*\([^\)]*\)$/', $col)) { + $col = new Zend_Db_Expr($col); + } elseif (preg_match('/(.+)\.(.+)/', $col, $m)) { + $currentCorrelationName = $m[1]; + $col = $m[2]; + } + } + $columnValues[] = array($currentCorrelationName, $col, is_string($alias) ? $alias : null); + } + + if ($columnValues) { + + // should we attempt to prepend or insert these values? + if ($afterCorrelationName === true || is_string($afterCorrelationName)) { + $tmpColumns = $this->_parts[self::COLUMNS]; + $this->_parts[self::COLUMNS] = array(); + } else { + $tmpColumns = array(); + } + + // find the correlation name to insert after + if (is_string($afterCorrelationName)) { + while ($tmpColumns) { + $this->_parts[self::COLUMNS][] = $currentColumn = array_shift($tmpColumns); + if ($currentColumn[0] == $afterCorrelationName) { + break; + } + } + } + + // apply current values to current stack + foreach ($columnValues as $columnValue) { + array_push($this->_parts[self::COLUMNS], $columnValue); + } + + // finish ensuring that all previous values are applied (if they exist) + while ($tmpColumns) { + array_push($this->_parts[self::COLUMNS], array_shift($tmpColumns)); + } + } + } + + /** + * Internal function for creating the where clause + * + * @param string $condition + * @param mixed $value optional + * @param string $type optional + * @param boolean $bool true = AND, false = OR + * @return string clause + */ + protected function _where($condition, $value = null, $type = null, $bool = true) + { + if (count($this->_parts[self::UNION])) { + throw new Zend_Db_Select_Exception("Invalid use of where clause with " . self::SQL_UNION); + } + + if ($value !== null) { + $condition = $this->_adapter->quoteInto($condition, $value, $type); + } + + $cond = ""; + if ($this->_parts[self::WHERE]) { + if ($bool === true) { + $cond = self::SQL_AND . ' '; + } else { + $cond = self::SQL_OR . ' '; + } + } + + return $cond . "($condition)"; + } + + /** + * @return array + */ + protected function _getDummyTable() + { + return array(); + } + + /** + * Return a quoted schema name + * + * @param string $schema The schema name OPTIONAL + * @return string|null + */ + protected function _getQuotedSchema($schema = null) + { + if ($schema === null) { + return null; + } + return $this->_adapter->quoteIdentifier($schema, true) . '.'; + } + + /** + * Return a quoted table name + * + * @param string $tableName The table name + * @param string $correlationName The correlation name OPTIONAL + * @return string + */ + protected function _getQuotedTable($tableName, $correlationName = null) + { + return $this->_adapter->quoteTableAs($tableName, $correlationName, true); + } + + /** + * Render DISTINCT clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderDistinct($sql) + { + if ($this->_parts[self::DISTINCT]) { + $sql .= ' ' . self::SQL_DISTINCT; + } + + return $sql; + } + + /** + * Render DISTINCT clause + * + * @param string $sql SQL query + * @return string|null + */ + protected function _renderColumns($sql) + { + if (!count($this->_parts[self::COLUMNS])) { + return null; + } + + $columns = array(); + foreach ($this->_parts[self::COLUMNS] as $columnEntry) { + list($correlationName, $column, $alias) = $columnEntry; + if ($column instanceof Zend_Db_Expr) { + $columns[] = $this->_adapter->quoteColumnAs($column, $alias, true); + } else { + if ($column == self::SQL_WILDCARD) { + $column = new Zend_Db_Expr(self::SQL_WILDCARD); + $alias = null; + } + if (empty($correlationName)) { + $columns[] = $this->_adapter->quoteColumnAs($column, $alias, true); + } else { + $columns[] = $this->_adapter->quoteColumnAs(array($correlationName, $column), $alias, true); + } + } + } + + return $sql .= ' ' . implode(', ', $columns); + } + + /** + * Render FROM clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderFrom($sql) + { + /* + * If no table specified, use RDBMS-dependent solution + * for table-less query. e.g. DUAL in Oracle. + */ + if (empty($this->_parts[self::FROM])) { + $this->_parts[self::FROM] = $this->_getDummyTable(); + } + + $from = array(); + + foreach ($this->_parts[self::FROM] as $correlationName => $table) { + $tmp = ''; + + $joinType = ($table['joinType'] == self::FROM) ? self::INNER_JOIN : $table['joinType']; + + // Add join clause (if applicable) + if (! empty($from)) { + $tmp .= ' ' . strtoupper($joinType) . ' '; + } + + $tmp .= $this->_getQuotedSchema($table['schema']); + $tmp .= $this->_getQuotedTable($table['tableName'], $correlationName); + + // Add join conditions (if applicable) + if (!empty($from) && ! empty($table['joinCondition'])) { + $tmp .= ' ' . self::SQL_ON . ' ' . $table['joinCondition']; + } + + // Add the table name and condition add to the list + $from[] = $tmp; + } + + // Add the list of all joins + if (!empty($from)) { + $sql .= ' ' . self::SQL_FROM . ' ' . implode("\n", $from); + } + + return $sql; + } + + /** + * Render UNION query + * + * @param string $sql SQL query + * @return string + */ + protected function _renderUnion($sql) + { + if ($this->_parts[self::UNION]) { + $parts = count($this->_parts[self::UNION]); + foreach ($this->_parts[self::UNION] as $cnt => $union) { + list($target, $type) = $union; + if ($target instanceof Zend_Db_Select) { + $target = $target->assemble(); + } + $sql .= $target; + if ($cnt < $parts - 1) { + $sql .= ' ' . $type . ' '; + } + } + } + + return $sql; + } + + /** + * Render WHERE clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderWhere($sql) + { + if ($this->_parts[self::FROM] && $this->_parts[self::WHERE]) { + $sql .= ' ' . self::SQL_WHERE . ' ' . implode(' ', $this->_parts[self::WHERE]); + } + + return $sql; + } + + /** + * Render GROUP clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderGroup($sql) + { + if ($this->_parts[self::FROM] && $this->_parts[self::GROUP]) { + $group = array(); + foreach ($this->_parts[self::GROUP] as $term) { + $group[] = $this->_adapter->quoteIdentifier($term, true); + } + $sql .= ' ' . self::SQL_GROUP_BY . ' ' . implode(",\n\t", $group); + } + + return $sql; + } + + /** + * Render HAVING clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderHaving($sql) + { + if ($this->_parts[self::FROM] && $this->_parts[self::HAVING]) { + $sql .= ' ' . self::SQL_HAVING . ' ' . implode(' ', $this->_parts[self::HAVING]); + } + + return $sql; + } + + /** + * Render ORDER clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderOrder($sql) + { + if ($this->_parts[self::ORDER]) { + $order = array(); + foreach ($this->_parts[self::ORDER] as $term) { + if (is_array($term)) { + if(is_numeric($term[0]) && strval(intval($term[0])) == $term[0]) { + $order[] = (int)trim($term[0]) . ' ' . $term[1]; + } else { + $order[] = $this->_adapter->quoteIdentifier($term[0], true) . ' ' . $term[1]; + } + } elseif (is_numeric($term) && strval(intval($term)) == $term) { + $order[] = (int)trim($term); + } else { + $order[] = $this->_adapter->quoteIdentifier($term, true); + } + } + $sql .= ' ' . self::SQL_ORDER_BY . ' ' . implode(', ', $order); + } + + return $sql; + } + + /** + * Render LIMIT OFFSET clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderLimitoffset($sql) + { + $count = 0; + $offset = 0; + + if (!empty($this->_parts[self::LIMIT_OFFSET])) { + $offset = (int) $this->_parts[self::LIMIT_OFFSET]; + $count = PHP_INT_MAX; + } + + if (!empty($this->_parts[self::LIMIT_COUNT])) { + $count = (int) $this->_parts[self::LIMIT_COUNT]; + } + + /* + * Add limits clause + */ + if ($count > 0) { + $sql = trim($this->_adapter->limit($sql, $count, $offset)); + } + + return $sql; + } + + /** + * Render FOR UPDATE clause + * + * @param string $sql SQL query + * @return string + */ + protected function _renderForupdate($sql) + { + if ($this->_parts[self::FOR_UPDATE]) { + $sql .= ' ' . self::SQL_FOR_UPDATE; + } + + return $sql; + } + + /** + * Turn magic function calls into non-magic function calls + * for joinUsing syntax + * + * @param string $method + * @param array $args OPTIONAL Zend_Db_Table_Select query modifier + * @return Zend_Db_Select + * @throws Zend_Db_Select_Exception If an invalid method is called. + */ + public function __call($method, array $args) + { + $matches = array(); + + /** + * Recognize methods for Has-Many cases: + * findParent() + * findParentBy() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^join([a-zA-Z]*?)Using$/', $method, $matches)) { + $type = strtolower($matches[1]); + if ($type) { + $type .= ' join'; + if (!in_array($type, self::$_joinTypes)) { + throw new Zend_Db_Select_Exception("Unrecognized method '$method()'"); + } + if (in_array($type, array(self::CROSS_JOIN, self::NATURAL_JOIN))) { + throw new Zend_Db_Select_Exception("Cannot perform a joinUsing with method '$method()'"); + } + } else { + $type = self::INNER_JOIN; + } + array_unshift($args, $type); + return call_user_func_array(array($this, '_joinUsing'), $args); + } + + throw new Zend_Db_Select_Exception("Unrecognized method '$method()'"); + } + + /** + * Implements magic method. + * + * @return string This object as a SELECT string. + */ + public function __toString() + { + try { + $sql = $this->assemble(); + } catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + $sql = ''; + } + return (string)$sql; + } + +} diff --git a/library/vendor/Zend/Db/Select/Exception.php b/library/vendor/Zend/Db/Select/Exception.php new file mode 100644 index 000000000..6c8b896f8 --- /dev/null +++ b/library/vendor/Zend/Db/Select/Exception.php @@ -0,0 +1,38 @@ +_adapter = $adapter; + if ($sql instanceof Zend_Db_Select) { + $sql = $sql->assemble(); + } + $this->_parseParameters($sql); + $this->_prepare($sql); + + $this->_queryId = $this->_adapter->getProfiler()->queryStart($sql); + } + + /** + * Internal method called by abstract statment constructor to setup + * the driver level statement + * + * @return void + */ + protected function _prepare($sql) + { + return; + } + + /** + * @param string $sql + * @return void + */ + protected function _parseParameters($sql) + { + $sql = $this->_stripQuoted($sql); + + // split into text and params + $this->_sqlSplit = preg_split('/(\?|\:[a-zA-Z0-9_]+)/', + $sql, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); + + // map params + $this->_sqlParam = array(); + foreach ($this->_sqlSplit as $key => $val) { + if ($val == '?') { + if ($this->_adapter->supportsParameters('positional') === false) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception("Invalid bind-variable position '$val'"); + } + } else if ($val[0] == ':') { + if ($this->_adapter->supportsParameters('named') === false) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception("Invalid bind-variable name '$val'"); + } + } + $this->_sqlParam[] = $val; + } + + // set up for binding + $this->_bindParam = array(); + } + + /** + * Remove parts of a SQL string that contain quoted strings + * of values or identifiers. + * + * @param string $sql + * @return string + */ + protected function _stripQuoted($sql) + { + + // get the character for value quoting + // this should be ' + $q = $this->_adapter->quote('a'); + $q = $q[0]; + // get the value used as an escaped quote, + // e.g. \' or '' + $qe = $this->_adapter->quote($q); + $qe = substr($qe, 1, 2); + $qe = preg_quote($qe); + $escapeChar = substr($qe,0,1); + // remove 'foo\'bar' + if (!empty($q)) { + $escapeChar = preg_quote($escapeChar); + // this segfaults only after 65,000 characters instead of 9,000 + $sql = preg_replace("/$q([^$q{$escapeChar}]*|($qe)*)*$q/s", '', $sql); + } + + // get a version of the SQL statement with all quoted + // values and delimited identifiers stripped out + // remove "foo\"bar" + $sql = preg_replace("/\"(\\\\\"|[^\"])*\"/Us", '', $sql); + + // get the character for delimited id quotes, + // this is usually " but in MySQL is ` + $d = $this->_adapter->quoteIdentifier('a'); + $d = $d[0]; + // get the value used as an escaped delimited id quote, + // e.g. \" or "" or \` + $de = $this->_adapter->quoteIdentifier($d); + $de = substr($de, 1, 2); + $de = preg_quote($de); + // Note: $de and $d where never used..., now they are: + $sql = preg_replace("/$d($de|\\\\{2}|[^$d])*$d/Us", '', $sql); + return $sql; + } + + /** + * Bind a column of the statement result set to a PHP variable. + * + * @param string $column Name the column in the result set, either by + * position or by name. + * @param mixed $param Reference to the PHP variable containing the value. + * @param mixed $type OPTIONAL + * @return bool + */ + public function bindColumn($column, &$param, $type = null) + { + $this->_bindColumn[$column] =& $param; + return true; + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + */ + public function bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + if (!is_int($parameter) && !is_string($parameter)) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception('Invalid bind-variable position'); + } + + $position = null; + if (($intval = (int) $parameter) > 0 && $this->_adapter->supportsParameters('positional')) { + if ($intval >= 1 || $intval <= count($this->_sqlParam)) { + $position = $intval; + } + } else if ($this->_adapter->supportsParameters('named')) { + if ($parameter[0] != ':') { + $parameter = ':' . $parameter; + } + if (in_array($parameter, $this->_sqlParam) !== false) { + $position = $parameter; + } + } + + if ($position === null) { + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception("Invalid bind-variable position '$parameter'"); + } + + // Finally we are assured that $position is valid + $this->_bindParam[$position] =& $variable; + return $this->_bindParam($position, $variable, $type, $length, $options); + } + + /** + * Binds a value to a parameter. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $value Scalar value to bind to the parameter. + * @param mixed $type OPTIONAL Datatype of the parameter. + * @return bool + */ + public function bindValue($parameter, $value, $type = null) + { + return $this->bindParam($parameter, $value, $type); + } + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + */ + public function execute(array $params = null) + { + /* + * Simple case - no query profiler to manage. + */ + if ($this->_queryId === null) { + return $this->_execute($params); + } + + /* + * Do the same thing, but with query profiler + * management before and after the execute. + */ + $prof = $this->_adapter->getProfiler(); + $qp = $prof->getQueryProfile($this->_queryId); + if ($qp->hasEnded()) { + $this->_queryId = $prof->queryClone($qp); + $qp = $prof->getQueryProfile($this->_queryId); + } + if ($params !== null) { + $qp->bindParams($params); + } else { + $qp->bindParams($this->_bindParam); + } + $qp->start($this->_queryId); + + $retval = $this->_execute($params); + + $prof->queryEnd($this->_queryId); + + return $retval; + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + */ + public function fetchAll($style = null, $col = null) + { + $data = array(); + if ($style === Zend_Db::FETCH_COLUMN && $col === null) { + $col = 0; + } + if ($col === null) { + while ($row = $this->fetch($style)) { + $data[] = $row; + } + } else { + while (false !== ($val = $this->fetchColumn($col))) { + $data[] = $val; + } + } + return $data; + } + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string One value from the next row of result set, or false. + */ + public function fetchColumn($col = 0) + { + $data = array(); + $col = (int) $col; + $row = $this->fetch(Zend_Db::FETCH_NUM); + if (!is_array($row)) { + return false; + } + return $row[$col]; + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class, or false. + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + $obj = new $class($config); + $row = $this->fetch(Zend_Db::FETCH_ASSOC); + if (!is_array($row)) { + return false; + } + foreach ($row as $key => $val) { + $obj->$key = $val; + } + return $obj; + } + + /** + * Retrieve a statement attribute. + * + * @param string $key Attribute name. + * @return mixed Attribute value. + */ + public function getAttribute($key) + { + if (array_key_exists($key, $this->_attribute)) { + return $this->_attribute[$key]; + } + } + + /** + * Set a statement attribute. + * + * @param string $key Attribute name. + * @param mixed $val Attribute value. + * @return bool + */ + public function setAttribute($key, $val) + { + $this->_attribute[$key] = $val; + } + + /** + * Set the default fetch mode for this statement. + * + * @param int $mode The fetch mode. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function setFetchMode($mode) + { + switch ($mode) { + case Zend_Db::FETCH_NUM: + case Zend_Db::FETCH_ASSOC: + case Zend_Db::FETCH_BOTH: + case Zend_Db::FETCH_OBJ: + $this->_fetchMode = $mode; + break; + case Zend_Db::FETCH_BOUND: + default: + $this->closeCursor(); + /** + * @see Zend_Db_Statement_Exception + */ + throw new Zend_Db_Statement_Exception('invalid fetch mode'); + break; + } + } + + /** + * Helper function to map retrieved row + * to bound column variables + * + * @param array $row + * @return bool True + */ + public function _fetchBound($row) + { + foreach ($row as $key => $value) { + // bindColumn() takes 1-based integer positions + // but fetch() returns 0-based integer indexes + if (is_int($key)) { + $key++; + } + // set results only to variables that were bound previously + if (isset($this->_bindColumn[$key])) { + $this->_bindColumn[$key] = $value; + } + } + return true; + } + + /** + * Gets the Zend_Db_Adapter_Abstract for this + * particular Zend_Db_Statement object. + * + * @return Zend_Db_Adapter_Abstract + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Gets the resource or object setup by the + * _parse + * @return unknown_type + */ + public function getDriverStatement() + { + return $this->_stmt; + } +} diff --git a/library/vendor/Zend/Db/Statement/Exception.php b/library/vendor/Zend/Db/Statement/Exception.php new file mode 100644 index 000000000..29bbecdb3 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Exception.php @@ -0,0 +1,55 @@ +getPrevious() !== null); + } + + /** + * @return Exception|null + */ + public function getChainedException() + { + return $this->getPrevious(); + } +} diff --git a/library/vendor/Zend/Db/Statement/Interface.php b/library/vendor/Zend/Db/Statement/Interface.php new file mode 100644 index 000000000..eaeb0bf4b --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Interface.php @@ -0,0 +1,203 @@ +_stmt = $this->_adapter->getConnection()->prepare($sql); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Bind a column of the statement result set to a PHP variable. + * + * @param string $column Name the column in the result set, either by + * position or by name. + * @param mixed $param Reference to the PHP variable containing the value. + * @param mixed $type OPTIONAL + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function bindColumn($column, &$param, $type = null) + { + try { + if ($type === null) { + return $this->_stmt->bindColumn($column, $param); + } else { + return $this->_stmt->bindColumn($column, $param, $type); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + try { + if ($type === null) { + if (is_bool($variable)) { + $type = PDO::PARAM_BOOL; + } elseif ($variable === null) { + $type = PDO::PARAM_NULL; + } elseif (is_integer($variable)) { + $type = PDO::PARAM_INT; + } else { + $type = PDO::PARAM_STR; + } + } + return $this->_stmt->bindParam($parameter, $variable, $type, $length, $options); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Binds a value to a parameter. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $value Scalar value to bind to the parameter. + * @param mixed $type OPTIONAL Datatype of the parameter. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function bindValue($parameter, $value, $type = null) + { + if (is_string($parameter) && $parameter[0] != ':') { + $parameter = ":$parameter"; + } + + $this->_bindParam[$parameter] = $value; + + try { + if ($type === null) { + return $this->_stmt->bindValue($parameter, $value); + } else { + return $this->_stmt->bindValue($parameter, $value, $type); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function closeCursor() + { + try { + return $this->_stmt->closeCursor(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + * @throws Zend_Db_Statement_Exception + */ + public function columnCount() + { + try { + return $this->_stmt->columnCount(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + * @throws Zend_Db_Statement_Exception + */ + public function errorCode() + { + try { + return $this->_stmt->errorCode(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + * @throws Zend_Db_Statement_Exception + */ + public function errorInfo() + { + try { + return $this->_stmt->errorInfo(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function _execute(array $params = null) + { + try { + if ($params !== null) { + return $this->_stmt->execute($params); + } else { + return $this->_stmt->execute(); + } + } catch (PDOException $e) { + $message = sprintf('%s, query was: %s', $e->getMessage(), $this->_stmt->queryString); + throw new Zend_Db_Statement_Exception($message, (int) $e->getCode(), $e); + } + } + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if ($style === null) { + $style = $this->_fetchMode; + } + try { + return $this->_stmt->fetch($style, $cursor, $offset); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Required by IteratorAggregate interface + * + * @return IteratorIterator + */ + public function getIterator() + { + return new IteratorIterator($this->_stmt); + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetchAll($style = null, $col = null) + { + if ($style === null) { + $style = $this->_fetchMode; + } + try { + if ($style == PDO::FETCH_COLUMN) { + if ($col === null) { + $col = 0; + } + return $this->_stmt->fetchAll($style, $col); + } else { + return $this->_stmt->fetchAll($style); + } + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string + * @throws Zend_Db_Statement_Exception + */ + public function fetchColumn($col = 0) + { + try { + return $this->_stmt->fetchColumn($col); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class. + * @throws Zend_Db_Statement_Exception + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + try { + return $this->_stmt->fetchObject($class, $config); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieve a statement attribute. + * + * @param integer $key Attribute name. + * @return mixed Attribute value. + * @throws Zend_Db_Statement_Exception + */ + public function getAttribute($key) + { + try { + return $this->_stmt->getAttribute($key); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns metadata for a column in a result set. + * + * @param int $column + * @return mixed + * @throws Zend_Db_Statement_Exception + */ + public function getColumnMeta($column) + { + try { + return $this->_stmt->getColumnMeta($column); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function nextRowset() + { + try { + return $this->_stmt->nextRowset(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + * @throws Zend_Db_Statement_Exception + */ + public function rowCount() + { + try { + return $this->_stmt->rowCount(); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Set a statement attribute. + * + * @param string $key Attribute name. + * @param mixed $val Attribute value. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function setAttribute($key, $val) + { + try { + return $this->_stmt->setAttribute($key, $val); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Set the default fetch mode for this statement. + * + * @param int $mode The fetch mode. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function setFetchMode($mode) + { + $this->_fetchMode = $mode; + try { + return $this->_stmt->setFetchMode($mode); + } catch (PDOException $e) { + throw new Zend_Db_Statement_Exception($e->getMessage(), $e->getCode(), $e); + } + } + +} diff --git a/library/vendor/Zend/Db/Statement/Sqlsrv.php b/library/vendor/Zend/Db/Statement/Sqlsrv.php new file mode 100644 index 000000000..6b36c82c9 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Sqlsrv.php @@ -0,0 +1,430 @@ +_adapter->getConnection(); + + $this->_stmt = sqlsrv_prepare($connection, $sql); + + if (!$this->_stmt) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + $this->_originalSQL = $sql; + } + + /** + * Binds a parameter to the specified variable name. + * + * @param mixed $parameter Name the parameter, either integer or string. + * @param mixed $variable Reference to PHP variable containing the value. + * @param mixed $type OPTIONAL Datatype of SQL parameter. + * @param mixed $length OPTIONAL Length of SQL parameter. + * @param mixed $options OPTIONAL Other options. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + protected function _bindParam($parameter, &$variable, $type = null, $length = null, $options = null) + { + //Sql server doesn't support bind by name + return true; + } + + /** + * Closes the cursor, allowing the statement to be executed again. + * + * @return bool + */ + public function closeCursor() + { + if (!$this->_stmt) { + return false; + } + + sqlsrv_free_stmt($this->_stmt); + $this->_stmt = false; + return true; + } + + /** + * Returns the number of columns in the result set. + * Returns null if the statement has no result set metadata. + * + * @return int The number of columns. + */ + public function columnCount() + { + if ($this->_stmt && $this->_executed) { + return sqlsrv_num_fields($this->_stmt); + } + + return 0; + } + + + /** + * Retrieves the error code, if any, associated with the last operation on + * the statement handle. + * + * @return string error code. + */ + public function errorCode() + { + if (!$this->_stmt) { + return false; + } + + $error = sqlsrv_errors(); + if (!$error) { + return false; + } + + return $error[0]['code']; + } + + + /** + * Retrieves an array of error information, if any, associated with the + * last operation on the statement handle. + * + * @return array + */ + public function errorInfo() + { + if (!$this->_stmt) { + return false; + } + + $error = sqlsrv_errors(); + if (!$error) { + return false; + } + + return array( + $error[0]['code'], + $error[0]['message'], + ); + } + + + /** + * Executes a prepared statement. + * + * @param array $params OPTIONAL Values to bind to parameter placeholders. + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function _execute(array $params = null) + { + $connection = $this->_adapter->getConnection(); + if (!$this->_stmt) { + return false; + } + + if ($params !== null) { + if (!is_array($params)) { + $params = array($params); + } + $error = false; + + // make all params passed by reference + $params_ = array(); + $temp = array(); + $i = 1; + foreach ($params as $param) { + $temp[$i] = $param; + $params_[] = &$temp[$i]; + $i++; + } + $params = $params_; + } + + $this->_stmt = sqlsrv_query($connection, $this->_originalSQL, $params); + + if (!$this->_stmt) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + $this->_executed = true; + + return (!$this->_stmt); + } + + /** + * Fetches a row from the result set. + * + * @param int $style OPTIONAL Fetch mode for this fetch operation. + * @param int $cursor OPTIONAL Absolute, relative, or other. + * @param int $offset OPTIONAL Number for absolute or relative cursors. + * @return mixed Array, object, or scalar depending on fetch mode. + * @throws Zend_Db_Statement_Exception + */ + public function fetch($style = null, $cursor = null, $offset = null) + { + if (!$this->_stmt) { + return false; + } + + if (null === $style) { + $style = $this->_fetchMode; + } + + $values = sqlsrv_fetch_array($this->_stmt, SQLSRV_FETCH_ASSOC); + + if (!$values && (null !== $error = sqlsrv_errors())) { + throw new Zend_Db_Statement_Sqlsrv_Exception($error); + } + + if (null === $values) { + return null; + } + + if (!$this->_keys) { + foreach ($values as $key => $value) { + $this->_keys[] = $this->_adapter->foldCase($key); + } + } + + $values = array_values($values); + + $row = false; + switch ($style) { + case Zend_Db::FETCH_NUM: + $row = $values; + break; + case Zend_Db::FETCH_ASSOC: + $row = array_combine($this->_keys, $values); + break; + case Zend_Db::FETCH_BOTH: + $assoc = array_combine($this->_keys, $values); + $row = array_merge($values, $assoc); + break; + case Zend_Db::FETCH_OBJ: + $row = (object) array_combine($this->_keys, $values); + break; + case Zend_Db::FETCH_BOUND: + $assoc = array_combine($this->_keys, $values); + $row = array_merge($values, $assoc); + $row = $this->_fetchBound($row); + break; + default: + throw new Zend_Db_Statement_Sqlsrv_Exception("Invalid fetch mode '$style' specified"); + break; + } + + return $row; + } + + /** + * Returns a single column from the next row of a result set. + * + * @param int $col OPTIONAL Position of the column to fetch. + * @return string + * @throws Zend_Db_Statement_Exception + */ + public function fetchColumn($col = 0) + { + if (!$this->_stmt) { + return false; + } + + if (!sqlsrv_fetch($this->_stmt)) { + if (null !== $error = sqlsrv_errors()) { + throw new Zend_Db_Statement_Sqlsrv_Exception($error); + } + + // If no error, there is simply no record + return false; + } + + $data = sqlsrv_get_field($this->_stmt, $col); //0-based + if ($data === false) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + return $data; + } + + /** + * Fetches the next row and returns it as an object. + * + * @param string $class OPTIONAL Name of the class to create. + * @param array $config OPTIONAL Constructor arguments for the class. + * @return mixed One object instance of the specified class. + * @throws Zend_Db_Statement_Exception + */ + public function fetchObject($class = 'stdClass', array $config = array()) + { + if (!$this->_stmt) { + return false; + } + + $obj = sqlsrv_fetch_object($this->_stmt); + + if ($error = sqlsrv_errors()) { + throw new Zend_Db_Statement_Sqlsrv_Exception($error); + } + + /* @todo XXX handle parameters */ + + if (null === $obj) { + return false; + } + + return $obj; + } + + /** + * Returns metadata for a column in a result set. + * + * @param int $column + * @return mixed + * @throws Zend_Db_Statement_Sqlsrv_Exception + */ + public function getColumnMeta($column) + { + $fields = sqlsrv_field_metadata($this->_stmt); + + if (!$fields) { + throw new Zend_Db_Statement_Sqlsrv_Exception('Column metadata can not be fetched'); + } + + if (!isset($fields[$column])) { + throw new Zend_Db_Statement_Sqlsrv_Exception('Column index does not exist in statement'); + } + + return $fields[$column]; + } + + /** + * Retrieves the next rowset (result set) for a SQL statement that has + * multiple result sets. An example is a stored procedure that returns + * the results of multiple queries. + * + * @return bool + * @throws Zend_Db_Statement_Exception + */ + public function nextRowset() + { + if (sqlsrv_next_result($this->_stmt) === false) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + // reset column keys + $this->_keys = null; + + return true; + } + + /** + * Returns the number of rows affected by the execution of the + * last INSERT, DELETE, or UPDATE statement executed by this + * statement object. + * + * @return int The number of rows affected. + * @throws Zend_Db_Statement_Exception + */ + public function rowCount() + { + if (!$this->_stmt) { + return false; + } + + if (!$this->_executed) { + return 0; + } + + $num_rows = sqlsrv_rows_affected($this->_stmt); + + // Strict check is necessary; 0 is a valid return value + if ($num_rows === false) { + throw new Zend_Db_Statement_Sqlsrv_Exception(sqlsrv_errors()); + } + + return $num_rows; + } + + /** + * Returns an array containing all of the result set rows. + * + * @param int $style OPTIONAL Fetch mode. + * @param int $col OPTIONAL Column number, if fetch mode is by column. + * @return array Collection of rows, each in a format by the fetch mode. + * + * Behaves like parent, but if limit() + * is used, the final result removes the extra column + * 'zend_db_rownum' + */ + public function fetchAll($style = null, $col = null) + { + $data = parent::fetchAll($style, $col); + $results = array(); + $remove = $this->_adapter->foldCase('ZEND_DB_ROWNUM'); + + foreach ($data as $row) { + if (is_array($row) && array_key_exists($remove, $row)) { + unset($row[$remove]); + } + $results[] = $row; + } + return $results; + } +} diff --git a/library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php b/library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php new file mode 100644 index 000000000..8d21296c7 --- /dev/null +++ b/library/vendor/Zend/Db/Statement/Sqlsrv/Exception.php @@ -0,0 +1,60 @@ + $config); + } else { + // process this as table with or without a definition + if ($definition instanceof Zend_Db_Table_Definition + && $definition->hasTableConfig($config)) { + // this will have DEFINITION_CONFIG_NAME & DEFINITION + $config = $definition->getTableConfig($config); + } else { + $config = array(self::NAME => $config); + } + } + } + + parent::__construct($config); + } +} diff --git a/library/vendor/Zend/Db/Table/Abstract.php b/library/vendor/Zend/Db/Table/Abstract.php new file mode 100644 index 000000000..cadeccad2 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Abstract.php @@ -0,0 +1,1589 @@ + $config); + } + + if ($config) { + $this->setOptions($config); + } + + $this->_setup(); + $this->init(); + } + + /** + * setOptions() + * + * @param array $options + * @return Zend_Db_Table_Abstract + */ + public function setOptions(Array $options) + { + foreach ($options as $key => $value) { + switch ($key) { + case self::ADAPTER: + $this->_setAdapter($value); + break; + case self::DEFINITION: + $this->setDefinition($value); + break; + case self::DEFINITION_CONFIG_NAME: + $this->setDefinitionConfigName($value); + break; + case self::SCHEMA: + $this->_schema = (string) $value; + break; + case self::NAME: + $this->_name = (string) $value; + break; + case self::PRIMARY: + $this->_primary = (array) $value; + break; + case self::ROW_CLASS: + $this->setRowClass($value); + break; + case self::ROWSET_CLASS: + $this->setRowsetClass($value); + break; + case self::REFERENCE_MAP: + $this->setReferences($value); + break; + case self::DEPENDENT_TABLES: + $this->setDependentTables($value); + break; + case self::METADATA_CACHE: + $this->_setMetadataCache($value); + break; + case self::METADATA_CACHE_IN_CLASS: + $this->setMetadataCacheInClass($value); + break; + case self::SEQUENCE: + $this->_setSequence($value); + break; + default: + // ignore unrecognized configuration directive + break; + } + } + + return $this; + } + + /** + * setDefinition() + * + * @param Zend_Db_Table_Definition $definition + * @return Zend_Db_Table_Abstract + */ + public function setDefinition(Zend_Db_Table_Definition $definition) + { + $this->_definition = $definition; + return $this; + } + + /** + * getDefinition() + * + * @return Zend_Db_Table_Definition|null + */ + public function getDefinition() + { + return $this->_definition; + } + + /** + * setDefinitionConfigName() + * + * @param string $definition + * @return Zend_Db_Table_Abstract + */ + public function setDefinitionConfigName($definitionConfigName) + { + $this->_definitionConfigName = $definitionConfigName; + return $this; + } + + /** + * getDefinitionConfigName() + * + * @return string + */ + public function getDefinitionConfigName() + { + return $this->_definitionConfigName; + } + + /** + * @param string $classname + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setRowClass($classname) + { + $this->_rowClass = (string) $classname; + + return $this; + } + + /** + * @return string + */ + public function getRowClass() + { + return $this->_rowClass; + } + + /** + * @param string $classname + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setRowsetClass($classname) + { + $this->_rowsetClass = (string) $classname; + + return $this; + } + + /** + * @return string + */ + public function getRowsetClass() + { + return $this->_rowsetClass; + } + + /** + * Add a reference to the reference map + * + * @param string $ruleKey + * @param string|array $columns + * @param string $refTableClass + * @param string|array $refColumns + * @param string $onDelete + * @param string $onUpdate + * @return Zend_Db_Table_Abstract + */ + public function addReference($ruleKey, $columns, $refTableClass, $refColumns, + $onDelete = null, $onUpdate = null) + { + $reference = array(self::COLUMNS => (array) $columns, + self::REF_TABLE_CLASS => $refTableClass, + self::REF_COLUMNS => (array) $refColumns); + + if (!empty($onDelete)) { + $reference[self::ON_DELETE] = $onDelete; + } + + if (!empty($onUpdate)) { + $reference[self::ON_UPDATE] = $onUpdate; + } + + $this->_referenceMap[$ruleKey] = $reference; + + return $this; + } + + /** + * @param array $referenceMap + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setReferences(array $referenceMap) + { + $this->_referenceMap = $referenceMap; + + return $this; + } + + /** + * @param string $tableClassname + * @param string $ruleKey OPTIONAL + * @return array + * @throws Zend_Db_Table_Exception + */ + public function getReference($tableClassname, $ruleKey = null) + { + $thisClass = get_class($this); + if ($thisClass === 'Zend_Db_Table') { + $thisClass = $this->_definitionConfigName; + } + $refMap = $this->_getReferenceMapNormalized(); + if ($ruleKey !== null) { + if (!isset($refMap[$ruleKey])) { + throw new Zend_Db_Table_Exception("No reference rule \"$ruleKey\" from table $thisClass to table $tableClassname"); + } + if ($refMap[$ruleKey][self::REF_TABLE_CLASS] != $tableClassname) { + throw new Zend_Db_Table_Exception("Reference rule \"$ruleKey\" does not reference table $tableClassname"); + } + return $refMap[$ruleKey]; + } + foreach ($refMap as $reference) { + if ($reference[self::REF_TABLE_CLASS] == $tableClassname) { + return $reference; + } + } + throw new Zend_Db_Table_Exception("No reference from table $thisClass to table $tableClassname"); + } + + /** + * @param array $dependentTables + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + public function setDependentTables(array $dependentTables) + { + $this->_dependentTables = $dependentTables; + + return $this; + } + + /** + * @return array + */ + public function getDependentTables() + { + return $this->_dependentTables; + } + + /** + * set the defaultSource property - this tells the table class where to find default values + * + * @param string $defaultSource + * @return Zend_Db_Table_Abstract + */ + public function setDefaultSource($defaultSource = self::DEFAULT_NONE) + { + if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) { + $defaultSource = self::DEFAULT_NONE; + } + + $this->_defaultSource = $defaultSource; + return $this; + } + + /** + * returns the default source flag that determines where defaultSources come from + * + * @return unknown + */ + public function getDefaultSource() + { + return $this->_defaultSource; + } + + /** + * set the default values for the table class + * + * @param array $defaultValues + * @return Zend_Db_Table_Abstract + */ + public function setDefaultValues(Array $defaultValues) + { + foreach ($defaultValues as $defaultName => $defaultValue) { + if (array_key_exists($defaultName, $this->_metadata)) { + $this->_defaultValues[$defaultName] = $defaultValue; + } + } + return $this; + } + + public function getDefaultValues() + { + return $this->_defaultValues; + } + + + /** + * Sets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects. + * + * @param mixed $db Either an Adapter object, or a string naming a Registry key + * @return void + */ + public static function setDefaultAdapter($db = null) + { + self::$_defaultDb = self::_setupAdapter($db); + } + + /** + * Gets the default Zend_Db_Adapter_Abstract for all Zend_Db_Table objects. + * + * @return Zend_Db_Adapter_Abstract or null + */ + public static function getDefaultAdapter() + { + return self::$_defaultDb; + } + + /** + * @param mixed $db Either an Adapter object, or a string naming a Registry key + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + protected function _setAdapter($db) + { + $this->_db = self::_setupAdapter($db); + return $this; + } + + /** + * Gets the Zend_Db_Adapter_Abstract for this particular Zend_Db_Table object. + * + * @return Zend_Db_Adapter_Abstract + */ + public function getAdapter() + { + return $this->_db; + } + + /** + * @param mixed $db Either an Adapter object, or a string naming a Registry key + * @return Zend_Db_Adapter_Abstract + * @throws Zend_Db_Table_Exception + */ + protected static function _setupAdapter($db) + { + if ($db === null) { + return null; + } + if (is_string($db)) { + $db = Zend_Registry::get($db); + } + if (!$db instanceof Zend_Db_Adapter_Abstract) { + throw new Zend_Db_Table_Exception('Argument must be of type Zend_Db_Adapter_Abstract, or a Registry key where a Zend_Db_Adapter_Abstract object is stored'); + } + return $db; + } + + /** + * Sets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * If $defaultMetadataCache is null, then no metadata cache is used by default. + * + * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key + * @return void + */ + public static function setDefaultMetadataCache($metadataCache = null) + { + self::$_defaultMetadataCache = self::_setupMetadataCache($metadataCache); + } + + /** + * Gets the default metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * @return Zend_Cache_Core or null + */ + public static function getDefaultMetadataCache() + { + return self::$_defaultMetadataCache; + } + + /** + * Sets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * If $metadataCache is null, then no metadata cache is used. Since there is no opportunity to reload metadata + * after instantiation, this method need not be public, particularly because that it would have no effect + * results in unnecessary API complexity. To configure the metadata cache, use the metadataCache configuration + * option for the class constructor upon instantiation. + * + * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key + * @return Zend_Db_Table_Abstract Provides a fluent interface + */ + protected function _setMetadataCache($metadataCache) + { + $this->_metadataCache = self::_setupMetadataCache($metadataCache); + return $this; + } + + /** + * Gets the metadata cache for information returned by Zend_Db_Adapter_Abstract::describeTable(). + * + * @return Zend_Cache_Core or null + */ + public function getMetadataCache() + { + return $this->_metadataCache; + } + + /** + * Indicate whether metadata should be cached in the class for the duration + * of the instance + * + * @param bool $flag + * @return Zend_Db_Table_Abstract + */ + public function setMetadataCacheInClass($flag) + { + $this->_metadataCacheInClass = (bool) $flag; + return $this; + } + + /** + * Retrieve flag indicating if metadata should be cached for duration of + * instance + * + * @return bool + */ + public function metadataCacheInClass() + { + return $this->_metadataCacheInClass; + } + + /** + * @param mixed $metadataCache Either a Cache object, or a string naming a Registry key + * @return Zend_Cache_Core + * @throws Zend_Db_Table_Exception + */ + protected static function _setupMetadataCache($metadataCache) + { + if ($metadataCache === null) { + return null; + } + if (is_string($metadataCache)) { + $metadataCache = Zend_Registry::get($metadataCache); + } + if (!$metadataCache instanceof Zend_Cache_Core) { + throw new Zend_Db_Table_Exception('Argument must be of type Zend_Cache_Core, or a Registry key where a Zend_Cache_Core object is stored'); + } + return $metadataCache; + } + + /** + * Sets the sequence member, which defines the behavior for generating + * primary key values in new rows. + * - If this is a string, then the string names the sequence object. + * - If this is boolean true, then the key uses an auto-incrementing + * or identity mechanism. + * - If this is boolean false, then the key is user-defined. + * Use this for natural keys, for example. + * + * @param mixed $sequence + * @return Zend_Db_Table_Adapter_Abstract Provides a fluent interface + */ + protected function _setSequence($sequence) + { + $this->_sequence = $sequence; + + return $this; + } + + /** + * Turnkey for initialization of a table object. + * Calls other protected methods for individual tasks, to make it easier + * for a subclass to override part of the setup logic. + * + * @return void + */ + protected function _setup() + { + $this->_setupDatabaseAdapter(); + $this->_setupTableName(); + } + + /** + * Initialize database adapter. + * + * @return void + * @throws Zend_Db_Table_Exception + */ + protected function _setupDatabaseAdapter() + { + if (! $this->_db) { + $this->_db = self::getDefaultAdapter(); + if (!$this->_db instanceof Zend_Db_Adapter_Abstract) { + throw new Zend_Db_Table_Exception('No adapter found for ' . get_class($this)); + } + } + } + + /** + * Initialize table and schema names. + * + * If the table name is not set in the class definition, + * use the class name itself as the table name. + * + * A schema name provided with the table name (e.g., "schema.table") overrides + * any existing value for $this->_schema. + * + * @return void + */ + protected function _setupTableName() + { + if (! $this->_name) { + $this->_name = get_class($this); + } else if (strpos($this->_name, '.')) { + list($this->_schema, $this->_name) = explode('.', $this->_name); + } + } + + /** + * Initializes metadata. + * + * If metadata cannot be loaded from cache, adapter's describeTable() method is called to discover metadata + * information. Returns true if and only if the metadata are loaded from cache. + * + * @return boolean + * @throws Zend_Db_Table_Exception + */ + protected function _setupMetadata() + { + if ($this->metadataCacheInClass() && (count($this->_metadata) > 0)) { + return true; + } + + // Assume that metadata will be loaded from cache + $isMetadataFromCache = true; + + // If $this has no metadata cache but the class has a default metadata cache + if (null === $this->_metadataCache && null !== self::$_defaultMetadataCache) { + // Make $this use the default metadata cache of the class + $this->_setMetadataCache(self::$_defaultMetadataCache); + } + + // If $this has a metadata cache + if (null !== $this->_metadataCache) { + // Define the cache identifier where the metadata are saved + + //get db configuration + $dbConfig = $this->_db->getConfig(); + + $port = isset($dbConfig['options']['port']) + ? ':'.$dbConfig['options']['port'] + : (isset($dbConfig['port']) + ? ':'.$dbConfig['port'] + : null); + + $host = isset($dbConfig['options']['host']) + ? ':'.$dbConfig['options']['host'] + : (isset($dbConfig['host']) + ? ':'.$dbConfig['host'] + : null); + + // Define the cache identifier where the metadata are saved + $cacheId = md5( // port:host/dbname:schema.table (based on availabilty) + $port . $host . '/'. $dbConfig['dbname'] . ':' + . $this->_schema. '.' . $this->_name + ); + } + + // If $this has no metadata cache or metadata cache misses + if (null === $this->_metadataCache || !($metadata = $this->_metadataCache->load($cacheId))) { + // Metadata are not loaded from cache + $isMetadataFromCache = false; + // Fetch metadata from the adapter's describeTable() method + $metadata = $this->_db->describeTable($this->_name, $this->_schema); + // If $this has a metadata cache, then cache the metadata + if (null !== $this->_metadataCache && !$this->_metadataCache->save($metadata, $cacheId)) { + trigger_error('Failed saving metadata to metadataCache', E_USER_NOTICE); + } + } + + // Assign the metadata to $this + $this->_metadata = $metadata; + + // Return whether the metadata were loaded from cache + return $isMetadataFromCache; + } + + /** + * Retrieve table columns + * + * @return array + */ + protected function _getCols() + { + if (null === $this->_cols) { + $this->_setupMetadata(); + $this->_cols = array_keys($this->_metadata); + } + return $this->_cols; + } + + /** + * Initialize primary key from metadata. + * If $_primary is not defined, discover primary keys + * from the information returned by describeTable(). + * + * @return void + * @throws Zend_Db_Table_Exception + */ + protected function _setupPrimaryKey() + { + if (!$this->_primary) { + $this->_setupMetadata(); + $this->_primary = array(); + foreach ($this->_metadata as $col) { + if ($col['PRIMARY']) { + $this->_primary[ $col['PRIMARY_POSITION'] ] = $col['COLUMN_NAME']; + if ($col['IDENTITY']) { + $this->_identity = $col['PRIMARY_POSITION']; + } + } + } + // if no primary key was specified and none was found in the metadata + // then throw an exception. + if (empty($this->_primary)) { + throw new Zend_Db_Table_Exception("A table must have a primary key, but none was found for table '{$this->_name}'"); + } + } else if (!is_array($this->_primary)) { + $this->_primary = array(1 => $this->_primary); + } else if (isset($this->_primary[0])) { + array_unshift($this->_primary, null); + unset($this->_primary[0]); + } + + $cols = $this->_getCols(); + if (! array_intersect((array) $this->_primary, $cols) == (array) $this->_primary) { + throw new Zend_Db_Table_Exception("Primary key column(s) (" + . implode(',', (array) $this->_primary) + . ") are not columns in this table (" + . implode(',', $cols) + . ")"); + } + + $primary = (array) $this->_primary; + $pkIdentity = $primary[(int) $this->_identity]; + + /** + * Special case for PostgreSQL: a SERIAL key implicitly uses a sequence + * object whose name is "__seq". + */ + if ($this->_sequence === true && $this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) { + $this->_sequence = $this->_db->quoteIdentifier("{$this->_name}_{$pkIdentity}_seq"); + if ($this->_schema) { + $this->_sequence = $this->_db->quoteIdentifier($this->_schema) . '.' . $this->_sequence; + } + } + } + + /** + * Returns a normalized version of the reference map + * + * @return array + */ + protected function _getReferenceMapNormalized() + { + $referenceMapNormalized = array(); + + foreach ($this->_referenceMap as $rule => $map) { + + $referenceMapNormalized[$rule] = array(); + + foreach ($map as $key => $value) { + switch ($key) { + + // normalize COLUMNS and REF_COLUMNS to arrays + case self::COLUMNS: + case self::REF_COLUMNS: + if (!is_array($value)) { + $referenceMapNormalized[$rule][$key] = array($value); + } else { + $referenceMapNormalized[$rule][$key] = $value; + } + break; + + // other values are copied as-is + default: + $referenceMapNormalized[$rule][$key] = $value; + break; + } + } + } + + return $referenceMapNormalized; + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Returns table information. + * + * You can elect to return only a part of this information by supplying its key name, + * otherwise all information is returned as an array. + * + * @param string $key The specific info part to return OPTIONAL + * @return mixed + * @throws Zend_Db_Table_Exception + */ + public function info($key = null) + { + $this->_setupPrimaryKey(); + + $info = array( + self::SCHEMA => $this->_schema, + self::NAME => $this->_name, + self::COLS => $this->_getCols(), + self::PRIMARY => (array) $this->_primary, + self::METADATA => $this->_metadata, + self::ROW_CLASS => $this->getRowClass(), + self::ROWSET_CLASS => $this->getRowsetClass(), + self::REFERENCE_MAP => $this->_referenceMap, + self::DEPENDENT_TABLES => $this->_dependentTables, + self::SEQUENCE => $this->_sequence + ); + + if ($key === null) { + return $info; + } + + if (!array_key_exists($key, $info)) { + throw new Zend_Db_Table_Exception('There is no table information for the key "' . $key . '"'); + } + + return $info[$key]; + } + + /** + * Returns an instance of a Zend_Db_Table_Select object. + * + * @param bool $withFromPart Whether or not to include the from part of the select based on the table + * @return Zend_Db_Table_Select + */ + public function select($withFromPart = self::SELECT_WITHOUT_FROM_PART) + { + $select = new Zend_Db_Table_Select($this); + if ($withFromPart == self::SELECT_WITH_FROM_PART) { + $select->from($this->info(self::NAME), Zend_Db_Table_Select::SQL_WILDCARD, $this->info(self::SCHEMA)); + } + return $select; + } + + /** + * Inserts a new row. + * + * @param array $data Column-value pairs. + * @return mixed The primary key of the row inserted. + */ + public function insert(array $data) + { + $this->_setupPrimaryKey(); + + /** + * Zend_Db_Table assumes that if you have a compound primary key + * and one of the columns in the key uses a sequence, + * it's the _first_ column in the compound key. + */ + $primary = (array) $this->_primary; + $pkIdentity = $primary[(int)$this->_identity]; + + + /** + * If the primary key can be generated automatically, and no value was + * specified in the user-supplied data, then omit it from the tuple. + * + * Note: this checks for sensible values in the supplied primary key + * position of the data. The following values are considered empty: + * null, false, true, '', array() + */ + if (array_key_exists($pkIdentity, $data)) { + if ($data[$pkIdentity] === null // null + || $data[$pkIdentity] === '' // empty string + || is_bool($data[$pkIdentity]) // boolean + || (is_array($data[$pkIdentity]) && empty($data[$pkIdentity]))) { // empty array + unset($data[$pkIdentity]); + } + } + + /** + * If this table uses a database sequence object and the data does not + * specify a value, then get the next ID from the sequence and add it + * to the row. We assume that only the first column in a compound + * primary key takes a value from a sequence. + */ + if (is_string($this->_sequence) && !isset($data[$pkIdentity])) { + $data[$pkIdentity] = $this->_db->nextSequenceId($this->_sequence); + } + + /** + * INSERT the new row. + */ + $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; + $this->_db->insert($tableSpec, $data); + + /** + * Fetch the most recent ID generated by an auto-increment + * or IDENTITY column, unless the user has specified a value, + * overriding the auto-increment mechanism. + */ + if ($this->_sequence === true && !isset($data[$pkIdentity])) { + $data[$pkIdentity] = $this->_db->lastInsertId(); + } + + /** + * Return the primary key value if the PK is a single column, + * else return an associative array of the PK column/value pairs. + */ + $pkData = array_intersect_key($data, array_flip($primary)); + if (count($primary) == 1) { + reset($pkData); + return current($pkData); + } + + return $pkData; + } + + /** + * Check if the provided column is an identity of the table + * + * @param string $column + * @throws Zend_Db_Table_Exception + * @return boolean + */ + public function isIdentity($column) + { + $this->_setupPrimaryKey(); + + if (!isset($this->_metadata[$column])) { + /** + * @see Zend_Db_Table_Exception + */ + + throw new Zend_Db_Table_Exception('Column "' . $column . '" not found in table.'); + } + + return (bool) $this->_metadata[$column]['IDENTITY']; + } + + /** + * Updates existing rows. + * + * @param array $data Column-value pairs. + * @param array|string $where An SQL WHERE clause, or an array of SQL WHERE clauses. + * @return int The number of rows updated. + */ + public function update(array $data, $where) + { + $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; + return $this->_db->update($tableSpec, $data, $where); + } + + /** + * Called by a row object for the parent table's class during save() method. + * + * @param string $parentTableClassname + * @param array $oldPrimaryKey + * @param array $newPrimaryKey + * @return int + */ + public function _cascadeUpdate($parentTableClassname, array $oldPrimaryKey, array $newPrimaryKey) + { + $this->_setupMetadata(); + $rowsAffected = 0; + foreach ($this->_getReferenceMapNormalized() as $map) { + if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_UPDATE])) { + switch ($map[self::ON_UPDATE]) { + case self::CASCADE: + $newRefs = array(); + $where = array(); + for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) { + $col = $this->_db->foldCase($map[self::COLUMNS][$i]); + $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]); + if (array_key_exists($refCol, $newPrimaryKey)) { + $newRefs[$col] = $newPrimaryKey[$refCol]; + } + $type = $this->_metadata[$col]['DATA_TYPE']; + $where[] = $this->_db->quoteInto( + $this->_db->quoteIdentifier($col, true) . ' = ?', + $oldPrimaryKey[$refCol], $type); + } + $rowsAffected += $this->update($newRefs, $where); + break; + default: + // no action + break; + } + } + } + return $rowsAffected; + } + + /** + * Deletes existing rows. + * + * @param array|string $where SQL WHERE clause(s). + * @return int The number of rows deleted. + */ + public function delete($where) + { + $depTables = $this->getDependentTables(); + if (!empty($depTables)) { + $resultSet = $this->fetchAll($where); + if (count($resultSet) > 0 ) { + foreach ($resultSet as $row) { + /** + * Execute cascading deletes against dependent tables + */ + foreach ($depTables as $tableClass) { + $t = self::getTableFromString($tableClass, $this); + $t->_cascadeDelete($tableClass, $row->getPrimaryKey()); + } + } + } + } + + $tableSpec = ($this->_schema ? $this->_schema . '.' : '') . $this->_name; + return $this->_db->delete($tableSpec, $where); + } + + /** + * Called by parent table's class during delete() method. + * + * @param string $parentTableClassname + * @param array $primaryKey + * @return int Number of affected rows + */ + public function _cascadeDelete($parentTableClassname, array $primaryKey) + { + // setup metadata + $this->_setupMetadata(); + + // get this class name + $thisClass = get_class($this); + if ($thisClass === 'Zend_Db_Table') { + $thisClass = $this->_definitionConfigName; + } + + $rowsAffected = 0; + + foreach ($this->_getReferenceMapNormalized() as $map) { + if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) { + + $where = array(); + + // CASCADE or CASCADE_RECURSE + if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) { + for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) { + $col = $this->_db->foldCase($map[self::COLUMNS][$i]); + $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]); + $type = $this->_metadata[$col]['DATA_TYPE']; + $where[] = $this->_db->quoteInto( + $this->_db->quoteIdentifier($col, true) . ' = ?', + $primaryKey[$refCol], $type); + } + } + + // CASCADE_RECURSE + if ($map[self::ON_DELETE] == self::CASCADE_RECURSE) { + + /** + * Execute cascading deletes against dependent tables + */ + $depTables = $this->getDependentTables(); + if (!empty($depTables)) { + foreach ($depTables as $tableClass) { + $t = self::getTableFromString($tableClass, $this); + foreach ($this->fetchAll($where) as $depRow) { + $rowsAffected += $t->_cascadeDelete($thisClass, $depRow->getPrimaryKey()); + } + } + } + } + + // CASCADE or CASCADE_RECURSE + if (in_array($map[self::ON_DELETE], array(self::CASCADE, self::CASCADE_RECURSE))) { + $rowsAffected += $this->delete($where); + } + + } + } + return $rowsAffected; + } + + /** + * Fetches rows by primary key. The argument specifies one or more primary + * key value(s). To find multiple rows by primary key, the argument must + * be an array. + * + * This method accepts a variable number of arguments. If the table has a + * multi-column primary key, the number of arguments must be the same as + * the number of columns in the primary key. To find multiple rows in a + * table with a multi-column primary key, each argument must be an array + * with the same number of elements. + * + * The find() method always returns a Rowset object, even if only one row + * was found. + * + * @param mixed $key The value(s) of the primary keys. + * @return Zend_Db_Table_Rowset_Abstract Row(s) matching the criteria. + * @throws Zend_Db_Table_Exception + */ + public function find() + { + $this->_setupPrimaryKey(); + $args = func_get_args(); + $keyNames = array_values((array) $this->_primary); + + if (count($args) < count($keyNames)) { + throw new Zend_Db_Table_Exception("Too few columns for the primary key"); + } + + if (count($args) > count($keyNames)) { + throw new Zend_Db_Table_Exception("Too many columns for the primary key"); + } + + $whereList = array(); + $numberTerms = 0; + foreach ($args as $keyPosition => $keyValues) { + $keyValuesCount = count($keyValues); + // Coerce the values to an array. + // Don't simply typecast to array, because the values + // might be Zend_Db_Expr objects. + if (!is_array($keyValues)) { + $keyValues = array($keyValues); + } + if ($numberTerms == 0) { + $numberTerms = $keyValuesCount; + } else if ($keyValuesCount != $numberTerms) { + throw new Zend_Db_Table_Exception("Missing value(s) for the primary key"); + } + $keyValues = array_values($keyValues); + for ($i = 0; $i < $keyValuesCount; ++$i) { + if (!isset($whereList[$i])) { + $whereList[$i] = array(); + } + $whereList[$i][$keyPosition] = $keyValues[$i]; + } + } + + $whereClause = null; + if (count($whereList)) { + $whereOrTerms = array(); + $tableName = $this->_db->quoteTableAs($this->_name, null, true); + foreach ($whereList as $keyValueSets) { + $whereAndTerms = array(); + foreach ($keyValueSets as $keyPosition => $keyValue) { + $type = $this->_metadata[$keyNames[$keyPosition]]['DATA_TYPE']; + $columnName = $this->_db->quoteIdentifier($keyNames[$keyPosition], true); + $whereAndTerms[] = $this->_db->quoteInto( + $tableName . '.' . $columnName . ' = ?', + $keyValue, $type); + } + $whereOrTerms[] = '(' . implode(' AND ', $whereAndTerms) . ')'; + } + $whereClause = '(' . implode(' OR ', $whereOrTerms) . ')'; + } + + // issue ZF-5775 (empty where clause should return empty rowset) + if ($whereClause == null) { + $rowsetClass = $this->getRowsetClass(); + if (!class_exists($rowsetClass)) { + Zend_Loader::loadClass($rowsetClass); + } + return new $rowsetClass(array('table' => $this, 'rowClass' => $this->getRowClass(), 'stored' => true)); + } + + return $this->fetchAll($whereClause); + } + + /** + * Fetches all rows. + * + * Honors the Zend_Db_Adapter fetch mode. + * + * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object. + * @param string|array $order OPTIONAL An SQL ORDER clause. + * @param int $count OPTIONAL An SQL LIMIT count. + * @param int $offset OPTIONAL An SQL LIMIT offset. + * @return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode. + */ + public function fetchAll($where = null, $order = null, $count = null, $offset = null) + { + if (!($where instanceof Zend_Db_Table_Select)) { + $select = $this->select(); + + if ($where !== null) { + $this->_where($select, $where); + } + + if ($order !== null) { + $this->_order($select, $order); + } + + if ($count !== null || $offset !== null) { + $select->limit($count, $offset); + } + + } else { + $select = $where; + } + + $rows = $this->_fetch($select); + + $data = array( + 'table' => $this, + 'data' => $rows, + 'readOnly' => $select->isReadOnly(), + 'rowClass' => $this->getRowClass(), + 'stored' => true + ); + + $rowsetClass = $this->getRowsetClass(); + if (!class_exists($rowsetClass)) { + Zend_Loader::loadClass($rowsetClass); + } + return new $rowsetClass($data); + } + + /** + * Fetches one row in an object of type Zend_Db_Table_Row_Abstract, + * or returns null if no row matches the specified criteria. + * + * @param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object. + * @param string|array $order OPTIONAL An SQL ORDER clause. + * @param int $offset OPTIONAL An SQL OFFSET value. + * @return Zend_Db_Table_Row_Abstract|null The row results per the + * Zend_Db_Adapter fetch mode, or null if no row found. + */ + public function fetchRow($where = null, $order = null, $offset = null) + { + if (!($where instanceof Zend_Db_Table_Select)) { + $select = $this->select(); + + if ($where !== null) { + $this->_where($select, $where); + } + + if ($order !== null) { + $this->_order($select, $order); + } + + $select->limit(1, ((is_numeric($offset)) ? (int) $offset : null)); + + } else { + $select = $where->limit(1, $where->getPart(Zend_Db_Select::LIMIT_OFFSET)); + } + + $rows = $this->_fetch($select); + + if (count($rows) == 0) { + return null; + } + + $data = array( + 'table' => $this, + 'data' => $rows[0], + 'readOnly' => $select->isReadOnly(), + 'stored' => true + ); + + $rowClass = $this->getRowClass(); + if (!class_exists($rowClass)) { + Zend_Loader::loadClass($rowClass); + } + return new $rowClass($data); + } + + /** + * Fetches a new blank row (not from the database). + * + * @return Zend_Db_Table_Row_Abstract + * @deprecated since 0.9.3 - use createRow() instead. + */ + public function fetchNew() + { + return $this->createRow(); + } + + /** + * Fetches a new blank row (not from the database). + * + * @param array $data OPTIONAL data to populate in the new row. + * @param string $defaultSource OPTIONAL flag to force default values into new row + * @return Zend_Db_Table_Row_Abstract + */ + public function createRow(array $data = array(), $defaultSource = null) + { + $cols = $this->_getCols(); + $defaults = array_combine($cols, array_fill(0, count($cols), null)); + + // nothing provided at call-time, take the class value + if ($defaultSource == null) { + $defaultSource = $this->_defaultSource; + } + + if (!in_array($defaultSource, array(self::DEFAULT_CLASS, self::DEFAULT_DB, self::DEFAULT_NONE))) { + $defaultSource = self::DEFAULT_NONE; + } + + if ($defaultSource == self::DEFAULT_DB) { + foreach ($this->_metadata as $metadataName => $metadata) { + if (($metadata['DEFAULT'] != null) && + ($metadata['NULLABLE'] !== true || ($metadata['NULLABLE'] === true && isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === true)) && + (!(isset($this->_defaultValues[$metadataName]) && $this->_defaultValues[$metadataName] === false))) { + $defaults[$metadataName] = $metadata['DEFAULT']; + } + } + } elseif ($defaultSource == self::DEFAULT_CLASS && $this->_defaultValues) { + foreach ($this->_defaultValues as $defaultName => $defaultValue) { + if (array_key_exists($defaultName, $defaults)) { + $defaults[$defaultName] = $defaultValue; + } + } + } + + $config = array( + 'table' => $this, + 'data' => $defaults, + 'readOnly' => false, + 'stored' => false + ); + + $rowClass = $this->getRowClass(); + if (!class_exists($rowClass)) { + Zend_Loader::loadClass($rowClass); + } + $row = new $rowClass($config); + $row->setFromArray($data); + return $row; + } + + /** + * Generate WHERE clause from user-supplied string or array + * + * @param string|array $where OPTIONAL An SQL WHERE clause. + * @return Zend_Db_Table_Select + */ + protected function _where(Zend_Db_Table_Select $select, $where) + { + $where = (array) $where; + + foreach ($where as $key => $val) { + // is $key an int? + if (is_int($key)) { + // $val is the full condition + $select->where($val); + } else { + // $key is the condition with placeholder, + // and $val is quoted into the condition + $select->where($key, $val); + } + } + + return $select; + } + + /** + * Generate ORDER clause from user-supplied string or array + * + * @param string|array $order OPTIONAL An SQL ORDER clause. + * @return Zend_Db_Table_Select + */ + protected function _order(Zend_Db_Table_Select $select, $order) + { + if (!is_array($order)) { + $order = array($order); + } + + foreach ($order as $val) { + $select->order($val); + } + + return $select; + } + + /** + * Support method for fetching rows. + * + * @param Zend_Db_Table_Select $select query options. + * @return array An array containing the row results in FETCH_ASSOC mode. + */ + protected function _fetch(Zend_Db_Table_Select $select) + { + $stmt = $this->_db->query($select); + $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC); + return $data; + } + + public static function getTableFromString($tableName, Zend_Db_Table_Abstract $referenceTable = null) + { + if ($referenceTable instanceof Zend_Db_Table_Abstract) { + $tableDefinition = $referenceTable->getDefinition(); + + if ($tableDefinition !== null && $tableDefinition->hasTableConfig($tableName)) { + return new Zend_Db_Table($tableName, $tableDefinition); + } + } + + // assume the tableName is the class name + if (!class_exists($tableName)) { + try { + Zend_Loader::loadClass($tableName); + } catch (Zend_Exception $e) { + throw new Zend_Db_Table_Row_Exception($e->getMessage(), $e->getCode(), $e); + } + } + + $options = array(); + + if ($referenceTable instanceof Zend_Db_Table_Abstract) { + $options['db'] = $referenceTable->getAdapter(); + } + + if (isset($tableDefinition) && $tableDefinition !== null) { + $options[Zend_Db_Table_Abstract::DEFINITION] = $tableDefinition; + } + + return new $tableName($options); + } + +} diff --git a/library/vendor/Zend/Db/Table/Definition.php b/library/vendor/Zend/Db/Table/Definition.php new file mode 100644 index 000000000..8a0dea807 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Definition.php @@ -0,0 +1,131 @@ +setConfig($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * setConfig() + * + * @param Zend_Config $config + * @return Zend_Db_Table_Definition + */ + public function setConfig(Zend_Config $config) + { + $this->setOptions($config->toArray()); + return $this; + } + + /** + * setOptions() + * + * @param array $options + * @return Zend_Db_Table_Definition + */ + public function setOptions(Array $options) + { + foreach ($options as $optionName => $optionValue) { + $this->setTableConfig($optionName, $optionValue); + } + return $this; + } + + /** + * @param string $tableName + * @param array $tableConfig + * @return Zend_Db_Table_Definition + */ + public function setTableConfig($tableName, array $tableConfig) + { + // @todo logic here + $tableConfig[Zend_Db_Table::DEFINITION_CONFIG_NAME] = $tableName; + $tableConfig[Zend_Db_Table::DEFINITION] = $this; + + if (!isset($tableConfig[Zend_Db_Table::NAME])) { + $tableConfig[Zend_Db_Table::NAME] = $tableName; + } + + $this->_tableConfigs[$tableName] = $tableConfig; + return $this; + } + + /** + * getTableConfig() + * + * @param string $tableName + * @return array + */ + public function getTableConfig($tableName) + { + return $this->_tableConfigs[$tableName]; + } + + /** + * removeTableConfig() + * + * @param string $tableName + */ + public function removeTableConfig($tableName) + { + unset($this->_tableConfigs[$tableName]); + } + + /** + * hasTableConfig() + * + * @param string $tableName + * @return bool + */ + public function hasTableConfig($tableName) + { + return (isset($this->_tableConfigs[$tableName])); + } + +} diff --git a/library/vendor/Zend/Db/Table/Exception.php b/library/vendor/Zend/Db/Table/Exception.php new file mode 100644 index 000000000..9189ff3a9 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Exception.php @@ -0,0 +1,37 @@ + value). + * The keys must match the physical names of columns in the + * table for which this row is defined. + * + * @var array + */ + protected $_data = array(); + + /** + * This is set to a copy of $_data when the data is fetched from + * a database, specified as a new tuple in the constructor, or + * when dirty data is posted to the database with save(). + * + * @var array + */ + protected $_cleanData = array(); + + /** + * Tracks columns where data has been updated. Allows more specific insert and + * update operations. + * + * @var array + */ + protected $_modifiedFields = array(); + + /** + * Zend_Db_Table_Abstract parent class or instance. + * + * @var Zend_Db_Table_Abstract + */ + protected $_table = null; + + /** + * Connected is true if we have a reference to a live + * Zend_Db_Table_Abstract object. + * This is false after the Rowset has been deserialized. + * + * @var boolean + */ + protected $_connected = true; + + /** + * A row is marked read only if it contains columns that are not physically represented within + * the database schema (e.g. evaluated columns/Zend_Db_Expr columns). This can also be passed + * as a run-time config options as a means of protecting row data. + * + * @var boolean + */ + protected $_readOnly = false; + + /** + * Name of the class of the Zend_Db_Table_Abstract object. + * + * @var string + */ + protected $_tableClass = null; + + /** + * Primary row key(s). + * + * @var array + */ + protected $_primary; + + /** + * Constructor. + * + * Supported params for $config are:- + * - table = class name or object of type Zend_Db_Table_Abstract + * - data = values of columns in this row. + * + * @param array $config OPTIONAL Array of user-specified config options. + * @return void + * @throws Zend_Db_Table_Row_Exception + */ + public function __construct(array $config = array()) + { + if (isset($config['table']) && $config['table'] instanceof Zend_Db_Table_Abstract) { + $this->_table = $config['table']; + $this->_tableClass = get_class($this->_table); + } elseif ($this->_tableClass !== null) { + $this->_table = $this->_getTableFromString($this->_tableClass); + } + + if (isset($config['data'])) { + if (!is_array($config['data'])) { + throw new Zend_Db_Table_Row_Exception('Data must be an array'); + } + $this->_data = $config['data']; + } + if (isset($config['stored']) && $config['stored'] === true) { + $this->_cleanData = $this->_data; + } + + if (isset($config['readOnly']) && $config['readOnly'] === true) { + $this->setReadOnly(true); + } + + // Retrieve primary keys from table schema + if (($table = $this->_getTable())) { + $info = $table->info(); + $this->_primary = (array) $info['primary']; + } + + $this->init(); + } + + /** + * Transform a column name from the user-specified form + * to the physical form used in the database. + * You can override this method in a custom Row class + * to implement column name mappings, for example inflection. + * + * @param string $columnName Column name given. + * @return string The column name after transformation applied (none by default). + * @throws Zend_Db_Table_Row_Exception if the $columnName is not a string. + */ + protected function _transformColumn($columnName) + { + if (!is_string($columnName)) { + throw new Zend_Db_Table_Row_Exception('Specified column is not a string'); + } + // Perform no transformation by default + return $columnName; + } + + /** + * Retrieve row field value + * + * @param string $columnName The user-specified column name. + * @return string The corresponding column value. + * @throws Zend_Db_Table_Row_Exception if the $columnName is not a column in the row. + */ + public function __get($columnName) + { + $columnName = $this->_transformColumn($columnName); + if (!array_key_exists($columnName, $this->_data)) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row"); + } + return $this->_data[$columnName]; + } + + /** + * Set row field value + * + * @param string $columnName The column key. + * @param mixed $value The value for the property. + * @return void + * @throws Zend_Db_Table_Row_Exception + */ + public function __set($columnName, $value) + { + $columnName = $this->_transformColumn($columnName); + if (!array_key_exists($columnName, $this->_data)) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row"); + } + $this->_data[$columnName] = $value; + $this->_modifiedFields[$columnName] = true; + } + + /** + * Unset row field value + * + * @param string $columnName The column key. + * @return Zend_Db_Table_Row_Abstract + * @throws Zend_Db_Table_Row_Exception + */ + public function __unset($columnName) + { + $columnName = $this->_transformColumn($columnName); + if (!array_key_exists($columnName, $this->_data)) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row"); + } + if ($this->isConnected() && in_array($columnName, $this->_table->info('primary'))) { + throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is a primary key and should not be unset"); + } + unset($this->_data[$columnName]); + return $this; + } + + /** + * Test existence of row field + * + * @param string $columnName The column key. + * @return boolean + */ + public function __isset($columnName) + { + $columnName = $this->_transformColumn($columnName); + return array_key_exists($columnName, $this->_data); + } + + /** + * Store table, primary key and data in serialized object + * + * @return array + */ + public function __sleep() + { + return array('_tableClass', '_primary', '_data', '_cleanData', '_readOnly' ,'_modifiedFields'); + } + + /** + * Setup to do on wakeup. + * A de-serialized Row should not be assumed to have access to a live + * database connection, so set _connected = false. + * + * @return void + */ + public function __wakeup() + { + $this->_connected = false; + } + + /** + * Proxy to __isset + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return boolean + */ + public function offsetExists($offset) + { + return $this->__isset($offset); + } + + /** + * Proxy to __get + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return string + */ + public function offsetGet($offset) + { + return $this->__get($offset); + } + + /** + * Proxy to __set + * Required by the ArrayAccess implementation + * + * @param string $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + $this->__set($offset, $value); + } + + /** + * Proxy to __unset + * Required by the ArrayAccess implementation + * + * @param string $offset + */ + public function offsetUnset($offset) + { + return $this->__unset($offset); + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Returns the table object, or null if this is disconnected row + * + * @return Zend_Db_Table_Abstract|null + */ + public function getTable() + { + return $this->_table; + } + + /** + * Set the table object, to re-establish a live connection + * to the database for a Row that has been de-serialized. + * + * @param Zend_Db_Table_Abstract $table + * @return boolean + * @throws Zend_Db_Table_Row_Exception + */ + public function setTable(Zend_Db_Table_Abstract $table = null) + { + if ($table == null) { + $this->_table = null; + $this->_connected = false; + return false; + } + + $tableClass = get_class($table); + if (! $table instanceof $this->_tableClass) { + throw new Zend_Db_Table_Row_Exception("The specified Table is of class $tableClass, expecting class to be instance of $this->_tableClass"); + } + + $this->_table = $table; + $this->_tableClass = $tableClass; + + $info = $this->_table->info(); + + if ($info['cols'] != array_keys($this->_data)) { + throw new Zend_Db_Table_Row_Exception('The specified Table does not have the same columns as the Row'); + } + + if (! array_intersect((array) $this->_primary, $info['primary']) == (array) $this->_primary) { + + throw new Zend_Db_Table_Row_Exception("The specified Table '$tableClass' does not have the same primary key as the Row"); + } + + $this->_connected = true; + return true; + } + + /** + * Query the class name of the Table object for which this + * Row was created. + * + * @return string + */ + public function getTableClass() + { + return $this->_tableClass; + } + + /** + * Test the connected status of the row. + * + * @return boolean + */ + public function isConnected() + { + return $this->_connected; + } + + /** + * Test the read-only status of the row. + * + * @return boolean + */ + public function isReadOnly() + { + return $this->_readOnly; + } + + /** + * Set the read-only status of the row. + * + * @param boolean $flag + * @return boolean + */ + public function setReadOnly($flag) + { + $this->_readOnly = (bool) $flag; + } + + /** + * Returns an instance of the parent table's Zend_Db_Table_Select object. + * + * @return Zend_Db_Table_Select + */ + public function select() + { + return $this->getTable()->select(); + } + + /** + * Saves the properties to the database. + * + * This performs an intelligent insert/update, and reloads the + * properties with fresh data from the table on success. + * + * @return mixed The primary key value(s), as an associative array if the + * key is compound, or a scalar if the key is single-column. + */ + public function save() + { + /** + * If the _cleanData array is empty, + * this is an INSERT of a new row. + * Otherwise it is an UPDATE. + */ + if (empty($this->_cleanData)) { + return $this->_doInsert(); + } else { + return $this->_doUpdate(); + } + } + + /** + * @return mixed The primary key value(s), as an associative array if the + * key is compound, or a scalar if the key is single-column. + */ + protected function _doInsert() + { + /** + * A read-only row cannot be saved. + */ + if ($this->_readOnly === true) { + throw new Zend_Db_Table_Row_Exception('This row has been marked read-only'); + } + + /** + * Run pre-INSERT logic + */ + $this->_insert(); + + /** + * Execute the INSERT (this may throw an exception) + */ + $data = array_intersect_key($this->_data, $this->_modifiedFields); + $primaryKey = $this->_getTable()->insert($data); + + /** + * Normalize the result to an array indexed by primary key column(s). + * The table insert() method may return a scalar. + */ + if (is_array($primaryKey)) { + $newPrimaryKey = $primaryKey; + } else { + //ZF-6167 Use tempPrimaryKey temporary to avoid that zend encoding fails. + $tempPrimaryKey = (array) $this->_primary; + $newPrimaryKey = array(current($tempPrimaryKey) => $primaryKey); + } + + /** + * Save the new primary key value in _data. The primary key may have + * been generated by a sequence or auto-increment mechanism, and this + * merge should be done before the _postInsert() method is run, so the + * new values are available for logging, etc. + */ + $this->_data = array_merge($this->_data, $newPrimaryKey); + + /** + * Run post-INSERT logic + */ + $this->_postInsert(); + + /** + * Update the _cleanData to reflect that the data has been inserted. + */ + $this->_refresh(); + + return $primaryKey; + } + + /** + * @return mixed The primary key value(s), as an associative array if the + * key is compound, or a scalar if the key is single-column. + */ + protected function _doUpdate() + { + /** + * A read-only row cannot be saved. + */ + if ($this->_readOnly === true) { + throw new Zend_Db_Table_Row_Exception('This row has been marked read-only'); + } + + /** + * Get expressions for a WHERE clause + * based on the primary key value(s). + */ + $where = $this->_getWhereQuery(false); + + /** + * Run pre-UPDATE logic + */ + $this->_update(); + + /** + * Compare the data to the modified fields array to discover + * which columns have been changed. + */ + $diffData = array_intersect_key($this->_data, $this->_modifiedFields); + + /** + * Were any of the changed columns part of the primary key? + */ + $pkDiffData = array_intersect_key($diffData, array_flip((array)$this->_primary)); + + /** + * Execute cascading updates against dependent tables. + * Do this only if primary key value(s) were changed. + */ + if (count($pkDiffData) > 0) { + $depTables = $this->_getTable()->getDependentTables(); + if (!empty($depTables)) { + $pkNew = $this->_getPrimaryKey(true); + $pkOld = $this->_getPrimaryKey(false); + foreach ($depTables as $tableClass) { + $t = $this->_getTableFromString($tableClass); + $t->_cascadeUpdate($this->getTableClass(), $pkOld, $pkNew); + } + } + } + + /** + * Execute the UPDATE (this may throw an exception) + * Do this only if data values were changed. + * Use the $diffData variable, so the UPDATE statement + * includes SET terms only for data values that changed. + */ + if (count($diffData) > 0) { + $this->_getTable()->update($diffData, $where); + } + + /** + * Run post-UPDATE logic. Do this before the _refresh() + * so the _postUpdate() function can tell the difference + * between changed data and clean (pre-changed) data. + */ + $this->_postUpdate(); + + /** + * Refresh the data just in case triggers in the RDBMS changed + * any columns. Also this resets the _cleanData. + */ + $this->_refresh(); + + /** + * Return the primary key value(s) as an array + * if the key is compound or a scalar if the key + * is a scalar. + */ + $primaryKey = $this->_getPrimaryKey(true); + if (count($primaryKey) == 1) { + return current($primaryKey); + } + + return $primaryKey; + } + + /** + * Deletes existing rows. + * + * @return int The number of rows deleted. + */ + public function delete() + { + /** + * A read-only row cannot be deleted. + */ + if ($this->_readOnly === true) { + throw new Zend_Db_Table_Row_Exception('This row has been marked read-only'); + } + + $where = $this->_getWhereQuery(); + + /** + * Execute pre-DELETE logic + */ + $this->_delete(); + + /** + * Execute cascading deletes against dependent tables + */ + $depTables = $this->_getTable()->getDependentTables(); + if (!empty($depTables)) { + $pk = $this->_getPrimaryKey(); + foreach ($depTables as $tableClass) { + $t = $this->_getTableFromString($tableClass); + $t->_cascadeDelete($this->getTableClass(), $pk); + } + } + + /** + * Execute the DELETE (this may throw an exception) + */ + $result = $this->_getTable()->delete($where); + + /** + * Execute post-DELETE logic + */ + $this->_postDelete(); + + /** + * Reset all fields to null to indicate that the row is not there + */ + $this->_data = array_combine( + array_keys($this->_data), + array_fill(0, count($this->_data), null) + ); + + return $result; + } + + public function getIterator() + { + return new ArrayIterator((array) $this->_data); + } + + /** + * Returns the column/value data as an array. + * + * @return array + */ + public function toArray() + { + return (array)$this->_data; + } + + /** + * Sets all data in the row from an array. + * + * @param array $data + * @return Zend_Db_Table_Row_Abstract Provides a fluent interface + */ + public function setFromArray(array $data) + { + $data = array_intersect_key($data, $this->_data); + + foreach ($data as $columnName => $value) { + $this->__set($columnName, $value); + } + + return $this; + } + + /** + * Refreshes properties from the database. + * + * @return void + */ + public function refresh() + { + return $this->_refresh(); + } + + /** + * Retrieves an instance of the parent table. + * + * @return Zend_Db_Table_Abstract + */ + protected function _getTable() + { + if (!$this->_connected) { + throw new Zend_Db_Table_Row_Exception('Cannot save a Row unless it is connected'); + } + return $this->_table; + } + + /** + * Retrieves an associative array of primary keys. + * + * @param bool $useDirty + * @return array + */ + protected function _getPrimaryKey($useDirty = true) + { + if (!is_array($this->_primary)) { + throw new Zend_Db_Table_Row_Exception("The primary key must be set as an array"); + } + + $primary = array_flip($this->_primary); + if ($useDirty) { + $array = array_intersect_key($this->_data, $primary); + } else { + $array = array_intersect_key($this->_cleanData, $primary); + } + if (count($primary) != count($array)) { + throw new Zend_Db_Table_Row_Exception("The specified Table '$this->_tableClass' does not have the same primary key as the Row"); + } + return $array; + } + + /** + * Retrieves an associative array of primary keys. + * + * @param bool $useDirty + * @return array + */ + public function getPrimaryKey($useDirty = true) + { + return $this->_getPrimaryKey($useDirty); + } + + /** + * Constructs where statement for retrieving row(s). + * + * @param bool $useDirty + * @return array + */ + protected function _getWhereQuery($useDirty = true) + { + $where = array(); + $db = $this->_getTable()->getAdapter(); + $primaryKey = $this->_getPrimaryKey($useDirty); + $info = $this->_getTable()->info(); + $metadata = $info[Zend_Db_Table_Abstract::METADATA]; + + // retrieve recently updated row using primary keys + $where = array(); + foreach ($primaryKey as $column => $value) { + $tableName = $db->quoteIdentifier($info[Zend_Db_Table_Abstract::NAME], true); + $type = $metadata[$column]['DATA_TYPE']; + $columnName = $db->quoteIdentifier($column, true); + $where[] = $db->quoteInto("{$tableName}.{$columnName} = ?", $value, $type); + } + return $where; + } + + /** + * Refreshes properties from the database. + * + * @return void + */ + protected function _refresh() + { + $where = $this->_getWhereQuery(); + $row = $this->_getTable()->fetchRow($where); + + if (null === $row) { + throw new Zend_Db_Table_Row_Exception('Cannot refresh row as parent is missing'); + } + + $this->_data = $row->toArray(); + $this->_cleanData = $this->_data; + $this->_modifiedFields = array(); + } + + /** + * Allows pre-insert logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _insert() + { + } + + /** + * Allows post-insert logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _postInsert() + { + } + + /** + * Allows pre-update logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _update() + { + } + + /** + * Allows post-update logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _postUpdate() + { + } + + /** + * Allows pre-delete logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _delete() + { + } + + /** + * Allows post-delete logic to be applied to row. + * Subclasses may override this method. + * + * @return void + */ + protected function _postDelete() + { + } + + /** + * Prepares a table reference for lookup. + * + * Ensures all reference keys are set and properly formatted. + * + * @param Zend_Db_Table_Abstract $dependentTable + * @param Zend_Db_Table_Abstract $parentTable + * @param string $ruleKey + * @return array + */ + protected function _prepareReference(Zend_Db_Table_Abstract $dependentTable, Zend_Db_Table_Abstract $parentTable, $ruleKey) + { + $parentTableName = (get_class($parentTable) === 'Zend_Db_Table') ? $parentTable->getDefinitionConfigName() : get_class($parentTable); + $map = $dependentTable->getReference($parentTableName, $ruleKey); + + if (!isset($map[Zend_Db_Table_Abstract::REF_COLUMNS])) { + $parentInfo = $parentTable->info(); + $map[Zend_Db_Table_Abstract::REF_COLUMNS] = array_values((array) $parentInfo['primary']); + } + + $map[Zend_Db_Table_Abstract::COLUMNS] = (array) $map[Zend_Db_Table_Abstract::COLUMNS]; + $map[Zend_Db_Table_Abstract::REF_COLUMNS] = (array) $map[Zend_Db_Table_Abstract::REF_COLUMNS]; + + return $map; + } + + /** + * Query a dependent table to retrieve rows matching the current row. + * + * @param string|Zend_Db_Table_Abstract $dependentTable + * @param string OPTIONAL $ruleKey + * @param Zend_Db_Table_Select OPTIONAL $select + * @return Zend_Db_Table_Rowset_Abstract Query result from $dependentTable + * @throws Zend_Db_Table_Row_Exception If $dependentTable is not a table or is not loadable. + */ + public function findDependentRowset($dependentTable, $ruleKey = null, Zend_Db_Table_Select $select = null) + { + $db = $this->_getTable()->getAdapter(); + + if (is_string($dependentTable)) { + $dependentTable = $this->_getTableFromString($dependentTable); + } + + if (!$dependentTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($dependentTable); + if ($type == 'object') { + $type = get_class($dependentTable); + } + throw new Zend_Db_Table_Row_Exception("Dependent table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($dependentTable->getDefinition() == null)) { + $dependentTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if ($select === null) { + $select = $dependentTable->select(); + } else { + $select->setTable($dependentTable); + } + + $map = $this->_prepareReference($dependentTable, $this->_getTable(), $ruleKey); + + for ($i = 0; $i < count($map[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $parentColumnName = $db->foldCase($map[Zend_Db_Table_Abstract::REF_COLUMNS][$i]); + $value = $this->_data[$parentColumnName]; + // Use adapter from dependent table to ensure correct query construction + $dependentDb = $dependentTable->getAdapter(); + $dependentColumnName = $dependentDb->foldCase($map[Zend_Db_Table_Abstract::COLUMNS][$i]); + $dependentColumn = $dependentDb->quoteIdentifier($dependentColumnName, true); + $dependentInfo = $dependentTable->info(); + $type = $dependentInfo[Zend_Db_Table_Abstract::METADATA][$dependentColumnName]['DATA_TYPE']; + $select->where("$dependentColumn = ?", $value, $type); + } + + return $dependentTable->fetchAll($select); + } + + /** + * Query a parent table to retrieve the single row matching the current row. + * + * @param string|Zend_Db_Table_Abstract $parentTable + * @param string OPTIONAL $ruleKey + * @param Zend_Db_Table_Select OPTIONAL $select + * @return Zend_Db_Table_Row_Abstract Query result from $parentTable + * @throws Zend_Db_Table_Row_Exception If $parentTable is not a table or is not loadable. + */ + public function findParentRow($parentTable, $ruleKey = null, Zend_Db_Table_Select $select = null) + { + $db = $this->_getTable()->getAdapter(); + + if (is_string($parentTable)) { + $parentTable = $this->_getTableFromString($parentTable); + } + + if (!$parentTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($parentTable); + if ($type == 'object') { + $type = get_class($parentTable); + } + throw new Zend_Db_Table_Row_Exception("Parent table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($parentTable->getDefinition() == null)) { + $parentTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if ($select === null) { + $select = $parentTable->select(); + } else { + $select->setTable($parentTable); + } + + $map = $this->_prepareReference($this->_getTable(), $parentTable, $ruleKey); + + // iterate the map, creating the proper wheres + for ($i = 0; $i < count($map[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $dependentColumnName = $db->foldCase($map[Zend_Db_Table_Abstract::COLUMNS][$i]); + $value = $this->_data[$dependentColumnName]; + // Use adapter from parent table to ensure correct query construction + $parentDb = $parentTable->getAdapter(); + $parentColumnName = $parentDb->foldCase($map[Zend_Db_Table_Abstract::REF_COLUMNS][$i]); + $parentColumn = $parentDb->quoteIdentifier($parentColumnName, true); + $parentInfo = $parentTable->info(); + + // determine where part + $type = $parentInfo[Zend_Db_Table_Abstract::METADATA][$parentColumnName]['DATA_TYPE']; + $nullable = $parentInfo[Zend_Db_Table_Abstract::METADATA][$parentColumnName]['NULLABLE']; + if ($value === null && $nullable == true) { + $select->where("$parentColumn IS NULL"); + } elseif ($value === null && $nullable == false) { + return null; + } else { + $select->where("$parentColumn = ?", $value, $type); + } + + } + + return $parentTable->fetchRow($select); + } + + /** + * @param string|Zend_Db_Table_Abstract $matchTable + * @param string|Zend_Db_Table_Abstract $intersectionTable + * @param string OPTIONAL $callerRefRule + * @param string OPTIONAL $matchRefRule + * @param Zend_Db_Table_Select OPTIONAL $select + * @return Zend_Db_Table_Rowset_Abstract Query result from $matchTable + * @throws Zend_Db_Table_Row_Exception If $matchTable or $intersectionTable is not a table class or is not loadable. + */ + public function findManyToManyRowset($matchTable, $intersectionTable, $callerRefRule = null, + $matchRefRule = null, Zend_Db_Table_Select $select = null) + { + $db = $this->_getTable()->getAdapter(); + + if (is_string($intersectionTable)) { + $intersectionTable = $this->_getTableFromString($intersectionTable); + } + + if (!$intersectionTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($intersectionTable); + if ($type == 'object') { + $type = get_class($intersectionTable); + } + throw new Zend_Db_Table_Row_Exception("Intersection table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($intersectionTable->getDefinition() == null)) { + $intersectionTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if (is_string($matchTable)) { + $matchTable = $this->_getTableFromString($matchTable); + } + + if (! $matchTable instanceof Zend_Db_Table_Abstract) { + $type = gettype($matchTable); + if ($type == 'object') { + $type = get_class($matchTable); + } + throw new Zend_Db_Table_Row_Exception("Match table must be a Zend_Db_Table_Abstract, but it is $type"); + } + + // even if we are interacting between a table defined in a class and a + // table via extension, ensure to persist the definition + if (($tableDefinition = $this->_table->getDefinition()) !== null + && ($matchTable->getDefinition() == null)) { + $matchTable->setOptions(array(Zend_Db_Table_Abstract::DEFINITION => $tableDefinition)); + } + + if ($select === null) { + $select = $matchTable->select(); + } else { + $select->setTable($matchTable); + } + + // Use adapter from intersection table to ensure correct query construction + $interInfo = $intersectionTable->info(); + $interDb = $intersectionTable->getAdapter(); + $interName = $interInfo['name']; + $interSchema = isset($interInfo['schema']) ? $interInfo['schema'] : null; + $matchInfo = $matchTable->info(); + $matchName = $matchInfo['name']; + $matchSchema = isset($matchInfo['schema']) ? $matchInfo['schema'] : null; + + $matchMap = $this->_prepareReference($intersectionTable, $matchTable, $matchRefRule); + + for ($i = 0; $i < count($matchMap[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $interCol = $interDb->quoteIdentifier('i' . '.' . $matchMap[Zend_Db_Table_Abstract::COLUMNS][$i], true); + $matchCol = $interDb->quoteIdentifier('m' . '.' . $matchMap[Zend_Db_Table_Abstract::REF_COLUMNS][$i], true); + $joinCond[] = "$interCol = $matchCol"; + } + $joinCond = implode(' AND ', $joinCond); + + $select->from(array('i' => $interName), array(), $interSchema) + ->joinInner(array('m' => $matchName), $joinCond, Zend_Db_Select::SQL_WILDCARD, $matchSchema) + ->setIntegrityCheck(false); + + $callerMap = $this->_prepareReference($intersectionTable, $this->_getTable(), $callerRefRule); + + for ($i = 0; $i < count($callerMap[Zend_Db_Table_Abstract::COLUMNS]); ++$i) { + $callerColumnName = $db->foldCase($callerMap[Zend_Db_Table_Abstract::REF_COLUMNS][$i]); + $value = $this->_data[$callerColumnName]; + $interColumnName = $interDb->foldCase($callerMap[Zend_Db_Table_Abstract::COLUMNS][$i]); + $interCol = $interDb->quoteIdentifier("i.$interColumnName", true); + $interInfo = $intersectionTable->info(); + $type = $interInfo[Zend_Db_Table_Abstract::METADATA][$interColumnName]['DATA_TYPE']; + $select->where($interDb->quoteInto("$interCol = ?", $value, $type)); + } + + $stmt = $select->query(); + + $config = array( + 'table' => $matchTable, + 'data' => $stmt->fetchAll(Zend_Db::FETCH_ASSOC), + 'rowClass' => $matchTable->getRowClass(), + 'readOnly' => false, + 'stored' => true + ); + + $rowsetClass = $matchTable->getRowsetClass(); + if (!class_exists($rowsetClass)) { + try { + Zend_Loader::loadClass($rowsetClass); + } catch (Zend_Exception $e) { + throw new Zend_Db_Table_Row_Exception($e->getMessage(), $e->getCode(), $e); + } + } + $rowset = new $rowsetClass($config); + return $rowset; + } + + /** + * Turn magic function calls into non-magic function calls + * to the above methods. + * + * @param string $method + * @param array $args OPTIONAL Zend_Db_Table_Select query modifier + * @return Zend_Db_Table_Row_Abstract|Zend_Db_Table_Rowset_Abstract + * @throws Zend_Db_Table_Row_Exception If an invalid method is called. + */ + public function __call($method, array $args) + { + $matches = array(); + + if (count($args) && $args[0] instanceof Zend_Db_Table_Select) { + $select = $args[0]; + } else { + $select = null; + } + + /** + * Recognize methods for Has-Many cases: + * findParent() + * findParentBy() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^findParent(\w+?)(?:By(\w+))?$/', $method, $matches)) { + $class = $matches[1]; + $ruleKey1 = isset($matches[2]) ? $matches[2] : null; + return $this->findParentRow($class, $ruleKey1, $select); + } + + /** + * Recognize methods for Many-to-Many cases: + * findVia() + * findViaBy() + * findViaByAnd() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^find(\w+?)Via(\w+?)(?:By(\w+?)(?:And(\w+))?)?$/', $method, $matches)) { + $class = $matches[1]; + $viaClass = $matches[2]; + $ruleKey1 = isset($matches[3]) ? $matches[3] : null; + $ruleKey2 = isset($matches[4]) ? $matches[4] : null; + return $this->findManyToManyRowset($class, $viaClass, $ruleKey1, $ruleKey2, $select); + } + + /** + * Recognize methods for Belongs-To cases: + * find() + * findBy() + * Use the non-greedy pattern repeat modifier e.g. \w+? + */ + if (preg_match('/^find(\w+?)(?:By(\w+))?$/', $method, $matches)) { + $class = $matches[1]; + $ruleKey1 = isset($matches[2]) ? $matches[2] : null; + return $this->findDependentRowset($class, $ruleKey1, $select); + } + + throw new Zend_Db_Table_Row_Exception("Unrecognized method '$method()'"); + } + + + /** + * _getTableFromString + * + * @param string $tableName + * @return Zend_Db_Table_Abstract + */ + protected function _getTableFromString($tableName) + { + return Zend_Db_Table_Abstract::getTableFromString($tableName, $this->_table); + } + +} diff --git a/library/vendor/Zend/Db/Table/Row/Exception.php b/library/vendor/Zend/Db/Table/Row/Exception.php new file mode 100644 index 000000000..67718b732 --- /dev/null +++ b/library/vendor/Zend/Db/Table/Row/Exception.php @@ -0,0 +1,37 @@ +_table = $config['table']; + $this->_tableClass = get_class($this->_table); + } + if (isset($config['rowClass'])) { + $this->_rowClass = $config['rowClass']; + } + if (!class_exists($this->_rowClass)) { + Zend_Loader::loadClass($this->_rowClass); + } + if (isset($config['data'])) { + $this->_data = $config['data']; + } + if (isset($config['readOnly'])) { + $this->_readOnly = $config['readOnly']; + } + if (isset($config['stored'])) { + $this->_stored = $config['stored']; + } + + // set the count of rows + $this->_count = count($this->_data); + + $this->init(); + } + + /** + * Store data, class names, and state in serialized object + * + * @return array + */ + public function __sleep() + { + return array('_data', '_tableClass', '_rowClass', '_pointer', '_count', '_rows', '_stored', + '_readOnly'); + } + + /** + * Setup to do on wakeup. + * A de-serialized Rowset should not be assumed to have access to a live + * database connection, so set _connected = false. + * + * @return void + */ + public function __wakeup() + { + $this->_connected = false; + } + + /** + * Initialize object + * + * Called from {@link __construct()} as final step of object instantiation. + * + * @return void + */ + public function init() + { + } + + /** + * Return the connected state of the rowset. + * + * @return boolean + */ + public function isConnected() + { + return $this->_connected; + } + + /** + * Returns the table object, or null if this is disconnected rowset + * + * @return Zend_Db_Table_Abstract + */ + public function getTable() + { + return $this->_table; + } + + /** + * Set the table object, to re-establish a live connection + * to the database for a Rowset that has been de-serialized. + * + * @param Zend_Db_Table_Abstract $table + * @return boolean + * @throws Zend_Db_Table_Row_Exception + */ + public function setTable(Zend_Db_Table_Abstract $table) + { + $this->_table = $table; + $this->_connected = false; + // @todo This works only if we have iterated through + // the result set once to instantiate the rows. + foreach ($this as $row) { + $connected = $row->setTable($table); + if ($connected == true) { + $this->_connected = true; + } + } + $this->rewind(); + return $this->_connected; + } + + /** + * Query the class name of the Table object for which this + * Rowset was created. + * + * @return string + */ + public function getTableClass() + { + return $this->_tableClass; + } + + /** + * Rewind the Iterator to the first element. + * Similar to the reset() function for arrays in PHP. + * Required by interface Iterator. + * + * @return Zend_Db_Table_Rowset_Abstract Fluent interface. + */ + public function rewind() + { + $this->_pointer = 0; + return $this; + } + + /** + * Return the current element. + * Similar to the current() function for arrays in PHP + * Required by interface Iterator. + * + * @return Zend_Db_Table_Row_Abstract current element from the collection + */ + public function current() + { + if ($this->valid() === false) { + return null; + } + + // return the row object + return $this->_loadAndReturnRow($this->_pointer); + } + + /** + * Return the identifying key of the current element. + * Similar to the key() function for arrays in PHP. + * Required by interface Iterator. + * + * @return int + */ + public function key() + { + return $this->_pointer; + } + + /** + * Move forward to next element. + * Similar to the next() function for arrays in PHP. + * Required by interface Iterator. + * + * @return void + */ + public function next() + { + ++$this->_pointer; + } + + /** + * Check if there is a current element after calls to rewind() or next(). + * Used to check if we've iterated to the end of the collection. + * Required by interface Iterator. + * + * @return bool False if there's nothing more to iterate over + */ + public function valid() + { + return $this->_pointer >= 0 && $this->_pointer < $this->_count; + } + + /** + * Returns the number of elements in the collection. + * + * Implements Countable::count() + * + * @return int + */ + public function count() + { + return $this->_count; + } + + /** + * Take the Iterator to position $position + * Required by interface SeekableIterator. + * + * @param int $position the position to seek to + * @return Zend_Db_Table_Rowset_Abstract + * @throws Zend_Db_Table_Rowset_Exception + */ + public function seek($position) + { + $position = (int) $position; + if ($position < 0 || $position >= $this->_count) { + throw new Zend_Db_Table_Rowset_Exception("Illegal index $position"); + } + $this->_pointer = $position; + return $this; + } + + /** + * Check if an offset exists + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return boolean + */ + public function offsetExists($offset) + { + return isset($this->_data[(int) $offset]); + } + + /** + * Get the row for the given offset + * Required by the ArrayAccess implementation + * + * @param string $offset + * @return Zend_Db_Table_Row_Abstract + */ + public function offsetGet($offset) + { + $offset = (int) $offset; + if ($offset < 0 || $offset >= $this->_count) { + throw new Zend_Db_Table_Rowset_Exception("Illegal index $offset"); + } + $this->_pointer = $offset; + + return $this->current(); + } + + /** + * Does nothing + * Required by the ArrayAccess implementation + * + * @param string $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + } + + /** + * Does nothing + * Required by the ArrayAccess implementation + * + * @param string $offset + */ + public function offsetUnset($offset) + { + } + + /** + * Returns a Zend_Db_Table_Row from a known position into the Iterator + * + * @param int $position the position of the row expected + * @param bool $seek wether or not seek the iterator to that position after + * @return Zend_Db_Table_Row + * @throws Zend_Db_Table_Rowset_Exception + */ + public function getRow($position, $seek = false) + { + try { + $row = $this->_loadAndReturnRow($position); + } catch (Zend_Db_Table_Rowset_Exception $e) { + throw new Zend_Db_Table_Rowset_Exception('No row could be found at position ' . (int) $position, 0, $e); + } + + if ($seek == true) { + $this->seek($position); + } + + return $row; + } + + /** + * Returns all data as an array. + * + * Updates the $_data property with current row object values. + * + * @return array + */ + public function toArray() + { + // @todo This works only if we have iterated through + // the result set once to instantiate the rows. + foreach ($this->_rows as $i => $row) { + $this->_data[$i] = $row->toArray(); + } + return $this->_data; + } + + protected function _loadAndReturnRow($position) + { + if (!isset($this->_data[$position])) { + throw new Zend_Db_Table_Rowset_Exception("Data for provided position does not exist"); + } + + // do we already have a row object for this position? + if (empty($this->_rows[$position])) { + $this->_rows[$position] = new $this->_rowClass( + array( + 'table' => $this->_table, + 'data' => $this->_data[$position], + 'stored' => $this->_stored, + 'readOnly' => $this->_readOnly + ) + ); + + if ( $this->_table instanceof Zend_Db_Table_Abstract ) { + $info = $this->_table->info(); + + if ( $this->_rows[$position] instanceof Zend_Db_Table_Row_Abstract ) { + if ($info['cols'] == array_keys($this->_data[$position])) { + $this->_rows[$position]->setTable($this->getTable()); + } + } + } else { + $this->_rows[$position]->setTable(null); + } + } + + // return the row object + return $this->_rows[$position]; + } + +} diff --git a/library/vendor/Zend/Db/Table/Rowset/Exception.php b/library/vendor/Zend/Db/Table/Rowset/Exception.php new file mode 100644 index 000000000..75ebce43c --- /dev/null +++ b/library/vendor/Zend/Db/Table/Rowset/Exception.php @@ -0,0 +1,36 @@ +getAdapter()); + + $this->setTable($table); + } + + /** + * Return the table that created this select object + * + * @return Zend_Db_Table_Abstract + */ + public function getTable() + { + return $this->_table; + } + + /** + * Sets the primary table name and retrieves the table schema. + * + * @param Zend_Db_Table_Abstract $adapter + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function setTable(Zend_Db_Table_Abstract $table) + { + $this->_adapter = $table->getAdapter(); + $this->_info = $table->info(); + $this->_table = $table; + + return $this; + } + + /** + * Sets the integrity check flag. + * + * Setting this flag to false skips the checks for table joins, allowing + * 'hybrid' table rows to be created. + * + * @param Zend_Db_Table_Abstract $adapter + * @return Zend_Db_Select This Zend_Db_Select object. + */ + public function setIntegrityCheck($flag = true) + { + $this->_integrityCheck = $flag; + return $this; + } + + /** + * Tests query to determine if expressions or aliases columns exist. + * + * @return boolean + */ + public function isReadOnly() + { + $readOnly = false; + $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS); + $cols = $this->_info[Zend_Db_Table_Abstract::COLS]; + + if (!count($fields)) { + return $readOnly; + } + + foreach ($fields as $columnEntry) { + $column = $columnEntry[1]; + $alias = $columnEntry[2]; + + if ($alias !== null) { + $column = $alias; + } + + switch (true) { + case ($column == self::SQL_WILDCARD): + break; + + case ($column instanceof Zend_Db_Expr): + case (!in_array($column, $cols)): + $readOnly = true; + break 2; + } + } + + return $readOnly; + } + + /** + * Adds a FROM table and optional columns to the query. + * + * The table name can be expressed + * + * @param array|string|Zend_Db_Expr|Zend_Db_Table_Abstract $name The table name or an + associative array relating + table name to correlation + name. + * @param array|string|Zend_Db_Expr $cols The columns to select from this table. + * @param string $schema The schema name to specify, if any. + * @return Zend_Db_Table_Select This Zend_Db_Table_Select object. + */ + public function from($name, $cols = self::SQL_WILDCARD, $schema = null) + { + if ($name instanceof Zend_Db_Table_Abstract) { + $info = $name->info(); + $name = $info[Zend_Db_Table_Abstract::NAME]; + if (isset($info[Zend_Db_Table_Abstract::SCHEMA])) { + $schema = $info[Zend_Db_Table_Abstract::SCHEMA]; + } + } + + return $this->joinInner($name, null, $cols, $schema); + } + + /** + * Performs a validation on the select query before passing back to the parent class. + * Ensures that only columns from the primary Zend_Db_Table are returned in the result. + * + * @return string|null This object as a SELECT string (or null if a string cannot be produced) + */ + public function assemble() + { + $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS); + $primary = $this->_info[Zend_Db_Table_Abstract::NAME]; + $schema = $this->_info[Zend_Db_Table_Abstract::SCHEMA]; + + + if (count($this->_parts[self::UNION]) == 0) { + + // If no fields are specified we assume all fields from primary table + if (!count($fields)) { + $this->from($primary, self::SQL_WILDCARD, $schema); + $fields = $this->getPart(Zend_Db_Table_Select::COLUMNS); + } + + $from = $this->getPart(Zend_Db_Table_Select::FROM); + + if ($this->_integrityCheck !== false) { + foreach ($fields as $columnEntry) { + list($table, $column) = $columnEntry; + + // Check each column to ensure it only references the primary table + if ($column) { + if (!isset($from[$table]) || $from[$table]['tableName'] != $primary) { + throw new Zend_Db_Table_Select_Exception('Select query cannot join with another table'); + } + } + } + } + } + + return parent::assemble(); + } +} diff --git a/library/vendor/Zend/Db/Table/Select/Exception.php b/library/vendor/Zend/Db/Table/Select/Exception.php new file mode 100644 index 000000000..3fb6b026f --- /dev/null +++ b/library/vendor/Zend/Db/Table/Select/Exception.php @@ -0,0 +1,38 @@ + tags, cleans up newlines and indents, and runs + * htmlentities() before output. + * + * @param mixed $var The variable to dump. + * @param string $label OPTIONAL Label to prepend to output. + * @param bool $echo OPTIONAL Echo output if true. + * @return string + */ + public static function dump($var, $label=null, $echo=true) + { + // format the label + $label = ($label===null) ? '' : rtrim($label) . ' '; + + // var_dump the variable into a buffer and keep the output + ob_start(); + var_dump($var); + $output = ob_get_clean(); + + // neaten the newlines and indents + $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output); + if (self::getSapi() == 'cli') { + $output = PHP_EOL . $label + . PHP_EOL . $output + . PHP_EOL; + } else { + if(!extension_loaded('xdebug')) { + $flags = ENT_QUOTES; + // PHP 5.4.0+ + if (defined('ENT_SUBSTITUTE')) { + $flags = ENT_QUOTES | ENT_SUBSTITUTE; + } + $output = htmlspecialchars($output, $flags); + } + + $output = '
              '
              +                    . $label
              +                    . $output
              +                    . '
              '; + } + + if ($echo) { + echo($output); + } + return $output; + } + +} diff --git a/library/vendor/Zend/Dom/Exception.php b/library/vendor/Zend/Dom/Exception.php new file mode 100644 index 000000000..38ad1d155 --- /dev/null +++ b/library/vendor/Zend/Dom/Exception.php @@ -0,0 +1,34 @@ +setEncoding($encoding); + $this->setDocument($document); + } + + /** + * Set document encoding + * + * @param string $encoding + * @return Zend_Dom_Query + */ + public function setEncoding($encoding) + { + $this->_encoding = (null === $encoding) ? null : (string) $encoding; + return $this; + } + + /** + * Get document encoding + * + * @return null|string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set document to query + * + * @param string $document + * @param null|string $encoding Document encoding + * @return Zend_Dom_Query + */ + public function setDocument($document, $encoding = null) + { + if (0 === strlen($document)) { + return $this; + } + // breaking XML declaration to make syntax highlighting work + if ('<' . '?xml' == substr(trim($document), 0, 5)) { + if (preg_match('/]*xmlns="([^"]+)"[^>]*>/i', $document, $matches)) { + $this->_xpathNamespaces[] = $matches[1]; + return $this->setDocumentXhtml($document, $encoding); + } + return $this->setDocumentXml($document, $encoding); + } + if (strstr($document, 'DTD XHTML')) { + return $this->setDocumentXhtml($document, $encoding); + } + return $this->setDocumentHtml($document, $encoding); + } + + /** + * Register HTML document + * + * @param string $document + * @param null|string $encoding Document encoding + * @return Zend_Dom_Query + */ + public function setDocumentHtml($document, $encoding = null) + { + $this->_document = (string) $document; + $this->_docType = self::DOC_HTML; + if (null !== $encoding) { + $this->setEncoding($encoding); + } + return $this; + } + + /** + * Register XHTML document + * + * @param string $document + * @param null|string $encoding Document encoding + * @return Zend_Dom_Query + */ + public function setDocumentXhtml($document, $encoding = null) + { + $this->_document = (string) $document; + $this->_docType = self::DOC_XHTML; + if (null !== $encoding) { + $this->setEncoding($encoding); + } + return $this; + } + + /** + * Register XML document + * + * @param string $document + * @param null|string $encoding Document encoding + * @return Zend_Dom_Query + */ + public function setDocumentXml($document, $encoding = null) + { + $this->_document = (string) $document; + $this->_docType = self::DOC_XML; + if (null !== $encoding) { + $this->setEncoding($encoding); + } + return $this; + } + + /** + * Retrieve current document + * + * @return string + */ + public function getDocument() + { + return $this->_document; + } + + /** + * Get document type + * + * @return string + */ + public function getDocumentType() + { + return $this->_docType; + } + + /** + * Get any DOMDocument errors found + * + * @return false|array + */ + public function getDocumentErrors() + { + return $this->_documentErrors; + } + + /** + * Perform a CSS selector query + * + * @param string $query + * @return Zend_Dom_Query_Result + */ + public function query($query) + { + $xpathQuery = Zend_Dom_Query_Css2Xpath::transform($query); + return $this->queryXpath($xpathQuery, $query); + } + + /** + * Perform an XPath query + * + * @param string|array $xpathQuery + * @param string $query CSS selector query + * @return Zend_Dom_Query_Result + */ + public function queryXpath($xpathQuery, $query = null) + { + if (null === ($document = $this->getDocument())) { + throw new Zend_Dom_Exception('Cannot query; no document registered'); + } + + $encoding = $this->getEncoding(); + libxml_use_internal_errors(true); + if (null === $encoding) { + $domDoc = new DOMDocument('1.0'); + } else { + $domDoc = new DOMDocument('1.0', $encoding); + } + $type = $this->getDocumentType(); + switch ($type) { + case self::DOC_XML: + try { + $domDoc = Zend_Xml_Security::scan($document, $domDoc); + $success = ($domDoc !== false); + } catch (Zend_Xml_Exception $e) { + throw new Zend_Dom_Exception( + $e->getMessage() + ); + } + break; + case self::DOC_HTML: + case self::DOC_XHTML: + default: + $success = $domDoc->loadHTML($document); + break; + } + $errors = libxml_get_errors(); + if (!empty($errors)) { + $this->_documentErrors = $errors; + libxml_clear_errors(); + } + libxml_use_internal_errors(false); + + if (!$success) { + throw new Zend_Dom_Exception(sprintf('Error parsing document (type == %s)', $type)); + } + + $nodeList = $this->_getNodeList($domDoc, $xpathQuery); + return new Zend_Dom_Query_Result($query, $xpathQuery, $domDoc, $nodeList); + } + + /** + * Register XPath namespaces + * + * @param array $xpathNamespaces + * @return void + */ + public function registerXpathNamespaces($xpathNamespaces) + { + $this->_xpathNamespaces = $xpathNamespaces; + } + + /** + * Prepare node list + * + * @param DOMDocument $document + * @param string|array $xpathQuery + * @return array + */ + protected function _getNodeList($document, $xpathQuery) + { + $xpath = new DOMXPath($document); + foreach ($this->_xpathNamespaces as $prefix => $namespaceUri) { + $xpath->registerNamespace($prefix, $namespaceUri); + } + $xpathQuery = (string) $xpathQuery; + if (preg_match_all('|\[contains\((@[a-z0-9_-]+),\s?\' |i', $xpathQuery, $matches)) { + foreach ($matches[1] as $attribute) { + $queryString = '//*[' . $attribute . ']'; + $attributeName = substr($attribute, 1); + $nodes = $xpath->query($queryString); + foreach ($nodes as $node) { + $attr = $node->attributes->getNamedItem($attributeName); + $attr->value = ' ' . $attr->value . ' '; + } + } + } + return $xpath->query($xpathQuery); + } +} diff --git a/library/vendor/Zend/Dom/Query/Css2Xpath.php b/library/vendor/Zend/Dom/Query/Css2Xpath.php new file mode 100644 index 000000000..21428042c --- /dev/null +++ b/library/vendor/Zend/Dom/Query/Css2Xpath.php @@ -0,0 +1,169 @@ +\s+|', '>', $path); + $segments = preg_split('/\s+/', $path); + foreach ($segments as $key => $segment) { + $pathSegment = self::_tokenize($segment); + if (0 == $key) { + if (0 === strpos($pathSegment, '[contains(')) { + $paths[0] .= '*' . ltrim($pathSegment, '*'); + } else { + $paths[0] .= $pathSegment; + } + continue; + } + if (0 === strpos($pathSegment, '[contains(')) { + foreach ($paths as $key => $xpath) { + $paths[$key] .= '//*' . ltrim($pathSegment, '*'); + $paths[] = $xpath . $pathSegment; + } + } else { + foreach ($paths as $key => $xpath) { + $paths[$key] .= '//' . $pathSegment; + } + } + } + + if (1 == count($paths)) { + return $paths[0]; + } + return implode('|', $paths); + } + + /** + * Tokenize CSS expressions to XPath + * + * @param string $expression + * @return string + */ + protected static function _tokenize($expression) + { + // Child selectors + $expression = str_replace('>', '/', $expression); + + // IDs + $expression = preg_replace('|#([a-z][a-z0-9_-]*)|i', '[@id=\'$1\']', $expression); + $expression = preg_replace('|(?_cssQuery = $cssQuery; + $this->_xpathQuery = $xpathQuery; + $this->_document = $document; + $this->_nodeList = $nodeList; + } + + /** + * Retrieve CSS Query + * + * @return string + */ + public function getCssQuery() + { + return $this->_cssQuery; + } + + /** + * Retrieve XPath query + * + * @return string + */ + public function getXpathQuery() + { + return $this->_xpathQuery; + } + + /** + * Retrieve DOMDocument + * + * @return DOMDocument + */ + public function getDocument() + { + return $this->_document; + } + + /** + * Iterator: rewind to first element + * + * @return void + */ + public function rewind() + { + $this->_position = 0; + return $this->_nodeList->item(0); + } + + /** + * Iterator: is current position valid? + * + * @return bool + */ + public function valid() + { + if (in_array($this->_position, range(0, $this->_nodeList->length - 1)) && $this->_nodeList->length > 0) { + return true; + } + return false; + } + + /** + * Iterator: return current element + * + * @return DOMElement + */ + public function current() + { + return $this->_nodeList->item($this->_position); + } + + /** + * Iterator: return key of current element + * + * @return int + */ + public function key() + { + return $this->_position; + } + + /** + * Iterator: move to next element + * + * @return void + */ + public function next() + { + ++$this->_position; + return $this->_nodeList->item($this->_position); + } + + /** + * Countable: get count + * + * @return int + */ + public function count() + { + return $this->_nodeList->length; + } +} diff --git a/library/vendor/Zend/EventManager/Event.php b/library/vendor/Zend/EventManager/Event.php new file mode 100644 index 000000000..60d175dd3 --- /dev/null +++ b/library/vendor/Zend/EventManager/Event.php @@ -0,0 +1,223 @@ +setName($name); + } + + if (null !== $target) { + $this->setTarget($target); + } + + if (null !== $params) { + $this->setParams($params); + } + } + + /** + * Get event name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get the event target + * + * This may be either an object, or the name of a static method. + * + * @return string|object + */ + public function getTarget() + { + return $this->target; + } + + /** + * Set parameters + * + * Overwrites parameters + * + * @param array|ArrayAccess|object $params + * @return Event + */ + public function setParams($params) + { + if (!is_array($params) && !is_object($params)) { + throw new Zend_EventManager_Exception_InvalidArgumentException(sprintf( + 'Event parameters must be an array or object; received "%s"', + (is_object($params) ? get_class($params) : gettype($params)) + )); + } + + $this->params = $params; + return $this; + } + + /** + * Get all parameters + * + * @return array|object|ArrayAccess + */ + public function getParams() + { + return $this->params; + } + + /** + * Get an individual parameter + * + * If the parameter does not exist, the $default value will be returned. + * + * @param string|int $name + * @param mixed $default + * @return mixed + */ + public function getParam($name, $default = null) + { + // Check in params that are arrays or implement array access + if (is_array($this->params) || $this->params instanceof ArrayAccess) { + if (!isset($this->params[$name])) { + return $default; + } + + return $this->params[$name]; + } + + // Check in normal objects + if (!isset($this->params->{$name})) { + return $default; + } + return $this->params->{$name}; + } + + /** + * Set the event name + * + * @param string $name + * @return Zend_EventManager_Event + */ + public function setName($name) + { + $this->name = (string) $name; + return $this; + } + + /** + * Set the event target/context + * + * @param null|string|object $target + * @return Zend_EventManager_Event + */ + public function setTarget($target) + { + $this->target = $target; + return $this; + } + + /** + * Set an individual parameter to a value + * + * @param string|int $name + * @param mixed $value + * @return Zend_EventManager_Event + */ + public function setParam($name, $value) + { + if (is_array($this->params) || $this->params instanceof ArrayAccess) { + // Arrays or objects implementing array access + $this->params[$name] = $value; + } else { + // Objects + $this->params->{$name} = $value; + } + return $this; + } + + /** + * Stop further event propagation + * + * @param bool $flag + * @return void + */ + public function stopPropagation($flag = true) + { + $this->stopPropagation = (bool) $flag; + } + + /** + * Is propagation stopped? + * + * @return bool + */ + public function propagationIsStopped() + { + return $this->stopPropagation; + } +} diff --git a/library/vendor/Zend/EventManager/EventCollection.php b/library/vendor/Zend/EventManager/EventCollection.php new file mode 100644 index 000000000..db7574139 --- /dev/null +++ b/library/vendor/Zend/EventManager/EventCollection.php @@ -0,0 +1,108 @@ +setIdentifiers($identifiers); + } + + /** + * Set the event class to utilize + * + * @param string $class + * @return Zend_EventManager_EventManager + */ + public function setEventClass($class) + { + $this->eventClass = $class; + return $this; + } + + /** + * Set static collections container + * + * @param Zend_EventManager_StaticEventCollection $collections + * @return void + */ + public function setSharedCollections(Zend_EventManager_SharedEventCollection $collections) + { + $this->sharedCollections = $collections; + return $this; + } + + /** + * Remove any shared collections + * + * Sets {@link $sharedCollections} to boolean false to disable ability + * to lazy-load static event manager instance. + * + * @return void + */ + public function unsetSharedCollections() + { + $this->sharedCollections = false; + } + + /** + * Get static collections container + * + * @return false|Zend_EventManager_SharedEventCollection + */ + public function getSharedCollections() + { + if (null === $this->sharedCollections) { + $this->setSharedCollections(Zend_EventManager_StaticEventManager::getInstance()); + } + return $this->sharedCollections; + } + + /** + * Get the identifier(s) for this Zend_EventManager_EventManager + * + * @return array + */ + public function getIdentifiers() + { + return $this->identifiers; + } + + /** + * Set the identifiers (overrides any currently set identifiers) + * + * @param string|int|array|Traversable $identifiers + * @return Zend_EventManager_EventManager + */ + public function setIdentifiers($identifiers) + { + if (is_array($identifiers) || $identifiers instanceof Traversable) { + $this->identifiers = array_unique((array) $identifiers); + } elseif ($identifiers !== null) { + $this->identifiers = array($identifiers); + } + return $this; + } + + /** + * Add some identifier(s) (appends to any currently set identifiers) + * + * @param string|int|array|Traversable $identifiers + * @return Zend_EventManager_EventManager + */ + public function addIdentifiers($identifiers) + { + if (is_array($identifiers) || $identifiers instanceof Traversable) { + $this->identifiers = array_unique($this->identifiers + (array) $identifiers); + } elseif ($identifiers !== null) { + $this->identifiers = array_unique(array_merge($this->identifiers, array($identifiers))); + } + return $this; + } + + /** + * Trigger all listeners for a given event + * + * Can emulate triggerUntil() if the last argument provided is a callback. + * + * @param string $event + * @param string|object $target Object calling emit, or symbol describing target (such as static method name) + * @param array|ArrayAccess $argv Array of arguments; typically, should be associative + * @param null|callback $callback + * @return Zend_EventManager_ResponseCollection All listener return values + */ + public function trigger($event, $target = null, $argv = array(), $callback = null) + { + if ($event instanceof Zend_EventManager_EventDescription) { + $e = $event; + $event = $e->getName(); + $callback = $target; + } elseif ($target instanceof Zend_EventManager_EventDescription) { + $e = $target; + $e->setName($event); + $callback = $argv; + } elseif ($argv instanceof Zend_EventManager_EventDescription) { + $e = $argv; + $e->setName($event); + $e->setTarget($target); + } else { + $e = new $this->eventClass(); + $e->setName($event); + $e->setTarget($target); + $e->setParams($argv); + } + + if ($callback && !is_callable($callback)) { + throw new Zend_Stdlib_Exception_InvalidCallbackException('Invalid callback provided'); + } + + return $this->triggerListeners($event, $e, $callback); + } + + /** + * Trigger listeners until return value of one causes a callback to + * evaluate to true + * + * Triggers listeners until the provided callback evaluates the return + * value of one as true, or until all listeners have been executed. + * + * @param string $event + * @param string|object $target Object calling emit, or symbol describing target (such as static method name) + * @param array|ArrayAccess $argv Array of arguments; typically, should be associative + * @param Callable $callback + * @throws Zend_Stdlib_Exception_InvalidCallbackException if invalid callback provided + */ + public function triggerUntil($event, $target, $argv = null, $callback = null) + { + if ($event instanceof Zend_EventManager_EventDescription) { + $e = $event; + $event = $e->getName(); + $callback = $target; + } elseif ($target instanceof Zend_EventManager_EventDescription) { + $e = $target; + $e->setName($event); + $callback = $argv; + } elseif ($argv instanceof Zend_EventManager_EventDescription) { + $e = $argv; + $e->setName($event); + $e->setTarget($target); + } else { + $e = new $this->eventClass(); + $e->setName($event); + $e->setTarget($target); + $e->setParams($argv); + } + + if (!is_callable($callback)) { + throw new Zend_Stdlib_Exception_InvalidCallbackException('Invalid callback provided'); + } + + return $this->triggerListeners($event, $e, $callback); + } + + /** + * Attach a listener to an event + * + * The first argument is the event, and the next argument describes a + * callback that will respond to that event. A CallbackHandler instance + * describing the event listener combination will be returned. + * + * The last argument indicates a priority at which the event should be + * executed. By default, this value is 1; however, you may set it for any + * integer value. Higher values have higher priority (i.e., execute first). + * + * You can specify "*" for the event name. In such cases, the listener will + * be triggered for every event. + * + * @param string|array|Zend_EventManager_ListenerAggregate $event An event or array of event names. If a ListenerAggregate, proxies to {@link attachAggregate()}. + * @param callback|int $callback If string $event provided, expects PHP callback; for a ListenerAggregate $event, this will be the priority + * @param int $priority If provided, the priority at which to register the callback + * @return Zend_Stdlib_CallbackHandler|mixed CallbackHandler if attaching callback (to allow later unsubscribe); mixed if attaching aggregate + */ + public function attach($event, $callback = null, $priority = 1) + { + // Proxy ListenerAggregate arguments to attachAggregate() + if ($event instanceof Zend_EventManager_ListenerAggregate) { + return $this->attachAggregate($event, $callback); + } + + // Null callback is invalid + if (null === $callback) { + throw new Zend_EventManager_Exception_InvalidArgumentException(sprintf( + '%s: expects a callback; none provided', + __METHOD__ + )); + } + + // Array of events should be registered individually, and return an array of all listeners + if (is_array($event)) { + $listeners = array(); + foreach ($event as $name) { + $listeners[] = $this->attach($name, $callback, $priority); + } + return $listeners; + } + + // If we don't have a priority queue for the event yet, create one + if (empty($this->events[$event])) { + $this->events[$event] = new Zend_Stdlib_PriorityQueue(); + } + + // Create a callback handler, setting the event and priority in its metadata + $listener = new Zend_Stdlib_CallbackHandler($callback, array('event' => $event, 'priority' => $priority)); + + // Inject the callback handler into the queue + $this->events[$event]->insert($listener, $priority); + return $listener; + } + + /** + * Attach a listener aggregate + * + * Listener aggregates accept an EventCollection instance, and call attach() + * one or more times, typically to attach to multiple events using local + * methods. + * + * @param Zend_EventManager_ListenerAggregate $aggregate + * @param int $priority If provided, a suggested priority for the aggregate to use + * @return mixed return value of {@link Zend_EventManager_ListenerAggregate::attach()} + */ + public function attachAggregate(Zend_EventManager_ListenerAggregate $aggregate, $priority = 1) + { + return $aggregate->attach($this, $priority); + } + + /** + * Unsubscribe a listener from an event + * + * @param Zend_Stdlib_CallbackHandler|Zend_EventManager_ListenerAggregate $listener + * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found + * @throws Zend_EventManager_Exception_InvalidArgumentException if invalid listener provided + */ + public function detach($listener) + { + if ($listener instanceof Zend_EventManager_ListenerAggregate) { + return $this->detachAggregate($listener); + } + + if (!$listener instanceof Zend_Stdlib_CallbackHandler) { + throw new Zend_EventManager_Exception_InvalidArgumentException(sprintf( + '%s: expected a Zend_EventManager_ListenerAggregate or Zend_Stdlib_CallbackHandler; received "%s"', + __METHOD__, + (is_object($listener) ? get_class($listener) : gettype($listener)) + )); + } + + $event = $listener->getMetadatum('event'); + if (!$event || empty($this->events[$event])) { + return false; + } + $return = $this->events[$event]->remove($listener); + if (!$return) { + return false; + } + if (!count($this->events[$event])) { + unset($this->events[$event]); + } + return true; + } + + /** + * Detach a listener aggregate + * + * Listener aggregates accept an EventCollection instance, and call detach() + * of all previously attached listeners. + * + * @param Zend_EventManager_ListenerAggregate $aggregate + * @return mixed return value of {@link Zend_EventManager_ListenerAggregate::detach()} + */ + public function detachAggregate(Zend_EventManager_ListenerAggregate $aggregate) + { + return $aggregate->detach($this); + } + + /** + * Retrieve all registered events + * + * @return array + */ + public function getEvents() + { + return array_keys($this->events); + } + + /** + * Retrieve all listeners for a given event + * + * @param string $event + * @return Zend_Stdlib_PriorityQueue + */ + public function getListeners($event) + { + if (!array_key_exists($event, $this->events)) { + return new Zend_Stdlib_PriorityQueue(); + } + return $this->events[$event]; + } + + /** + * Clear all listeners for a given event + * + * @param string $event + * @return void + */ + public function clearListeners($event) + { + if (!empty($this->events[$event])) { + unset($this->events[$event]); + } + } + + /** + * Prepare arguments + * + * Use this method if you want to be able to modify arguments from within a + * listener. It returns an ArrayObject of the arguments, which may then be + * passed to trigger() or triggerUntil(). + * + * @param array $args + * @return ArrayObject + */ + public function prepareArgs(array $args) + { + return new ArrayObject($args); + } + + /** + * Trigger listeners + * + * Actual functionality for triggering listeners, to which both trigger() and triggerUntil() + * delegate. + * + * @param string $event Event name + * @param EventDescription $e + * @param null|callback $callback + * @return ResponseCollection + */ + protected function triggerListeners($event, Zend_EventManager_EventDescription $e, $callback = null) + { + $responses = new Zend_EventManager_ResponseCollection; + $listeners = $this->getListeners($event); + + // Add shared/wildcard listeners to the list of listeners, + // but don't modify the listeners object + $sharedListeners = $this->getSharedListeners($event); + $sharedWildcardListeners = $this->getSharedListeners('*'); + $wildcardListeners = $this->getListeners('*'); + if (count($sharedListeners) || count($sharedWildcardListeners) || count($wildcardListeners)) { + $listeners = clone $listeners; + } + + // Shared listeners on this specific event + $this->insertListeners($listeners, $sharedListeners); + + // Shared wildcard listeners + $this->insertListeners($listeners, $sharedWildcardListeners); + + // Add wildcard listeners + $this->insertListeners($listeners, $wildcardListeners); + + if ($listeners->isEmpty()) { + return $responses; + } + + foreach ($listeners as $listener) { + // Trigger the listener's callback, and push its result onto the + // response collection + $responses->push(call_user_func($listener->getCallback(), $e)); + + // If the event was asked to stop propagating, do so + if ($e->propagationIsStopped()) { + $responses->setStopped(true); + break; + } + + // If the result causes our validation callback to return true, + // stop propagation + if ($callback && call_user_func($callback, $responses->last())) { + $responses->setStopped(true); + break; + } + } + + return $responses; + } + + /** + * Get list of all listeners attached to the shared collection for + * identifiers registered by this instance + * + * @param string $event + * @return array + */ + protected function getSharedListeners($event) + { + if (!$sharedCollections = $this->getSharedCollections()) { + return array(); + } + + $identifiers = $this->getIdentifiers(); + $sharedListeners = array(); + + foreach ($identifiers as $id) { + if (!$listeners = $sharedCollections->getListeners($id, $event)) { + continue; + } + + if (!is_array($listeners) && !($listeners instanceof Traversable)) { + continue; + } + + foreach ($listeners as $listener) { + if (!$listener instanceof Zend_Stdlib_CallbackHandler) { + continue; + } + $sharedListeners[] = $listener; + } + } + + return $sharedListeners; + } + + /** + * Add listeners to the master queue of listeners + * + * Used to inject shared listeners and wildcard listeners. + * + * @param Zend_Stdlib_PriorityQueue $masterListeners + * @param Zend_Stdlib_PriorityQueue $listeners + * @return void + */ + protected function insertListeners($masterListeners, $listeners) + { + if (!count($listeners)) { + return; + } + + foreach ($listeners as $listener) { + $priority = $listener->getMetadatum('priority'); + if (null === $priority) { + $priority = 1; + } elseif (is_array($priority)) { + // If we have an array, likely using PriorityQueue. Grab first + // element of the array, as that's the actual priority. + $priority = array_shift($priority); + } + $masterListeners->insert($listener, $priority); + } + } +} diff --git a/library/vendor/Zend/EventManager/EventManagerAware.php b/library/vendor/Zend/EventManager/EventManagerAware.php new file mode 100644 index 000000000..1e9d85664 --- /dev/null +++ b/library/vendor/Zend/EventManager/EventManagerAware.php @@ -0,0 +1,40 @@ +setExtractFlags(self::EXTR_BOTH); + + // Iterate and remove any matches + $removed = false; + $items = array(); + $this->rewind(); + while (!$this->isEmpty()) { + $item = $this->extract(); + if ($item['data'] === $datum) { + $removed = true; + continue; + } + $items[] = $item; + } + + // Repopulate + foreach ($items as $item) { + $this->insert($item['data'], $item['priority']); + } + + $this->setExtractFlags(self::EXTR_DATA); + return $removed; + } + + /** + * Iterate the next filter in the chain + * + * Iterates and calls the next filter in the chain. + * + * @param mixed $context + * @param array $params + * @param Zend_EventManager_Filter_FilterIterator $chain + * @return void + */ + public function next($context = null, array $params = array(), $chain = null) + { + if (empty($context) || $chain->isEmpty()) { + return; + } + + $next = $this->extract(); + if (!$next instanceof Zend_Stdlib_CallbackHandler) { + return; + } + + $return = call_user_func($next->getCallback(), $context, $params, $chain); + return $return; + } +} diff --git a/library/vendor/Zend/EventManager/FilterChain.php b/library/vendor/Zend/EventManager/FilterChain.php new file mode 100644 index 000000000..b52d059a7 --- /dev/null +++ b/library/vendor/Zend/EventManager/FilterChain.php @@ -0,0 +1,134 @@ +filters = new Zend_EventManager_Filter_FilterIterator(); + } + + /** + * Apply the filters + * + * Begins iteration of the filters. + * + * @param mixed $context Object under observation + * @param mixed $argv Associative array of arguments + * @return mixed + */ + public function run($context, array $argv = array()) + { + $chain = clone $this->getFilters(); + + if ($chain->isEmpty()) { + return; + } + + $next = $chain->extract(); + if (!$next instanceof Zend_Stdlib_CallbackHandler) { + return; + } + + return call_user_func($next->getCallback(), $context, $argv, $chain); + } + + /** + * Connect a filter to the chain + * + * @param callback $callback PHP Callback + * @param int $priority Priority in the queue at which to execute; defaults to 1 (higher numbers == higher priority) + * @return Zend_Stdlib_CallbackHandler (to allow later unsubscribe) + */ + public function attach($callback, $priority = 1) + { + if (empty($callback)) { + throw new Zend_Stdlib_Exception_InvalidCallbackException('No callback provided'); + } + $filter = new Zend_Stdlib_CallbackHandler($callback, array('priority' => $priority)); + $this->filters->insert($filter, $priority); + return $filter; + } + + /** + * Detach a filter from the chain + * + * @param Zend_Stdlib_CallbackHandler $filter + * @return bool Returns true if filter found and unsubscribed; returns false otherwise + */ + public function detach(Zend_Stdlib_CallbackHandler $filter) + { + return $this->filters->remove($filter); + } + + /** + * Retrieve all filters + * + * @return Zend_EventManager_Filter_FilterIterator + */ + public function getFilters() + { + return $this->filters; + } + + /** + * Clear all filters + * + * @return void + */ + public function clearFilters() + { + $this->filters = new Zend_EventManager_Filter_FilterIterator(); + } + + /** + * Return current responses + * + * Only available while the chain is still being iterated. Returns the + * current ResponseCollection. + * + * @return null|Zend_EventManager_ResponseCollection + */ + public function getResponses() + { + return $this->responses; + } +} diff --git a/library/vendor/Zend/EventManager/GlobalEventManager.php b/library/vendor/Zend/EventManager/GlobalEventManager.php new file mode 100644 index 000000000..41da3437c --- /dev/null +++ b/library/vendor/Zend/EventManager/GlobalEventManager.php @@ -0,0 +1,147 @@ +trigger($event, $context, $argv); + } + + /** + * Trigger listeenrs until return value of one causes a callback to evaluate + * to true. + * + * @param string $event + * @param string|object $context + * @param array|object $argv + * @param callback $callback + * @return Zend_EventManager_ResponseCollection + */ + public static function triggerUntil($event, $context, $argv, $callback) + { + return self::getEventCollection()->triggerUntil($event, $context, $argv, $callback); + } + + /** + * Attach a listener to an event + * + * @param string $event + * @param callback $callback + * @param int $priority + * @return Zend_Stdlib_CallbackHandler + */ + public static function attach($event, $callback, $priority = 1) + { + return self::getEventCollection()->attach($event, $callback, $priority); + } + + /** + * Detach a callback from a listener + * + * @param Zend_Stdlib_CallbackHandler $listener + * @return bool + */ + public static function detach(Zend_Stdlib_CallbackHandler $listener) + { + return self::getEventCollection()->detach($listener); + } + + /** + * Retrieve list of events this object manages + * + * @return array + */ + public static function getEvents() + { + return self::getEventCollection()->getEvents(); + } + + /** + * Retrieve all listeners for a given event + * + * @param string $event + * @return Zend_Stdlib_PriorityQueue|array + */ + public static function getListeners($event) + { + return self::getEventCollection()->getListeners($event); + } + + /** + * Clear all listeners for a given event + * + * @param string $event + * @return void + */ + public static function clearListeners($event) + { + return self::getEventCollection()->clearListeners($event); + } +} diff --git a/library/vendor/Zend/EventManager/ListenerAggregate.php b/library/vendor/Zend/EventManager/ListenerAggregate.php new file mode 100644 index 000000000..6ffe131f4 --- /dev/null +++ b/library/vendor/Zend/EventManager/ListenerAggregate.php @@ -0,0 +1,53 @@ + true, + self::IT_MODE_KEEP => true, + ); + + if (!isset($expected[$mode])) { + throw new InvalidArgumentException(sprintf('Invalid iterator mode specified ("%s")', $mode)); + } + + $this->mode = $mode; + } + + /** + * Return last element in the stack + * + * @return mixed + */ + public function bottom() + { + $this->rewind(); + $value = array_pop($this->stack); + array_push($this->stack, $value); + return $value; + } + + /** + * Countable: return count of items in the stack + * + * @return int + */ + public function count() + { + return $this->count; + } + + /** + * Iterator: return current item in the stack + * + * @return mixed + */ + public function current() + { + if (!$this->stack) { + $this->rewind(); + } + return current($this->stack); + } + + /** + * Get iteration mode + * + * @return int + */ + public function getIteratorMode() + { + return $this->mode; + } + + /** + * Is the stack empty? + * + * @return bool + */ + public function isEmpty() + { + return ($this->count === 0); + } + + /** + * Iterator: return key of current item in the stack + * + * @return mixed + */ + public function key() + { + if (!$this->stack) { + $this->rewind(); + } + return key($this->stack); + } + + /** + * Iterator: advance pointer to next item in the stack + * + * @return void + */ + public function next() + { + if (!$this->stack) { + $this->rewind(); + } + return next($this->stack); + } + + /** + * ArrayAccess: does an item exist at the specified offset? + * + * @param mixed $index + * @return bool + */ + public function offsetExists($index) + { + return array_key_exists($index, $this->data); + } + + /** + * ArrayAccess: get the item at the specified offset + * + * @param mixed $index + * @return mixed + * @throws OutOfRangeException + */ + public function offsetGet($index) + { + if (!$this->offsetExists($index)) { + throw OutOfRangeException(sprintf('Invalid index ("%s") specified', $index)); + } + return $this->data[$index]; + } + + /** + * ArrayAccess: add an item at the specified offset + * + * @param mixed $index + * @param mixed $newval + * @return void + */ + public function offsetSet($index, $newval) + { + $this->data[$index] = $newval; + $this->stack = false; + $this->count++; + } + + /** + * ArrayAccess: unset the item at the specified offset + * + * @param mixed $index + * @return void + * @throws OutOfRangeException + */ + public function offsetUnset($index) + { + if (!$this->offsetExists($index)) { + throw OutOfRangeException(sprintf('Invalid index ("%s") specified', $index)); + } + unset($this->data[$index]); + $this->stack = false; + $this->count--; + } + + /** + * Pop a node from the end of the stack + * + * @return mixed + * @throws RuntimeException + */ + public function pop() + { + $val = array_pop($this->data); + $this->stack = false; + $this->count--; + return $val; + } + + /** + * Move the iterator to the previous node + * + * @todo Does this need to be implemented? + * @return void + */ + public function prev() + { + } + + /** + * Push an element to the list + * + * @param mixed $value + * @return void + */ + public function push($value) + { + array_push($this->data, $value); + $this->count++; + $this->stack = false; + } + + /** + * Iterator: rewind to beginning of stack + * + * @return void + */ + public function rewind() + { + if (is_array($this->stack)) { + return reset($this->stack); + } + $this->stack = array_reverse($this->data, true); + } + + /** + * Serialize the storage + * + * @return string + */ + public function serialize() + { + return serialize($this->data); + } + + /** + * Shifts a node from the beginning of the list + * + * @return mixed + * @throws RuntimeException + */ + public function shift() + { + $val = array_shift($this->data); + $this->stack = false; + $this->count--; + return $val; + } + + /** + * Peek at the top node of the stack + * + * @return mixed + */ + public function top() + { + $this->rewind(); + $value = array_shift($this->stack); + array_unshift($this->stack, $value); + return $value; + } + + /** + * Unserialize the storage + * + * @param string + * @return void + */ + public function unserialize($serialized) + { + $this->data = unserialize($serialized); + $this->stack = false; + } + + /** + * Unshift a node onto the beginning of the list + * + * @param mixed $value + * @return void + */ + public function unshift($value) + { + array_unshift($this->data, $value); + $this->count++; + $this->stack = false; + } + + /** + * Iterator: is the current pointer valid? + * + * @return bool + */ + public function valid() + { + $key = key($this->stack); + $var = ($key !== null && $key !== false); + return $var; + } + } +} + +/** + * Collection of signal handler return values + * + * @category Zend + * @package Zend_EventManager + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_EventManager_ResponseCollection extends SplStack +{ + protected $stopped = false; + + /** + * Did the last response provided trigger a short circuit of the stack? + * + * @return bool + */ + public function stopped() + { + return $this->stopped; + } + + /** + * Mark the collection as stopped (or its opposite) + * + * @param bool $flag + * @return Zend_EventManager_ResponseCollection + */ + public function setStopped($flag) + { + $this->stopped = (bool) $flag; + return $this; + } + + /** + * Convenient access to the first handler return value. + * + * @return mixed The first handler return value + */ + public function first() + { + return parent::bottom(); + } + + /** + * Convenient access to the last handler return value. + * + * If the collection is empty, returns null. Otherwise, returns value + * returned by last handler. + * + * @return mixed The last handler return value + */ + public function last() + { + if (count($this) === 0) { + return null; + } + return parent::top(); + } + + /** + * Check if any of the responses match the given value. + * + * @param mixed $value The value to look for among responses + */ + public function contains($value) + { + foreach ($this as $response) { + if ($response === $value) { + return true; + } + } + return false; + } +} diff --git a/library/vendor/Zend/EventManager/SharedEventCollection.php b/library/vendor/Zend/EventManager/SharedEventCollection.php new file mode 100644 index 000000000..237c32154 --- /dev/null +++ b/library/vendor/Zend/EventManager/SharedEventCollection.php @@ -0,0 +1,32 @@ + + * SharedEventManager::getInstance()->connect( + * array('My\Resource\AbstractResource', 'My\Resource\EntityResource'), + * 'getOne', + * function ($e) use ($cache) { + * if (!$id = $e->getParam('id', false)) { + * return; + * } + * if (!$data = $cache->load(get_class($resource) . '::getOne::' . $id )) { + * return; + * } + * return $data; + * } + * ); + * + * + * @param string|array $id Identifier(s) for event emitting component(s) + * @param string $event + * @param callback $callback PHP Callback + * @param int $priority Priority at which listener should execute + * @return void + */ + public function attach($id, $event, $callback, $priority = 1) + { + $ids = (array) $id; + foreach ($ids as $id) { + if (!array_key_exists($id, $this->identifiers)) { + $this->identifiers[$id] = new Zend_EventManager_EventManager(); + } + $this->identifiers[$id]->attach($event, $callback, $priority); + } + } + + /** + * Detach a listener from an event offered by a given resource + * + * @param string|int $id + * @param Zend_Stdlib_CallbackHandler $listener + * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found + */ + public function detach($id, Zend_Stdlib_CallbackHandler $listener) + { + if (!array_key_exists($id, $this->identifiers)) { + return false; + } + return $this->identifiers[$id]->detach($listener); + } + + /** + * Retrieve all registered events for a given resource + * + * @param string|int $id + * @return array + */ + public function getEvents($id) + { + if (!array_key_exists($id, $this->identifiers)) { + return false; + } + return $this->identifiers[$id]->getEvents(); + } + + /** + * Retrieve all listeners for a given identifier and event + * + * @param string|int $id + * @param string|int $event + * @return false|Zend_Stdlib_PriorityQueue + */ + public function getListeners($id, $event) + { + if (!array_key_exists($id, $this->identifiers)) { + return false; + } + return $this->identifiers[$id]->getListeners($event); + } + + /** + * Clear all listeners for a given identifier, optionally for a specific event + * + * @param string|int $id + * @param null|string $event + * @return bool + */ + public function clearListeners($id, $event = null) + { + if (!array_key_exists($id, $this->identifiers)) { + return false; + } + + if (null === $event) { + unset($this->identifiers[$id]); + return true; + } + + return $this->identifiers[$id]->clearListeners($event); + } +} diff --git a/library/vendor/Zend/EventManager/StaticEventManager.php b/library/vendor/Zend/EventManager/StaticEventManager.php new file mode 100644 index 000000000..656816129 --- /dev/null +++ b/library/vendor/Zend/EventManager/StaticEventManager.php @@ -0,0 +1,77 @@ +_previous = $previous; + } else { + parent::__construct($msg, (int) $code, $previous); + } + } + + /** + * Overloading + * + * For PHP < 5.3.0, provides access to the getPrevious() method. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, array $args) + { + if ('getprevious' == strtolower($method)) { + return $this->_getPrevious(); + } + return null; + } + + /** + * String representation of the exception + * + * @return string + */ + public function __toString() + { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if (null !== ($e = $this->getPrevious())) { + return $e->__toString() + . "\n\nNext " + . parent::__toString(); + } + } + return parent::__toString(); + } + + /** + * Returns previous Exception + * + * @return Exception|null + */ + protected function _getPrevious() + { + return $this->_previous; + } +} diff --git a/library/vendor/Zend/File/ClassFileLocator.php b/library/vendor/Zend/File/ClassFileLocator.php new file mode 100644 index 000000000..547694300 --- /dev/null +++ b/library/vendor/Zend/File/ClassFileLocator.php @@ -0,0 +1,177 @@ +setInfoClass('Zend_File_PhpClassFile'); + + // Forward-compat with PHP 5.3 + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if (!defined('T_NAMESPACE')) { + define('T_NAMESPACE', 'namespace'); + } + if (!defined('T_NS_SEPARATOR')) { + define('T_NS_SEPARATOR', '\\'); + } + } + } + + /** + * Filter for files containing PHP classes, interfaces, or abstracts + * + * @return bool + */ + public function accept() + { + $file = $this->getInnerIterator()->current(); + // If we somehow have something other than an SplFileInfo object, just + // return false + if (!$file instanceof SplFileInfo) { + return false; + } + + // If we have a directory, it's not a file, so return false + if (!$file->isFile()) { + return false; + } + + // If not a PHP file, skip + if ($file->getBasename('.php') == $file->getBasename()) { + return false; + } + + $contents = file_get_contents($file->getRealPath()); + $tokens = token_get_all($contents); + $count = count($tokens); + $t_trait = defined('T_TRAIT') ? T_TRAIT : -1; // For preserve PHP 5.3 compatibility + for ($i = 0; $i < $count; $i++) { + $token = $tokens[$i]; + if (!is_array($token)) { + // single character token found; skip + $i++; + continue; + } + switch ($token[0]) { + case T_NAMESPACE: + // Namespace found; grab it for later + $namespace = ''; + for ($i++; $i < $count; $i++) { + $token = $tokens[$i]; + if (is_string($token)) { + if (';' === $token) { + $saveNamespace = false; + break; + } + if ('{' === $token) { + $saveNamespace = true; + break; + } + continue; + } + list($type, $content, $line) = $token; + switch ($type) { + case T_STRING: + case T_NS_SEPARATOR: + $namespace .= $content; + break; + } + } + if ($saveNamespace) { + $savedNamespace = $namespace; + } + break; + case $t_trait: + case T_CLASS: + case T_INTERFACE: + // Abstract class, class, interface or trait found + + // Get the classname + for ($i++; $i < $count; $i++) { + $token = $tokens[$i]; + if (is_string($token)) { + continue; + } + list($type, $content, $line) = $token; + if (T_STRING == $type) { + // If a classname was found, set it in the object, and + // return boolean true (found) + if (!isset($namespace) || null === $namespace) { + if (isset($saveNamespace) && $saveNamespace) { + $namespace = $savedNamespace; + } else { + $namespace = null; + } + + } + $class = (null === $namespace) ? $content : $namespace . '\\' . $content; + $file->addClass($class); + $namespace = null; + break; + } + } + break; + default: + break; + } + } + $classes = $file->getClasses(); + if (!empty($classes)) { + return true; + } + // No class-type tokens found; return false + return false; + } +} diff --git a/library/vendor/Zend/File/PhpClassFile.php b/library/vendor/Zend/File/PhpClassFile.php new file mode 100644 index 000000000..22107c15b --- /dev/null +++ b/library/vendor/Zend/File/PhpClassFile.php @@ -0,0 +1,56 @@ +classes; + } + + /** + * Add class + * + * @param string $class + * @return Zend_File_PhpClassFile + */ + public function addClass($class) + { + $this->classes[] = $class; + return $this; + } +} diff --git a/library/vendor/Zend/File/Transfer.php b/library/vendor/Zend/File/Transfer.php new file mode 100644 index 000000000..77c411c4c --- /dev/null +++ b/library/vendor/Zend/File/Transfer.php @@ -0,0 +1,122 @@ +setAdapter($adapter, $direction, $options); + } + + /** + * Sets a new adapter + * + * @param string $adapter Adapter to use + * @param boolean $direction OPTIONAL False means Download, true means upload + * @param array $options OPTIONAL Options to set for this adapter + * @throws Zend_File_Transfer_Exception + */ + public function setAdapter($adapter, $direction = false, $options = array()) + { + if (Zend_Loader::isReadable('Zend/File/Transfer/Adapter/' . ucfirst($adapter). '.php')) { + $adapter = 'Zend_File_Transfer_Adapter_' . ucfirst($adapter); + } + + if (!class_exists($adapter)) { + Zend_Loader::loadClass($adapter); + } + + $direction = (integer) $direction; + $this->_adapter[$direction] = new $adapter($options); + if (!$this->_adapter[$direction] instanceof Zend_File_Transfer_Adapter_Abstract) { + throw new Zend_File_Transfer_Exception("Adapter " . $adapter . " does not extend Zend_File_Transfer_Adapter_Abstract"); + } + + return $this; + } + + /** + * Returns all set adapters + * + * @param boolean $direction On null, all directions are returned + * On false, download direction is returned + * On true, upload direction is returned + * @return array|Zend_File_Transfer_Adapter + */ + public function getAdapter($direction = null) + { + if ($direction === null) { + return $this->_adapter; + } + + $direction = (integer) $direction; + return $this->_adapter[$direction]; + } + + /** + * Calls all methods from the adapter + * + * @param string $method Method to call + * @param array $options Options for this method + * @return mixed + */ + public function __call($method, array $options) + { + if (array_key_exists('direction', $options)) { + $direction = (integer) $options['direction']; + } else { + $direction = 0; + } + + if (method_exists($this->_adapter[$direction], $method)) { + return call_user_func_array(array($this->_adapter[$direction], $method), $options); + } + + throw new Zend_File_Transfer_Exception("Unknown method '" . $method . "' called!"); + } +} diff --git a/library/vendor/Zend/File/Transfer/Adapter/Abstract.php b/library/vendor/Zend/File/Transfer/Adapter/Abstract.php new file mode 100644 index 000000000..35d67dfd2 --- /dev/null +++ b/library/vendor/Zend/File/Transfer/Adapter/Abstract.php @@ -0,0 +1,1548 @@ + array( - Form is the name within the form or, if not set the filename + * name, - Original name of this file + * type, - Mime type of this file + * size, - Filesize in bytes + * tmp_name, - Internalally temporary filename for uploaded files + * error, - Error which has occured + * destination, - New destination for this file + * validators, - Set validator names for this file + * files - Set file names for this file + * )) + * + * @var array + */ + protected $_files = array(); + + /** + * TMP directory + * @var string + */ + protected $_tmpDir; + + /** + * Available options for file transfers + */ + protected $_options = array( + 'ignoreNoFile' => false, + 'useByteString' => true, + 'magicFile' => null, + 'detectInfos' => true, + ); + + /** + * Send file + * + * @param mixed $options + * @return bool + */ + abstract public function send($options = null); + + /** + * Receive file + * + * @param mixed $options + * @return bool + */ + abstract public function receive($options = null); + + /** + * Is file sent? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isSent($files = null); + + /** + * Is file received? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isReceived($files = null); + + /** + * Has a file been uploaded ? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isUploaded($files = null); + + /** + * Has the file been filtered ? + * + * @param array|string|null $files + * @return bool + */ + abstract public function isFiltered($files = null); + + /** + * Retrieve progress of transfer + * + * @return float + */ + public static function getProgress() + { + throw new Zend_File_Transfer_Exception('Method must be implemented within the adapter'); + } + + /** + * Set plugin loader to use for validator or filter chain + * + * @param Zend_Loader_PluginLoader_Interface $loader + * @param string $type 'filter', or 'validate' + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception on invalid type + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) + { + $type = strtoupper($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $this->_loaders[$type] = $loader; + return $this; + default: + throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); + } + } + + /** + * Retrieve plugin loader for validator or filter chain + * + * Instantiates with default rules if none available for that type. Use + * 'filter' or 'validate' for $type. + * + * @param string $type + * @return Zend_Loader_PluginLoader + * @throws Zend_File_Transfer_Exception on invalid type. + */ + public function getPluginLoader($type) + { + $type = strtoupper($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $prefixSegment = ucfirst(strtolower($type)); + $pathSegment = $prefixSegment; + if (!isset($this->_loaders[$type])) { + $paths = array( + 'Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/', + 'Zend_' . $prefixSegment . '_File' => 'Zend/' . $pathSegment . '/File', + ); + + $this->_loaders[$type] = new Zend_Loader_PluginLoader($paths); + } else { + $loader = $this->_loaders[$type]; + $prefix = 'Zend_' . $prefixSegment . '_File_'; + if (!$loader->getPaths($prefix)) { + $loader->addPrefixPath($prefix, str_replace('_', '/', $prefix)); + } + } + return $this->_loaders[$type]; + default: + throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + } + + /** + * Add prefix path for plugin loader + * + * If no $type specified, assumes it is a base path for both filters and + * validators, and sets each according to the following rules: + * - filters: $prefix = $prefix . '_Filter' + * - validators: $prefix = $prefix . '_Validate' + * + * Otherwise, the path prefix is set on the appropriate plugin loader. + * + * @param string $prefix + * @param string $path + * @param string $type + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception for invalid type + */ + public function addPrefixPath($prefix, $path, $type = null) + { + $type = strtoupper($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $loader = $this->getPluginLoader($type); + $loader->addPrefixPath($prefix, $path); + return $this; + case null: + $prefix = rtrim($prefix, '_'); + $path = rtrim($path, DIRECTORY_SEPARATOR); + foreach (array(self::FILTER, self::VALIDATE) as $type) { + $cType = ucfirst(strtolower($type)); + $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR; + $pluginPrefix = $prefix . '_' . $cType; + $loader = $this->getPluginLoader($type); + $loader->addPrefixPath($pluginPrefix, $pluginPath); + } + return $this; + default: + throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + } + + /** + * Add many prefix paths at once + * + * @param array $spec + * @return Zend_File_Transfer_Exception + */ + public function addPrefixPaths(array $spec) + { + if (isset($spec['prefix']) && isset($spec['path'])) { + return $this->addPrefixPath($spec['prefix'], $spec['path']); + } + foreach ($spec as $type => $paths) { + if (is_numeric($type) && is_array($paths)) { + $type = null; + if (isset($paths['prefix']) && isset($paths['path'])) { + if (isset($paths['type'])) { + $type = $paths['type']; + } + $this->addPrefixPath($paths['prefix'], $paths['path'], $type); + } + } elseif (!is_numeric($type)) { + if (!isset($paths['prefix']) || !isset($paths['path'])) { + foreach ($paths as $prefix => $spec) { + if (is_array($spec)) { + foreach ($spec as $path) { + if (!is_string($path)) { + continue; + } + $this->addPrefixPath($prefix, $path, $type); + } + } elseif (is_string($spec)) { + $this->addPrefixPath($prefix, $spec, $type); + } + } + } else { + $this->addPrefixPath($paths['prefix'], $paths['path'], $type); + } + } + } + return $this; + } + + /** + * Adds a new validator for this class + * + * @param string|array $validator Type of validator to add + * @param boolean $breakChainOnFailure If the validation chain should stop an failure + * @param string|array $options Options to set for the validator + * @param string|array $files Files to limit this validator to + * @return Zend_File_Transfer_Adapter + */ + public function addValidator($validator, $breakChainOnFailure = false, $options = null, $files = null) + { + if ($validator instanceof Zend_Validate_Interface) { + $name = get_class($validator); + } elseif (is_string($validator)) { + $name = $this->getPluginLoader(self::VALIDATE)->load($validator); + $validator = new $name($options); + if (is_array($options) && isset($options['messages'])) { + if (is_array($options['messages'])) { + $validator->setMessages($options['messages']); + } elseif (is_string($options['messages'])) { + $validator->setMessage($options['messages']); + } + + unset($options['messages']); + } + } else { + throw new Zend_File_Transfer_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface'); + } + + $this->_validators[$name] = $validator; + $this->_break[$name] = $breakChainOnFailure; + $files = $this->_getFiles($files, true, true); + foreach ($files as $file) { + if ($name == 'NotEmpty') { + $temp = $this->_files[$file]['validators']; + $this->_files[$file]['validators'] = array($name); + $this->_files[$file]['validators'] += $temp; + } else { + $this->_files[$file]['validators'][] = $name; + } + + $this->_files[$file]['validated'] = false; + } + + return $this; + } + + /** + * Add Multiple validators at once + * + * @param array $validators + * @param string|array $files + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function addValidators(array $validators, $files = null) + { + foreach ($validators as $name => $validatorInfo) { + if ($validatorInfo instanceof Zend_Validate_Interface) { + $this->addValidator($validatorInfo, null, null, $files); + } else if (is_string($validatorInfo)) { + if (!is_int($name)) { + $this->addValidator($name, null, $validatorInfo, $files); + } else { + $this->addValidator($validatorInfo, null, null, $files); + } + } else if (is_array($validatorInfo)) { + $argc = count($validatorInfo); + $breakChainOnFailure = false; + $options = array(); + if (isset($validatorInfo['validator'])) { + $validator = $validatorInfo['validator']; + if (isset($validatorInfo['breakChainOnFailure'])) { + $breakChainOnFailure = $validatorInfo['breakChainOnFailure']; + } + + if (isset($validatorInfo['options'])) { + $options = $validatorInfo['options']; + } + + $this->addValidator($validator, $breakChainOnFailure, $options, $files); + } else { + if (is_string($name)) { + $validator = $name; + $options = $validatorInfo; + $this->addValidator($validator, $breakChainOnFailure, $options, $files); + } else { + $file = $files; + switch (true) { + case (0 == $argc): + break; + case (1 <= $argc): + $validator = array_shift($validatorInfo); + case (2 <= $argc): + $breakChainOnFailure = array_shift($validatorInfo); + case (3 <= $argc): + $options = array_shift($validatorInfo); + case (4 <= $argc): + if (!empty($validatorInfo)) { + $file = array_shift($validatorInfo); + } + default: + $this->addValidator($validator, $breakChainOnFailure, $options, $file); + break; + } + } + } + } else { + throw new Zend_File_Transfer_Exception('Invalid validator passed to addValidators()'); + } + } + + return $this; + } + + /** + * Sets a validator for the class, erasing all previous set + * + * @param string|array $validator Validator to set + * @param string|array $files Files to limit this validator to + * @return Zend_File_Transfer_Adapter + */ + public function setValidators(array $validators, $files = null) + { + $this->clearValidators(); + return $this->addValidators($validators, $files); + } + + /** + * Determine if a given validator has already been registered + * + * @param string $name + * @return bool + */ + public function hasValidator($name) + { + return (false !== $this->_getValidatorIdentifier($name)); + } + + /** + * Retrieve individual validator + * + * @param string $name + * @return Zend_Validate_Interface|null + */ + public function getValidator($name) + { + if (false === ($identifier = $this->_getValidatorIdentifier($name))) { + return null; + } + return $this->_validators[$identifier]; + } + + /** + * Returns all set validators + * + * @param string|array $files (Optional) Returns the validator for this files + * @return null|array List of set validators + */ + public function getValidators($files = null) + { + if ($files == null) { + return $this->_validators; + } + + $files = $this->_getFiles($files, true, true); + $validators = array(); + foreach ($files as $file) { + if (!empty($this->_files[$file]['validators'])) { + $validators += $this->_files[$file]['validators']; + } + } + + $validators = array_unique($validators); + $result = array(); + foreach ($validators as $validator) { + $result[$validator] = $this->_validators[$validator]; + } + + return $result; + } + + /** + * Remove an individual validator + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function removeValidator($name) + { + if (false === ($key = $this->_getValidatorIdentifier($name))) { + return $this; + } + + unset($this->_validators[$key]); + foreach (array_keys($this->_files) as $file) { + if (empty($this->_files[$file]['validators'])) { + continue; + } + + $index = array_search($key, $this->_files[$file]['validators']); + if ($index === false) { + continue; + } + + unset($this->_files[$file]['validators'][$index]); + $this->_files[$file]['validated'] = false; + } + + return $this; + } + + /** + * Remove all validators + * + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function clearValidators() + { + $this->_validators = array(); + foreach (array_keys($this->_files) as $file) { + $this->_files[$file]['validators'] = array(); + $this->_files[$file]['validated'] = false; + } + + return $this; + } + + /** + * Sets Options for adapters + * + * @param array $options Options to set + * @param array $files (Optional) Files to set the options for + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function setOptions($options = array(), $files = null) { + $file = $this->_getFiles($files, false, true); + + if (is_array($options)) { + if (empty($file)) { + $this->_options = array_merge($this->_options, $options); + } + + foreach ($options as $name => $value) { + foreach ($file as $key => $content) { + switch ($name) { + case 'magicFile' : + $this->_files[$key]['options'][$name] = (string) $value; + break; + + case 'ignoreNoFile' : + case 'useByteString' : + case 'detectInfos' : + $this->_files[$key]['options'][$name] = (boolean) $value; + break; + + default: + throw new Zend_File_Transfer_Exception("Unknown option: $name = $value"); + } + } + } + } + + return $this; + } + + /** + * Returns set options for adapters or files + * + * @param array $files (Optional) Files to return the options for + * @return array Options for given files + */ + public function getOptions($files = null) { + $file = $this->_getFiles($files, false, true); + + foreach ($file as $key => $content) { + if (isset($this->_files[$key]['options'])) { + $options[$key] = $this->_files[$key]['options']; + } else { + $options[$key] = array(); + } + } + + return $options; + } + + /** + * Checks if the files are valid + * + * @param string|array $files (Optional) Files to check + * @return boolean True if all checks are valid + */ + public function isValid($files = null) + { + $check = $this->_getFiles($files, false, true); + if (empty($check)) { + return false; + } + + $translator = $this->getTranslator(); + $this->_messages = array(); + $break = false; + foreach($check as $key => $content) { + if (array_key_exists('validators', $content) && + in_array('Zend_Validate_File_Count', $content['validators'])) { + $validator = $this->_validators['Zend_Validate_File_Count']; + $count = $content; + if (empty($content['tmp_name'])) { + continue; + } + + if (array_key_exists('destination', $content)) { + $checkit = $content['destination']; + } else { + $checkit = dirname($content['tmp_name']); + } + + $checkit .= DIRECTORY_SEPARATOR . $content['name']; + $validator->addFile($checkit); + } + } + + if (isset($count)) { + if (!$validator->isValid($count['tmp_name'], $count)) { + $this->_messages += $validator->getMessages(); + } + } + + foreach ($check as $key => $content) { + $fileerrors = array(); + if (array_key_exists('validators', $content) && $content['validated']) { + continue; + } + + if (array_key_exists('validators', $content)) { + foreach ($content['validators'] as $class) { + $validator = $this->_validators[$class]; + if (method_exists($validator, 'setTranslator')) { + $validator->setTranslator($translator); + } + + if (($class === 'Zend_Validate_File_Upload') and (empty($content['tmp_name']))) { + $tocheck = $key; + } else { + $tocheck = $content['tmp_name']; + } + + if (!$validator->isValid($tocheck, $content)) { + $fileerrors += $validator->getMessages(); + } + + if (!empty($content['options']['ignoreNoFile']) and (isset($fileerrors['fileUploadErrorNoFile']))) { + unset($fileerrors['fileUploadErrorNoFile']); + break; + } + + if (($class === 'Zend_Validate_File_Upload') and (count($fileerrors) > 0)) { + break; + } + + if (($this->_break[$class]) and (count($fileerrors) > 0)) { + $break = true; + break; + } + } + } + + if (count($fileerrors) > 0) { + $this->_files[$key]['validated'] = false; + } else { + $this->_files[$key]['validated'] = true; + } + + $this->_messages += $fileerrors; + if ($break) { + break; + } + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } + + /** + * Returns found validation messages + * + * @return array + */ + public function getMessages() + { + return $this->_messages; + } + + /** + * Retrieve error codes + * + * @return array + */ + public function getErrors() + { + return array_keys($this->_messages); + } + + /** + * Are there errors registered? + * + * @return boolean + */ + public function hasErrors() + { + return (!empty($this->_messages)); + } + + /** + * Adds a new filter for this class + * + * @param string|array $filter Type of filter to add + * @param string|array $options Options to set for the filter + * @param string|array $files Files to limit this filter to + * @return Zend_File_Transfer_Adapter + */ + public function addFilter($filter, $options = null, $files = null) + { + if ($filter instanceof Zend_Filter_Interface) { + $class = get_class($filter); + } elseif (is_string($filter)) { + $class = $this->getPluginLoader(self::FILTER)->load($filter); + $filter = new $class($options); + } else { + throw new Zend_File_Transfer_Exception('Invalid filter specified'); + } + + $this->_filters[$class] = $filter; + $files = $this->_getFiles($files, true, true); + foreach ($files as $file) { + $this->_files[$file]['filters'][] = $class; + } + + return $this; + } + + /** + * Add Multiple filters at once + * + * @param array $filters + * @param string|array $files + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function addFilters(array $filters, $files = null) + { + foreach ($filters as $key => $spec) { + if ($spec instanceof Zend_Filter_Interface) { + $this->addFilter($spec, null, $files); + continue; + } + + if (is_string($key)) { + $this->addFilter($key, $spec, $files); + continue; + } + + if (is_int($key)) { + if (is_string($spec)) { + $this->addFilter($spec, null, $files); + continue; + } + + if (is_array($spec)) { + if (!array_key_exists('filter', $spec)) { + continue; + } + + $filter = $spec['filter']; + unset($spec['filter']); + $this->addFilter($filter, $spec, $files); + continue; + } + + continue; + } + } + + return $this; + } + + /** + * Sets a filter for the class, erasing all previous set + * + * @param string|array $filter Filter to set + * @param string|array $files Files to limit this filter to + * @return Zend_File_Transfer_Adapter + */ + public function setFilters(array $filters, $files = null) + { + $this->clearFilters(); + return $this->addFilters($filters, $files); + } + + /** + * Determine if a given filter has already been registered + * + * @param string $name + * @return bool + */ + public function hasFilter($name) + { + return (false !== $this->_getFilterIdentifier($name)); + } + + /** + * Retrieve individual filter + * + * @param string $name + * @return Zend_Filter_Interface|null + */ + public function getFilter($name) + { + if (false === ($identifier = $this->_getFilterIdentifier($name))) { + return null; + } + return $this->_filters[$identifier]; + } + + /** + * Returns all set filters + * + * @param string|array $files (Optional) Returns the filter for this files + * @return array List of set filters + * @throws Zend_File_Transfer_Exception When file not found + */ + public function getFilters($files = null) + { + if ($files === null) { + return $this->_filters; + } + + $files = $this->_getFiles($files, true, true); + $filters = array(); + foreach ($files as $file) { + if (!empty($this->_files[$file]['filters'])) { + $filters += $this->_files[$file]['filters']; + } + } + + $filters = array_unique($filters); + $result = array(); + foreach ($filters as $filter) { + $result[] = $this->_filters[$filter]; + } + + return $result; + } + + /** + * Remove an individual filter + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function removeFilter($name) + { + if (false === ($key = $this->_getFilterIdentifier($name))) { + return $this; + } + + unset($this->_filters[$key]); + foreach (array_keys($this->_files) as $file) { + if (empty($this->_files[$file]['filters'])) { + continue; + } + + $index = array_search($key, $this->_files[$file]['filters']); + if ($index === false) { + continue; + } + + unset($this->_files[$file]['filters'][$index]); + } + return $this; + } + + /** + * Remove all filters + * + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function clearFilters() + { + $this->_filters = array(); + foreach (array_keys($this->_files) as $file) { + $this->_files[$file]['filters'] = array(); + } + return $this; + } + + /** + * Returns all set files + * + * @return array List of set files + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function getFile() + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Retrieves the filename of transferred files. + * + * @param string|null $file + * @param boolean $path (Optional) Should the path also be returned ? + * @return string|array + */ + public function getFileName($file = null, $path = true) + { + $files = $this->_getFiles($file, true, true); + $result = array(); + $directory = ""; + foreach($files as $file) { + if (empty($this->_files[$file]['name'])) { + continue; + } + + if ($path === true) { + $directory = $this->getDestination($file) . DIRECTORY_SEPARATOR; + } + + $result[$file] = $directory . $this->_files[$file]['name']; + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Retrieve additional internal file informations for files + * + * @param string $file (Optional) File to get informations for + * @return array + */ + public function getFileInfo($file = null) + { + return $this->_getFiles($file); + } + + /** + * Adds one or more files + * + * @param string|array $file File to add + * @param string|array $validator Validators to use for this file, must be set before + * @param string|array $filter Filters to use for this file, must be set before + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function addFile($file, $validator = null, $filter = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Returns all set types + * + * @return array List of set types + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function getType() + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Adds one or more type of files + * + * @param string|array $type Type of files to add + * @param string|array $validator Validators to use for this file, must be set before + * @param string|array $filter Filters to use for this file, must be set before + * @return Zend_File_Transfer_Adapter_Abstract + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function addType($type, $validator = null, $filter = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Sets a new destination for the given files + * + * @deprecated Will be changed to be a filter!!! + * @param string $destination New destination directory + * @param string|array $files Files to set the new destination for + * @return Zend_File_Transfer_Abstract + * @throws Zend_File_Transfer_Exception when the given destination is not a directory or does not exist + */ + public function setDestination($destination, $files = null) + { + $orig = $files; + $destination = rtrim($destination, "/\\"); + if (!is_dir($destination)) { + throw new Zend_File_Transfer_Exception( + 'The given destination is not a directory or does not exist' + ); + } + + if (!$this->_isPathWriteable($destination)) { + throw new Zend_File_Transfer_Exception( + 'The given destination is not writable' + ); + } + + if ($files === null) { + foreach ($this->_files as $file => $content) { + $this->_files[$file]['destination'] = $destination; + } + } else { + $files = $this->_getFiles($files, true, true); + if (empty($files) and is_string($orig)) { + $this->_files[$orig]['destination'] = $destination; + } + + foreach ($files as $file) { + $this->_files[$file]['destination'] = $destination; + } + } + + return $this; + } + + /** + * Retrieve destination directory value + * + * @param null|string|array $files + * @return null|string|array + * @throws Zend_File_Transfer_Exception + */ + public function getDestination($files = null) + { + $orig = $files; + $files = $this->_getFiles($files, false, true); + $destinations = array(); + if (empty($files) and is_string($orig)) { + if (isset($this->_files[$orig]['destination'])) { + $destinations[$orig] = $this->_files[$orig]['destination']; + } else { + throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $orig)); + } + } + + foreach ($files as $key => $content) { + if (isset($this->_files[$key]['destination'])) { + $destinations[$key] = $this->_files[$key]['destination']; + } else { + $tmpdir = $this->_getTmpDir(); + $this->setDestination($tmpdir, $key); + $destinations[$key] = $tmpdir; + } + } + + if (empty($destinations)) { + $destinations = $this->_getTmpDir(); + } else if (count($destinations) == 1) { + $destinations = current($destinations); + } + + return $destinations; + } + + /** + * Set translator object for localization + * + * @param Zend_Translate|null $translator + * @return Zend_File_Transfer_Abstract + * @throws Zend_File_Transfer_Exception + */ + public function setTranslator($translator = null) + { + if (null === $translator) { + $this->_translator = null; + } elseif ($translator instanceof Zend_Translate_Adapter) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + throw new Zend_File_Transfer_Exception('Invalid translator specified'); + } + + return $this; + } + + /** + * Retrieve localization translator object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->translatorIsDisabled()) { + return null; + } + + return $this->_translator; + } + + /** + * Indicate whether or not translation should be disabled + * + * @param bool $flag + * @return Zend_File_Transfer_Abstract + */ + public function setDisableTranslator($flag) + { + $this->_translatorDisabled = (bool) $flag; + return $this; + } + + /** + * Is translation disabled? + * + * @return bool + */ + public function translatorIsDisabled() + { + return $this->_translatorDisabled; + } + + /** + * Returns the hash for a given file + * + * @param string $hash Hash algorithm to use + * @param string|array $files Files to return the hash for + * @return string|array Hashstring + * @throws Zend_File_Transfer_Exception On unknown hash algorithm + */ + public function getHash($hash = 'crc32', $files = null) + { + if (!in_array($hash, hash_algos())) { + throw new Zend_File_Transfer_Exception('Unknown hash algorithm'); + } + + $files = $this->_getFiles($files); + $result = array(); + foreach($files as $key => $value) { + if (file_exists($value['name'])) { + $result[$key] = hash_file($hash, $value['name']); + } else if (file_exists($value['tmp_name'])) { + $result[$key] = hash_file($hash, $value['tmp_name']); + } else if (empty($value['options']['ignoreNoFile'])) { + throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); + } + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Returns the real filesize of the file + * + * @param string|array $files Files to get the filesize from + * @throws Zend_File_Transfer_Exception When the file does not exist + * @return string|array Filesize + */ + public function getFileSize($files = null) + { + $files = $this->_getFiles($files); + $result = array(); + foreach($files as $key => $value) { + if (file_exists($value['name']) || file_exists($value['tmp_name'])) { + if ($value['options']['useByteString']) { + $result[$key] = self::_toByteString($value['size']); + } else { + $result[$key] = $value['size']; + } + } else if (empty($value['options']['ignoreNoFile'])) { + throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); + } else { + continue; + } + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Internal method to detect the size of a file + * + * @param array $value File infos + * @return string Filesize of given file + */ + protected function _detectFileSize($value) + { + if (file_exists($value['name'])) { + $result = sprintf("%u", @filesize($value['name'])); + } else if (file_exists($value['tmp_name'])) { + $result = sprintf("%u", @filesize($value['tmp_name'])); + } else { + return null; + } + + return $result; + } + + /** + * Returns the real mimetype of the file + * Uses fileinfo, when not available mime_magic and as last fallback a manual given mimetype + * + * @param string|array $files Files to get the mimetype from + * @throws Zend_File_Transfer_Exception When the file does not exist + * @return string|array MimeType + */ + public function getMimeType($files = null) + { + $files = $this->_getFiles($files); + $result = array(); + foreach($files as $key => $value) { + if (file_exists($value['name']) || file_exists($value['tmp_name'])) { + $result[$key] = $value['type']; + } else if (empty($value['options']['ignoreNoFile'])) { + throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); + } else { + continue; + } + } + + if (count($result) == 1) { + return current($result); + } + + return $result; + } + + /** + * Internal method to detect the mime type of a file + * + * @param array $value File infos + * @return string Mimetype of given file + */ + protected function _detectMimeType($value) + { + if (file_exists($value['name'])) { + $file = $value['name']; + } else if (file_exists($value['tmp_name'])) { + $file = $value['tmp_name']; + } else { + return null; + } + + if (class_exists('finfo', false)) { + $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; + if (!empty($value['options']['magicFile'])) { + $mime = @finfo_open($const, $value['options']['magicFile']); + } + + if (empty($mime)) { + $mime = @finfo_open($const); + } + + if (!empty($mime)) { + $result = finfo_file($mime, $file); + } + + unset($mime); + } + + if (empty($result) && (function_exists('mime_content_type') + && ini_get('mime_magic.magicfile'))) { + $result = mime_content_type($file); + } + + if (empty($result)) { + $result = 'application/octet-stream'; + } + + return $result; + } + + /** + * Returns the formatted size + * + * @param integer $size + * @return string + */ + protected static function _toByteString($size) + { + $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + for ($i=0; $size >= 1024 && $i < 9; $i++) { + $size /= 1024; + } + + return round($size, 2) . $sizes[$i]; + } + + /** + * Internal function to filter all given files + * + * @param string|array $files (Optional) Files to check + * @return boolean False on error + */ + protected function _filter($files = null) + { + $check = $this->_getFiles($files); + foreach ($check as $name => $content) { + if (array_key_exists('filters', $content)) { + foreach ($content['filters'] as $class) { + $filter = $this->_filters[$class]; + try { + $result = $filter->filter($this->getFileName($name)); + + $this->_files[$name]['destination'] = dirname($result); + $this->_files[$name]['name'] = basename($result); + } catch (Zend_Filter_Exception $e) { + $this->_messages += array($e->getMessage()); + } + } + } + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } + + /** + * Determine system TMP directory and detect if we have read access + * + * @return string + * @throws Zend_File_Transfer_Exception if unable to determine directory + */ + protected function _getTmpDir() + { + if (null === $this->_tmpDir) { + $tmpdir = array(); + if (function_exists('sys_get_temp_dir')) { + $tmpdir[] = sys_get_temp_dir(); + } + + if (!empty($_ENV['TMP'])) { + $tmpdir[] = realpath($_ENV['TMP']); + } + + if (!empty($_ENV['TMPDIR'])) { + $tmpdir[] = realpath($_ENV['TMPDIR']); + } + + if (!empty($_ENV['TEMP'])) { + $tmpdir[] = realpath($_ENV['TEMP']); + } + + $upload = ini_get('upload_tmp_dir'); + if ($upload) { + $tmpdir[] = realpath($upload); + } + + foreach($tmpdir as $directory) { + if ($this->_isPathWriteable($directory)) { + $this->_tmpDir = $directory; + } + } + + if (empty($this->_tmpDir)) { + // Attemp to detect by creating a temporary file + $tempFile = tempnam(md5(uniqid(rand(), TRUE)), ''); + if ($tempFile) { + $this->_tmpDir = realpath(dirname($tempFile)); + unlink($tempFile); + } else { + throw new Zend_File_Transfer_Exception('Could not determine a temporary directory'); + } + } + + $this->_tmpDir = rtrim($this->_tmpDir, "/\\"); + } + return $this->_tmpDir; + } + + /** + * Tries to detect if we can read and write to the given path + * + * @param string $path + * @return bool + */ + protected function _isPathWriteable($path) + { + $tempFile = rtrim($path, "/\\"); + $tempFile .= '/' . 'test.1'; + + $result = @file_put_contents($tempFile, 'TEST'); + + if ($result == false) { + return false; + } + + $result = @unlink($tempFile); + + if ($result == false) { + return false; + } + + return true; + } + + /** + * Returns found files based on internal file array and given files + * + * @param string|array $files (Optional) Files to return + * @param boolean $names (Optional) Returns only names on true, else complete info + * @param boolean $noexception (Optional) Allows throwing an exception, otherwise returns an empty array + * @return array Found files + * @throws Zend_File_Transfer_Exception On false filename + */ + protected function _getFiles($files, $names = false, $noexception = false) + { + $check = array(); + + if (is_string($files)) { + $files = array($files); + } + + if (is_array($files)) { + foreach ($files as $find) { + $found = array(); + foreach ($this->_files as $file => $content) { + if (!isset($content['name'])) { + continue; + } + + if (($content['name'] === $find) && isset($content['multifiles'])) { + foreach ($content['multifiles'] as $multifile) { + $found[] = $multifile; + } + break; + } + + if ($file === $find) { + $found[] = $file; + break; + } + + if ($content['name'] === $find) { + $found[] = $file; + break; + } + } + + if (empty($found)) { + if ($noexception !== false) { + return array(); + } + + throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $find)); + } + + foreach ($found as $checked) { + $check[$checked] = $this->_files[$checked]; + } + } + } + + if ($files === null) { + $check = $this->_files; + $keys = array_keys($check); + foreach ($keys as $key) { + if (isset($check[$key]['multifiles'])) { + unset($check[$key]); + } + } + } + + if ($names) { + $check = array_keys($check); + } + + return $check; + } + + /** + * Retrieve internal identifier for a named validator + * + * @param string $name + * @return string + */ + protected function _getValidatorIdentifier($name) + { + if (array_key_exists($name, $this->_validators)) { + return $name; + } + + foreach (array_keys($this->_validators) as $test) { + if (preg_match('/' . preg_quote($name) . '$/i', $test)) { + return $test; + } + } + + return false; + } + + /** + * Retrieve internal identifier for a named filter + * + * @param string $name + * @return string + */ + protected function _getFilterIdentifier($name) + { + if (array_key_exists($name, $this->_filters)) { + return $name; + } + + foreach (array_keys($this->_filters) as $test) { + if (preg_match('/' . preg_quote($name) . '$/i', $test)) { + return $test; + } + } + + return false; + } +} diff --git a/library/vendor/Zend/File/Transfer/Adapter/Http.php b/library/vendor/Zend/File/Transfer/Adapter/Http.php new file mode 100644 index 000000000..2035fc7af --- /dev/null +++ b/library/vendor/Zend/File/Transfer/Adapter/Http.php @@ -0,0 +1,480 @@ +setOptions($options); + $this->_prepareFiles(); + $this->addValidator('Upload', false, $this->_files); + } + + /** + * Sets a validator for the class, erasing all previous set + * + * @param string|array $validator Validator to set + * @param string|array $files Files to limit this validator to + * @return Zend_File_Transfer_Adapter + */ + public function setValidators(array $validators, $files = null) + { + $this->clearValidators(); + return $this->addValidators($validators, $files); + } + + /** + * Remove an individual validator + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function removeValidator($name) + { + if ($name == 'Upload') { + return $this; + } + + return parent::removeValidator($name); + } + + /** + * Remove an individual validator + * + * @param string $name + * @return Zend_File_Transfer_Adapter_Abstract + */ + public function clearValidators() + { + parent::clearValidators(); + $this->addValidator('Upload', false, $this->_files); + + return $this; + } + + /** + * Send the file to the client (Download) + * + * @param string|array $options Options for the file(s) to send + * @return void + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function send($options = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Checks if the files are valid + * + * @param string|array $files (Optional) Files to check + * @return boolean True if all checks are valid + */ + public function isValid($files = null) + { + // Workaround for WebServer not conforming HTTP and omitting CONTENT_LENGTH + $content = 0; + if (isset($_SERVER['CONTENT_LENGTH'])) { + $content = $_SERVER['CONTENT_LENGTH']; + } else if (!empty($_POST)) { + $content = serialize($_POST); + } + + // Workaround for a PHP error returning empty $_FILES when form data exceeds php settings + if (empty($this->_files) && ($content > 0)) { + if (is_array($files)) { + if (0 === count($files)) { + return false; + } + + $files = current($files); + } + + $temp = array($files => array( + 'name' => $files, + 'error' => 1)); + $validator = $this->_validators['Zend_Validate_File_Upload']; + $validator->setFiles($temp) + ->isValid($files, null); + $this->_messages += $validator->getMessages(); + return false; + } + + return parent::isValid($files); + } + + /** + * Receive the file from the client (Upload) + * + * @param string|array $files (Optional) Files to receive + * @return bool + */ + public function receive($files = null) + { + if (!$this->isValid($files)) { + return false; + } + + $check = $this->_getFiles($files); + foreach ($check as $file => $content) { + if (!$content['received']) { + $directory = ''; + $destination = $this->getDestination($file); + if ($destination !== null) { + $directory = $destination . DIRECTORY_SEPARATOR; + } + + $filename = $directory . $content['name']; + $rename = $this->getFilter('Rename'); + if ($rename !== null) { + $tmp = $rename->getNewName($content['tmp_name']); + if ($tmp != $content['tmp_name']) { + $filename = $tmp; + } + + if (dirname($filename) == '.') { + $filename = $directory . $filename; + } + + $key = array_search(get_class($rename), $this->_files[$file]['filters']); + unset($this->_files[$file]['filters'][$key]); + } + + // Should never return false when it's tested by the upload validator + if (!move_uploaded_file($content['tmp_name'], $filename)) { + if ($content['options']['ignoreNoFile']) { + $this->_files[$file]['received'] = true; + $this->_files[$file]['filtered'] = true; + continue; + } + + $this->_files[$file]['received'] = false; + return false; + } + + if ($rename !== null) { + $this->_files[$file]['destination'] = dirname($filename); + $this->_files[$file]['name'] = basename($filename); + } + + $this->_files[$file]['tmp_name'] = $filename; + $this->_files[$file]['received'] = true; + } + + if (!$content['filtered']) { + if (!$this->_filter($file)) { + $this->_files[$file]['filtered'] = false; + return false; + } + + $this->_files[$file]['filtered'] = true; + } + } + + return true; + } + + /** + * Checks if the file was already sent + * + * @param string|array $file Files to check + * @return bool + * @throws Zend_File_Transfer_Exception Not implemented + */ + public function isSent($files = null) + { + throw new Zend_File_Transfer_Exception('Method not implemented'); + } + + /** + * Checks if the file was already received + * + * @param string|array $files (Optional) Files to check + * @return bool + */ + public function isReceived($files = null) + { + $files = $this->_getFiles($files, false, true); + if (empty($files)) { + return false; + } + + foreach ($files as $content) { + if ($content['received'] !== true) { + return false; + } + } + + return true; + } + + /** + * Checks if the file was already filtered + * + * @param string|array $files (Optional) Files to check + * @return bool + */ + public function isFiltered($files = null) + { + $files = $this->_getFiles($files, false, true); + if (empty($files)) { + return false; + } + + foreach ($files as $content) { + if ($content['filtered'] !== true) { + return false; + } + } + + return true; + } + + /** + * Has a file been uploaded ? + * + * @param array|string|null $file + * @return bool + */ + public function isUploaded($files = null) + { + $files = $this->_getFiles($files, false, true); + if (empty($files)) { + return false; + } + + foreach ($files as $file) { + if (empty($file['name'])) { + return false; + } + } + + return true; + } + + /** + * Returns the actual progress of file up-/downloads + * + * @param string $id The upload to get the progress for + * @return array|null + */ + public static function getProgress($id = null) + { + if (!function_exists('apc_fetch') and !function_exists('uploadprogress_get_info')) { + throw new Zend_File_Transfer_Exception('Neither APC nor uploadprogress extension installed'); + } + + $session = 'Zend_File_Transfer_Adapter_Http_ProgressBar'; + $status = array( + 'total' => 0, + 'current' => 0, + 'rate' => 0, + 'message' => '', + 'done' => false + ); + + if (is_array($id)) { + if (isset($id['progress'])) { + $adapter = $id['progress']; + } + + if (isset($id['session'])) { + $session = $id['session']; + } + + if (isset($id['id'])) { + $id = $id['id']; + } else { + unset($id); + } + } + + if (!empty($id) && (($id instanceof Zend_ProgressBar_Adapter) || ($id instanceof Zend_ProgressBar))) { + $adapter = $id; + unset($id); + } + + if (empty($id)) { + if (!isset($_GET['progress_key'])) { + $status['message'] = 'No upload in progress'; + $status['done'] = true; + } else { + $id = $_GET['progress_key']; + } + } + + if (!empty($id)) { + if (self::isApcAvailable()) { + + $call = call_user_func(self::$_callbackApc, ini_get('apc.rfc1867_prefix') . $id); + if (is_array($call)) { + $status = $call + $status; + } + } else if (self::isUploadProgressAvailable()) { + $call = call_user_func(self::$_callbackUploadProgress, $id); + if (is_array($call)) { + $status = $call + $status; + $status['total'] = $status['bytes_total']; + $status['current'] = $status['bytes_uploaded']; + $status['rate'] = $status['speed_average']; + if ($status['total'] == $status['current']) { + $status['done'] = true; + } + } + } + + if (!is_array($call)) { + $status['done'] = true; + $status['message'] = 'Failure while retrieving the upload progress'; + } else if (!empty($status['cancel_upload'])) { + $status['done'] = true; + $status['message'] = 'The upload has been canceled'; + } else { + $status['message'] = self::_toByteString($status['current']) . " - " . self::_toByteString($status['total']); + } + + $status['id'] = $id; + } + + if (isset($adapter) && isset($status['id'])) { + if ($adapter instanceof Zend_ProgressBar_Adapter) { + $adapter = new Zend_ProgressBar($adapter, 0, $status['total'], $session); + } + + if (!($adapter instanceof Zend_ProgressBar)) { + throw new Zend_File_Transfer_Exception('Unknown Adapter given'); + } + + if ($status['done']) { + $adapter->finish(); + } else { + $adapter->update($status['current'], $status['message']); + } + + $status['progress'] = $adapter; + } + + return $status; + } + + /** + * Checks the APC extension for progress information + * + * @return boolean + */ + public static function isApcAvailable() + { + return (bool) ini_get('apc.enabled') && (bool) ini_get('apc.rfc1867') && is_callable(self::$_callbackApc); + } + + /** + * Checks the UploadProgress extension for progress information + * + * @return boolean + */ + public static function isUploadProgressAvailable() + { + return is_callable(self::$_callbackUploadProgress); + } + + /** + * Prepare the $_FILES array to match the internal syntax of one file per entry + * + * @param array $files + * @return array + */ + protected function _prepareFiles() + { + $this->_files = array(); + foreach ($_FILES as $form => $content) { + if (is_array($content['name'])) { + foreach ($content as $param => $file) { + foreach ($file as $number => $target) { + $this->_files[$form . '_' . $number . '_'][$param] = $target; + $this->_files[$form]['multifiles'][$number] = $form . '_' . $number . '_'; + } + } + + $this->_files[$form]['name'] = $form; + foreach($this->_files[$form]['multifiles'] as $key => $value) { + $this->_files[$value]['options'] = $this->_options; + $this->_files[$value]['validated'] = false; + $this->_files[$value]['received'] = false; + $this->_files[$value]['filtered'] = false; + + $mimetype = $this->_detectMimeType($this->_files[$value]); + $this->_files[$value]['type'] = $mimetype; + + $filesize = $this->_detectFileSize($this->_files[$value]); + $this->_files[$value]['size'] = $filesize; + + if ($this->_options['detectInfos']) { + $_FILES[$form]['type'][$key] = $mimetype; + $_FILES[$form]['size'][$key] = $filesize; + } + } + } else { + $this->_files[$form] = $content; + $this->_files[$form]['options'] = $this->_options; + $this->_files[$form]['validated'] = false; + $this->_files[$form]['received'] = false; + $this->_files[$form]['filtered'] = false; + + $mimetype = $this->_detectMimeType($this->_files[$form]); + $this->_files[$form]['type'] = $mimetype; + + $filesize = $this->_detectFileSize($this->_files[$form]); + $this->_files[$form]['size'] = $filesize; + + if ($this->_options['detectInfos']) { + $_FILES[$form]['type'] = $mimetype; + $_FILES[$form]['size'] = $filesize; + } + } + } + + return $this; + } +} diff --git a/library/vendor/Zend/File/Transfer/Exception.php b/library/vendor/Zend/File/Transfer/Exception.php new file mode 100644 index 000000000..e0b868650 --- /dev/null +++ b/library/vendor/Zend/File/Transfer/Exception.php @@ -0,0 +1,54 @@ +_fileerror = $fileerror; + parent::__construct($message); + } + + /** + * Returns the transfer error code for the exception + * This is not the exception code !!! + * + * @return integer + */ + public function getFileError() + { + return $this->_fileerror; + } +} diff --git a/library/vendor/Zend/Filter.php b/library/vendor/Zend/Filter.php new file mode 100644 index 000000000..12fd93c8c --- /dev/null +++ b/library/vendor/Zend/Filter.php @@ -0,0 +1,236 @@ +_filters, $filter); + } else { + $this->_filters[] = $filter; + } + return $this; + } + + /** + * Add a filter to the end of the chain + * + * @param Zend_Filter_Interface $filter + * @return Zend_Filter Provides a fluent interface + */ + public function appendFilter(Zend_Filter_Interface $filter) + { + return $this->addFilter($filter, self::CHAIN_APPEND); + } + + /** + * Add a filter to the start of the chain + * + * @param Zend_Filter_Interface $filter + * @return Zend_Filter Provides a fluent interface + */ + public function prependFilter(Zend_Filter_Interface $filter) + { + return $this->addFilter($filter, self::CHAIN_PREPEND); + } + + /** + * Get all the filters + * + * @return array + */ + public function getFilters() + { + return $this->_filters; + } + + /** + * Returns $value filtered through each filter in the chain + * + * Filters are run in the order in which they were added to the chain (FIFO) + * + * @param mixed $value + * @return mixed + */ + public function filter($value) + { + $valueFiltered = $value; + foreach ($this->_filters as $filter) { + $valueFiltered = $filter->filter($valueFiltered); + } + return $valueFiltered; + } + + /** + * Returns the set default namespaces + * + * @return array + */ + public static function getDefaultNamespaces() + { + return self::$_defaultNamespaces; + } + + /** + * Sets new default namespaces + * + * @param array|string $namespace + * @return null + */ + public static function setDefaultNamespaces($namespace) + { + if (!is_array($namespace)) { + $namespace = array((string) $namespace); + } + + self::$_defaultNamespaces = $namespace; + } + + /** + * Adds a new default namespace + * + * @param array|string $namespace + * @return null + */ + public static function addDefaultNamespaces($namespace) + { + if (!is_array($namespace)) { + $namespace = array((string) $namespace); + } + + self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace)); + } + + /** + * Returns true when defaultNamespaces are set + * + * @return boolean + */ + public static function hasDefaultNamespaces() + { + return (!empty(self::$_defaultNamespaces)); + } + + /** + * @deprecated + * @see Zend_Filter::filterStatic() + * + * @param mixed $value + * @param string $classBaseName + * @param array $args OPTIONAL + * @param array|string $namespaces OPTIONAL + * @return mixed + * @throws Zend_Filter_Exception + */ + public static function get($value, $classBaseName, array $args = array(), $namespaces = array()) + { + trigger_error( + 'Zend_Filter::get() is deprecated as of 1.9.0; please update your code to utilize Zend_Filter::filterStatic()', + E_USER_NOTICE + ); + + return self::filterStatic($value, $classBaseName, $args, $namespaces); + } + + /** + * Returns a value filtered through a specified filter class, without requiring separate + * instantiation of the filter object. + * + * The first argument of this method is a data input value, that you would have filtered. + * The second argument is a string, which corresponds to the basename of the filter class, + * relative to the Zend_Filter namespace. This method automatically loads the class, + * creates an instance, and applies the filter() method to the data input. You can also pass + * an array of constructor arguments, if they are needed for the filter class. + * + * @param mixed $value + * @param string $classBaseName + * @param array $args OPTIONAL + * @param array|string $namespaces OPTIONAL + * @return mixed + * @throws Zend_Filter_Exception + */ + public static function filterStatic($value, $classBaseName, array $args = array(), $namespaces = array()) + { + $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Filter')); + foreach ($namespaces as $namespace) { + $className = $namespace . '_' . ucfirst($classBaseName); + if (!class_exists($className, false)) { + try { + $file = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; + if (Zend_Loader::isReadable($file)) { + Zend_Loader::loadClass($className); + } else { + continue; + } + } catch (Zend_Exception $ze) { + continue; + } + } + + $class = new ReflectionClass($className); + if ($class->implementsInterface('Zend_Filter_Interface')) { + if ($class->hasMethod('__construct')) { + $object = $class->newInstanceArgs($args); + } else { + $object = $class->newInstance(); + } + return $object->filter($value); + } + } + throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'"); + } +} diff --git a/library/vendor/Zend/Filter/Alnum.php b/library/vendor/Zend/Filter/Alnum.php new file mode 100644 index 000000000..f0b86b355 --- /dev/null +++ b/library/vendor/Zend/Filter/Alnum.php @@ -0,0 +1,144 @@ +toArray(); + } else if (is_array($allowWhiteSpace)) { + if (array_key_exists('allowwhitespace', $allowWhiteSpace)) { + $allowWhiteSpace = $allowWhiteSpace['allowwhitespace']; + } else { + $allowWhiteSpace = false; + } + } + + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + if (null === self::$_unicodeEnabled) { + self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; + } + + if (null === self::$_meansEnglishAlphabet) { + $this->_locale = new Zend_Locale('auto'); + self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), + array('ja', 'ko', 'zh') + ); + } + + } + + /** + * Returns the allowWhiteSpace option + * + * @return boolean + */ + public function getAllowWhiteSpace() + { + return $this->allowWhiteSpace; + } + + /** + * Sets the allowWhiteSpace option + * + * @param boolean $allowWhiteSpace + * @return Zend_Filter_Alnum Provides a fluent interface + */ + public function setAllowWhiteSpace($allowWhiteSpace) + { + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, removing all but alphabetic and digit characters + * + * @param string $value + * @return string + */ + public function filter($value) + { + $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; + if (!self::$_unicodeEnabled) { + // POSIX named classes are not supported, use alternative a-zA-Z0-9 match + $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/'; + } else if (self::$_meansEnglishAlphabet) { + //The Alphabet means english alphabet. + $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/u'; + } else { + //The Alphabet means each language's alphabet. + $pattern = '/[^\p{L}\p{N}' . $whiteSpace . ']/u'; + } + + return preg_replace($pattern, '', (string) $value); + } +} diff --git a/library/vendor/Zend/Filter/Alpha.php b/library/vendor/Zend/Filter/Alpha.php new file mode 100644 index 000000000..4fe835c30 --- /dev/null +++ b/library/vendor/Zend/Filter/Alpha.php @@ -0,0 +1,144 @@ +toArray(); + } else if (is_array($allowWhiteSpace)) { + if (array_key_exists('allowwhitespace', $allowWhiteSpace)) { + $allowWhiteSpace = $allowWhiteSpace['allowwhitespace']; + } else { + $allowWhiteSpace = false; + } + } + + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + if (null === self::$_unicodeEnabled) { + self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; + } + + if (null === self::$_meansEnglishAlphabet) { + $this->_locale = new Zend_Locale('auto'); + self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), + array('ja', 'ko', 'zh') + ); + } + + } + + /** + * Returns the allowWhiteSpace option + * + * @return boolean + */ + public function getAllowWhiteSpace() + { + return $this->allowWhiteSpace; + } + + /** + * Sets the allowWhiteSpace option + * + * @param boolean $allowWhiteSpace + * @return Zend_Filter_Alpha Provides a fluent interface + */ + public function setAllowWhiteSpace($allowWhiteSpace) + { + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, removing all but alphabetic characters + * + * @param string $value + * @return string + */ + public function filter($value) + { + $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; + if (!self::$_unicodeEnabled) { + // POSIX named classes are not supported, use alternative a-zA-Z match + $pattern = '/[^a-zA-Z' . $whiteSpace . ']/'; + } else if (self::$_meansEnglishAlphabet) { + //The Alphabet means english alphabet. + $pattern = '/[^a-zA-Z' . $whiteSpace . ']/u'; + } else { + //The Alphabet means each language's alphabet. + $pattern = '/[^\p{L}' . $whiteSpace . ']/u'; + } + + return preg_replace($pattern, '', (string) $value); + } +} diff --git a/library/vendor/Zend/Filter/BaseName.php b/library/vendor/Zend/Filter/BaseName.php new file mode 100644 index 000000000..3c0143792 --- /dev/null +++ b/library/vendor/Zend/Filter/BaseName.php @@ -0,0 +1,49 @@ + 'boolean', + self::INTEGER => 'integer', + self::FLOAT => 'float', + self::STRING => 'string', + self::ZERO => 'zero', + self::EMPTY_ARRAY => 'array', + self::NULL => 'null', + self::PHP => 'php', + self::FALSE_STRING => 'false', + self::YES => 'yes', + self::ALL => 'all', + ); + + /** + * Internal type to detect + * + * @var integer + */ + protected $_type = self::PHP; + + /** + * Internal locale + * + * @var array + */ + protected $_locale = array('auto'); + + /** + * Internal mode + * + * @var boolean + */ + protected $_casting = true; + + /** + * Constructor + * + * @param string|array|Zend_Config $options OPTIONAL + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['type'] = array_shift($options); + } + + if (!empty($options)) { + $temp['casting'] = array_shift($options); + } + + if (!empty($options)) { + $temp['locale'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('type', $options)) { + $this->setType($options['type']); + } + + if (array_key_exists('casting', $options)) { + $this->setCasting($options['casting']); + } + + if (array_key_exists('locale', $options)) { + $this->setLocale($options['locale']); + } + } + + /** + * Returns the set null types + * + * @return int + */ + public function getType() + { + return $this->_type; + } + + /** + * Set the null types + * + * @param integer|array $type + * @throws Zend_Filter_Exception + * @return Zend_Filter_Boolean + */ + public function setType($type = null) + { + if (is_array($type)) { + $detected = 0; + foreach($type as $value) { + if (is_int($value)) { + $detected += $value; + } elseif (in_array($value, $this->_constants)) { + $detected += array_search($value, $this->_constants); + } + } + + $type = $detected; + } elseif (is_string($type) && in_array($type, $this->_constants)) { + $type = array_search($type, $this->_constants); + } + + if (!is_int($type) || ($type < 0) || ($type > self::ALL)) { + throw new Zend_Filter_Exception('Unknown type'); + } + + $this->_type = $type; + return $this; + } + + /** + * Returns the set locale + * + * @return array + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Set the locales which are accepted + * + * @param string|array|Zend_Locale $locale + * @throws Zend_Filter_Exception + * @return Zend_Filter_Boolean + */ + public function setLocale($locale = null) + { + if (is_string($locale)) { + $locale = array($locale); + } elseif ($locale instanceof Zend_Locale) { + $locale = array($locale->toString()); + } elseif (!is_array($locale)) { + throw new Zend_Filter_Exception('Locale has to be string, array or an instance of Zend_Locale'); + } + + foreach ($locale as $single) { + if (!Zend_Locale::isLocale($single)) { + throw new Zend_Filter_Exception("Unknown locale '$single'"); + } + } + + $this->_locale = $locale; + return $this; + } + + /** + * Returns the casting option + * + * @return boolean + */ + public function getCasting() + { + return $this->_casting; + } + + /** + * Set the working mode + * + * @param boolean $locale When true this filter works like cast + * When false it recognises only true and false + * and all other values are returned as is + * @throws Zend_Filter_Exception + * @return Zend_Filter_Boolean + */ + public function setCasting($casting = true) + { + $this->_casting = (boolean) $casting; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns a boolean representation of $value + * + * @param string $value + * @return string + */ + public function filter($value) + { + $type = $this->getType(); + $casting = $this->getCasting(); + + // STRING YES (Localized) + if ($type >= self::YES) { + $type -= self::YES; + if (is_string($value)) { + $locales = $this->getLocale(); + foreach ($locales as $locale) { + if ($this->_getLocalizedQuestion($value, false, $locale) === false) { + return false; + } + + if (!$casting && ($this->_getLocalizedQuestion($value, true, $locale) === true)) { + return true; + } + } + } + } + + // STRING FALSE ('false') + if ($type >= self::FALSE_STRING) { + $type -= self::FALSE_STRING; + if (is_string($value) && (strtolower($value) == 'false')) { + return false; + } + + if ((!$casting) && is_string($value) && (strtolower($value) == 'true')) { + return true; + } + } + + // NULL (null) + if ($type >= self::NULL) { + $type -= self::NULL; + if ($value === null) { + return false; + } + } + + // EMPTY_ARRAY (array()) + if ($type >= self::EMPTY_ARRAY) { + $type -= self::EMPTY_ARRAY; + if (is_array($value) && ($value == array())) { + return false; + } + } + + // ZERO ('0') + if ($type >= self::ZERO) { + $type -= self::ZERO; + if (is_string($value) && ($value == '0')) { + return false; + } + + if ((!$casting) && (is_string($value)) && ($value == '1')) { + return true; + } + } + + // STRING ('') + if ($type >= self::STRING) { + $type -= self::STRING; + if (is_string($value) && ($value == '')) { + return false; + } + } + + // FLOAT (0.0) + if ($type >= self::FLOAT) { + $type -= self::FLOAT; + if (is_float($value) && ($value == 0.0)) { + return false; + } + + if ((!$casting) && is_float($value) && ($value == 1.0)) { + return true; + } + } + + // INTEGER (0) + if ($type >= self::INTEGER) { + $type -= self::INTEGER; + if (is_int($value) && ($value == 0)) { + return false; + } + + if ((!$casting) && is_int($value) && ($value == 1)) { + return true; + } + } + + // BOOLEAN (false) + if ($type >= self::BOOLEAN) { + $type -= self::BOOLEAN; + if (is_bool($value)) { + return $value; + } + } + + if ($casting) { + return true; + } + + return $value; + } + + /** + * Determine the value of a localized string, and compare it to a given value + * + * @param string $value + * @param boolean $yes + * @param array $locale + * @return boolean + */ + protected function _getLocalizedQuestion($value, $yes, $locale) + { + if ($yes == true) { + $question = 'yes'; + $return = true; + } else { + $question = 'no'; + $return = false; + } + $str = Zend_Locale::getTranslation($question, 'question', $locale); + $str = explode(':', $str); + if (!empty($str)) { + foreach($str as $no) { + if (($no == $value) || (strtolower($no) == strtolower($value))) { + return $return; + } + } + } + } +} diff --git a/library/vendor/Zend/Filter/Callback.php b/library/vendor/Zend/Filter/Callback.php new file mode 100644 index 000000000..017fc4f83 --- /dev/null +++ b/library/vendor/Zend/Filter/Callback.php @@ -0,0 +1,149 @@ +toArray(); + } else if (!is_array($options) || !array_key_exists('callback', $options)) { + $options = func_get_args(); + $temp['callback'] = array_shift($options); + if (!empty($options)) { + $temp['options'] = array_shift($options); + } + + $options = $temp; + } + + if (!array_key_exists('callback', $options)) { + throw new Zend_Filter_Exception('Missing callback to use'); + } + + $this->setCallback($options['callback']); + if (array_key_exists('options', $options)) { + $this->setOptions($options['options']); + } + } + + /** + * Returns the set callback + * + * @return string|array Set callback + */ + public function getCallback() + { + return $this->_callback; + } + + /** + * Sets a new callback for this filter + * + * @param unknown_type $callback + * @return unknown + */ + public function setCallback($callback, $options = null) + { + if (!is_callable($callback)) { + throw new Zend_Filter_Exception('Callback can not be accessed'); + } + + $this->_callback = $callback; + $this->setOptions($options); + return $this; + } + + /** + * Returns the set default options + * + * @return mixed + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets new default options to the callback filter + * + * @param mixed $options Default options to set + * @return Zend_Filter_Callback + */ + public function setOptions($options) + { + $this->_options = $options; + return $this; + } + + /** + * Calls the filter per callback + * + * @param mixed $value Options for the set callback + * @return mixed Result from the filter which was callbacked + */ + public function filter($value) + { + $options = array(); + + if ($this->_options !== null) { + if (!is_array($this->_options)) { + $options = array($this->_options); + } else { + $options = $this->_options; + } + } + + array_unshift($options, $value); + + return call_user_func_array($this->_callback, $options); + } +} diff --git a/library/vendor/Zend/Filter/Compress.php b/library/vendor/Zend/Filter/Compress.php new file mode 100644 index 000000000..c6b17e2ee --- /dev/null +++ b/library/vendor/Zend/Filter/Compress.php @@ -0,0 +1,192 @@ +toArray(); + } + if (is_string($options)) { + $this->setAdapter($options); + } elseif ($options instanceof Zend_Filter_Compress_CompressInterface) { + $this->setAdapter($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Set filter setate + * + * @param array $options + * @return Zend_Filter_Compress + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + if ($key == 'options') { + $key = 'adapterOptions'; + } + $method = 'set' . ucfirst($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + } + return $this; + } + + /** + * Returns the current adapter, instantiating it if necessary + * + * @return string + */ + public function getAdapter() + { + if ($this->_adapter instanceof Zend_Filter_Compress_CompressInterface) { + return $this->_adapter; + } + + $adapter = $this->_adapter; + $options = $this->getAdapterOptions(); + if (!class_exists($adapter)) { + if (Zend_Loader::isReadable('Zend/Filter/Compress/' . ucfirst($adapter) . '.php')) { + $adapter = 'Zend_Filter_Compress_' . ucfirst($adapter); + } + Zend_Loader::loadClass($adapter); + } + + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Filter_Compress_CompressInterface) { + throw new Zend_Filter_Exception("Compression adapter '" . $adapter . "' does not implement Zend_Filter_Compress_CompressInterface"); + } + return $this->_adapter; + } + + /** + * Retrieve adapter name + * + * @return string + */ + public function getAdapterName() + { + return $this->getAdapter()->toString(); + } + + /** + * Sets compression adapter + * + * @param string|Zend_Filter_Compress_CompressInterface $adapter Adapter to use + * @return Zend_Filter_Compress + */ + public function setAdapter($adapter) + { + if ($adapter instanceof Zend_Filter_Compress_CompressInterface) { + $this->_adapter = $adapter; + return $this; + } + if (!is_string($adapter)) { + throw new Zend_Filter_Exception('Invalid adapter provided; must be string or instance of Zend_Filter_Compress_CompressInterface'); + } + $this->_adapter = $adapter; + + return $this; + } + + /** + * Retrieve adapter options + * + * @return array + */ + public function getAdapterOptions() + { + return $this->_adapterOptions; + } + + /** + * Set adapter options + * + * @param array $options + * @return void + */ + public function setAdapterOptions(array $options) + { + $this->_adapterOptions = $options; + return $this; + } + + /** + * Calls adapter methods + * + * @param string $method Method to call + * @param string|array $options Options for this method + */ + public function __call($method, $options) + { + $adapter = $this->getAdapter(); + if (!method_exists($adapter, $method)) { + throw new Zend_Filter_Exception("Unknown method '{$method}'"); + } + + return call_user_func_array(array($adapter, $method), $options); + } + + /** + * Defined by Zend_Filter_Interface + * + * Compresses the content $value with the defined settings + * + * @param string $value Content to compress + * @return string The compressed content + */ + public function filter($value) + { + return $this->getAdapter()->compress($value); + } +} diff --git a/library/vendor/Zend/Filter/Compress/Bz2.php b/library/vendor/Zend/Filter/Compress/Bz2.php new file mode 100644 index 000000000..fba7d009f --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Bz2.php @@ -0,0 +1,181 @@ + Blocksize to use from 0-9 + * 'archive' => Archive to use + * ) + * + * @var array + */ + protected $_options = array( + 'blocksize' => 4, + 'archive' => null, + ); + + /** + * Class constructor + * + * @param array|Zend_Config $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('bz2')) { + throw new Zend_Filter_Exception('This filter needs the bz2 extension'); + } + parent::__construct($options); + } + + /** + * Returns the set blocksize + * + * @return integer + */ + public function getBlocksize() + { + return $this->_options['blocksize']; + } + + /** + * Sets a new blocksize + * + * @param integer $level + * @return Zend_Filter_Compress_Bz2 + */ + public function setBlocksize($blocksize) + { + if (($blocksize < 0) || ($blocksize > 9)) { + throw new Zend_Filter_Exception('Blocksize must be between 0 and 9'); + } + + $this->_options['blocksize'] = (int) $blocksize; + return $this; + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Bz2 + */ + public function setArchive($archive) + { + $this->_options['archive'] = (string) $archive; + return $this; + } + + /** + * Compresses the given content + * + * @param string $content + * @return string + */ + public function compress($content) + { + $archive = $this->getArchive(); + if (!empty($archive)) { + $file = bzopen($archive, 'w'); + if (!$file) { + throw new Zend_Filter_Exception("Error opening the archive '" . $archive . "'"); + } + + bzwrite($file, $content); + bzclose($file); + $compressed = true; + } else { + $compressed = bzcompress($content, $this->getBlocksize()); + } + + if (is_int($compressed)) { + throw new Zend_Filter_Exception('Error during compression'); + } + + return $compressed; + } + + /** + * Decompresses the given content + * + * @param string $content + * @return string + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (@file_exists($content)) { + $archive = $content; + } + + if (@file_exists($archive)) { + $file = bzopen($archive, 'r'); + if (!$file) { + throw new Zend_Filter_Exception("Error opening the archive '" . $content . "'"); + } + + $compressed = bzread($file); + bzclose($file); + } else { + $compressed = bzdecompress($content); + } + + if (is_int($compressed)) { + throw new Zend_Filter_Exception('Error during decompression'); + } + + return $compressed; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Bz2'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/CompressAbstract.php b/library/vendor/Zend/Filter/Compress/CompressAbstract.php new file mode 100644 index 000000000..bbcaa325c --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/CompressAbstract.php @@ -0,0 +1,88 @@ +toArray(); + } + + if (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * Returns one or all set options + * + * @param string $option (Optional) Option to return + * @return mixed + */ + public function getOptions($option = null) + { + if ($option === null) { + return $this->_options; + } + + if (!array_key_exists($option, $this->_options)) { + return null; + } + + return $this->_options[$option]; + } + + /** + * Sets all or one option + * + * @param array $options + * @return Zend_Filter_Compress_Bz2 + */ + public function setOptions(array $options) + { + foreach ($options as $key => $option) { + $method = 'set' . $key; + if (method_exists($this, $method)) { + $this->$method($option); + } + } + + return $this; + } +} diff --git a/library/vendor/Zend/Filter/Compress/CompressInterface.php b/library/vendor/Zend/Filter/Compress/CompressInterface.php new file mode 100644 index 000000000..cbec1a668 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/CompressInterface.php @@ -0,0 +1,54 @@ + Compression level 0-9 + * 'mode' => Compression mode, can be 'compress', 'deflate' + * 'archive' => Archive to use + * ) + * + * @var array + */ + protected $_options = array( + 'level' => 9, + 'mode' => 'compress', + 'archive' => null, + ); + + /** + * Class constructor + * + * @param array|Zend_Config|null $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('zlib')) { + throw new Zend_Filter_Exception('This filter needs the zlib extension'); + } + parent::__construct($options); + } + + /** + * Returns the set compression level + * + * @return integer + */ + public function getLevel() + { + return $this->_options['level']; + } + + /** + * Sets a new compression level + * + * @param integer $level + * @return Zend_Filter_Compress_Gz + */ + public function setLevel($level) + { + if (($level < 0) || ($level > 9)) { + throw new Zend_Filter_Exception('Level must be between 0 and 9'); + } + + $this->_options['level'] = (int) $level; + return $this; + } + + /** + * Returns the set compression mode + * + * @return string + */ + public function getMode() + { + return $this->_options['mode']; + } + + /** + * Sets a new compression mode + * + * @param string $mode Supported are 'compress', 'deflate' and 'file' + */ + public function setMode($mode) + { + if (($mode != 'compress') && ($mode != 'deflate')) { + throw new Zend_Filter_Exception('Given compression mode not supported'); + } + + $this->_options['mode'] = $mode; + return $this; + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Gz + */ + public function setArchive($archive) + { + $this->_options['archive'] = (string) $archive; + return $this; + } + + /** + * Compresses the given content + * + * @param string $content + * @return string + */ + public function compress($content) + { + $archive = $this->getArchive(); + if (!empty($archive)) { + $file = gzopen($archive, 'w' . $this->getLevel()); + if (!$file) { + throw new Zend_Filter_Exception("Error opening the archive '" . $this->_options['archive'] . "'"); + } + + gzwrite($file, $content); + gzclose($file); + $compressed = true; + } else if ($this->_options['mode'] == 'deflate') { + $compressed = gzdeflate($content, $this->getLevel()); + } else { + $compressed = gzcompress($content, $this->getLevel()); + } + + if (!$compressed) { + throw new Zend_Filter_Exception('Error during compression'); + } + + return $compressed; + } + + /** + * Decompresses the given content + * + * @param string $content + * @return string + */ + public function decompress($content) + { + $archive = $this->getArchive(); + $mode = $this->getMode(); + if (@file_exists($content)) { + $archive = $content; + } + + if (@file_exists($archive)) { + $handler = fopen($archive, "rb"); + if (!$handler) { + throw new Zend_Filter_Exception("Error opening the archive '" . $archive . "'"); + } + + fseek($handler, -4, SEEK_END); + $packet = fread($handler, 4); + $bytes = unpack("V", $packet); + $size = end($bytes); + fclose($handler); + + $file = gzopen($archive, 'r'); + $compressed = gzread($file, $size); + gzclose($file); + } else if ($mode == 'deflate') { + $compressed = gzinflate($content); + } else { + $compressed = gzuncompress($content); + } + + if (!$compressed) { + throw new Zend_Filter_Exception('Error during compression'); + } + + return $compressed; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Gz'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/Lzf.php b/library/vendor/Zend/Filter/Compress/Lzf.php new file mode 100644 index 000000000..ba05d0cb6 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Lzf.php @@ -0,0 +1,87 @@ + Callback for compression + * 'archive' => Archive to use + * 'password' => Password to use + * 'target' => Target to write the files to + * ) + * + * @var array + */ + protected $_options = array( + 'callback' => null, + 'archive' => null, + 'password' => null, + 'target' => '.', + ); + + /** + * Class constructor + * + * @param array $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('rar')) { + throw new Zend_Filter_Exception('This filter needs the rar extension'); + } + parent::__construct($options); + } + + /** + * Returns the set callback for compression + * + * @return string + */ + public function getCallback() + { + return $this->_options['callback']; + } + + /** + * Sets the callback to use + * + * @param string $callback + * @return Zend_Filter_Compress_Rar + */ + public function setCallback($callback) + { + if (!is_callable($callback)) { + throw new Zend_Filter_Exception('Callback can not be accessed'); + } + + $this->_options['callback'] = $callback; + return $this; + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Rar + */ + public function setArchive($archive) + { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive); + $this->_options['archive'] = (string) $archive; + + return $this; + } + + /** + * Returns the set password + * + * @return string + */ + public function getPassword() + { + return $this->_options['password']; + } + + /** + * Sets the password to use + * + * @param string $password + * @return Zend_Filter_Compress_Rar + */ + public function setPassword($password) + { + $this->_options['password'] = (string) $password; + return $this; + } + + /** + * Returns the set targetpath + * + * @return string + */ + public function getTarget() + { + return $this->_options['target']; + } + + /** + * Sets the targetpath to use + * + * @param string $target + * @return Zend_Filter_Compress_Rar + */ + public function setTarget($target) + { + if (!file_exists(dirname($target))) { + throw new Zend_Filter_Exception("The directory '$target' does not exist"); + } + + $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target); + $this->_options['target'] = (string) $target; + return $this; + } + + /** + * Compresses the given content + * + * @param string|array $content + * @return string + */ + public function compress($content) + { + $callback = $this->getCallback(); + if ($callback === null) { + throw new Zend_Filter_Exception('No compression callback available'); + } + + $options = $this->getOptions(); + unset($options['callback']); + + $result = call_user_func($callback, $options, $content); + if ($result !== true) { + throw new Zend_Filter_Exception('Error compressing the RAR Archive'); + } + + return $this->getArchive(); + } + + /** + * Decompresses the given content + * + * @param string $content + * @return boolean + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (file_exists($content)) { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + } elseif (empty($archive) || !file_exists($archive)) { + throw new Zend_Filter_Exception('RAR Archive not found'); + } + + $password = $this->getPassword(); + if ($password !== null) { + $archive = rar_open($archive, $password); + } else { + $archive = rar_open($archive); + } + + if (!$archive) { + throw new Zend_Filter_Exception("Error opening the RAR Archive"); + } + + $target = $this->getTarget(); + if (!is_dir($target)) { + $target = dirname($target); + } + + $filelist = rar_list($archive); + if (!$filelist) { + throw new Zend_Filter_Exception("Error reading the RAR Archive"); + } + + foreach($filelist as $file) { + $file->extract($target); + } + + rar_close($archive); + return true; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Rar'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/Tar.php b/library/vendor/Zend/Filter/Compress/Tar.php new file mode 100644 index 000000000..6f14fa6e2 --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Tar.php @@ -0,0 +1,234 @@ + Archive to use + * 'target' => Target to write the files to + * ) + * + * @var array + */ + protected $_options = array( + 'archive' => null, + 'target' => '.', + 'mode' => null, + ); + + /** + * Class constructor + * + * @param array $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!class_exists('Archive_Tar')) { + try { + Zend_Loader::loadClass('Archive_Tar'); + } catch (Zend_Exception $e) { + throw new Zend_Filter_Exception('This filter needs PEARs Archive_Tar', 0, $e); + } + } + + parent::__construct($options); + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Tar + */ + public function setArchive($archive) + { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive); + $this->_options['archive'] = (string) $archive; + + return $this; + } + + /** + * Returns the set targetpath + * + * @return string + */ + public function getTarget() + { + return $this->_options['target']; + } + + /** + * Sets the targetpath to use + * + * @param string $target + * @return Zend_Filter_Compress_Tar + */ + public function setTarget($target) + { + if (!file_exists(dirname($target))) { + throw new Zend_Filter_Exception("The directory '$target' does not exist"); + } + + $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target); + $this->_options['target'] = (string) $target; + return $this; + } + + /** + * Returns the set compression mode + */ + public function getMode() + { + return $this->_options['mode']; + } + + /** + * Compression mode to use + * Eighter Gz or Bz2 + * + * @param string $mode + */ + public function setMode($mode) + { + $mode = ucfirst(strtolower($mode)); + if (($mode != 'Bz2') && ($mode != 'Gz')) { + throw new Zend_Filter_Exception("The mode '$mode' is unknown"); + } + + if (($mode == 'Bz2') && (!extension_loaded('bz2'))) { + throw new Zend_Filter_Exception('This mode needs the bz2 extension'); + } + + if (($mode == 'Gz') && (!extension_loaded('zlib'))) { + throw new Zend_Filter_Exception('This mode needs the zlib extension'); + } + } + + /** + * Compresses the given content + * + * @param string $content + * @return string + */ + public function compress($content) + { + $archive = new Archive_Tar($this->getArchive(), $this->getMode()); + if (!file_exists($content)) { + $file = $this->getTarget(); + if (is_dir($file)) { + $file .= DIRECTORY_SEPARATOR . "tar.tmp"; + } + + $result = file_put_contents($file, $content); + if ($result === false) { + throw new Zend_Filter_Exception('Error creating the temporary file'); + } + + $content = $file; + } + + if (is_dir($content)) { + // collect all file infos + foreach (new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($content, RecursiveDirectoryIterator::KEY_AS_PATHNAME), + RecursiveIteratorIterator::SELF_FIRST + ) as $directory => $info + ) { + if ($info->isFile()) { + $file[] = $directory; + } + } + + $content = $file; + } + + $result = $archive->create($content); + if ($result === false) { + throw new Zend_Filter_Exception('Error creating the Tar archive'); + } + + return $this->getArchive(); + } + + /** + * Decompresses the given content + * + * @param string $content + * @return boolean + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (file_exists($content)) { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + } elseif (empty($archive) || !file_exists($archive)) { + throw new Zend_Filter_Exception('Tar Archive not found'); + } + + $archive = new Archive_Tar($archive, $this->getMode()); + $target = $this->getTarget(); + if (!is_dir($target)) { + $target = dirname($target); + } + + $result = $archive->extract($target); + if ($result === false) { + throw new Zend_Filter_Exception('Error while extracting the Tar archive'); + } + + return true; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Tar'; + } +} diff --git a/library/vendor/Zend/Filter/Compress/Zip.php b/library/vendor/Zend/Filter/Compress/Zip.php new file mode 100644 index 000000000..7b4eb423f --- /dev/null +++ b/library/vendor/Zend/Filter/Compress/Zip.php @@ -0,0 +1,343 @@ + Archive to use + * 'password' => Password to use + * 'target' => Target to write the files to + * ) + * + * @var array + */ + protected $_options = array( + 'archive' => null, + 'target' => null, + ); + + /** + * Class constructor + * + * @param string|array $options (Optional) Options to set + */ + public function __construct($options = null) + { + if (!extension_loaded('zip')) { + throw new Zend_Filter_Exception('This filter needs the zip extension'); + } + parent::__construct($options); + } + + /** + * Returns the set archive + * + * @return string + */ + public function getArchive() + { + return $this->_options['archive']; + } + + /** + * Sets the archive to use for de-/compression + * + * @param string $archive Archive to use + * @return Zend_Filter_Compress_Rar + */ + public function setArchive($archive) + { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive); + $this->_options['archive'] = (string) $archive; + + return $this; + } + + /** + * Returns the set targetpath + * + * @return string + */ + public function getTarget() + { + return $this->_options['target']; + } + + /** + * Sets the target to use + * + * @param string $target + * @return Zend_Filter_Compress_Rar + */ + public function setTarget($target) + { + if (!file_exists(dirname($target))) { + throw new Zend_Filter_Exception("The directory '$target' does not exist"); + } + + $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target); + $this->_options['target'] = (string) $target; + return $this; + } + + /** + * Compresses the given content + * + * @param string $content + * @return string Compressed archive + */ + public function compress($content) + { + $zip = new ZipArchive(); + $res = $zip->open($this->getArchive(), ZipArchive::CREATE | ZipArchive::OVERWRITE); + + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + + if (file_exists($content)) { + $content = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + $basename = substr($content, strrpos($content, DIRECTORY_SEPARATOR) + 1); + if (is_dir($content)) { + $index = strrpos($content, DIRECTORY_SEPARATOR) + 1; + $content .= DIRECTORY_SEPARATOR; + $stack = array($content); + while (!empty($stack)) { + $current = array_pop($stack); + $files = array(); + + $dir = dir($current); + while (false !== ($node = $dir->read())) { + if (($node == '.') || ($node == '..')) { + continue; + } + + if (is_dir($current . $node)) { + array_push($stack, $current . $node . DIRECTORY_SEPARATOR); + } + + if (is_file($current . $node)) { + $files[] = $node; + } + } + + $local = substr($current, $index); + $zip->addEmptyDir(substr($local, 0, -1)); + + foreach ($files as $file) { + $zip->addFile($current . $file, $local . $file); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + } + } + } else { + $res = $zip->addFile($content, $basename); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + } + } else { + $file = $this->getTarget(); + if (!is_dir($file)) { + $file = basename($file); + } else { + $file = "zip.tmp"; + } + + $res = $zip->addFromString($file, $content); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + } + + $zip->close(); + return $this->_options['archive']; + } + + /** + * Decompresses the given content + * + * @param string $content + * @return string + */ + public function decompress($content) + { + $archive = $this->getArchive(); + if (file_exists($content)) { + $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content)); + } elseif (empty($archive) || !file_exists($archive)) { + throw new Zend_Filter_Exception('ZIP Archive not found'); + } + + $zip = new ZipArchive(); + $res = $zip->open($archive); + + $target = $this->getTarget(); + + if (!empty($target) && !is_dir($target)) { + $target = dirname($target); + } + + if (!empty($target)) { + $target = rtrim($target, '/\\') . DIRECTORY_SEPARATOR; + } + + if (empty($target) || !is_dir($target)) { + throw new Zend_Filter_Exception('No target for ZIP decompression set'); + } + + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + + if (version_compare(PHP_VERSION, '5.2.8', '<')) { + for ($i = 0; $i < $zip->numFiles; $i++) { + $statIndex = $zip->statIndex($i); + $currName = $statIndex['name']; + if (($currName{0} == '/') || + (substr($currName, 0, 2) == '..') || + (substr($currName, 0, 4) == './..') + ) + { + throw new Zend_Filter_Exception('Upward directory traversal was detected inside ' . $archive + . ' please use PHP 5.2.8 or greater to take advantage of path resolution features of ' + . 'the zip extension in this decompress() method.' + ); + } + } + } + + $res = @$zip->extractTo($target); + if ($res !== true) { + throw new Zend_Filter_Exception($this->_errorString($res)); + } + + $zip->close(); + return $target; + } + + /** + * Returns the proper string based on the given error constant + * + * @param string $error + */ + protected function _errorString($error) + { + switch($error) { + case ZipArchive::ER_MULTIDISK : + return 'Multidisk ZIP Archives not supported'; + + case ZipArchive::ER_RENAME : + return 'Failed to rename the temporary file for ZIP'; + + case ZipArchive::ER_CLOSE : + return 'Failed to close the ZIP Archive'; + + case ZipArchive::ER_SEEK : + return 'Failure while seeking the ZIP Archive'; + + case ZipArchive::ER_READ : + return 'Failure while reading the ZIP Archive'; + + case ZipArchive::ER_WRITE : + return 'Failure while writing the ZIP Archive'; + + case ZipArchive::ER_CRC : + return 'CRC failure within the ZIP Archive'; + + case ZipArchive::ER_ZIPCLOSED : + return 'ZIP Archive already closed'; + + case ZipArchive::ER_NOENT : + return 'No such file within the ZIP Archive'; + + case ZipArchive::ER_EXISTS : + return 'ZIP Archive already exists'; + + case ZipArchive::ER_OPEN : + return 'Can not open ZIP Archive'; + + case ZipArchive::ER_TMPOPEN : + return 'Failure creating temporary ZIP Archive'; + + case ZipArchive::ER_ZLIB : + return 'ZLib Problem'; + + case ZipArchive::ER_MEMORY : + return 'Memory allocation problem while working on a ZIP Archive'; + + case ZipArchive::ER_CHANGED : + return 'ZIP Entry has been changed'; + + case ZipArchive::ER_COMPNOTSUPP : + return 'Compression method not supported within ZLib'; + + case ZipArchive::ER_EOF : + return 'Premature EOF within ZIP Archive'; + + case ZipArchive::ER_INVAL : + return 'Invalid argument for ZLIB'; + + case ZipArchive::ER_NOZIP : + return 'Given file is no zip archive'; + + case ZipArchive::ER_INTERNAL : + return 'Internal error while working on a ZIP Archive'; + + case ZipArchive::ER_INCONS : + return 'Inconsistent ZIP archive'; + + case ZipArchive::ER_REMOVE : + return 'Can not remove ZIP Archive'; + + case ZipArchive::ER_DELETED : + return 'ZIP Entry has been deleted'; + + default : + return 'Unknown error within ZIP Archive'; + } + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Zip'; + } +} diff --git a/library/vendor/Zend/Filter/Decompress.php b/library/vendor/Zend/Filter/Decompress.php new file mode 100644 index 000000000..52ba2aafa --- /dev/null +++ b/library/vendor/Zend/Filter/Decompress.php @@ -0,0 +1,48 @@ +getAdapter()->decompress($value); + } +} diff --git a/library/vendor/Zend/Filter/Decrypt.php b/library/vendor/Zend/Filter/Decrypt.php new file mode 100644 index 000000000..0c9c47455 --- /dev/null +++ b/library/vendor/Zend/Filter/Decrypt.php @@ -0,0 +1,48 @@ +_adapter->decrypt($value); + } +} diff --git a/library/vendor/Zend/Filter/Digits.php b/library/vendor/Zend/Filter/Digits.php new file mode 100644 index 000000000..6031c1121 --- /dev/null +++ b/library/vendor/Zend/Filter/Digits.php @@ -0,0 +1,81 @@ +toArray(); + } + + $this->setAdapter($options); + } + + /** + * Returns the name of the set adapter + * + * @return string + */ + public function getAdapter() + { + return $this->_adapter->toString(); + } + + /** + * Sets new encryption options + * + * @param string|array $options (Optional) Encryption options + * @return Zend_Filter_Encrypt + */ + public function setAdapter($options = null) + { + if (is_string($options)) { + $adapter = $options; + } else if (isset($options['adapter'])) { + $adapter = $options['adapter']; + unset($options['adapter']); + } else { + $adapter = 'Mcrypt'; + } + + if (!is_array($options)) { + $options = array(); + } + + if (Zend_Loader::isReadable('Zend/Filter/Encrypt/' . ucfirst($adapter). '.php')) { + $adapter = 'Zend_Filter_Encrypt_' . ucfirst($adapter); + } + + if (!class_exists($adapter)) { + Zend_Loader::loadClass($adapter); + } + + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Filter_Encrypt_Interface) { + throw new Zend_Filter_Exception("Encoding adapter '" . $adapter . "' does not implement Zend_Filter_Encrypt_Interface"); + } + + return $this; + } + + /** + * Calls adapter methods + * + * @param string $method Method to call + * @param string|array $options Options for this method + */ + public function __call($method, $options) + { + $part = substr($method, 0, 3); + if ((($part != 'get') and ($part != 'set')) or !method_exists($this->_adapter, $method)) { + throw new Zend_Filter_Exception("Unknown method '{$method}'"); + } + + return call_user_func_array(array($this->_adapter, $method), $options); + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts the content $value with the defined settings + * + * @param string $value Content to encrypt + * @return string The encrypted content + */ + public function filter($value) + { + return $this->_adapter->encrypt($value); + } +} diff --git a/library/vendor/Zend/Filter/Encrypt/Interface.php b/library/vendor/Zend/Filter/Encrypt/Interface.php new file mode 100644 index 000000000..9a396841a --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Interface.php @@ -0,0 +1,47 @@ + encryption key string + * 'algorithm' => algorithm to use + * 'algorithm_directory' => directory where to find the algorithm + * 'mode' => encryption mode to use + * 'modedirectory' => directory where to find the mode + * ) + */ + protected $_encryption = array( + 'key' => 'ZendFramework', + 'algorithm' => 'blowfish', + 'algorithm_directory' => '', + 'mode' => 'cbc', + 'mode_directory' => '', + 'vector' => null, + 'salt' => false + ); + + /** + * Internal compression + * + * @var array + */ + protected $_compression; + + protected static $_srandCalled = false; + + /** + * Class constructor + * + * @param string|array|Zend_Config $options Cryption Options + */ + public function __construct($options) + { + if (!extension_loaded('mcrypt')) { + throw new Zend_Filter_Exception('This filter needs the mcrypt extension'); + } + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options)) { + $options = array('key' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + if (array_key_exists('compression', $options)) { + $this->setCompression($options['compression']); + unset($options['compress']); + } + + $this->setEncryption($options); + } + + /** + * Returns the set encryption options + * + * @return array + */ + public function getEncryption() + { + return $this->_encryption; + } + + /** + * Sets new encryption options + * + * @param string|array $options Encryption options + * @return Zend_Filter_File_Encryption + */ + public function setEncryption($options) + { + if (is_string($options)) { + $options = array('key' => $options); + } + + if (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + $options = $options + $this->getEncryption(); + $algorithms = mcrypt_list_algorithms($options['algorithm_directory']); + if (!in_array($options['algorithm'], $algorithms)) { + throw new Zend_Filter_Exception("The algorithm '{$options['algorithm']}' is not supported"); + } + + $modes = mcrypt_list_modes($options['mode_directory']); + if (!in_array($options['mode'], $modes)) { + throw new Zend_Filter_Exception("The mode '{$options['mode']}' is not supported"); + } + + if (!mcrypt_module_self_test($options['algorithm'], $options['algorithm_directory'])) { + throw new Zend_Filter_Exception('The given algorithm can not be used due an internal mcrypt problem'); + } + + if (!isset($options['vector'])) { + $options['vector'] = null; + } + + $this->_encryption = $options; + $this->setVector($options['vector']); + + return $this; + } + + /** + * Returns the set vector + * + * @return string + */ + public function getVector() + { + return $this->_encryption['vector']; + } + + /** + * Sets the initialization vector + * + * @param string $vector (Optional) Vector to set + * @return Zend_Filter_Encrypt_Mcrypt + */ + public function setVector($vector = null) + { + $cipher = $this->_openCipher(); + $size = mcrypt_enc_get_iv_size($cipher); + if (empty($vector)) { + $this->_srand(); + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { + $method = MCRYPT_RAND; + } else { + if (file_exists('/dev/urandom') || (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) { + $method = MCRYPT_DEV_URANDOM; + } elseif (file_exists('/dev/random')) { + $method = MCRYPT_DEV_RANDOM; + } else { + $method = MCRYPT_RAND; + } + } + $vector = mcrypt_create_iv($size, $method); + } else if (strlen($vector) != $size) { + throw new Zend_Filter_Exception('The given vector has a wrong size for the set algorithm'); + } + + $this->_encryption['vector'] = $vector; + $this->_closeCipher($cipher); + + return $this; + } + + /** + * Returns the compression + * + * @return array + */ + public function getCompression() + { + return $this->_compression; + } + + /** + * Sets a internal compression for values to encrypt + * + * @param string|array $compression + * @return Zend_Filter_Encrypt_Mcrypt + */ + public function setCompression($compression) + { + if (is_string($this->_compression)) { + $compression = array('adapter' => $compression); + } + + $this->_compression = $compression; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts $value with the defined settings + * + * @param string $value The content to encrypt + * @return string The encrypted content + */ + public function encrypt($value) + { + // compress prior to encryption + if (!empty($this->_compression)) { + $compress = new Zend_Filter_Compress($this->_compression); + $value = $compress->filter($value); + } + + $cipher = $this->_openCipher(); + $this->_initCipher($cipher); + $encrypted = mcrypt_generic($cipher, $value); + mcrypt_generic_deinit($cipher); + $this->_closeCipher($cipher); + + return $encrypted; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts $value with the defined settings + * + * @param string $value Content to decrypt + * @return string The decrypted content + */ + public function decrypt($value) + { + $cipher = $this->_openCipher(); + $this->_initCipher($cipher); + $decrypted = mdecrypt_generic($cipher, $value); + mcrypt_generic_deinit($cipher); + $this->_closeCipher($cipher); + + // decompress after decryption + if (!empty($this->_compression)) { + $decompress = new Zend_Filter_Decompress($this->_compression); + $decrypted = $decompress->filter($decrypted); + } + + return $decrypted; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Mcrypt'; + } + + /** + * Open a cipher + * + * @throws Zend_Filter_Exception When the cipher can not be opened + * @return resource Returns the opened cipher + */ + protected function _openCipher() + { + $cipher = mcrypt_module_open( + $this->_encryption['algorithm'], + $this->_encryption['algorithm_directory'], + $this->_encryption['mode'], + $this->_encryption['mode_directory']); + + if ($cipher === false) { + throw new Zend_Filter_Exception('Mcrypt can not be opened with your settings'); + } + + return $cipher; + } + + /** + * Close a cipher + * + * @param resource $cipher Cipher to close + * @return Zend_Filter_Encrypt_Mcrypt + */ + protected function _closeCipher($cipher) + { + mcrypt_module_close($cipher); + + return $this; + } + + /** + * Initialises the cipher with the set key + * + * @param resource $cipher + * @throws + * @return resource + */ + protected function _initCipher($cipher) + { + $key = $this->_encryption['key']; + + $keysizes = mcrypt_enc_get_supported_key_sizes($cipher); + if (empty($keysizes) || ($this->_encryption['salt'] == true)) { + $this->_srand(); + $keysize = mcrypt_enc_get_key_size($cipher); + $key = substr(md5($key), 0, $keysize); + } else if (!in_array(strlen($key), $keysizes)) { + throw new Zend_Filter_Exception('The given key has a wrong size for the set algorithm'); + } + + $result = mcrypt_generic_init($cipher, $key, $this->_encryption['vector']); + if ($result < 0) { + throw new Zend_Filter_Exception('Mcrypt could not be initialize with the given setting'); + } + + return $this; + } + + /** + * _srand() interception + * + * @see ZF-8742 + */ + protected function _srand() + { + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + return; + } + + if (!self::$_srandCalled) { + srand((double) microtime() * 1000000); + self::$_srandCalled = true; + } + } +} diff --git a/library/vendor/Zend/Filter/Encrypt/Openssl.php b/library/vendor/Zend/Filter/Encrypt/Openssl.php new file mode 100644 index 000000000..5239ea436 --- /dev/null +++ b/library/vendor/Zend/Filter/Encrypt/Openssl.php @@ -0,0 +1,480 @@ + public keys + * 'private' => private keys + * 'envelope' => resulting envelope keys + * ) + */ + protected $_keys = array( + 'public' => array(), + 'private' => array(), + 'envelope' => array() + ); + + /** + * Internal passphrase + * + * @var string + */ + protected $_passphrase; + + /** + * Internal compression + * + * @var array + */ + protected $_compression; + + /** + * Internal create package + * + * @var boolean + */ + protected $_package = false; + + /** + * Class constructor + * Available options + * 'public' => public key + * 'private' => private key + * 'envelope' => envelope key + * 'passphrase' => passphrase + * 'compression' => compress value with this compression adapter + * 'package' => pack envelope keys into encrypted string, simplifies decryption + * + * @param string|array $options Options for this adapter + */ + public function __construct($options = array()) + { + if (!extension_loaded('openssl')) { + throw new Zend_Filter_Exception('This filter needs the openssl extension'); + } + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (!is_array($options)) { + $options = array('public' => $options); + } + + if (array_key_exists('passphrase', $options)) { + $this->setPassphrase($options['passphrase']); + unset($options['passphrase']); + } + + if (array_key_exists('compression', $options)) { + $this->setCompression($options['compression']); + unset($options['compress']); + } + + if (array_key_exists('package', $options)) { + $this->setPackage($options['package']); + unset($options['package']); + } + + $this->_setKeys($options); + } + + /** + * Sets the encryption keys + * + * @param string|array $keys Key with type association + * @return Zend_Filter_Encrypt_Openssl + */ + protected function _setKeys($keys) + { + if (!is_array($keys)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + foreach ($keys as $type => $key) { + if (ctype_print($key) && is_file(realpath($key)) && is_readable($key)) { + $file = fopen($key, 'r'); + $cert = fread($file, 8192); + fclose($file); + } else { + $cert = $key; + $key = count($this->_keys[$type]); + } + + switch ($type) { + case 'public': + $test = openssl_pkey_get_public($cert); + if ($test === false) { + throw new Zend_Filter_Exception("Public key '{$cert}' not valid"); + } + + openssl_free_key($test); + $this->_keys['public'][$key] = $cert; + break; + case 'private': + $test = openssl_pkey_get_private($cert, $this->_passphrase); + if ($test === false) { + throw new Zend_Filter_Exception("Private key '{$cert}' not valid"); + } + + openssl_free_key($test); + $this->_keys['private'][$key] = $cert; + break; + case 'envelope': + $this->_keys['envelope'][$key] = $cert; + break; + default: + break; + } + } + + return $this; + } + + /** + * Returns all public keys + * + * @return array + */ + public function getPublicKey() + { + $key = $this->_keys['public']; + return $key; + } + + /** + * Sets public keys + * + * @param string|array $key Public keys + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPublicKey($key) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'public') { + $key['public'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('public' => $key); + } + + return $this->_setKeys($key); + } + + /** + * Returns all private keys + * + * @return array + */ + public function getPrivateKey() + { + $key = $this->_keys['private']; + return $key; + } + + /** + * Sets private keys + * + * @param string $key Private key + * @param string $passphrase + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPrivateKey($key, $passphrase = null) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'private') { + $key['private'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('private' => $key); + } + + if ($passphrase !== null) { + $this->setPassphrase($passphrase); + } + + return $this->_setKeys($key); + } + + /** + * Returns all envelope keys + * + * @return array + */ + public function getEnvelopeKey() + { + $key = $this->_keys['envelope']; + return $key; + } + + /** + * Sets envelope keys + * + * @param string|array $options Envelope keys + * @return Zend_Filter_Encrypt_Openssl + */ + public function setEnvelopeKey($key) + { + if (is_array($key)) { + foreach($key as $type => $option) { + if ($type !== 'envelope') { + $key['envelope'] = $option; + unset($key[$type]); + } + } + } else { + $key = array('envelope' => $key); + } + + return $this->_setKeys($key); + } + + /** + * Returns the passphrase + * + * @return string + */ + public function getPassphrase() + { + return $this->_passphrase; + } + + /** + * Sets a new passphrase + * + * @param string $passphrase + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPassphrase($passphrase) + { + $this->_passphrase = $passphrase; + return $this; + } + + /** + * Returns the compression + * + * @return array + */ + public function getCompression() + { + return $this->_compression; + } + + /** + * Sets a internal compression for values to encrypt + * + * @param string|array $compression + * @return Zend_Filter_Encrypt_Openssl + */ + public function setCompression($compression) + { + if (is_string($this->_compression)) { + $compression = array('adapter' => $compression); + } + + $this->_compression = $compression; + return $this; + } + + /** + * Returns if header should be packaged + * + * @return boolean + */ + public function getPackage() + { + return $this->_package; + } + + /** + * Sets if the envelope keys should be included in the encrypted value + * + * @param boolean $package + * @return Zend_Filter_Encrypt_Openssl + */ + public function setPackage($package) + { + $this->_package = (boolean) $package; + return $this; + } + + /** + * Encrypts $value with the defined settings + * Note that you also need the "encrypted" keys to be able to decrypt + * + * @param string $value Content to encrypt + * @return string The encrypted content + * @throws Zend_Filter_Exception + */ + public function encrypt($value) + { + $encrypted = array(); + $encryptedkeys = array(); + + if (count($this->_keys['public']) == 0) { + throw new Zend_Filter_Exception('Openssl can not encrypt without public keys'); + } + + $keys = array(); + $fingerprints = array(); + $count = -1; + foreach($this->_keys['public'] as $key => $cert) { + $keys[$key] = openssl_pkey_get_public($cert); + if ($this->_package) { + $details = openssl_pkey_get_details($keys[$key]); + if ($details === false) { + $details = array('key' => 'ZendFramework'); + } + + ++$count; + $fingerprints[$count] = md5($details['key']); + } + } + + // compress prior to encryption + if (!empty($this->_compression)) { + $compress = new Zend_Filter_Compress($this->_compression); + $value = $compress->filter($value); + } + + $crypt = openssl_seal($value, $encrypted, $encryptedkeys, $keys); + foreach ($keys as $key) { + openssl_free_key($key); + } + + if ($crypt === false) { + throw new Zend_Filter_Exception('Openssl was not able to encrypt your content with the given options'); + } + + $this->_keys['envelope'] = $encryptedkeys; + + // Pack data and envelope keys into single string + if ($this->_package) { + $header = pack('n', count($this->_keys['envelope'])); + foreach($this->_keys['envelope'] as $key => $envKey) { + $header .= pack('H32n', $fingerprints[$key], strlen($envKey)) . $envKey; + } + + $encrypted = $header . $encrypted; + } + + return $encrypted; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts $value with the defined settings + * + * @param string $value Content to decrypt + * @return string The decrypted content + * @throws Zend_Filter_Exception + */ + public function decrypt($value) + { + $decrypted = ""; + $envelope = current($this->getEnvelopeKey()); + + if (count($this->_keys['private']) !== 1) { + throw new Zend_Filter_Exception('Please give a private key for decryption with Openssl'); + } + + if (!$this->_package && empty($envelope)) { + throw new Zend_Filter_Exception('Please give a envelope key for decryption with Openssl'); + } + + foreach($this->_keys['private'] as $key => $cert) { + $keys = openssl_pkey_get_private($cert, $this->getPassphrase()); + } + + if ($this->_package) { + $details = openssl_pkey_get_details($keys); + if ($details !== false) { + $fingerprint = md5($details['key']); + } else { + $fingerprint = md5("ZendFramework"); + } + + $count = unpack('ncount', $value); + $count = $count['count']; + $length = 2; + for($i = $count; $i > 0; --$i) { + $header = unpack('H32print/nsize', substr($value, $length, 18)); + $length += 18; + if ($header['print'] == $fingerprint) { + $envelope = substr($value, $length, $header['size']); + } + + $length += $header['size']; + } + + // remainder of string is the value to decrypt + $value = substr($value, $length); + } + + $crypt = openssl_open($value, $decrypted, $envelope, $keys); + openssl_free_key($keys); + + if ($crypt === false) { + throw new Zend_Filter_Exception('Openssl was not able to decrypt you content with the given options'); + } + + // decompress after decryption + if (!empty($this->_compression)) { + $decompress = new Zend_Filter_Decompress($this->_compression); + $decrypted = $decompress->filter($decrypted); + } + + return $decrypted; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return 'Openssl'; + } +} diff --git a/library/vendor/Zend/Filter/Exception.php b/library/vendor/Zend/Filter/Exception.php new file mode 100644 index 000000000..10e9b8ac6 --- /dev/null +++ b/library/vendor/Zend/Filter/Exception.php @@ -0,0 +1,36 @@ +_filename; + } + + /** + * Sets the new filename where the content will be stored + * + * @param string $filename (Optional) New filename to set + * @return Zend_Filter_File_Encryt + */ + public function setFilename($filename = null) + { + $this->_filename = $filename; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Decrypts the file $value with the defined settings + * + * @param string $value Full path of file to change + * @return string The filename which has been set, or false when there were errors + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!isset($this->_filename)) { + $this->_filename = $value; + } + + if (file_exists($this->_filename) and !is_writable($this->_filename)) { + throw new Zend_Filter_Exception("File '{$this->_filename}' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $decrypted = parent::filter($content); + $result = file_put_contents($this->_filename, $decrypted); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '{$this->_filename}'"); + } + + return $this->_filename; + } +} diff --git a/library/vendor/Zend/Filter/File/Encrypt.php b/library/vendor/Zend/Filter/File/Encrypt.php new file mode 100644 index 000000000..c37c23ff2 --- /dev/null +++ b/library/vendor/Zend/Filter/File/Encrypt.php @@ -0,0 +1,101 @@ +_filename; + } + + /** + * Sets the new filename where the content will be stored + * + * @param string $filename (Optional) New filename to set + * @return Zend_Filter_File_Encryt + */ + public function setFilename($filename = null) + { + $this->_filename = $filename; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Encrypts the file $value with the defined settings + * + * @param string $value Full path of file to change + * @return string The filename which has been set, or false when there were errors + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!isset($this->_filename)) { + $this->_filename = $value; + } + + if (file_exists($this->_filename) and !is_writable($this->_filename)) { + throw new Zend_Filter_Exception("File '{$this->_filename}' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $encrypted = parent::filter($content); + $result = file_put_contents($this->_filename, $encrypted); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '{$this->_filename}'"); + } + + return $this->_filename; + } +} diff --git a/library/vendor/Zend/Filter/File/LowerCase.php b/library/vendor/Zend/Filter/File/LowerCase.php new file mode 100644 index 000000000..8a2d755cd --- /dev/null +++ b/library/vendor/Zend/Filter/File/LowerCase.php @@ -0,0 +1,79 @@ +setEncoding($options); + } + } + + /** + * Defined by Zend_Filter_Interface + * + * Does a lowercase on the content of the given file + * + * @param string $value Full path of file to change + * @return string The given $value + * @throws Zend_Filter_Exception + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!is_writable($value)) { + throw new Zend_Filter_Exception("File '$value' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $content = parent::filter($content); + $result = file_put_contents($value, $content); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '$value'"); + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/File/Rename.php b/library/vendor/Zend/Filter/File/Rename.php new file mode 100644 index 000000000..cec3b2546 --- /dev/null +++ b/library/vendor/Zend/Filter/File/Rename.php @@ -0,0 +1,304 @@ + Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Target file or directory to be renamed + * @param string $target Source filename or directory (deprecated) + * @param bool $overwrite Should existing files be overwritten (deprecated) + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options)) { + $options = array('target' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception('Invalid options argument provided to filter'); + } + + if (1 < func_num_args()) { + $argv = func_get_args(); + array_shift($argv); + $source = array_shift($argv); + $overwrite = false; + if (!empty($argv)) { + $overwrite = array_shift($argv); + } + $options['source'] = $source; + $options['overwrite'] = $overwrite; + } + + $this->setFile($options); + } + + /** + * Returns the files to rename and their new name and location + * + * @return array + */ + public function getFile() + { + return $this->_files; + } + + /** + * Sets a new file or directory as target, deleting existing ones + * + * Array accepts the following keys: + * 'source' => Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Old file or directory to be rewritten + * @return Zend_Filter_File_Rename + */ + public function setFile($options) + { + $this->_files = array(); + $this->addFile($options); + + return $this; + } + + /** + * Adds a new file or directory as target to the existing ones + * + * Array accepts the following keys: + * 'source' => Source filename or directory which will be renamed + * 'target' => Target filename or directory, the new name of the sourcefile + * 'overwrite' => Shall existing files be overwritten ? + * + * @param string|array $options Old file or directory to be rewritten + * @return Zend_Filter_File_Rename + */ + public function addFile($options) + { + if (is_string($options)) { + $options = array('target' => $options); + } elseif (!is_array($options)) { + throw new Zend_Filter_Exception ('Invalid options to rename filter provided'); + } + + $this->_convertOptions($options); + + return $this; + } + + /** + * Returns only the new filename without moving it + * But existing files will be erased when the overwrite option is true + * + * @param string $value Full path of file to change + * @param boolean $source Return internal informations + * @return string The new filename which has been set + */ + public function getNewName($value, $source = false) + { + $file = $this->_getFileName($value); + + if (!is_array($file) || !array_key_exists('source', $file) || !array_key_exists('target', $file)) { + return $value; + } + + if ($file['source'] == $file['target']) { + return $value; + } + + if (!file_exists($file['source'])) { + return $value; + } + + if (($file['overwrite'] == true) && (file_exists($file['target']))) { + unlink($file['target']); + } + + if (file_exists($file['target'])) { + throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. It already exists.", $value)); + } + + if ($source) { + return $file; + } + + return $file['target']; + } + + /** + * Defined by Zend_Filter_Interface + * + * Renames the file $value to the new name set before + * Returns the file $value, removing all but digit characters + * + * @param string $value Full path of file to change + * @throws Zend_Filter_Exception + * @return string The new filename which has been set, or false when there were errors + */ + public function filter($value) + { + $file = $this->getNewName($value, true); + if (is_string($file)) { + return $file; + } + + $result = rename($file['source'], $file['target']); + + if ($result === true) { + return $file['target']; + } + + throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. An error occured while processing the file.", $value)); + } + + /** + * Internal method for creating the file array + * Supports single and nested arrays + * + * @param array $options + * @return array + */ + protected function _convertOptions($options) { + $files = array(); + foreach ($options as $key => $value) { + if (is_array($value)) { + $this->_convertOptions($value); + continue; + } + + switch ($key) { + case "source": + $files['source'] = (string) $value; + break; + + case 'target' : + $files['target'] = (string) $value; + break; + + case 'overwrite' : + $files['overwrite'] = (boolean) $value; + break; + + default: + break; + } + } + + if (empty($files)) { + return $this; + } + + if (empty($files['source'])) { + $files['source'] = '*'; + } + + if (empty($files['target'])) { + $files['target'] = '*'; + } + + if (empty($files['overwrite'])) { + $files['overwrite'] = false; + } + + $found = false; + foreach ($this->_files as $key => $value) { + if ($value['source'] == $files['source']) { + $this->_files[$key] = $files; + $found = true; + } + } + + if (!$found) { + $count = count($this->_files); + $this->_files[$count] = $files; + } + + return $this; + } + + /** + * Internal method to resolve the requested source + * and return all other related parameters + * + * @param string $file Filename to get the informations for + * @return array + */ + protected function _getFileName($file) + { + $rename = array(); + foreach ($this->_files as $value) { + if ($value['source'] == '*') { + if (!isset($rename['source'])) { + $rename = $value; + $rename['source'] = $file; + } + } + + if ($value['source'] == $file) { + $rename = $value; + } + } + + if (!isset($rename['source'])) { + return $file; + } + + if (!isset($rename['target']) or ($rename['target'] == '*')) { + $rename['target'] = $rename['source']; + } + + if (is_dir($rename['target'])) { + $name = basename($rename['source']); + $last = $rename['target'][strlen($rename['target']) - 1]; + if (($last != '/') and ($last != '\\')) { + $rename['target'] .= DIRECTORY_SEPARATOR; + } + + $rename['target'] .= $name; + } + + return $rename; + } +} diff --git a/library/vendor/Zend/Filter/File/UpperCase.php b/library/vendor/Zend/Filter/File/UpperCase.php new file mode 100644 index 000000000..c99e8b8ad --- /dev/null +++ b/library/vendor/Zend/Filter/File/UpperCase.php @@ -0,0 +1,79 @@ +setEncoding($options); + } + } + + /** + * Defined by Zend_Filter_Interface + * + * Does a lowercase on the content of the given file + * + * @param string $value Full path of file to change + * @return string The given $value + * @throws Zend_Filter_Exception + */ + public function filter($value) + { + if (!file_exists($value)) { + throw new Zend_Filter_Exception("File '$value' not found"); + } + + if (!is_writable($value)) { + throw new Zend_Filter_Exception("File '$value' is not writable"); + } + + $content = file_get_contents($value); + if (!$content) { + throw new Zend_Filter_Exception("Problem while reading file '$value'"); + } + + $content = parent::filter($content); + $result = file_put_contents($value, $content); + + if (!$result) { + throw new Zend_Filter_Exception("Problem while writing file '$value'"); + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/HtmlEntities.php b/library/vendor/Zend/Filter/HtmlEntities.php new file mode 100644 index 000000000..9c6acb8f6 --- /dev/null +++ b/library/vendor/Zend/Filter/HtmlEntities.php @@ -0,0 +1,213 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['quotestyle'] = array_shift($options); + if (!empty($options)) { + $temp['charset'] = array_shift($options); + } + + $options = $temp; + } + + if (!isset($options['quotestyle'])) { + $options['quotestyle'] = ENT_COMPAT; + } + + if (!isset($options['encoding'])) { + $options['encoding'] = 'UTF-8'; + } + if (isset($options['charset'])) { + $options['encoding'] = $options['charset']; + } + + if (!isset($options['doublequote'])) { + $options['doublequote'] = true; + } + + $this->setQuoteStyle($options['quotestyle']); + $this->setEncoding($options['encoding']); + $this->setDoubleQuote($options['doublequote']); + } + + /** + * Returns the quoteStyle option + * + * @return integer + */ + public function getQuoteStyle() + { + return $this->_quoteStyle; + } + + /** + * Sets the quoteStyle option + * + * @param integer $quoteStyle + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setQuoteStyle($quoteStyle) + { + $this->_quoteStyle = $quoteStyle; + return $this; + } + + + /** + * Get encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set encoding + * + * @param string $value + * @return Zend_Filter_HtmlEntities + */ + public function setEncoding($value) + { + $this->_encoding = (string) $value; + return $this; + } + + /** + * Returns the charSet option + * + * Proxies to {@link getEncoding()} + * + * @return string + */ + public function getCharSet() + { + return $this->getEncoding(); + } + + /** + * Sets the charSet option + * + * Proxies to {@link setEncoding()} + * + * @param string $charSet + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setCharSet($charSet) + { + return $this->setEncoding($charSet); + } + + /** + * Returns the doubleQuote option + * + * @return boolean + */ + public function getDoubleQuote() + { + return $this->_doubleQuote; + } + + /** + * Sets the doubleQuote option + * + * @param boolean $doubleQuote + * @return Zend_Filter_HtmlEntities Provides a fluent interface + */ + public function setDoubleQuote($doubleQuote) + { + $this->_doubleQuote = (boolean) $doubleQuote; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to their corresponding HTML entity + * equivalents where they exist + * + * @param string $value + * @return string + */ + public function filter($value) + { + $filtered = htmlentities((string) $value, $this->getQuoteStyle(), $this->getEncoding(), $this->getDoubleQuote()); + if (strlen((string) $value) && !strlen($filtered)) { + if (!function_exists('iconv')) { + throw new Zend_Filter_Exception('Encoding mismatch has resulted in htmlentities errors'); + } + $enc = $this->getEncoding(); + $value = iconv('', $enc . '//IGNORE', (string) $value); + $filtered = htmlentities($value, $this->getQuoteStyle(), $enc, $this->getDoubleQuote()); + if (!strlen($filtered)) { + throw new Zend_Filter_Exception('Encoding mismatch has resulted in htmlentities errors'); + } + } + return $filtered; + } +} diff --git a/library/vendor/Zend/Filter/Inflector.php b/library/vendor/Zend/Filter/Inflector.php new file mode 100644 index 000000000..65a872dd9 --- /dev/null +++ b/library/vendor/Zend/Filter/Inflector.php @@ -0,0 +1,523 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + + if (!empty($options)) { + $temp['target'] = array_shift($options); + } + + if (!empty($options)) { + $temp['rules'] = array_shift($options); + } + + if (!empty($options)) { + $temp['throwTargetExceptionsOn'] = array_shift($options); + } + + if (!empty($options)) { + $temp['targetReplacementIdentifier'] = array_shift($options); + } + + $options = $temp; + } + + $this->setOptions($options); + } + + /** + * Retreive PluginLoader + * + * @return Zend_Loader_PluginLoader_Interface + */ + public function getPluginLoader() + { + if (!$this->_pluginLoader instanceof Zend_Loader_PluginLoader_Interface) { + $this->_pluginLoader = new Zend_Loader_PluginLoader(array('Zend_Filter_' => 'Zend/Filter/'), __CLASS__); + } + + return $this->_pluginLoader; + } + + /** + * Set PluginLoader + * + * @param Zend_Loader_PluginLoader_Interface $pluginLoader + * @return Zend_Filter_Inflector + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $pluginLoader) + { + $this->_pluginLoader = $pluginLoader; + return $this; + } + + /** + * Use Zend_Config object to set object state + * + * @deprecated Use setOptions() instead + * @param Zend_Config $config + * @return Zend_Filter_Inflector + */ + public function setConfig(Zend_Config $config) + { + return $this->setOptions($config); + } + + /** + * Set options + * + * @param array $options + * @return Zend_Filter_Inflector + */ + public function setOptions($options) { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + // Set Präfix Path + if (array_key_exists('filterPrefixPath', $options)) { + if (!is_scalar($options['filterPrefixPath'])) { + foreach ($options['filterPrefixPath'] as $prefix => $path) { + $this->addFilterPrefixPath($prefix, $path); + } + } + } + + if (array_key_exists('throwTargetExceptionsOn', $options)) { + $this->setThrowTargetExceptionsOn($options['throwTargetExceptionsOn']); + } + + if (array_key_exists('targetReplacementIdentifier', $options)) { + $this->setTargetReplacementIdentifier($options['targetReplacementIdentifier']); + } + + if (array_key_exists('target', $options)) { + $this->setTarget($options['target']); + } + + if (array_key_exists('rules', $options)) { + $this->addRules($options['rules']); + } + + return $this; + } + + /** + * Convienence method to add prefix and path to PluginLoader + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Inflector + */ + public function addFilterPrefixPath($prefix, $path) + { + $this->getPluginLoader()->addPrefixPath($prefix, $path); + return $this; + } + + /** + * Set Whether or not the inflector should throw an exception when a replacement + * identifier is still found within an inflected target. + * + * @param bool $throwTargetExceptions + * @return Zend_Filter_Inflector + */ + public function setThrowTargetExceptionsOn($throwTargetExceptionsOn) + { + $this->_throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false; + return $this; + } + + /** + * Will exceptions be thrown? + * + * @return bool + */ + public function isThrowTargetExceptionsOn() + { + return $this->_throwTargetExceptionsOn; + } + + /** + * Set the Target Replacement Identifier, by default ':' + * + * @param string $targetReplacementIdentifier + * @return Zend_Filter_Inflector + */ + public function setTargetReplacementIdentifier($targetReplacementIdentifier) + { + if ($targetReplacementIdentifier) { + $this->_targetReplacementIdentifier = (string) $targetReplacementIdentifier; + } + + return $this; + } + + /** + * Get Target Replacement Identifier + * + * @return string + */ + public function getTargetReplacementIdentifier() + { + return $this->_targetReplacementIdentifier; + } + + /** + * Set a Target + * ex: 'scripts/:controller/:action.:suffix' + * + * @param string + * @return Zend_Filter_Inflector + */ + public function setTarget($target) + { + $this->_target = (string) $target; + return $this; + } + + /** + * Retrieve target + * + * @return string + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Set Target Reference + * + * @param reference $target + * @return Zend_Filter_Inflector + */ + public function setTargetReference(&$target) + { + $this->_target =& $target; + return $this; + } + + /** + * SetRules() is the same as calling addRules() with the exception that it + * clears the rules before adding them. + * + * @param array $rules + * @return Zend_Filter_Inflector + */ + public function setRules(Array $rules) + { + $this->clearRules(); + $this->addRules($rules); + return $this; + } + + /** + * AddRules(): multi-call to setting filter rules. + * + * If prefixed with a ":" (colon), a filter rule will be added. If not + * prefixed, a static replacement will be added. + * + * ex: + * array( + * ':controller' => array('CamelCaseToUnderscore','StringToLower'), + * ':action' => array('CamelCaseToUnderscore','StringToLower'), + * 'suffix' => 'phtml' + * ); + * + * @param array + * @return Zend_Filter_Inflector + */ + public function addRules(Array $rules) + { + $keys = array_keys($rules); + foreach ($keys as $spec) { + if ($spec[0] == ':') { + $this->addFilterRule($spec, $rules[$spec]); + } else { + $this->setStaticRule($spec, $rules[$spec]); + } + } + + return $this; + } + + /** + * Get rules + * + * By default, returns all rules. If a $spec is provided, will return those + * rules if found, false otherwise. + * + * @param string $spec + * @return array|false + */ + public function getRules($spec = null) + { + if (null !== $spec) { + $spec = $this->_normalizeSpec($spec); + if (isset($this->_rules[$spec])) { + return $this->_rules[$spec]; + } + return false; + } + + return $this->_rules; + } + + /** + * getRule() returns a rule set by setFilterRule(), a numeric index must be provided + * + * @param string $spec + * @param int $index + * @return Zend_Filter_Interface|false + */ + public function getRule($spec, $index) + { + $spec = $this->_normalizeSpec($spec); + if (isset($this->_rules[$spec]) && is_array($this->_rules[$spec])) { + if (isset($this->_rules[$spec][$index])) { + return $this->_rules[$spec][$index]; + } + } + return false; + } + + /** + * ClearRules() clears the rules currently in the inflector + * + * @return Zend_Filter_Inflector + */ + public function clearRules() + { + $this->_rules = array(); + return $this; + } + + /** + * Set a filtering rule for a spec. $ruleSet can be a string, Filter object + * or an array of strings or filter objects. + * + * @param string $spec + * @param array|string|Zend_Filter_Interface $ruleSet + * @return Zend_Filter_Inflector + */ + public function setFilterRule($spec, $ruleSet) + { + $spec = $this->_normalizeSpec($spec); + $this->_rules[$spec] = array(); + return $this->addFilterRule($spec, $ruleSet); + } + + /** + * Add a filter rule for a spec + * + * @param mixed $spec + * @param mixed $ruleSet + * @return void + */ + public function addFilterRule($spec, $ruleSet) + { + $spec = $this->_normalizeSpec($spec); + if (!isset($this->_rules[$spec])) { + $this->_rules[$spec] = array(); + } + + if (!is_array($ruleSet)) { + $ruleSet = array($ruleSet); + } + + if (is_string($this->_rules[$spec])) { + $temp = $this->_rules[$spec]; + $this->_rules[$spec] = array(); + $this->_rules[$spec][] = $temp; + } + + foreach ($ruleSet as $rule) { + $this->_rules[$spec][] = $this->_getRule($rule); + } + + return $this; + } + + /** + * Set a static rule for a spec. This is a single string value + * + * @param string $name + * @param string $value + * @return Zend_Filter_Inflector + */ + public function setStaticRule($name, $value) + { + $name = $this->_normalizeSpec($name); + $this->_rules[$name] = (string) $value; + return $this; + } + + /** + * Set Static Rule Reference. + * + * This allows a consuming class to pass a property or variable + * in to be referenced when its time to build the output string from the + * target. + * + * @param string $name + * @param mixed $reference + * @return Zend_Filter_Inflector + */ + public function setStaticRuleReference($name, &$reference) + { + $name = $this->_normalizeSpec($name); + $this->_rules[$name] =& $reference; + return $this; + } + + /** + * Inflect + * + * @param string|array $source + * @return string + */ + public function filter($source) + { + // clean source + foreach ( (array) $source as $sourceName => $sourceValue) { + $source[ltrim($sourceName, ':')] = $sourceValue; + } + + $pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#'); + $processedParts = array(); + + foreach ($this->_rules as $ruleName => $ruleValue) { + if (isset($source[$ruleName])) { + if (is_string($ruleValue)) { + // overriding the set rule + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]); + } elseif (is_array($ruleValue)) { + $processedPart = $source[$ruleName]; + foreach ($ruleValue as $ruleFilter) { + $processedPart = $ruleFilter->filter($processedPart); + } + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart); + } + } elseif (is_string($ruleValue)) { + $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue); + } + } + + // all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences + $inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target); + + if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) { + throw new Zend_Filter_Exception('A replacement identifier ' . $this->_targetReplacementIdentifier . ' was found inside the inflected target, perhaps a rule was not satisfied with a target source? Unsatisfied inflected target: ' . $inflectedTarget); + } + + return $inflectedTarget; + } + + /** + * Normalize spec string + * + * @param string $spec + * @return string + */ + protected function _normalizeSpec($spec) + { + return ltrim((string) $spec, ':&'); + } + + /** + * Resolve named filters and convert them to filter objects. + * + * @param string $rule + * @return Zend_Filter_Interface + */ + protected function _getRule($rule) + { + if ($rule instanceof Zend_Filter_Interface) { + return $rule; + } + + $rule = (string) $rule; + + $className = $this->getPluginLoader()->load($rule); + $ruleObject = new $className(); + if (!$ruleObject instanceof Zend_Filter_Interface) { + throw new Zend_Filter_Exception('No class named ' . $rule . ' implementing Zend_Filter_Interface could be found'); + } + + return $ruleObject; + } +} diff --git a/library/vendor/Zend/Filter/Input.php b/library/vendor/Zend/Filter/Input.php new file mode 100644 index 000000000..f892137d6 --- /dev/null +++ b/library/vendor/Zend/Filter/Input.php @@ -0,0 +1,1196 @@ + false, + self::BREAK_CHAIN => false, + self::ESCAPE_FILTER => 'HtmlEntities', + self::MISSING_MESSAGE => "Field '%field%' is required by rule '%rule%', but the field is missing", + self::NOT_EMPTY_MESSAGE => "You must give a non-empty value for field '%field%'", + self::PRESENCE => self::PRESENCE_OPTIONAL + ); + + /** + * @var boolean Set to False initially, this is set to True after the + * input data have been processed. Reset to False in setData() method. + */ + protected $_processed = false; + + /** + * Translation object + * @var Zend_Translate + */ + protected $_translator; + + /** + * Is translation disabled? + * @var Boolean + */ + protected $_translatorDisabled = false; + + /** + * @param array $filterRules + * @param array $validatorRules + * @param array $data OPTIONAL + * @param array $options OPTIONAL + */ + public function __construct($filterRules, $validatorRules, array $data = null, array $options = null) + { + if ($options) { + $this->setOptions($options); + } + + $this->_filterRules = (array) $filterRules; + $this->_validatorRules = (array) $validatorRules; + + if ($data) { + $this->setData($data); + } + } + + /** + * @param mixed $namespaces + * @return Zend_Filter_Input + * @deprecated since 1.5.0RC1 - use addFilterPrefixPath() or addValidatorPrefixPath instead. + */ + public function addNamespace($namespaces) + { + if (!is_array($namespaces)) { + $namespaces = array($namespaces); + } + + foreach ($namespaces as $namespace) { + $prefix = $namespace; + $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix); + $this->addFilterPrefixPath($prefix, $path); + $this->addValidatorPrefixPath($prefix, $path); + } + + return $this; + } + + /** + * Add prefix path for all elements + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Input + */ + public function addFilterPrefixPath($prefix, $path) + { + $this->getPluginLoader(self::FILTER)->addPrefixPath($prefix, $path); + + return $this; + } + + /** + * Add prefix path for all elements + * + * @param string $prefix + * @param string $path + * @return Zend_Filter_Input + */ + public function addValidatorPrefixPath($prefix, $path) + { + $this->getPluginLoader(self::VALIDATE)->addPrefixPath($prefix, $path); + + return $this; + } + + /** + * Set plugin loaders for use with decorators and elements + * + * @param Zend_Loader_PluginLoader_Interface $loader + * @param string $type 'filter' or 'validate' + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception on invalid type + */ + public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) + { + $type = strtolower($type); + switch ($type) { + case self::FILTER: + case self::VALIDATE: + $this->_loaders[$type] = $loader; + return $this; + default: + throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); + } + + return $this; + } + + /** + * Retrieve plugin loader for given type + * + * $type may be one of: + * - filter + * - validator + * + * If a plugin loader does not exist for the given type, defaults are + * created. + * + * @param string $type 'filter' or 'validate' + * @return Zend_Loader_PluginLoader_Interface + * @throws Zend_Filter_Exception on invalid type + */ + public function getPluginLoader($type) + { + $type = strtolower($type); + if (!isset($this->_loaders[$type])) { + switch ($type) { + case self::FILTER: + $prefixSegment = 'Zend_Filter_'; + $pathSegment = 'Zend/Filter/'; + break; + case self::VALIDATE: + $prefixSegment = 'Zend_Validate_'; + $pathSegment = 'Zend/Validate/'; + break; + default: + throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); + } + + $this->_loaders[$type] = new Zend_Loader_PluginLoader( + array($prefixSegment => $pathSegment) + ); + } + + return $this->_loaders[$type]; + } + + /** + * @return array + */ + public function getMessages() + { + $this->_process(); + return array_merge($this->_invalidMessages, $this->_missingFields); + } + + /** + * @return array + */ + public function getErrors() + { + $this->_process(); + return $this->_invalidErrors; + } + + /** + * @return array + */ + public function getInvalid() + { + $this->_process(); + return $this->_invalidMessages; + } + + /** + * @return array + */ + public function getMissing() + { + $this->_process(); + return $this->_missingFields; + } + + /** + * @return array + */ + public function getUnknown() + { + $this->_process(); + return $this->_unknownFields; + } + + /** + * @param string $fieldName OPTIONAL + * @return mixed + */ + public function getEscaped($fieldName = null) + { + $this->_process(); + $this->_getDefaultEscapeFilter(); + + if ($fieldName === null) { + return $this->_escapeRecursive($this->_validFields); + } + if (array_key_exists($fieldName, $this->_validFields)) { + return $this->_escapeRecursive($this->_validFields[$fieldName]); + } + return null; + } + + /** + * @param mixed $value + * @return mixed + */ + protected function _escapeRecursive($data) + { + if($data === null) { + return $data; + } + + if (!is_array($data)) { + return $this->_getDefaultEscapeFilter()->filter($data); + } + foreach ($data as &$element) { + $element = $this->_escapeRecursive($element); + } + return $data; + } + + /** + * @param string $fieldName OPTIONAL + * @return mixed + */ + public function getUnescaped($fieldName = null) + { + $this->_process(); + if ($fieldName === null) { + return $this->_validFields; + } + if (array_key_exists($fieldName, $this->_validFields)) { + return $this->_validFields[$fieldName]; + } + return null; + } + + /** + * @param string $fieldName + * @return mixed + */ + public function __get($fieldName) + { + return $this->getEscaped($fieldName); + } + + /** + * @return boolean + */ + public function hasInvalid() + { + $this->_process(); + return !(empty($this->_invalidMessages)); + } + + /** + * @return boolean + */ + public function hasMissing() + { + $this->_process(); + return !(empty($this->_missingFields)); + } + + /** + * @return boolean + */ + public function hasUnknown() + { + $this->_process(); + return !(empty($this->_unknownFields)); + } + + /** + * @return boolean + */ + public function hasValid() + { + $this->_process(); + return !(empty($this->_validFields)); + } + + /** + * @param string $fieldName + * @return boolean + */ + public function isValid($fieldName = null) + { + $this->_process(); + if ($fieldName === null) { + return !($this->hasMissing() || $this->hasInvalid()); + } + return array_key_exists($fieldName, $this->_validFields); + } + + /** + * @param string $fieldName + * @return boolean + */ + public function __isset($fieldName) + { + $this->_process(); + return isset($this->_validFields[$fieldName]); + } + + /** + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception + */ + public function process() + { + $this->_process(); + if ($this->hasInvalid()) { + throw new Zend_Filter_Exception("Input has invalid fields"); + } + if ($this->hasMissing()) { + throw new Zend_Filter_Exception("Input has missing fields"); + } + + return $this; + } + + /** + * @param array $data + * @return Zend_Filter_Input + */ + public function setData(array $data) + { + $this->_data = $data; + + /** + * Reset to initial state + */ + $this->_validFields = array(); + $this->_invalidMessages = array(); + $this->_invalidErrors = array(); + $this->_missingFields = array(); + $this->_unknownFields = array(); + + $this->_processed = false; + + return $this; + } + + /** + * @param mixed $escapeFilter + * @return Zend_Filter_Interface + */ + public function setDefaultEscapeFilter($escapeFilter) + { + if (is_string($escapeFilter) || is_array($escapeFilter)) { + $escapeFilter = $this->_getFilter($escapeFilter); + } + if (!$escapeFilter instanceof Zend_Filter_Interface) { + throw new Zend_Filter_Exception('Escape filter specified does not implement Zend_Filter_Interface'); + } + $this->_defaultEscapeFilter = $escapeFilter; + return $escapeFilter; + } + + /** + * @param array $options + * @return Zend_Filter_Input + * @throws Zend_Filter_Exception if an unknown option is given + */ + public function setOptions(array $options) + { + foreach ($options as $option => $value) { + switch ($option) { + case self::ESCAPE_FILTER: + $this->setDefaultEscapeFilter($value); + break; + case self::INPUT_NAMESPACE: + $this->addNamespace($value); + break; + case self::VALIDATOR_NAMESPACE: + if(is_string($value)) { + $value = array($value); + } + + foreach($value AS $prefix) { + $this->addValidatorPrefixPath( + $prefix, + str_replace('_', DIRECTORY_SEPARATOR, $prefix) + ); + } + break; + case self::FILTER_NAMESPACE: + if(is_string($value)) { + $value = array($value); + } + + foreach($value AS $prefix) { + $this->addFilterPrefixPath( + $prefix, + str_replace('_', DIRECTORY_SEPARATOR, $prefix) + ); + } + break; + case self::ALLOW_EMPTY: + case self::BREAK_CHAIN: + case self::MISSING_MESSAGE: + case self::NOT_EMPTY_MESSAGE: + case self::PRESENCE: + $this->_defaults[$option] = $value; + break; + default: + throw new Zend_Filter_Exception("Unknown option '$option'"); + break; + } + } + + return $this; + } + + /** + * Set translation object + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return Zend_Filter_Input + */ + public function setTranslator($translator = null) + { + if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + throw new Zend_Validate_Exception('Invalid translator specified'); + } + + return $this; + } + + /** + * Return translation object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->translatorIsDisabled()) { + return null; + } + + if ($this->_translator === null) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $translator = Zend_Registry::get('Zend_Translate'); + if ($translator instanceof Zend_Translate_Adapter) { + return $translator; + } elseif ($translator instanceof Zend_Translate) { + return $translator->getAdapter(); + } + } + } + + return $this->_translator; + } + + /** + * Indicate whether or not translation should be disabled + * + * @param bool $flag + * @return Zend_Filter_Input + */ + public function setDisableTranslator($flag) + { + $this->_translatorDisabled = (bool) $flag; + return $this; + } + + /** + * Is translation disabled? + * + * @return bool + */ + public function translatorIsDisabled() + { + return $this->_translatorDisabled; + } + + /* + * Protected methods + */ + + /** + * @return void + */ + protected function _filter() + { + foreach ($this->_filterRules as $ruleName => &$filterRule) { + /** + * Make sure we have an array representing this filter chain. + * Don't typecast to (array) because it might be a Zend_Filter object + */ + if (!is_array($filterRule)) { + $filterRule = array($filterRule); + } + + /** + * Filters are indexed by integer, metacommands are indexed by string. + * Pick out the filters. + */ + $filterList = array(); + foreach ($filterRule as $key => $value) { + if (is_int($key)) { + $filterList[] = $value; + } + } + + /** + * Use defaults for filter metacommands. + */ + $filterRule[self::RULE] = $ruleName; + if (!isset($filterRule[self::FIELDS])) { + $filterRule[self::FIELDS] = $ruleName; + } + + /** + * Load all the filter classes and add them to the chain. + */ + if (!isset($filterRule[self::FILTER_CHAIN])) { + $filterRule[self::FILTER_CHAIN] = new Zend_Filter(); + foreach ($filterList as $filter) { + if (is_string($filter) || is_array($filter)) { + $filter = $this->_getFilter($filter); + } + $filterRule[self::FILTER_CHAIN]->addFilter($filter); + } + } + + /** + * If the ruleName is the special wildcard rule, + * then apply the filter chain to all input data. + * Else just process the field named by the rule. + */ + if ($ruleName == self::RULE_WILDCARD) { + foreach (array_keys($this->_data) as $field) { + $this->_filterRule(array_merge($filterRule, array(self::FIELDS => $field))); + } + } else { + $this->_filterRule($filterRule); + } + } + } + + /** + * @param array $filterRule + * @return void + */ + protected function _filterRule(array $filterRule) + { + $field = $filterRule[self::FIELDS]; + if (!array_key_exists($field, $this->_data)) { + return; + } + if (is_array($this->_data[$field])) { + foreach ($this->_data[$field] as $key => $value) { + $this->_data[$field][$key] = $filterRule[self::FILTER_CHAIN]->filter($value); + } + } else { + $this->_data[$field] = + $filterRule[self::FILTER_CHAIN]->filter($this->_data[$field]); + } + } + + /** + * @return Zend_Filter_Interface + */ + protected function _getDefaultEscapeFilter() + { + if ($this->_defaultEscapeFilter !== null) { + return $this->_defaultEscapeFilter; + } + return $this->setDefaultEscapeFilter($this->_defaults[self::ESCAPE_FILTER]); + } + + /** + * @param string $rule + * @param string $field + * @return string + */ + protected function _getMissingMessage($rule, $field) + { + $message = $this->_defaults[self::MISSING_MESSAGE]; + + if (null !== ($translator = $this->getTranslator())) { + if ($translator->isTranslated(self::MISSING_MESSAGE)) { + $message = $translator->translate(self::MISSING_MESSAGE); + } else { + $message = $translator->translate($message); + } + } + + $message = str_replace('%rule%', $rule, $message); + $message = str_replace('%field%', $field, $message); + return $message; + } + + /** + * @return string + */ + protected function _getNotEmptyMessage($rule, $field) + { + $message = $this->_defaults[self::NOT_EMPTY_MESSAGE]; + + if (null !== ($translator = $this->getTranslator())) { + if ($translator->isTranslated(self::NOT_EMPTY_MESSAGE)) { + $message = $translator->translate(self::NOT_EMPTY_MESSAGE); + } else { + $message = $translator->translate($message); + } + } + + $message = str_replace('%rule%', $rule, $message); + $message = str_replace('%field%', $field, $message); + return $message; + } + + /** + * @return void + */ + protected function _process() + { + if ($this->_processed === false) { + $this->_filter(); + $this->_validate(); + $this->_processed = true; + } + } + + /** + * @return void + */ + protected function _validate() + { + /** + * Special case: if there are no validators, treat all fields as valid. + */ + if (!$this->_validatorRules) { + $this->_validFields = $this->_data; + $this->_data = array(); + return; + } + + // remember the default not empty message in case we want to temporarily change it + $preserveDefaultNotEmptyMessage = $this->_defaults[self::NOT_EMPTY_MESSAGE]; + + foreach ($this->_validatorRules as $ruleName => &$validatorRule) { + /** + * Make sure we have an array representing this validator chain. + * Don't typecast to (array) because it might be a Zend_Validate object + */ + if (!is_array($validatorRule)) { + $validatorRule = array($validatorRule); + } + + /** + * Validators are indexed by integer, metacommands are indexed by string. + * Pick out the validators. + */ + $validatorList = array(); + foreach ($validatorRule as $key => $value) { + if (is_int($key)) { + $validatorList[$key] = $value; + } + } + + /** + * Use defaults for validation metacommands. + */ + $validatorRule[self::RULE] = $ruleName; + if (!isset($validatorRule[self::FIELDS])) { + $validatorRule[self::FIELDS] = $ruleName; + } + if (!isset($validatorRule[self::BREAK_CHAIN])) { + $validatorRule[self::BREAK_CHAIN] = $this->_defaults[self::BREAK_CHAIN]; + } + if (!isset($validatorRule[self::PRESENCE])) { + $validatorRule[self::PRESENCE] = $this->_defaults[self::PRESENCE]; + } + if (!isset($validatorRule[self::ALLOW_EMPTY])) { + $foundNotEmptyValidator = false; + + foreach ($validatorRule as $rule) { + if ($rule === 'NotEmpty') { + $foundNotEmptyValidator = true; + // field may not be empty, we are ready + break 1; + } + + if (is_array($rule)) { + $keys = array_keys($rule); + $classKey = array_shift($keys); + if (isset($rule[$classKey])) { + $ruleClass = $rule[$classKey]; + if ($ruleClass === 'NotEmpty') { + $foundNotEmptyValidator = true; + // field may not be empty, we are ready + break 1; + } + } + } + + // we must check if it is an object before using instanceof + if (!is_object($rule)) { + // it cannot be a NotEmpty validator, skip this one + continue; + } + + if($rule instanceof Zend_Validate_NotEmpty) { + $foundNotEmptyValidator = true; + // field may not be empty, we are ready + break 1; + } + } + + if (!$foundNotEmptyValidator) { + $validatorRule[self::ALLOW_EMPTY] = $this->_defaults[self::ALLOW_EMPTY]; + } else { + $validatorRule[self::ALLOW_EMPTY] = false; + } + } + + if (!isset($validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array(); + } else if (!is_array($validatorRule[self::MESSAGES])) { + $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]); + } else if (array_intersect_key($validatorList, $validatorRule[self::MESSAGES])) { + // this seems pointless... it just re-adds what it already has... + // I can disable all this and not a single unit test fails... + // There are now corresponding numeric keys in the validation rule messages array + // Treat it as a named messages list for all rule validators + $unifiedMessages = $validatorRule[self::MESSAGES]; + $validatorRule[self::MESSAGES] = array(); + + foreach ($validatorList as $key => $validator) { + if (array_key_exists($key, $unifiedMessages)) { + $validatorRule[self::MESSAGES][$key] = $unifiedMessages[$key]; + } + } + } + + /** + * Load all the validator classes and add them to the chain. + */ + if (!isset($validatorRule[self::VALIDATOR_CHAIN])) { + $validatorRule[self::VALIDATOR_CHAIN] = new Zend_Validate(); + + foreach ($validatorList as $key => $validator) { + if (is_string($validator) || is_array($validator)) { + $validator = $this->_getValidator($validator); + } + + if (isset($validatorRule[self::MESSAGES][$key])) { + $value = $validatorRule[self::MESSAGES][$key]; + if (is_array($value)) { + $validator->setMessages($value); + } else { + $validator->setMessage($value); + } + + if ($validator instanceof Zend_Validate_NotEmpty) { + /** we are changing the defaults here, this is alright if all subsequent validators are also a not empty + * validator, but it goes wrong if one of them is not AND is required!!! + * that is why we restore the default value at the end of this loop + */ + if (is_array($value)) { + $temp = $value; // keep the original value + $this->_defaults[self::NOT_EMPTY_MESSAGE] = array_pop($temp); + unset($temp); + } else { + $this->_defaults[self::NOT_EMPTY_MESSAGE] = $value; + } + } + } + + $validatorRule[self::VALIDATOR_CHAIN]->addValidator($validator, $validatorRule[self::BREAK_CHAIN]); + } + $validatorRule[self::VALIDATOR_CHAIN_COUNT] = count($validatorList); + } + + /** + * If the ruleName is the special wildcard rule, + * then apply the validator chain to all input data. + * Else just process the field named by the rule. + */ + if ($ruleName == self::RULE_WILDCARD) { + foreach (array_keys($this->_data) as $field) { + $this->_validateRule(array_merge($validatorRule, array(self::FIELDS => $field))); + } + } else { + $this->_validateRule($validatorRule); + } + + // reset the default not empty message + $this->_defaults[self::NOT_EMPTY_MESSAGE] = $preserveDefaultNotEmptyMessage; + } + + + + /** + * Unset fields in $_data that have been added to other arrays. + * We have to wait until all rules have been processed because + * a given field may be referenced by multiple rules. + */ + foreach (array_merge(array_keys($this->_missingFields), array_keys($this->_invalidMessages)) as $rule) { + foreach ((array) $this->_validatorRules[$rule][self::FIELDS] as $field) { + unset($this->_data[$field]); + } + } + foreach ($this->_validFields as $field => $value) { + unset($this->_data[$field]); + } + + /** + * Anything left over in $_data is an unknown field. + */ + $this->_unknownFields = $this->_data; + } + + /** + * @param array $validatorRule + * @return void + */ + protected function _validateRule(array $validatorRule) + { + /** + * Get one or more data values from input, and check for missing fields. + * Apply defaults if fields are missing. + */ + $data = array(); + foreach ((array) $validatorRule[self::FIELDS] as $key => $field) { + if (array_key_exists($field, $this->_data)) { + $data[$field] = $this->_data[$field]; + } else if (isset($validatorRule[self::DEFAULT_VALUE])) { + /** @todo according to this code default value can't be an array. It has to be reviewed */ + if (!is_array($validatorRule[self::DEFAULT_VALUE])) { + // Default value is a scalar + $data[$field] = $validatorRule[self::DEFAULT_VALUE]; + } else { + // Default value is an array. Search for corresponding key + if (isset($validatorRule[self::DEFAULT_VALUE][$key])) { + $data[$field] = $validatorRule[self::DEFAULT_VALUE][$key]; + } else if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) { + // Default value array is provided, but it doesn't have an entry for current field + // and presence is required + $this->_missingFields[$validatorRule[self::RULE]][] = + $this->_getMissingMessage($validatorRule[self::RULE], $field); + } + } + } else if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) { + $this->_missingFields[$validatorRule[self::RULE]][] = + $this->_getMissingMessage($validatorRule[self::RULE], $field); + } + } + + /** + * If any required fields are missing, break the loop. + */ + if (isset($this->_missingFields[$validatorRule[self::RULE]]) && count($this->_missingFields[$validatorRule[self::RULE]]) > 0) { + return; + } + + /** + * Evaluate the inputs against the validator chain. + */ + if (count((array) $validatorRule[self::FIELDS]) > 1) { + if (!$validatorRule[self::ALLOW_EMPTY]) { + $emptyFieldsFound = false; + $errorsList = array(); + $messages = array(); + + foreach ($data as $fieldKey => $field) { + // if there is no Zend_Validate_NotEmpty instance in the rules, we will use the default + if (!($notEmptyValidator = $this->_getNotEmptyValidatorInstance($validatorRule))) { + $notEmptyValidator = $this->_getValidator('NotEmpty'); + $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldKey)); + } + + if (!$notEmptyValidator->isValid($field)) { + foreach ($notEmptyValidator->getMessages() as $messageKey => $message) { + if (!isset($messages[$messageKey])) { + $messages[$messageKey] = $message; + } else { + $messages[] = $message; + } + } + $errorsList[] = $notEmptyValidator->getErrors(); + $emptyFieldsFound = true; + } + } + + if ($emptyFieldsFound) { + $this->_invalidMessages[$validatorRule[self::RULE]] = $messages; + $this->_invalidErrors[$validatorRule[self::RULE]] = array_unique(call_user_func_array('array_merge', $errorsList)); + return; + } + } + + if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($data)) { + $this->_invalidMessages[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getMessages(); + $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getErrors(); + return; + } + } else if (count($data) > 0) { + // $data is actually a one element array + $fieldNames = array_keys($data); + $fieldName = reset($fieldNames); + $field = reset($data); + + $failed = false; + if (!is_array($field)) { + $field = array($field); + } + + // if there is no Zend_Validate_NotEmpty instance in the rules, we will use the default + if (!($notEmptyValidator = $this->_getNotEmptyValidatorInstance($validatorRule))) { + $notEmptyValidator = $this->_getValidator('NotEmpty'); + $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldName)); + } + + if ($validatorRule[self::ALLOW_EMPTY]) { + $validatorChain = $validatorRule[self::VALIDATOR_CHAIN]; + } else { + $validatorChain = new Zend_Validate(); + $validatorChain->addValidator($notEmptyValidator, true /* Always break on failure */); + $validatorChain->addValidator($validatorRule[self::VALIDATOR_CHAIN]); + } + + foreach ($field as $key => $value) { + if ($validatorRule[self::ALLOW_EMPTY] && !$notEmptyValidator->isValid($value)) { + // Field is empty AND it's allowed. Do nothing. + continue; + } + + if (!$validatorChain->isValid($value)) { + if (isset($this->_invalidMessages[$validatorRule[self::RULE]])) { + $collectedMessages = $this->_invalidMessages[$validatorRule[self::RULE]]; + } else { + $collectedMessages = array(); + } + + foreach ($validatorChain->getMessages() as $messageKey => $message) { + if (!isset($collectedMessages[$messageKey])) { + $collectedMessages[$messageKey] = $message; + } else { + $collectedMessages[] = $message; + } + } + + $this->_invalidMessages[$validatorRule[self::RULE]] = $collectedMessages; + if (isset($this->_invalidErrors[$validatorRule[self::RULE]])) { + $this->_invalidErrors[$validatorRule[self::RULE]] = array_merge($this->_invalidErrors[$validatorRule[self::RULE]], + $validatorChain->getErrors()); + } else { + $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorChain->getErrors(); + } + unset($this->_validFields[$fieldName]); + $failed = true; + if ($validatorRule[self::BREAK_CHAIN]) { + return; + } + } + } + if ($failed) { + return; + } + } + + /** + * If we got this far, the inputs for this rule pass validation. + */ + foreach ((array) $validatorRule[self::FIELDS] as $field) { + if (array_key_exists($field, $data)) { + $this->_validFields[$field] = $data[$field]; + } + } + } + + /** + * Check a validatorRule for the presence of a NotEmpty validator instance. + * The purpose is to preserve things like a custom message, that may have been + * set on the validator outside Zend_Filter_Input. + * @param array $validatorRule + * @return mixed false if none is found, Zend_Validate_NotEmpty instance if found + */ + protected function _getNotEmptyValidatorInstance($validatorRule) { + foreach ($validatorRule as $rule => $value) { + if (is_object($value) and $value instanceof Zend_Validate_NotEmpty) { + return $value; + } + } + + return false; + } + + /** + * @param mixed $classBaseName + * @return Zend_Filter_Interface + */ + protected function _getFilter($classBaseName) + { + return $this->_getFilterOrValidator(self::FILTER, $classBaseName); + } + + /** + * @param mixed $classBaseName + * @return Zend_Validate_Interface + */ + protected function _getValidator($classBaseName) + { + return $this->_getFilterOrValidator(self::VALIDATE, $classBaseName); + } + + /** + * @param string $type + * @param mixed $classBaseName + * @return Zend_Filter_Interface|Zend_Validate_Interface + * @throws Zend_Filter_Exception + */ + protected function _getFilterOrValidator($type, $classBaseName) + { + $args = array(); + + if (is_array($classBaseName)) { + $args = $classBaseName; + $classBaseName = array_shift($args); + } + + $interfaceName = 'Zend_' . ucfirst($type) . '_Interface'; + $className = $this->getPluginLoader($type)->load(ucfirst($classBaseName)); + + $class = new ReflectionClass($className); + + if (!$class->implementsInterface($interfaceName)) { + throw new Zend_Filter_Exception("Class '$className' based on basename '$classBaseName' must implement the '$interfaceName' interface"); + } + + if ($class->hasMethod('__construct')) { + $object = $class->newInstanceArgs($args); + } else { + $object = $class->newInstance(); + } + + return $object; + } + +} diff --git a/library/vendor/Zend/Filter/Int.php b/library/vendor/Zend/Filter/Int.php new file mode 100644 index 000000000..d2de695de --- /dev/null +++ b/library/vendor/Zend/Filter/Int.php @@ -0,0 +1,49 @@ + null, + 'date_format' => null, + 'precision' => null + ); + + /** + * Class constructor + * + * @param string|Zend_Locale $locale (Optional) Locale to set + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Returns the set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets options to use + * + * @param array $options (Optional) Options to use + * @return Zend_Filter_LocalizedToNormalized + */ + public function setOptions(array $options = null) + { + $this->_options = $options + $this->_options; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Normalizes the given input + * + * @param string $value Value to normalized + * @return string|array The normalized value + */ + public function filter($value) + { + if (Zend_Locale_Format::isNumber($value, $this->_options)) { + return Zend_Locale_Format::getNumber($value, $this->_options); + } else if (($this->_options['date_format'] === null) && (strpos($value, ':') !== false)) { + // Special case, no date format specified, detect time input + return Zend_Locale_Format::getTime($value, $this->_options); + } else if (Zend_Locale_Format::checkDateFormat($value, $this->_options)) { + // Detect date or time input + return Zend_Locale_Format::getDate($value, $this->_options); + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/NormalizedToLocalized.php b/library/vendor/Zend/Filter/NormalizedToLocalized.php new file mode 100644 index 000000000..461e9ab05 --- /dev/null +++ b/library/vendor/Zend/Filter/NormalizedToLocalized.php @@ -0,0 +1,108 @@ + null, + 'date_format' => null, + 'precision' => null + ); + + /** + * Class constructor + * + * @param string|Zend_Locale $locale (Optional) Locale to set + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (null !== $options) { + $this->setOptions($options); + } + } + + /** + * Returns the set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets options to use + * + * @param array $options (Optional) Options to use + * @return Zend_Filter_LocalizedToNormalized + */ + public function setOptions(array $options = null) + { + $this->_options = $options + $this->_options; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Normalizes the given input + * + * @param string $value Value to normalized + * @return string|array The normalized value + */ + public function filter($value) + { + if (is_array($value)) { + $date = new Zend_Date($value, $this->_options['locale']); + return $date->toString($this->_options['date_format']); + } else if ($this->_options['precision'] === 0) { + return Zend_Locale_Format::toInteger($value, $this->_options); + } else if ($this->_options['precision'] === null) { + return Zend_Locale_Format::toFloat($value, $this->_options); + } + + return Zend_Locale_Format::toNumber($value, $this->_options); + } +} diff --git a/library/vendor/Zend/Filter/Null.php b/library/vendor/Zend/Filter/Null.php new file mode 100644 index 000000000..6e97af08e --- /dev/null +++ b/library/vendor/Zend/Filter/Null.php @@ -0,0 +1,181 @@ + 'boolean', + self::INTEGER => 'integer', + self::EMPTY_ARRAY => 'array', + self::STRING => 'string', + self::ZERO => 'zero', + self::ALL => 'all' + ); + + /** + * Internal type to detect + * + * @var integer + */ + protected $_type = self::ALL; + + /** + * Constructor + * + * @param string|array|Zend_Config $options OPTIONAL + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp = array_shift($options); + } + $options = $temp; + } else if (is_array($options) && array_key_exists('type', $options)) { + $options = $options['type']; + } + + if (!empty($options)) { + $this->setType($options); + } + } + + /** + * Returns the set null types + * + * @return array + */ + public function getType() + { + return $this->_type; + } + + /** + * Set the null types + * + * @param integer|array $type + * @throws Zend_Filter_Exception + * @return Zend_Filter_Null + */ + public function setType($type = null) + { + if (is_array($type)) { + $detected = 0; + foreach($type as $value) { + if (is_int($value)) { + $detected += $value; + } else if (in_array($value, $this->_constants)) { + $detected += array_search($value, $this->_constants); + } + } + + $type = $detected; + } else if (is_string($type)) { + if (in_array($type, $this->_constants)) { + $type = array_search($type, $this->_constants); + } + } + + if (!is_int($type) || ($type < 0) || ($type > self::ALL)) { + throw new Zend_Filter_Exception('Unknown type'); + } + + $this->_type = $type; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns null representation of $value, if value is empty and matches + * types that should be considered null. + * + * @param string $value + * @return string + */ + public function filter($value) + { + $type = $this->getType(); + + // STRING ZERO ('0') + if ($type >= self::ZERO) { + $type -= self::ZERO; + if (is_string($value) && ($value == '0')) { + return null; + } + } + + // STRING ('') + if ($type >= self::STRING) { + $type -= self::STRING; + if (is_string($value) && ($value == '')) { + return null; + } + } + + // EMPTY_ARRAY (array()) + if ($type >= self::EMPTY_ARRAY) { + $type -= self::EMPTY_ARRAY; + if (is_array($value) && ($value == array())) { + return null; + } + } + + // INTEGER (0) + if ($type >= self::INTEGER) { + $type -= self::INTEGER; + if (is_int($value) && ($value == 0)) { + return null; + } + } + + // BOOLEAN (false) + if ($type >= self::BOOLEAN) { + $type -= self::BOOLEAN; + if (is_bool($value) && ($value == false)) { + return null; + } + } + + return $value; + } +} diff --git a/library/vendor/Zend/Filter/PregReplace.php b/library/vendor/Zend/Filter/PregReplace.php new file mode 100644 index 000000000..356052ae0 --- /dev/null +++ b/library/vendor/Zend/Filter/PregReplace.php @@ -0,0 +1,172 @@ + matching pattern + * 'replace' => replace with this + * + * @param string|array $options + * @return void + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['match'] = array_shift($options); + } + + if (!empty($options)) { + $temp['replace'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('match', $options)) { + $this->setMatchPattern($options['match']); + } + + if (array_key_exists('replace', $options)) { + $this->setReplacement($options['replace']); + } + } + + /** + * Set the match pattern for the regex being called within filter() + * + * @param mixed $match - same as the first argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setMatchPattern($match) + { + $this->_matchPattern = $match; + return $this; + } + + /** + * Get currently set match pattern + * + * @return string + */ + public function getMatchPattern() + { + return $this->_matchPattern; + } + + /** + * Set the Replacement pattern/string for the preg_replace called in filter + * + * @param mixed $replacement - same as the second argument of preg_replace + * @return Zend_Filter_PregReplace + */ + public function setReplacement($replacement) + { + $this->_replacement = $replacement; + return $this; + } + + /** + * Get currently set replacement value + * + * @return string + */ + public function getReplacement() + { + return $this->_replacement; + } + + /** + * Perform regexp replacement as filter + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_matchPattern == null) { + throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.'); + } + + return preg_replace($this->_matchPattern, $this->_replacement, $value); + } + +} diff --git a/library/vendor/Zend/Filter/RealPath.php b/library/vendor/Zend/Filter/RealPath.php new file mode 100644 index 000000000..7da9e55bb --- /dev/null +++ b/library/vendor/Zend/Filter/RealPath.php @@ -0,0 +1,133 @@ +setExists($options); + } + + /** + * Returns true if the filtered path must exist + * + * @return boolean + */ + public function getExists() + { + return $this->_exists; + } + + /** + * Sets if the path has to exist + * TRUE when the path must exist + * FALSE when not existing paths can be given + * + * @param boolean|Zend_Config $exists Path must exist + * @return Zend_Filter_RealPath + */ + public function setExists($exists) + { + if ($exists instanceof Zend_Config) { + $exists = $exists->toArray(); + } + + if (is_array($exists)) { + if (isset($exists['exists'])) { + $exists = (boolean) $exists['exists']; + } + } + + $this->_exists = (boolean) $exists; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns realpath($value) + * + * @param string $value + * @return string + */ + public function filter($value) + { + $path = (string) $value; + if ($this->_exists) { + return realpath($path); + } + + $realpath = @realpath($path); + if ($realpath) { + return $realpath; + } + + $drive = ''; + if (substr(PHP_OS, 0, 3) == 'WIN') { + $path = preg_replace('/[\\\\\/]/', DIRECTORY_SEPARATOR, $path); + if (preg_match('/([a-zA-Z]\:)(.*)/', $path, $matches)) { + list($fullMatch, $drive, $path) = $matches; + } else { + $cwd = getcwd(); + $drive = substr($cwd, 0, 2); + if (substr($path, 0, 1) != DIRECTORY_SEPARATOR) { + $path = substr($cwd, 3) . DIRECTORY_SEPARATOR . $path; + } + } + } elseif (substr($path, 0, 1) != DIRECTORY_SEPARATOR) { + $path = getcwd() . DIRECTORY_SEPARATOR . $path; + } + + $stack = array(); + $parts = explode(DIRECTORY_SEPARATOR, $path); + foreach ($parts as $dir) { + if (strlen($dir) && $dir !== '.') { + if ($dir == '..') { + array_pop($stack); + } else { + array_push($stack, $dir); + } + } + } + + return $drive . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $stack); + } +} diff --git a/library/vendor/Zend/Filter/StringToLower.php b/library/vendor/Zend/Filter/StringToLower.php new file mode 100644 index 000000000..e2970e4b5 --- /dev/null +++ b/library/vendor/Zend/Filter/StringToLower.php @@ -0,0 +1,118 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['encoding'] = array_shift($options); + } + $options = $temp; + } + + if (!array_key_exists('encoding', $options) && function_exists('mb_internal_encoding')) { + $options['encoding'] = mb_internal_encoding(); + } + + if (array_key_exists('encoding', $options)) { + $this->setEncoding($options['encoding']); + } + } + + /** + * Returns the set encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set the input encoding for the given string + * + * @param string $encoding + * @return Zend_Filter_StringToLower Provides a fluent interface + * @throws Zend_Filter_Exception + */ + public function setEncoding($encoding = null) + { + if ($encoding !== null) { + if (!function_exists('mb_strtolower')) { + throw new Zend_Filter_Exception('mbstring is required for this feature'); + } + + $encoding = (string) $encoding; + if (!in_array(strtolower($encoding), array_map('strtolower', mb_list_encodings()))) { + throw new Zend_Filter_Exception("The given encoding '$encoding' is not supported by mbstring"); + } + } + + $this->_encoding = $encoding; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to lowercase as necessary + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_encoding !== null) { + return mb_strtolower((string) $value, $this->_encoding); + } + + return strtolower((string) $value); + } +} diff --git a/library/vendor/Zend/Filter/StringToUpper.php b/library/vendor/Zend/Filter/StringToUpper.php new file mode 100644 index 000000000..689d2c0af --- /dev/null +++ b/library/vendor/Zend/Filter/StringToUpper.php @@ -0,0 +1,118 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['encoding'] = array_shift($options); + } + $options = $temp; + } + + if (!array_key_exists('encoding', $options) && function_exists('mb_internal_encoding')) { + $options['encoding'] = mb_internal_encoding(); + } + + if (array_key_exists('encoding', $options)) { + $this->setEncoding($options['encoding']); + } + } + + /** + * Returns the set encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set the input encoding for the given string + * + * @param string $encoding + * @return Zend_Filter_StringToUpper Provides a fluent interface + * @throws Zend_Filter_Exception + */ + public function setEncoding($encoding = null) + { + if ($encoding !== null) { + if (!function_exists('mb_strtoupper')) { + throw new Zend_Filter_Exception('mbstring is required for this feature'); + } + + $encoding = (string) $encoding; + if (!in_array(strtolower($encoding), array_map('strtolower', mb_list_encodings()))) { + throw new Zend_Filter_Exception("The given encoding '$encoding' is not supported by mbstring"); + } + } + + $this->_encoding = $encoding; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value, converting characters to uppercase as necessary + * + * @param string $value + * @return string + */ + public function filter($value) + { + if ($this->_encoding) { + return mb_strtoupper((string) $value, $this->_encoding); + } + + return strtoupper((string) $value); + } +} diff --git a/library/vendor/Zend/Filter/StringTrim.php b/library/vendor/Zend/Filter/StringTrim.php new file mode 100644 index 000000000..cb9c4380e --- /dev/null +++ b/library/vendor/Zend/Filter/StringTrim.php @@ -0,0 +1,123 @@ +toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['charlist'] = array_shift($options); + $options = $temp; + } + + if (array_key_exists('charlist', $options)) { + $this->setCharList($options['charlist']); + } + } + + /** + * Returns the charList option + * + * @return string|null + */ + public function getCharList() + { + return $this->_charList; + } + + /** + * Sets the charList option + * + * @param string|null $charList + * @return Zend_Filter_StringTrim Provides a fluent interface + */ + public function setCharList($charList) + { + $this->_charList = $charList; + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * Returns the string $value with characters stripped from the beginning and end + * + * @param string $value + * @return string + */ + public function filter($value) + { + if (null === $this->_charList) { + return $this->_unicodeTrim((string) $value); + } else { + return $this->_unicodeTrim((string) $value, $this->_charList); + } + } + + /** + * Unicode aware trim method + * Fixes a PHP problem + * + * @param string $value + * @param string $charlist + * @return string + */ + protected function _unicodeTrim($value, $charlist = '\\\\s') + { + $chars = preg_replace( + array( '/[\^\-\]\\\]/S', '/\\\{4}/S', '/\//'), + array( '\\\\\\0', '\\', '\/' ), + $charlist + ); + + $pattern = '^[' . $chars . ']*|[' . $chars . ']*$'; + return preg_replace("/$pattern/sSD", '', $value); + } +} diff --git a/library/vendor/Zend/Filter/StripNewlines.php b/library/vendor/Zend/Filter/StripNewlines.php new file mode 100644 index 000000000..33f0a01f1 --- /dev/null +++ b/library/vendor/Zend/Filter/StripNewlines.php @@ -0,0 +1,47 @@ + Tags which are allowed + * 'allowAttribs' => Attributes which are allowed + * 'allowComments' => Are comments allowed ? + * + * @param string|array|Zend_Config $options + * @return void + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if ((!is_array($options)) || (is_array($options) && !array_key_exists('allowTags', $options) && + !array_key_exists('allowAttribs', $options) && !array_key_exists('allowComments', $options))) { + $options = func_get_args(); + $temp['allowTags'] = array_shift($options); + if (!empty($options)) { + $temp['allowAttribs'] = array_shift($options); + } + + if (!empty($options)) { + $temp['allowComments'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('allowTags', $options)) { + $this->setTagsAllowed($options['allowTags']); + } + + if (array_key_exists('allowAttribs', $options)) { + $this->setAttributesAllowed($options['allowAttribs']); + } + + if (array_key_exists('allowComments', $options)) { + $this->setCommentsAllowed($options['allowComments']); + } + } + + /** + * Returns the commentsAllowed option + * + * This setting is now deprecated and ignored internally. + * + * @deprecated + * @return bool + */ + public function getCommentsAllowed() + { + return $this->commentsAllowed; + } + + /** + * Sets the commentsAllowed option + * + * This setting is now deprecated and ignored internally. + * + * @deprecated + * @param boolean $commentsAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setCommentsAllowed($commentsAllowed) + { + $this->commentsAllowed = (boolean) $commentsAllowed; + return $this; + } + + /** + * Returns the tagsAllowed option + * + * @return array + */ + public function getTagsAllowed() + { + return $this->_tagsAllowed; + } + + /** + * Sets the tagsAllowed option + * + * @param array|string $tagsAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setTagsAllowed($tagsAllowed) + { + if (!is_array($tagsAllowed)) { + $tagsAllowed = array($tagsAllowed); + } + + foreach ($tagsAllowed as $index => $element) { + // If the tag was provided without attributes + if (is_int($index) && is_string($element)) { + // Canonicalize the tag name + $tagName = strtolower($element); + // Store the tag as allowed with no attributes + $this->_tagsAllowed[$tagName] = array(); + } + // Otherwise, if a tag was provided with attributes + else if (is_string($index) && (is_array($element) || is_string($element))) { + // Canonicalize the tag name + $tagName = strtolower($index); + // Canonicalize the attributes + if (is_string($element)) { + $element = array($element); + } + // Store the tag as allowed with the provided attributes + $this->_tagsAllowed[$tagName] = array(); + foreach ($element as $attribute) { + if (is_string($attribute)) { + // Canonicalize the attribute name + $attributeName = strtolower($attribute); + $this->_tagsAllowed[$tagName][$attributeName] = null; + } + } + } + } + + return $this; + } + + /** + * Returns the attributesAllowed option + * + * @return array + */ + public function getAttributesAllowed() + { + return $this->_attributesAllowed; + } + + /** + * Sets the attributesAllowed option + * + * @param array|string $attributesAllowed + * @return Zend_Filter_StripTags Provides a fluent interface + */ + public function setAttributesAllowed($attributesAllowed) + { + if (!is_array($attributesAllowed)) { + $attributesAllowed = array($attributesAllowed); + } + + // Store each attribute as allowed + foreach ($attributesAllowed as $attribute) { + if (is_string($attribute)) { + // Canonicalize the attribute name + $attributeName = strtolower($attribute); + $this->_attributesAllowed[$attributeName] = null; + } + } + + return $this; + } + + /** + * Defined by Zend_Filter_Interface + * + * @todo improve docblock descriptions + * + * @param string $value + * @return string + */ + public function filter($value) + { + $value = (string) $value; + + // Strip HTML comments first + while (strpos($value, ' + + + + +EOS; + } + +} diff --git a/library/vendor/Zend/Tool/Project/Context/Zf/TestsDirectory.php b/library/vendor/Zend/Tool/Project/Context/Zf/TestsDirectory.php new file mode 100644 index 000000000..4a25f72d0 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Context/Zf/TestsDirectory.php @@ -0,0 +1,56 @@ +_forControllerName = $this->_resource->getAttribute('forControllerName'); + $this->_filesystemName = $this->_convertControllerNameToFilesystemName($this->_forControllerName); + parent::init(); + return $this; + } + + /** + * getPersistentAttributes() + * + * @return array + */ + public function getPersistentAttributes() + { + return array( + 'forControllerName' => $this->_forControllerName + ); + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + return 'ViewControllerScriptsDirectory'; + } + + protected function _convertControllerNameToFilesystemName($controllerName) + { + $filter = new Zend_Filter(); + $filter->addFilter(new Zend_Filter_Word_CamelCaseToDash()) + ->addFilter(new Zend_Filter_StringToLower()); + return $filter->filter($controllerName); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Context/Zf/ViewFiltersDirectory.php b/library/vendor/Zend/Tool/Project/Context/Zf/ViewFiltersDirectory.php new file mode 100644 index 000000000..75393e7cb --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Context/Zf/ViewFiltersDirectory.php @@ -0,0 +1,56 @@ +_resource->getAttribute('forActionName')) { + $this->_forActionName = $forActionName; + $this->_filesystemName = $this->_convertActionNameToFilesystemName($forActionName) . '.phtml'; + } elseif ($scriptName = $this->_resource->getAttribute('scriptName')) { + $this->_scriptName = $scriptName; + $this->_filesystemName = $scriptName . '.phtml'; + } else { + throw new Exception('Either a forActionName or scriptName is required.'); + } + + parent::init(); + return $this; + } + + /** + * getPersistentAttributes() + * + * @return unknown + */ + public function getPersistentAttributes() + { + $attributes = array(); + + if ($this->_forActionName) { + $attributes['forActionName'] = $this->_forActionName; + } + + if ($this->_scriptName) { + $attributes['scriptName'] = $this->_scriptName; + } + + return $attributes; + } + + /** + * getContents() + * + * @return string + */ + public function getContents() + { + $contents = ''; + + $controllerName = $this->_resource->getParentResource()->getAttribute('forControllerName'); + + $viewsDirectoryResource = $this->_resource + ->getParentResource() // view script + ->getParentResource() // view controller dir + ->getParentResource(); // views dir + if ($viewsDirectoryResource->getParentResource()->getName() == 'ModuleDirectory') { + $moduleName = $viewsDirectoryResource->getParentResource()->getModuleName(); + } else { + $moduleName = 'default'; + } + + if ($this->_filesystemName == 'error.phtml') { // should also check that the above directory is forController=error + $contents .= << + + + + Zend Framework Default Application + + +

              An error occurred

              +

              message ?>

              + + exception)): ?> + +

              Exception information:

              +

              + Message: exception->getMessage() ?> +

              + +

              Stack trace:

              +
              exception->getTraceAsString() ?>
              +  
              + +

              Request Parameters:

              +
              escape(var_export(\$this->request->getParams(), true)) ?>
              +  
              + + + + + + +EOS; + } elseif ($this->_forActionName == 'index' && $controllerName == 'Index' && $moduleName == 'default') { + + $contents =<< + a:link, + a:visited + { + color: #0398CA; + } + + span#zf-name + { + color: #91BE3F; + } + + div#welcome + { + color: #FFFFFF; + background-image: url(http://framework.zend.com/images/bkg_header.jpg); + width: 600px; + height: 400px; + border: 2px solid #444444; + overflow: hidden; + text-align: center; + } + + div#more-information + { + background-image: url(http://framework.zend.com/images/bkg_body-bottom.gif); + height: 100%; + } + +
              +

              Welcome to the Zend Framework!

              + +

              This is your project's main page

              + +
              +

              +

              + Helpful Links:
              + Zend Framework Website | + Zend Framework Manual +

              +
              +
              +EOS; + + } else { + $controllerName = $this->_resource->getParentResource()->getAttribute('forControllerName'); + $actionName = $this->_forActionName; + $contents = <<
              +
              +

              View script for controller $controllerName and script/action name $actionName

              +
              +EOS; + } + return $contents; + } + + protected function _convertActionNameToFilesystemName($actionName) + { + $filter = new Zend_Filter(); + $filter->addFilter(new Zend_Filter_Word_CamelCaseToDash()) + ->addFilter(new Zend_Filter_StringToLower()); + return $filter->filter($actionName); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Context/Zf/ViewScriptsDirectory.php b/library/vendor/Zend/Tool/Project/Context/Zf/ViewScriptsDirectory.php new file mode 100644 index 000000000..4ff80f3cf --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Context/Zf/ViewScriptsDirectory.php @@ -0,0 +1,56 @@ +_getZfPath(); + if ($zfPath != false) { + $zfIterator = new RecursiveDirectoryIterator($zfPath); + foreach ($rii = new RecursiveIteratorIterator($zfIterator, RecursiveIteratorIterator::SELF_FIRST) as $file) { + $relativePath = preg_replace('#^'.preg_quote(realpath($zfPath), '#').'#', '', realpath($file->getPath())) . DIRECTORY_SEPARATOR . $file->getFilename(); + if (strpos($relativePath, DIRECTORY_SEPARATOR . '.') !== false) { + continue; + } + + if ($file->isDir()) { + mkdir($this->getBaseDirectory() . DIRECTORY_SEPARATOR . $this->getFilesystemName() . $relativePath); + } else { + copy($file->getPathname(), $this->getBaseDirectory() . DIRECTORY_SEPARATOR . $this->getFilesystemName() . $relativePath); + } + + } + } + } + + /** + * _getZfPath() + * + * @return string|false + */ + protected function _getZfPath() + { + foreach (Zend_Loader::explodeIncludePath() as $includePath) { + if (!file_exists($includePath) || $includePath[0] == '.') { + continue; + } + + if (realpath($checkedPath = rtrim($includePath, '\\/') . '/Zend/Loader.php') !== false && file_exists($checkedPath)) { + return dirname($checkedPath); + } + } + + return false; + } + +} diff --git a/library/vendor/Zend/Tool/Project/Exception.php b/library/vendor/Zend/Tool/Project/Exception.php new file mode 100644 index 000000000..279b3bd5d --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Exception.php @@ -0,0 +1,36 @@ +setOptions($options); + } + + $this->_topResources = new Zend_Tool_Project_Profile_Resource_Container(); + } + + /** + * Process options and either set a profile property or + * set a profile 'attribute' + * + * @param array $options + */ + public function setOptions(Array $options) + { + $this->setAttributes($options); + } + + /** + * getIterator() - reqruied by the RecursiveIterator interface + * + * @return RecursiveIteratorIterator + */ + public function getIterator() + { + + return new RecursiveIteratorIterator( + new Zend_Tool_Project_Profile_Iterator_EnabledResourceFilter($this), + RecursiveIteratorIterator::SELF_FIRST + ); + } + + /** + * loadFromData() - Load a profile from data provided by the + * 'profilData' attribute + * + */ + public function loadFromData() + { + if (!isset($this->_attributes['profileData'])) { + throw new Zend_Tool_Project_Exception('loadFromData() must have "profileData" set.'); + } + + $profileFileParser = new Zend_Tool_Project_Profile_FileParser_Xml(); + $profileFileParser->unserialize($this->_attributes['profileData'], $this); + + $this->rewind(); + } + + /** + * isLoadableFromFile() - can a profile be loaded from a file + * + * wether or not a profile can be loaded from the + * file in attribute 'projectProfileFile', or from a file named + * '.zfproject.xml' inside a directory in key 'projectDirectory' + * + * @return bool + */ + public function isLoadableFromFile() + { + if (!isset($this->_attributes['projectProfileFile']) && !isset($this->_attributes['projectDirectory'])) { + return false; + } + + if (isset($this->_attributes['projectProfileFile'])) { + $projectProfileFilePath = $this->_attributes['projectProfileFile']; + if (!file_exists($projectProfileFilePath)) { + return false; + } + } else { + $projectProfileFilePath = rtrim($this->_attributes['projectDirectory'], '/\\') . '/.zfproject.xml'; + if (!file_exists($projectProfileFilePath)) { + return false; + } + } + + return true; + } + + /** + * loadFromFile() - Load data from file + * + * this attempts to load a project profile file from a variety of locations depending + * on what information the user provided vie $options or attributes, specifically the + * 'projectDirectory' or 'projectProfileFile' + * + */ + public function loadFromFile() + { + // if no data is supplied, need either a projectProfileFile or a projectDirectory + if (!isset($this->_attributes['projectProfileFile']) && !isset($this->_attributes['projectDirectory'])) { + throw new Zend_Tool_Project_Exception('loadFromFile() must have at least "projectProfileFile" or "projectDirectory" set.'); + } + + if (isset($this->_attributes['projectProfileFile'])) { + $projectProfileFilePath = $this->_attributes['projectProfileFile']; + if (!file_exists($projectProfileFilePath)) { + throw new Zend_Tool_Project_Exception('"projectProfileFile" was supplied but file was not found at location ' . $projectProfileFilePath); + } + $this->_attributes['projectDirectory'] = dirname($projectProfileFilePath); + } else { + $projectProfileFilePath = rtrim($this->_attributes['projectDirectory'], '/\\') . '/.zfproject.xml'; + if (!file_exists($projectProfileFilePath)) { + throw new Zend_Tool_Project_Exception('"projectDirectory" was supplied but no profile file file was not found at location ' . $projectProfileFilePath); + } + $this->_attributes['projectProfileFile'] = $projectProfileFilePath; + } + + $profileData = file_get_contents($projectProfileFilePath); + + $profileFileParser = new Zend_Tool_Project_Profile_FileParser_Xml(); + $profileFileParser->unserialize($profileData, $this); + + $this->rewind(); + } + + /** + * storeToFile() - store the current profile to file + * + * This will store the profile in memory to a place on disk determined by the attributes + * available, specifically if the key 'projectProfileFile' is available + * + */ + public function storeToFile() + { + $file = null; + + if (isset($this->_attributes['projectProfileFile'])) { + $file = $this->_attributes['projectProfileFile']; + } + + if ($file == null) { + throw new Zend_Tool_Project_Exception('storeToFile() must have a "projectProfileFile" attribute set.'); + } + + $parser = new Zend_Tool_Project_Profile_FileParser_Xml(); + $xml = $parser->serialize($this); + file_put_contents($file, $xml); + } + + /** + * storeToData() - create a string representation of the profile in memory + * + * @return string + */ + public function storeToData() + { + $parser = new Zend_Tool_Project_Profile_FileParser_Xml(); + $xml = $parser->serialize($this); + return $xml; + } + + /** + * __toString() - cast this profile to string to be able to view it. + * + * @return string + */ + public function __toString() + { + $string = ''; + foreach ($this as $resource) { + $string .= $resource->getName() . PHP_EOL; + $rii = new RecursiveIteratorIterator($resource, RecursiveIteratorIterator::SELF_FIRST); + foreach ($rii as $item) { + $string .= str_repeat(' ', $rii->getDepth()+1) . $item->getName() + . ((count($attributes = $item->getAttributes()) > 0) ? ' [' . http_build_query($attributes) . ']' : '') + . PHP_EOL; + } + } + return $string; + } +} diff --git a/library/vendor/Zend/Tool/Project/Profile/Exception.php b/library/vendor/Zend/Tool/Project/Profile/Exception.php new file mode 100644 index 000000000..088a3c897 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Profile/Exception.php @@ -0,0 +1,36 @@ +_contextRepository = Zend_Tool_Project_Context_Repository::getInstance(); + } + + /** + * serialize() + * + * create an xml string from the provided profile + * + * @param Zend_Tool_Project_Profile $profile + * @return string + */ + public function serialize(Zend_Tool_Project_Profile $profile) + { + + $profile = clone $profile; + + $this->_profile = $profile; + $xmlElement = new SimpleXMLElement(''); + + if ($profile->hasAttribute('type')) { + $xmlElement->addAttribute('type', $profile->getAttribute('type')); + } + + if ($profile->hasAttribute('version')) { + $xmlElement->addAttribute('version', $profile->getAttribute('version')); + } + + self::_serializeRecurser($profile, $xmlElement); + + $doc = new DOMDocument('1.0'); + $doc->formatOutput = true; + $domnode = dom_import_simplexml($xmlElement); + $domnode = $doc->importNode($domnode, true); + $domnode = $doc->appendChild($domnode); + + return $doc->saveXML(); + } + + /** + * unserialize() + * + * Create a structure in the object $profile from the structure specficied + * in the xml string provided + * + * @param string xml data + * @param Zend_Tool_Project_Profile The profile to use as the top node + * @return Zend_Tool_Project_Profile + */ + public function unserialize($data, Zend_Tool_Project_Profile $profile) + { + if ($data == null) { + throw new Exception('contents not available to unserialize.'); + } + + $this->_profile = $profile; + + $xmlDataIterator = new SimpleXMLIterator($data); + + if ($xmlDataIterator->getName() != 'projectProfile') { + throw new Exception('Profiles must start with a projectProfile node'); + } + + if (isset($xmlDataIterator['type'])) { + $this->_profile->setAttribute('type', (string) $xmlDataIterator['type']); + } + + if (isset($xmlDataIterator['version'])) { + $this->_profile->setAttribute('version', (string) $xmlDataIterator['version']); + } + + // start un-serialization of the xml doc + $this->_unserializeRecurser($xmlDataIterator); + + // contexts should be initialized after the unwinding of the profile structure + $this->_lazyLoadContexts(); + + return $this->_profile; + + } + + /** + * _serializeRecurser() + * + * This method will be used to traverse the depths of the structure + * when *serializing* an xml structure into a string + * + * @param array $resources + * @param SimpleXmlElement $xmlNode + */ + protected function _serializeRecurser($resources, SimpleXmlElement $xmlNode) + { + // @todo find a better way to handle concurrency.. if no clone, _position in node gets messed up + //if ($resources instanceof Zend_Tool_Project_Profile_Resource) { + // $resources = clone $resources; + //} + + foreach ($resources as $resource) { + + if ($resource->isDeleted()) { + continue; + } + + $resourceName = $resource->getContext()->getName(); + $resourceName[0] = strtolower($resourceName[0]); + + $newNode = $xmlNode->addChild($resourceName); + + //$reflectionClass = new ReflectionClass($resource->getContext()); + + if ($resource->isEnabled() == false) { + $newNode->addAttribute('enabled', 'false'); + } + + foreach ($resource->getPersistentAttributes() as $paramName => $paramValue) { + $newNode->addAttribute($paramName, $paramValue); + } + + if ($resource->hasChildren()) { + self::_serializeRecurser($resource, $newNode); + } + + } + + } + + + /** + * _unserializeRecurser() + * + * This method will be used to traverse the depths of the structure + * as needed to *unserialize* the profile from an xmlIterator + * + * @param SimpleXMLIterator $xmlIterator + * @param Zend_Tool_Project_Profile_Resource $resource + */ + protected function _unserializeRecurser(SimpleXMLIterator $xmlIterator, Zend_Tool_Project_Profile_Resource $resource = null) + { + + foreach ($xmlIterator as $resourceName => $resourceData) { + + $contextName = $resourceName; + $subResource = new Zend_Tool_Project_Profile_Resource($contextName); + $subResource->setProfile($this->_profile); + + if ($resourceAttributes = $resourceData->attributes()) { + $attributes = array(); + foreach ($resourceAttributes as $attrName => $attrValue) { + $attributes[$attrName] = (string) $attrValue; + } + $subResource->setAttributes($attributes); + } + + if ($resource) { + $resource->append($subResource, false); + } else { + $this->_profile->append($subResource); + } + + if ($this->_contextRepository->isOverwritableContext($contextName) == false) { + $subResource->initializeContext(); + } + + if ($xmlIterator->hasChildren()) { + self::_unserializeRecurser($xmlIterator->getChildren(), $subResource); + } + } + } + + /** + * _lazyLoadContexts() + * + * This method will call initializeContext on the resources in a profile + * @todo determine if this method belongs inside the profile + * + */ + protected function _lazyLoadContexts() + { + + foreach ($this->_profile as $topResource) { + $rii = new RecursiveIteratorIterator($topResource, RecursiveIteratorIterator::SELF_FIRST); + foreach ($rii as $resource) { + $resource->initializeContext(); + } + } + + } + +} diff --git a/library/vendor/Zend/Tool/Project/Profile/Iterator/ContextFilter.php b/library/vendor/Zend/Tool/Project/Profile/Iterator/ContextFilter.php new file mode 100644 index 000000000..e6729cf05 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Profile/Iterator/ContextFilter.php @@ -0,0 +1,211 @@ +_rawOptions = $options; + if ($options) { + $this->setOptions($options); + } + } + + /** + * setOptions() + * + * @param array $options + */ + public function setOptions(Array $options) + { + foreach ($options as $optionName => $optionValue) { + if (substr($optionName, -1, 1) != 's') { + $optionName .= 's'; + } + if (method_exists($this, 'set' . $optionName)) { + $this->{'set' . $optionName}($optionValue); + } + } + } + + /** + * setAcceptTypes() + * + * @param array|string $acceptTypes + * @return Zend_Tool_Project_Profile_Iterator_ContextFilter + */ + public function setAcceptTypes($acceptTypes) + { + if (!is_array($acceptTypes)) { + $acceptTypes = array($acceptTypes); + } + + $this->_acceptTypes = $acceptTypes; + return $this; + } + + /** + * setDenyTypes() + * + * @param array|string $denyTypes + * @return Zend_Tool_Project_Profile_Iterator_ContextFilter + */ + public function setDenyTypes($denyTypes) + { + if (!is_array($denyTypes)) { + $denyTypes = array($denyTypes); + } + + $this->_denyTypes = $denyTypes; + return $this; + } + + /** + * setAcceptNames() + * + * @param array|string $acceptNames + * @return Zend_Tool_Project_Profile_Iterator_ContextFilter + */ + public function setAcceptNames($acceptNames) + { + if (!is_array($acceptNames)) { + $acceptNames = array($acceptNames); + } + + foreach ($acceptNames as $n => $v) { + $acceptNames[$n] = strtolower($v); + } + + $this->_acceptNames = $acceptNames; + return $this; + } + + /** + * setDenyNames() + * + * @param array|string $denyNames + * @return Zend_Tool_Project_Profile_Iterator_ContextFilter + */ + public function setDenyNames($denyNames) + { + if (!is_array($denyNames)) { + $denyNames = array($denyNames); + } + + foreach ($denyNames as $n => $v) { + $denyNames[$n] = strtolower($v); + } + + $this->_denyNames = $denyNames; + return $this; + } + + /** + * accept() is required by teh RecursiveFilterIterator + * + * @return bool + */ + public function accept() + { + $currentItem = $this->current(); + + if (in_array(strtolower($currentItem->getName()), $this->_acceptNames)) { + return true; + } elseif (in_array(strtolower($currentItem->getName()), $this->_denyNames)) { + return false; + } + + foreach ($this->_acceptTypes as $acceptType) { + if ($currentItem->getContent() instanceof $acceptType) { + return true; + } + } + + foreach ($this->_denyTypes as $denyType) { + if ($currentItem->getContext() instanceof $denyType) { + return false; + } + } + + return true; + } + + /** + * getChildren() + * + * This is here due to a bug/design issue in PHP + * @link + * + * @return unknown + */ + function getChildren() + { + + if (empty($this->ref)) { + $this->ref = new ReflectionClass($this); + } + + return $this->ref->newInstance($this->getInnerIterator()->getChildren(), $this->_rawOptions); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Profile/Iterator/EnabledResourceFilter.php b/library/vendor/Zend/Tool/Project/Profile/Iterator/EnabledResourceFilter.php new file mode 100644 index 000000000..1f165160a --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Profile/Iterator/EnabledResourceFilter.php @@ -0,0 +1,43 @@ +current()->isEnabled(); + } +} diff --git a/library/vendor/Zend/Tool/Project/Profile/Resource.php b/library/vendor/Zend/Tool/Project/Profile/Resource.php new file mode 100644 index 000000000..338d84368 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Profile/Resource.php @@ -0,0 +1,260 @@ +setContext($context); + } + + /** + * setContext() + * + * @param string|Zend_Tool_Project_Context_Interface $context + * @return Zend_Tool_Project_Profile_Resource + */ + public function setContext($context) + { + $this->_context = $context; + return $this; + } + + /** + * getContext() + * + * @return Zend_Tool_Project_Context_Interface + */ + public function getContext() + { + return $this->_context; + } + + /** + * getName() - Get the resource name + * + * Name is derived from the context name + * + * @return string + */ + public function getName() + { + if (is_string($this->_context)) { + return $this->_context; + } elseif ($this->_context instanceof Zend_Tool_Project_Context_Interface) { + return $this->_context->getName(); + } else { + throw new Zend_Tool_Project_Exception('Invalid context in resource'); + } + } + + /** + * setProfile() + * + * @param Zend_Tool_Project_Profile $profile + * @return Zend_Tool_Project_Profile_Resource + */ + public function setProfile(Zend_Tool_Project_Profile $profile) + { + $this->_profile = $profile; + return $this; + } + + /** + * getProfile + * + * @return Zend_Tool_Project_Profile + */ + public function getProfile() + { + return $this->_profile; + } + + /** + * getPersistentAttributes() + * + * @return array + */ + public function getPersistentAttributes() + { + if (method_exists($this->_context, 'getPersistentAttributes')) { + return $this->_context->getPersistentAttributes(); + } + + return array(); + } + + /** + * setEnabled() + * + * @param bool $enabled + * @return Zend_Tool_Project_Profile_Resource + */ + public function setEnabled($enabled = true) + { + // convert fuzzy types to bool + $this->_enabled = (!in_array($enabled, array('false', 'disabled', 0, -1, false), true)) ? true : false; + return $this; + } + + /** + * isEnabled() + * + * @return bool + */ + public function isEnabled() + { + return $this->_enabled; + } + + /** + * setDeleted() + * + * @param bool $deleted + * @return Zend_Tool_Project_Profile_Resource + */ + public function setDeleted($deleted = true) + { + $this->_deleted = (bool) $deleted; + return $this; + } + + /** + * isDeleted() + * + * @return Zend_Tool_Project_Profile_Resource + */ + public function isDeleted() + { + return $this->_deleted; + } + + /** + * initializeContext() + * + * @return Zend_Tool_Project_Profile_Resource + */ + public function initializeContext() + { + if ($this->_isContextInitialized) { + return; + } + if (is_string($this->_context)) { + $this->_context = Zend_Tool_Project_Context_Repository::getInstance()->getContext($this->_context); + } + + if (method_exists($this->_context, 'setResource')) { + $this->_context->setResource($this); + } + + if (method_exists($this->_context, 'init')) { + $this->_context->init(); + } + + $this->_isContextInitialized = true; + return $this; + } + + /** + * __toString() + * + * @return string + */ + public function __toString() + { + return $this->_context->getName(); + } + + /** + * __call() + * + * @param string $method + * @param array $arguments + * @return Zend_Tool_Project_Profile_Resource + */ + public function __call($method, $arguments) + { + if (method_exists($this->_context, $method)) { + if (!$this->isEnabled()) { + $this->setEnabled(true); + } + return call_user_func_array(array($this->_context, $method), $arguments); + } else { + throw new Zend_Tool_Project_Profile_Exception('cannot call ' . $method); + } + } + +} diff --git a/library/vendor/Zend/Tool/Project/Profile/Resource/Container.php b/library/vendor/Zend/Tool/Project/Profile/Resource/Container.php new file mode 100644 index 000000000..2774950e4 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Profile/Resource/Container.php @@ -0,0 +1,416 @@ + + * + * + * + * @param Zend_Tool_Project_Profile_Resource_SearchConstraints|string|array $searchParameters + * @return Zend_Tool_Project_Profile_Resource + */ + public function search($matchSearchConstraints, $nonMatchSearchConstraints = null) + { + if (!$matchSearchConstraints instanceof Zend_Tool_Project_Profile_Resource_SearchConstraints) { + $matchSearchConstraints = new Zend_Tool_Project_Profile_Resource_SearchConstraints($matchSearchConstraints); + } + + $this->rewind(); + + /** + * @todo This should be re-written with better support for a filter iterator, its the way to go + */ + + if ($nonMatchSearchConstraints) { + $filterIterator = new Zend_Tool_Project_Profile_Iterator_ContextFilter($this, array('denyNames' => $nonMatchSearchConstraints)); + $riIterator = new RecursiveIteratorIterator($filterIterator, RecursiveIteratorIterator::SELF_FIRST); + } else { + $riIterator = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::SELF_FIRST); + } + + $foundResource = false; + $currentConstraint = $matchSearchConstraints->getConstraint(); + $foundDepth = 0; + + foreach ($riIterator as $currentResource) { + + // if current depth is less than found depth, end + if ($riIterator->getDepth() < $foundDepth) { + break; + } + + if (strtolower($currentResource->getName()) == strtolower($currentConstraint->name)) { + + $paramsMatch = true; + + // @todo check to ensure params match (perhaps) + if (count($currentConstraint->params) > 0) { + $currentResourceAttributes = $currentResource->getAttributes(); + if (!is_array($currentConstraint->params)) { + throw new Zend_Tool_Project_Profile_Exception('Search parameter specifics must be in the form of an array for key "' + . $currentConstraint->name .'"'); + } + foreach ($currentConstraint->params as $paramName => $paramValue) { + if (!isset($currentResourceAttributes[$paramName]) || $currentResourceAttributes[$paramName] != $paramValue) { + $paramsMatch = false; + break; + } + } + } + + if ($paramsMatch) { + $foundDepth = $riIterator->getDepth(); + + if (($currentConstraint = $matchSearchConstraints->getConstraint()) == null) { + $foundResource = $currentResource; + break; + } + } + + } + + } + + return $foundResource; + } + + /** + * createResourceAt() + * + * @param array|Zend_Tool_Project_Profile_Resource_SearchConstraints $appendResourceOrSearchConstraints + * @param string $context + * @param array $attributes + * @return Zend_Tool_Project_Profile_Resource + */ + public function createResourceAt($appendResourceOrSearchConstraints, $context, Array $attributes = array()) + { + if (!$appendResourceOrSearchConstraints instanceof Zend_Tool_Project_Profile_Resource_Container) { + if (($parentResource = $this->search($appendResourceOrSearchConstraints)) == false) { + throw new Zend_Tool_Project_Profile_Exception('No node was found to append to.'); + } + } else { + $parentResource = $appendResourceOrSearchConstraints; + } + + return $parentResource->createResource($context, $attributes); + } + + /** + * createResource() + * + * Method to create a resource with a given context with specific attributes + * + * @param string $context + * @param array $attributes + * @return Zend_Tool_Project_Profile_Resource + */ + public function createResource($context, Array $attributes = array()) + { + if (is_string($context)) { + $contextRegistry = Zend_Tool_Project_Context_Repository::getInstance(); + if ($contextRegistry->hasContext($context)) { + $context = $contextRegistry->getContext($context); + } else { + throw new Zend_Tool_Project_Profile_Exception('Context by name ' . $context . ' was not found in the context registry.'); + } + } elseif (!$context instanceof Zend_Tool_Project_Context_Interface) { + throw new Zend_Tool_Project_Profile_Exception('Context must be of type string or Zend_Tool_Project_Context_Interface.'); + } + + $newResource = new Zend_Tool_Project_Profile_Resource($context); + + if ($attributes) { + $newResource->setAttributes($attributes); + } + + /** + * Interesting logic here: + * + * First set the parentResource (this will also be done inside append). This will allow + * the initialization routine to change the appendability of the parent resource. This + * is important to allow specific resources to be appendable by very specific sub-resources. + */ + $newResource->setParentResource($this); + $newResource->initializeContext(); + $this->append($newResource); + + return $newResource; + } + + /** + * setAttributes() + * + * persist the attributes if the resource will accept them + * + * @param array $attributes + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function setAttributes(Array $attributes) + { + foreach ($attributes as $attrName => $attrValue) { + $setMethod = 'set' . $attrName; + if (method_exists($this, $setMethod)) { + $this->{$setMethod}($attrValue); + } else { + $this->setAttribute($attrName, $attrValue); + } + } + return $this; + } + + /** + * getAttributes() + * + * @return array + */ + public function getAttributes() + { + return $this->_attributes; + } + + /** + * setAttribute() + * + * @param string $name + * @param mixed $value + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function setAttribute($name, $value) + { + $this->_attributes[$name] = $value; + return $this; + } + + /** + * getAttribute() + * + * @param string $name + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function getAttribute($name) + { + return (array_key_exists($name, $this->_attributes)) ? $this->_attributes[$name] : null; + } + + /** + * hasAttribute() + * + * @param string $name + * @return bool + */ + public function hasAttribute($name) + { + return array_key_exists($name, $this->_attributes); + } + + /** + * setAppendable() + * + * @param bool $appendable + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function setAppendable($appendable) + { + $this->_appendable = (bool) $appendable; + return $this; + } + + /** + * isAppendable() + * + * @return bool + */ + public function isAppendable() + { + return $this->_appendable; + } + + /** + * setParentResource() + * + * @param Zend_Tool_Project_Profile_Resource_Container $parentResource + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function setParentResource(Zend_Tool_Project_Profile_Resource_Container $parentResource) + { + $this->_parentResource = $parentResource; + return $this; + } + + /** + * getParentResource() + * + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function getParentResource() + { + return $this->_parentResource; + } + + /** + * append() + * + * @param Zend_Tool_Project_Profile_Resource_Container $resource + * @return Zend_Tool_Project_Profile_Resource_Container + */ + public function append(Zend_Tool_Project_Profile_Resource_Container $resource) + { + if (!$this->isAppendable()) { + throw new Exception('Resource by name ' . (string) $this . ' is not appendable'); + } + array_push($this->_subResources, $resource); + $resource->setParentResource($this); + + return $this; + } + + /** + * current() - required by RecursiveIterator + * + * @return Zend_Tool_Project_Profile_Resource + */ + public function current() + { + return current($this->_subResources); + } + + /** + * key() - required by RecursiveIterator + * + * @return int + */ + public function key() + { + return key($this->_subResources); + } + + /** + * next() - required by RecursiveIterator + * + * @return bool + */ + public function next() + { + return next($this->_subResources); + } + + /** + * rewind() - required by RecursiveIterator + * + * @return bool + */ + public function rewind() + { + return reset($this->_subResources); + } + + /** + * valid() - - required by RecursiveIterator + * + * @return bool + */ + public function valid() + { + return (bool) $this->current(); + } + + /** + * hasChildren() + * + * @return bool + */ + public function hasChildren() + { + return (count($this->_subResources > 0)) ? true : false; + } + + /** + * getChildren() + * + * @return array + */ + public function getChildren() + { + return $this->current(); + } + + /** + * count() + * + * @return int + */ + public function count() + { + return count($this->_subResources); + } + + /** + * __clone() + * + */ + public function __clone() + { + $this->rewind(); + foreach ($this->_subResources as $index => $resource) { + $this->_subResources[$index] = clone $resource; + } + } + +} diff --git a/library/vendor/Zend/Tool/Project/Profile/Resource/SearchConstraints.php b/library/vendor/Zend/Tool/Project/Profile/Resource/SearchConstraints.php new file mode 100644 index 000000000..1b03cef13 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Profile/Resource/SearchConstraints.php @@ -0,0 +1,117 @@ +addConstraint($options); + } elseif (is_array($options)) { + $this->setOptions($options); + } + } + + /** + * setOptions() + * + * @param array $option + * @return Zend_Tool_Project_Profile_Resource_SearchConstraints + */ + public function setOptions(Array $option) + { + foreach ($option as $optionName => $optionValue) { + if (is_int($optionName)) { + $this->addConstraint($optionValue); + } elseif (is_string($optionName)) { + $this->addConstraint(array('name' => $optionName, 'params' => $optionValue)); + } + } + + return $this; + } + + /** + * addConstraint() + * + * @param string|array $constraint + * @return Zend_Tool_Project_Profile_Resource_SearchConstraints + */ + public function addConstraint($constraint) + { + if (is_string($constraint)) { + $name = $constraint; + $params = array(); + } elseif (is_array($constraint)) { + $name = $constraint['name']; + $params = $constraint['params']; + } + + $constraint = $this->_makeConstraint($name, $params); + + array_push($this->_constraints, $constraint); + return $this; + } + + /** + * getConstraint() + * + * @return ArrayObject + */ + public function getConstraint() + { + return array_shift($this->_constraints); + } + + /** + * _makeConstraint + * + * @param string $name + * @param mixed $params + * @return ArrayObject + */ + protected function _makeConstraint($name, $params) + { + $value = array('name' => $name, 'params' => $params); + return new ArrayObject($value, ArrayObject::ARRAY_AS_PROPS); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Abstract.php b/library/vendor/Zend/Tool/Project/Provider/Abstract.php new file mode 100644 index 000000000..55a770a21 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Abstract.php @@ -0,0 +1,271 @@ +addContextsFromDirectory( + dirname(dirname(__FILE__)) . '/Context/Zf/', 'Zend_Tool_Project_Context_Zf_' + ); + $contextRegistry->addContextsFromDirectory( + dirname(dirname(__FILE__)) . '/Context/Filesystem/', 'Zend_Tool_Project_Context_Filesystem_' + ); + + // determine if there are project specfic providers ONCE + $profilePath = $this->_findProfileDirectory(); + if ($this->_hasProjectProviderDirectory($profilePath . DIRECTORY_SEPARATOR . '.zfproject.xml')) { + $profile = $this->_loadProfile(); + // project providers directory resource + $ppd = $profile->search('ProjectProvidersDirectory'); + $ppd->loadProviders($this->_registry); + } + + self::$_isInitialized = true; + } + + // load up the extending providers required context classes + if ($contextClasses = $this->getContextClasses()) { + $this->_loadContextClassesIntoRegistry($contextClasses); + } + + } + + public function getContextClasses() + { + return array(); + } + + /** + * _getProject is designed to find if there is project file in the context of where + * the client has been called from.. The search order is as follows.. + * - traversing downwards from (PWD) - current working directory + * - if an enpoint variable has been registered in teh client registry - key=workingDirectory + * - if an ENV variable with the key ZFPROJECT_PATH is found + * + * @param bool $loadProfileFlag Whether or not to throw an exception when no profile is found + * @param string $projectDirectory The project directory to use to search + * @param bool $searchParentDirectories Whether or not to search upper level direcotries + * @return Zend_Tool_Project_Profile + */ + protected function _loadProfile($loadProfileFlag = self::NO_PROFILE_THROW_EXCEPTION, $projectDirectory = null, $searchParentDirectories = true) + { + $foundPath = $this->_findProfileDirectory($projectDirectory, $searchParentDirectories); + + if ($foundPath == false) { + if ($loadProfileFlag == self::NO_PROFILE_THROW_EXCEPTION) { + throw new Zend_Tool_Project_Provider_Exception('A project profile was not found.'); + } else { + return false; + } + } + + $profile = new Zend_Tool_Project_Profile(); + $profile->setAttribute('projectDirectory', $foundPath); + $profile->loadFromFile(); + $this->_loadedProfile = $profile; + return $profile; + } + + protected function _findProfileDirectory($projectDirectory = null, $searchParentDirectories = true) + { + // use the cwd if no directory was provided + if ($projectDirectory == null) { + $projectDirectory = getcwd(); + } elseif (realpath($projectDirectory) == false) { + throw new Zend_Tool_Project_Provider_Exception('The $projectDirectory supplied does not exist.'); + } + + $profile = new Zend_Tool_Project_Profile(); + + $parentDirectoriesArray = explode(DIRECTORY_SEPARATOR, ltrim($projectDirectory, DIRECTORY_SEPARATOR)); + while ($parentDirectoriesArray) { + $projectDirectoryAssembled = implode(DIRECTORY_SEPARATOR, $parentDirectoriesArray); + + if (DIRECTORY_SEPARATOR !== "\\") { + $projectDirectoryAssembled = DIRECTORY_SEPARATOR . $projectDirectoryAssembled; + } + + $profile->setAttribute('projectDirectory', $projectDirectoryAssembled); + if ($profile->isLoadableFromFile()) { + unset($profile); + return $projectDirectoryAssembled; + } + + // break after first run if we are not to check upper directories + if ($searchParentDirectories == false) { + break; + } + + array_pop($parentDirectoriesArray); + } + + return false; + } + + /** + * Load the project profile from the current working directory, if not throw exception + * + * @return Zend_Tool_Project_Profile + */ + protected function _loadProfileRequired() + { + $profile = $this->_loadProfile(); + if ($profile === false) { + throw new Zend_Tool_Project_Provider_Exception('A project profile was not found in the current working directory.'); + } + return $profile; + } + + /** + * Return the currently loaded profile + * + * @return Zend_Tool_Project_Profile + */ + protected function _getProfile($loadProfileFlag = self::NO_PROFILE_THROW_EXCEPTION) + { + if (!$this->_loadedProfile) { + if (($this->_loadProfile($loadProfileFlag) === false) && ($loadProfileFlag === self::NO_PROFILE_RETURN_FALSE)) { + return false; + } + } + + return $this->_loadedProfile; + } + + /** + * _storeProfile() + * + * This method will store the profile into its proper location + * + */ + protected function _storeProfile() + { + $projectProfileFile = $this->_loadedProfile->search('ProjectProfileFile'); + + $name = $projectProfileFile->getContext()->getPath(); + + $this->_registry->getResponse()->appendContent('Updating project profile \'' . $name . '\''); + + $projectProfileFile->getContext()->save(); + } + + protected function _getContentForContext(Zend_Tool_Project_Context_Interface $context, $methodName, $parameters) + { + $storage = $this->_registry->getStorage(); + if (!$storage->isEnabled()) { + return false; + } + + if (!class_exists('Zend_Tool_Project_Context_Content_Engine')) { + } + + $engine = new Zend_Tool_Project_Context_Content_Engine($storage); + return $engine->getContent($context, $methodName, $parameters); + } + + protected function _hasProjectProviderDirectory($pathToProfileFile) + { + // do some static analysis of the file so that we can determin whether or not to incure + // the cost of loading the profile before the system is fully bootstrapped + if (!file_exists($pathToProfileFile)) { + return false; + } + + $contents = file_get_contents($pathToProfileFile); + if (strstr($contents, 'addContextClass($contextClass); + } + } +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Action.php b/library/vendor/Zend/Tool/Project/Provider/Action.php new file mode 100644 index 000000000..379e3116c --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Action.php @@ -0,0 +1,239 @@ +createResource('ActionMethod', array('actionName' => $actionName)); + + return $actionMethod; + } + + /** + * hasResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $actionName + * @param string $controllerName + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + public static function hasResource(Zend_Tool_Project_Profile $profile, $actionName, $controllerName, $moduleName = null) + { + if (!is_string($actionName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_Action::createResource() expects \"actionName\" is the name of a action resource to create.'); + } + + if (!is_string($controllerName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_Action::createResource() expects \"controllerName\" is the name of a controller resource to create.'); + } + + $controllerFile = self::_getControllerFileResource($profile, $controllerName, $moduleName); + + if ($controllerFile == null) { + throw new Zend_Tool_Project_Provider_Exception('Controller ' . $controllerName . ' was not found.'); + } + + return (($controllerFile->search(array('actionMethod' => array('actionName' => $actionName)))) instanceof Zend_Tool_Project_Profile_Resource); + } + + /** + * _getControllerFileResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $controllerName + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + protected static function _getControllerFileResource(Zend_Tool_Project_Profile $profile, $controllerName, $moduleName = null) + { + $profileSearchParams = array(); + + if ($moduleName != null && is_string($moduleName)) { + $profileSearchParams = array('modulesDirectory', 'moduleDirectory' => array('moduleName' => $moduleName)); + } + + $profileSearchParams[] = 'controllersDirectory'; + $profileSearchParams['controllerFile'] = array('controllerName' => $controllerName); + + return $profile->search($profileSearchParams); + } + + /** + * create() + * + * @param string $name Action name for controller, in camelCase format. + * @param string $controllerName Controller name action should be applied to. + * @param bool $viewIncluded Whether the view should the view be included. + * @param string $module Module name action should be applied to. + */ + public function create($name, $controllerName = 'Index', $viewIncluded = true, $module = null) + { + + $this->_loadProfile(); + + // get request/response object + $request = $this->_registry->getRequest(); + $response = $this->_registry->getResponse(); + + // determine if testing is enabled in the project + $testingEnabled = Zend_Tool_Project_Provider_Test::isTestingEnabled($this->_loadedProfile); + + if ($testingEnabled && !Zend_Tool_Project_Provider_Test::isPHPUnitAvailable()) { + $testingEnabled = false; + $response->appendContent( + 'Note: PHPUnit is required in order to generate controller test stubs.', + array('color' => array('yellow')) + ); + } + + // Check that there is not a dash or underscore, return if doesnt match regex + if (preg_match('#[_-]#', $name)) { + throw new Zend_Tool_Project_Provider_Exception('Action names should be camel cased.'); + } + + $originalName = $name; + $originalControllerName = $controllerName; + + // ensure it is camelCase (lower first letter) + $name = strtolower(substr($name, 0, 1)) . substr($name, 1); + + // ensure controller is MixedCase + $controllerName = ucfirst($controllerName); + + if (self::hasResource($this->_loadedProfile, $name, $controllerName, $module)) { + throw new Zend_Tool_Project_Provider_Exception('This controller (' . $controllerName . ') already has an action named (' . $name . ')'); + } + + $actionMethodResource = self::createResource($this->_loadedProfile, $name, $controllerName, $module); + + $testActionMethodResource = null; + if ($testingEnabled) { + $testActionMethodResource = Zend_Tool_Project_Provider_Test::createApplicationResource($this->_loadedProfile, $controllerName, $name, $module); + } + + // alert the user about inline converted names + $tense = (($request->isPretend()) ? 'would be' : 'is'); + + if ($name !== $originalName) { + $response->appendContent( + 'Note: The canonical action name that ' . $tense + . ' used with other providers is "' . $name . '";' + . ' not "' . $originalName . '" as supplied', + array('color' => array('yellow')) + ); + } + + if ($controllerName !== $originalControllerName) { + $response->appendContent( + 'Note: The canonical controller name that ' . $tense + . ' used with other providers is "' . $controllerName . '";' + . ' not "' . $originalControllerName . '" as supplied', + array('color' => array('yellow')) + ); + } + + unset($tense); + + if ($request->isPretend()) { + $response->appendContent( + 'Would create an action named ' . $name . + ' inside controller at ' . $actionMethodResource->getParentResource()->getContext()->getPath() + ); + + if ($testActionMethodResource) { + $response->appendContent('Would create an action test in ' . $testActionMethodResource->getParentResource()->getContext()->getPath()); + } + + } else { + $response->appendContent( + 'Creating an action named ' . $name . + ' inside controller at ' . $actionMethodResource->getParentResource()->getContext()->getPath() + ); + $actionMethodResource->create(); + + if ($testActionMethodResource) { + $response->appendContent('Creating an action test in ' . $testActionMethodResource->getParentResource()->getContext()->getPath()); + $testActionMethodResource->create(); + } + + $this->_storeProfile(); + } + + if ($viewIncluded) { + $viewResource = Zend_Tool_Project_Provider_View::createResource($this->_loadedProfile, $name, $controllerName, $module); + + if ($this->_registry->getRequest()->isPretend()) { + $response->appendContent( + 'Would create a view script for the ' . $name . ' action method at ' . $viewResource->getContext()->getPath() + ); + } else { + $response->appendContent( + 'Creating a view script for the ' . $name . ' action method at ' . $viewResource->getContext()->getPath() + ); + $viewResource->create(); + $this->_storeProfile(); + } + + } + + } + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Application.php b/library/vendor/Zend/Tool/Project/Provider/Application.php new file mode 100644 index 000000000..394aeee83 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Application.php @@ -0,0 +1,87 @@ +_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + $originalClassNamePrefix = $classNamePrefix; + + if (substr($classNamePrefix, -1) != '_') { + $classNamePrefix .= '_'; + } + + $configFileResource = $profile->search('ApplicationConfigFile'); + $zc = $configFileResource->getAsZendConfig('production'); + if ($zc->appnamespace == $classNamePrefix) { + throw new Zend_Tool_Project_Exception('The requested name ' . $classNamePrefix . ' is already the prefix.'); + } + + // remove the old + $configFileResource->removeStringItem('appnamespace', 'production'); + $configFileResource->create(); + + // add the new + $configFileResource->addStringItem('appnamespace', $classNamePrefix, 'production', true); + $configFileResource->create(); + + // update the project profile + $applicationDirectory = $profile->search('ApplicationDirectory'); + $applicationDirectory->setClassNamePrefix($classNamePrefix); + + $response = $this->_registry->getResponse(); + + if ($originalClassNamePrefix !== $classNamePrefix) { + $response->appendContent( + 'Note: the name provided "' . $originalClassNamePrefix . '" was' + . ' altered to "' . $classNamePrefix . '" for correctness.', + array('color' => 'yellow') + ); + } + + // note to the user + $response->appendContent('Note: All existing models will need to be altered to this new namespace by hand', array('color' => 'yellow')); + $response->appendContent('application.ini updated with new appnamespace ' . $classNamePrefix); + + // store profile + $this->_storeProfile(); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Controller.php b/library/vendor/Zend/Tool/Project/Provider/Controller.php new file mode 100644 index 000000000..3781693d0 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Controller.php @@ -0,0 +1,208 @@ +createResource( + 'controllerFile', + array('controllerName' => $controllerName, 'moduleName' => $moduleName) + ); + + return $newController; + } + + /** + * hasResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $controllerName + * @param string $moduleName + * @return boolean + */ + public static function hasResource(Zend_Tool_Project_Profile $profile, $controllerName, $moduleName = null) + { + if (!is_string($controllerName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_Controller::createResource() expects \"controllerName\" is the name of a controller resource to create.'); + } + + $controllersDirectory = self::_getControllersDirectoryResource($profile, $moduleName); + return ($controllersDirectory &&($controllersDirectory->search(array('controllerFile' => array('controllerName' => $controllerName)))) instanceof Zend_Tool_Project_Profile_Resource); + } + + /** + * _getControllersDirectoryResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + protected static function _getControllersDirectoryResource(Zend_Tool_Project_Profile $profile, $moduleName = null) + { + $profileSearchParams = array(); + + if ($moduleName != null && is_string($moduleName)) { + $profileSearchParams = array('modulesDirectory', 'moduleDirectory' => array('moduleName' => $moduleName)); + } + + $profileSearchParams[] = 'controllersDirectory'; + + return $profile->search($profileSearchParams); + } + + /** + * Create a new controller + * + * @param string $name The name of the controller to create, in camelCase. + * @param bool $indexActionIncluded Whether or not to create the index action. + */ + public function create($name, $indexActionIncluded = true, $module = null) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + // get request & response + $request = $this->_registry->getRequest(); + $response = $this->_registry->getResponse(); + + // determine if testing is enabled in the project + $testingEnabled = Zend_Tool_Project_Provider_Test::isTestingEnabled($this->_loadedProfile); + + if ($testingEnabled && !Zend_Tool_Project_Provider_Test::isPHPUnitAvailable()) { + $testingEnabled = false; + $response->appendContent( + 'Note: PHPUnit is required in order to generate controller test stubs.', + array('color' => array('yellow')) + ); + } + + $originalName = $name; + $name = ucfirst($name); + + if (self::hasResource($this->_loadedProfile, $name, $module)) { + throw new Zend_Tool_Project_Provider_Exception('This project already has a controller named ' . $name); + } + + // Check that there is not a dash or underscore, return if doesnt match regex + if (preg_match('#[_-]#', $name)) { + throw new Zend_Tool_Project_Provider_Exception('Controller names should be camel cased.'); + } + + try { + $controllerResource = self::createResource($this->_loadedProfile, $name, $module); + if ($indexActionIncluded) { + $indexActionResource = Zend_Tool_Project_Provider_Action::createResource($this->_loadedProfile, 'index', $name, $module); + $indexActionViewResource = Zend_Tool_Project_Provider_View::createResource($this->_loadedProfile, 'index', $name, $module); + } + if ($testingEnabled) { + $testActionResource = Zend_Tool_Project_Provider_Test::createApplicationResource($this->_loadedProfile, $name, 'index', $module); + } + + } catch (Exception $e) { + $response->setException($e); + return; + } + + // determime if we need to note to the user about the name + if (($name !== $originalName)) { + $tense = (($request->isPretend()) ? 'would be' : 'is'); + $response->appendContent( + 'Note: The canonical controller name that ' . $tense + . ' used with other providers is "' . $name . '";' + . ' not "' . $originalName . '" as supplied', + array('color' => array('yellow')) + ); + unset($tense); + } + + // do the creation + if ($request->isPretend()) { + + $response->appendContent('Would create a controller at ' . $controllerResource->getContext()->getPath()); + + if (isset($indexActionResource)) { + $response->appendContent('Would create an index action method in controller ' . $name); + $response->appendContent('Would create a view script for the index action method at ' . $indexActionViewResource->getContext()->getPath()); + } + + if ($testingEnabled) { + $response->appendContent('Would create a controller test file at ' . $testActionResource->getParentResource()->getContext()->getPath()); + } + + } else { + + $response->appendContent('Creating a controller at ' . $controllerResource->getContext()->getPath()); + $controllerResource->create(); + + if (isset($indexActionResource)) { + $response->appendContent('Creating an index action method in controller ' . $name); + $indexActionResource->create(); + $response->appendContent('Creating a view script for the index action method at ' . $indexActionViewResource->getContext()->getPath()); + $indexActionViewResource->create(); + } + + if ($testingEnabled) { + $response->appendContent('Creating a controller test file at ' . $testActionResource->getParentResource()->getContext()->getPath()); + $testActionResource->getParentResource()->create(); + $testActionResource->create(); + } + + $this->_storeProfile(); + } + + } + + + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/DbAdapter.php b/library/vendor/Zend/Tool/Project/Provider/DbAdapter.php new file mode 100644 index 000000000..fac32ebdb --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/DbAdapter.php @@ -0,0 +1,137 @@ +_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + $appConfigFileResource = $profile->search('applicationConfigFile'); + + if ($appConfigFileResource == false) { + throw new Zend_Tool_Project_Exception('A project with an application config file is required to use this provider.'); + } + + $this->_appConfigFilePath = $appConfigFileResource->getPath(); + + $this->_config = new Zend_Config_Ini($this->_appConfigFilePath, null, array('skipExtends' => true, 'allowModifications' => true)); + + if ($sectionName != 'production') { + $this->_sectionName = $sectionName; + } + + if (!isset($this->_config->{$this->_sectionName})) { + throw new Zend_Tool_Project_Exception('The config does not have a ' . $this->_sectionName . ' section.'); + } + + if (isset($this->_config->{$this->_sectionName}->resources->db)) { + throw new Zend_Tool_Project_Exception('The config already has a db resource configured in section ' . $this->_sectionName . '.'); + } + + if ($dsn) { + $this->_configureViaDSN($dsn); + //} elseif ($interactivelyPrompt) { + // $this->_promptForConfig(); + } else { + $this->_registry->getResponse()->appendContent('Nothing to do!'); + } + + + } + + protected function _configureViaDSN($dsn) + { + $dsnVars = array(); + + if (strpos($dsn, '=') === false) { + throw new Zend_Tool_Project_Provider_Exception('At least one name value pair is expected, typcially ' + . 'in the format of "adapter=Mysqli&username=uname&password=mypass&dbname=mydb"' + ); + } + + parse_str($dsn, $dsnVars); + + // parse_str suffers when magic_quotes is enabled + if (get_magic_quotes_gpc()) { + array_walk_recursive($dsnVars, array($this, '_cleanMagicQuotesInValues')); + } + + $dbConfigValues = array('resources' => array('db' => null)); + + if (isset($dsnVars['adapter'])) { + $dbConfigValues['resources']['db']['adapter'] = $dsnVars['adapter']; + unset($dsnVars['adapter']); + } + + $dbConfigValues['resources']['db']['params'] = $dsnVars; + + $isPretend = $this->_registry->getRequest()->isPretend(); + + // get the config resource + $applicationConfig = $this->_loadedProfile->search('ApplicationConfigFile'); + $applicationConfig->addItem($dbConfigValues, $this->_sectionName, null); + + $response = $this->_registry->getResponse(); + + if ($isPretend) { + $response->appendContent('A db configuration for the ' . $this->_sectionName + . ' section would be written to the application config file with the following contents: ' + ); + $response->appendContent($applicationConfig->getContents()); + } else { + $applicationConfig->create(); + $response->appendContent('A db configuration for the ' . $this->_sectionName + . ' section has been written to the application config file.' + ); + } + } + + protected function _cleanMagicQuotesInValues(&$value, $key) + { + $value = stripslashes($value); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/DbTable.php b/library/vendor/Zend/Tool/Project/Provider/DbTable.php new file mode 100644 index 000000000..07be93826 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/DbTable.php @@ -0,0 +1,225 @@ + array('moduleName' => $moduleName)); + } + + $profileSearchParams[] = 'modelsDirectory'; + + $modelsDirectory = $profile->search($profileSearchParams); + + if (!($modelsDirectory instanceof Zend_Tool_Project_Profile_Resource)) { + throw new Zend_Tool_Project_Provider_Exception( + 'A models directory was not found' . + (($moduleName) ? ' for module ' . $moduleName . '.' : '.') + ); + } + + if (!($dbTableDirectory = $modelsDirectory->search('DbTableDirectory'))) { + $dbTableDirectory = $modelsDirectory->createResource('DbTableDirectory'); + } + + $dbTableFile = $dbTableDirectory->createResource('DbTableFile', array('dbTableName' => $dbTableName, 'actualTableName' => $actualTableName)); + + return $dbTableFile; + } + + public static function hasResource(Zend_Tool_Project_Profile $profile, $dbTableName, $moduleName = null) + { + $profileSearchParams = array(); + + if ($moduleName != null && is_string($moduleName)) { + $profileSearchParams = array('modulesDirectory', 'moduleDirectory' => array('moduleName' => $moduleName)); + } + + $profileSearchParams[] = 'modelsDirectory'; + + $modelsDirectory = $profile->search($profileSearchParams); + + if (!($modelsDirectory instanceof Zend_Tool_Project_Profile_Resource) + || !($dbTableDirectory = $modelsDirectory->search('DbTableDirectory'))) { + return false; + } + + $dbTableFile = $dbTableDirectory->search(array('DbTableFile' => array('dbTableName' => $dbTableName))); + + return ($dbTableFile instanceof Zend_Tool_Project_Profile_Resource) ? true : false; + } + + + public function create($name, $actualTableName, $module = null, $forceOverwrite = false) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + // Check that there is not a dash or underscore, return if doesnt match regex + if (preg_match('#[_-]#', $name)) { + throw new Zend_Tool_Project_Provider_Exception('DbTable names should be camel cased.'); + } + + $originalName = $name; + $name = ucfirst($name); + + if ($actualTableName == '') { + throw new Zend_Tool_Project_Provider_Exception('You must provide both the DbTable name as well as the actual db table\'s name.'); + } + + if (self::hasResource($this->_loadedProfile, $name, $module)) { + throw new Zend_Tool_Project_Provider_Exception('This project already has a DbTable named ' . $name); + } + + // get request/response object + $request = $this->_registry->getRequest(); + $response = $this->_registry->getResponse(); + + // alert the user about inline converted names + $tense = (($request->isPretend()) ? 'would be' : 'is'); + + if ($name !== $originalName) { + $response->appendContent( + 'Note: The canonical model name that ' . $tense + . ' used with other providers is "' . $name . '";' + . ' not "' . $originalName . '" as supplied', + array('color' => array('yellow')) + ); + } + + try { + $tableResource = self::createResource($this->_loadedProfile, $name, $actualTableName, $module); + } catch (Exception $e) { + $response = $this->_registry->getResponse(); + $response->setException($e); + return; + } + + // do the creation + if ($request->isPretend()) { + $response->appendContent('Would create a DbTable at ' . $tableResource->getContext()->getPath()); + } else { + $response->appendContent('Creating a DbTable at ' . $tableResource->getContext()->getPath()); + $tableResource->create(); + $this->_storeProfile(); + } + } + + /** + * @param string $module Module name action should be applied to. + * @param bool $forceOverwrite Whether should force overwriting previous classes generated + * @return void + */ + public function createFromDatabase($module = null, $forceOverwrite = false) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + $bootstrapResource = $this->_loadedProfile->search('BootstrapFile'); + + /* @var $zendApp Zend_Application */ + $zendApp = $bootstrapResource->getApplicationInstance(); + + try { + $zendApp->bootstrap('db'); + } catch (Zend_Application_Exception $e) { + throw new Zend_Tool_Project_Provider_Exception('Db resource not available, you might need to configure a DbAdapter.'); + return; + } + + /* @var $db Zend_Db_Adapter_Abstract */ + $db = $zendApp->getBootstrap()->getResource('db'); + + $tableResources = array(); + foreach ($db->listTables() as $actualTableName) { + + $dbTableName = $this->_convertTableNameToClassName($actualTableName); + + if (!$forceOverwrite && self::hasResource($this->_loadedProfile, $dbTableName, $module)) { + throw new Zend_Tool_Project_Provider_Exception( + 'This DbTable resource already exists, if you wish to overwrite it, ' + . 'pass the "forceOverwrite" flag to this provider.' + ); + } + + $tableResources[] = self::createResource( + $this->_loadedProfile, + $dbTableName, + $actualTableName, + $module + ); + } + + if (count($tableResources) == 0) { + $this->_registry->getResponse()->appendContent('There are no tables in the selected database to write.'); + } + + // do the creation + if ($this->_registry->getRequest()->isPretend()) { + + foreach ($tableResources as $tableResource) { + $this->_registry->getResponse()->appendContent('Would create a DbTable at ' . $tableResource->getContext()->getPath()); + } + + } else { + + foreach ($tableResources as $tableResource) { + $this->_registry->getResponse()->appendContent('Creating a DbTable at ' . $tableResource->getContext()->getPath()); + $tableResource->create(); + } + + $this->_storeProfile(); + } + + + } + + protected function _convertTableNameToClassName($tableName) + { + if ($this->_nameFilter == null) { + $this->_nameFilter = new Zend_Filter(); + $this->_nameFilter + ->addFilter(new Zend_Filter_Word_UnderscoreToCamelCase()); + } + + return $this->_nameFilter->filter($tableName); + } + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Exception.php b/library/vendor/Zend/Tool/Project/Provider/Exception.php new file mode 100644 index 000000000..bdfbc54c0 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Exception.php @@ -0,0 +1,36 @@ +createResource( + 'formFile', + array('formName' => $formName, 'moduleName' => $moduleName) + ); + + return $newForm; + } + + /** + * hasResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $formName + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + public static function hasResource(Zend_Tool_Project_Profile $profile, $formName, $moduleName = null) + { + if (!is_string($formName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_Form::createResource() expects \"formName\" is the name of a form resource to check for existence.'); + } + + $formsDirectory = self::_getFormsDirectoryResource($profile, $moduleName); + return (($formsDirectory->search(array('formFile' => array('formName' => $formName)))) instanceof Zend_Tool_Project_Profile_Resource); + } + + /** + * _getFormsDirectoryResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + protected static function _getFormsDirectoryResource(Zend_Tool_Project_Profile $profile, $moduleName = null) + { + $profileSearchParams = array(); + + if ($moduleName != null && is_string($moduleName)) { + $profileSearchParams = array('modulesDirectory', 'moduleDirectory' => array('moduleName' => $moduleName)); + } + + $profileSearchParams[] = 'formsDirectory'; + + return $profile->search($profileSearchParams); + } + + public function enable($module = null) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + // determine if testing is enabled in the project + $testingEnabled = Zend_Tool_Project_Provider_Test::isTestingEnabled($this->_loadedProfile); + + $formDirectoryResource = self::_getFormsDirectoryResource($this->_loadedProfile, $module); + + if ($formDirectoryResource->isEnabled()) { + throw new Zend_Tool_Project_Provider_Exception('This project already has forms enabled.'); + } else { + if ($this->_registry->getRequest()->isPretend()) { + $this->_registry->getResponse()->appendContent('Would enable forms directory at ' . $formDirectoryResource->getContext()->getPath()); + } else { + $this->_registry->getResponse()->appendContent('Enabling forms directory at ' . $formDirectoryResource->getContext()->getPath()); + $formDirectoryResource->setEnabled(true); + $formDirectoryResource->create(); + $this->_storeProfile(); + } + + } + } + + /** + * Create a new form + * + * @param string $name + * @param string $module + */ + public function create($name, $module = null) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + // determine if testing is enabled in the project + $testingEnabled = Zend_Tool_Project_Provider_Test::isTestingEnabled($this->_loadedProfile); + + if (self::hasResource($this->_loadedProfile, $name, $module)) { + throw new Zend_Tool_Project_Provider_Exception('This project already has a form named ' . $name); + } + + // Check that there is not a dash or underscore, return if doesnt match regex + if (preg_match('#[_-]#', $name)) { + throw new Zend_Tool_Project_Provider_Exception('Form names should be camel cased.'); + } + + $name = ucwords($name); + + try { + $formResource = self::createResource($this->_loadedProfile, $name, $module); + + if ($testingEnabled) { + $testFormResource = null; + // $testFormResource = Zend_Tool_Project_Provider_Test::createApplicationResource($this->_loadedProfile, $name, 'index', $module); + } + + } catch (Exception $e) { + $response = $this->_registry->getResponse(); + $response->setException($e); + return; + } + + // do the creation + if ($this->_registry->getRequest()->isPretend()) { + + $this->_registry->getResponse()->appendContent('Would create a form at ' . $formResource->getContext()->getPath()); + + if ($testFormResource) { + $this->_registry->getResponse()->appendContent('Would create a form test file at ' . $testFormResource->getContext()->getPath()); + } + + } else { + + $this->_registry->getResponse()->appendContent('Creating a form at ' . $formResource->getContext()->getPath()); + $formResource->create(); + + if ($testFormResource) { + $this->_registry->getResponse()->appendContent('Creating a form test file at ' . $testFormResource->getContext()->getPath()); + $testFormResource->create(); + } + + $this->_storeProfile(); + } + + } + + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Layout.php b/library/vendor/Zend/Tool/Project/Provider/Layout.php new file mode 100644 index 000000000..953811343 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Layout.php @@ -0,0 +1,139 @@ +search('applicationDirectory'); + $layoutDirectory = $applicationDirectory->search('layoutsDirectory'); + + if ($layoutDirectory == false) { + $layoutDirectory = $applicationDirectory->createResource('layoutsDirectory'); + } + + $layoutScriptsDirectory = $layoutDirectory->search('layoutScriptsDirectory'); + + if ($layoutScriptsDirectory == false) { + $layoutScriptsDirectory = $layoutDirectory->createResource('layoutScriptsDirectory'); + } + + $layoutScriptFile = $layoutScriptsDirectory->search('layoutScriptFile', array('layoutName' => 'layout')); + + if ($layoutScriptFile == false) { + $layoutScriptFile = $layoutScriptsDirectory->createResource('layoutScriptFile', array('layoutName' => 'layout')); + } + + return $layoutScriptFile; + } + + public function enable() + { + $profile = $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + $applicationConfigResource = $profile->search('ApplicationConfigFile'); + + if (!$applicationConfigResource) { + throw new Zend_Tool_Project_Exception('A project with an application config file is required to use this provider.'); + } + + $zc = $applicationConfigResource->getAsZendConfig(); + + if (isset($zc->resources) && isset($zc->resources->layout)) { + $this->_registry->getResponse()->appendContent('A layout resource already exists in this project\'s application configuration file.'); + return; + } + + if ($this->_registry->getRequest()->isPretend()) { + $this->_registry->getResponse()->appendContent('Would add "resources.layout.layoutPath" key to the application config file.'); + } else { + $applicationConfigResource->addStringItem('resources.layout.layoutPath', $this->_layoutPath, 'production', false); + $applicationConfigResource->create(); + + $this->_registry->getResponse()->appendContent('A layout entry has been added to the application config file.'); + + $layoutScriptFile = self::createResource($profile); + if (!$layoutScriptFile->exists()) { + $layoutScriptFile->create(); + $this->_registry->getResponse()->appendContent( + 'A default layout has been created at ' + . $layoutScriptFile->getPath() + ); + + } + + $this->_storeProfile(); + } + } + + public function disable() + { + $profile = $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + $applicationConfigResource = $this->_getApplicationConfigResource($profile); + $zc = $applicationConfigResource->getAsZendConfig(); + + if (isset($zc->resources) && !isset($zc->resources->layout)) { + $this->_registry->getResponse()->appendContent('No layout configuration exists in application config file.'); + return; + } + + if ($this->_registry->getRequest()->isPretend()) { + $this->_registry->getResponse()->appendContent('Would remove "resources.layout.layoutPath" key from the application config file.'); + } else { + + // Remove the resources.layout.layoutPath directive from application config + $applicationConfigResource->removeStringItem('resources.layout.layoutPath', $this->_layoutPath, 'production', false); + $applicationConfigResource->create(); + + // Tell the user about the good work we've done + $this->_registry->getResponse()->appendContent('Layout entry has been removed from the application config file.'); + + $this->_storeProfile(); + } + } + + protected function _getApplicationConfigResource(Zend_Tool_Project_Profile $profile) + { + $applicationConfigResource = $profile->search('ApplicationConfigFile'); + if (!$applicationConfigResource) { + throw new Zend_Tool_Project_Exception('A project with an application config file is required to use this provider.'); + } + + return $applicationConfigResource; + } +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Manifest.php b/library/vendor/Zend/Tool/Project/Provider/Manifest.php new file mode 100644 index 000000000..74b9d5ff0 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Manifest.php @@ -0,0 +1,74 @@ +createResource( + 'modelFile', + array('modelName' => $modelName, 'moduleName' => $moduleName) + ); + + return $newModel; + } + + /** + * hasResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $modelName + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + public static function hasResource(Zend_Tool_Project_Profile $profile, $modelName, $moduleName = null) + { + if (!is_string($modelName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_Model::createResource() expects \"modelName\" is the name of a model resource to check for existence.'); + } + + $modelsDirectory = self::_getModelsDirectoryResource($profile, $moduleName); + + if (!$modelsDirectory instanceof Zend_Tool_Project_Profile_Resource) { + return false; + } + + return (($modelsDirectory->search(array('modelFile' => array('modelName' => $modelName)))) instanceof Zend_Tool_Project_Profile_Resource); + } + + /** + * _getModelsDirectoryResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + protected static function _getModelsDirectoryResource(Zend_Tool_Project_Profile $profile, $moduleName = null) + { + $profileSearchParams = array(); + + if ($moduleName != null && is_string($moduleName)) { + $profileSearchParams = array('modulesDirectory', 'moduleDirectory' => array('moduleName' => $moduleName)); + } + + $profileSearchParams[] = 'modelsDirectory'; + + return $profile->search($profileSearchParams); + } + + /** + * Create a new model + * + * @param string $name + * @param string $module + */ + public function create($name, $module = null) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + $originalName = $name; + + $name = ucwords($name); + + // determine if testing is enabled in the project + $testingEnabled = false; //Zend_Tool_Project_Provider_Test::isTestingEnabled($this->_loadedProfile); + $testModelResource = null; + + // Check that there is not a dash or underscore, return if doesnt match regex + if (preg_match('#[_-]#', $name)) { + throw new Zend_Tool_Project_Provider_Exception('Model names should be camel cased.'); + } + + if (self::hasResource($this->_loadedProfile, $name, $module)) { + throw new Zend_Tool_Project_Provider_Exception('This project already has a model named ' . $name); + } + + // get request/response object + $request = $this->_registry->getRequest(); + $response = $this->_registry->getResponse(); + + // alert the user about inline converted names + $tense = (($request->isPretend()) ? 'would be' : 'is'); + + if ($name !== $originalName) { + $response->appendContent( + 'Note: The canonical model name that ' . $tense + . ' used with other providers is "' . $name . '";' + . ' not "' . $originalName . '" as supplied', + array('color' => array('yellow')) + ); + } + + try { + $modelResource = self::createResource($this->_loadedProfile, $name, $module); + + if ($testingEnabled) { + // $testModelResource = Zend_Tool_Project_Provider_Test::createApplicationResource($this->_loadedProfile, $name, 'index', $module); + } + + } catch (Exception $e) { + $response->setException($e); + return; + } + + // do the creation + if ($request->isPretend()) { + + $response->appendContent('Would create a model at ' . $modelResource->getContext()->getPath()); + + if ($testModelResource) { + $response->appendContent('Would create a model test file at ' . $testModelResource->getContext()->getPath()); + } + + } else { + + $response->appendContent('Creating a model at ' . $modelResource->getContext()->getPath()); + $modelResource->create(); + + if ($testModelResource) { + $response->appendContent('Creating a model test file at ' . $testModelResource->getContext()->getPath()); + $testModelResource->create(); + } + + $this->_storeProfile(); + } + + } + + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Module.php b/library/vendor/Zend/Tool/Project/Provider/Module.php new file mode 100644 index 000000000..44cc73a86 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Module.php @@ -0,0 +1,176 @@ +search('applicationDirectory'); + $targetModuleEnabledResources = array( + 'ControllersDirectory', 'ModelsDirectory', 'ViewsDirectory', + 'ViewScriptsDirectory', 'ViewHelpersDirectory', 'ViewFiltersDirectory' + ); + } + + // find the actual modules directory we will use to house our module + $modulesDirectory = $profile->search('modulesDirectory'); + + // if there is a module directory already, except + if ($modulesDirectory->search(array('moduleDirectory' => array('moduleName' => $moduleName)))) { + throw new Zend_Tool_Project_Provider_Exception('A module named "' . $moduleName . '" already exists.'); + } + + // create the module directory + $moduleDirectory = $modulesDirectory->createResource('moduleDirectory', array('moduleName' => $moduleName)); + + // create a context filter so that we can pull out only what we need from the module skeleton + $moduleContextFilterIterator = new Zend_Tool_Project_Profile_Iterator_ContextFilter( + $targetModuleResource, + array( + 'denyNames' => array('ModulesDirectory', 'ViewControllerScriptsDirectory'), + 'denyType' => 'Zend_Tool_Project_Context_Filesystem_File' + ) + ); + + // the iterator for the module skeleton + $targetIterator = new RecursiveIteratorIterator($moduleContextFilterIterator, RecursiveIteratorIterator::SELF_FIRST); + + // initialize some loop state information + $currentDepth = 0; + $parentResources = array(); + $currentResource = $moduleDirectory; + + // loop through the target module skeleton + foreach ($targetIterator as $targetSubResource) { + + $depthDifference = $targetIterator->getDepth() - $currentDepth; + $currentDepth = $targetIterator->getDepth(); + + if ($depthDifference === 1) { + // if we went down into a child, make note + array_push($parentResources, $currentResource); + // this will have always been set previously by another loop + $currentResource = $currentChildResource; + } elseif ($depthDifference < 0) { + // if we went up to a parent, make note + $i = $depthDifference; + do { + // if we went out more than 1 parent, get to the correct parent + $currentResource = array_pop($parentResources); + } while ($i-- > 0); + } + + // get parameters for the newly created module resource + $params = $targetSubResource->getAttributes(); + $currentChildResource = $currentResource->createResource($targetSubResource->getName(), $params); + + // based of the provided list (Currently up top), enable specific resources + if (isset($targetModuleEnabledResources)) { + $currentChildResource->setEnabled(in_array($targetSubResource->getName(), $targetModuleEnabledResources)); + } else { + $currentChildResource->setEnabled($targetSubResource->isEnabled()); + } + + } + + return $moduleDirectory; + } + + /** + * create() + * + * @param string $name + */ + public function create($name) //, $moduleProfile = null) + { + $this->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); + + // determine if testing is enabled in the project + //$testingEnabled = Zend_Tool_Project_Provider_Test::isTestingEnabled($this->_loadedProfile); + + $resources = self::createResources($this->_loadedProfile, $name); + + $response = $this->_registry->getResponse(); + + if ($this->_registry->getRequest()->isPretend()) { + $response->appendContent('I would create the following module and artifacts:'); + foreach (new RecursiveIteratorIterator($resources, RecursiveIteratorIterator::SELF_FIRST) as $resource) { + if (is_callable(array($resource->getContext(), 'getPath'))) { + $response->appendContent($resource->getContext()->getPath()); + } + } + } else { + $response->appendContent('Creating the following module and artifacts:'); + $enabledFilter = new Zend_Tool_Project_Profile_Iterator_EnabledResourceFilter($resources); + foreach (new RecursiveIteratorIterator($enabledFilter, RecursiveIteratorIterator::SELF_FIRST) as $resource) { + $response->appendContent($resource->getContext()->getPath()); + $resource->create(); + } + + $response->appendContent('Added a key for path module directory to the application.ini file'); + $appConfigFile = $this->_loadedProfile->search('ApplicationConfigFile'); + $appConfigFile->removeStringItem('resources.frontController.moduleDirectory', 'production'); + $appConfigFile->addStringItem('resources.frontController.moduleDirectory', 'APPLICATION_PATH "/modules"', 'production', false); + + if (strtolower($name) == 'default') { + $response->appendContent('Added a key for the default module to the application.ini file'); + $appConfigFile->addStringItem('resources.frontController.params.prefixDefaultModule', '1', 'production'); + } + + $appConfigFile->create(); + + // store changes to the profile + $this->_storeProfile(); + } + + } + +} + diff --git a/library/vendor/Zend/Tool/Project/Provider/Profile.php b/library/vendor/Zend/Tool/Project/Provider/Profile.php new file mode 100644 index 000000000..be3bcdcdd --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Profile.php @@ -0,0 +1,53 @@ +_loadProfile(); + + $profileIterator = $this->_loadedProfile->getIterator(); + + foreach ($profileIterator as $profileItem) { + $this->_registry->getResponse()->appendContent( + str_repeat(' ', $profileIterator->getDepth()) . $profileItem + ); + } + + } +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Project.php b/library/vendor/Zend/Tool/Project/Provider/Project.php new file mode 100644 index 000000000..165f800f6 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Project.php @@ -0,0 +1,251 @@ +_loadProfile(self::NO_PROFILE_RETURN_FALSE, $path); + + if ($profile !== false) { + throw new Zend_Tool_Framework_Client_Exception('A project already exists here'); + } + + $profileData = null; + + if ($fileOfProfile != null && file_exists($fileOfProfile)) { + $profileData = file_get_contents($fileOfProfile); + } + + $storage = $this->_registry->getStorage(); + if ($profileData == '' && $nameOfProfile != null && $storage->isEnabled()) { + $profileData = $storage->get('project/profiles/' . $nameOfProfile . '.xml'); + } + + if ($profileData == '') { + $profileData = $this->_getDefaultProfile(); + } + + $newProfile = new Zend_Tool_Project_Profile(array( + 'projectDirectory' => $path, + 'profileData' => $profileData + )); + + $newProfile->loadFromData(); + + $response = $this->_registry->getResponse(); + + $response->appendContent('Creating project at ' . $path); + $response->appendContent('Note: ', array('separator' => false, 'color' => 'yellow')); + $response->appendContent( + 'This command created a web project, ' + . 'for more information setting up your VHOST, please see docs/README'); + + if (!Zend_Tool_Project_Provider_Test::isPHPUnitAvailable()) { + $response->appendContent('Testing Note: ', array('separator' => false, 'color' => 'yellow')); + $response->appendContent('PHPUnit was not found in your include_path, therefore no testing actions will be created.'); + } + + foreach ($newProfile->getIterator() as $resource) { + $resource->create(); + } + } + + public function show() + { + $this->_registry->getResponse()->appendContent('You probably meant to run "show project.info".', array('color' => 'yellow')); + } + + public function showInfo() + { + $profile = $this->_loadProfile(self::NO_PROFILE_RETURN_FALSE); + if (!$profile) { + $this->_registry->getResponse()->appendContent('No project found.'); + } else { + $this->_registry->getResponse()->appendContent('Working with project located at: ' . $profile->getAttribute('projectDirectory')); + } + } + + protected function _getDefaultProfile() + { + $testAction = ''; + if (Zend_Tool_Project_Provider_Test::isPHPUnitAvailable()) { + $testAction = ' '; + } + + $version = Zend_Version::VERSION; + + $data = << + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +$testAction + + + + + + + +EOS; + return $data; + } + + public static function getDefaultReadmeContents($caller = null) + { + $projectDirResource = $caller->getResource()->getProfile()->search('projectDirectory'); + if ($projectDirResource) { + $name = ltrim(strrchr($projectDirResource->getPath(), DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR); + $path = $projectDirResource->getPath() . '/public'; + } else { + $path = '/path/to/public'; + } + + return <<< EOS +README +====== + +This directory should be used to place project specfic documentation including +but not limited to project notes, generated API/phpdoc documentation, or +manual files generated or hand written. Ideally, this directory would remain +in your development environment only and should not be deployed with your +application to it's final production location. + + +Setting Up Your VHOST +===================== + +The following is a sample VHOST you might want to consider for your project. + + + DocumentRoot "$path" + ServerName $name.local + + # This should be omitted in the production environment + SetEnv APPLICATION_ENV development + + + Options Indexes MultiViews FollowSymLinks + AllowOverride All + Order allow,deny + Allow from all + + + + +EOS; + } +} diff --git a/library/vendor/Zend/Tool/Project/Provider/ProjectProvider.php b/library/vendor/Zend/Tool/Project/Provider/ProjectProvider.php new file mode 100644 index 000000000..75c5efbd9 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/ProjectProvider.php @@ -0,0 +1,95 @@ +createResourceAt($profileSearchParams, 'projectProviderFile', array('projectProviderName' => $projectProviderName, 'actionNames' => $actionNames)); + + return $projectProvider; + } + + /** + * getName() + * + * @return string + */ + public function getName() + { + return 'ProjectProvider'; + } + + /** + * Create stub for Zend_Tool Project Provider + * + * @var string $name class name for new Zend_Tool Project Provider + * @var array|string $actions list of provider methods + * @throws Zend_Tool_Project_Provider_Exception + */ + public function create($name, $actions = null) + { + $profile = $this->_loadProfileRequired(); + + $projectProvider = self::createResource($profile, $name, $actions); + + if ($this->_registry->getRequest()->isPretend()) { + $this->_registry->getResponse()->appendContent('Would create a project provider named ' . $name + . ' in location ' . $projectProvider->getPath() + ); + } else { + $this->_registry->getResponse()->appendContent('Creating a project provider named ' . $name + . ' in location ' . $projectProvider->getPath() + ); + $projectProvider->create(); + $this->_storeProfile(); + } + + } +} diff --git a/library/vendor/Zend/Tool/Project/Provider/Test.php b/library/vendor/Zend/Tool/Project/Provider/Test.php new file mode 100644 index 000000000..4627e104f --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/Test.php @@ -0,0 +1,196 @@ +search($profileSearchParams); + + return $testsDirectory->isEnabled(); + } + + public static function isPHPUnitAvailable() + { + if (class_exists('PHPUnit_Runner_Version', false)) { + return true; + } + + $included = @include 'PHPUnit/Runner/Version.php'; + + if ($included === false) { + return false; + } else { + return true; + } + } + + /** + * createApplicationResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $controllerName + * @param string $actionName + * @param string $moduleName + * @return Zend_Tool_Project_Profile_Resource + */ + public static function createApplicationResource(Zend_Tool_Project_Profile $profile, $controllerName, $actionName, $moduleName = null) + { + if (!is_string($controllerName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_View::createApplicationResource() expects \"controllerName\" is the name of a controller resource to create.'); + } + + if (!is_string($actionName)) { + throw new Zend_Tool_Project_Provider_Exception('Zend_Tool_Project_Provider_View::createApplicationResource() expects \"actionName\" is the name of a controller resource to create.'); + } + + $testsDirectoryResource = $profile->search('testsDirectory'); + + // parentOfController could either be application/ or a particular module folder, which is why we use this name + if (($testParentOfControllerDirectoryResource = $testsDirectoryResource->search('testApplicationDirectory')) === false) { + $testParentOfControllerDirectoryResource = $testsDirectoryResource->createResource('testApplicationDirectory'); + } + + if ($moduleName) { + if (($testAppModulesDirectoryResource = $testParentOfControllerDirectoryResource->search('testApplicationModulesDirectory')) === false) { + $testAppModulesDirectoryResource = $testParentOfControllerDirectoryResource->createResource('testApplicationModulesDirectory'); + } + + if (($testAppModuleDirectoryResource = $testAppModulesDirectoryResource->search(array('testApplicationModuleDirectory' => array('forModuleName' => $moduleName)))) === false) { + $testAppModuleDirectoryResource = $testAppModulesDirectoryResource->createResource('testApplicationModuleDirectory', array('forModuleName' => $moduleName)); + } + + $testParentOfControllerDirectoryResource = $testAppModuleDirectoryResource; + } + + if (($testAppControllerDirectoryResource = $testParentOfControllerDirectoryResource->search('testApplicationControllerDirectory', 'testApplicationModuleDirectory')) === false) { + $testAppControllerDirectoryResource = $testParentOfControllerDirectoryResource->createResource('testApplicationControllerDirectory'); + } + + if (($testAppControllerFileResource = $testAppControllerDirectoryResource->search(array('testApplicationControllerFile' => array('forControllerName' => $controllerName)))) === false) { + $testAppControllerFileResource = $testAppControllerDirectoryResource->createResource('testApplicationControllerFile', array('forControllerName' => $controllerName)); + } + + return $testAppControllerFileResource->createResource('testApplicationActionMethod', array('forActionName' => $actionName)); + } + + /** + * createLibraryResource() + * + * @param Zend_Tool_Project_Profile $profile + * @param string $libraryClassName + * @return Zend_Tool_Project_Profile_Resource + */ + public static function createLibraryResource(Zend_Tool_Project_Profile $profile, $libraryClassName) + { + $testLibraryDirectoryResource = $profile->search(array('TestsDirectory', 'TestLibraryDirectory')); + + + $fsParts = explode('_', $libraryClassName); + + $currentDirectoryResource = $testLibraryDirectoryResource; + + while ($nameOrNamespacePart = array_shift($fsParts)) { + + if (count($fsParts) > 0) { + + if (($libraryDirectoryResource = $currentDirectoryResource->search(array('TestLibraryNamespaceDirectory' => array('namespaceName' => $nameOrNamespacePart)))) === false) { + $currentDirectoryResource = $currentDirectoryResource->createResource('TestLibraryNamespaceDirectory', array('namespaceName' => $nameOrNamespacePart)); + } else { + $currentDirectoryResource = $libraryDirectoryResource; + } + + } else { + + if (($libraryFileResource = $currentDirectoryResource->search(array('TestLibraryFile' => array('forClassName' => $libraryClassName)))) === false) { + $libraryFileResource = $currentDirectoryResource->createResource('TestLibraryFile', array('forClassName' => $libraryClassName)); + } + + } + + } + + return $libraryFileResource; + } + + public function enable() + { + + } + + public function disable() + { + + } + + /** + * create() + * + * @param string $libraryClassName + */ + public function create($libraryClassName) + { + $profile = $this->_loadProfile(); + + if (!self::isTestingEnabled($profile)) { + $this->_registry->getResponse()->appendContent('Testing is not enabled for this project.'); + } + + $testLibraryResource = self::createLibraryResource($profile, $libraryClassName); + + $response = $this->_registry->getResponse(); + + if ($this->_registry->getRequest()->isPretend()) { + $response->appendContent('Would create a library stub in location ' . $testLibraryResource->getContext()->getPath()); + } else { + $response->appendContent('Creating a library stub in location ' . $testLibraryResource->getContext()->getPath()); + $testLibraryResource->create(); + $this->_storeProfile(); + } + + } + +} diff --git a/library/vendor/Zend/Tool/Project/Provider/View.php b/library/vendor/Zend/Tool/Project/Provider/View.php new file mode 100644 index 000000000..ebd163e06 --- /dev/null +++ b/library/vendor/Zend/Tool/Project/Provider/View.php @@ -0,0 +1,113 @@ + array('moduleName' => $moduleName)); + $noModuleSearch = null; + } else { + $noModuleSearch = array('modulesDirectory'); + } + + $profileSearchParams[] = 'viewsDirectory'; + $profileSearchParams[] = 'viewScriptsDirectory'; + + if (($viewScriptsDirectory = $profile->search($profileSearchParams, $noModuleSearch)) === false) { + throw new Zend_Tool_Project_Provider_Exception('This project does not have a viewScriptsDirectory resource.'); + } + + $profileSearchParams['viewControllerScriptsDirectory'] = array('forControllerName' => $controllerName); + + // @todo check if below is failing b/c of above search params + if (($viewControllerScriptsDirectory = $viewScriptsDirectory->search($profileSearchParams)) === false) { + $viewControllerScriptsDirectory = $viewScriptsDirectory->createResource('viewControllerScriptsDirectory', array('forControllerName' => $controllerName)); + } + + $newViewScriptFile = $viewControllerScriptsDirectory->createResource('ViewScriptFile', array('forActionName' => $actionName)); + + return $newViewScriptFile; + } + + /** + * create() + * + * @param string $controllerName + * @param string $actionNameOrSimpleName + */ + public function create($controllerName, $actionNameOrSimpleName, $module = null) + { + + if ($controllerName == '' || $actionNameOrSimpleName == '') { + throw new Zend_Tool_Project_Provider_Exception('ControllerName and/or ActionName are empty.'); + } + + $profile = $this->_loadProfile(); + + $view = self::createResource($profile, $actionNameOrSimpleName, $controllerName, $module); + + if ($this->_registry->getRequest()->isPretend()) { + $this->_registry->getResponse( + 'Would create a view script in location ' . $view->getContext()->getPath() + ); + } else { + $this->_registry->getResponse( + 'Creating a view script in location ' . $view->getContext()->getPath() + ); + $view->create(); + $this->_storeProfile(); + } + + } +} diff --git a/library/vendor/Zend/Translate.php b/library/vendor/Zend/Translate.php new file mode 100644 index 000000000..6264d225a --- /dev/null +++ b/library/vendor/Zend/Translate.php @@ -0,0 +1,216 @@ +toArray(); + } else if (func_num_args() > 1) { + $args = func_get_args(); + $options = array(); + $options['adapter'] = array_shift($args); + if (!empty($args)) { + $options['content'] = array_shift($args); + } + + if (!empty($args)) { + $options['locale'] = array_shift($args); + } + + if (!empty($args)) { + $opt = array_shift($args); + $options = array_merge($opt, $options); + } + } else if (!is_array($options)) { + $options = array('adapter' => $options); + } + + $this->setAdapter($options); + } + + /** + * Sets a new adapter + * + * @param array|Zend_Config $options Options to use + * @throws Zend_Translate_Exception + */ + public function setAdapter($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (func_num_args() > 1) { + $args = func_get_args(); + $options = array(); + $options['adapter'] = array_shift($args); + if (!empty($args)) { + $options['content'] = array_shift($args); + } + + if (!empty($args)) { + $options['locale'] = array_shift($args); + } + + if (!empty($args)) { + $opt = array_shift($args); + $options = array_merge($opt, $options); + } + } else if (!is_array($options)) { + $options = array('adapter' => $options); + } + + if (Zend_Loader::isReadable('Zend/Translate/Adapter/' . ucfirst($options['adapter']). '.php')) { + $options['adapter'] = 'Zend_Translate_Adapter_' . ucfirst($options['adapter']); + } + + if (!class_exists($options['adapter'])) { + Zend_Loader::loadClass($options['adapter']); + } + + if (array_key_exists('cache', $options)) { + Zend_Translate_Adapter::setCache($options['cache']); + } + + $adapter = $options['adapter']; + unset($options['adapter']); + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Translate_Adapter) { + throw new Zend_Translate_Exception("Adapter " . $adapter . " does not extend Zend_Translate_Adapter"); + } + } + + /** + * Returns the adapters name and it's options + * + * @return Zend_Translate_Adapter + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Returns the set cache + * + * @return Zend_Cache_Core The set cache + */ + public static function getCache() + { + return Zend_Translate_Adapter::getCache(); + } + + /** + * Sets a cache for all instances of Zend_Translate + * + * @param Zend_Cache_Core $cache Cache to store to + * @return void + */ + public static function setCache(Zend_Cache_Core $cache) + { + Zend_Translate_Adapter::setCache($cache); + } + + /** + * Returns true when a cache is set + * + * @return boolean + */ + public static function hasCache() + { + return Zend_Translate_Adapter::hasCache(); + } + + /** + * Removes any set cache + * + * @return void + */ + public static function removeCache() + { + Zend_Translate_Adapter::removeCache(); + } + + /** + * Clears all set cache data + * + * @param string $tag Tag to clear when the default tag name is not used + * @return void + */ + public static function clearCache($tag = null) + { + Zend_Translate_Adapter::clearCache($tag); + } + + /** + * Calls all methods from the adapter + */ + public function __call($method, array $options) + { + if (method_exists($this->_adapter, $method)) { + return call_user_func_array(array($this->_adapter, $method), $options); + } + throw new Zend_Translate_Exception("Unknown method '" . $method . "' called!"); + } +} diff --git a/library/vendor/Zend/Translate/Adapter.php b/library/vendor/Zend/Translate/Adapter.php new file mode 100644 index 000000000..6d8ac47c0 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter.php @@ -0,0 +1,986 @@ + when true, clears already loaded translations when adding new files + * 'content' => content to translate or file or directory with content + * 'disableNotices' => when true, omits notices from being displayed + * 'ignore' => a prefix for files and directories which are not being added + * 'locale' => the actual set locale to use + * 'log' => a instance of Zend_Log where logs are written to + * 'logMessage' => message to be logged + * 'logPriority' => priority which is used to write the log message + * 'logUntranslated' => when true, untranslated messages are not logged + * 'reload' => reloads the cache by reading the content again + * 'scan' => searches for translation files using the LOCALE constants + * 'tag' => tag to use for the cache + * + * @var array + */ + protected $_options = array( + 'clear' => false, + 'content' => null, + 'disableNotices' => false, + 'ignore' => '.', + 'locale' => 'auto', + 'log' => null, + 'logMessage' => "Untranslated message within '%locale%': %message%", + 'logPriority' => 5, + 'logUntranslated' => false, + 'reload' => false, + 'route' => null, + 'scan' => null, + 'tag' => 'Zend_Translate' + ); + + /** + * Translation table + * @var array + */ + protected $_translate = array(); + + /** + * Generates the adapter + * + * @param array|Zend_Config $options Translation options for this adapter + * @throws Zend_Translate_Exception + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (func_num_args() > 1) { + $args = func_get_args(); + $options = array(); + $options['content'] = array_shift($args); + + if (!empty($args)) { + $options['locale'] = array_shift($args); + } + + if (!empty($args)) { + $opt = array_shift($args); + $options = array_merge($opt, $options); + } + } else if (!is_array($options)) { + $options = array('content' => $options); + } + + if (array_key_exists('cache', $options)) { + self::setCache($options['cache']); + unset($options['cache']); + } + + if (isset(self::$_cache)) { + $id = 'Zend_Translate_' . $this->toString() . '_Options'; + $result = self::$_cache->load($id); + if ($result) { + $this->_options = $result; + } + } + + if (empty($options['locale']) || ($options['locale'] === "auto")) { + $this->_automatic = true; + } else { + $this->_automatic = false; + } + + $locale = null; + if (!empty($options['locale'])) { + $locale = $options['locale']; + unset($options['locale']); + } + + $this->setOptions($options); + $options['locale'] = $locale; + + if (!empty($options['content'])) { + $this->addTranslation($options); + } + + if ($this->getLocale() !== (string) $options['locale']) { + $this->setLocale($options['locale']); + } + } + + /** + * Add translations + * + * This may be a new language or additional content for an existing language + * If the key 'clear' is true, then translations for the specified + * language will be replaced and added otherwise + * + * @param array|Zend_Config $options Options and translations to be added + * @throws Zend_Translate_Exception + * @return Zend_Translate_Adapter Provides fluent interface + */ + public function addTranslation($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (func_num_args() > 1) { + $args = func_get_args(); + $options = array(); + $options['content'] = array_shift($args); + + if (!empty($args)) { + $options['locale'] = array_shift($args); + } + + if (!empty($args)) { + $opt = array_shift($args); + $options = array_merge($opt, $options); + } + } else if (!is_array($options)) { + $options = array('content' => $options); + } + + if (!isset($options['content']) || empty($options['content'])) { + throw new Zend_Translate_Exception("Required option 'content' is missing"); + } + + $originate = null; + if (!empty($options['locale'])) { + $originate = (string) $options['locale']; + } + + if ((array_key_exists('log', $options)) && !($options['log'] instanceof Zend_Log)) { + throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log'); + } + + try { + if (!($options['content'] instanceof Zend_Translate) && !($options['content'] instanceof Zend_Translate_Adapter)) { + if (empty($options['locale'])) { + $options['locale'] = null; + } + + $options['locale'] = Zend_Locale::findLocale($options['locale']); + } + } catch (Zend_Locale_Exception $e) { + throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e); + } + + $options = $options + $this->_options; + if (is_string($options['content']) and is_dir($options['content'])) { + $options['content'] = realpath($options['content']); + $prev = ''; + $iterator = new RecursiveIteratorIterator( + new RecursiveRegexIterator( + new RecursiveDirectoryIterator($options['content'], RecursiveDirectoryIterator::KEY_AS_PATHNAME), + '/^(?!.*(\.svn|\.cvs)).*$/', RecursiveRegexIterator::MATCH + ), + RecursiveIteratorIterator::SELF_FIRST + ); + + foreach ($iterator as $directory => $info) { + $file = $info->getFilename(); + if (is_array($options['ignore'])) { + foreach ($options['ignore'] as $key => $ignore) { + if (strpos($key, 'regex') !== false) { + if (preg_match($ignore, $directory)) { + // ignore files matching the given regex from option 'ignore' and all files below + continue 2; + } + } else if (strpos($directory, DIRECTORY_SEPARATOR . $ignore) !== false) { + // ignore files matching first characters from option 'ignore' and all files below + continue 2; + } + } + } else { + if (strpos($directory, DIRECTORY_SEPARATOR . $options['ignore']) !== false) { + // ignore files matching first characters from option 'ignore' and all files below + continue; + } + } + + if ($info->isDir()) { + // pathname as locale + if (($options['scan'] === self::LOCALE_DIRECTORY) and (Zend_Locale::isLocale($file, true, false))) { + $options['locale'] = $file; + $prev = (string) $options['locale']; + } + } else if ($info->isFile()) { + // filename as locale + if ($options['scan'] === self::LOCALE_FILENAME) { + $filename = explode('.', $file); + array_pop($filename); + $filename = implode('.', $filename); + if (Zend_Locale::isLocale((string) $filename, true, false)) { + $options['locale'] = (string) $filename; + } else { + $parts = explode('.', $file); + $parts2 = array(); + foreach($parts as $token) { + $parts2 += explode('_', $token); + } + $parts = array_merge($parts, $parts2); + $parts2 = array(); + foreach($parts as $token) { + $parts2 += explode('-', $token); + } + $parts = array_merge($parts, $parts2); + $parts = array_unique($parts); + $prev = ''; + foreach($parts as $token) { + if (Zend_Locale::isLocale($token, true, false)) { + if (strlen($prev) <= strlen($token)) { + $options['locale'] = $token; + $prev = $token; + } + } + } + } + } + + try { + $options['content'] = $info->getPathname(); + $this->_addTranslationData($options); + } catch (Zend_Translate_Exception $e) { + // ignore failed sources while scanning + } + } + } + + unset($iterator); + } else { + $this->_addTranslationData($options); + } + + if ((isset($this->_translate[$originate]) === true) and (count($this->_translate[$originate]) > 0)) { + $this->setLocale($originate); + } + + return $this; + } + + /** + * Sets new adapter options + * + * @param array $options Adapter options + * @throws Zend_Translate_Exception + * @return Zend_Translate_Adapter Provides fluent interface + */ + public function setOptions(array $options = array()) + { + $change = false; + $locale = null; + foreach ($options as $key => $option) { + if ($key == 'locale') { + $locale = $option; + } else if ((isset($this->_options[$key]) and ($this->_options[$key] != $option)) or + !isset($this->_options[$key])) { + if (($key == 'log') && !($option instanceof Zend_Log)) { + throw new Zend_Translate_Exception('Instance of Zend_Log expected for option log'); + } + + if ($key == 'cache') { + self::setCache($option); + continue; + } + + $this->_options[$key] = $option; + $change = true; + } + } + + if ($locale !== null) { + $this->setLocale($locale); + } + + if (isset(self::$_cache) and ($change == true)) { + $id = 'Zend_Translate_' . $this->toString() . '_Options'; + if (self::$_cacheTags) { + self::$_cache->save($this->_options, $id, array($this->_options['tag'])); + } else { + self::$_cache->save($this->_options, $id); + } + } + + return $this; + } + + /** + * Returns the adapters name and it's options + * + * @param string|null $optionKey String returns this option + * null returns all options + * @return integer|string|array|null + */ + public function getOptions($optionKey = null) + { + if ($optionKey === null) { + return $this->_options; + } + + if (isset($this->_options[$optionKey]) === true) { + return $this->_options[$optionKey]; + } + + return null; + } + + /** + * Gets locale + * + * @return Zend_Locale|string|null + */ + public function getLocale() + { + return $this->_options['locale']; + } + + /** + * Sets locale + * + * @param string|Zend_Locale $locale Locale to set + * @throws Zend_Translate_Exception + * @return Zend_Translate_Adapter Provides fluent interface + */ + public function setLocale($locale) + { + if (($locale === "auto") or ($locale === null)) { + $this->_automatic = true; + } else { + $this->_automatic = false; + } + + try { + $locale = Zend_Locale::findLocale($locale); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Translate_Exception("The given Language ({$locale}) does not exist", 0, $e); + } + + if (!isset($this->_translate[$locale])) { + $temp = explode('_', $locale); + if (!isset($this->_translate[$temp[0]]) and !isset($this->_translate[$locale])) { + if (!$this->_options['disableNotices']) { + if ($this->_options['log']) { + $this->_options['log']->log("The language '{$locale}' has to be added before it can be used.", $this->_options['logPriority']); + } else { + trigger_error("The language '{$locale}' has to be added before it can be used.", E_USER_NOTICE); + } + } + } + + $locale = $temp[0]; + } + + if (empty($this->_translate[$locale])) { + if (!$this->_options['disableNotices']) { + if ($this->_options['log']) { + $this->_options['log']->log("No translation for the language '{$locale}' available.", $this->_options['logPriority']); + } else { + trigger_error("No translation for the language '{$locale}' available.", E_USER_NOTICE); + } + } + } + + if ($this->_options['locale'] != $locale) { + $this->_options['locale'] = $locale; + + if (isset(self::$_cache)) { + $id = 'Zend_Translate_' . $this->toString() . '_Options'; + if (self::$_cacheTags) { + self::$_cache->save($this->_options, $id, array($this->_options['tag'])); + } else { + self::$_cache->save($this->_options, $id); + } + } + } + + return $this; + } + + /** + * Returns the available languages from this adapter + * + * @return array|null + */ + public function getList() + { + $list = array_keys($this->_translate); + $result = null; + foreach($list as $value) { + if (!empty($this->_translate[$value])) { + $result[$value] = $value; + } + } + return $result; + } + + /** + * Returns the message id for a given translation + * If no locale is given, the actual language will be used + * + * @param string $message Message to get the key for + * @param string|Zend_Locale $locale (optional) Language to return the message ids from + * @return string|array|false + */ + public function getMessageId($message, $locale = null) + { + if (empty($locale) or !$this->isAvailable($locale)) { + $locale = $this->_options['locale']; + } + + return array_search($message, $this->_translate[(string) $locale]); + } + + /** + * Returns all available message ids from this adapter + * If no locale is given, the actual language will be used + * + * @param string|Zend_Locale $locale (optional) Language to return the message ids from + * @return array + */ + public function getMessageIds($locale = null) + { + if (empty($locale) or !$this->isAvailable($locale)) { + $locale = $this->_options['locale']; + } + + return array_keys($this->_translate[(string) $locale]); + } + + /** + * Returns all available translations from this adapter + * If no locale is given, the actual language will be used + * If 'all' is given the complete translation dictionary will be returned + * + * @param string|Zend_Locale $locale (optional) Language to return the messages from + * @return array + */ + public function getMessages($locale = null) + { + if ($locale === 'all') { + return $this->_translate; + } + + if ((empty($locale) === true) or ($this->isAvailable($locale) === false)) { + $locale = $this->_options['locale']; + } + + return $this->_translate[(string) $locale]; + } + + /** + * Is the wished language available ? + * + * @see Zend_Locale + * @param string|Zend_Locale $locale Language to search for, identical with locale identifier, + * @see Zend_Locale for more information + * @return boolean + */ + public function isAvailable($locale) + { + $return = isset($this->_translate[(string) $locale]); + return $return; + } + + /** + * Load translation data + * + * @param mixed $data + * @param string|Zend_Locale $locale + * @param array $options (optional) + * @return array + */ + abstract protected function _loadTranslationData($data, $locale, array $options = array()); + + /** + * Internal function for adding translation data + * + * This may be a new language or additional data for an existing language + * If the options 'clear' is true, then the translation data for the specified + * language is replaced and added otherwise + * + * @see Zend_Locale + * @param array|Zend_Config $content Translation data to add + * @throws Zend_Translate_Exception + * @return Zend_Translate_Adapter Provides fluent interface + */ + private function _addTranslationData($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (func_num_args() > 1) { + $args = func_get_args(); + $options['content'] = array_shift($args); + + if (!empty($args)) { + $options['locale'] = array_shift($args); + } + + if (!empty($args)) { + $options += array_shift($args); + } + } + + if (($options['content'] instanceof Zend_Translate) || ($options['content'] instanceof Zend_Translate_Adapter)) { + $options['usetranslateadapter'] = true; + if (!empty($options['locale']) && ($options['locale'] !== 'auto')) { + $options['content'] = $options['content']->getMessages($options['locale']); + } else { + $content = $options['content']; + $locales = $content->getList(); + foreach ($locales as $locale) { + $options['locale'] = $locale; + $options['content'] = $content->getMessages($locale); + $this->_addTranslationData($options); + } + + return $this; + } + } + + try { + $options['locale'] = Zend_Locale::findLocale($options['locale']); + } catch (Zend_Locale_Exception $e) { + throw new Zend_Translate_Exception("The given Language '{$options['locale']}' does not exist", 0, $e); + } + + if ($options['clear'] || !isset($this->_translate[$options['locale']])) { + $this->_translate[$options['locale']] = array(); + } + + $read = true; + if (isset(self::$_cache)) { + $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString(); + $temp = self::$_cache->load($id); + if ($temp) { + $read = false; + } + } + + if ($options['reload']) { + $read = true; + } + + if ($read) { + if (!empty($options['usetranslateadapter'])) { + $temp = array($options['locale'] => $options['content']); + } else { + $temp = $this->_loadTranslationData($options['content'], $options['locale'], $options); + } + } + + if (empty($temp)) { + $temp = array(); + } + + $keys = array_keys($temp); + foreach($keys as $key) { + if (!isset($this->_translate[$key])) { + $this->_translate[$key] = array(); + } + + if (array_key_exists($key, $temp) && is_array($temp[$key])) { + $this->_translate[$key] = $temp[$key] + $this->_translate[$key]; + } + } + + if ($this->_automatic === true) { + $find = new Zend_Locale($options['locale']); + $browser = $find->getEnvironment() + $find->getBrowser(); + arsort($browser); + foreach($browser as $language => $quality) { + if (isset($this->_translate[$language])) { + $this->_options['locale'] = $language; + break; + } + } + } + + if (($read) and (isset(self::$_cache))) { + $id = 'Zend_Translate_' . md5(serialize($options['content'])) . '_' . $this->toString(); + if (self::$_cacheTags) { + self::$_cache->save($temp, $id, array($this->_options['tag'])); + } else { + self::$_cache->save($temp, $id); + } + } + + return $this; + } + + /** + * Translates the given string + * returns the translation + * + * @see Zend_Locale + * @param string|array $messageId Translation string, or Array for plural translations + * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with + * locale identifier, @see Zend_Locale for more information + * @return string + */ + public function translate($messageId, $locale = null) + { + if ($locale === null) { + $locale = $this->_options['locale']; + } + + $plural = null; + if (is_array($messageId)) { + if (count($messageId) > 2) { + $number = array_pop($messageId); + if (!is_numeric($number)) { + $plocale = $number; + $number = array_pop($messageId); + } else { + $plocale = 'en'; + } + + $plural = $messageId; + $messageId = $messageId[0]; + } else { + $messageId = $messageId[0]; + } + } + + if (!Zend_Locale::isLocale($locale, true, false)) { + if (!Zend_Locale::isLocale($locale, false, false)) { + // language does not exist, return original string + $this->_log($messageId, $locale); + // use rerouting when enabled + if (!empty($this->_options['route'])) { + if (array_key_exists($locale, $this->_options['route']) && + !array_key_exists($locale, $this->_routed)) { + $this->_routed[$locale] = true; + return $this->translate($messageId, $this->_options['route'][$locale]); + } + } + + $this->_routed = array(); + if ($plural === null) { + return $messageId; + } + + $rule = Zend_Translate_Plural::getPlural($number, $plocale); + if (!isset($plural[$rule])) { + $rule = 0; + } + + return $plural[$rule]; + } + + $locale = new Zend_Locale($locale); + } + + $locale = (string) $locale; + if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { + // return original translation + if ($plural === null) { + $this->_routed = array(); + return $this->_translate[$locale][$messageId]; + } + + $rule = Zend_Translate_Plural::getPlural($number, $locale); + if (isset($this->_translate[$locale][$plural[0]][$rule])) { + $this->_routed = array(); + return $this->_translate[$locale][$plural[0]][$rule]; + } + } else if (strlen($locale) != 2) { + // faster than creating a new locale and separate the leading part + $locale = substr($locale, 0, -strlen(strrchr($locale, '_'))); + + if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { + // return regionless translation (en_US -> en) + if ($plural === null) { + $this->_routed = array(); + return $this->_translate[$locale][$messageId]; + } + + $rule = Zend_Translate_Plural::getPlural($number, $locale); + if (isset($this->_translate[$locale][$plural[0]][$rule])) { + $this->_routed = array(); + return $this->_translate[$locale][$plural[0]][$rule]; + } + } + } + + $this->_log($messageId, $locale); + // use rerouting when enabled + if (!empty($this->_options['route'])) { + if (array_key_exists($locale, $this->_options['route']) && + !array_key_exists($locale, $this->_routed)) { + $this->_routed[$locale] = true; + return $this->translate($messageId, $this->_options['route'][$locale]); + } + } + + $this->_routed = array(); + if ($plural === null) { + return $messageId; + } + + $rule = Zend_Translate_Plural::getPlural($number, $plocale); + if (!isset($plural[$rule])) { + $rule = 0; + } + + return $plural[$rule]; + } + + /** + * Translates the given string using plural notations + * Returns the translated string + * + * @see Zend_Locale + * @param string $singular Singular translation string + * @param string $plural Plural translation string + * @param integer $number Number for detecting the correct plural + * @param string|Zend_Locale $locale (Optional) Locale/Language to use, identical with + * locale identifier, @see Zend_Locale for more information + * @return string + */ + public function plural($singular, $plural, $number, $locale = null) + { + return $this->translate(array($singular, $plural, $number), $locale); + } + + /** + * Logs a message when the log option is set + * + * @param string $message Message to log + * @param String $locale Locale to log + */ + protected function _log($message, $locale) { + if ($this->_options['logUntranslated']) { + $message = str_replace('%message%', $message, $this->_options['logMessage']); + $message = str_replace('%locale%', $locale, $message); + if ($this->_options['log']) { + $this->_options['log']->log($message, $this->_options['logPriority']); + } else { + trigger_error($message, E_USER_NOTICE); + } + } + } + + /** + * Translates the given string + * returns the translation + * + * @param string $messageId Translation string + * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale + * identifier, @see Zend_Locale for more information + * @return string + */ + public function _($messageId, $locale = null) + { + return $this->translate($messageId, $locale); + } + + /** + * Checks if a string is translated within the source or not + * returns boolean + * + * @param string $messageId Translation string + * @param boolean $original (optional) Allow translation only for original language + * when true, a translation for 'en_US' would give false when it can + * be translated with 'en' only + * @param string|Zend_Locale $locale (optional) Locale/Language to use, identical with locale identifier, + * see Zend_Locale for more information + * @return boolean + */ + public function isTranslated($messageId, $original = false, $locale = null) + { + if (($original !== false) and ($original !== true)) { + $locale = $original; + $original = false; + } + + if ($locale === null) { + $locale = $this->_options['locale']; + } + + if (!Zend_Locale::isLocale($locale, true, false)) { + if (!Zend_Locale::isLocale($locale, false, false)) { + // language does not exist, return original string + return false; + } + + $locale = new Zend_Locale($locale); + } + + $locale = (string) $locale; + if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { + // return original translation + return true; + } else if ((strlen($locale) != 2) and ($original === false)) { + // faster than creating a new locale and separate the leading part + $locale = substr($locale, 0, -strlen(strrchr($locale, '_'))); + + if ((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId])) { + // return regionless translation (en_US -> en) + return true; + } + } + + // No translation found, return original + return false; + } + + /** + * Returns the set cache + * + * @return Zend_Cache_Core The set cache + */ + public static function getCache() + { + return self::$_cache; + } + + /** + * Sets a cache for all Zend_Translate_Adapters + * + * @param Zend_Cache_Core $cache Cache to store to + */ + public static function setCache(Zend_Cache_Core $cache) + { + self::$_cache = $cache; + self::_getTagSupportForCache(); + } + + /** + * Returns true when a cache is set + * + * @return boolean + */ + public static function hasCache() + { + if (self::$_cache !== null) { + return true; + } + + return false; + } + + /** + * Removes any set cache + * + * @return void + */ + public static function removeCache() + { + self::$_cache = null; + } + + /** + * Clears all set cache data + * + * @param string $tag Tag to clear when the default tag name is not used + * @return void + */ + public static function clearCache($tag = null) + { + if (self::$_cacheTags) { + if ($tag == null) { + $tag = 'Zend_Translate'; + } + + self::$_cache->clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array($tag)); + } else { + self::$_cache->clean(Zend_Cache::CLEANING_MODE_ALL); + } + } + + /** + * Returns the adapter name + * + * @return string + */ + abstract public function toString(); + + /** + * Internal method to check if the given cache supports tags + * + * @param Zend_Cache $cache + */ + private static function _getTagSupportForCache() + { + $backend = self::$_cache->getBackend(); + if ($backend instanceof Zend_Cache_Backend_ExtendedInterface) { + $cacheOptions = $backend->getCapabilities(); + self::$_cacheTags = $cacheOptions['tags']; + } else { + self::$_cacheTags = false; + } + + return self::$_cacheTags; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Array.php b/library/vendor/Zend/Translate/Adapter/Array.php new file mode 100644 index 000000000..fbbe2161e --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Array.php @@ -0,0 +1,78 @@ +_data = array(); + if (!is_array($data)) { + if (file_exists($data)) { + ob_start(); + $data = include($data); + ob_end_clean(); + } + } + if (!is_array($data)) { + throw new Zend_Translate_Exception("Error including array or file '".$data."'"); + } + + if (!isset($this->_data[$locale])) { + $this->_data[$locale] = array(); + } + + $this->_data[$locale] = $data + $this->_data[$locale]; + return $this->_data; + } + + /** + * returns the adapters name + * + * @return string + */ + public function toString() + { + return "Array"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Csv.php b/library/vendor/Zend/Translate/Adapter/Csv.php new file mode 100644 index 000000000..15ff356fe --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Csv.php @@ -0,0 +1,118 @@ +_options['delimiter'] = ";"; + $this->_options['length'] = 0; + $this->_options['enclosure'] = '"'; + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (func_num_args() > 1) { + $args = func_get_args(); + $options = array(); + $options['content'] = array_shift($args); + + if (!empty($args)) { + $options['locale'] = array_shift($args); + } + + if (!empty($args)) { + $opt = array_shift($args); + $options = array_merge($opt, $options); + } + } else if (!is_array($options)) { + $options = array('content' => $options); + } + + parent::__construct($options); + } + + /** + * Load translation data + * + * @param string|array $filename Filename and full path to the translation source + * @param string $locale Locale/Language to add data for, identical with locale identifier, + * see Zend_Locale for more information + * @param array $option OPTIONAL Options to use + * @return array + */ + protected function _loadTranslationData($filename, $locale, array $options = array()) + { + $this->_data = array(); + $options = $options + $this->_options; + $this->_file = @fopen($filename, 'rb'); + if (!$this->_file) { + throw new Zend_Translate_Exception('Error opening translation file \'' . $filename . '\'.'); + } + + while(($data = fgetcsv($this->_file, $options['length'], $options['delimiter'], $options['enclosure'])) !== false) { + if (substr($data[0], 0, 1) === '#') { + continue; + } + + if (!isset($data[1])) { + continue; + } + + if (count($data) == 2) { + $this->_data[$locale][$data[0]] = $data[1]; + } else { + $singular = array_shift($data); + $this->_data[$locale][$singular] = $data; + } + } + + return $this->_data; + } + + /** + * returns the adapters name + * + * @return string + */ + public function toString() + { + return "Csv"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Gettext.php b/library/vendor/Zend/Translate/Adapter/Gettext.php new file mode 100644 index 000000000..b9cd02245 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Gettext.php @@ -0,0 +1,164 @@ +_bigEndian === false) { + return unpack('V' . $bytes, fread($this->_file, 4 * $bytes)); + } else { + return unpack('N' . $bytes, fread($this->_file, 4 * $bytes)); + } + } + + /** + * Load translation data (MO file reader) + * + * @param string $filename MO file to add, full path must be given for access + * @param string $locale New Locale/Language to set, identical with locale identifier, + * see Zend_Locale for more information + * @param array $option OPTIONAL Options to use + * @throws Zend_Translation_Exception + * @return array + */ + protected function _loadTranslationData($filename, $locale, array $options = array()) + { + $this->_data = array(); + $this->_bigEndian = false; + $this->_file = @fopen($filename, 'rb'); + if (!$this->_file) { + throw new Zend_Translate_Exception('Error opening translation file \'' . $filename . '\'.'); + } + if (@filesize($filename) < 10) { + @fclose($this->_file); + throw new Zend_Translate_Exception('\'' . $filename . '\' is not a gettext file'); + } + + // get Endian + $input = $this->_readMOData(1); + if (strtolower(substr(dechex($input[1]), -8)) == "950412de") { + $this->_bigEndian = false; + } else if (strtolower(substr(dechex($input[1]), -8)) == "de120495") { + $this->_bigEndian = true; + } else { + @fclose($this->_file); + throw new Zend_Translate_Exception('\'' . $filename . '\' is not a gettext file'); + } + // read revision - not supported for now + $input = $this->_readMOData(1); + + // number of bytes + $input = $this->_readMOData(1); + $total = $input[1]; + + // number of original strings + $input = $this->_readMOData(1); + $OOffset = $input[1]; + + // number of translation strings + $input = $this->_readMOData(1); + $TOffset = $input[1]; + + // fill the original table + fseek($this->_file, $OOffset); + $origtemp = $this->_readMOData(2 * $total); + fseek($this->_file, $TOffset); + $transtemp = $this->_readMOData(2 * $total); + + for($count = 0; $count < $total; ++$count) { + if ($origtemp[$count * 2 + 1] != 0) { + fseek($this->_file, $origtemp[$count * 2 + 2]); + $original = @fread($this->_file, $origtemp[$count * 2 + 1]); + $original = explode("\0", $original); + } else { + $original[0] = ''; + } + + if ($transtemp[$count * 2 + 1] != 0) { + fseek($this->_file, $transtemp[$count * 2 + 2]); + $translate = fread($this->_file, $transtemp[$count * 2 + 1]); + $translate = explode("\0", $translate); + if ((count($original) > 1)) { + $this->_data[$locale][$original[0]] = $translate; + array_shift($original); + foreach ($original as $orig) { + $this->_data[$locale][$orig] = ''; + } + } else { + $this->_data[$locale][$original[0]] = $translate[0]; + } + } + } + + @fclose($this->_file); + + $this->_data[$locale][''] = trim($this->_data[$locale]['']); + if (empty($this->_data[$locale][''])) { + $this->_adapterInfo[$filename] = 'No adapter information available'; + } else { + $this->_adapterInfo[$filename] = $this->_data[$locale]['']; + } + + unset($this->_data[$locale]['']); + return $this->_data; + } + + /** + * Returns the adapter informations + * + * @return array Each loaded adapter information as array value + */ + public function getAdapterInfo() + { + return $this->_adapterInfo; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return "Gettext"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Ini.php b/library/vendor/Zend/Translate/Adapter/Ini.php new file mode 100644 index 000000000..595b2f8c6 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Ini.php @@ -0,0 +1,71 @@ +_data = array(); + if (!file_exists($data)) { + throw new Zend_Translate_Exception("Ini file '".$data."' not found"); + } + + $inidata = parse_ini_file($data, false); + if (!isset($this->_data[$locale])) { + $this->_data[$locale] = array(); + } + + $this->_data[$locale] = array_merge($this->_data[$locale], $inidata); + return $this->_data; + } + + /** + * returns the adapters name + * + * @return string + */ + public function toString() + { + return "Ini"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Qt.php b/library/vendor/Zend/Translate/Adapter/Qt.php new file mode 100644 index 000000000..7b9122196 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Qt.php @@ -0,0 +1,168 @@ +_data = array(); + if (!is_readable($filename)) { + throw new Zend_Translate_Exception('Translation file \'' . $filename . '\' is not readable.'); + } + + $this->_target = $locale; + + $encoding = $this->_findEncoding($filename); + $this->_file = xml_parser_create($encoding); + xml_set_object($this->_file, $this); + xml_parser_set_option($this->_file, XML_OPTION_CASE_FOLDING, 0); + xml_set_element_handler($this->_file, "_startElement", "_endElement"); + xml_set_character_data_handler($this->_file, "_contentElement"); + + try { + Zend_Xml_Security::scanFile($filename); + } catch (Zend_Xml_Exception $e) { + throw new Zend_Translate_Exception( + $e->getMessage() + ); + } + + if (!xml_parse($this->_file, file_get_contents($filename))) { + $ex = sprintf('XML error: %s at line %d of file %s', + xml_error_string(xml_get_error_code($this->_file)), + xml_get_current_line_number($this->_file), + $filename); + xml_parser_free($this->_file); + throw new Zend_Translate_Exception($ex); + } + + return $this->_data; + } + + private function _startElement($file, $name, $attrib) + { + switch(strtolower($name)) { + case 'message': + $this->_source = null; + $this->_stag = false; + $this->_ttag = false; + $this->_scontent = null; + $this->_tcontent = null; + break; + case 'source': + $this->_stag = true; + break; + case 'translation': + $this->_ttag = true; + break; + default: + break; + } + } + + private function _endElement($file, $name) + { + switch (strtolower($name)) { + case 'source': + $this->_stag = false; + break; + + case 'translation': + if (!empty($this->_scontent) and !empty($this->_tcontent) or + (isset($this->_data[$this->_target][$this->_scontent]) === false)) { + $this->_data[$this->_target][$this->_scontent] = $this->_tcontent; + } + $this->_ttag = false; + break; + + default: + break; + } + } + + private function _contentElement($file, $data) + { + if ($this->_stag === true) { + $this->_scontent .= $data; + } + + if ($this->_ttag === true) { + $this->_tcontent .= $data; + } + } + + private function _findEncoding($filename) + { + $file = file_get_contents($filename, null, null, 0, 100); + if (strpos($file, "encoding") !== false) { + $encoding = substr($file, strpos($file, "encoding") + 9); + $encoding = substr($encoding, 1, strpos($encoding, $encoding[0], 1) - 1); + return $encoding; + } + return 'UTF-8'; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return "Qt"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Tbx.php b/library/vendor/Zend/Translate/Adapter/Tbx.php new file mode 100644 index 000000000..b69bcd1a5 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Tbx.php @@ -0,0 +1,173 @@ +_data = array(); + if (!is_readable($filename)) { + throw new Zend_Translate_Exception('Translation file \'' . $filename . '\' is not readable.'); + } + + $encoding = $this->_findEncoding($filename); + $this->_file = xml_parser_create($encoding); + xml_set_object($this->_file, $this); + xml_parser_set_option($this->_file, XML_OPTION_CASE_FOLDING, 0); + xml_set_element_handler($this->_file, "_startElement", "_endElement"); + xml_set_character_data_handler($this->_file, "_contentElement"); + + try { + Zend_Xml_Security::scanFile($filename); + } catch (Zend_Xml_Exception $e) { + throw new Zend_Translate_Exception( + $e->getMessage() + ); + } + + if (!xml_parse($this->_file, file_get_contents($filename))) { + $ex = sprintf('XML error: %s at line %d of file %s', + xml_error_string(xml_get_error_code($this->_file)), + xml_get_current_line_number($this->_file), + $filename); + xml_parser_free($this->_file); + throw new Zend_Translate_Exception($ex); + } + + return $this->_data; + } + + private function _startElement($file, $name, $attrib) + { + if ($this->_term !== null) { + $this->_content .= "<".$name; + foreach($attrib as $key => $value) { + $this->_content .= " $key=\"$value\""; + } + $this->_content .= ">"; + } else { + switch(strtolower($name)) { + case 'termentry': + $this->_termentry = null; + break; + case 'langset': + if (isset($attrib['xml:lang']) === true) { + $this->_langset = $attrib['xml:lang']; + if (isset($this->_data[$this->_langset]) === false) { + $this->_data[$this->_langset] = array(); + } + } + break; + case 'term': + $this->_term = true; + $this->_content = null; + break; + default: + break; + } + } + } + + private function _endElement($file, $name) + { + if (($this->_term !== null) and ($name != "term")) { + $this->_content .= ""; + } else { + switch (strtolower($name)) { + case 'langset': + $this->_langset = null; + break; + case 'term': + $this->_term = null; + if (empty($this->_termentry)) { + $this->_termentry = $this->_content; + } + if (!empty($this->_content) or (isset($this->_data[$this->_langset][$this->_termentry]) === false)) { + $this->_data[$this->_langset][$this->_termentry] = $this->_content; + } + break; + default: + break; + } + } + } + + private function _contentElement($file, $data) + { + if ($this->_term !== null) { + $this->_content .= $data; + } + } + + private function _findEncoding($filename) + { + $file = file_get_contents($filename, null, null, 0, 100); + if (strpos($file, "encoding") !== false) { + $encoding = substr($file, strpos($file, "encoding") + 9); + $encoding = substr($encoding, 1, strpos($encoding, $encoding[0], 1) - 1); + return $encoding; + } + return 'UTF-8'; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return "Tbx"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Tmx.php b/library/vendor/Zend/Translate/Adapter/Tmx.php new file mode 100644 index 000000000..4bb2d61f5 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Tmx.php @@ -0,0 +1,241 @@ +_data = array(); + if (!is_readable($filename)) { + throw new Zend_Translate_Exception('Translation file \'' . $filename . '\' is not readable.'); + } + + if (isset($options['useId'])) { + $this->_useId = (boolean) $options['useId']; + } + + $encoding = $this->_findEncoding($filename); + $this->_file = xml_parser_create($encoding); + xml_set_object($this->_file, $this); + xml_parser_set_option($this->_file, XML_OPTION_CASE_FOLDING, 0); + xml_set_element_handler($this->_file, "_startElement", "_endElement"); + xml_set_character_data_handler($this->_file, "_contentElement"); + + try { + Zend_Xml_Security::scanFile($filename); + } catch (Zend_Xml_Exception $e) { + throw new Zend_Translate_Exception( + $e->getMessage() + ); + } + + if (!xml_parse($this->_file, file_get_contents($filename))) { + $ex = sprintf('XML error: %s at line %d of file %s', + xml_error_string(xml_get_error_code($this->_file)), + xml_get_current_line_number($this->_file), + $filename); + xml_parser_free($this->_file); + throw new Zend_Translate_Exception($ex); + } + + return $this->_data; + } + + /** + * Internal method, called by xml element handler at start + * + * @param resource $file File handler + * @param string $name Elements name + * @param array $attrib Attributes for this element + */ + protected function _startElement($file, $name, $attrib) + { + if ($this->_seg !== null) { + $this->_content .= "<".$name; + foreach($attrib as $key => $value) { + $this->_content .= " $key=\"$value\""; + } + $this->_content .= ">"; + } else { + switch(strtolower($name)) { + case 'header': + if (empty($this->_useId) && isset($attrib['srclang'])) { + if (Zend_Locale::isLocale($attrib['srclang'])) { + $this->_srclang = Zend_Locale::findLocale($attrib['srclang']); + } else { + if (!$this->_options['disableNotices']) { + if ($this->_options['log']) { + $this->_options['log']->notice("The language '{$attrib['srclang']}' can not be set because it does not exist."); + } else { + trigger_error("The language '{$attrib['srclang']}' can not be set because it does not exist.", E_USER_NOTICE); + } + } + + $this->_srclang = $attrib['srclang']; + } + } + break; + case 'tu': + if (isset($attrib['tuid'])) { + $this->_tu = $attrib['tuid']; + } + break; + case 'tuv': + if (isset($attrib['xml:lang'])) { + if (Zend_Locale::isLocale($attrib['xml:lang'])) { + $this->_tuv = Zend_Locale::findLocale($attrib['xml:lang']); + } else { + if (!$this->_options['disableNotices']) { + if ($this->_options['log']) { + $this->_options['log']->notice("The language '{$attrib['xml:lang']}' can not be set because it does not exist."); + } else { + trigger_error("The language '{$attrib['xml:lang']}' can not be set because it does not exist.", E_USER_NOTICE); + } + } + + $this->_tuv = $attrib['xml:lang']; + } + + if (!isset($this->_data[$this->_tuv])) { + $this->_data[$this->_tuv] = array(); + } + } + break; + case 'seg': + $this->_seg = true; + $this->_content = null; + break; + default: + break; + } + } + } + + + /** + * Internal method, called by xml element handler at end + * + * @param resource $file File handler + * @param string $name Elements name + */ + protected function _endElement($file, $name) + { + if (($this->_seg !== null) and ($name !== 'seg')) { + $this->_content .= ""; + } else { + switch (strtolower($name)) { + case 'tu': + $this->_tu = null; + break; + case 'tuv': + $this->_tuv = null; + break; + case 'seg': + $this->_seg = null; + if (!empty($this->_srclang) && ($this->_srclang == $this->_tuv)) { + $this->_tu = $this->_content; + } + + if (!empty($this->_content) or (!isset($this->_data[$this->_tuv][$this->_tu]))) { + $this->_data[$this->_tuv][$this->_tu] = $this->_content; + } + break; + default: + break; + } + } + } + + /** + * Internal method, called by xml element handler for content + * + * @param resource $file File handler + * @param string $data Elements content + */ + protected function _contentElement($file, $data) + { + if (($this->_seg !== null) and ($this->_tu !== null) and ($this->_tuv !== null)) { + $this->_content .= $data; + } + } + + + /** + * Internal method, detects the encoding of the xml file + * + * @param string $name Filename + * @return string Encoding + */ + protected function _findEncoding($filename) + { + $file = file_get_contents($filename, null, null, 0, 100); + if (strpos($file, "encoding") !== false) { + $encoding = substr($file, strpos($file, "encoding") + 9); + $encoding = substr($encoding, 1, strpos($encoding, $encoding[0], 1) - 1); + return $encoding; + } + return 'UTF-8'; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return "Tmx"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/Xliff.php b/library/vendor/Zend/Translate/Adapter/Xliff.php new file mode 100644 index 000000000..1a5bbdd82 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/Xliff.php @@ -0,0 +1,237 @@ +_data = array(); + if (!is_readable($filename)) { + throw new Zend_Translate_Exception('Translation file \'' . $filename . '\' is not readable.'); + } + + if (empty($options['useId'])) { + $this->_useId = false; + } else { + $this->_useId = true; + } + + $encoding = $this->_findEncoding($filename); + $this->_target = $locale; + $this->_file = xml_parser_create($encoding); + xml_set_object($this->_file, $this); + xml_parser_set_option($this->_file, XML_OPTION_CASE_FOLDING, 0); + xml_set_element_handler($this->_file, "_startElement", "_endElement"); + xml_set_character_data_handler($this->_file, "_contentElement"); + + try { + Zend_Xml_Security::scanFile($filename); + } catch (Zend_Xml_Exception $e) { + throw new Zend_Translate_Exception( + $e->getMessage() + ); + } + + if (!xml_parse($this->_file, file_get_contents($filename))) { + $ex = sprintf('XML error: %s at line %d of file %s', + xml_error_string(xml_get_error_code($this->_file)), + xml_get_current_line_number($this->_file), + $filename); + xml_parser_free($this->_file); + throw new Zend_Translate_Exception($ex); + } + + return $this->_data; + } + + private function _startElement($file, $name, $attrib) + { + if ($this->_stag === true) { + $this->_scontent .= "<".$name; + foreach($attrib as $key => $value) { + $this->_scontent .= " $key=\"$value\""; + } + $this->_scontent .= ">"; + } else if ($this->_ttag === true) { + $this->_tcontent .= "<".$name; + foreach($attrib as $key => $value) { + $this->_tcontent .= " $key=\"$value\""; + } + $this->_tcontent .= ">"; + } else { + switch(strtolower($name)) { + case 'file': + $this->_source = $attrib['source-language']; + if (isset($attrib['target-language'])) { + $this->_target = $attrib['target-language']; + } + + if (!isset($this->_data[$this->_source])) { + $this->_data[$this->_source] = array(); + } + + if (!isset($this->_data[$this->_target])) { + $this->_data[$this->_target] = array(); + } + + break; + case 'trans-unit': + $this->_transunit = true; + $this->_langId = $attrib['id']; + break; + case 'source': + if ($this->_transunit === true) { + $this->_scontent = null; + $this->_stag = true; + $this->_ttag = false; + } + break; + case 'target': + if ($this->_transunit === true) { + $this->_tcontent = null; + $this->_ttag = true; + $this->_stag = false; + } + break; + default: + break; + } + } + } + + private function _endElement($file, $name) + { + if (($this->_stag === true) and ($name !== 'source')) { + $this->_scontent .= ""; + } else if (($this->_ttag === true) and ($name !== 'target')) { + $this->_tcontent .= ""; + } else { + switch (strtolower($name)) { + case 'trans-unit': + $this->_transunit = null; + $this->_langId = null; + $this->_scontent = null; + $this->_tcontent = null; + break; + case 'source': + if ($this->_useId) { + if (!empty($this->_scontent) && !empty($this->_langId) && + !isset($this->_data[$this->_source][$this->_langId])) { + $this->_data[$this->_source][$this->_langId] = $this->_scontent; + } + } else { + if (!empty($this->_scontent) && + !isset($this->_data[$this->_source][$this->_scontent])) { + $this->_data[$this->_source][$this->_scontent] = $this->_scontent; + } + } + $this->_stag = false; + break; + case 'target': + if ($this->_useId) { + if (!empty($this->_tcontent) && !empty($this->_langId) && + !isset($this->_data[$this->_target][$this->_langId])) { + $this->_data[$this->_target][$this->_langId] = $this->_tcontent; + } + } else { + if (!empty($this->_tcontent) && !empty($this->_scontent) && + !isset($this->_data[$this->_target][$this->_scontent])) { + $this->_data[$this->_target][$this->_scontent] = $this->_tcontent; + } + } + $this->_ttag = false; + break; + default: + break; + } + } + } + + private function _contentElement($file, $data) + { + if (($this->_transunit !== null) and ($this->_source !== null) and ($this->_stag === true)) { + $this->_scontent .= $data; + } + + if (($this->_transunit !== null) and ($this->_target !== null) and ($this->_ttag === true)) { + $this->_tcontent .= $data; + } + } + + private function _findEncoding($filename) + { + $file = file_get_contents($filename, null, null, 0, 100); + if (strpos($file, "encoding") !== false) { + $encoding = substr($file, strpos($file, "encoding") + 9); + $encoding = substr($encoding, 1, strpos($encoding, $encoding[0], 1) - 1); + return $encoding; + } + return 'UTF-8'; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return "Xliff"; + } +} diff --git a/library/vendor/Zend/Translate/Adapter/XmlTm.php b/library/vendor/Zend/Translate/Adapter/XmlTm.php new file mode 100644 index 000000000..0e9d6de72 --- /dev/null +++ b/library/vendor/Zend/Translate/Adapter/XmlTm.php @@ -0,0 +1,147 @@ +_data = array(); + $this->_lang = $locale; + if (!is_readable($filename)) { + throw new Zend_Translate_Exception('Translation file \'' . $filename . '\' is not readable.'); + } + + $encoding = $this->_findEncoding($filename); + $this->_file = xml_parser_create($encoding); + xml_set_object($this->_file, $this); + xml_parser_set_option($this->_file, XML_OPTION_CASE_FOLDING, 0); + xml_set_element_handler($this->_file, "_startElement", "_endElement"); + xml_set_character_data_handler($this->_file, "_contentElement"); + + try { + Zend_Xml_Security::scanFile($filename); + } catch (Zend_Xml_Exception $e) { + throw new Zend_Translate_Exception( + $e->getMessage() + ); + } + + if (!xml_parse($this->_file, file_get_contents($filename))) { + $ex = sprintf('XML error: %s at line %d of file %s', + xml_error_string(xml_get_error_code($this->_file)), + xml_get_current_line_number($this->_file), + $filename); + xml_parser_free($this->_file); + throw new Zend_Translate_Exception($ex); + } + + return $this->_data; + } + + private function _startElement($file, $name, $attrib) + { + switch(strtolower($name)) { + case 'tm:tu': + $this->_tag = $attrib['id']; + $this->_content = null; + break; + default: + break; + } + } + + private function _endElement($file, $name) + { + switch (strtolower($name)) { + case 'tm:tu': + if (!empty($this->_tag) and !empty($this->_content) or + (isset($this->_data[$this->_lang][$this->_tag]) === false)) { + $this->_data[$this->_lang][$this->_tag] = $this->_content; + } + $this->_tag = null; + $this->_content = null; + break; + + default: + break; + } + } + + private function _contentElement($file, $data) + { + if (($this->_tag !== null)) { + $this->_content .= $data; + } + } + + private function _findEncoding($filename) + { + $file = file_get_contents($filename, null, null, 0, 100); + if (strpos($file, "encoding") !== false) { + $encoding = substr($file, strpos($file, "encoding") + 9); + $encoding = substr($encoding, 1, strpos($encoding, $encoding[0], 1) - 1); + return $encoding; + } + return 'UTF-8'; + } + + /** + * Returns the adapter name + * + * @return string + */ + public function toString() + { + return "XmlTm"; + } +} diff --git a/library/vendor/Zend/Translate/Exception.php b/library/vendor/Zend/Translate/Exception.php new file mode 100644 index 000000000..396a94cf7 --- /dev/null +++ b/library/vendor/Zend/Translate/Exception.php @@ -0,0 +1,36 @@ + 3) { + $locale = substr($locale, 0, -strlen(strrchr($locale, '_'))); + } + + if (isset(self::$_plural[$locale])) { + $return = call_user_func(self::$_plural[$locale], $number); + + if (!is_int($return) || ($return < 0)) { + $return = 0; + } + + return $return; + } + + switch($locale) { + case 'bo': + case 'dz': + case 'id': + case 'ja': + case 'jv': + case 'ka': + case 'km': + case 'kn': + case 'ko': + case 'ms': + case 'th': + case 'tr': + case 'vi': + case 'zh': + return 0; + break; + + case 'af': + case 'az': + case 'bn': + case 'bg': + case 'ca': + case 'da': + case 'de': + case 'el': + case 'en': + case 'eo': + case 'es': + case 'et': + case 'eu': + case 'fa': + case 'fi': + case 'fo': + case 'fur': + case 'fy': + case 'gl': + case 'gu': + case 'ha': + case 'he': + case 'hu': + case 'is': + case 'it': + case 'ku': + case 'lb': + case 'ml': + case 'mn': + case 'mr': + case 'nah': + case 'nb': + case 'ne': + case 'nl': + case 'nn': + case 'no': + case 'om': + case 'or': + case 'pa': + case 'pap': + case 'ps': + case 'pt': + case 'so': + case 'sq': + case 'sv': + case 'sw': + case 'ta': + case 'te': + case 'tk': + case 'ur': + case 'zu': + return ($number == 1) ? 0 : 1; + + case 'am': + case 'bh': + case 'fil': + case 'fr': + case 'gun': + case 'hi': + case 'ln': + case 'mg': + case 'nso': + case 'xbr': + case 'ti': + case 'wa': + return (($number == 0) || ($number == 1)) ? 0 : 1; + + case 'be': + case 'bs': + case 'hr': + case 'ru': + case 'sr': + case 'uk': + return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); + + case 'cs': + case 'sk': + return ($number == 1) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); + + case 'ga': + return ($number == 1) ? 0 : (($number == 2) ? 1 : 2); + + case 'lt': + return (($number % 10 == 1) && ($number % 100 != 11)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); + + case 'sl': + return ($number % 100 == 1) ? 0 : (($number % 100 == 2) ? 1 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 2 : 3)); + + case 'mk': + return ($number % 10 == 1) ? 0 : 1; + + case 'mt': + return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); + + case 'lv': + return ($number == 0) ? 0 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2); + + case 'pl': + return ($number == 1) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); + + case 'cy': + return ($number == 1) ? 0 : (($number == 2) ? 1 : ((($number == 8) || ($number == 11)) ? 2 : 3)); + + case 'ro': + return ($number == 1) ? 0 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); + + case 'ar': + return ($number == 0) ? 0 : (($number == 1) ? 1 : (($number == 2) ? 2 : ((($number >= 3) && ($number <= 10)) ? 3 : ((($number >= 11) && ($number <= 99)) ? 4 : 5)))); + + default: + return 0; + } + } + + /** + * Set's a new plural rule + * + * @param string $rule Callback which acts as rule + * @param string $locale Locale which is used for this callback + * @return null + */ + public static function setPlural($rule, $locale) + { + if ($locale == "pt_BR") { + // temporary set a locale for brasilian + $locale = "xbr"; + } + + if (strlen($locale) > 3) { + $locale = substr($locale, 0, -strlen(strrchr($locale, '_'))); + } + + if (!is_callable($rule)) { + throw new Zend_Translate_Exception('The given rule can not be called'); + } + + self::$_plural[$locale] = $rule; + } +} diff --git a/library/vendor/Zend/Uri.php b/library/vendor/Zend/Uri.php new file mode 100644 index 000000000..3bcd9c5d8 --- /dev/null +++ b/library/vendor/Zend/Uri.php @@ -0,0 +1,201 @@ + false + ); + + /** + * Return a string representation of this URI. + * + * @see getUri() + * @return string + */ + public function __toString() + { + try { + return $this->getUri(); + } catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + return ''; + } + } + + /** + * Convenience function, checks that a $uri string is well-formed + * by validating it but not returning an object. Returns TRUE if + * $uri is a well-formed URI, or FALSE otherwise. + * + * @param string $uri The URI to check + * @return boolean + */ + public static function check($uri) + { + try { + $uri = self::factory($uri); + } catch (Exception $e) { + return false; + } + + return $uri->valid(); + } + + /** + * Create a new Zend_Uri object for a URI. If building a new URI, then $uri should contain + * only the scheme (http, ftp, etc). Otherwise, supply $uri with the complete URI. + * + * @param string $uri The URI form which a Zend_Uri instance is created + * @param string $className The name of the class to use in order to manipulate URI + * @throws Zend_Uri_Exception When an empty string was supplied for the scheme + * @throws Zend_Uri_Exception When an illegal scheme is supplied + * @throws Zend_Uri_Exception When the scheme is not supported + * @throws Zend_Uri_Exception When $className doesn't exist or doesn't implements Zend_Uri + * @return Zend_Uri + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public static function factory($uri = 'http', $className = null) + { + // Separate the scheme from the scheme-specific parts + $uri = explode(':', $uri, 2); + $scheme = strtolower($uri[0]); + $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; + + if (strlen($scheme) === 0) { + throw new Zend_Uri_Exception('An empty string was supplied for the scheme'); + } + + // Security check: $scheme is used to load a class file, so only alphanumerics are allowed. + if (ctype_alnum($scheme) === false) { + throw new Zend_Uri_Exception('Illegal scheme supplied, only alphanumeric characters are permitted'); + } + + if ($className === null) { + /** + * Create a new Zend_Uri object for the $uri. If a subclass of Zend_Uri exists for the + * scheme, return an instance of that class. Otherwise, a Zend_Uri_Exception is thrown. + */ + switch ($scheme) { + case 'http': + // Break intentionally omitted + case 'https': + $className = 'Zend_Uri_Http'; + break; + + case 'mailto': + // TODO + default: + throw new Zend_Uri_Exception("Scheme \"$scheme\" is not supported"); + break; + } + } + + try { + Zend_Loader::loadClass($className); + } catch (Exception $e) { + throw new Zend_Uri_Exception("\"$className\" not found"); + } + + $schemeHandler = new $className($scheme, $schemeSpecific); + + if (! $schemeHandler instanceof Zend_Uri) { + throw new Zend_Uri_Exception("\"$className\" is not an instance of Zend_Uri"); + } + + return $schemeHandler; + } + + /** + * Get the URI's scheme + * + * @return string|false Scheme or false if no scheme is set. + */ + public function getScheme() + { + if (empty($this->_scheme) === false) { + return $this->_scheme; + } else { + return false; + } + } + + /** + * Set global configuration options + * + * @param Zend_Config|array $config + */ + static public function setConfig($config) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + } elseif (!is_array($config)) { + throw new Zend_Uri_Exception("Config must be an array or an instance of Zend_Config."); + } + + foreach ($config as $k => $v) { + self::$_config[$k] = $v; + } + } + + /** + * Zend_Uri and its subclasses cannot be instantiated directly. + * Use Zend_Uri::factory() to return a new Zend_Uri object. + * + * @param string $scheme The scheme of the URI + * @param string $schemeSpecific The scheme-specific part of the URI + */ + abstract protected function __construct($scheme, $schemeSpecific = ''); + + /** + * Return a string representation of this URI. + * + * @return string + */ + abstract public function getUri(); + + /** + * Returns TRUE if this URI is valid, or FALSE otherwise. + * + * @return boolean + */ + abstract public function valid(); +} diff --git a/library/vendor/Zend/Uri/Exception.php b/library/vendor/Zend/Uri/Exception.php new file mode 100644 index 000000000..58ef6d1d6 --- /dev/null +++ b/library/vendor/Zend/Uri/Exception.php @@ -0,0 +1,36 @@ +_scheme = $scheme; + + // Set up grammar rules for validation via regular expressions. These + // are to be used with slash-delimited regular expression strings. + + // Escaped special characters (eg. '%25' for '%') + $this->_regex['escaped'] = '%[[:xdigit:]]{2}'; + + // Unreserved characters + $this->_regex['unreserved'] = '[' . self::CHAR_ALNUM . self::CHAR_MARK . ']'; + + // Segment can use escaped, unreserved or a set of additional chars + $this->_regex['segment'] = '(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_SEGMENT . '])*'; + + // Path can be a series of segmets char strings seperated by '/' + $this->_regex['path'] = '(?:\/(?:' . $this->_regex['segment'] . ')?)+'; + + // URI characters can be escaped, alphanumeric, mark or reserved chars + $this->_regex['uric'] = '(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . self::CHAR_RESERVED . + + // If unwise chars are allowed, add them to the URI chars class + (self::$_config['allow_unwise'] ? self::CHAR_UNWISE : '') . '])'; + + // If no scheme-specific part was supplied, the user intends to create + // a new URI with this object. No further parsing is required. + if (strlen($schemeSpecific) === 0) { + return; + } + + // Parse the scheme-specific URI parts into the instance variables. + $this->_parseUri($schemeSpecific); + + // Validate the URI + if ($this->valid() === false) { + throw new Zend_Uri_Exception('Invalid URI supplied'); + } + } + + /** + * Creates a Zend_Uri_Http from the given string + * + * @param string $uri String to create URI from, must start with + * 'http://' or 'https://' + * @throws InvalidArgumentException When the given $uri is not a string or + * does not start with http:// or https:// + * @throws Zend_Uri_Exception When the given $uri is invalid + * @return Zend_Uri_Http + */ + public static function fromString($uri) + { + if (is_string($uri) === false) { + throw new Zend_Uri_Exception('$uri is not a string'); + } + + $uri = explode(':', $uri, 2); + $scheme = strtolower($uri[0]); + $schemeSpecific = isset($uri[1]) === true ? $uri[1] : ''; + + if (in_array($scheme, array('http', 'https')) === false) { + throw new Zend_Uri_Exception("Invalid scheme: '$scheme'"); + } + + $schemeHandler = new Zend_Uri_Http($scheme, $schemeSpecific); + return $schemeHandler; + } + + /** + * Parse the scheme-specific portion of the URI and place its parts into instance variables. + * + * @param string $schemeSpecific The scheme-specific portion to parse + * @throws Zend_Uri_Exception When scheme-specific decoposition fails + * @throws Zend_Uri_Exception When authority decomposition fails + * @return void + */ + protected function _parseUri($schemeSpecific) + { + // High-level decomposition parser + $pattern = '~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~'; + $status = @preg_match($pattern, $schemeSpecific, $matches); + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: scheme-specific decomposition failed'); + } + + // Failed decomposition; no further processing needed + if ($status === false) { + return; + } + + // Save URI components that need no further decomposition + $this->_path = isset($matches[4]) === true ? $matches[4] : ''; + $this->_query = isset($matches[6]) === true ? $matches[6] : ''; + $this->_fragment = isset($matches[8]) === true ? $matches[8] : ''; + + // Additional decomposition to get username, password, host, and port + $combo = isset($matches[3]) === true ? $matches[3] : ''; + $pattern = '~^(([^:@]*)(:([^@]*))?@)?((?(?=[[])[[][^]]+[]]|[^:]+))(:(.*))?$~'; + $status = @preg_match($pattern, $combo, $matches); + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: authority decomposition failed'); + } + + // Save remaining URI components + $this->_username = isset($matches[2]) === true ? $matches[2] : ''; + $this->_password = isset($matches[4]) === true ? $matches[4] : ''; + $this->_host = isset($matches[5]) === true + ? preg_replace('~^\[([^]]+)\]$~', '\1', $matches[5]) // Strip wrapper [] from IPv6 literal + : ''; + $this->_port = isset($matches[7]) === true ? $matches[7] : ''; + } + + /** + * Returns a URI based on current values of the instance variables. If any + * part of the URI does not pass validation, then an exception is thrown. + * + * @throws Zend_Uri_Exception When one or more parts of the URI are invalid + * @return string + */ + public function getUri() + { + if ($this->valid() === false) { + throw new Zend_Uri_Exception('One or more parts of the URI are invalid'); + } + + $password = strlen($this->_password) > 0 ? ":$this->_password" : ''; + $auth = strlen($this->_username) > 0 ? "$this->_username$password@" : ''; + $port = strlen($this->_port) > 0 ? ":$this->_port" : ''; + $query = strlen($this->_query) > 0 ? "?$this->_query" : ''; + $fragment = strlen($this->_fragment) > 0 ? "#$this->_fragment" : ''; + + return $this->_scheme + . '://' + . $auth + . $this->_host + . $port + . $this->_path + . $query + . $fragment; + } + + /** + * Validate the current URI from the instance variables. Returns true if and only if all + * parts pass validation. + * + * @return boolean + */ + public function valid() + { + // Return true if and only if all parts of the URI have passed validation + return $this->validateUsername() + and $this->validatePassword() + and $this->validateHost() + and $this->validatePort() + and $this->validatePath() + and $this->validateQuery() + and $this->validateFragment(); + } + + /** + * Returns the username portion of the URL, or FALSE if none. + * + * @return string + */ + public function getUsername() + { + return strlen($this->_username) > 0 ? $this->_username : false; + } + + /** + * Returns true if and only if the username passes validation. If no username is passed, + * then the username contained in the instance variable is used. + * + * @param string $username The HTTP username + * @throws Zend_Uri_Exception When username validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validateUsername($username = null) + { + if ($username === null) { + $username = $this->_username; + } + + // If the username is empty, then it is considered valid + if (strlen($username) === 0) { + return true; + } + + // Check the username against the allowed values + $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $username); + + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: username validation failed'); + } + + return $status === 1; + } + + /** + * Sets the username for the current URI, and returns the old username + * + * @param string $username The HTTP username + * @throws Zend_Uri_Exception When $username is not a valid HTTP username + * @return string + */ + public function setUsername($username) + { + if ($this->validateUsername($username) === false) { + throw new Zend_Uri_Exception("Username \"$username\" is not a valid HTTP username"); + } + + $oldUsername = $this->_username; + $this->_username = $username; + + return $oldUsername; + } + + /** + * Returns the password portion of the URL, or FALSE if none. + * + * @return string + */ + public function getPassword() + { + return strlen($this->_password) > 0 ? $this->_password : false; + } + + /** + * Returns true if and only if the password passes validation. If no password is passed, + * then the password contained in the instance variable is used. + * + * @param string $password The HTTP password + * @throws Zend_Uri_Exception When password validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validatePassword($password = null) + { + if ($password === null) { + $password = $this->_password; + } + + // If the password is empty, then it is considered valid + if (strlen($password) === 0) { + return true; + } + + // If the password is nonempty, but there is no username, then it is considered invalid + if (strlen($password) > 0 and strlen($this->_username) === 0) { + return false; + } + + // Check the password against the allowed values + $status = @preg_match('/^(?:' . $this->_regex['escaped'] . '|[' . + self::CHAR_ALNUM . self::CHAR_MARK . ';:&=+$,' . '])+$/', $password); + + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: password validation failed.'); + } + + return $status == 1; + } + + /** + * Sets the password for the current URI, and returns the old password + * + * @param string $password The HTTP password + * @throws Zend_Uri_Exception When $password is not a valid HTTP password + * @return string + */ + public function setPassword($password) + { + if ($this->validatePassword($password) === false) { + throw new Zend_Uri_Exception("Password \"$password\" is not a valid HTTP password."); + } + + $oldPassword = $this->_password; + $this->_password = $password; + + return $oldPassword; + } + + /** + * Returns the domain or host IP portion of the URL, or FALSE if none. + * + * @return string + */ + public function getHost() + { + return strlen($this->_host) > 0 ? $this->_host : false; + } + + /** + * Returns true if and only if the host string passes validation. If no host is passed, + * then the host contained in the instance variable is used. + * + * @param string $host The HTTP host + * @return boolean + * @uses Zend_Filter + */ + public function validateHost($host = null) + { + if ($host === null) { + $host = $this->_host; + } + + // If the host is empty, then it is considered invalid + if (strlen($host) === 0) { + return false; + } + + // Check the host against the allowed values; delegated to Zend_Filter. + $validate = new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL); + + return $validate->isValid($host); + } + + /** + * Sets the host for the current URI, and returns the old host + * + * @param string $host The HTTP host + * @throws Zend_Uri_Exception When $host is nota valid HTTP host + * @return string + */ + public function setHost($host) + { + if ($this->validateHost($host) === false) { + throw new Zend_Uri_Exception("Host \"$host\" is not a valid HTTP host"); + } + + $oldHost = $this->_host; + $this->_host = $host; + + return $oldHost; + } + + /** + * Returns the TCP port, or FALSE if none. + * + * @return string + */ + public function getPort() + { + return strlen($this->_port) > 0 ? $this->_port : false; + } + + /** + * Returns true if and only if the TCP port string passes validation. If no port is passed, + * then the port contained in the instance variable is used. + * + * @param string $port The HTTP port + * @return boolean + */ + public function validatePort($port = null) + { + if ($port === null) { + $port = $this->_port; + } + + // If the port is empty, then it is considered valid + if (strlen($port) === 0) { + return true; + } + + // Check the port against the allowed values + return ctype_digit((string) $port) and 1 <= $port and $port <= 65535; + } + + /** + * Sets the port for the current URI, and returns the old port + * + * @param string $port The HTTP port + * @throws Zend_Uri_Exception When $port is not a valid HTTP port + * @return string + */ + public function setPort($port) + { + if ($this->validatePort($port) === false) { + throw new Zend_Uri_Exception("Port \"$port\" is not a valid HTTP port."); + } + + $oldPort = $this->_port; + $this->_port = $port; + + return $oldPort; + } + + /** + * Returns the path and filename portion of the URL. + * + * @return string + */ + public function getPath() + { + return strlen($this->_path) > 0 ? $this->_path : '/'; + } + + /** + * Returns true if and only if the path string passes validation. If no path is passed, + * then the path contained in the instance variable is used. + * + * @param string $path The HTTP path + * @throws Zend_Uri_Exception When path validation fails + * @return boolean + */ + public function validatePath($path = null) + { + if ($path === null) { + $path = $this->_path; + } + + // If the path is empty, then it is considered valid + if (strlen($path) === 0) { + return true; + } + + // Determine whether the path is well-formed + $pattern = '/^' . $this->_regex['path'] . '$/'; + $status = @preg_match($pattern, $path); + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: path validation failed'); + } + + return (boolean) $status; + } + + /** + * Sets the path for the current URI, and returns the old path + * + * @param string $path The HTTP path + * @throws Zend_Uri_Exception When $path is not a valid HTTP path + * @return string + */ + public function setPath($path) + { + if ($this->validatePath($path) === false) { + throw new Zend_Uri_Exception("Path \"$path\" is not a valid HTTP path"); + } + + $oldPath = $this->_path; + $this->_path = $path; + + return $oldPath; + } + + /** + * Returns the query portion of the URL (after ?), or FALSE if none. + * + * @return string + */ + public function getQuery() + { + return strlen($this->_query) > 0 ? $this->_query : false; + } + + /** + * Returns the query portion of the URL (after ?) as a + * key-value-array. If the query is empty an empty array + * is returned + * + * @return array + */ + public function getQueryAsArray() + { + $query = $this->getQuery(); + $querryArray = array(); + if ($query !== false) { + parse_str($query, $querryArray); + } + return $querryArray; + } + + /** + * Returns true if and only if the query string passes validation. If no query is passed, + * then the query string contained in the instance variable is used. + * + * @param string $query The query to validate + * @throws Zend_Uri_Exception When query validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validateQuery($query = null) + { + if ($query === null) { + $query = $this->_query; + } + + // If query is empty, it is considered to be valid + if (strlen($query) === 0) { + return true; + } + + // Determine whether the query is well-formed + $pattern = '/^' . $this->_regex['uric'] . '*$/'; + $status = @preg_match($pattern, $query); + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: query validation failed'); + } + + return $status == 1; + } + + /** + * Add or replace params in the query string for the current URI, and + * return the old query. + * + * @param array $queryParams + * @return string Old query string + */ + public function addReplaceQueryParameters(array $queryParams) + { + $queryParams = array_merge($this->getQueryAsArray(), $queryParams); + return $this->setQuery($queryParams); + } + + /** + * Remove params in the query string for the current URI, and + * return the old query. + * + * @param array $queryParamKeys + * @return string Old query string + */ + public function removeQueryParameters(array $queryParamKeys) + { + $queryParams = array_diff_key($this->getQueryAsArray(), array_fill_keys($queryParamKeys, 0)); + return $this->setQuery($queryParams); + } + + /** + * Set the query string for the current URI, and return the old query + * string This method accepts both strings and arrays. + * + * @param string|array $query The query string or array + * @throws Zend_Uri_Exception When $query is not a valid query string + * @return string Old query string + */ + public function setQuery($query) + { + $oldQuery = $this->_query; + + // If query is empty, set an empty string + if (empty($query) === true) { + $this->_query = ''; + return $oldQuery; + } + + // If query is an array, make a string out of it + if (is_array($query) === true) { + $query = http_build_query($query, '', '&'); + } else { + // If it is a string, make sure it is valid. If not parse and encode it + $query = (string) $query; + if ($this->validateQuery($query) === false) { + parse_str($query, $queryArray); + $query = http_build_query($queryArray, '', '&'); + } + } + + // Make sure the query is valid, and set it + if ($this->validateQuery($query) === false) { + throw new Zend_Uri_Exception("'$query' is not a valid query string"); + } + + $this->_query = $query; + + return $oldQuery; + } + + /** + * Returns the fragment portion of the URL (after #), or FALSE if none. + * + * @return string|false + */ + public function getFragment() + { + return strlen($this->_fragment) > 0 ? $this->_fragment : false; + } + + /** + * Returns true if and only if the fragment passes validation. If no fragment is passed, + * then the fragment contained in the instance variable is used. + * + * @param string $fragment Fragment of an URI + * @throws Zend_Uri_Exception When fragment validation fails + * @return boolean + * @link http://www.faqs.org/rfcs/rfc2396.html + */ + public function validateFragment($fragment = null) + { + if ($fragment === null) { + $fragment = $this->_fragment; + } + + // If fragment is empty, it is considered to be valid + if (strlen($fragment) === 0) { + return true; + } + + // Determine whether the fragment is well-formed + $pattern = '/^' . $this->_regex['uric'] . '*$/'; + $status = @preg_match($pattern, $fragment); + if ($status === false) { + throw new Zend_Uri_Exception('Internal error: fragment validation failed'); + } + + return (boolean) $status; + } + + /** + * Sets the fragment for the current URI, and returns the old fragment + * + * @param string $fragment Fragment of the current URI + * @throws Zend_Uri_Exception When $fragment is not a valid HTTP fragment + * @return string + */ + public function setFragment($fragment) + { + if ($this->validateFragment($fragment) === false) { + throw new Zend_Uri_Exception("Fragment \"$fragment\" is not a valid HTTP fragment"); + } + + $oldFragment = $this->_fragment; + $this->_fragment = $fragment; + + return $oldFragment; + } +} diff --git a/library/vendor/Zend/Validate.php b/library/vendor/Zend/Validate.php new file mode 100644 index 000000000..ab2144cf2 --- /dev/null +++ b/library/vendor/Zend/Validate.php @@ -0,0 +1,283 @@ +_validators[] = array( + 'instance' => $validator, + 'breakChainOnFailure' => (boolean) $breakChainOnFailure + ); + return $this; + } + + /** + * Returns true if and only if $value passes all validations in the chain + * + * Validators are run in the order in which they were added to the chain (FIFO). + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + $this->_messages = array(); + $this->_errors = array(); + $result = true; + foreach ($this->_validators as $element) { + $validator = $element['instance']; + if ($validator->isValid($value)) { + continue; + } + $result = false; + $messages = $validator->getMessages(); + $this->_messages = array_merge($this->_messages, $messages); + $this->_errors = array_merge($this->_errors, array_keys($messages)); + if ($element['breakChainOnFailure']) { + break; + } + } + return $result; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns array of validation failure messages + * + * @return array + */ + public function getMessages() + { + return $this->_messages; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns array of validation failure message codes + * + * @return array + * @deprecated Since 1.5.0 + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Returns the set default namespaces + * + * @return array + */ + public static function getDefaultNamespaces() + { + return self::$_defaultNamespaces; + } + + /** + * Sets new default namespaces + * + * @param array|string $namespace + * @return null + */ + public static function setDefaultNamespaces($namespace) + { + if (!is_array($namespace)) { + $namespace = array((string) $namespace); + } + + self::$_defaultNamespaces = $namespace; + } + + /** + * Adds a new default namespace + * + * @param array|string $namespace + * @return null + */ + public static function addDefaultNamespaces($namespace) + { + if (!is_array($namespace)) { + $namespace = array((string) $namespace); + } + + self::$_defaultNamespaces = array_unique(array_merge(self::$_defaultNamespaces, $namespace)); + } + + /** + * Returns true when defaultNamespaces are set + * + * @return boolean + */ + public static function hasDefaultNamespaces() + { + return (!empty(self::$_defaultNamespaces)); + } + + /** + * @param mixed $value + * @param string $classBaseName + * @param array $args OPTIONAL + * @param mixed $namespaces OPTIONAL + * @return boolean + * @throws Zend_Validate_Exception + */ + public static function is($value, $classBaseName, array $args = array(), $namespaces = array()) + { + $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Validate')); + $className = ucfirst($classBaseName); + try { + if (!class_exists($className, false)) { + foreach($namespaces as $namespace) { + $class = $namespace . '_' . $className; + $file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; + if (Zend_Loader::isReadable($file)) { + Zend_Loader::loadClass($class); + $className = $class; + break; + } + } + } + + $class = new ReflectionClass($className); + if ($class->implementsInterface('Zend_Validate_Interface')) { + if ($class->hasMethod('__construct')) { + $keys = array_keys($args); + $numeric = false; + foreach($keys as $key) { + if (is_numeric($key)) { + $numeric = true; + break; + } + } + + if ($numeric) { + $object = $class->newInstanceArgs($args); + } else { + $object = $class->newInstance($args); + } + } else { + $object = $class->newInstance(); + } + + return $object->isValid($value); + } + } catch (Zend_Validate_Exception $ze) { + // if there is an exception while validating throw it + throw $ze; + } catch (Exception $e) { + // fallthrough and continue for missing validation classes + } + + throw new Zend_Validate_Exception("Validate class not found from basename '$classBaseName'"); + } + + /** + * Returns the maximum allowed message length + * + * @return integer + */ + public static function getMessageLength() + { + return Zend_Validate_Abstract::getMessageLength(); + } + + /** + * Sets the maximum allowed message length + * + * @param integer $length + */ + public static function setMessageLength($length = -1) + { + Zend_Validate_Abstract::setMessageLength($length); + } + + /** + * Returns the default translation object + * + * @return Zend_Translate_Adapter|null + */ + public static function getDefaultTranslator($translator = null) + { + return Zend_Validate_Abstract::getDefaultTranslator(); + } + + /** + * Sets a default translation object for all validation objects + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + */ + public static function setDefaultTranslator($translator = null) + { + Zend_Validate_Abstract::setDefaultTranslator($translator); + } +} diff --git a/library/vendor/Zend/Validate/Abstract.php b/library/vendor/Zend/Validate/Abstract.php new file mode 100644 index 000000000..fa9d24644 --- /dev/null +++ b/library/vendor/Zend/Validate/Abstract.php @@ -0,0 +1,476 @@ +_messages; + } + + /** + * Returns an array of the names of variables that are used in constructing validation failure messages + * + * @return array + */ + public function getMessageVariables() + { + return array_keys($this->_messageVariables); + } + + /** + * Returns the message templates from the validator + * + * @return array + */ + public function getMessageTemplates() + { + return $this->_messageTemplates; + } + + /** + * Sets the validation failure message template for a particular key + * + * @param string $messageString + * @param string $messageKey OPTIONAL + * @return Zend_Validate_Abstract Provides a fluent interface + * @throws Zend_Validate_Exception + */ + public function setMessage($messageString, $messageKey = null) + { + if ($messageKey === null) { + $keys = array_keys($this->_messageTemplates); + foreach($keys as $key) { + $this->setMessage($messageString, $key); + } + return $this; + } + + if (!isset($this->_messageTemplates[$messageKey])) { + throw new Zend_Validate_Exception("No message template exists for key '$messageKey'"); + } + + $this->_messageTemplates[$messageKey] = $messageString; + return $this; + } + + /** + * Sets validation failure message templates given as an array, where the array keys are the message keys, + * and the array values are the message template strings. + * + * @param array $messages + * @return Zend_Validate_Abstract + */ + public function setMessages(array $messages) + { + foreach ($messages as $key => $message) { + $this->setMessage($message, $key); + } + return $this; + } + + /** + * Magic function returns the value of the requested property, if and only if it is the value or a + * message variable. + * + * @param string $property + * @return mixed + * @throws Zend_Validate_Exception + */ + public function __get($property) + { + if ($property == 'value') { + return $this->_value; + } + if (array_key_exists($property, $this->_messageVariables)) { + return $this->{$this->_messageVariables[$property]}; + } + /** + * @see Zend_Validate_Exception + */ + throw new Zend_Validate_Exception("No property exists by the name '$property'"); + } + + /** + * Constructs and returns a validation failure message with the given message key and value. + * + * Returns null if and only if $messageKey does not correspond to an existing template. + * + * If a translator is available and a translation exists for $messageKey, + * the translation will be used. + * + * @param string $messageKey + * @param string $value + * @return string + */ + protected function _createMessage($messageKey, $value) + { + if (!isset($this->_messageTemplates[$messageKey])) { + return null; + } + + $message = $this->_messageTemplates[$messageKey]; + + if (null !== ($translator = $this->getTranslator())) { + if ($translator->isTranslated($messageKey)) { + $message = $translator->translate($messageKey); + } else { + $message = $translator->translate($message); + } + } + + if (is_object($value)) { + if (!in_array('__toString', get_class_methods($value))) { + $value = get_class($value) . ' object'; + } else { + $value = $value->__toString(); + } + } elseif (is_array($value)) { + $value = $this->_implodeRecursive($value); + } else { + $value = implode((array) $value); + } + + if ($this->getObscureValue()) { + $value = str_repeat('*', strlen($value)); + } + + $message = str_replace('%value%', $value, $message); + foreach ($this->_messageVariables as $ident => $property) { + $message = str_replace( + "%$ident%", + implode(' ', (array) $this->$property), + $message + ); + } + + $length = self::getMessageLength(); + if (($length > -1) && (strlen($message) > $length)) { + $message = substr($message, 0, (self::getMessageLength() - 3)) . '...'; + } + + return $message; + } + + /** + * Joins elements of a multidimensional array + * + * @param array $pieces + * @return string + */ + protected function _implodeRecursive(array $pieces) + { + $values = array(); + foreach ($pieces as $item) { + if (is_array($item)) { + $values[] = $this->_implodeRecursive($item); + } else { + $values[] = $item; + } + } + + return implode(', ', $values); + } + + /** + * @param string $messageKey + * @param string $value OPTIONAL + * @return void + */ + protected function _error($messageKey, $value = null) + { + if ($messageKey === null) { + $keys = array_keys($this->_messageTemplates); + $messageKey = current($keys); + } + if ($value === null) { + $value = $this->_value; + } + $this->_errors[] = $messageKey; + $this->_messages[$messageKey] = $this->_createMessage($messageKey, $value); + } + + /** + * Sets the value to be validated and clears the messages and errors arrays + * + * @param mixed $value + * @return void + */ + protected function _setValue($value) + { + $this->_value = $value; + $this->_messages = array(); + $this->_errors = array(); + } + + /** + * Returns array of validation failure message codes + * + * @return array + * @deprecated Since 1.5.0 + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Set flag indicating whether or not value should be obfuscated in messages + * + * @param bool $flag + * @return Zend_Validate_Abstract + */ + public function setObscureValue($flag) + { + $this->_obscureValue = (bool) $flag; + return $this; + } + + /** + * Retrieve flag indicating whether or not value should be obfuscated in + * messages + * + * @return bool + */ + public function getObscureValue() + { + return $this->_obscureValue; + } + + /** + * Set translation object + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return Zend_Validate_Abstract + */ + public function setTranslator($translator = null) + { + if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + throw new Zend_Validate_Exception('Invalid translator specified'); + } + return $this; + } + + /** + * Return translation object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->translatorIsDisabled()) { + return null; + } + + if (null === $this->_translator) { + return self::getDefaultTranslator(); + } + + return $this->_translator; + } + + /** + * Does this validator have its own specific translator? + * + * @return bool + */ + public function hasTranslator() + { + return (bool)$this->_translator; + } + + /** + * Set default translation object for all validate objects + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return void + */ + public static function setDefaultTranslator($translator = null) + { + if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) { + self::$_defaultTranslator = $translator; + } elseif ($translator instanceof Zend_Translate) { + self::$_defaultTranslator = $translator->getAdapter(); + } else { + throw new Zend_Validate_Exception('Invalid translator specified'); + } + } + + /** + * Get default translation object for all validate objects + * + * @return Zend_Translate_Adapter|null + */ + public static function getDefaultTranslator() + { + if (null === self::$_defaultTranslator) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $translator = Zend_Registry::get('Zend_Translate'); + if ($translator instanceof Zend_Translate_Adapter) { + return $translator; + } elseif ($translator instanceof Zend_Translate) { + return $translator->getAdapter(); + } + } + } + + return self::$_defaultTranslator; + } + + /** + * Is there a default translation object set? + * + * @return boolean + */ + public static function hasDefaultTranslator() + { + return (bool)self::$_defaultTranslator; + } + + /** + * Indicate whether or not translation should be disabled + * + * @param bool $flag + * @return Zend_Validate_Abstract + */ + public function setDisableTranslator($flag) + { + $this->_translatorDisabled = (bool) $flag; + return $this; + } + + /** + * Is translation disabled? + * + * @return bool + */ + public function translatorIsDisabled() + { + return $this->_translatorDisabled; + } + + /** + * Returns the maximum allowed message length + * + * @return integer + */ + public static function getMessageLength() + { + return self::$_messageLength; + } + + /** + * Sets the maximum allowed message length + * + * @param integer $length + */ + public static function setMessageLength($length = -1) + { + self::$_messageLength = $length; + } +} diff --git a/library/vendor/Zend/Validate/Alnum.php b/library/vendor/Zend/Validate/Alnum.php new file mode 100644 index 000000000..c01dca634 --- /dev/null +++ b/library/vendor/Zend/Validate/Alnum.php @@ -0,0 +1,148 @@ + "Invalid type given. String, integer or float expected", + self::NOT_ALNUM => "'%value%' contains characters which are non alphabetic and no digits", + self::STRING_EMPTY => "'%value%' is an empty string", + ); + + /** + * Sets default option values for this instance + * + * @param boolean|Zend_Config $allowWhiteSpace + * @return void + */ + public function __construct($allowWhiteSpace = false) + { + if ($allowWhiteSpace instanceof Zend_Config) { + $allowWhiteSpace = $allowWhiteSpace->toArray(); + } + + if (is_array($allowWhiteSpace)) { + if (array_key_exists('allowWhiteSpace', $allowWhiteSpace)) { + $allowWhiteSpace = $allowWhiteSpace['allowWhiteSpace']; + } else { + $allowWhiteSpace = false; + } + } + + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + } + + /** + * Returns the allowWhiteSpace option + * + * @return boolean + */ + public function getAllowWhiteSpace() + { + return $this->allowWhiteSpace; + } + + /** + * Sets the allowWhiteSpace option + * + * @param boolean $allowWhiteSpace + * @return Zend_Filter_Alnum Provides a fluent interface + */ + public function setAllowWhiteSpace($allowWhiteSpace) + { + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value contains only alphabetic and digit characters + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + + if ('' === $value) { + $this->_error(self::STRING_EMPTY); + return false; + } + + if (null === self::$_filter) { + /** + * @see Zend_Filter_Alnum + */ + self::$_filter = new Zend_Filter_Alnum(); + } + + self::$_filter->allowWhiteSpace = $this->allowWhiteSpace; + + if ($value != self::$_filter->filter($value)) { + $this->_error(self::NOT_ALNUM); + return false; + } + + return true; + } + +} diff --git a/library/vendor/Zend/Validate/Alpha.php b/library/vendor/Zend/Validate/Alpha.php new file mode 100644 index 000000000..c4a7ea617 --- /dev/null +++ b/library/vendor/Zend/Validate/Alpha.php @@ -0,0 +1,148 @@ + "Invalid type given. String expected", + self::NOT_ALPHA => "'%value%' contains non alphabetic characters", + self::STRING_EMPTY => "'%value%' is an empty string" + ); + + /** + * Sets default option values for this instance + * + * @param boolean|Zend_Config $allowWhiteSpace + * @return void + */ + public function __construct($allowWhiteSpace = false) + { + if ($allowWhiteSpace instanceof Zend_Config) { + $allowWhiteSpace = $allowWhiteSpace->toArray(); + } + + if (is_array($allowWhiteSpace)) { + if (array_key_exists('allowWhiteSpace', $allowWhiteSpace)) { + $allowWhiteSpace = $allowWhiteSpace['allowWhiteSpace']; + } else { + $allowWhiteSpace = false; + } + } + + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + } + + /** + * Returns the allowWhiteSpace option + * + * @return boolean + */ + public function getAllowWhiteSpace() + { + return $this->allowWhiteSpace; + } + + /** + * Sets the allowWhiteSpace option + * + * @param boolean $allowWhiteSpace + * @return Zend_Filter_Alpha Provides a fluent interface + */ + public function setAllowWhiteSpace($allowWhiteSpace) + { + $this->allowWhiteSpace = (boolean) $allowWhiteSpace; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value contains only alphabetic characters + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + + if ('' === $value) { + $this->_error(self::STRING_EMPTY); + return false; + } + + if (null === self::$_filter) { + /** + * @see Zend_Filter_Alpha + */ + self::$_filter = new Zend_Filter_Alpha(); + } + + self::$_filter->allowWhiteSpace = $this->allowWhiteSpace; + + if ($value !== self::$_filter->filter($value)) { + $this->_error(self::NOT_ALPHA); + return false; + } + + return true; + } + +} diff --git a/library/vendor/Zend/Validate/Barcode.php b/library/vendor/Zend/Validate/Barcode.php new file mode 100644 index 000000000..4e7a9f39a --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode.php @@ -0,0 +1,223 @@ + "'%value%' failed checksum validation", + self::INVALID_CHARS => "'%value%' contains invalid characters", + self::INVALID_LENGTH => "'%value%' should have a length of %length% characters", + self::INVALID => "Invalid type given. String expected", + ); + + /** + * Additional variables available for validation failure messages + * + * @var array + */ + protected $_messageVariables = array( + 'length' => '_length' + ); + + /** + * Length for the set subtype + * + * @var integer + */ + protected $_length; + + /** + * Barcode adapter + * + * @var Zend_Validate_Barcode_BarcodeAdapter + */ + protected $_adapter; + + /** + * Generates the standard validator object + * + * @param string|Zend_Config| + * Zend_Validate_Barcode_BarcodeAdapter $adapter Barcode adapter to use + * @return void + * @throws Zend_Validate_Exception + */ + public function __construct($adapter) + { + if ($adapter instanceof Zend_Config) { + $adapter = $adapter->toArray(); + } + + $options = null; + $checksum = null; + if (is_array($adapter)) { + if (array_key_exists('options', $adapter)) { + $options = $adapter['options']; + } + + if (array_key_exists('checksum', $adapter)) { + $checksum = $adapter['checksum']; + } + + if (array_key_exists('adapter', $adapter)) { + $adapter = $adapter['adapter']; + } else { + throw new Zend_Validate_Exception("Missing option 'adapter'"); + } + } + + $this->setAdapter($adapter, $options); + if ($checksum !== null) { + $this->setChecksum($checksum); + } + } + + /** + * Returns the set adapter + * + * @return Zend_Validate_Barcode_BarcodeAdapter + */ + public function getAdapter() + { + return $this->_adapter; + } + + /** + * Sets a new barcode adapter + * + * @param string|Zend_Validate_Barcode $adapter Barcode adapter to use + * @param array $options Options for this adapter + * @return void + * @throws Zend_Validate_Exception + */ + public function setAdapter($adapter, $options = null) + { + $adapter = ucfirst(strtolower($adapter)); + if (Zend_Loader::isReadable('Zend/Validate/Barcode/' . $adapter. '.php')) { + $adapter = 'Zend_Validate_Barcode_' . $adapter; + } + + if (!class_exists($adapter)) { + Zend_Loader::loadClass($adapter); + } + + $this->_adapter = new $adapter($options); + if (!$this->_adapter instanceof Zend_Validate_Barcode_AdapterInterface) { + throw new Zend_Validate_Exception( + "Adapter " . $adapter . " does not implement Zend_Validate_Barcode_AdapterInterface" + ); + } + + return $this; + } + + /** + * Returns the checksum option + * + * @return boolean + */ + public function getChecksum() + { + return $this->getAdapter()->getCheck(); + } + + /** + * Sets the checksum option + * + * @param boolean $checksum + * @return Zend_Validate_Barcode + */ + public function setChecksum($checksum) + { + $this->getAdapter()->setCheck($checksum); + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value contains a valid barcode + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + $adapter = $this->getAdapter(); + $this->_length = $adapter->getLength(); + $result = $adapter->checkLength($value); + if (!$result) { + if (is_array($this->_length)) { + $temp = $this->_length; + $this->_length = ""; + foreach($temp as $length) { + $this->_length .= "/"; + $this->_length .= $length; + } + + $this->_length = substr($this->_length, 1); + } + + $this->_error(self::INVALID_LENGTH); + return false; + } + + $result = $adapter->checkChars($value); + if (!$result) { + $this->_error(self::INVALID_CHARS); + return false; + } + + if ($this->getChecksum()) { + $result = $adapter->checksum($value); + if (!$result) { + $this->_error(self::FAILED); + return false; + } + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Barcode/AdapterAbstract.php b/library/vendor/Zend/Validate/Barcode/AdapterAbstract.php new file mode 100644 index 000000000..7bdea8e18 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/AdapterAbstract.php @@ -0,0 +1,314 @@ +getLength(); + if (is_array($length)) { + foreach ($length as $value) { + if ($fixum == $value) { + $found = true; + } + + if ($value == -1) { + $found = true; + } + } + } elseif ($fixum == $length) { + $found = true; + } elseif ($length == -1) { + $found = true; + } elseif ($length == 'even') { + $count = $fixum % 2; + $found = ($count == 0) ? true : false; + } elseif ($length == 'odd') { + $count = $fixum % 2; + $found = ($count == 1) ? true : false; + } + + return $found; + } + + /** + * Checks for allowed characters within the barcode + * + * @param string $value The barcode to check for allowed characters + * @return boolean + */ + public function checkChars($value) + { + if (!is_string($value)) { + return false; + } + + $characters = $this->getCharacters(); + if ($characters == 128) { + for ($x = 0; $x < 128; ++$x) { + $value = str_replace(chr($x), '', $value); + } + } else { + $chars = str_split($characters); + foreach ($chars as $char) { + $value = str_replace($char, '', $value); + } + } + + if (strlen($value) > 0) { + return false; + } + + return true; + } + + /** + * Validates the checksum + * + * @param string $value The barcode to check the checksum for + * @return boolean + */ + public function checksum($value) + { + $checksum = $this->getChecksum(); + if (!empty($checksum)) { + if (method_exists($this, $checksum)) { + return call_user_func(array($this, $checksum), $value); + } + } + + return false; + } + + /** + * Returns the allowed barcode length + * + * @return string + */ + public function getLength() + { + return $this->_length; + } + + /** + * Returns the allowed characters + * + * @return integer|string + */ + public function getCharacters() + { + return $this->_characters; + } + + /** + * Returns the checksum function name + * + */ + public function getChecksum() + { + return $this->_checksum; + } + + /** + * Returns if barcode uses checksum + * + * @return boolean + */ + public function getCheck() + { + return $this->_hasChecksum; + } + + /** + * Sets the checksum validation + * + * @param boolean $check + * @return Zend_Validate_Barcode_AdapterAbstract + */ + public function setCheck($check) + { + $this->_hasChecksum = (boolean) $check; + return $this; + } + + /** + * Validates the checksum (Modulo 10) + * GTIN implementation factor 3 + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _gtin($value) + { + $barcode = substr($value, 0, -1); + $sum = 0; + $length = strlen($barcode) - 1; + + for ($i = 0; $i <= $length; $i++) { + if (($i % 2) === 0) { + $sum += $barcode[$length - $i] * 3; + } else { + $sum += $barcode[$length - $i]; + } + } + + $calc = $sum % 10; + $checksum = ($calc === 0) ? 0 : (10 - $calc); + if ($value[$length + 1] != $checksum) { + return false; + } + + return true; + } + + /** + * Validates the checksum (Modulo 10) + * IDENTCODE implementation factors 9 and 4 + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _identcode($value) + { + $barcode = substr($value, 0, -1); + $sum = 0; + $length = strlen($value) - 2; + + for ($i = 0; $i <= $length; $i++) { + if (($i % 2) === 0) { + $sum += $barcode[$length - $i] * 4; + } else { + $sum += $barcode[$length - $i] * 9; + } + } + + $calc = $sum % 10; + $checksum = ($calc === 0) ? 0 : (10 - $calc); + if ($value[$length + 1] != $checksum) { + return false; + } + + return true; + } + + /** + * Validates the checksum (Modulo 10) + * CODE25 implementation factor 3 + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _code25($value) + { + $barcode = substr($value, 0, -1); + $sum = 0; + $length = strlen($barcode) - 1; + + for ($i = 0; $i <= $length; $i++) { + if (($i % 2) === 0) { + $sum += $barcode[$i] * 3; + } else { + $sum += $barcode[$i]; + } + } + + $calc = $sum % 10; + $checksum = ($calc === 0) ? 0 : (10 - $calc); + if ($value[$length + 1] != $checksum) { + return false; + } + + return true; + } + + /** + * Validates the checksum () + * POSTNET implementation + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _postnet($value) + { + $checksum = substr($value, -1, 1); + $values = str_split(substr($value, 0, -1)); + + $check = 0; + foreach($values as $row) { + $check += $row; + } + + $check %= 10; + $check = 10 - $check; + if ($check == $checksum) { + return true; + } + + return false; + } +} diff --git a/library/vendor/Zend/Validate/Barcode/AdapterInterface.php b/library/vendor/Zend/Validate/Barcode/AdapterInterface.php new file mode 100644 index 000000000..4531aefc8 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/AdapterInterface.php @@ -0,0 +1,68 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Code25interleaved.php b/library/vendor/Zend/Validate/Barcode/Code25interleaved.php new file mode 100644 index 000000000..c1c16cfbf --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Code25interleaved.php @@ -0,0 +1,63 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Code39.php b/library/vendor/Zend/Validate/Barcode/Code39.php new file mode 100644 index 000000000..811d2b28a --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Code39.php @@ -0,0 +1,99 @@ + 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, + '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, + 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, + 'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, + 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34, + 'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41, + '%' => 42, + ); + + /** + * Constructor + * + * Sets check flag to false. + * + * @return void + */ + public function __construct() + { + $this->setCheck(false); + } + + /** + * Validates the checksum (Modulo 43) + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _code39($value) + { + $checksum = substr($value, -1, 1); + $value = str_split(substr($value, 0, -1)); + $count = 0; + foreach($value as $char) { + $count += $this->_check[$char]; + } + + $mod = $count % 43; + if ($mod == $this->_check[$checksum]) { + return true; + } + + return false; + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Code39ext.php b/library/vendor/Zend/Validate/Barcode/Code39ext.php new file mode 100644 index 000000000..3a6b56808 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Code39ext.php @@ -0,0 +1,57 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Code93.php b/library/vendor/Zend/Validate/Barcode/Code93.php new file mode 100644 index 000000000..7989b5cce --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Code93.php @@ -0,0 +1,119 @@ + 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, + '7' => 7, '8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, + 'E' => 14, 'F' => 15, 'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, + 'L' => 21, 'M' => 22, 'N' => 23, 'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, + 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31, 'W' => 32, 'X' => 33, 'Y' => 34, + 'Z' => 35, '-' => 36, '.' => 37, ' ' => 38, '$' => 39, '/' => 40, '+' => 41, + '%' => 42, '!' => 43, '"' => 44, '§' => 45, '&' => 46, + ); + + /** + * Constructor + * + * Sets check flag to false. + * + * @return void + */ + public function __construct() + { + $this->setCheck(false); + } + + /** + * Validates the checksum (Modulo CK) + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _code93($value) + { + $checksum = substr($value, -2, 2); + $value = str_split(substr($value, 0, -2)); + $count = 0; + $length = count($value) % 20; + foreach($value as $char) { + if ($length == 0) { + $length = 20; + } + + $count += $this->_check[$char] * $length; + --$length; + } + + $check = array_search(($count % 47), $this->_check); + $value[] = $check; + $count = 0; + $length = count($value) % 15; + foreach($value as $char) { + if ($length == 0) { + $length = 15; + } + + $count += $this->_check[$char] * $length; + --$length; + } + $check .= array_search(($count % 47), $this->_check); + + if ($check == $checksum) { + return true; + } + + return false; + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Code93ext.php b/library/vendor/Zend/Validate/Barcode/Code93ext.php new file mode 100644 index 000000000..3d0ff2b20 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Code93ext.php @@ -0,0 +1,57 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Ean12.php b/library/vendor/Zend/Validate/Barcode/Ean12.php new file mode 100644 index 000000000..3bcf35b7b --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Ean12.php @@ -0,0 +1,51 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Ean5.php b/library/vendor/Zend/Validate/Barcode/Ean5.php new file mode 100644 index 000000000..2bba83399 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Ean5.php @@ -0,0 +1,57 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Ean8.php b/library/vendor/Zend/Validate/Barcode/Ean8.php new file mode 100644 index 000000000..f19b51e2c --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Ean8.php @@ -0,0 +1,68 @@ +setCheck(false); + } else { + $this->setCheck(true); + } + + return parent::checkLength($value); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Gtin12.php b/library/vendor/Zend/Validate/Barcode/Gtin12.php new file mode 100644 index 000000000..e682bc071 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Gtin12.php @@ -0,0 +1,51 @@ +setCheck(false); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Issn.php b/library/vendor/Zend/Validate/Barcode/Issn.php new file mode 100644 index 000000000..7b6ff2d0a --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Issn.php @@ -0,0 +1,118 @@ +_checksum = '_issn'; + } else { + $this->_checksum = '_gtin'; + } + + return parent::checksum($value); + } + + /** + * Validates the checksum () + * ISSN implementation (reversed mod11) + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _issn($value) + { + $checksum = substr($value, -1, 1); + $values = str_split(substr($value, 0, -1)); + $check = 0; + $multi = 8; + foreach($values as $token) { + if ($token == 'X') { + $token = 10; + } + + $check += ($token * $multi); + --$multi; + } + + $check %= 11; + $check = 11 - $check; + if ($check == $checksum) { + return true; + } else if (($check == 10) && ($checksum == 'X')) { + return true; + } + + return false; + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Itf14.php b/library/vendor/Zend/Validate/Barcode/Itf14.php new file mode 100644 index 000000000..fab7a423c --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Itf14.php @@ -0,0 +1,51 @@ + 1, '1' => 1, '2' => 1, '3' => 1, '4' => 1, '5' => 1, + '6' => 2, '7' => 2, '8' => 2, '9' => 2, 'A' => 2, 'B' => 2, + 'C' => 3, 'D' => 3, 'E' => 3, 'F' => 3, 'G' => 3, 'H' => 3, + 'I' => 4, 'J' => 4, 'K' => 4, 'L' => 4, 'M' => 4, 'N' => 4, + 'O' => 5, 'P' => 5, 'Q' => 5, 'R' => 5, 'S' => 5, 'T' => 5, + 'U' => 0, 'V' => 0, 'W' => 0, 'X' => 0, 'Y' => 0, 'Z' => 0, + ); + + protected $_columns = array( + '0' => 1, '1' => 2, '2' => 3, '3' => 4, '4' => 5, '5' => 0, + '6' => 1, '7' => 2, '8' => 3, '9' => 4, 'A' => 5, 'B' => 0, + 'C' => 1, 'D' => 2, 'E' => 3, 'F' => 4, 'G' => 5, 'H' => 0, + 'I' => 1, 'J' => 2, 'K' => 3, 'L' => 4, 'M' => 5, 'N' => 0, + 'O' => 1, 'P' => 2, 'Q' => 3, 'R' => 4, 'S' => 5, 'T' => 0, + 'U' => 1, 'V' => 2, 'W' => 3, 'X' => 4, 'Y' => 5, 'Z' => 0, + ); + + /** + * Checksum function + * @var string + */ + protected $_checksum = '_royalmail'; + + /** + * Validates the checksum () + * + * @param string $value The barcode to validate + * @return boolean + */ + protected function _royalmail($value) + { + $checksum = substr($value, -1, 1); + $values = str_split(substr($value, 0, -1)); + $rowvalue = 0; + $colvalue = 0; + foreach($values as $row) { + $rowvalue += $this->_rows[$row]; + $colvalue += $this->_columns[$row]; + } + + $rowvalue %= 6; + $colvalue %= 6; + + $rowchkvalue = array_keys($this->_rows, $rowvalue); + $colchkvalue = array_keys($this->_columns, $colvalue); + $chkvalue = current(array_intersect($rowchkvalue, $colchkvalue)); + if ($chkvalue == $checksum) { + return true; + } + + return false; + } + + /** + * Allows start and stop tag within checked chars + * + * @param string $value The barcode to check for allowed characters + * @return boolean + */ + public function checkChars($value) + { + if ($value[0] == '(') { + $value = substr($value, 1); + + if ($value[strlen($value) - 1] == ')') { + $value = substr($value, 0, -1); + } else { + return false; + } + } + + return parent::checkChars($value); + } +} diff --git a/library/vendor/Zend/Validate/Barcode/Sscc.php b/library/vendor/Zend/Validate/Barcode/Sscc.php new file mode 100644 index 000000000..2dde1a533 --- /dev/null +++ b/library/vendor/Zend/Validate/Barcode/Sscc.php @@ -0,0 +1,51 @@ +setCheck(false); + } else { + $this->setCheck(true); + } + + return parent::checkLength($value); + } +} diff --git a/library/vendor/Zend/Validate/Between.php b/library/vendor/Zend/Validate/Between.php new file mode 100644 index 000000000..9532dff3c --- /dev/null +++ b/library/vendor/Zend/Validate/Between.php @@ -0,0 +1,222 @@ + "'%value%' is not between '%min%' and '%max%', inclusively", + self::NOT_BETWEEN_STRICT => "'%value%' is not strictly between '%min%' and '%max%'" + ); + + /** + * Additional variables available for validation failure messages + * + * @var array + */ + protected $_messageVariables = array( + 'min' => '_min', + 'max' => '_max' + ); + + /** + * Minimum value + * + * @var mixed + */ + protected $_min; + + /** + * Maximum value + * + * @var mixed + */ + protected $_max; + + /** + * Whether to do inclusive comparisons, allowing equivalence to min and/or max + * + * If false, then strict comparisons are done, and the value may equal neither + * the min nor max options + * + * @var boolean + */ + protected $_inclusive; + + /** + * Sets validator options + * Accepts the following option keys: + * 'min' => scalar, minimum border + * 'max' => scalar, maximum border + * 'inclusive' => boolean, inclusive border values + * + * @param array|Zend_Config $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['min'] = array_shift($options); + if (!empty($options)) { + $temp['max'] = array_shift($options); + } + + if (!empty($options)) { + $temp['inclusive'] = array_shift($options); + } + + $options = $temp; + } + + if (!array_key_exists('min', $options) || !array_key_exists('max', $options)) { + throw new Zend_Validate_Exception("Missing option. 'min' and 'max' has to be given"); + } + + if (!array_key_exists('inclusive', $options)) { + $options['inclusive'] = true; + } + + $this->setMin($options['min']) + ->setMax($options['max']) + ->setInclusive($options['inclusive']); + } + + /** + * Returns the min option + * + * @return mixed + */ + public function getMin() + { + return $this->_min; + } + + /** + * Sets the min option + * + * @param mixed $min + * @return Zend_Validate_Between Provides a fluent interface + */ + public function setMin($min) + { + $this->_min = $min; + return $this; + } + + /** + * Returns the max option + * + * @return mixed + */ + public function getMax() + { + return $this->_max; + } + + /** + * Sets the max option + * + * @param mixed $max + * @return Zend_Validate_Between Provides a fluent interface + */ + public function setMax($max) + { + $this->_max = $max; + return $this; + } + + /** + * Returns the inclusive option + * + * @return boolean + */ + public function getInclusive() + { + return $this->_inclusive; + } + + /** + * Sets the inclusive option + * + * @param boolean $inclusive + * @return Zend_Validate_Between Provides a fluent interface + */ + public function setInclusive($inclusive) + { + $this->_inclusive = $inclusive; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is between min and max options, inclusively + * if inclusive option is true. + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + + if ($this->_inclusive) { + if ($this->_min > $value || $value > $this->_max) { + $this->_error(self::NOT_BETWEEN); + return false; + } + } else { + if ($this->_min >= $value || $value >= $this->_max) { + $this->_error(self::NOT_BETWEEN_STRICT); + return false; + } + } + return true; + } + +} diff --git a/library/vendor/Zend/Validate/Callback.php b/library/vendor/Zend/Validate/Callback.php new file mode 100644 index 000000000..8029a5fcb --- /dev/null +++ b/library/vendor/Zend/Validate/Callback.php @@ -0,0 +1,171 @@ + "'%value%' is not valid", + self::INVALID_CALLBACK => "An exception has been raised within the callback", + ); + + /** + * Callback in a call_user_func format + * + * @var string|array + */ + protected $_callback = null; + + /** + * Default options to set for the filter + * + * @var mixed + */ + protected $_options = array(); + + /** + * Sets validator options + * + * @param string|array $callback + * @param mixed $max + * @param boolean $inclusive + * @return void + */ + public function __construct($callback = null) + { + if (is_callable($callback)) { + $this->setCallback($callback); + } elseif (is_array($callback)) { + if (isset($callback['callback'])) { + $this->setCallback($callback['callback']); + } + if (isset($callback['options'])) { + $this->setOptions($callback['options']); + } + } + + if (null === ($initializedCallack = $this->getCallback())) { + throw new Zend_Validate_Exception('No callback registered'); + } + } + + /** + * Returns the set callback + * + * @return mixed + */ + public function getCallback() + { + return $this->_callback; + } + + /** + * Sets the callback + * + * @param string|array $callback + * @return Zend_Validate_Callback Provides a fluent interface + */ + public function setCallback($callback) + { + if (!is_callable($callback)) { + throw new Zend_Validate_Exception('Invalid callback given'); + } + $this->_callback = $callback; + return $this; + } + + /** + * Returns the set options for the callback + * + * @return mixed + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets options for the callback + * + * @param mixed $max + * @return Zend_Validate_Callback Provides a fluent interface + */ + public function setOptions($options) + { + $this->_options = (array) $options; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the set callback returns + * for the provided $value + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + + $options = $this->getOptions(); + $callback = $this->getCallback(); + $args = func_get_args(); + $options = array_merge($args, $options); + + try { + if (!call_user_func_array($callback, $options)) { + $this->_error(self::INVALID_VALUE); + return false; + } + } catch (Exception $e) { + $this->_error(self::INVALID_CALLBACK); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Ccnum.php b/library/vendor/Zend/Validate/Ccnum.php new file mode 100644 index 000000000..3a3e1e1eb --- /dev/null +++ b/library/vendor/Zend/Validate/Ccnum.php @@ -0,0 +1,110 @@ + "'%value%' must contain between 13 and 19 digits", + self::CHECKSUM => "Luhn algorithm (mod-10 checksum) failed on '%value%'" + ); + + public function __construct() + { + trigger_error('Using the Ccnum validator is deprecated in favor of the CreditCard validator'); + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value follows the Luhn algorithm (mod-10 checksum) + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + + if (null === self::$_filter) { + /** + * @see Zend_Filter_Digits + */ + self::$_filter = new Zend_Filter_Digits(); + } + + $valueFiltered = self::$_filter->filter($value); + + $length = strlen($valueFiltered); + + if ($length < 13 || $length > 19) { + $this->_error(self::LENGTH); + return false; + } + + $sum = 0; + $weight = 2; + + for ($i = $length - 2; $i >= 0; $i--) { + $digit = $weight * $valueFiltered[$i]; + $sum += floor($digit / 10) + $digit % 10; + $weight = $weight % 2 + 1; + } + + if ((10 - $sum % 10) % 10 != $valueFiltered[$length - 1]) { + $this->_error(self::CHECKSUM, $valueFiltered); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/CreditCard.php b/library/vendor/Zend/Validate/CreditCard.php new file mode 100644 index 000000000..ca6816190 --- /dev/null +++ b/library/vendor/Zend/Validate/CreditCard.php @@ -0,0 +1,314 @@ + "'%value%' seems to contain an invalid checksum", + self::CONTENT => "'%value%' must contain only digits", + self::INVALID => "Invalid type given. String expected", + self::LENGTH => "'%value%' contains an invalid amount of digits", + self::PREFIX => "'%value%' is not from an allowed institute", + self::SERVICE => "'%value%' seems to be an invalid creditcard number", + self::SERVICEFAILURE => "An exception has been raised while validating '%value%'", + ); + + /** + * List of allowed CCV lengths + * + * @var array + */ + protected $_cardLength = array( + self::AMERICAN_EXPRESS => array(15), + self::DINERS_CLUB => array(14), + self::DINERS_CLUB_US => array(16), + self::DISCOVER => array(16), + self::JCB => array(16), + self::LASER => array(16, 17, 18, 19), + self::MAESTRO => array(12, 13, 14, 15, 16, 17, 18, 19), + self::MASTERCARD => array(16), + self::SOLO => array(16, 18, 19), + self::UNIONPAY => array(16, 17, 18, 19), + self::VISA => array(16), + ); + + /** + * List of accepted CCV provider tags + * + * @var array + */ + protected $_cardType = array( + self::AMERICAN_EXPRESS => array('34', '37'), + self::DINERS_CLUB => array('300', '301', '302', '303', '304', '305', '36'), + self::DINERS_CLUB_US => array('54', '55'), + self::DISCOVER => array('6011', '622126', '622127', '622128', '622129', '62213', + '62214', '62215', '62216', '62217', '62218', '62219', + '6222', '6223', '6224', '6225', '6226', '6227', '6228', + '62290', '62291', '622920', '622921', '622922', '622923', + '622924', '622925', '644', '645', '646', '647', '648', + '649', '65'), + self::JCB => array('3528', '3529', '353', '354', '355', '356', '357', '358'), + self::LASER => array('6304', '6706', '6771', '6709'), + self::MAESTRO => array('5018', '5020', '5038', '6304', '6759', '6761', '6763'), + self::MASTERCARD => array('51', '52', '53', '54', '55'), + self::SOLO => array('6334', '6767'), + self::UNIONPAY => array('622126', '622127', '622128', '622129', '62213', '62214', + '62215', '62216', '62217', '62218', '62219', '6222', '6223', + '6224', '6225', '6226', '6227', '6228', '62290', '62291', + '622920', '622921', '622922', '622923', '622924', '622925'), + self::VISA => array('4'), + ); + + /** + * CCIs which are accepted by validation + * + * @var array + */ + protected $_type = array(); + + /** + * Service callback for additional validation + * + * @var callback + */ + protected $_service; + + /** + * Constructor + * + * @param string|array $type OPTIONAL Type of CCI to allow + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['type'] = array_shift($options); + if (!empty($options)) { + $temp['service'] = array_shift($options); + } + + $options = $temp; + } + + if (!array_key_exists('type', $options)) { + $options['type'] = self::ALL; + } + + $this->setType($options['type']); + if (array_key_exists('service', $options)) { + $this->setService($options['service']); + } + } + + /** + * Returns a list of accepted CCIs + * + * @return array + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets CCIs which are accepted by validation + * + * @param string|array $type Type to allow for validation + * @return Zend_Validate_CreditCard Provides a fluid interface + */ + public function setType($type) + { + $this->_type = array(); + return $this->addType($type); + } + + /** + * Adds a CCI to be accepted by validation + * + * @param string|array $type Type to allow for validation + * @return Zend_Validate_CreditCard Provides a fluid interface + */ + public function addType($type) + { + if (is_string($type)) { + $type = array($type); + } + + foreach($type as $typ) { + if (defined('self::' . strtoupper($typ)) && !in_array($typ, $this->_type)) { + $this->_type[] = $typ; + } + + if (($typ == self::ALL)) { + $this->_type = array_keys($this->_cardLength); + } + } + + return $this; + } + + /** + * Returns the actual set service + * + * @return callback + */ + public function getService() + { + return $this->_service; + } + + /** + * Sets a new callback for service validation + * + * @param unknown_type $service + */ + public function setService($service) + { + if (!is_callable($service)) { + throw new Zend_Validate_Exception('Invalid callback given'); + } + + $this->_service = $service; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value follows the Luhn algorithm (mod-10 checksum) + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + + if (!is_string($value)) { + $this->_error(self::INVALID, $value); + return false; + } + + if (!ctype_digit($value)) { + $this->_error(self::CONTENT, $value); + return false; + } + + $length = strlen($value); + $types = $this->getType(); + $foundp = false; + $foundl = false; + foreach ($types as $type) { + foreach ($this->_cardType[$type] as $prefix) { + if (substr($value, 0, strlen($prefix)) == $prefix) { + $foundp = true; + if (in_array($length, $this->_cardLength[$type])) { + $foundl = true; + break 2; + } + } + } + } + + if ($foundp == false){ + $this->_error(self::PREFIX, $value); + return false; + } + + if ($foundl == false) { + $this->_error(self::LENGTH, $value); + return false; + } + + $sum = 0; + $weight = 2; + + for ($i = $length - 2; $i >= 0; $i--) { + $digit = $weight * $value[$i]; + $sum += floor($digit / 10) + $digit % 10; + $weight = $weight % 2 + 1; + } + + if ((10 - $sum % 10) % 10 != $value[$length - 1]) { + $this->_error(self::CHECKSUM, $value); + return false; + } + + if (!empty($this->_service)) { + try { + $callback = new Zend_Validate_Callback($this->_service); + $callback->setOptions($this->_type); + if (!$callback->isValid($value)) { + $this->_error(self::SERVICE, $value); + return false; + } + } catch (Zend_Exception $e) { + $this->_error(self::SERVICEFAILURE, $value); + return false; + } + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Date.php b/library/vendor/Zend/Validate/Date.php new file mode 100644 index 000000000..257c26933 --- /dev/null +++ b/library/vendor/Zend/Validate/Date.php @@ -0,0 +1,254 @@ + "Invalid type given. String, integer, array or Zend_Date expected", + self::INVALID_DATE => "'%value%' does not appear to be a valid date", + self::FALSEFORMAT => "'%value%' does not fit the date format '%format%'", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'format' => '_format' + ); + + /** + * Optional format + * + * @var string|null + */ + protected $_format; + + /** + * Optional locale + * + * @var string|Zend_Locale|null + */ + protected $_locale; + + /** + * Sets validator options + * + * @param string|Zend_Config $options OPTIONAL + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['format'] = array_shift($options); + if (!empty($options)) { + $temp['locale'] = array_shift($options); + } + + $options = $temp; + } + + if (array_key_exists('format', $options)) { + $this->setFormat($options['format']); + } + + if (!array_key_exists('locale', $options)) { + if (Zend_Registry::isRegistered('Zend_Locale')) { + $options['locale'] = Zend_Registry::get('Zend_Locale'); + } + } + + if (array_key_exists('locale', $options)) { + $this->setLocale($options['locale']); + } + } + + /** + * Returns the locale option + * + * @return string|Zend_Locale|null + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Sets the locale option + * + * @param string|Zend_Locale $locale + * @return Zend_Validate_Date provides a fluent interface + */ + public function setLocale($locale = null) + { + $this->_locale = Zend_Locale::findLocale($locale); + return $this; + } + + /** + * Returns the locale option + * + * @return string|null + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets the format option + * + * @param string $format + * @return Zend_Validate_Date provides a fluent interface + */ + public function setFormat($format = null) + { + $this->_format = $format; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if $value is a valid date of the format YYYY-MM-DD + * If optional $format or $locale is set the date format is checked + * according to Zend_Date, see Zend_Date::isDate() + * + * @param string|array|Zend_Date $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value) && + !is_array($value) && !($value instanceof Zend_Date)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + + if (($this->_format !== null) || ($this->_locale !== null) || is_array($value) || + $value instanceof Zend_Date) { + if (!Zend_Date::isDate($value, $this->_format, $this->_locale)) { + if ($this->_checkFormat($value) === false) { + $this->_error(self::FALSEFORMAT); + } else { + $this->_error(self::INVALID_DATE); + } + return false; + } + } else { + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { + $this->_format = 'yyyy-MM-dd'; + $this->_error(self::FALSEFORMAT); + $this->_format = null; + return false; + } + + list($year, $month, $day) = sscanf($value, '%d-%d-%d'); + + if (!checkdate($month, $day, $year)) { + $this->_error(self::INVALID_DATE); + return false; + } + } + + return true; + } + + /** + * Check if the given date fits the given format + * + * @param string $value Date to check + * @return boolean False when date does not fit the format + */ + private function _checkFormat($value) + { + try { + $parsed = Zend_Locale_Format::getDate($value, array( + 'date_format' => $this->_format, 'format_type' => 'iso', + 'fix_date' => false)); + if (isset($parsed['year']) and ((strpos(strtoupper($this->_format), 'YY') !== false) and + (strpos(strtoupper($this->_format), 'YYYY') === false))) { + $parsed['year'] = Zend_Date::getFullYear($parsed['year']); + } + } catch (Exception $e) { + // Date can not be parsed + return false; + } + + if (((strpos($this->_format, 'Y') !== false) or (strpos($this->_format, 'y') !== false)) and + (!isset($parsed['year']))) { + // Year expected but not found + return false; + } + + if ((strpos($this->_format, 'M') !== false) and (!isset($parsed['month']))) { + // Month expected but not found + return false; + } + + if ((strpos($this->_format, 'd') !== false) and (!isset($parsed['day']))) { + // Day expected but not found + return false; + } + + if (((strpos($this->_format, 'H') !== false) or (strpos($this->_format, 'h') !== false)) and + (!isset($parsed['hour']))) { + // Hour expected but not found + return false; + } + + if ((strpos($this->_format, 'm') !== false) and (!isset($parsed['minute']))) { + // Minute expected but not found + return false; + } + + if ((strpos($this->_format, 's') !== false) and (!isset($parsed['second']))) { + // Second expected but not found + return false; + } + + // Date fits the format + return true; + } +} diff --git a/library/vendor/Zend/Validate/Db/Abstract.php b/library/vendor/Zend/Validate/Db/Abstract.php new file mode 100644 index 000000000..2c1fc30bf --- /dev/null +++ b/library/vendor/Zend/Validate/Db/Abstract.php @@ -0,0 +1,346 @@ + "No record matching '%value%' was found", + self::ERROR_RECORD_FOUND => "A record matching '%value%' was found", + ); + + /** + * @var string + */ + protected $_schema = null; + + /** + * @var string + */ + protected $_table = ''; + + /** + * @var string + */ + protected $_field = ''; + + /** + * @var mixed + */ + protected $_exclude = null; + + /** + * Database adapter to use. If null isValid() will use Zend_Db::getInstance instead + * + * @var unknown_type + */ + protected $_adapter = null; + + /** + * Select object to use. can be set, or will be auto-generated + * @var Zend_Db_Select + */ + protected $_select; + + /** + * Provides basic configuration for use with Zend_Validate_Db Validators + * Setting $exclude allows a single record to be excluded from matching. + * Exclude can either be a String containing a where clause, or an array with `field` and `value` keys + * to define the where clause added to the sql. + * A database adapter may optionally be supplied to avoid using the registered default adapter. + * + * The following option keys are supported: + * 'table' => The database table to validate against + * 'schema' => The schema keys + * 'field' => The field to check for a match + * 'exclude' => An optional where clause or field/value pair to exclude from the query + * 'adapter' => An optional database adapter to use + * + * @param array|Zend_Config $options Options to use for this validator + */ + public function __construct($options) + { + if ($options instanceof Zend_Db_Select) { + $this->setSelect($options); + return; + } + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (func_num_args() > 1) { + $options = func_get_args(); + $temp['table'] = array_shift($options); + $temp['field'] = array_shift($options); + if (!empty($options)) { + $temp['exclude'] = array_shift($options); + } + + if (!empty($options)) { + $temp['adapter'] = array_shift($options); + } + + $options = $temp; + } + + if (!array_key_exists('table', $options) && !array_key_exists('schema', $options)) { + throw new Zend_Validate_Exception('Table or Schema option missing!'); + } + + if (!array_key_exists('field', $options)) { + throw new Zend_Validate_Exception('Field option missing!'); + } + + if (array_key_exists('adapter', $options)) { + $this->setAdapter($options['adapter']); + } + + if (array_key_exists('exclude', $options)) { + $this->setExclude($options['exclude']); + } + + $this->setField($options['field']); + if (array_key_exists('table', $options)) { + $this->setTable($options['table']); + } + + if (array_key_exists('schema', $options)) { + $this->setSchema($options['schema']); + } + } + + /** + * Returns the set adapter + * + * @return Zend_Db_Adapter + */ + public function getAdapter() + { + /** + * Check for an adapter being defined. if not, fetch the default adapter. + */ + if ($this->_adapter === null) { + $this->_adapter = Zend_Db_Table_Abstract::getDefaultAdapter(); + if (null === $this->_adapter) { + throw new Zend_Validate_Exception('No database adapter present'); + } + } + return $this->_adapter; + } + + /** + * Sets a new database adapter + * + * @param Zend_Db_Adapter_Abstract $adapter + * @return Zend_Validate_Db_Abstract + */ + public function setAdapter($adapter) + { + if (!($adapter instanceof Zend_Db_Adapter_Abstract)) { + throw new Zend_Validate_Exception('Adapter option must be a database adapter!'); + } + + $this->_adapter = $adapter; + return $this; + } + + /** + * Returns the set exclude clause + * + * @return string|array + */ + public function getExclude() + { + return $this->_exclude; + } + + /** + * Sets a new exclude clause + * + * @param string|array $exclude + * @return Zend_Validate_Db_Abstract + */ + public function setExclude($exclude) + { + $this->_exclude = $exclude; + return $this; + } + + /** + * Returns the set field + * + * @return string|array + */ + public function getField() + { + return $this->_field; + } + + /** + * Sets a new field + * + * @param string $field + * @return Zend_Validate_Db_Abstract + */ + public function setField($field) + { + $this->_field = (string) $field; + return $this; + } + + /** + * Returns the set table + * + * @return string + */ + public function getTable() + { + return $this->_table; + } + + /** + * Sets a new table + * + * @param string $table + * @return Zend_Validate_Db_Abstract + */ + public function setTable($table) + { + $this->_table = (string) $table; + return $this; + } + + /** + * Returns the set schema + * + * @return string + */ + public function getSchema() + { + return $this->_schema; + } + + /** + * Sets a new schema + * + * @param string $schema + * @return Zend_Validate_Db_Abstract + */ + public function setSchema($schema) + { + $this->_schema = $schema; + return $this; + } + + /** + * Sets the select object to be used by the validator + * + * @param Zend_Db_Select $select + * @return Zend_Validate_Db_Abstract + */ + public function setSelect($select) + { + if (!$select instanceof Zend_Db_Select) { + throw new Zend_Validate_Exception('Select option must be a valid ' . + 'Zend_Db_Select object'); + } + $this->_select = $select; + return $this; + } + + /** + * Gets the select object to be used by the validator. + * If no select object was supplied to the constructor, + * then it will auto-generate one from the given table, + * schema, field, and adapter options. + * + * @return Zend_Db_Select The Select object which will be used + */ + public function getSelect() + { + if (null === $this->_select) { + $db = $this->getAdapter(); + /** + * Build select object + */ + $select = new Zend_Db_Select($db); + $select->from($this->_table, array($this->_field), $this->_schema); + if ($db->supportsParameters('named')) { + $select->where($db->quoteIdentifier($this->_field, true).' = :value'); // named + } else { + $select->where($db->quoteIdentifier($this->_field, true).' = ?'); // positional + } + if ($this->_exclude !== null) { + if (is_array($this->_exclude)) { + $select->where( + $db->quoteIdentifier($this->_exclude['field'], true) . + ' != ?', $this->_exclude['value'] + ); + } else { + $select->where($this->_exclude); + } + } + $select->limit(1); + $this->_select = $select; + } + return $this->_select; + } + + /** + * Run query and returns matches, or null if no matches are found. + * + * @param String $value + * @return Array when matches are found. + */ + protected function _query($value) + { + $select = $this->getSelect(); + /** + * Run query + */ + $result = $select->getAdapter()->fetchRow( + $select, + array('value' => $value), // this should work whether db supports positional or named params + Zend_Db::FETCH_ASSOC + ); + + return $result; + } +} diff --git a/library/vendor/Zend/Validate/Db/NoRecordExists.php b/library/vendor/Zend/Validate/Db/NoRecordExists.php new file mode 100644 index 000000000..34a23b5d7 --- /dev/null +++ b/library/vendor/Zend/Validate/Db/NoRecordExists.php @@ -0,0 +1,50 @@ +_setValue($value); + + $result = $this->_query($value); + if ($result) { + $valid = false; + $this->_error(self::ERROR_RECORD_FOUND); + } + + return $valid; + } +} diff --git a/library/vendor/Zend/Validate/Db/RecordExists.php b/library/vendor/Zend/Validate/Db/RecordExists.php new file mode 100644 index 000000000..94d74e4df --- /dev/null +++ b/library/vendor/Zend/Validate/Db/RecordExists.php @@ -0,0 +1,50 @@ +_setValue($value); + + $result = $this->_query($value); + if (!$result) { + $valid = false; + $this->_error(self::ERROR_NO_RECORD_FOUND); + } + + return $valid; + } +} diff --git a/library/vendor/Zend/Validate/Digits.php b/library/vendor/Zend/Validate/Digits.php new file mode 100644 index 000000000..1c10a9fba --- /dev/null +++ b/library/vendor/Zend/Validate/Digits.php @@ -0,0 +1,89 @@ + "'%value%' must contain only digits", + self::STRING_EMPTY => "'%value%' is an empty string", + self::INVALID => "Invalid type given. String, integer or float expected", + ); + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value only contains digit characters + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue((string) $value); + + if ('' === $this->_value) { + $this->_error(self::STRING_EMPTY); + return false; + } + + if (null === self::$_filter) { + self::$_filter = new Zend_Filter_Digits(); + } + + if ($this->_value !== self::$_filter->filter($this->_value)) { + $this->_error(self::NOT_DIGITS); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/EmailAddress.php b/library/vendor/Zend/Validate/EmailAddress.php new file mode 100644 index 000000000..e5e9d04c4 --- /dev/null +++ b/library/vendor/Zend/Validate/EmailAddress.php @@ -0,0 +1,564 @@ + "Invalid type given. String expected", + self::INVALID_FORMAT => "'%value%' is not a valid email address in the basic format local-part@hostname", + self::INVALID_HOSTNAME => "'%hostname%' is not a valid hostname for email address '%value%'", + self::INVALID_MX_RECORD => "'%hostname%' does not appear to have a valid MX record for the email address '%value%'", + self::INVALID_SEGMENT => "'%hostname%' is not in a routable network segment. The email address '%value%' should not be resolved from public network", + self::DOT_ATOM => "'%localPart%' can not be matched against dot-atom format", + self::QUOTED_STRING => "'%localPart%' can not be matched against quoted-string format", + self::INVALID_LOCAL_PART => "'%localPart%' is not a valid local part for email address '%value%'", + self::LENGTH_EXCEEDED => "'%value%' exceeds the allowed length", + ); + + /** + * As of RFC5753 (JAN 2010), the following blocks are no logner reserved: + * - 128.0.0.0/16 + * - 191.255.0.0/16 + * - 223.255.255.0/24 + * @see http://tools.ietf.org/html/rfc5735#page-6 + * + * As of RFC6598 (APR 2012), the following blocks are now reserved: + * - 100.64.0.0/10 + * @see http://tools.ietf.org/html/rfc6598#section-7 + * + * @see http://en.wikipedia.org/wiki/IPv4 + * @var array + */ + protected $_invalidIp = array( + '0' => '0.0.0.0/8', + '10' => '10.0.0.0/8', + '100' => '100.64.0.0/10', + '127' => '127.0.0.0/8', + '169' => '169.254.0.0/16', + '172' => '172.16.0.0/12', + '192' => array( + '192.0.0.0/24', + '192.0.2.0/24', + '192.88.99.0/24', + '192.168.0.0/16' + ), + '198' => '198.18.0.0/15', + '224' => '224.0.0.0/4', + '240' => '240.0.0.0/4' + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'hostname' => '_hostname', + 'localPart' => '_localPart' + ); + + /** + * @var string + */ + protected $_hostname; + + /** + * @var string + */ + protected $_localPart; + + /** + * Internal options array + */ + protected $_options = array( + 'mx' => false, + 'deep' => false, + 'domain' => true, + 'allow' => Zend_Validate_Hostname::ALLOW_DNS, + 'hostname' => null + ); + + /** + * Instantiates hostname validator for local use + * + * The following option keys are supported: + * 'hostname' => A hostname validator, see Zend_Validate_Hostname + * 'allow' => Options for the hostname validator, see Zend_Validate_Hostname::ALLOW_* + * 'mx' => If MX check should be enabled, boolean + * 'deep' => If a deep MX check should be done, boolean + * + * @param array|Zend_Config $options OPTIONAL + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['allow'] = array_shift($options); + if (!empty($options)) { + $temp['mx'] = array_shift($options); + } + + if (!empty($options)) { + $temp['hostname'] = array_shift($options); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions($options); + } + + /** + * Returns all set Options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Set options for the email validator + * + * @param array $options + * @return Zend_Validate_EmailAddress fluid interface + */ + public function setOptions(array $options = array()) + { + if (array_key_exists('messages', $options)) { + $this->setMessages($options['messages']); + } + + if (array_key_exists('hostname', $options)) { + if (array_key_exists('allow', $options)) { + $this->setHostnameValidator($options['hostname'], $options['allow']); + } else { + $this->setHostnameValidator($options['hostname']); + } + } elseif ($this->_options['hostname'] == null) { + $this->setHostnameValidator(); + } + + if (array_key_exists('mx', $options)) { + $this->setValidateMx($options['mx']); + } + + if (array_key_exists('deep', $options)) { + $this->setDeepMxCheck($options['deep']); + } + + if (array_key_exists('domain', $options)) { + $this->setDomainCheck($options['domain']); + } + + return $this; + } + + /** + * Sets the validation failure message template for a particular key + * Adds the ability to set messages to the attached hostname validator + * + * @param string $messageString + * @param string $messageKey OPTIONAL + * @return Zend_Validate_Abstract Provides a fluent interface + * @throws Zend_Validate_Exception + */ + public function setMessage($messageString, $messageKey = null) + { + if ($messageKey === null) { + $this->_options['hostname']->setMessage($messageString); + parent::setMessage($messageString); + return $this; + } + + if (!isset($this->_messageTemplates[$messageKey])) { + $this->_options['hostname']->setMessage($messageString, $messageKey); + } + + $this->_messageTemplates[$messageKey] = $messageString; + return $this; + } + + /** + * Returns the set hostname validator + * + * @return Zend_Validate_Hostname + */ + public function getHostnameValidator() + { + return $this->_options['hostname']; + } + + /** + * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL + * @param int $allow OPTIONAL + * @return void + */ + public function setHostnameValidator(Zend_Validate_Hostname $hostnameValidator = null, $allow = Zend_Validate_Hostname::ALLOW_DNS) + { + if (!$hostnameValidator) { + $hostnameValidator = new Zend_Validate_Hostname($allow); + } + + $this->_options['hostname'] = $hostnameValidator; + $this->_options['allow'] = $allow; + return $this; + } + + /** + * Whether MX checking via getmxrr is supported or not + * + * This currently only works on UNIX systems + * + * @return boolean + */ + public function validateMxSupported() + { + return function_exists('getmxrr'); + } + + /** + * Returns the set validateMx option + * + * @return boolean + */ + public function getValidateMx() + { + return $this->_options['mx']; + } + + /** + * Set whether we check for a valid MX record via DNS + * + * This only applies when DNS hostnames are validated + * + * @param boolean $mx Set allowed to true to validate for MX records, and false to not validate them + * @return Zend_Validate_EmailAddress Fluid Interface + */ + public function setValidateMx($mx) + { + if ((bool) $mx && !$this->validateMxSupported()) { + throw new Zend_Validate_Exception('MX checking not available on this system'); + } + + $this->_options['mx'] = (bool) $mx; + return $this; + } + + /** + * Returns the set deepMxCheck option + * + * @return boolean + */ + public function getDeepMxCheck() + { + return $this->_options['deep']; + } + + /** + * Set whether we check MX record should be a deep validation + * + * @param boolean $deep Set deep to true to perform a deep validation process for MX records + * @return Zend_Validate_EmailAddress Fluid Interface + */ + public function setDeepMxCheck($deep) + { + $this->_options['deep'] = (bool) $deep; + return $this; + } + + /** + * Returns the set domainCheck option + * + * @return unknown + */ + public function getDomainCheck() + { + return $this->_options['domain']; + } + + /** + * Sets if the domain should also be checked + * or only the local part of the email address + * + * @param boolean $domain + * @return Zend_Validate_EmailAddress Fluid Interface + */ + public function setDomainCheck($domain = true) + { + $this->_options['domain'] = (boolean) $domain; + return $this; + } + + /** + * Returns if the given host is reserved + * + * @param string $host + * @return boolean + */ + private function _isReserved($host){ + if (!preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $host)) { + $host = gethostbyname($host); + } + + $octet = explode('.',$host); + if ((int)$octet[0] >= 224) { + return true; + } else if (array_key_exists($octet[0], $this->_invalidIp)) { + foreach ((array)$this->_invalidIp[$octet[0]] as $subnetData) { + // we skip the first loop as we already know that octet matches + for ($i = 1; $i < 4; $i++) { + if (strpos($subnetData, $octet[$i]) !== $i * 4) { + break; + } + } + + $host = explode("/", $subnetData); + $binaryHost = ""; + $tmp = explode(".", $host[0]); + for ($i = 0; $i < 4 ; $i++) { + $binaryHost .= str_pad(decbin($tmp[$i]), 8, "0", STR_PAD_LEFT); + } + + $segmentData = array( + 'network' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 0)), + 'broadcast' => (int)$this->_toIp(str_pad(substr($binaryHost, 0, $host[1]), 32, 1)) + ); + + for ($j = $i; $j < 4; $j++) { + if ((int)$octet[$j] < $segmentData['network'][$j] || + (int)$octet[$j] > $segmentData['broadcast'][$j]) { + return false; + } + } + } + + return true; + } else { + return false; + } + } + + /** + * Converts a binary string to an IP address + * + * @param string $binary + * @return mixed + */ + private function _toIp($binary) + { + $ip = array(); + $tmp = explode(".", chunk_split($binary, 8, ".")); + for ($i = 0; $i < 4 ; $i++) { + $ip[$i] = bindec($tmp[$i]); + } + + return $ip; + } + + /** + * Internal method to validate the local part of the email address + * + * @return boolean + */ + private function _validateLocalPart() + { + // First try to match the local part on the common dot-atom format + $result = false; + + // Dot-atom characters are: 1*atext *("." 1*atext) + // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*", + // "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~" + $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d\x7e'; + if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) { + $result = true; + } else { + // Try quoted string format (RFC 5321 Chapter 4.1.2) + + // Quoted-string characters are: DQUOTE *(qtext/quoted-pair) DQUOTE + $qtext = '\x20-\x21\x23-\x5b\x5d-\x7e'; // %d32-33 / %d35-91 / %d93-126 + $quotedPair = '\x20-\x7e'; // %d92 %d32-126 + if (preg_match('/^"(['. $qtext .']|\x5c[' . $quotedPair . '])*"$/', $this->localPart)) { + $result = true; + } else { + $this->_error(self::DOT_ATOM); + $this->_error(self::QUOTED_STRING); + $this->_error(self::INVALID_LOCAL_PART); + } + } + + return $result; + } + + /** + * Internal method to validate the servers MX records + * + * @return boolean + */ + private function _validateMXRecords() + { + $mxHosts = array(); + $result = getmxrr($this->_hostname, $mxHosts); + if (!$result) { + $this->_error(self::INVALID_MX_RECORD); + } else if ($this->_options['deep'] && function_exists('checkdnsrr')) { + $validAddress = false; + $reserved = true; + foreach ($mxHosts as $hostname) { + $res = $this->_isReserved($hostname); + if (!$res) { + $reserved = false; + } + + if (!$res + && (checkdnsrr($hostname, "A") + || checkdnsrr($hostname, "AAAA") + || checkdnsrr($hostname, "A6"))) { + $validAddress = true; + break; + } + } + + if (!$validAddress) { + $result = false; + if ($reserved) { + $this->_error(self::INVALID_SEGMENT); + } else { + $this->_error(self::INVALID_MX_RECORD); + } + } + } + + return $result; + } + + /** + * Internal method to validate the hostname part of the email address + * + * @return boolean + */ + private function _validateHostnamePart() + { + $hostname = $this->_options['hostname']->setTranslator($this->getTranslator()) + ->isValid($this->_hostname); + if (!$hostname) { + $this->_error(self::INVALID_HOSTNAME); + + // Get messages and errors from hostnameValidator + foreach ($this->_options['hostname']->getMessages() as $code => $message) { + $this->_messages[$code] = $message; + } + + foreach ($this->_options['hostname']->getErrors() as $error) { + $this->_errors[] = $error; + } + } else if ($this->_options['mx']) { + // MX check on hostname + $hostname = $this->_validateMXRecords(); + } + + return $hostname; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a valid email address + * according to RFC2822 + * + * @link http://www.ietf.org/rfc/rfc2822.txt RFC2822 + * @link http://www.columbia.edu/kermit/ascii.html US-ASCII characters + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $matches = array(); + $length = true; + $this->_setValue($value); + + // Split email address up and disallow '..' + if ((strpos($value, '..') !== false) or + (!preg_match('/^(.+)@([^@]+)$/', $value, $matches))) { + $this->_error(self::INVALID_FORMAT); + return false; + } + + $this->_localPart = $matches[1]; + $this->_hostname = $matches[2]; + + if ((strlen($this->_localPart) > 64) || (strlen($this->_hostname) > 255)) { + $length = false; + $this->_error(self::LENGTH_EXCEEDED); + } + + // Match hostname part + if ($this->_options['domain']) { + $hostname = $this->_validateHostnamePart(); + } + + $local = $this->_validateLocalPart(); + + // If both parts valid, return true + if ($local && $length) { + if (($this->_options['domain'] && $hostname) || !$this->_options['domain']) { + return true; + } + } + + return false; + } +} diff --git a/library/vendor/Zend/Validate/Exception.php b/library/vendor/Zend/Validate/Exception.php new file mode 100644 index 000000000..12d1e5c73 --- /dev/null +++ b/library/vendor/Zend/Validate/Exception.php @@ -0,0 +1,33 @@ + "Too many files, maximum '%max%' are allowed but '%count%' are given", + self::TOO_FEW => "Too few files, minimum '%min%' are expected but '%count%' are given", + ); + + /** + * @var array Error message template variables + */ + protected $_messageVariables = array( + 'min' => '_min', + 'max' => '_max', + 'count' => '_count' + ); + + /** + * Minimum file count + * + * If null, there is no minimum file count + * + * @var integer + */ + protected $_min; + + /** + * Maximum file count + * + * If null, there is no maximum file count + * + * @var integer|null + */ + protected $_max; + + /** + * Actual filecount + * + * @var integer + */ + protected $_count; + + /** + * Internal file array + * @var array + */ + protected $_files; + + /** + * Sets validator options + * + * Min limits the file count, when used with max=null it is the maximum file count + * It also accepts an array with the keys 'min' and 'max' + * + * If $options is a integer, it will be used as maximum file count + * As Array is accepts the following keys: + * 'min': Minimum filecount + * 'max': Maximum filecount + * + * @param integer|array|Zend_Config $options Options for the adapter + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options) || is_numeric($options)) { + $options = array('max' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + if (1 < func_num_args()) { + $options['min'] = func_get_arg(0); + $options['max'] = func_get_arg(1); + } + + if (isset($options['min'])) { + $this->setMin($options); + } + + if (isset($options['max'])) { + $this->setMax($options); + } + } + + /** + * Returns the minimum file count + * + * @return integer + */ + public function getMin() + { + return $this->_min; + } + + /** + * Sets the minimum file count + * + * @param integer|array $min The minimum file count + * @return Zend_Validate_File_Count Provides a fluent interface + * @throws Zend_Validate_Exception When min is greater than max + */ + public function setMin($min) + { + if (is_array($min) and isset($min['min'])) { + $min = $min['min']; + } + + if (!is_string($min) and !is_numeric($min)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + $min = (integer) $min; + if (($this->_max !== null) && ($min > $this->_max)) { + throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum file count, but $min >" + . " {$this->_max}"); + } + + $this->_min = $min; + return $this; + } + + /** + * Returns the maximum file count + * + * @return integer + */ + public function getMax() + { + return $this->_max; + } + + /** + * Sets the maximum file count + * + * @param integer|array $max The maximum file count + * @return Zend_Validate_StringLength Provides a fluent interface + * @throws Zend_Validate_Exception When max is smaller than min + */ + public function setMax($max) + { + if (is_array($max) and isset($max['max'])) { + $max = $max['max']; + } + + if (!is_string($max) and !is_numeric($max)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + $max = (integer) $max; + if (($this->_min !== null) && ($max < $this->_min)) { + throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum file count, but " + . "$max < {$this->_min}"); + } + + $this->_max = $max; + return $this; + } + + /** + * Adds a file for validation + * + * @param string|array $file + */ + public function addFile($file) + { + if (is_string($file)) { + $file = array($file); + } + + if (is_array($file)) { + foreach ($file as $name) { + if (!isset($this->_files[$name]) && !empty($name)) { + $this->_files[$name] = $name; + } + } + } + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the file count of all checked files is at least min and + * not bigger than max (when max is not null). Attention: When checking with set min you + * must give all files with the first call, otherwise you will get an false. + * + * @param string|array $value Filenames to check for count + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + if (($file !== null) && !array_key_exists('destination', $file)) { + $file['destination'] = dirname($value); + } + + if (($file !== null) && array_key_exists('tmp_name', $file)) { + $value = $file['destination'] . DIRECTORY_SEPARATOR . $file['name']; + } + + if (($file === null) || !empty($file['tmp_name'])) { + $this->addFile($value); + } + + $this->_count = count($this->_files); + if (($this->_max !== null) && ($this->_count > $this->_max)) { + return $this->_throw($file, self::TOO_MANY); + } + + if (($this->_min !== null) && ($this->_count < $this->_min)) { + return $this->_throw($file, self::TOO_FEW); + } + + return true; + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/Crc32.php b/library/vendor/Zend/Validate/File/Crc32.php new file mode 100644 index 000000000..c932d5fd9 --- /dev/null +++ b/library/vendor/Zend/Validate/File/Crc32.php @@ -0,0 +1,176 @@ + "File '%value%' does not match the given crc32 hashes", + self::NOT_DETECTED => "A crc32 hash could not be evaluated for the given file", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * Hash of the file + * + * @var string + */ + protected $_hash; + + /** + * Sets validator options + * + * @param string|array|Zend_Config $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_scalar($options)) { + $options = array('hash1' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception('Invalid options to validator provided'); + } + + $this->setCrc32($options); + } + + /** + * Returns all set crc32 hashes + * + * @return array + */ + public function getCrc32() + { + return $this->getHash(); + } + + /** + * Sets the crc32 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setHash($options) + { + if (!is_array($options)) { + $options = array($options); + } + + $options['algorithm'] = 'crc32'; + parent::setHash($options); + return $this; + } + + /** + * Sets the crc32 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setCrc32($options) + { + $this->setHash($options); + return $this; + } + + /** + * Adds the crc32 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addHash($options) + { + if (!is_array($options)) { + $options = array($options); + } + + $options['algorithm'] = 'crc32'; + parent::addHash($options); + return $this; + } + + /** + * Adds the crc32 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addCrc32($options) + { + $this->addHash($options); + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the given file confirms the set hash + * + * @param string $value Filename to check for hash + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + $hashes = array_unique(array_keys($this->_hash)); + $filehash = hash_file('crc32', $value); + if ($filehash === false) { + return $this->_throw($file, self::NOT_DETECTED); + } + + foreach($hashes as $hash) { + if ($filehash === $hash) { + return true; + } + } + + return $this->_throw($file, self::DOES_NOT_MATCH); + } +} diff --git a/library/vendor/Zend/Validate/File/ExcludeExtension.php b/library/vendor/Zend/Validate/File/ExcludeExtension.php new file mode 100644 index 000000000..7ad0e6f6d --- /dev/null +++ b/library/vendor/Zend/Validate/File/ExcludeExtension.php @@ -0,0 +1,92 @@ + "File '%value%' has a false extension", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the fileextension of $value is not included in the + * set extension list + * + * @param string $value Real file to check for extension + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + if ($file !== null) { + $info['extension'] = substr($file['name'], strrpos($file['name'], '.') + 1); + } else { + $info = pathinfo($value); + } + + $extensions = $this->getExtension(); + + if ($this->_case and (!in_array($info['extension'], $extensions))) { + return true; + } else if (!$this->_case) { + $found = false; + foreach ($extensions as $extension) { + if (strtolower($extension) == strtolower($info['extension'])) { + $found = true; + } + } + + if (!$found) { + return true; + } + } + + return $this->_throw($file, self::FALSE_EXTENSION); + } +} diff --git a/library/vendor/Zend/Validate/File/ExcludeMimeType.php b/library/vendor/Zend/Validate/File/ExcludeMimeType.php new file mode 100644 index 000000000..f12bc8daa --- /dev/null +++ b/library/vendor/Zend/Validate/File/ExcludeMimeType.php @@ -0,0 +1,99 @@ + "File '%value%' has a false mimetype of '%type%'", + self::NOT_DETECTED => "The mimetype of file '%value%' could not be detected", + self::NOT_READABLE => "File '%value%' is not readable or does not exist", + ); + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if the mimetype of the file does not matche the given ones. Also parts + * of mimetypes can be checked. If you give for example "image" all image + * mime types will not be accepted like "image/gif", "image/jpeg" and so on. + * + * @param string $value Real file to check for mimetype + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + if ($file === null) { + $file = array( + 'type' => null, + 'name' => $value + ); + } + + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_READABLE); + } + + $this->_type = $this->_detectMimeType($value); + + if (empty($this->_type) && $this->_headerCheck) { + $this->_type = $file['type']; + } + + if (empty($this->_type)) { + return $this->_throw($file, self::NOT_DETECTED); + } + + $mimetype = $this->getMimeType(true); + if (in_array($this->_type, $mimetype)) { + return $this->_throw($file, self::FALSE_TYPE); + } + + $types = explode('/', $this->_type); + $types = array_merge($types, explode('-', $this->_type)); + foreach($mimetype as $mime) { + if (in_array($mime, $types)) { + return $this->_throw($file, self::FALSE_TYPE); + } + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/File/Exists.php b/library/vendor/Zend/Validate/File/Exists.php new file mode 100644 index 000000000..153cead5d --- /dev/null +++ b/library/vendor/Zend/Validate/File/Exists.php @@ -0,0 +1,200 @@ + "File '%value%' does not exist", + ); + + /** + * Internal list of directories + * @var string + */ + protected $_directory = ''; + + /** + * @var array Error message template variables + */ + protected $_messageVariables = array( + 'directory' => '_directory' + ); + + /** + * Sets validator options + * + * @param string|array|Zend_Config $directory + * @return void + */ + public function __construct($directory = array()) + { + if ($directory instanceof Zend_Config) { + $directory = $directory->toArray(); + } else if (is_string($directory)) { + $directory = explode(',', $directory); + } else if (!is_array($directory)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + $this->setDirectory($directory); + } + + /** + * Returns the set file directories which are checked + * + * @param boolean $asArray Returns the values as array, when false an concated string is returned + * @return string + */ + public function getDirectory($asArray = false) + { + $asArray = (bool) $asArray; + $directory = (string) $this->_directory; + if ($asArray) { + $directory = explode(',', $directory); + } + + return $directory; + } + + /** + * Sets the file directory which will be checked + * + * @param string|array $directory The directories to validate + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function setDirectory($directory) + { + $this->_directory = null; + $this->addDirectory($directory); + return $this; + } + + /** + * Adds the file directory which will be checked + * + * @param string|array $directory The directory to add for validation + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function addDirectory($directory) + { + $directories = $this->getDirectory(true); + + if (is_string($directory)) { + $directory = explode(',', $directory); + } else if (!is_array($directory)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + foreach ($directory as $content) { + if (empty($content) || !is_string($content)) { + continue; + } + + $directories[] = trim($content); + } + $directories = array_unique($directories); + + // Sanity check to ensure no empty values + foreach ($directories as $key => $dir) { + if (empty($dir)) { + unset($directories[$key]); + } + } + + $this->_directory = implode(',', $directories); + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the file already exists in the set directories + * + * @param string $value Real file to check for existance + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + $directories = $this->getDirectory(true); + if (($file !== null) and (!empty($file['destination']))) { + $directories[] = $file['destination']; + } else if (!isset($file['name'])) { + $file['name'] = $value; + } + + $check = false; + foreach ($directories as $directory) { + if (empty($directory)) { + continue; + } + + $check = true; + if (!file_exists($directory . DIRECTORY_SEPARATOR . $file['name'])) { + return $this->_throw($file, self::DOES_NOT_EXIST); + } + } + + if (!$check) { + return $this->_throw($file, self::DOES_NOT_EXIST); + } + + return true; + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/Extension.php b/library/vendor/Zend/Validate/File/Extension.php new file mode 100644 index 000000000..7a6041f7a --- /dev/null +++ b/library/vendor/Zend/Validate/File/Extension.php @@ -0,0 +1,236 @@ + "File '%value%' has a false extension", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * Internal list of extensions + * @var string + */ + protected $_extension = ''; + + /** + * Validate case sensitive + * + * @var boolean + */ + protected $_case = false; + + /** + * @var array Error message template variables + */ + protected $_messageVariables = array( + 'extension' => '_extension' + ); + + /** + * Sets validator options + * + * @param string|array|Zend_Config $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (1 < func_num_args()) { + $case = func_get_arg(1); + $this->setCase($case); + } + + if (is_array($options) and isset($options['case'])) { + $this->setCase($options['case']); + unset($options['case']); + } + + $this->setExtension($options); + } + + /** + * Returns the case option + * + * @return boolean + */ + public function getCase() + { + return $this->_case; + } + + /** + * Sets the case to use + * + * @param boolean $case + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function setCase($case) + { + $this->_case = (boolean) $case; + return $this; + } + + /** + * Returns the set file extension + * + * @return array + */ + public function getExtension() + { + $extension = explode(',', $this->_extension); + + return $extension; + } + + /** + * Sets the file extensions + * + * @param string|array $extension The extensions to validate + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function setExtension($extension) + { + $this->_extension = null; + $this->addExtension($extension); + return $this; + } + + /** + * Adds the file extensions + * + * @param string|array $extension The extensions to add for validation + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function addExtension($extension) + { + $extensions = $this->getExtension(); + if (is_string($extension)) { + $extension = explode(',', $extension); + } + + foreach ($extension as $content) { + if (empty($content) || !is_string($content)) { + continue; + } + + $extensions[] = trim($content); + } + $extensions = array_unique($extensions); + + // Sanity check to ensure no empty values + foreach ($extensions as $key => $ext) { + if (empty($ext)) { + unset($extensions[$key]); + } + } + + $this->_extension = implode(',', $extensions); + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the fileextension of $value is included in the + * set extension list + * + * @param string $value Real file to check for extension + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + if ($file !== null) { + $info['extension'] = substr($file['name'], strrpos($file['name'], '.') + 1); + } else { + $info = pathinfo($value); + if (!array_key_exists('extension', $info)) { + // From the manual at http://php.net/pathinfo: + // "If the path does not have an extension, no extension element + // will be returned (see second example below)." + return false; + } + } + + $extensions = $this->getExtension(); + + if ($this->_case && (in_array($info['extension'], $extensions))) { + return true; + } else if (!$this->getCase()) { + foreach ($extensions as $extension) { + if (strtolower($extension) == strtolower($info['extension'])) { + return true; + } + } + } + + return $this->_throw($file, self::FALSE_EXTENSION); + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if (null !== $file) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/FilesSize.php b/library/vendor/Zend/Validate/File/FilesSize.php new file mode 100644 index 000000000..fcdbdf96f --- /dev/null +++ b/library/vendor/Zend/Validate/File/FilesSize.php @@ -0,0 +1,161 @@ + "All files in sum should have a maximum size of '%max%' but '%size%' were detected", + self::TOO_SMALL => "All files in sum should have a minimum size of '%min%' but '%size%' were detected", + self::NOT_READABLE => "One or more files can not be read", + ); + + /** + * Internal file array + * + * @var array + */ + protected $_files; + + /** + * Sets validator options + * + * Min limits the used diskspace for all files, when used with max=null it is the maximum filesize + * It also accepts an array with the keys 'min' and 'max' + * + * @param integer|array|Zend_Config $options Options for this validator + * @return void + */ + public function __construct($options) + { + $this->_files = array(); + $this->_setSize(0); + + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_scalar($options)) { + $options = array('max' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception('Invalid options to validator provided'); + } + + if (1 < func_num_args()) { + $argv = func_get_args(); + array_shift($argv); + $options['max'] = array_shift($argv); + if (!empty($argv)) { + $options['bytestring'] = array_shift($argv); + } + } + + parent::__construct($options); + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the disk usage of all files is at least min and + * not bigger than max (when max is not null). + * + * @param string|array $value Real file to check for size + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + if (is_string($value)) { + $value = array($value); + } + + $min = $this->getMin(true); + $max = $this->getMax(true); + $size = $this->_getSize(); + foreach ($value as $files) { + // Is file readable ? + if (!Zend_Loader::isReadable($files)) { + $this->_throw($file, self::NOT_READABLE); + continue; + } + + if (!isset($this->_files[$files])) { + $this->_files[$files] = $files; + } else { + // file already counted... do not count twice + continue; + } + + // limited to 2GB files + $size += @filesize($files); + $this->_size = $size; + if (($max !== null) && ($max < $size)) { + if ($this->useByteString()) { + $this->_max = $this->_toByteString($max); + $this->_size = $this->_toByteString($size); + $this->_throw($file, self::TOO_BIG); + $this->_max = $max; + $this->_size = $size; + } else { + $this->_throw($file, self::TOO_BIG); + } + } + } + + // Check that aggregate files are >= minimum size + if (($min !== null) && ($size < $min)) { + if ($this->useByteString()) { + $this->_min = $this->_toByteString($min); + $this->_size = $this->_toByteString($size); + $this->_throw($file, self::TOO_SMALL); + $this->_min = $min; + $this->_size = $size; + } else { + $this->_throw($file, self::TOO_SMALL); + } + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/File/Hash.php b/library/vendor/Zend/Validate/File/Hash.php new file mode 100644 index 000000000..2a669fd83 --- /dev/null +++ b/library/vendor/Zend/Validate/File/Hash.php @@ -0,0 +1,189 @@ + "File '%value%' does not match the given hashes", + self::NOT_DETECTED => "A hash could not be evaluated for the given file", + self::NOT_FOUND => "File '%value%' is not readable or does not exist" + ); + + /** + * Hash of the file + * + * @var string + */ + protected $_hash; + + /** + * Sets validator options + * + * @param string|array $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_scalar($options)) { + $options = array('hash1' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception('Invalid options to validator provided'); + } + + if (1 < func_num_args()) { + $options['algorithm'] = func_get_arg(1); + } + + $this->setHash($options); + } + + /** + * Returns the set hash values as array, the hash as key and the algorithm the value + * + * @return array + */ + public function getHash() + { + return $this->_hash; + } + + /** + * Sets the hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setHash($options) + { + $this->_hash = null; + $this->addHash($options); + + return $this; + } + + /** + * Adds the hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addHash($options) + { + if (is_string($options)) { + $options = array($options); + } else if (!is_array($options)) { + throw new Zend_Validate_Exception("False parameter given"); + } + + $known = hash_algos(); + if (!isset($options['algorithm'])) { + $algorithm = 'crc32'; + } else { + $algorithm = $options['algorithm']; + unset($options['algorithm']); + } + + if (!in_array($algorithm, $known)) { + throw new Zend_Validate_Exception("Unknown algorithm '{$algorithm}'"); + } + + foreach ($options as $value) { + $this->_hash[$value] = $algorithm; + } + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the given file confirms the set hash + * + * @param string $value Filename to check for hash + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + $algos = array_unique(array_values($this->_hash)); + $hashes = array_unique(array_keys($this->_hash)); + foreach ($algos as $algorithm) { + $filehash = hash_file($algorithm, $value); + if ($filehash === false) { + return $this->_throw($file, self::NOT_DETECTED); + } + + foreach($hashes as $hash) { + if ($filehash === $hash) { + return true; + } + } + } + + return $this->_throw($file, self::DOES_NOT_MATCH); + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/ImageSize.php b/library/vendor/Zend/Validate/File/ImageSize.php new file mode 100644 index 000000000..65e057d04 --- /dev/null +++ b/library/vendor/Zend/Validate/File/ImageSize.php @@ -0,0 +1,357 @@ + "Maximum allowed width for image '%value%' should be '%maxwidth%' but '%width%' detected", + self::WIDTH_TOO_SMALL => "Minimum expected width for image '%value%' should be '%minwidth%' but '%width%' detected", + self::HEIGHT_TOO_BIG => "Maximum allowed height for image '%value%' should be '%maxheight%' but '%height%' detected", + self::HEIGHT_TOO_SMALL => "Minimum expected height for image '%value%' should be '%minheight%' but '%height%' detected", + self::NOT_DETECTED => "The size of image '%value%' could not be detected", + self::NOT_READABLE => "File '%value%' is not readable or does not exist", + ); + + /** + * @var array Error message template variables + */ + protected $_messageVariables = array( + 'minwidth' => '_minwidth', + 'maxwidth' => '_maxwidth', + 'minheight' => '_minheight', + 'maxheight' => '_maxheight', + 'width' => '_width', + 'height' => '_height' + ); + + /** + * Minimum image width + * + * @var integer + */ + protected $_minwidth; + + /** + * Maximum image width + * + * @var integer + */ + protected $_maxwidth; + + /** + * Minimum image height + * + * @var integer + */ + protected $_minheight; + + /** + * Maximum image height + * + * @var integer + */ + protected $_maxheight; + + /** + * Detected width + * + * @var integer + */ + protected $_width; + + /** + * Detected height + * + * @var integer + */ + protected $_height; + + /** + * Sets validator options + * + * Accepts the following option keys: + * - minheight + * - minwidth + * - maxheight + * - maxwidth + * + * @param Zend_Config|array $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (1 < func_num_args()) { + if (!is_array($options)) { + $options = array('minwidth' => $options); + } + $argv = func_get_args(); + array_shift($argv); + $options['minheight'] = array_shift($argv); + if (!empty($argv)) { + $options['maxwidth'] = array_shift($argv); + if (!empty($argv)) { + $options['maxheight'] = array_shift($argv); + } + } + } else if (!is_array($options)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + if (isset($options['minheight']) || isset($options['minwidth'])) { + $this->setImageMin($options); + } + + if (isset($options['maxheight']) || isset($options['maxwidth'])) { + $this->setImageMax($options); + } + } + + /** + * Returns the set minimum image sizes + * + * @return array + */ + public function getImageMin() + { + return array('minwidth' => $this->_minwidth, 'minheight' => $this->_minheight); + } + + /** + * Returns the set maximum image sizes + * + * @return array + */ + public function getImageMax() + { + return array('maxwidth' => $this->_maxwidth, 'maxheight' => $this->_maxheight); + } + + /** + * Returns the set image width sizes + * + * @return array + */ + public function getImageWidth() + { + return array('minwidth' => $this->_minwidth, 'maxwidth' => $this->_maxwidth); + } + + /** + * Returns the set image height sizes + * + * @return array + */ + public function getImageHeight() + { + return array('minheight' => $this->_minheight, 'maxheight' => $this->_maxheight); + } + + /** + * Sets the minimum image size + * + * @param array $options The minimum image dimensions + * @throws Zend_Validate_Exception When minwidth is greater than maxwidth + * @throws Zend_Validate_Exception When minheight is greater than maxheight + * @return Zend_Validate_File_ImageSize Provides a fluent interface + */ + public function setImageMin($options) + { + if (isset($options['minwidth'])) { + if (($this->_maxwidth !== null) and ($options['minwidth'] > $this->_maxwidth)) { + throw new Zend_Validate_Exception("The minimum image width must be less than or equal to the " + . " maximum image width, but {$options['minwidth']} > {$this->_maxwidth}"); + } + } + + if (isset($options['maxheight'])) { + if (($this->_maxheight !== null) and ($options['minheight'] > $this->_maxheight)) { + throw new Zend_Validate_Exception("The minimum image height must be less than or equal to the " + . " maximum image height, but {$options['minheight']} > {$this->_maxheight}"); + } + } + + if (isset($options['minwidth'])) { + $this->_minwidth = (int) $options['minwidth']; + } + + if (isset($options['minheight'])) { + $this->_minheight = (int) $options['minheight']; + } + + return $this; + } + + /** + * Sets the maximum image size + * + * @param array $options The maximum image dimensions + * @throws Zend_Validate_Exception When maxwidth is smaller than minwidth + * @throws Zend_Validate_Exception When maxheight is smaller than minheight + * @return Zend_Validate_StringLength Provides a fluent interface + */ + public function setImageMax($options) + { + if (isset($options['maxwidth'])) { + if (($this->_minwidth !== null) and ($options['maxwidth'] < $this->_minwidth)) { + throw new Zend_Validate_Exception("The maximum image width must be greater than or equal to the " + . "minimum image width, but {$options['maxwidth']} < {$this->_minwidth}"); + } + } + + if (isset($options['maxheight'])) { + if (($this->_minheight !== null) and ($options['maxheight'] < $this->_minheight)) { + throw new Zend_Validate_Exception("The maximum image height must be greater than or equal to the " + . "minimum image height, but {$options['maxheight']} < {$this->_minwidth}"); + } + } + + if (isset($options['maxwidth'])) { + $this->_maxwidth = (int) $options['maxwidth']; + } + + if (isset($options['maxheight'])) { + $this->_maxheight = (int) $options['maxheight']; + } + + return $this; + } + + /** + * Sets the mimimum and maximum image width + * + * @param array $options The image width dimensions + * @return Zend_Validate_File_ImageSize Provides a fluent interface + */ + public function setImageWidth($options) + { + $this->setImageMin($options); + $this->setImageMax($options); + + return $this; + } + + /** + * Sets the mimimum and maximum image height + * + * @param array $options The image height dimensions + * @return Zend_Validate_File_ImageSize Provides a fluent interface + */ + public function setImageHeight($options) + { + $this->setImageMin($options); + $this->setImageMax($options); + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the imagesize of $value is at least min and + * not bigger than max + * + * @param string $value Real file to check for image size + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_READABLE); + } + + $size = @getimagesize($value); + $this->_setValue($file); + + if (empty($size) or ($size[0] === 0) or ($size[1] === 0)) { + return $this->_throw($file, self::NOT_DETECTED); + } + + $this->_width = $size[0]; + $this->_height = $size[1]; + if ($this->_width < $this->_minwidth) { + $this->_throw($file, self::WIDTH_TOO_SMALL); + } + + if (($this->_maxwidth !== null) and ($this->_maxwidth < $this->_width)) { + $this->_throw($file, self::WIDTH_TOO_BIG); + } + + if ($this->_height < $this->_minheight) { + $this->_throw($file, self::HEIGHT_TOO_SMALL); + } + + if (($this->_maxheight !== null) and ($this->_maxheight < $this->_height)) { + $this->_throw($file, self::HEIGHT_TOO_BIG); + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/IsCompressed.php b/library/vendor/Zend/Validate/File/IsCompressed.php new file mode 100644 index 000000000..2478b4f0b --- /dev/null +++ b/library/vendor/Zend/Validate/File/IsCompressed.php @@ -0,0 +1,149 @@ + "File '%value%' is not compressed, '%type%' detected", + self::NOT_DETECTED => "The mimetype of file '%value%' could not be detected", + self::NOT_READABLE => "File '%value%' is not readable or does not exist", + ); + + /** + * Sets validator options + * + * @param string|array|Zend_Config $compression + * @return void + */ + public function __construct($mimetype = array()) + { + if ($mimetype instanceof Zend_Config) { + $mimetype = $mimetype->toArray(); + } + + $temp = array(); + // http://de.wikipedia.org/wiki/Liste_von_Dateiendungen + $default = array( + 'application/arj', + 'application/gnutar', + 'application/lha', + 'application/lzx', + 'application/vnd.ms-cab-compressed', + 'application/x-ace-compressed', + 'application/x-arc', + 'application/x-archive', + 'application/x-arj', + 'application/x-bzip', + 'application/x-bzip2', + 'application/x-cab-compressed', + 'application/x-compress', + 'application/x-compressed', + 'application/x-cpio', + 'application/x-debian-package', + 'application/x-eet', + 'application/x-gzip', + 'application/x-java-pack200', + 'application/x-lha', + 'application/x-lharc', + 'application/x-lzh', + 'application/x-lzma', + 'application/x-lzx', + 'application/x-rar', + 'application/x-sit', + 'application/x-stuffit', + 'application/x-tar', + 'application/zip', + 'application/x-zip', + 'application/zoo', + 'multipart/x-gzip', + ); + + if (is_array($mimetype)) { + $temp = $mimetype; + if (array_key_exists('magicfile', $temp)) { + unset($temp['magicfile']); + } + + if (array_key_exists('headerCheck', $temp)) { + unset($temp['headerCheck']); + } + + if (empty($temp)) { + $mimetype += $default; + } + } + + if (empty($mimetype)) { + $mimetype = $default; + } + + parent::__construct($mimetype); + } + + /** + * Throws an error of the given type + * Duplicates parent method due to OOP Problem with late static binding in PHP 5.2 + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + $this->_value = $file['name']; + switch($errorType) { + case Zend_Validate_File_MimeType::FALSE_TYPE : + $errorType = self::FALSE_TYPE; + break; + case Zend_Validate_File_MimeType::NOT_DETECTED : + $errorType = self::NOT_DETECTED; + break; + case Zend_Validate_File_MimeType::NOT_READABLE : + $errorType = self::NOT_READABLE; + break; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/IsImage.php b/library/vendor/Zend/Validate/File/IsImage.php new file mode 100644 index 000000000..4fe2dce48 --- /dev/null +++ b/library/vendor/Zend/Validate/File/IsImage.php @@ -0,0 +1,172 @@ + "File '%value%' is no image, '%type%' detected", + self::NOT_DETECTED => "The mimetype of file '%value%' could not be detected", + self::NOT_READABLE => "File '%value%' is not readable or does not exist", + ); + + /** + * Sets validator options + * + * @param string|array|Zend_Config $mimetype + * @return void + */ + public function __construct($mimetype = array()) + { + if ($mimetype instanceof Zend_Config) { + $mimetype = $mimetype->toArray(); + } + + $temp = array(); + // http://de.wikipedia.org/wiki/Liste_von_Dateiendungen + // http://www.iana.org/assignments/media-types/image/ + $default = array( + 'application/cdf', + 'application/dicom', + 'application/fractals', + 'application/postscript', + 'application/vnd.hp-hpgl', + 'application/vnd.oasis.opendocument.graphics', + 'application/x-cdf', + 'application/x-cmu-raster', + 'application/x-ima', + 'application/x-inventor', + 'application/x-koan', + 'application/x-portable-anymap', + 'application/x-world-x-3dmf', + 'image/bmp', + 'image/c', + 'image/cgm', + 'image/fif', + 'image/gif', + 'image/jpeg', + 'image/jpm', + 'image/jpx', + 'image/jp2', + 'image/naplps', + 'image/pjpeg', + 'image/png', + 'image/svg', + 'image/svg+xml', + 'image/tiff', + 'image/vnd.adobe.photoshop', + 'image/vnd.djvu', + 'image/vnd.fpx', + 'image/vnd.net-fpx', + 'image/x-cmu-raster', + 'image/x-cmx', + 'image/x-coreldraw', + 'image/x-cpi', + 'image/x-emf', + 'image/x-ico', + 'image/x-icon', + 'image/x-jg', + 'image/x-ms-bmp', + 'image/x-niff', + 'image/x-pict', + 'image/x-pcx', + 'image/x-portable-anymap', + 'image/x-portable-bitmap', + 'image/x-portable-greymap', + 'image/x-portable-pixmap', + 'image/x-quicktime', + 'image/x-rgb', + 'image/x-tiff', + 'image/x-unknown', + 'image/x-windows-bmp', + 'image/x-xpmi', + ); + + if (is_array($mimetype)) { + $temp = $mimetype; + if (array_key_exists('magicfile', $temp)) { + unset($temp['magicfile']); + } + + if (array_key_exists('headerCheck', $temp)) { + unset($temp['headerCheck']); + } + + if (empty($temp)) { + $mimetype += $default; + } + } + + if (empty($mimetype)) { + $mimetype = $default; + } + + parent::__construct($mimetype); + } + + /** + * Throws an error of the given type + * Duplicates parent method due to OOP Problem with late static binding in PHP 5.2 + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + $this->_value = $file['name']; + switch($errorType) { + case Zend_Validate_File_MimeType::FALSE_TYPE : + $errorType = self::FALSE_TYPE; + break; + case Zend_Validate_File_MimeType::NOT_DETECTED : + $errorType = self::NOT_DETECTED; + break; + case Zend_Validate_File_MimeType::NOT_READABLE : + $errorType = self::NOT_READABLE; + break; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/Md5.php b/library/vendor/Zend/Validate/File/Md5.php new file mode 100644 index 000000000..2e3d6e2b3 --- /dev/null +++ b/library/vendor/Zend/Validate/File/Md5.php @@ -0,0 +1,180 @@ + "File '%value%' does not match the given md5 hashes", + self::NOT_DETECTED => "A md5 hash could not be evaluated for the given file", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * Hash of the file + * + * @var string + */ + protected $_hash; + + /** + * Sets validator options + * + * $hash is the hash we accept for the file $file + * + * @param string|array $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_scalar($options)) { + $options = array('hash1' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception('Invalid options to validator provided'); + } + + $this->setMd5($options); + } + + /** + * Returns all set md5 hashes + * + * @return array + */ + public function getMd5() + { + return $this->getHash(); + } + + /** + * Sets the md5 hash for one or multiple files + * + * @param string|array $options + * @param string $algorithm (Deprecated) Algorithm to use, fixed to md5 + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setHash($options) + { + if (!is_array($options)) { + $options = (array) $options; + } + + $options['algorithm'] = 'md5'; + parent::setHash($options); + return $this; + } + + /** + * Sets the md5 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setMd5($options) + { + $this->setHash($options); + return $this; + } + + /** + * Adds the md5 hash for one or multiple files + * + * @param string|array $options + * @param string $algorithm (Deprecated) Algorithm to use, fixed to md5 + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addHash($options) + { + if (!is_array($options)) { + $options = (array) $options; + } + + $options['algorithm'] = 'md5'; + parent::addHash($options); + return $this; + } + + /** + * Adds the md5 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addMd5($options) + { + $this->addHash($options); + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the given file confirms the set hash + * + * @param string $value Filename to check for hash + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + $hashes = array_unique(array_keys($this->_hash)); + $filehash = hash_file('md5', $value); + if ($filehash === false) { + return $this->_throw($file, self::NOT_DETECTED); + } + + foreach($hashes as $hash) { + if ($filehash === $hash) { + return true; + } + } + + return $this->_throw($file, self::DOES_NOT_MATCH); + } +} diff --git a/library/vendor/Zend/Validate/File/MimeType.php b/library/vendor/Zend/Validate/File/MimeType.php new file mode 100644 index 000000000..57d86703c --- /dev/null +++ b/library/vendor/Zend/Validate/File/MimeType.php @@ -0,0 +1,469 @@ + "File '%value%' has a false mimetype of '%type%'", + self::NOT_DETECTED => "The mimetype of file '%value%' could not be detected", + self::NOT_READABLE => "File '%value%' is not readable or does not exist", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'type' => '_type' + ); + + /** + * @var string + */ + protected $_type; + + /** + * Mimetypes + * + * If null, there is no mimetype + * + * @var string|null + */ + protected $_mimetype; + + /** + * Magicfile to use + * + * @var string|null + */ + protected $_magicfile; + + /** + * Finfo object to use + * + * @var resource + */ + protected $_finfo; + + /** + * If no $_ENV['MAGIC'] is set, try and autodiscover it based on common locations + * @var array + */ + protected $_magicFiles = array( + '/usr/share/misc/magic', + '/usr/share/misc/magic.mime', + '/usr/share/misc/magic.mgc', + '/usr/share/mime/magic', + '/usr/share/mime/magic.mime', + '/usr/share/mime/magic.mgc', + '/usr/share/file/magic', + '/usr/share/file/magic.mime', + '/usr/share/file/magic.mgc', + ); + + /** + * Indicates whether use of $_magicFiles should be attempted. + * @var boolean + */ + protected $_tryCommonMagicFiles = true; + + /** + * Option to allow header check + * + * @var boolean + */ + protected $_headerCheck = false; + + /** + * Holds error information returned by finfo_open + * + * @var array + */ + protected $_finfoError; + + /** + * Sets validator options + * + * Mimetype to accept + * + * @param string|array $mimetype MimeType + * @return void + */ + public function __construct($mimetype) + { + if ($mimetype instanceof Zend_Config) { + $mimetype = $mimetype->toArray(); + } elseif (is_string($mimetype)) { + $mimetype = explode(',', $mimetype); + } elseif (!is_array($mimetype)) { + throw new Zend_Validate_Exception("Invalid options to validator provided"); + } + + if (isset($mimetype['magicfile'])) { + $this->setMagicFile($mimetype['magicfile']); + unset($mimetype['magicfile']); + } + + if (isset($mimetype['headerCheck'])) { + $this->enableHeaderCheck($mimetype['headerCheck']); + unset($mimetype['headerCheck']); + } + + $this->setMimeType($mimetype); + } + + /** + * Returns the actual set magicfile + * + * Note that for PHP 5.3.0 or higher, we don't use $_ENV['MAGIC'] or try to + * find a magic file in a common location as PHP now has a built-in internal + * magic file. + * + * @return string + */ + public function getMagicFile() + { + if (version_compare(PHP_VERSION, '5.3.0', '<') + && null === $this->_magicfile) { + if (!empty($_ENV['MAGIC'])) { + $this->setMagicFile($_ENV['MAGIC']); + } elseif ( + !(@ini_get("safe_mode") == 'On' || @ini_get("safe_mode") === 1) + && $this->shouldTryCommonMagicFiles() // @see ZF-11784 + ) { + foreach ($this->_magicFiles as $file) { + // supressing errors which are thrown due to openbase_dir restrictions + try { + $this->setMagicFile($file); + if ($this->_magicfile !== null) { + break; + } + } catch (Zend_Validate_Exception $e) { + // Intentionally, catch and fall through + } + } + } + + if ($this->_magicfile === null) { + $this->_magicfile = false; + } + } + + return $this->_magicfile; + } + + /** + * Sets the magicfile to use + * if null, the MAGIC constant from php is used + * if the MAGIC file is errorous, no file will be set + * + * @param string $file + * @throws Zend_Validate_Exception When finfo can not read the magicfile + * @return Zend_Validate_File_MimeType Provides fluid interface + */ + public function setMagicFile($file) + { + if (empty($file)) { + $this->_magicfile = null; + } else if (!(class_exists('finfo', false))) { + $this->_magicfile = null; + throw new Zend_Validate_Exception('Magicfile can not be set. There is no finfo extension installed'); + } else if (!is_file($file) || !is_readable($file)) { + throw new Zend_Validate_Exception('The given magicfile can not be read'); + } else { + $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; + set_error_handler(array($this, '_errorHandler'), E_NOTICE | E_WARNING); + $this->_finfo = finfo_open($const, $file); + restore_error_handler(); + if (empty($this->_finfo)) { + $this->_finfo = null; + throw new Zend_Validate_Exception( + sprintf('The given magicfile ("%s") is not accepted by finfo', $file), + null, + $this->_finfoError + ); + } else { + $this->_magicfile = $file; + } + } + + return $this; + } + + /** + * Enables or disables attempts to try the common magic file locations + * specified by Zend_Validate_File_MimeType::_magicFiles + * + * @param boolean $flag + * @return Zend_Validate_File_MimeType Provides fluent interface + * @see http://framework.zend.com/issues/browse/ZF-11784 + */ + public function setTryCommonMagicFilesFlag($flag = true) + { + $this->_tryCommonMagicFiles = (boolean) $flag; + + return $this; + } + + /** + * Accessor for Zend_Validate_File_MimeType::_magicFiles + * + * @return boolean + * @see http://framework.zend.com/issues/browse/ZF-11784 + */ + public function shouldTryCommonMagicFiles() + { + return $this->_tryCommonMagicFiles; + } + + /** + * Returns the Header Check option + * + * @return boolean + */ + public function getHeaderCheck() + { + return $this->_headerCheck; + } + + /** + * Defines if the http header should be used + * Note that this is unsave and therefor the default value is false + * + * @param boolean $checkHeader + * @return Zend_Validate_File_MimeType Provides fluid interface + */ + public function enableHeaderCheck($headerCheck = true) + { + $this->_headerCheck = (boolean) $headerCheck; + return $this; + } + + /** + * Returns the set mimetypes + * + * @param boolean $asArray Returns the values as array, when false an concated string is returned + * @return string|array + */ + public function getMimeType($asArray = false) + { + $asArray = (bool) $asArray; + $mimetype = (string) $this->_mimetype; + if ($asArray) { + $mimetype = explode(',', $mimetype); + } + + return $mimetype; + } + + /** + * Sets the mimetypes + * + * @param string|array $mimetype The mimetypes to validate + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function setMimeType($mimetype) + { + $this->_mimetype = null; + $this->addMimeType($mimetype); + return $this; + } + + /** + * Adds the mimetypes + * + * @param string|array $mimetype The mimetypes to add for validation + * @return Zend_Validate_File_Extension Provides a fluent interface + */ + public function addMimeType($mimetype) + { + $mimetypes = $this->getMimeType(true); + + if (is_string($mimetype)) { + $mimetype = explode(',', $mimetype); + } elseif (!is_array($mimetype)) { + throw new Zend_Validate_Exception("Invalid options to validator provided"); + } + + if (isset($mimetype['magicfile'])) { + unset($mimetype['magicfile']); + } + + foreach ($mimetype as $content) { + if (empty($content) || !is_string($content)) { + continue; + } + $mimetypes[] = trim($content); + } + $mimetypes = array_unique($mimetypes); + + // Sanity check to ensure no empty values + foreach ($mimetypes as $key => $mt) { + if (empty($mt)) { + unset($mimetypes[$key]); + } + } + + $this->_mimetype = implode(',', $mimetypes); + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if the mimetype of the file matches the given ones. Also parts + * of mimetypes can be checked. If you give for example "image" all image + * mime types will be accepted like "image/gif", "image/jpeg" and so on. + * + * @param string $value Real file to check for mimetype + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + if ($file === null) { + $file = array( + 'type' => null, + 'name' => $value + ); + } + + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_READABLE); + } + + $this->_type = $this->_detectMimeType($value); + + if (empty($this->_type) && $this->_headerCheck) { + $this->_type = $file['type']; + } + + if (empty($this->_type)) { + return $this->_throw($file, self::NOT_DETECTED); + } + + $mimetype = $this->getMimeType(true); + if (in_array($this->_type, $mimetype)) { + return true; + } + + $types = explode('/', $this->_type); + $types = array_merge($types, explode('-', $this->_type)); + $types = array_merge($types, explode(';', $this->_type)); + foreach($mimetype as $mime) { + if (in_array($mime, $types)) { + return true; + } + } + + return $this->_throw($file, self::FALSE_TYPE); + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + $this->_value = $file['name']; + $this->_error($errorType); + return false; + } + + /** + * Try to detect mime type of given file. + * @param string $file File which mime type should be detected + * @return string File mime type or null if not detected + */ + protected function _detectMimeType($file) + { + $mimefile = $this->getMagicFile(); + $type = null; + + if (class_exists('finfo', false)) { + $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; + + if (!empty($mimefile) && empty($this->_finfo)) { + set_error_handler(array($this, '_errorHandler'), E_NOTICE | E_WARNING); + $this->_finfo = finfo_open($const, $mimefile); + restore_error_handler(); + } + + if (empty($this->_finfo)) { + set_error_handler(array($this, '_errorHandler'), E_NOTICE | E_WARNING); + $this->_finfo = finfo_open($const); + restore_error_handler(); + } + + if (!empty($this->_finfo)) { + $type = finfo_file($this->_finfo, $file); + } + } + + if (empty($type) && + (function_exists('mime_content_type') && ini_get('mime_magic.magicfile'))) { + $type = mime_content_type($file); + } + + return $type; + } + + /** + * Saves the provided error information by finfo_open to this instance + * + * @param integer $errno + * @param string $errstr + * @param string $errfile + * @param integer $errline + * @param array $errcontext + * @return void + */ + protected function _errorHandler($errno, $errstr, $errfile, $errline) + { + $this->_finfoError = new ErrorException($errstr, $errno, 0, $errfile, $errline); + } +} diff --git a/library/vendor/Zend/Validate/File/NotExists.php b/library/vendor/Zend/Validate/File/NotExists.php new file mode 100644 index 000000000..033756140 --- /dev/null +++ b/library/vendor/Zend/Validate/File/NotExists.php @@ -0,0 +1,83 @@ + "File '%value%' exists", + ); + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the file does not exist in the set destinations + * + * @param string $value Real file to check for + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + $directories = $this->getDirectory(true); + if (($file !== null) and (!empty($file['destination']))) { + $directories[] = $file['destination']; + } else if (!isset($file['name'])) { + $file['name'] = $value; + } + + foreach ($directories as $directory) { + if (empty($directory)) { + continue; + } + + $check = true; + if (file_exists($directory . DIRECTORY_SEPARATOR . $file['name'])) { + return $this->_throw($file, self::DOES_EXIST); + } + } + + if (!isset($check)) { + return $this->_throw($file, self::DOES_EXIST); + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/File/Sha1.php b/library/vendor/Zend/Validate/File/Sha1.php new file mode 100644 index 000000000..6d78cac2e --- /dev/null +++ b/library/vendor/Zend/Validate/File/Sha1.php @@ -0,0 +1,178 @@ + "File '%value%' does not match the given sha1 hashes", + self::NOT_DETECTED => "A sha1 hash could not be evaluated for the given file", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * Hash of the file + * + * @var string + */ + protected $_hash; + + /** + * Sets validator options + * + * $hash is the hash we accept for the file $file + * + * @param string|array $options + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_scalar($options)) { + $options = array('hash1' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception('Invalid options to validator provided'); + } + + $this->setHash($options); + } + + /** + * Returns all set sha1 hashes + * + * @return array + */ + public function getSha1() + { + return $this->getHash(); + } + + /** + * Sets the sha1 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setHash($options) + { + if (!is_array($options)) { + $options = (array) $options; + } + + $options['algorithm'] = 'sha1'; + parent::setHash($options); + return $this; + } + + /** + * Sets the sha1 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function setSha1($options) + { + $this->setHash($options); + return $this; + } + + /** + * Adds the sha1 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addHash($options) + { + if (!is_array($options)) { + $options = (array) $options; + } + + $options['algorithm'] = 'sha1'; + parent::addHash($options); + return $this; + } + + /** + * Adds the sha1 hash for one or multiple files + * + * @param string|array $options + * @return Zend_Validate_File_Hash Provides a fluent interface + */ + public function addSha1($options) + { + $this->addHash($options); + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the given file confirms the set hash + * + * @param string $value Filename to check for hash + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + $hashes = array_unique(array_keys($this->_hash)); + $filehash = hash_file('sha1', $value); + if ($filehash === false) { + return $this->_throw($file, self::NOT_DETECTED); + } + + foreach ($hashes as $hash) { + if ($filehash === $hash) { + return true; + } + } + + return $this->_throw($file, self::DOES_NOT_MATCH); + } +} diff --git a/library/vendor/Zend/Validate/File/Size.php b/library/vendor/Zend/Validate/File/Size.php new file mode 100644 index 000000000..af3a0128b --- /dev/null +++ b/library/vendor/Zend/Validate/File/Size.php @@ -0,0 +1,397 @@ + "Maximum allowed size for file '%value%' is '%max%' but '%size%' detected", + self::TOO_SMALL => "Minimum expected size for file '%value%' is '%min%' but '%size%' detected", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * @var array Error message template variables + */ + protected $_messageVariables = array( + 'min' => '_min', + 'max' => '_max', + 'size' => '_size', + ); + + /** + * Minimum filesize + * @var integer + */ + protected $_min; + + /** + * Maximum filesize + * + * If null, there is no maximum filesize + * + * @var integer|null + */ + protected $_max; + + /** + * Detected size + * + * @var integer + */ + protected $_size; + + /** + * Use bytestring ? + * + * @var boolean + */ + protected $_useByteString = true; + + /** + * Sets validator options + * + * If $options is a integer, it will be used as maximum filesize + * As Array is accepts the following keys: + * 'min': Minimum filesize + * 'max': Maximum filesize + * 'bytestring': Use bytestring or real size for messages + * + * @param integer|array $options Options for the adapter + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } elseif (is_string($options) || is_numeric($options)) { + $options = array('max' => $options); + } elseif (!is_array($options)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + if (1 < func_num_args()) { + $argv = func_get_args(); + array_shift($argv); + $options['max'] = array_shift($argv); + if (!empty($argv)) { + $options['bytestring'] = array_shift($argv); + } + } + + if (isset($options['bytestring'])) { + $this->setUseByteString($options['bytestring']); + } + + if (isset($options['min'])) { + $this->setMin($options['min']); + } + + if (isset($options['max'])) { + $this->setMax($options['max']); + } + } + + /** + * Returns the minimum filesize + * + * @param boolean $byteString Use bytestring ? + * @return integer + */ + public function setUseByteString($byteString = true) + { + $this->_useByteString = (bool) $byteString; + return $this; + } + + /** + * Will bytestring be used? + * + * @return boolean + */ + public function useByteString() + { + return $this->_useByteString; + } + + /** + * Returns the minimum filesize + * + * @param bool $raw Whether or not to force return of the raw value (defaults off) + * @return integer|string + */ + public function getMin($raw = false) + { + $min = $this->_min; + if (!$raw && $this->useByteString()) { + $min = $this->_toByteString($min); + } + + return $min; + } + + /** + * Sets the minimum filesize + * + * @param integer $min The minimum filesize + * @throws Zend_Validate_Exception When min is greater than max + * @return Zend_Validate_File_Size Provides a fluent interface + */ + public function setMin($min) + { + if (!is_string($min) and !is_numeric($min)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + $min = (integer) $this->_fromByteString($min); + $max = $this->getMax(true); + if (($max !== null) && ($min > $max)) { + throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum filesize, but $min >" + . " $max"); + } + + $this->_min = $min; + return $this; + } + + /** + * Returns the maximum filesize + * + * @param bool $raw Whether or not to force return of the raw value (defaults off) + * @return integer|string + */ + public function getMax($raw = false) + { + $max = $this->_max; + if (!$raw && $this->useByteString()) { + $max = $this->_toByteString($max); + } + + return $max; + } + + /** + * Sets the maximum filesize + * + * @param integer $max The maximum filesize + * @throws Zend_Validate_Exception When max is smaller than min + * @return Zend_Validate_StringLength Provides a fluent interface + */ + public function setMax($max) + { + if (!is_string($max) && !is_numeric($max)) { + throw new Zend_Validate_Exception ('Invalid options to validator provided'); + } + + $max = (integer) $this->_fromByteString($max); + $min = $this->getMin(true); + if (($min !== null) && ($max < $min)) { + throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum filesize, but " + . "$max < $min"); + } + + $this->_max = $max; + return $this; + } + + /** + * Retrieve current detected file size + * + * @return int + */ + protected function _getSize() + { + return $this->_size; + } + + /** + * Set current size + * + * @param int $size + * @return Zend_Validate_File_Size + */ + protected function _setSize($size) + { + $this->_size = $size; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the filesize of $value is at least min and + * not bigger than max (when max is not null). + * + * @param string $value Real file to check for size + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + // limited to 4GB files + $size = sprintf("%u", @filesize($value)); + $this->_size = $size; + + // Check to see if it's smaller than min size + $min = $this->getMin(true); + $max = $this->getMax(true); + if (($min !== null) && ($size < $min)) { + if ($this->useByteString()) { + $this->_min = $this->_toByteString($min); + $this->_size = $this->_toByteString($size); + $this->_throw($file, self::TOO_SMALL); + $this->_min = $min; + $this->_size = $size; + } else { + $this->_throw($file, self::TOO_SMALL); + } + } + + // Check to see if it's larger than max size + if (($max !== null) && ($max < $size)) { + if ($this->useByteString()) { + $this->_max = $this->_toByteString($max); + $this->_size = $this->_toByteString($size); + $this->_throw($file, self::TOO_BIG); + $this->_max = $max; + $this->_size = $size; + } else { + $this->_throw($file, self::TOO_BIG); + } + } + + if (count($this->_messages) > 0) { + return false; + } + + return true; + } + + /** + * Returns the formatted size + * + * @param integer $size + * @return string + */ + protected function _toByteString($size) + { + $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + for ($i=0; $size >= 1024 && $i < 9; $i++) { + $size /= 1024; + } + + return round($size, 2) . $sizes[$i]; + } + + /** + * Returns the unformatted size + * + * @param string $size + * @return integer + */ + protected function _fromByteString($size) + { + if (is_numeric($size)) { + return (integer) $size; + } + + $type = trim(substr($size, -2, 1)); + + $value = substr($size, 0, -1); + if (!is_numeric($value)) { + $value = substr($value, 0, -1); + } + + switch (strtoupper($type)) { + case 'Y': + $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024); + break; + case 'Z': + $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024); + break; + case 'E': + $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024); + break; + case 'P': + $value *= (1024 * 1024 * 1024 * 1024 * 1024); + break; + case 'T': + $value *= (1024 * 1024 * 1024 * 1024); + break; + case 'G': + $value *= (1024 * 1024 * 1024); + break; + case 'M': + $value *= (1024 * 1024); + break; + case 'K': + $value *= 1024; + break; + default: + break; + } + + return $value; + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/Upload.php b/library/vendor/Zend/Validate/File/Upload.php new file mode 100644 index 000000000..842f1dc1e --- /dev/null +++ b/library/vendor/Zend/Validate/File/Upload.php @@ -0,0 +1,249 @@ + "File '%value%' exceeds the defined ini size", + self::FORM_SIZE => "File '%value%' exceeds the defined form size", + self::PARTIAL => "File '%value%' was only partially uploaded", + self::NO_FILE => "File '%value%' was not uploaded", + self::NO_TMP_DIR => "No temporary directory was found for file '%value%'", + self::CANT_WRITE => "File '%value%' can't be written", + self::EXTENSION => "A PHP extension returned an error while uploading the file '%value%'", + self::ATTACK => "File '%value%' was illegally uploaded. This could be a possible attack", + self::FILE_NOT_FOUND => "File '%value%' was not found", + self::UNKNOWN => "Unknown error while uploading file '%value%'" + ); + + /** + * Internal array of files + * @var array + */ + protected $_files = array(); + + /** + * Sets validator options + * + * The array $files must be given in syntax of Zend_File_Transfer to be checked + * If no files are given the $_FILES array will be used automatically. + * NOTE: This validator will only work with HTTP POST uploads! + * + * @param array|Zend_Config $files Array of files in syntax of Zend_File_Transfer + * @return void + */ + public function __construct($files = array()) + { + if ($files instanceof Zend_Config) { + $files = $files->toArray(); + } + + $this->setFiles($files); + } + + /** + * Returns the array of set files + * + * @param string $files (Optional) The file to return in detail + * @return array + * @throws Zend_Validate_Exception If file is not found + */ + public function getFiles($file = null) + { + if ($file !== null) { + $return = array(); + foreach ($this->_files as $name => $content) { + if ($name === $file) { + $return[$file] = $this->_files[$name]; + } + + if ($content['name'] === $file) { + $return[$name] = $this->_files[$name]; + } + } + + if (count($return) === 0) { + throw new Zend_Validate_Exception("The file '$file' was not found"); + } + + return $return; + } + + return $this->_files; + } + + /** + * Sets the files to be checked + * + * @param array $files The files to check in syntax of Zend_File_Transfer + * @return Zend_Validate_File_Upload Provides a fluent interface + */ + public function setFiles($files = array()) + { + if (count($files) === 0) { + $this->_files = $_FILES; + } else { + $this->_files = $files; + } + + // see ZF-10738 + if (is_null($this->_files)) { + $this->_files = array(); + } + + foreach($this->_files as $file => $content) { + if (!isset($content['error'])) { + unset($this->_files[$file]); + } + } + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the file was uploaded without errors + * + * @param string $value Single file to check for upload errors, when giving null the $_FILES array + * from initialization will be used + * @return boolean + */ + public function isValid($value, $file = null) + { + $this->_messages = null; + if (array_key_exists($value, $this->_files)) { + $files[$value] = $this->_files[$value]; + } else { + foreach ($this->_files as $file => $content) { + if (isset($content['name']) && ($content['name'] === $value)) { + $files[$file] = $this->_files[$file]; + } + + if (isset($content['tmp_name']) && ($content['tmp_name'] === $value)) { + $files[$file] = $this->_files[$file]; + } + } + } + + if (empty($files)) { + return $this->_throw($file, self::FILE_NOT_FOUND); + } + + foreach ($files as $file => $content) { + $this->_value = $file; + switch($content['error']) { + case 0: + if (!is_uploaded_file($content['tmp_name'])) { + $this->_throw($content, self::ATTACK); + } + break; + + case 1: + $this->_throw($content, self::INI_SIZE); + break; + + case 2: + $this->_throw($content, self::FORM_SIZE); + break; + + case 3: + $this->_throw($content, self::PARTIAL); + break; + + case 4: + $this->_throw($content, self::NO_FILE); + break; + + case 6: + $this->_throw($content, self::NO_TMP_DIR); + break; + + case 7: + $this->_throw($content, self::CANT_WRITE); + break; + + case 8: + $this->_throw($content, self::EXTENSION); + break; + + default: + $this->_throw($content, self::UNKNOWN); + break; + } + } + + if (count($this->_messages) > 0) { + return false; + } else { + return true; + } + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + if (is_array($file) and !empty($file['name'])) { + $this->_value = $file['name']; + } + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/File/WordCount.php b/library/vendor/Zend/Validate/File/WordCount.php new file mode 100644 index 000000000..ad2abbcec --- /dev/null +++ b/library/vendor/Zend/Validate/File/WordCount.php @@ -0,0 +1,99 @@ + "Too much words, maximum '%max%' are allowed but '%count%' were counted", + self::TOO_LESS => "Too less words, minimum '%min%' are expected but '%count%' were counted", + self::NOT_FOUND => "File '%value%' is not readable or does not exist", + ); + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the counted words are at least min and + * not bigger than max (when max is not null). + * + * @param string $value Filename to check for word count + * @param array $file File data from Zend_File_Transfer + * @return boolean + */ + public function isValid($value, $file = null) + { + // Is file readable ? + if (!Zend_Loader::isReadable($value)) { + return $this->_throw($file, self::NOT_FOUND); + } + + $content = file_get_contents($value); + $this->_count = str_word_count($content); + if (($this->_max !== null) && ($this->_count > $this->_max)) { + return $this->_throw($file, self::TOO_MUCH); + } + + if (($this->_min !== null) && ($this->_count < $this->_min)) { + return $this->_throw($file, self::TOO_LESS); + } + + return true; + } + + /** + * Throws an error of the given type + * + * @param string $file + * @param string $errorType + * @return false + */ + protected function _throw($file, $errorType) + { + if ($file !== null) { + $this->_value = $file['name']; + } + + $this->_error($errorType); + return false; + } +} diff --git a/library/vendor/Zend/Validate/Float.php b/library/vendor/Zend/Validate/Float.php new file mode 100644 index 000000000..f34efa1a3 --- /dev/null +++ b/library/vendor/Zend/Validate/Float.php @@ -0,0 +1,130 @@ + "Invalid type given. String, integer or float expected", + self::NOT_FLOAT => "'%value%' does not appear to be a float", + ); + + protected $_locale; + + /** + * Constructor for the float validator + * + * @param string|Zend_Config|Zend_Locale $locale + */ + public function __construct($locale = null) + { + if ($locale instanceof Zend_Config) { + $locale = $locale->toArray(); + } + + if (is_array($locale)) { + if (array_key_exists('locale', $locale)) { + $locale = $locale['locale']; + } else { + $locale = null; + } + } + + if (empty($locale)) { + if (Zend_Registry::isRegistered('Zend_Locale')) { + $locale = Zend_Registry::get('Zend_Locale'); + } + } + + $this->setLocale($locale); + } + + /** + * Returns the set locale + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Sets the locale to use + * + * @param string|Zend_Locale $locale + */ + public function setLocale($locale = null) + { + $this->_locale = Zend_Locale::findLocale($locale); + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a floating-point value + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value)) { + $this->_error(self::INVALID); + return false; + } + + if (is_float($value)) { + return true; + } + + $this->_setValue($value); + try { + if (!Zend_Locale_Format::isFloat($value, array('locale' => $this->_locale))) { + $this->_error(self::NOT_FLOAT); + return false; + } + } catch (Zend_Locale_Exception $e) { + $this->_error(self::NOT_FLOAT); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/GreaterThan.php b/library/vendor/Zend/Validate/GreaterThan.php new file mode 100644 index 000000000..91b8d6d8b --- /dev/null +++ b/library/vendor/Zend/Validate/GreaterThan.php @@ -0,0 +1,122 @@ + "'%value%' is not greater than '%min%'", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'min' => '_min' + ); + + /** + * Minimum value + * + * @var mixed + */ + protected $_min; + + /** + * Sets validator options + * + * @param mixed|Zend_Config $min + * @return void + */ + public function __construct($min) + { + if ($min instanceof Zend_Config) { + $min = $min->toArray(); + } + + if (is_array($min)) { + if (array_key_exists('min', $min)) { + $min = $min['min']; + } else { + throw new Zend_Validate_Exception("Missing option 'min'"); + } + } + + $this->setMin($min); + } + + /** + * Returns the min option + * + * @return mixed + */ + public function getMin() + { + return $this->_min; + } + + /** + * Sets the min option + * + * @param mixed $min + * @return Zend_Validate_GreaterThan Provides a fluent interface + */ + public function setMin($min) + { + $this->_min = $min; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is greater than min option + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + + if ($this->_min >= $value) { + $this->_error(self::NOT_GREATER); + return false; + } + return true; + } + +} diff --git a/library/vendor/Zend/Validate/Hex.php b/library/vendor/Zend/Validate/Hex.php new file mode 100644 index 000000000..f58997fad --- /dev/null +++ b/library/vendor/Zend/Validate/Hex.php @@ -0,0 +1,71 @@ + "Invalid type given. String expected", + self::NOT_HEX => "'%value%' has not only hexadecimal digit characters", + ); + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value contains only hexadecimal digit characters + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + if (!ctype_xdigit((string) $value)) { + $this->_error(self::NOT_HEX); + return false; + } + + return true; + } + +} diff --git a/library/vendor/Zend/Validate/Hostname.php b/library/vendor/Zend/Validate/Hostname.php new file mode 100644 index 000000000..7c4eb5656 --- /dev/null +++ b/library/vendor/Zend/Validate/Hostname.php @@ -0,0 +1,1427 @@ + "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded", + self::INVALID => "Invalid type given. String expected", + self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position", + self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname", + self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", + self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name", + self::INVALID_URI => "'%value%' does not appear to be a valid URI hostname", + self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed", + self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed", + self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part", + self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'tld' => '_tld' + ); + + /** + * Allows Internet domain names (e.g., example.com) + */ + const ALLOW_DNS = 1; + + /** + * Allows IP addresses + */ + const ALLOW_IP = 2; + + /** + * Allows local network names (e.g., localhost, www.localdomain) + */ + const ALLOW_LOCAL = 4; + + /** + * Allows all types of hostnames + */ + const ALLOW_URI = 8; + + /** + * Allows all types of hostnames + */ + const ALLOW_ALL = 15; + + /** + * Array of valid top-level-domains + * + * Version 2014071001, Last Updated Fri Jul 11 07:07:01 2014 UTC + * + * @see http://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain + * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs + * @var array + */ + protected $_validTlds = array( + 'ac', + 'academy', + 'accountants', + 'active', + 'actor', + 'ad', + 'ae', + 'aero', + 'af', + 'ag', + 'agency', + 'ai', + 'airforce', + 'al', + 'am', + 'an', + 'ao', + 'aq', + 'ar', + 'archi', + 'army', + 'arpa', + 'as', + 'asia', + 'associates', + 'at', + 'attorney', + 'au', + 'audio', + 'autos', + 'aw', + 'ax', + 'axa', + 'az', + 'ba', + 'bar', + 'bargains', + 'bayern', + 'bb', + 'bd', + 'be', + 'beer', + 'berlin', + 'best', + 'bf', + 'bg', + 'bh', + 'bi', + 'bid', + 'bike', + 'bio', + 'biz', + 'bj', + 'black', + 'blackfriday', + 'blue', + 'bm', + 'bmw', + 'bn', + 'bo', + 'boutique', + 'br', + 'brussels', + 'bs', + 'bt', + 'build', + 'builders', + 'buzz', + 'bv', + 'bw', + 'by', + 'bz', + 'bzh', + 'ca', + 'cab', + 'camera', + 'camp', + 'cancerresearch', + 'capetown', + 'capital', + 'cards', + 'care', + 'career', + 'careers', + 'cash', + 'cat', + 'catering', + 'cc', + 'cd', + 'center', + 'ceo', + 'cf', + 'cg', + 'ch', + 'cheap', + 'christmas', + 'church', + 'ci', + 'citic', + 'city', + 'ck', + 'cl', + 'claims', + 'cleaning', + 'clinic', + 'clothing', + 'club', + 'cm', + 'cn', + 'co', + 'codes', + 'coffee', + 'college', + 'cologne', + 'com', + 'community', + 'company', + 'computer', + 'condos', + 'construction', + 'consulting', + 'contractors', + 'cooking', + 'cool', + 'coop', + 'country', + 'cr', + 'credit', + 'creditcard', + 'cruises', + 'cu', + 'cuisinella', + 'cv', + 'cw', + 'cx', + 'cy', + 'cz', + 'dance', + 'dating', + 'de', + 'deals', + 'degree', + 'democrat', + 'dental', + 'dentist', + 'desi', + 'diamonds', + 'digital', + 'direct', + 'directory', + 'discount', + 'dj', + 'dk', + 'dm', + 'dnp', + 'do', + 'domains', + 'durban', + 'dz', + 'ec', + 'edu', + 'education', + 'ee', + 'eg', + 'email', + 'engineer', + 'engineering', + 'enterprises', + 'equipment', + 'er', + 'es', + 'estate', + 'et', + 'eu', + 'eus', + 'events', + 'exchange', + 'expert', + 'exposed', + 'fail', + 'farm', + 'feedback', + 'fi', + 'finance', + 'financial', + 'fish', + 'fishing', + 'fitness', + 'fj', + 'fk', + 'flights', + 'florist', + 'fm', + 'fo', + 'foo', + 'foundation', + 'fr', + 'frogans', + 'fund', + 'furniture', + 'futbol', + 'ga', + 'gal', + 'gallery', + 'gb', + 'gd', + 'ge', + 'gf', + 'gg', + 'gh', + 'gi', + 'gift', + 'gives', + 'gl', + 'glass', + 'global', + 'globo', + 'gm', + 'gmo', + 'gn', + 'gop', + 'gov', + 'gp', + 'gq', + 'gr', + 'graphics', + 'gratis', + 'green', + 'gripe', + 'gs', + 'gt', + 'gu', + 'guide', + 'guitars', + 'guru', + 'gw', + 'gy', + 'hamburg', + 'haus', + 'hiphop', + 'hiv', + 'hk', + 'hm', + 'hn', + 'holdings', + 'holiday', + 'homes', + 'horse', + 'host', + 'house', + 'hr', + 'ht', + 'hu', + 'id', + 'ie', + 'il', + 'im', + 'immobilien', + 'in', + 'industries', + 'info', + 'ink', + 'institute', + 'insure', + 'int', + 'international', + 'investments', + 'io', + 'iq', + 'ir', + 'is', + 'it', + 'je', + 'jetzt', + 'jm', + 'jo', + 'jobs', + 'joburg', + 'jp', + 'juegos', + 'kaufen', + 'ke', + 'kg', + 'kh', + 'ki', + 'kim', + 'kitchen', + 'kiwi', + 'km', + 'kn', + 'koeln', + 'kp', + 'kr', + 'kred', + 'kw', + 'ky', + 'kz', + 'la', + 'land', + 'lawyer', + 'lb', + 'lc', + 'lease', + 'li', + 'life', + 'lighting', + 'limited', + 'limo', + 'link', + 'lk', + 'loans', + 'london', + 'lotto', + 'lr', + 'ls', + 'lt', + 'lu', + 'luxe', + 'luxury', + 'lv', + 'ly', + 'ma', + 'maison', + 'management', + 'mango', + 'market', + 'marketing', + 'mc', + 'md', + 'me', + 'media', + 'meet', + 'melbourne', + 'menu', + 'mg', + 'mh', + 'miami', + 'mil', + 'mini', + 'mk', + 'ml', + 'mm', + 'mn', + 'mo', + 'mobi', + 'moda', + 'moe', + 'monash', + 'mortgage', + 'moscow', + 'motorcycles', + 'mp', + 'mq', + 'mr', + 'ms', + 'mt', + 'mu', + 'museum', + 'mv', + 'mw', + 'mx', + 'my', + 'mz', + 'na', + 'nagoya', + 'name', + 'navy', + 'nc', + 'ne', + 'net', + 'neustar', + 'nf', + 'ng', + 'nhk', + 'ni', + 'ninja', + 'nl', + 'no', + 'np', + 'nr', + 'nu', + 'nyc', + 'nz', + 'okinawa', + 'om', + 'onl', + 'org', + 'organic', + 'ovh', + 'pa', + 'paris', + 'partners', + 'parts', + 'pe', + 'pf', + 'pg', + 'ph', + 'photo', + 'photography', + 'photos', + 'physio', + 'pics', + 'pictures', + 'pink', + 'pk', + 'pl', + 'place', + 'plumbing', + 'pm', + 'pn', + 'post', + 'pr', + 'press', + 'pro', + 'productions', + 'properties', + 'ps', + 'pt', + 'pub', + 'pw', + 'py', + 'qa', + 'qpon', + 'quebec', + 're', + 'recipes', + 'red', + 'rehab', + 'reise', + 'reisen', + 'ren', + 'rentals', + 'repair', + 'report', + 'republican', + 'rest', + 'reviews', + 'rich', + 'rio', + 'ro', + 'rocks', + 'rodeo', + 'rs', + 'ru', + 'ruhr', + 'rw', + 'ryukyu', + 'sa', + 'saarland', + 'sb', + 'sc', + 'schmidt', + 'schule', + 'scot', + 'sd', + 'se', + 'services', + 'sexy', + 'sg', + 'sh', + 'shiksha', + 'shoes', + 'si', + 'singles', + 'sj', + 'sk', + 'sl', + 'sm', + 'sn', + 'so', + 'social', + 'software', + 'sohu', + 'solar', + 'solutions', + 'soy', + 'space', + 'sr', + 'st', + 'su', + 'supplies', + 'supply', + 'support', + 'surf', + 'surgery', + 'suzuki', + 'sv', + 'sx', + 'sy', + 'systems', + 'sz', + 'tattoo', + 'tax', + 'tc', + 'td', + 'technology', + 'tel', + 'tf', + 'tg', + 'th', + 'tienda', + 'tips', + 'tirol', + 'tj', + 'tk', + 'tl', + 'tm', + 'tn', + 'to', + 'today', + 'tokyo', + 'tools', + 'town', + 'toys', + 'tp', + 'tr', + 'trade', + 'training', + 'travel', + 'tt', + 'tv', + 'tw', + 'tz', + 'ua', + 'ug', + 'uk', + 'university', + 'uno', + 'us', + 'uy', + 'uz', + 'va', + 'vacations', + 'vc', + 've', + 'vegas', + 'ventures', + 'versicherung', + 'vet', + 'vg', + 'vi', + 'viajes', + 'villas', + 'vision', + 'vlaanderen', + 'vn', + 'vodka', + 'vote', + 'voting', + 'voto', + 'voyage', + 'vu', + 'wang', + 'watch', + 'webcam', + 'website', + 'wed', + 'wf', + 'wien', + 'wiki', + 'works', + 'ws', + 'wtc', + 'wtf', + 'xn--3bst00m', + 'xn--3ds443g', + 'xn--3e0b707e', + 'xn--45brj9c', + 'xn--4gbrim', + 'xn--55qw42g', + 'xn--55qx5d', + 'xn--6frz82g', + 'xn--6qq986b3xl', + 'xn--80adxhks', + 'xn--80ao21a', + 'xn--80asehdb', + 'xn--80aswg', + 'xn--90a3ac', + 'xn--c1avg', + 'xn--cg4bki', + 'xn--clchc0ea0b2g2a9gcd', + 'xn--czr694b', + 'xn--czru2d', + 'xn--d1acj3b', + 'xn--fiq228c5hs', + 'xn--fiq64b', + 'xn--fiqs8s', + 'xn--fiqz9s', + 'xn--fpcrj9c3d', + 'xn--fzc2c9e2c', + 'xn--gecrj9c', + 'xn--h2brj9c', + 'xn--i1b6b1a6a2e', + 'xn--io0a7i', + 'xn--j1amh', + 'xn--j6w193g', + 'xn--kprw13d', + 'xn--kpry57d', + 'xn--kput3i', + 'xn--l1acc', + 'xn--lgbbat1ad8j', + 'xn--mgb9awbf', + 'xn--mgba3a4f16a', + 'xn--mgbaam7a8h', + 'xn--mgbab2bd', + 'xn--mgbayh7gpa', + 'xn--mgbbh1a71e', + 'xn--mgbc0a9azcg', + 'xn--mgberp4a5d4ar', + 'xn--mgbx4cd0ab', + 'xn--ngbc5azd', + 'xn--nqv7f', + 'xn--nqv7fs00ema', + 'xn--o3cw4h', + 'xn--ogbpf8fl', + 'xn--p1ai', + 'xn--pgbs0dh', + 'xn--q9jyb4c', + 'xn--rhqv96g', + 'xn--s9brj9c', + 'xn--ses554g', + 'xn--unup4y', + 'xn--wgbh1c', + 'xn--wgbl6a', + 'xn--xkc2al3hye2a', + 'xn--xkc2dl3a5ee0h', + 'xn--yfro4i67o', + 'xn--ygbi2ammx', + 'xn--zfr164b', + 'xxx', + 'xyz', + 'yachts', + 'ye', + 'yokohama', + 'yt', + 'za', + 'zm', + 'zone', + 'zw', + ); + + /** + * @var string + */ + protected $_tld; + + /** + * Array for valid Idns + * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars + * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf + * (.AR) Argentinia http://www.nic.ar/faqidn.html + * (.AS) American Samoa http://www.nic.as/idn/chars.cfm + * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/ + * (.BIZ) International http://www.iana.org/domains/idn-tables/ + * (.BR) Brazil http://registro.br/faq/faq6.html + * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.CA) Canada http://www.iana.org/domains/idn-tables/tables/ca_fr_1.0.html + * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html + * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 + * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html + * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html + * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html + * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151 + * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf + * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html + * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp + * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html + * (.INFO) International http://www.nic.info/info/idn + * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf + * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran + * (.IS) Iceland http://www.isnic.is/domain/rules.php + * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html + * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 + * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf + * (.MD) Moldova http://www.register.md/ + * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html + * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html + * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.NU) Niue http://www.worldnames.net/ + * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2 + * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php + * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf + * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp + * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100); + * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html + * (.RS) Serbia http://www.iana.org/domains/idn-tables/tables/rs_sr-rs_1.0.pdf + * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html + * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en + * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf + * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html + * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf + * (.TR) Turkey https://www.nic.tr/index.php + * (.UA) Ukraine http://www.iana.org/domains/idn-tables/tables/ua_cyrl_1.2.html + * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html + * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction + * + * @var array + */ + protected $_validIdns = array( + 'AC' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'), + 'AR' => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'), + 'AS' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'), + 'AT' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'), + 'BIZ' => 'Hostname/Biz.php', + 'BR' => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'), + 'BV' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), + 'CA' => array(1 => '/^[\x{002d}0-9a-zàâæçéèêëîïôœùûüÿ\x{00E0}\x{00E2}\x{00E7}\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{00EE}\x{00EF}\x{00F4}\x{00F9}\x{00FB}\x{00FC}\x{00E6}\x{0153}\x{00FF}]{1,63}$/iu'), + 'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'), + 'CH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'), + 'CL' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'), + 'CN' => 'Hostname/Cn.php', + 'COM' => 'Zend/Validate/Hostname/Com.php', + 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), + 'DK' => array(1 => '/^[\x{002d}0-9a-zäéöüæøå]{1,63}$/iu'), + 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'), + 'EU' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'), + 'FI' => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'), + 'GR' => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'), + 'HK' => 'Zend/Validate/Hostname/Cn.php', + 'HU' => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'), + 'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu', + 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'), + 'IO' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), + 'IS' => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'), + 'JP' => 'Zend/Validate/Hostname/Jp.php', + 'KR' => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'), + 'LI' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'), + 'LT' => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'), + 'MD' => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'), + 'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'), + 'NET' => 'Zend/Validate/Hostname/Com.php', + 'NO' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), + 'NU' => 'Zend/Validate/Hostname/Com.php', + 'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'), + 'PE' => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'), + 'PL' => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', + 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu', + 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', + 10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu', + 11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu', + 12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu', + 13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu', + 14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu', + 15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu', + 17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu', + 18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu', + 19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu', + 20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu', + 21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu', + 22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu', + 23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu', + 24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu', + 25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu', + 26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu', + 27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu', + 28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu', + 29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', + 31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu', + 32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu', + 33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'), + 'PR' => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'), + 'PT' => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'), + 'RS' => array(1 => '/^[\x{002D}\x{0030}-\x{0039}\x{0061}-\x{007A}\x{0107}\x{010D}\x{0111}\x{0161}\x{017E}]{1,63}$/iu)'), + 'RU' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'), + 'SA' => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'), + 'SE' => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'), + 'SH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), + 'SI' => array( + 1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu'), + 'SJ' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), + 'TH' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'), + 'TM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'), + 'TW' => 'Zend/Validate/Hostname/Cn.php', + 'TR' => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'), + 'UA' => array(1 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџґӂʼ]{1,63}$/iu'), + 'VE' => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'), + 'VN' => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'), + 'ایران' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), + '中国' => 'Zend/Validate/Hostname/Cn.php', + '公司' => 'Zend/Validate/Hostname/Cn.php', + '网络' => 'Zend/Validate/Hostname/Cn.php' + ); + + protected $_idnLength = array( + 'BIZ' => array(5 => 17, 11 => 15, 12 => 20), + 'CN' => array(1 => 20), + 'COM' => array(3 => 17, 5 => 20), + 'HK' => array(1 => 15), + 'INFO'=> array(4 => 17), + 'KR' => array(1 => 17), + 'NET' => array(3 => 17, 5 => 20), + 'ORG' => array(6 => 17), + 'TW' => array(1 => 20), + 'ایران' => array(1 => 30), + '中国' => array(1 => 20), + '公司' => array(1 => 20), + '网络' => array(1 => 20), + ); + + protected $_options = array( + 'allow' => self::ALLOW_DNS, + 'idn' => true, + 'tld' => true, + 'ip' => null + ); + + /** + * Sets validator options + * + * @param integer $allow OPTIONAL Set what types of hostname to allow (default ALLOW_DNS) + * @param boolean $validateIdn OPTIONAL Set whether IDN domains are validated (default true) + * @param boolean $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true) + * @param Zend_Validate_Ip $ipValidator OPTIONAL + * @return void + * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['allow'] = array_shift($options); + if (!empty($options)) { + $temp['idn'] = array_shift($options); + } + + if (!empty($options)) { + $temp['tld'] = array_shift($options); + } + + if (!empty($options)) { + $temp['ip'] = array_shift($options); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions($options); + } + + /** + * Returns all set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets the options for this validator + * + * @param array $options + * @return Zend_Validate_Hostname + */ + public function setOptions($options) + { + if (array_key_exists('allow', $options)) { + $this->setAllow($options['allow']); + } + + if (array_key_exists('idn', $options)) { + $this->setValidateIdn($options['idn']); + } + + if (array_key_exists('tld', $options)) { + $this->setValidateTld($options['tld']); + } + + if (array_key_exists('ip', $options)) { + $this->setIpValidator($options['ip']); + } + + return $this; + } + + /** + * Returns the set ip validator + * + * @return Zend_Validate_Ip + */ + public function getIpValidator() + { + return $this->_options['ip']; + } + + /** + * @param Zend_Validate_Ip $ipValidator OPTIONAL + * @return void; + */ + public function setIpValidator(Zend_Validate_Ip $ipValidator = null) + { + if ($ipValidator === null) { + $ipValidator = new Zend_Validate_Ip(); + } + + $this->_options['ip'] = $ipValidator; + return $this; + } + + /** + * Returns the allow option + * + * @return integer + */ + public function getAllow() + { + return $this->_options['allow']; + } + + /** + * Sets the allow option + * + * @param integer $allow + * @return Zend_Validate_Hostname Provides a fluent interface + */ + public function setAllow($allow) + { + $this->_options['allow'] = $allow; + return $this; + } + + /** + * Returns the set idn option + * + * @return boolean + */ + public function getValidateIdn() + { + return $this->_options['idn']; + } + + /** + * Set whether IDN domains are validated + * + * This only applies when DNS hostnames are validated + * + * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them + */ + public function setValidateIdn ($allowed) + { + $this->_options['idn'] = (bool) $allowed; + return $this; + } + + /** + * Returns the set tld option + * + * @return boolean + */ + public function getValidateTld() + { + return $this->_options['tld']; + } + + /** + * Set whether the TLD element of a hostname is validated + * + * This only applies when DNS hostnames are validated + * + * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them + */ + public function setValidateTld ($allowed) + { + $this->_options['tld'] = (bool) $allowed; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the $value is a valid hostname with respect to the current allow option + * + * @param string $value + * @throws Zend_Validate_Exception if a fatal error occurs for validation process + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + // Check input against IP address schema + if (preg_match('/^[0-9a-f:.]*$/i', $value) && + $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) { + if (!($this->_options['allow'] & self::ALLOW_IP)) { + $this->_error(self::IP_ADDRESS_NOT_ALLOWED); + return false; + } else { + return true; + } + } + + // RFC3986 3.2.2 states: + // + // The rightmost domain label of a fully qualified domain name + // in DNS may be followed by a single "." and should be if it is + // necessary to distinguish between the complete domain name and + // some local domain. + // + // (see ZF-6363) + + // Local hostnames are allowed to be partitial (ending '.') + if ($this->_options['allow'] & self::ALLOW_LOCAL) { + if (substr($value, -1) === '.') { + $value = substr($value, 0, -1); + if (substr($value, -1) === '.') { + // Empty hostnames (ending '..') are not allowed + $this->_error(self::INVALID_LOCAL_NAME); + return false; + } + } + } + + $domainParts = explode('.', $value); + + // Prevent partitial IP V4 adresses (ending '.') + if ((count($domainParts) == 4) && preg_match('/^[0-9.a-e:.]*$/i', $value) && + $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) { + $this->_error(self::INVALID_LOCAL_NAME); + } + + // Check input against DNS hostname schema + if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) { + $status = false; + + $origenc = PHP_VERSION_ID < 50600 + ? iconv_get_encoding('internal_encoding') + : ini_get('default_charset'); + if (PHP_VERSION_ID < 50600) { + iconv_set_encoding('internal_encoding', 'UTF-8'); + } else { + ini_set('default_charset', 'UTF-8'); + } + do { + // First check TLD + $matches = array(); + if (preg_match('/([^.]{2,63})$/i', end($domainParts), $matches) || + (end($domainParts) == 'ایران') || (end($domainParts) == '中国') || + (end($domainParts) == '公司') || (end($domainParts) == '网络')) { + + reset($domainParts); + + // Hostname characters are: *(label dot)(label dot label); max 254 chars + // label: id-prefix [*ldh{61} id-prefix]; max 63 chars + // id-prefix: alpha / digit + // ldh: alpha / digit / dash + + // Match TLD against known list + $this->_tld = strtolower($matches[1]); + if ($this->_options['tld']) { + if (!in_array($this->_tld, $this->_validTlds)) { + $this->_error(self::UNKNOWN_TLD); + $status = false; + break; + } + } + + /** + * Match against IDN hostnames + * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames + * @see Zend_Validate_Hostname_Interface + */ + $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i'); + if ($this->_options['idn'] && isset($this->_validIdns[strtoupper($this->_tld)])) { + if (is_string($this->_validIdns[strtoupper($this->_tld)])) { + $regexChars += include($this->_validIdns[strtoupper($this->_tld)]); + } else { + $regexChars += $this->_validIdns[strtoupper($this->_tld)]; + } + } + + // Check each hostname part + $check = 0; + foreach ($domainParts as $domainPart) { + // If some domain part is empty (i.e. zend..com), it's invalid + if (empty($domainPart)) { + $this->_error(self::INVALID_HOSTNAME); + return false; + } + + // Decode Punycode domainnames to IDN + if (strpos($domainPart, 'xn--') === 0) { + $domainPart = $this->decodePunycode(substr($domainPart, 4)); + if ($domainPart === false) { + return false; + } + } + + // Check dash (-) does not start, end or appear in 3rd and 4th positions + if ((strpos($domainPart, '-') === 0) + || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3)) + || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) { + $this->_error(self::INVALID_DASH); + $status = false; + break 2; + } + + // Check each domain part + $checked = false; + foreach($regexChars as $regexKey => $regexChar) { + $status = @preg_match($regexChar, $domainPart); + if ($status > 0) { + $length = 63; + if (array_key_exists(strtoupper($this->_tld), $this->_idnLength) + && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) { + $length = $this->_idnLength[strtoupper($this->_tld)]; + } + + if (iconv_strlen($domainPart, 'UTF-8') > $length) { + $this->_error(self::INVALID_HOSTNAME); + } else { + $checked = true; + break; + } + } + } + + if ($checked) { + ++$check; + } + } + + // If one of the labels doesn't match, the hostname is invalid + if ($check !== count($domainParts)) { + $this->_error(self::INVALID_HOSTNAME_SCHEMA); + $status = false; + } + } else { + // Hostname not long enough + $this->_error(self::UNDECIPHERABLE_TLD); + $status = false; + } + } while (false); + + if (PHP_VERSION_ID < 50600) { + iconv_set_encoding('internal_encoding', $origenc); + } else { + ini_set('default_charset', $origenc); + } + // If the input passes as an Internet domain name, and domain names are allowed, then the hostname + // passes validation + if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) { + return true; + } + } else if ($this->_options['allow'] & self::ALLOW_DNS) { + $this->_error(self::INVALID_HOSTNAME); + } + + // Check for URI Syntax (RFC3986) + if ($this->_options['allow'] & self::ALLOW_URI) { + if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) { + return true; + } else { + $this->_error(self::INVALID_URI); + } + } + + // Check input against local network name schema; last chance to pass validation + $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/'; + $status = @preg_match($regexLocal, $value); + + // If the input passes as a local network name, and local network names are allowed, then the + // hostname passes validation + $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL; + if ($status && $allowLocal) { + return true; + } + + // If the input does not pass as a local network name, add a message + if (!$status) { + $this->_error(self::INVALID_LOCAL_NAME); + } + + // If local network names are not allowed, add a message + if ($status && !$allowLocal) { + $this->_error(self::LOCAL_NAME_NOT_ALLOWED); + } + + return false; + } + + /** + * Decodes a punycode encoded string to it's original utf8 string + * In case of a decoding failure the original string is returned + * + * @param string $encoded Punycode encoded string to decode + * @return string + */ + protected function decodePunycode($encoded) + { + if (!preg_match('/^[a-z0-9-]+$/i', $encoded)) { + // no punycode encoded string + $this->_error(self::CANNOT_DECODE_PUNYCODE); + return false; + } + + $decoded = array(); + $separator = strrpos($encoded, '-'); + if ($separator > 0) { + for ($x = 0; $x < $separator; ++$x) { + // prepare decoding matrix + $decoded[] = ord($encoded[$x]); + } + } + + $lengthd = count($decoded); + $lengthe = strlen($encoded); + + // decoding + $init = true; + $base = 72; + $index = 0; + $char = 0x80; + + for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) { + for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) { + $hex = ord($encoded[$indexe++]); + $digit = ($hex - 48 < 10) ? $hex - 22 + : (($hex - 65 < 26) ? $hex - 65 + : (($hex - 97 < 26) ? $hex - 97 + : 36)); + + $index += $digit * $pos; + $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base)); + if ($digit < $tag) { + break; + } + + $pos = (int) ($pos * (36 - $tag)); + } + + $delta = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2)); + $delta += intval($delta / ($lengthd + 1)); + for ($key = 0; $delta > 910 / 2; $key += 36) { + $delta = intval($delta / 35); + } + + $base = intval($key + 36 * $delta / ($delta + 38)); + $init = false; + $char += (int) ($index / ($lengthd + 1)); + $index %= ($lengthd + 1); + if ($lengthd > 0) { + for ($i = $lengthd; $i > $index; $i--) { + $decoded[$i] = $decoded[($i - 1)]; + } + } + + $decoded[$index++] = $char; + } + + // convert decoded ucs4 to utf8 string + foreach ($decoded as $key => $value) { + if ($value < 128) { + $decoded[$key] = chr($value); + } elseif ($value < (1 << 11)) { + $decoded[$key] = chr(192 + ($value >> 6)); + $decoded[$key] .= chr(128 + ($value & 63)); + } elseif ($value < (1 << 16)) { + $decoded[$key] = chr(224 + ($value >> 12)); + $decoded[$key] .= chr(128 + (($value >> 6) & 63)); + $decoded[$key] .= chr(128 + ($value & 63)); + } elseif ($value < (1 << 21)) { + $decoded[$key] = chr(240 + ($value >> 18)); + $decoded[$key] .= chr(128 + (($value >> 12) & 63)); + $decoded[$key] .= chr(128 + (($value >> 6) & 63)); + $decoded[$key] .= chr(128 + ($value & 63)); + } else { + $this->_error(self::CANNOT_DECODE_PUNYCODE); + return false; + } + } + + return implode($decoded); + } +} diff --git a/library/vendor/Zend/Validate/Hostname/Biz.php b/library/vendor/Zend/Validate/Hostname/Biz.php new file mode 100644 index 000000000..d4a09f2d5 --- /dev/null +++ b/library/vendor/Zend/Validate/Hostname/Biz.php @@ -0,0 +1,2917 @@ + '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu', + 5 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu', + 9 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 10 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu', + 11 => '/^[\x{002d}0-9a-z\x{3005}-\x{3007}\x{3041}-\x{3093}\x{309D}\x{309E}\x{30A1}-\x{30F6}\x{30FC}' . +'\x{30FD}\x{30FE}\x{4E00}\x{4E01}\x{4E03}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0D}\x{4E0E}\x{4E10}\x{4E11}\x{4E14}\x{4E15}\x{4E16}\x{4E17}' . +'\x{4E18}\x{4E19}\x{4E1E}\x{4E21}\x{4E26}\x{4E2A}\x{4E2D}\x{4E31}\x{4E32}' . +'\x{4E36}\x{4E38}\x{4E39}\x{4E3B}\x{4E3C}\x{4E3F}\x{4E42}\x{4E43}\x{4E45}' . +'\x{4E4B}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E55}\x{4E56}\x{4E57}\x{4E58}\x{4E59}' . +'\x{4E5D}\x{4E5E}\x{4E5F}\x{4E62}\x{4E71}\x{4E73}\x{4E7E}\x{4E80}\x{4E82}' . +'\x{4E85}\x{4E86}\x{4E88}\x{4E89}\x{4E8A}\x{4E8B}\x{4E8C}\x{4E8E}\x{4E91}' . +'\x{4E92}\x{4E94}\x{4E95}\x{4E98}\x{4E99}\x{4E9B}\x{4E9C}\x{4E9E}\x{4E9F}' . +'\x{4EA0}\x{4EA1}\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA8}\x{4EAB}\x{4EAC}' . +'\x{4EAD}\x{4EAE}\x{4EB0}\x{4EB3}\x{4EB6}\x{4EBA}\x{4EC0}\x{4EC1}\x{4EC2}' . +'\x{4EC4}\x{4EC6}\x{4EC7}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED4}' . +'\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EED}\x{4EEE}\x{4EF0}\x{4EF2}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4F01}\x{4F09}\x{4F0A}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}\x{4F11}\x{4F1A}' . +'\x{4F1C}\x{4F1D}\x{4F2F}\x{4F30}\x{4F34}\x{4F36}\x{4F38}\x{4F3A}\x{4F3C}' . +'\x{4F3D}\x{4F43}\x{4F46}\x{4F47}\x{4F4D}\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}' . +'\x{4F53}\x{4F55}\x{4F57}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}' . +'\x{4F69}\x{4F6F}\x{4F70}\x{4F73}\x{4F75}\x{4F76}\x{4F7B}\x{4F7C}\x{4F7F}' . +'\x{4F83}\x{4F86}\x{4F88}\x{4F8B}\x{4F8D}\x{4F8F}\x{4F91}\x{4F96}\x{4F98}' . +'\x{4F9B}\x{4F9D}\x{4FA0}\x{4FA1}\x{4FAB}\x{4FAD}\x{4FAE}\x{4FAF}\x{4FB5}' . +'\x{4FB6}\x{4FBF}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FCA}\x{4FCE}\x{4FD0}\x{4FD1}' . +'\x{4FD4}\x{4FD7}\x{4FD8}\x{4FDA}\x{4FDB}\x{4FDD}\x{4FDF}\x{4FE1}\x{4FE3}' . +'\x{4FE4}\x{4FE5}\x{4FEE}\x{4FEF}\x{4FF3}\x{4FF5}\x{4FF6}\x{4FF8}\x{4FFA}' . +'\x{4FFE}\x{5005}\x{5006}\x{5009}\x{500B}\x{500D}\x{500F}\x{5011}\x{5012}' . +'\x{5014}\x{5016}\x{5019}\x{501A}\x{501F}\x{5021}\x{5023}\x{5024}\x{5025}' . +'\x{5026}\x{5028}\x{5029}\x{502A}\x{502B}\x{502C}\x{502D}\x{5036}\x{5039}' . +'\x{5043}\x{5047}\x{5048}\x{5049}\x{504F}\x{5050}\x{5055}\x{5056}\x{505A}' . +'\x{505C}\x{5065}\x{506C}\x{5072}\x{5074}\x{5075}\x{5076}\x{5078}\x{507D}' . +'\x{5080}\x{5085}\x{508D}\x{5091}\x{5098}\x{5099}\x{509A}\x{50AC}\x{50AD}' . +'\x{50B2}\x{50B3}\x{50B4}\x{50B5}\x{50B7}\x{50BE}\x{50C2}\x{50C5}\x{50C9}' . +'\x{50CA}\x{50CD}\x{50CF}\x{50D1}\x{50D5}\x{50D6}\x{50DA}\x{50DE}\x{50E3}' . +'\x{50E5}\x{50E7}\x{50ED}\x{50EE}\x{50F5}\x{50F9}\x{50FB}\x{5100}\x{5101}' . +'\x{5102}\x{5104}\x{5109}\x{5112}\x{5114}\x{5115}\x{5116}\x{5118}\x{511A}' . +'\x{511F}\x{5121}\x{512A}\x{5132}\x{5137}\x{513A}\x{513B}\x{513C}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5152}\x{5154}\x{515A}\x{515C}' . +'\x{5162}\x{5165}\x{5168}\x{5169}\x{516A}\x{516B}\x{516C}\x{516D}\x{516E}' . +'\x{5171}\x{5175}\x{5176}\x{5177}\x{5178}\x{517C}\x{5180}\x{5182}\x{5185}' . +'\x{5186}\x{5189}\x{518A}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}' . +'\x{5193}\x{5195}\x{5196}\x{5197}\x{5199}\x{51A0}\x{51A2}\x{51A4}\x{51A5}' . +'\x{51A6}\x{51A8}\x{51A9}\x{51AA}\x{51AB}\x{51AC}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B4}\x{51B5}\x{51B6}\x{51B7}\x{51BD}\x{51C4}\x{51C5}\x{51C6}' . +'\x{51C9}\x{51CB}\x{51CC}\x{51CD}\x{51D6}\x{51DB}\x{51DC}\x{51DD}\x{51E0}' . +'\x{51E1}\x{51E6}\x{51E7}\x{51E9}\x{51EA}\x{51ED}\x{51F0}\x{51F1}\x{51F5}' . +'\x{51F6}\x{51F8}\x{51F9}\x{51FA}\x{51FD}\x{51FE}\x{5200}\x{5203}\x{5204}' . +'\x{5206}\x{5207}\x{5208}\x{520A}\x{520B}\x{520E}\x{5211}\x{5214}\x{5217}' . +'\x{521D}\x{5224}\x{5225}\x{5227}\x{5229}\x{522A}\x{522E}\x{5230}\x{5233}' . +'\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{5243}\x{5244}\x{5247}' . +'\x{524A}\x{524B}\x{524C}\x{524D}\x{524F}\x{5254}\x{5256}\x{525B}\x{525E}' . +'\x{5263}\x{5264}\x{5265}\x{5269}\x{526A}\x{526F}\x{5270}\x{5271}\x{5272}' . +'\x{5273}\x{5274}\x{5275}\x{527D}\x{527F}\x{5283}\x{5287}\x{5288}\x{5289}' . +'\x{528D}\x{5291}\x{5292}\x{5294}\x{529B}\x{529F}\x{52A0}\x{52A3}\x{52A9}' . +'\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52B1}\x{52B4}\x{52B5}\x{52B9}\x{52BC}' . +'\x{52BE}\x{52C1}\x{52C3}\x{52C5}\x{52C7}\x{52C9}\x{52CD}\x{52D2}\x{52D5}' . +'\x{52D7}\x{52D8}\x{52D9}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}' . +'\x{52E4}\x{52E6}\x{52E7}\x{52F2}\x{52F3}\x{52F5}\x{52F8}\x{52F9}\x{52FA}' . +'\x{52FE}\x{52FF}\x{5301}\x{5302}\x{5305}\x{5306}\x{5308}\x{530D}\x{530F}' . +'\x{5310}\x{5315}\x{5316}\x{5317}\x{5319}\x{531A}\x{531D}\x{5320}\x{5321}' . +'\x{5323}\x{532A}\x{532F}\x{5331}\x{5333}\x{5338}\x{5339}\x{533A}\x{533B}' . +'\x{533F}\x{5340}\x{5341}\x{5343}\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}' . +'\x{534A}\x{534D}\x{5351}\x{5352}\x{5353}\x{5354}\x{5357}\x{5358}\x{535A}' . +'\x{535C}\x{535E}\x{5360}\x{5366}\x{5369}\x{536E}\x{536F}\x{5370}\x{5371}' . +'\x{5373}\x{5374}\x{5375}\x{5377}\x{5378}\x{537B}\x{537F}\x{5382}\x{5384}' . +'\x{5396}\x{5398}\x{539A}\x{539F}\x{53A0}\x{53A5}\x{53A6}\x{53A8}\x{53A9}' . +'\x{53AD}\x{53AE}\x{53B0}\x{53B3}\x{53B6}\x{53BB}\x{53C2}\x{53C3}\x{53C8}' . +'\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}\x{53D4}\x{53D6}\x{53D7}' . +'\x{53D9}\x{53DB}\x{53DF}\x{53E1}\x{53E2}\x{53E3}\x{53E4}\x{53E5}\x{53E8}' . +'\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}\x{53EF}\x{53F0}\x{53F1}' . +'\x{53F2}\x{53F3}\x{53F6}\x{53F7}\x{53F8}\x{53FA}\x{5401}\x{5403}\x{5404}' . +'\x{5408}\x{5409}\x{540A}\x{540B}\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}' . +'\x{5411}\x{541B}\x{541D}\x{541F}\x{5420}\x{5426}\x{5429}\x{542B}\x{542C}' . +'\x{542D}\x{542E}\x{5436}\x{5438}\x{5439}\x{543B}\x{543C}\x{543D}\x{543E}' . +'\x{5440}\x{5442}\x{5446}\x{5448}\x{5449}\x{544A}\x{544E}\x{5451}\x{545F}' . +'\x{5468}\x{546A}\x{5470}\x{5471}\x{5473}\x{5475}\x{5476}\x{5477}\x{547B}' . +'\x{547C}\x{547D}\x{5480}\x{5484}\x{5486}\x{548B}\x{548C}\x{548E}\x{548F}' . +'\x{5490}\x{5492}\x{54A2}\x{54A4}\x{54A5}\x{54A8}\x{54AB}\x{54AC}\x{54AF}' . +'\x{54B2}\x{54B3}\x{54B8}\x{54BC}\x{54BD}\x{54BE}\x{54C0}\x{54C1}\x{54C2}' . +'\x{54C4}\x{54C7}\x{54C8}\x{54C9}\x{54D8}\x{54E1}\x{54E2}\x{54E5}\x{54E6}' . +'\x{54E8}\x{54E9}\x{54ED}\x{54EE}\x{54F2}\x{54FA}\x{54FD}\x{5504}\x{5506}' . +'\x{5507}\x{550F}\x{5510}\x{5514}\x{5516}\x{552E}\x{552F}\x{5531}\x{5533}' . +'\x{5538}\x{5539}\x{553E}\x{5540}\x{5544}\x{5545}\x{5546}\x{554C}\x{554F}' . +'\x{5553}\x{5556}\x{5557}\x{555C}\x{555D}\x{5563}\x{557B}\x{557C}\x{557E}' . +'\x{5580}\x{5583}\x{5584}\x{5587}\x{5589}\x{558A}\x{558B}\x{5598}\x{5599}' . +'\x{559A}\x{559C}\x{559D}\x{559E}\x{559F}\x{55A7}\x{55A8}\x{55A9}\x{55AA}' . +'\x{55AB}\x{55AC}\x{55AE}\x{55B0}\x{55B6}\x{55C4}\x{55C5}\x{55C7}\x{55D4}' . +'\x{55DA}\x{55DC}\x{55DF}\x{55E3}\x{55E4}\x{55F7}\x{55F9}\x{55FD}\x{55FE}' . +'\x{5606}\x{5609}\x{5614}\x{5616}\x{5617}\x{5618}\x{561B}\x{5629}\x{562F}' . +'\x{5631}\x{5632}\x{5634}\x{5636}\x{5638}\x{5642}\x{564C}\x{564E}\x{5650}' . +'\x{565B}\x{5664}\x{5668}\x{566A}\x{566B}\x{566C}\x{5674}\x{5678}\x{567A}' . +'\x{5680}\x{5686}\x{5687}\x{568A}\x{568F}\x{5694}\x{56A0}\x{56A2}\x{56A5}' . +'\x{56AE}\x{56B4}\x{56B6}\x{56BC}\x{56C0}\x{56C1}\x{56C2}\x{56C3}\x{56C8}' . +'\x{56CE}\x{56D1}\x{56D3}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DE}\x{56E0}' . +'\x{56E3}\x{56EE}\x{56F0}\x{56F2}\x{56F3}\x{56F9}\x{56FA}\x{56FD}\x{56FF}' . +'\x{5700}\x{5703}\x{5704}\x{5708}\x{5709}\x{570B}\x{570D}\x{570F}\x{5712}' . +'\x{5713}\x{5716}\x{5718}\x{571C}\x{571F}\x{5726}\x{5727}\x{5728}\x{572D}' . +'\x{5730}\x{5737}\x{5738}\x{573B}\x{5740}\x{5742}\x{5747}\x{574A}\x{574E}' . +'\x{574F}\x{5750}\x{5751}\x{5761}\x{5764}\x{5766}\x{5769}\x{576A}\x{577F}' . +'\x{5782}\x{5788}\x{5789}\x{578B}\x{5793}\x{57A0}\x{57A2}\x{57A3}\x{57A4}' . +'\x{57AA}\x{57B0}\x{57B3}\x{57C0}\x{57C3}\x{57C6}\x{57CB}\x{57CE}\x{57D2}' . +'\x{57D3}\x{57D4}\x{57D6}\x{57DC}\x{57DF}\x{57E0}\x{57E3}\x{57F4}\x{57F7}' . +'\x{57F9}\x{57FA}\x{57FC}\x{5800}\x{5802}\x{5805}\x{5806}\x{580A}\x{580B}' . +'\x{5815}\x{5819}\x{581D}\x{5821}\x{5824}\x{582A}\x{582F}\x{5830}\x{5831}' . +'\x{5834}\x{5835}\x{583A}\x{583D}\x{5840}\x{5841}\x{584A}\x{584B}\x{5851}' . +'\x{5852}\x{5854}\x{5857}\x{5858}\x{5859}\x{585A}\x{585E}\x{5862}\x{5869}' . +'\x{586B}\x{5870}\x{5872}\x{5875}\x{5879}\x{587E}\x{5883}\x{5885}\x{5893}' . +'\x{5897}\x{589C}\x{589F}\x{58A8}\x{58AB}\x{58AE}\x{58B3}\x{58B8}\x{58B9}' . +'\x{58BA}\x{58BB}\x{58BE}\x{58C1}\x{58C5}\x{58C7}\x{58CA}\x{58CC}\x{58D1}' . +'\x{58D3}\x{58D5}\x{58D7}\x{58D8}\x{58D9}\x{58DC}\x{58DE}\x{58DF}\x{58E4}' . +'\x{58E5}\x{58EB}\x{58EC}\x{58EE}\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F7}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{5902}\x{5909}\x{590A}\x{590F}' . +'\x{5910}\x{5915}\x{5916}\x{5918}\x{5919}\x{591A}\x{591B}\x{591C}\x{5922}' . +'\x{5925}\x{5927}\x{5929}\x{592A}\x{592B}\x{592C}\x{592D}\x{592E}\x{5931}' . +'\x{5932}\x{5937}\x{5938}\x{593E}\x{5944}\x{5947}\x{5948}\x{5949}\x{594E}' . +'\x{594F}\x{5950}\x{5951}\x{5954}\x{5955}\x{5957}\x{5958}\x{595A}\x{5960}' . +'\x{5962}\x{5965}\x{5967}\x{5968}\x{5969}\x{596A}\x{596C}\x{596E}\x{5973}' . +'\x{5974}\x{5978}\x{597D}\x{5981}\x{5982}\x{5983}\x{5984}\x{598A}\x{598D}' . +'\x{5993}\x{5996}\x{5999}\x{599B}\x{599D}\x{59A3}\x{59A5}\x{59A8}\x{59AC}' . +'\x{59B2}\x{59B9}\x{59BB}\x{59BE}\x{59C6}\x{59C9}\x{59CB}\x{59D0}\x{59D1}' . +'\x{59D3}\x{59D4}\x{59D9}\x{59DA}\x{59DC}\x{59E5}\x{59E6}\x{59E8}\x{59EA}' . +'\x{59EB}\x{59F6}\x{59FB}\x{59FF}\x{5A01}\x{5A03}\x{5A09}\x{5A11}\x{5A18}' . +'\x{5A1A}\x{5A1C}\x{5A1F}\x{5A20}\x{5A25}\x{5A29}\x{5A2F}\x{5A35}\x{5A36}' . +'\x{5A3C}\x{5A40}\x{5A41}\x{5A46}\x{5A49}\x{5A5A}\x{5A62}\x{5A66}\x{5A6A}' . +'\x{5A6C}\x{5A7F}\x{5A92}\x{5A9A}\x{5A9B}\x{5ABC}\x{5ABD}\x{5ABE}\x{5AC1}' . +'\x{5AC2}\x{5AC9}\x{5ACB}\x{5ACC}\x{5AD0}\x{5AD6}\x{5AD7}\x{5AE1}\x{5AE3}' . +'\x{5AE6}\x{5AE9}\x{5AFA}\x{5AFB}\x{5B09}\x{5B0B}\x{5B0C}\x{5B16}\x{5B22}' . +'\x{5B2A}\x{5B2C}\x{5B30}\x{5B32}\x{5B36}\x{5B3E}\x{5B40}\x{5B43}\x{5B45}' . +'\x{5B50}\x{5B51}\x{5B54}\x{5B55}\x{5B57}\x{5B58}\x{5B5A}\x{5B5B}\x{5B5C}' . +'\x{5B5D}\x{5B5F}\x{5B63}\x{5B64}\x{5B65}\x{5B66}\x{5B69}\x{5B6B}\x{5B70}' . +'\x{5B71}\x{5B73}\x{5B75}\x{5B78}\x{5B7A}\x{5B80}\x{5B83}\x{5B85}\x{5B87}' . +'\x{5B88}\x{5B89}\x{5B8B}\x{5B8C}\x{5B8D}\x{5B8F}\x{5B95}\x{5B97}\x{5B98}' . +'\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9F}\x{5BA2}\x{5BA3}\x{5BA4}' . +'\x{5BA5}\x{5BA6}\x{5BAE}\x{5BB0}\x{5BB3}\x{5BB4}\x{5BB5}\x{5BB6}\x{5BB8}' . +'\x{5BB9}\x{5BBF}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BC9}' . +'\x{5BCC}\x{5BD0}\x{5BD2}\x{5BD3}\x{5BD4}\x{5BDB}\x{5BDD}\x{5BDE}\x{5BDF}' . +'\x{5BE1}\x{5BE2}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}\x{5BE8}\x{5BE9}\x{5BEB}' . +'\x{5BEE}\x{5BF0}\x{5BF3}\x{5BF5}\x{5BF6}\x{5BF8}\x{5BFA}\x{5BFE}\x{5BFF}' . +'\x{5C01}\x{5C02}\x{5C04}\x{5C05}\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}' . +'\x{5C0B}\x{5C0D}\x{5C0E}\x{5C0F}\x{5C11}\x{5C13}\x{5C16}\x{5C1A}\x{5C20}' . +'\x{5C22}\x{5C24}\x{5C28}\x{5C2D}\x{5C31}\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}' . +'\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}\x{5C41}\x{5C45}\x{5C46}\x{5C48}' . +'\x{5C4A}\x{5C4B}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C53}\x{5C55}' . +'\x{5C5E}\x{5C60}\x{5C61}\x{5C64}\x{5C65}\x{5C6C}\x{5C6E}\x{5C6F}\x{5C71}' . +'\x{5C76}\x{5C79}\x{5C8C}\x{5C90}\x{5C91}\x{5C94}\x{5CA1}\x{5CA8}\x{5CA9}' . +'\x{5CAB}\x{5CAC}\x{5CB1}\x{5CB3}\x{5CB6}\x{5CB7}\x{5CB8}\x{5CBB}\x{5CBC}' . +'\x{5CBE}\x{5CC5}\x{5CC7}\x{5CD9}\x{5CE0}\x{5CE1}\x{5CE8}\x{5CE9}\x{5CEA}' . +'\x{5CED}\x{5CEF}\x{5CF0}\x{5CF6}\x{5CFA}\x{5CFB}\x{5CFD}\x{5D07}\x{5D0B}' . +'\x{5D0E}\x{5D11}\x{5D14}\x{5D15}\x{5D16}\x{5D17}\x{5D18}\x{5D19}\x{5D1A}' . +'\x{5D1B}\x{5D1F}\x{5D22}\x{5D29}\x{5D4B}\x{5D4C}\x{5D4E}\x{5D50}\x{5D52}' . +'\x{5D5C}\x{5D69}\x{5D6C}\x{5D6F}\x{5D73}\x{5D76}\x{5D82}\x{5D84}\x{5D87}' . +'\x{5D8B}\x{5D8C}\x{5D90}\x{5D9D}\x{5DA2}\x{5DAC}\x{5DAE}\x{5DB7}\x{5DBA}' . +'\x{5DBC}\x{5DBD}\x{5DC9}\x{5DCC}\x{5DCD}\x{5DD2}\x{5DD3}\x{5DD6}\x{5DDB}' . +'\x{5DDD}\x{5DDE}\x{5DE1}\x{5DE3}\x{5DE5}\x{5DE6}\x{5DE7}\x{5DE8}\x{5DEB}' . +'\x{5DEE}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DFB}\x{5DFD}' . +'\x{5DFE}\x{5E02}\x{5E03}\x{5E06}\x{5E0B}\x{5E0C}\x{5E11}\x{5E16}\x{5E19}' . +'\x{5E1A}\x{5E1B}\x{5E1D}\x{5E25}\x{5E2B}\x{5E2D}\x{5E2F}\x{5E30}\x{5E33}' . +'\x{5E36}\x{5E37}\x{5E38}\x{5E3D}\x{5E40}\x{5E43}\x{5E44}\x{5E45}\x{5E47}' . +'\x{5E4C}\x{5E4E}\x{5E54}\x{5E55}\x{5E57}\x{5E5F}\x{5E61}\x{5E62}\x{5E63}' . +'\x{5E64}\x{5E72}\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E78}\x{5E79}\x{5E7A}' . +'\x{5E7B}\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E81}\x{5E83}\x{5E84}\x{5E87}' . +'\x{5E8A}\x{5E8F}\x{5E95}\x{5E96}\x{5E97}\x{5E9A}\x{5E9C}\x{5EA0}\x{5EA6}' . +'\x{5EA7}\x{5EAB}\x{5EAD}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EC1}\x{5EC2}' . +'\x{5EC3}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECF}\x{5ED0}\x{5ED3}\x{5ED6}\x{5EDA}' . +'\x{5EDB}\x{5EDD}\x{5EDF}\x{5EE0}\x{5EE1}\x{5EE2}\x{5EE3}\x{5EE8}\x{5EE9}' . +'\x{5EEC}\x{5EF0}\x{5EF1}\x{5EF3}\x{5EF4}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}' . +'\x{5EFB}\x{5EFC}\x{5EFE}\x{5EFF}\x{5F01}\x{5F03}\x{5F04}\x{5F09}\x{5F0A}' . +'\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F10}\x{5F11}\x{5F13}\x{5F14}\x{5F15}' . +'\x{5F16}\x{5F17}\x{5F18}\x{5F1B}\x{5F1F}\x{5F25}\x{5F26}\x{5F27}\x{5F29}' . +'\x{5F2D}\x{5F2F}\x{5F31}\x{5F35}\x{5F37}\x{5F38}\x{5F3C}\x{5F3E}\x{5F41}' . +'\x{5F48}\x{5F4A}\x{5F4C}\x{5F4E}\x{5F51}\x{5F53}\x{5F56}\x{5F57}\x{5F59}' . +'\x{5F5C}\x{5F5D}\x{5F61}\x{5F62}\x{5F66}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}' . +'\x{5F6D}\x{5F70}\x{5F71}\x{5F73}\x{5F77}\x{5F79}\x{5F7C}\x{5F7F}\x{5F80}' . +'\x{5F81}\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F87}\x{5F88}\x{5F8A}\x{5F8B}' . +'\x{5F8C}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F97}\x{5F98}\x{5F99}\x{5F9E}' . +'\x{5FA0}\x{5FA1}\x{5FA8}\x{5FA9}\x{5FAA}\x{5FAD}\x{5FAE}\x{5FB3}\x{5FB4}' . +'\x{5FB9}\x{5FBC}\x{5FBD}\x{5FC3}\x{5FC5}\x{5FCC}\x{5FCD}\x{5FD6}\x{5FD7}' . +'\x{5FD8}\x{5FD9}\x{5FDC}\x{5FDD}\x{5FE0}\x{5FE4}\x{5FEB}\x{5FF0}\x{5FF1}' . +'\x{5FF5}\x{5FF8}\x{5FFB}\x{5FFD}\x{5FFF}\x{600E}\x{600F}\x{6010}\x{6012}' . +'\x{6015}\x{6016}\x{6019}\x{601B}\x{601C}\x{601D}\x{6020}\x{6021}\x{6025}' . +'\x{6026}\x{6027}\x{6028}\x{6029}\x{602A}\x{602B}\x{602F}\x{6031}\x{603A}' . +'\x{6041}\x{6042}\x{6043}\x{6046}\x{604A}\x{604B}\x{604D}\x{6050}\x{6052}' . +'\x{6055}\x{6059}\x{605A}\x{605F}\x{6060}\x{6062}\x{6063}\x{6064}\x{6065}' . +'\x{6068}\x{6069}\x{606A}\x{606B}\x{606C}\x{606D}\x{606F}\x{6070}\x{6075}' . +'\x{6077}\x{6081}\x{6083}\x{6084}\x{6089}\x{608B}\x{608C}\x{608D}\x{6092}' . +'\x{6094}\x{6096}\x{6097}\x{609A}\x{609B}\x{609F}\x{60A0}\x{60A3}\x{60A6}' . +'\x{60A7}\x{60A9}\x{60AA}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B8}' . +'\x{60BC}\x{60BD}\x{60C5}\x{60C6}\x{60C7}\x{60D1}\x{60D3}\x{60D8}\x{60DA}' . +'\x{60DC}\x{60DF}\x{60E0}\x{60E1}\x{60E3}\x{60E7}\x{60E8}\x{60F0}\x{60F1}' . +'\x{60F3}\x{60F4}\x{60F6}\x{60F7}\x{60F9}\x{60FA}\x{60FB}\x{6100}\x{6101}' . +'\x{6103}\x{6106}\x{6108}\x{6109}\x{610D}\x{610E}\x{610F}\x{6115}\x{611A}' . +'\x{611B}\x{611F}\x{6121}\x{6127}\x{6128}\x{612C}\x{6134}\x{613C}\x{613D}' . +'\x{613E}\x{613F}\x{6142}\x{6144}\x{6147}\x{6148}\x{614A}\x{614B}\x{614C}' . +'\x{614D}\x{614E}\x{6153}\x{6155}\x{6158}\x{6159}\x{615A}\x{615D}\x{615F}' . +'\x{6162}\x{6163}\x{6165}\x{6167}\x{6168}\x{616B}\x{616E}\x{616F}\x{6170}' . +'\x{6171}\x{6173}\x{6174}\x{6175}\x{6176}\x{6177}\x{617E}\x{6182}\x{6187}' . +'\x{618A}\x{618E}\x{6190}\x{6191}\x{6194}\x{6196}\x{6199}\x{619A}\x{61A4}' . +'\x{61A7}\x{61A9}\x{61AB}\x{61AC}\x{61AE}\x{61B2}\x{61B6}\x{61BA}\x{61BE}' . +'\x{61C3}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61D0}\x{61E3}\x{61E6}\x{61F2}\x{61F4}\x{61F6}\x{61F7}\x{61F8}\x{61FA}' . +'\x{61FC}\x{61FD}\x{61FE}\x{61FF}\x{6200}\x{6208}\x{6209}\x{620A}\x{620C}' . +'\x{620D}\x{620E}\x{6210}\x{6211}\x{6212}\x{6214}\x{6216}\x{621A}\x{621B}' . +'\x{621D}\x{621E}\x{621F}\x{6221}\x{6226}\x{622A}\x{622E}\x{622F}\x{6230}' . +'\x{6232}\x{6233}\x{6234}\x{6238}\x{623B}\x{623F}\x{6240}\x{6241}\x{6247}' . +'\x{6248}\x{6249}\x{624B}\x{624D}\x{624E}\x{6253}\x{6255}\x{6258}\x{625B}' . +'\x{625E}\x{6260}\x{6263}\x{6268}\x{626E}\x{6271}\x{6276}\x{6279}\x{627C}' . +'\x{627E}\x{627F}\x{6280}\x{6282}\x{6283}\x{6284}\x{6289}\x{628A}\x{6291}' . +'\x{6292}\x{6293}\x{6294}\x{6295}\x{6296}\x{6297}\x{6298}\x{629B}\x{629C}' . +'\x{629E}\x{62AB}\x{62AC}\x{62B1}\x{62B5}\x{62B9}\x{62BB}\x{62BC}\x{62BD}' . +'\x{62C2}\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CC}\x{62CD}' . +'\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D7}\x{62D8}\x{62D9}' . +'\x{62DB}\x{62DC}\x{62DD}\x{62E0}\x{62E1}\x{62EC}\x{62ED}\x{62EE}\x{62EF}' . +'\x{62F1}\x{62F3}\x{62F5}\x{62F6}\x{62F7}\x{62FE}\x{62FF}\x{6301}\x{6302}' . +'\x{6307}\x{6308}\x{6309}\x{630C}\x{6311}\x{6319}\x{631F}\x{6327}\x{6328}' . +'\x{632B}\x{632F}\x{633A}\x{633D}\x{633E}\x{633F}\x{6349}\x{634C}\x{634D}' . +'\x{634F}\x{6350}\x{6355}\x{6357}\x{635C}\x{6367}\x{6368}\x{6369}\x{636B}' . +'\x{636E}\x{6372}\x{6376}\x{6377}\x{637A}\x{637B}\x{6380}\x{6383}\x{6388}' . +'\x{6389}\x{638C}\x{638E}\x{638F}\x{6392}\x{6396}\x{6398}\x{639B}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A5}\x{63A7}\x{63A8}\x{63A9}\x{63AA}' . +'\x{63AB}\x{63AC}\x{63B2}\x{63B4}\x{63B5}\x{63BB}\x{63BE}\x{63C0}\x{63C3}' . +'\x{63C4}\x{63C6}\x{63C9}\x{63CF}\x{63D0}\x{63D2}\x{63D6}\x{63DA}\x{63DB}' . +'\x{63E1}\x{63E3}\x{63E9}\x{63EE}\x{63F4}\x{63F6}\x{63FA}\x{6406}\x{640D}' . +'\x{640F}\x{6413}\x{6416}\x{6417}\x{641C}\x{6426}\x{6428}\x{642C}\x{642D}' . +'\x{6434}\x{6436}\x{643A}\x{643E}\x{6442}\x{644E}\x{6458}\x{6467}\x{6469}' . +'\x{646F}\x{6476}\x{6478}\x{647A}\x{6483}\x{6488}\x{6492}\x{6493}\x{6495}' . +'\x{649A}\x{649E}\x{64A4}\x{64A5}\x{64A9}\x{64AB}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B2}\x{64B9}\x{64BB}\x{64BC}\x{64C1}\x{64C2}\x{64C5}\x{64C7}\x{64CD}' . +'\x{64D2}\x{64D4}\x{64D8}\x{64DA}\x{64E0}\x{64E1}\x{64E2}\x{64E3}\x{64E6}' . +'\x{64E7}\x{64EC}\x{64EF}\x{64F1}\x{64F2}\x{64F4}\x{64F6}\x{64FA}\x{64FD}' . +'\x{64FE}\x{6500}\x{6505}\x{6518}\x{651C}\x{651D}\x{6523}\x{6524}\x{652A}' . +'\x{652B}\x{652C}\x{652F}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}' . +'\x{653B}\x{653E}\x{653F}\x{6545}\x{6548}\x{654D}\x{654F}\x{6551}\x{6555}' . +'\x{6556}\x{6557}\x{6558}\x{6559}\x{655D}\x{655E}\x{6562}\x{6563}\x{6566}' . +'\x{656C}\x{6570}\x{6572}\x{6574}\x{6575}\x{6577}\x{6578}\x{6582}\x{6583}' . +'\x{6587}\x{6588}\x{6589}\x{658C}\x{658E}\x{6590}\x{6591}\x{6597}\x{6599}' . +'\x{659B}\x{659C}\x{659F}\x{65A1}\x{65A4}\x{65A5}\x{65A7}\x{65AB}\x{65AC}' . +'\x{65AD}\x{65AF}\x{65B0}\x{65B7}\x{65B9}\x{65BC}\x{65BD}\x{65C1}\x{65C3}' . +'\x{65C4}\x{65C5}\x{65C6}\x{65CB}\x{65CC}\x{65CF}\x{65D2}\x{65D7}\x{65D9}' . +'\x{65DB}\x{65E0}\x{65E1}\x{65E2}\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}' . +'\x{65EC}\x{65ED}\x{65F1}\x{65FA}\x{65FB}\x{6602}\x{6603}\x{6606}\x{6607}' . +'\x{660A}\x{660C}\x{660E}\x{660F}\x{6613}\x{6614}\x{661C}\x{661F}\x{6620}' . +'\x{6625}\x{6627}\x{6628}\x{662D}\x{662F}\x{6634}\x{6635}\x{6636}\x{663C}' . +'\x{663F}\x{6641}\x{6642}\x{6643}\x{6644}\x{6649}\x{664B}\x{664F}\x{6652}' . +'\x{665D}\x{665E}\x{665F}\x{6662}\x{6664}\x{6666}\x{6667}\x{6668}\x{6669}' . +'\x{666E}\x{666F}\x{6670}\x{6674}\x{6676}\x{667A}\x{6681}\x{6683}\x{6684}' . +'\x{6687}\x{6688}\x{6689}\x{668E}\x{6691}\x{6696}\x{6697}\x{6698}\x{669D}' . +'\x{66A2}\x{66A6}\x{66AB}\x{66AE}\x{66B4}\x{66B8}\x{66B9}\x{66BC}\x{66BE}' . +'\x{66C1}\x{66C4}\x{66C7}\x{66C9}\x{66D6}\x{66D9}\x{66DA}\x{66DC}\x{66DD}' . +'\x{66E0}\x{66E6}\x{66E9}\x{66F0}\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F7}' . +'\x{66F8}\x{66F9}\x{66FC}\x{66FD}\x{66FE}\x{66FF}\x{6700}\x{6703}\x{6708}' . +'\x{6709}\x{670B}\x{670D}\x{670F}\x{6714}\x{6715}\x{6716}\x{6717}\x{671B}' . +'\x{671D}\x{671E}\x{671F}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}' . +'\x{672D}\x{672E}\x{6731}\x{6734}\x{6736}\x{6737}\x{6738}\x{673A}\x{673D}' . +'\x{673F}\x{6741}\x{6746}\x{6749}\x{674E}\x{674F}\x{6750}\x{6751}\x{6753}' . +'\x{6756}\x{6759}\x{675C}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{676A}\x{676D}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}' . +'\x{6775}\x{6777}\x{677C}\x{677E}\x{677F}\x{6785}\x{6787}\x{6789}\x{678B}' . +'\x{678C}\x{6790}\x{6795}\x{6797}\x{679A}\x{679C}\x{679D}\x{67A0}\x{67A1}' . +'\x{67A2}\x{67A6}\x{67A9}\x{67AF}\x{67B3}\x{67B4}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67C1}\x{67C4}\x{67C6}\x{67CA}\x{67CE}\x{67CF}\x{67D0}\x{67D1}' . +'\x{67D3}\x{67D4}\x{67D8}\x{67DA}\x{67DD}\x{67DE}\x{67E2}\x{67E4}\x{67E7}' . +'\x{67E9}\x{67EC}\x{67EE}\x{67EF}\x{67F1}\x{67F3}\x{67F4}\x{67F5}\x{67FB}' . +'\x{67FE}\x{67FF}\x{6802}\x{6803}\x{6804}\x{6813}\x{6816}\x{6817}\x{681E}' . +'\x{6821}\x{6822}\x{6829}\x{682A}\x{682B}\x{6832}\x{6834}\x{6838}\x{6839}' . +'\x{683C}\x{683D}\x{6840}\x{6841}\x{6842}\x{6843}\x{6846}\x{6848}\x{684D}' . +'\x{684E}\x{6850}\x{6851}\x{6853}\x{6854}\x{6859}\x{685C}\x{685D}\x{685F}' . +'\x{6863}\x{6867}\x{6874}\x{6876}\x{6877}\x{687E}\x{687F}\x{6881}\x{6883}' . +'\x{6885}\x{688D}\x{688F}\x{6893}\x{6894}\x{6897}\x{689B}\x{689D}\x{689F}' . +'\x{68A0}\x{68A2}\x{68A6}\x{68A7}\x{68A8}\x{68AD}\x{68AF}\x{68B0}\x{68B1}' . +'\x{68B3}\x{68B5}\x{68B6}\x{68B9}\x{68BA}\x{68BC}\x{68C4}\x{68C6}\x{68C9}' . +'\x{68CA}\x{68CB}\x{68CD}\x{68D2}\x{68D4}\x{68D5}\x{68D7}\x{68D8}\x{68DA}' . +'\x{68DF}\x{68E0}\x{68E1}\x{68E3}\x{68E7}\x{68EE}\x{68EF}\x{68F2}\x{68F9}' . +'\x{68FA}\x{6900}\x{6901}\x{6904}\x{6905}\x{6908}\x{690B}\x{690C}\x{690D}' . +'\x{690E}\x{690F}\x{6912}\x{6919}\x{691A}\x{691B}\x{691C}\x{6921}\x{6922}' . +'\x{6923}\x{6925}\x{6926}\x{6928}\x{692A}\x{6930}\x{6934}\x{6936}\x{6939}' . +'\x{693D}\x{693F}\x{694A}\x{6953}\x{6954}\x{6955}\x{6959}\x{695A}\x{695C}' . +'\x{695D}\x{695E}\x{6960}\x{6961}\x{6962}\x{696A}\x{696B}\x{696D}\x{696E}' . +'\x{696F}\x{6973}\x{6974}\x{6975}\x{6977}\x{6978}\x{6979}\x{697C}\x{697D}' . +'\x{697E}\x{6981}\x{6982}\x{698A}\x{698E}\x{6991}\x{6994}\x{6995}\x{699B}' . +'\x{699C}\x{69A0}\x{69A7}\x{69AE}\x{69B1}\x{69B2}\x{69B4}\x{69BB}\x{69BE}' . +'\x{69BF}\x{69C1}\x{69C3}\x{69C7}\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}' . +'\x{69D0}\x{69D3}\x{69D8}\x{69D9}\x{69DD}\x{69DE}\x{69E7}\x{69E8}\x{69EB}' . +'\x{69ED}\x{69F2}\x{69F9}\x{69FB}\x{69FD}\x{69FF}\x{6A02}\x{6A05}\x{6A0A}' . +'\x{6A0B}\x{6A0C}\x{6A12}\x{6A13}\x{6A14}\x{6A17}\x{6A19}\x{6A1B}\x{6A1E}' . +'\x{6A1F}\x{6A21}\x{6A22}\x{6A23}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2E}\x{6A35}' . +'\x{6A36}\x{6A38}\x{6A39}\x{6A3A}\x{6A3D}\x{6A44}\x{6A47}\x{6A48}\x{6A4B}' . +'\x{6A58}\x{6A59}\x{6A5F}\x{6A61}\x{6A62}\x{6A66}\x{6A72}\x{6A78}\x{6A7F}' . +'\x{6A80}\x{6A84}\x{6A8D}\x{6A8E}\x{6A90}\x{6A97}\x{6A9C}\x{6AA0}\x{6AA2}' . +'\x{6AA3}\x{6AAA}\x{6AAC}\x{6AAE}\x{6AB3}\x{6AB8}\x{6ABB}\x{6AC1}\x{6AC2}' . +'\x{6AC3}\x{6AD1}\x{6AD3}\x{6ADA}\x{6ADB}\x{6ADE}\x{6ADF}\x{6AE8}\x{6AEA}' . +'\x{6AFA}\x{6AFB}\x{6B04}\x{6B05}\x{6B0A}\x{6B12}\x{6B16}\x{6B1D}\x{6B1F}' . +'\x{6B20}\x{6B21}\x{6B23}\x{6B27}\x{6B32}\x{6B37}\x{6B38}\x{6B39}\x{6B3A}' . +'\x{6B3D}\x{6B3E}\x{6B43}\x{6B47}\x{6B49}\x{6B4C}\x{6B4E}\x{6B50}\x{6B53}' . +'\x{6B54}\x{6B59}\x{6B5B}\x{6B5F}\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B66}' . +'\x{6B69}\x{6B6A}\x{6B6F}\x{6B73}\x{6B74}\x{6B78}\x{6B79}\x{6B7B}\x{6B7F}' . +'\x{6B80}\x{6B83}\x{6B84}\x{6B86}\x{6B89}\x{6B8A}\x{6B8B}\x{6B8D}\x{6B95}' . +'\x{6B96}\x{6B98}\x{6B9E}\x{6BA4}\x{6BAA}\x{6BAB}\x{6BAF}\x{6BB1}\x{6BB2}' . +'\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB7}\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBF}\x{6BC0}' . +'\x{6BC5}\x{6BC6}\x{6BCB}\x{6BCD}\x{6BCE}\x{6BD2}\x{6BD3}\x{6BD4}\x{6BD8}' . +'\x{6BDB}\x{6BDF}\x{6BEB}\x{6BEC}\x{6BEF}\x{6BF3}\x{6C08}\x{6C0F}\x{6C11}' . +'\x{6C13}\x{6C14}\x{6C17}\x{6C1B}\x{6C23}\x{6C24}\x{6C34}\x{6C37}\x{6C38}' . +'\x{6C3E}\x{6C40}\x{6C41}\x{6C42}\x{6C4E}\x{6C50}\x{6C55}\x{6C57}\x{6C5A}' . +'\x{6C5D}\x{6C5E}\x{6C5F}\x{6C60}\x{6C62}\x{6C68}\x{6C6A}\x{6C70}\x{6C72}' . +'\x{6C73}\x{6C7A}\x{6C7D}\x{6C7E}\x{6C81}\x{6C82}\x{6C83}\x{6C88}\x{6C8C}' . +'\x{6C8D}\x{6C90}\x{6C92}\x{6C93}\x{6C96}\x{6C99}\x{6C9A}\x{6C9B}\x{6CA1}' . +'\x{6CA2}\x{6CAB}\x{6CAE}\x{6CB1}\x{6CB3}\x{6CB8}\x{6CB9}\x{6CBA}\x{6CBB}' . +'\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC1}\x{6CC4}\x{6CC5}\x{6CC9}\x{6CCA}' . +'\x{6CCC}\x{6CD3}\x{6CD5}\x{6CD7}\x{6CD9}\x{6CDB}\x{6CDD}\x{6CE1}\x{6CE2}' . +'\x{6CE3}\x{6CE5}\x{6CE8}\x{6CEA}\x{6CEF}\x{6CF0}\x{6CF1}\x{6CF3}\x{6D0B}' . +'\x{6D0C}\x{6D12}\x{6D17}\x{6D19}\x{6D1B}\x{6D1E}\x{6D1F}\x{6D25}\x{6D29}' . +'\x{6D2A}\x{6D2B}\x{6D32}\x{6D33}\x{6D35}\x{6D36}\x{6D38}\x{6D3B}\x{6D3D}' . +'\x{6D3E}\x{6D41}\x{6D44}\x{6D45}\x{6D59}\x{6D5A}\x{6D5C}\x{6D63}\x{6D64}' . +'\x{6D66}\x{6D69}\x{6D6A}\x{6D6C}\x{6D6E}\x{6D74}\x{6D77}\x{6D78}\x{6D79}' . +'\x{6D85}\x{6D88}\x{6D8C}\x{6D8E}\x{6D93}\x{6D95}\x{6D99}\x{6D9B}\x{6D9C}' . +'\x{6DAF}\x{6DB2}\x{6DB5}\x{6DB8}\x{6DBC}\x{6DC0}\x{6DC5}\x{6DC6}\x{6DC7}' . +'\x{6DCB}\x{6DCC}\x{6DD1}\x{6DD2}\x{6DD5}\x{6DD8}\x{6DD9}\x{6DDE}\x{6DE1}' . +'\x{6DE4}\x{6DE6}\x{6DE8}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DEE}\x{6DF1}\x{6DF3}' . +'\x{6DF5}\x{6DF7}\x{6DF9}\x{6DFA}\x{6DFB}\x{6E05}\x{6E07}\x{6E08}\x{6E09}' . +'\x{6E0A}\x{6E0B}\x{6E13}\x{6E15}\x{6E19}\x{6E1A}\x{6E1B}\x{6E1D}\x{6E1F}' . +'\x{6E20}\x{6E21}\x{6E23}\x{6E24}\x{6E25}\x{6E26}\x{6E29}\x{6E2B}\x{6E2C}' . +'\x{6E2D}\x{6E2E}\x{6E2F}\x{6E38}\x{6E3A}\x{6E3E}\x{6E43}\x{6E4A}\x{6E4D}' . +'\x{6E4E}\x{6E56}\x{6E58}\x{6E5B}\x{6E5F}\x{6E67}\x{6E6B}\x{6E6E}\x{6E6F}' . +'\x{6E72}\x{6E76}\x{6E7E}\x{6E7F}\x{6E80}\x{6E82}\x{6E8C}\x{6E8F}\x{6E90}' . +'\x{6E96}\x{6E98}\x{6E9C}\x{6E9D}\x{6E9F}\x{6EA2}\x{6EA5}\x{6EAA}\x{6EAF}' . +'\x{6EB2}\x{6EB6}\x{6EB7}\x{6EBA}\x{6EBD}\x{6EC2}\x{6EC4}\x{6EC5}\x{6EC9}' . +'\x{6ECB}\x{6ECC}\x{6ED1}\x{6ED3}\x{6ED4}\x{6ED5}\x{6EDD}\x{6EDE}\x{6EEC}' . +'\x{6EEF}\x{6EF2}\x{6EF4}\x{6EF7}\x{6EF8}\x{6EFE}\x{6EFF}\x{6F01}\x{6F02}' . +'\x{6F06}\x{6F09}\x{6F0F}\x{6F11}\x{6F13}\x{6F14}\x{6F15}\x{6F20}\x{6F22}' . +'\x{6F23}\x{6F2B}\x{6F2C}\x{6F31}\x{6F32}\x{6F38}\x{6F3E}\x{6F3F}\x{6F41}' . +'\x{6F45}\x{6F54}\x{6F58}\x{6F5B}\x{6F5C}\x{6F5F}\x{6F64}\x{6F66}\x{6F6D}' . +'\x{6F6E}\x{6F6F}\x{6F70}\x{6F74}\x{6F78}\x{6F7A}\x{6F7C}\x{6F80}\x{6F81}' . +'\x{6F82}\x{6F84}\x{6F86}\x{6F8E}\x{6F91}\x{6F97}\x{6FA1}\x{6FA3}\x{6FA4}' . +'\x{6FAA}\x{6FB1}\x{6FB3}\x{6FB9}\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC6}' . +'\x{6FD4}\x{6FD5}\x{6FD8}\x{6FDB}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE4}\x{6FEB}' . +'\x{6FEC}\x{6FEE}\x{6FEF}\x{6FF1}\x{6FF3}\x{6FF6}\x{6FFA}\x{6FFE}\x{7001}' . +'\x{7009}\x{700B}\x{700F}\x{7011}\x{7015}\x{7018}\x{701A}\x{701B}\x{701D}' . +'\x{701E}\x{701F}\x{7026}\x{7027}\x{702C}\x{7030}\x{7032}\x{703E}\x{704C}' . +'\x{7051}\x{7058}\x{7063}\x{706B}\x{706F}\x{7070}\x{7078}\x{707C}\x{707D}' . +'\x{7089}\x{708A}\x{708E}\x{7092}\x{7099}\x{70AC}\x{70AD}\x{70AE}\x{70AF}' . +'\x{70B3}\x{70B8}\x{70B9}\x{70BA}\x{70C8}\x{70CB}\x{70CF}\x{70D9}\x{70DD}' . +'\x{70DF}\x{70F1}\x{70F9}\x{70FD}\x{7109}\x{7114}\x{7119}\x{711A}\x{711C}' . +'\x{7121}\x{7126}\x{7136}\x{713C}\x{7149}\x{714C}\x{714E}\x{7155}\x{7156}' . +'\x{7159}\x{7162}\x{7164}\x{7165}\x{7166}\x{7167}\x{7169}\x{716C}\x{716E}' . +'\x{717D}\x{7184}\x{7188}\x{718A}\x{718F}\x{7194}\x{7195}\x{7199}\x{719F}' . +'\x{71A8}\x{71AC}\x{71B1}\x{71B9}\x{71BE}\x{71C3}\x{71C8}\x{71C9}\x{71CE}' . +'\x{71D0}\x{71D2}\x{71D4}\x{71D5}\x{71D7}\x{71DF}\x{71E0}\x{71E5}\x{71E6}' . +'\x{71E7}\x{71EC}\x{71ED}\x{71EE}\x{71F5}\x{71F9}\x{71FB}\x{71FC}\x{71FF}' . +'\x{7206}\x{720D}\x{7210}\x{721B}\x{7228}\x{722A}\x{722C}\x{722D}\x{7230}' . +'\x{7232}\x{7235}\x{7236}\x{723A}\x{723B}\x{723C}\x{723D}\x{723E}\x{723F}' . +'\x{7240}\x{7246}\x{7247}\x{7248}\x{724B}\x{724C}\x{7252}\x{7258}\x{7259}' . +'\x{725B}\x{725D}\x{725F}\x{7261}\x{7262}\x{7267}\x{7269}\x{7272}\x{7274}' . +'\x{7279}\x{727D}\x{727E}\x{7280}\x{7281}\x{7282}\x{7287}\x{7292}\x{7296}' . +'\x{72A0}\x{72A2}\x{72A7}\x{72AC}\x{72AF}\x{72B2}\x{72B6}\x{72B9}\x{72C2}' . +'\x{72C3}\x{72C4}\x{72C6}\x{72CE}\x{72D0}\x{72D2}\x{72D7}\x{72D9}\x{72DB}' . +'\x{72E0}\x{72E1}\x{72E2}\x{72E9}\x{72EC}\x{72ED}\x{72F7}\x{72F8}\x{72F9}' . +'\x{72FC}\x{72FD}\x{730A}\x{7316}\x{7317}\x{731B}\x{731C}\x{731D}\x{731F}' . +'\x{7325}\x{7329}\x{732A}\x{732B}\x{732E}\x{732F}\x{7334}\x{7336}\x{7337}' . +'\x{733E}\x{733F}\x{7344}\x{7345}\x{734E}\x{734F}\x{7357}\x{7363}\x{7368}' . +'\x{736A}\x{7370}\x{7372}\x{7375}\x{7378}\x{737A}\x{737B}\x{7384}\x{7387}' . +'\x{7389}\x{738B}\x{7396}\x{73A9}\x{73B2}\x{73B3}\x{73BB}\x{73C0}\x{73C2}' . +'\x{73C8}\x{73CA}\x{73CD}\x{73CE}\x{73DE}\x{73E0}\x{73E5}\x{73EA}\x{73ED}' . +'\x{73EE}\x{73F1}\x{73F8}\x{73FE}\x{7403}\x{7405}\x{7406}\x{7409}\x{7422}' . +'\x{7425}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{743A}\x{743F}\x{7441}' . +'\x{7455}\x{7459}\x{745A}\x{745B}\x{745C}\x{745E}\x{745F}\x{7460}\x{7463}' . +'\x{7464}\x{7469}\x{746A}\x{746F}\x{7470}\x{7473}\x{7476}\x{747E}\x{7483}' . +'\x{748B}\x{749E}\x{74A2}\x{74A7}\x{74B0}\x{74BD}\x{74CA}\x{74CF}\x{74D4}' . +'\x{74DC}\x{74E0}\x{74E2}\x{74E3}\x{74E6}\x{74E7}\x{74E9}\x{74EE}\x{74F0}' . +'\x{74F1}\x{74F2}\x{74F6}\x{74F7}\x{74F8}\x{7503}\x{7504}\x{7505}\x{750C}' . +'\x{750D}\x{750E}\x{7511}\x{7513}\x{7515}\x{7518}\x{751A}\x{751C}\x{751E}' . +'\x{751F}\x{7523}\x{7525}\x{7526}\x{7528}\x{752B}\x{752C}\x{7530}\x{7531}' . +'\x{7532}\x{7533}\x{7537}\x{7538}\x{753A}\x{753B}\x{753C}\x{7544}\x{7546}' . +'\x{7549}\x{754A}\x{754B}\x{754C}\x{754D}\x{754F}\x{7551}\x{7554}\x{7559}' . +'\x{755A}\x{755B}\x{755C}\x{755D}\x{7560}\x{7562}\x{7564}\x{7565}\x{7566}' . +'\x{7567}\x{7569}\x{756A}\x{756B}\x{756D}\x{7570}\x{7573}\x{7574}\x{7576}' . +'\x{7577}\x{7578}\x{757F}\x{7582}\x{7586}\x{7587}\x{7589}\x{758A}\x{758B}' . +'\x{758E}\x{758F}\x{7591}\x{7594}\x{759A}\x{759D}\x{75A3}\x{75A5}\x{75AB}' . +'\x{75B1}\x{75B2}\x{75B3}\x{75B5}\x{75B8}\x{75B9}\x{75BC}\x{75BD}\x{75BE}' . +'\x{75C2}\x{75C3}\x{75C5}\x{75C7}\x{75CA}\x{75CD}\x{75D2}\x{75D4}\x{75D5}' . +'\x{75D8}\x{75D9}\x{75DB}\x{75DE}\x{75E2}\x{75E3}\x{75E9}\x{75F0}\x{75F2}' . +'\x{75F3}\x{75F4}\x{75FA}\x{75FC}\x{75FE}\x{75FF}\x{7601}\x{7609}\x{760B}' . +'\x{760D}\x{761F}\x{7620}\x{7621}\x{7622}\x{7624}\x{7627}\x{7630}\x{7634}' . +'\x{763B}\x{7642}\x{7646}\x{7647}\x{7648}\x{764C}\x{7652}\x{7656}\x{7658}' . +'\x{765C}\x{7661}\x{7662}\x{7667}\x{7668}\x{7669}\x{766A}\x{766C}\x{7670}' . +'\x{7672}\x{7676}\x{7678}\x{767A}\x{767B}\x{767C}\x{767D}\x{767E}\x{7680}' . +'\x{7683}\x{7684}\x{7686}\x{7687}\x{7688}\x{768B}\x{768E}\x{7690}\x{7693}' . +'\x{7696}\x{7699}\x{769A}\x{76AE}\x{76B0}\x{76B4}\x{76B7}\x{76B8}\x{76B9}' . +'\x{76BA}\x{76BF}\x{76C2}\x{76C3}\x{76C6}\x{76C8}\x{76CA}\x{76CD}\x{76D2}' . +'\x{76D6}\x{76D7}\x{76DB}\x{76DC}\x{76DE}\x{76DF}\x{76E1}\x{76E3}\x{76E4}' . +'\x{76E5}\x{76E7}\x{76EA}\x{76EE}\x{76F2}\x{76F4}\x{76F8}\x{76FB}\x{76FE}' . +'\x{7701}\x{7704}\x{7707}\x{7708}\x{7709}\x{770B}\x{770C}\x{771B}\x{771E}' . +'\x{771F}\x{7720}\x{7724}\x{7725}\x{7726}\x{7729}\x{7737}\x{7738}\x{773A}' . +'\x{773C}\x{7740}\x{7747}\x{775A}\x{775B}\x{7761}\x{7763}\x{7765}\x{7766}' . +'\x{7768}\x{776B}\x{7779}\x{777E}\x{777F}\x{778B}\x{778E}\x{7791}\x{779E}' . +'\x{77A0}\x{77A5}\x{77AC}\x{77AD}\x{77B0}\x{77B3}\x{77B6}\x{77B9}\x{77BB}' . +'\x{77BC}\x{77BD}\x{77BF}\x{77C7}\x{77CD}\x{77D7}\x{77DA}\x{77DB}\x{77DC}' . +'\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E9}\x{77ED}\x{77EE}\x{77EF}\x{77F3}' . +'\x{77FC}\x{7802}\x{780C}\x{7812}\x{7814}\x{7815}\x{7820}\x{7825}\x{7826}' . +'\x{7827}\x{7832}\x{7834}\x{783A}\x{783F}\x{7845}\x{785D}\x{786B}\x{786C}' . +'\x{786F}\x{7872}\x{7874}\x{787C}\x{7881}\x{7886}\x{7887}\x{788C}\x{788D}' . +'\x{788E}\x{7891}\x{7893}\x{7895}\x{7897}\x{789A}\x{78A3}\x{78A7}\x{78A9}' . +'\x{78AA}\x{78AF}\x{78B5}\x{78BA}\x{78BC}\x{78BE}\x{78C1}\x{78C5}\x{78C6}' . +'\x{78CA}\x{78CB}\x{78D0}\x{78D1}\x{78D4}\x{78DA}\x{78E7}\x{78E8}\x{78EC}' . +'\x{78EF}\x{78F4}\x{78FD}\x{7901}\x{7907}\x{790E}\x{7911}\x{7912}\x{7919}' . +'\x{7926}\x{792A}\x{792B}\x{792C}\x{793A}\x{793C}\x{793E}\x{7940}\x{7941}' . +'\x{7947}\x{7948}\x{7949}\x{7950}\x{7953}\x{7955}\x{7956}\x{7957}\x{795A}' . +'\x{795D}\x{795E}\x{795F}\x{7960}\x{7962}\x{7965}\x{7968}\x{796D}\x{7977}' . +'\x{797A}\x{797F}\x{7980}\x{7981}\x{7984}\x{7985}\x{798A}\x{798D}\x{798E}' . +'\x{798F}\x{799D}\x{79A6}\x{79A7}\x{79AA}\x{79AE}\x{79B0}\x{79B3}\x{79B9}' . +'\x{79BA}\x{79BD}\x{79BE}\x{79BF}\x{79C0}\x{79C1}\x{79C9}\x{79CB}\x{79D1}' . +'\x{79D2}\x{79D5}\x{79D8}\x{79DF}\x{79E1}\x{79E3}\x{79E4}\x{79E6}\x{79E7}' . +'\x{79E9}\x{79EC}\x{79F0}\x{79FB}\x{7A00}\x{7A08}\x{7A0B}\x{7A0D}\x{7A0E}' . +'\x{7A14}\x{7A17}\x{7A18}\x{7A19}\x{7A1A}\x{7A1C}\x{7A1F}\x{7A20}\x{7A2E}' . +'\x{7A31}\x{7A32}\x{7A37}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A42}\x{7A43}\x{7A46}\x{7A49}\x{7A4D}\x{7A4E}\x{7A4F}\x{7A50}\x{7A57}' . +'\x{7A61}\x{7A62}\x{7A63}\x{7A69}\x{7A6B}\x{7A70}\x{7A74}\x{7A76}\x{7A79}' . +'\x{7A7A}\x{7A7D}\x{7A7F}\x{7A81}\x{7A83}\x{7A84}\x{7A88}\x{7A92}\x{7A93}' . +'\x{7A95}\x{7A96}\x{7A97}\x{7A98}\x{7A9F}\x{7AA9}\x{7AAA}\x{7AAE}\x{7AAF}' . +'\x{7AB0}\x{7AB6}\x{7ABA}\x{7ABF}\x{7AC3}\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}' . +'\x{7ACA}\x{7ACB}\x{7ACD}\x{7ACF}\x{7AD2}\x{7AD3}\x{7AD5}\x{7AD9}\x{7ADA}' . +'\x{7ADC}\x{7ADD}\x{7ADF}\x{7AE0}\x{7AE1}\x{7AE2}\x{7AE3}\x{7AE5}\x{7AE6}' . +'\x{7AEA}\x{7AED}\x{7AEF}\x{7AF0}\x{7AF6}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFF}' . +'\x{7B02}\x{7B04}\x{7B06}\x{7B08}\x{7B0A}\x{7B0B}\x{7B0F}\x{7B11}\x{7B18}' . +'\x{7B19}\x{7B1B}\x{7B1E}\x{7B20}\x{7B25}\x{7B26}\x{7B28}\x{7B2C}\x{7B33}' . +'\x{7B35}\x{7B36}\x{7B39}\x{7B45}\x{7B46}\x{7B48}\x{7B49}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B56}\x{7B5D}\x{7B65}' . +'\x{7B67}\x{7B6C}\x{7B6E}\x{7B70}\x{7B71}\x{7B74}\x{7B75}\x{7B7A}\x{7B86}' . +'\x{7B87}\x{7B8B}\x{7B8D}\x{7B8F}\x{7B92}\x{7B94}\x{7B95}\x{7B97}\x{7B98}' . +'\x{7B99}\x{7B9A}\x{7B9C}\x{7B9D}\x{7B9F}\x{7BA1}\x{7BAA}\x{7BAD}\x{7BB1}' . +'\x{7BB4}\x{7BB8}\x{7BC0}\x{7BC1}\x{7BC4}\x{7BC6}\x{7BC7}\x{7BC9}\x{7BCB}' . +'\x{7BCC}\x{7BCF}\x{7BDD}\x{7BE0}\x{7BE4}\x{7BE5}\x{7BE6}\x{7BE9}\x{7BED}' . +'\x{7BF3}\x{7BF6}\x{7BF7}\x{7C00}\x{7C07}\x{7C0D}\x{7C11}\x{7C12}\x{7C13}' . +'\x{7C14}\x{7C17}\x{7C1F}\x{7C21}\x{7C23}\x{7C27}\x{7C2A}\x{7C2B}\x{7C37}' . +'\x{7C38}\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C43}\x{7C4C}\x{7C4D}\x{7C4F}' . +'\x{7C50}\x{7C54}\x{7C56}\x{7C58}\x{7C5F}\x{7C60}\x{7C64}\x{7C65}\x{7C6C}' . +'\x{7C73}\x{7C75}\x{7C7E}\x{7C81}\x{7C82}\x{7C83}\x{7C89}\x{7C8B}\x{7C8D}' . +'\x{7C90}\x{7C92}\x{7C95}\x{7C97}\x{7C98}\x{7C9B}\x{7C9F}\x{7CA1}\x{7CA2}' . +'\x{7CA4}\x{7CA5}\x{7CA7}\x{7CA8}\x{7CAB}\x{7CAD}\x{7CAE}\x{7CB1}\x{7CB2}' . +'\x{7CB3}\x{7CB9}\x{7CBD}\x{7CBE}\x{7CC0}\x{7CC2}\x{7CC5}\x{7CCA}\x{7CCE}' . +'\x{7CD2}\x{7CD6}\x{7CD8}\x{7CDC}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE7}' . +'\x{7CEF}\x{7CF2}\x{7CF4}\x{7CF6}\x{7CF8}\x{7CFA}\x{7CFB}\x{7CFE}\x{7D00}' . +'\x{7D02}\x{7D04}\x{7D05}\x{7D06}\x{7D0A}\x{7D0B}\x{7D0D}\x{7D10}\x{7D14}' . +'\x{7D15}\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D20}\x{7D21}' . +'\x{7D22}\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D32}\x{7D33}\x{7D35}' . +'\x{7D39}\x{7D3A}\x{7D3F}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}\x{7D4B}' . +'\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D56}\x{7D5B}\x{7D5E}\x{7D61}\x{7D62}' . +'\x{7D63}\x{7D66}\x{7D68}\x{7D6E}\x{7D71}\x{7D72}\x{7D73}\x{7D75}\x{7D76}' . +'\x{7D79}\x{7D7D}\x{7D89}\x{7D8F}\x{7D93}\x{7D99}\x{7D9A}\x{7D9B}\x{7D9C}' . +'\x{7D9F}\x{7DA2}\x{7DA3}\x{7DAB}\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}' . +'\x{7DB1}\x{7DB2}\x{7DB4}\x{7DB5}\x{7DB8}\x{7DBA}\x{7DBB}\x{7DBD}\x{7DBE}' . +'\x{7DBF}\x{7DC7}\x{7DCA}\x{7DCB}\x{7DCF}\x{7DD1}\x{7DD2}\x{7DD5}\x{7DD8}' . +'\x{7DDA}\x{7DDC}\x{7DDD}\x{7DDE}\x{7DE0}\x{7DE1}\x{7DE4}\x{7DE8}\x{7DE9}' . +'\x{7DEC}\x{7DEF}\x{7DF2}\x{7DF4}\x{7DFB}\x{7E01}\x{7E04}\x{7E05}\x{7E09}' . +'\x{7E0A}\x{7E0B}\x{7E12}\x{7E1B}\x{7E1E}\x{7E1F}\x{7E21}\x{7E22}\x{7E23}' . +'\x{7E26}\x{7E2B}\x{7E2E}\x{7E31}\x{7E32}\x{7E35}\x{7E37}\x{7E39}\x{7E3A}' . +'\x{7E3B}\x{7E3D}\x{7E3E}\x{7E41}\x{7E43}\x{7E46}\x{7E4A}\x{7E4B}\x{7E4D}' . +'\x{7E54}\x{7E55}\x{7E56}\x{7E59}\x{7E5A}\x{7E5D}\x{7E5E}\x{7E66}\x{7E67}' . +'\x{7E69}\x{7E6A}\x{7E6D}\x{7E70}\x{7E79}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7F}' . +'\x{7E82}\x{7E83}\x{7E88}\x{7E89}\x{7E8C}\x{7E8E}\x{7E8F}\x{7E90}\x{7E92}' . +'\x{7E93}\x{7E94}\x{7E96}\x{7E9B}\x{7E9C}\x{7F36}\x{7F38}\x{7F3A}\x{7F45}' . +'\x{7F4C}\x{7F4D}\x{7F4E}\x{7F50}\x{7F51}\x{7F54}\x{7F55}\x{7F58}\x{7F5F}' . +'\x{7F60}\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6E}\x{7F70}\x{7F72}' . +'\x{7F75}\x{7F77}\x{7F78}\x{7F79}\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}' . +'\x{7F88}\x{7F8A}\x{7F8C}\x{7F8E}\x{7F94}\x{7F9A}\x{7F9D}\x{7F9E}\x{7FA3}' . +'\x{7FA4}\x{7FA8}\x{7FA9}\x{7FAE}\x{7FAF}\x{7FB2}\x{7FB6}\x{7FB8}\x{7FB9}' . +'\x{7FBD}\x{7FC1}\x{7FC5}\x{7FC6}\x{7FCA}\x{7FCC}\x{7FD2}\x{7FD4}\x{7FD5}' . +'\x{7FE0}\x{7FE1}\x{7FE6}\x{7FE9}\x{7FEB}\x{7FF0}\x{7FF3}\x{7FF9}\x{7FFB}' . +'\x{7FFC}\x{8000}\x{8001}\x{8003}\x{8004}\x{8005}\x{8006}\x{800B}\x{800C}' . +'\x{8010}\x{8012}\x{8015}\x{8017}\x{8018}\x{8019}\x{801C}\x{8021}\x{8028}' . +'\x{8033}\x{8036}\x{803B}\x{803D}\x{803F}\x{8046}\x{804A}\x{8052}\x{8056}' . +'\x{8058}\x{805A}\x{805E}\x{805F}\x{8061}\x{8062}\x{8068}\x{806F}\x{8070}' . +'\x{8072}\x{8073}\x{8074}\x{8076}\x{8077}\x{8079}\x{807D}\x{807E}\x{807F}' . +'\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808B}\x{808C}\x{8093}\x{8096}' . +'\x{8098}\x{809A}\x{809B}\x{809D}\x{80A1}\x{80A2}\x{80A5}\x{80A9}\x{80AA}' . +'\x{80AC}\x{80AD}\x{80AF}\x{80B1}\x{80B2}\x{80B4}\x{80BA}\x{80C3}\x{80C4}' . +'\x{80C6}\x{80CC}\x{80CE}\x{80D6}\x{80D9}\x{80DA}\x{80DB}\x{80DD}\x{80DE}' . +'\x{80E1}\x{80E4}\x{80E5}\x{80EF}\x{80F1}\x{80F4}\x{80F8}\x{80FC}\x{80FD}' . +'\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{811A}\x{811B}' . +'\x{8123}\x{8129}\x{812F}\x{8131}\x{8133}\x{8139}\x{813E}\x{8146}\x{814B}' . +'\x{814E}\x{8150}\x{8151}\x{8153}\x{8154}\x{8155}\x{815F}\x{8165}\x{8166}' . +'\x{816B}\x{816E}\x{8170}\x{8171}\x{8174}\x{8178}\x{8179}\x{817A}\x{817F}' . +'\x{8180}\x{8182}\x{8183}\x{8188}\x{818A}\x{818F}\x{8193}\x{8195}\x{819A}' . +'\x{819C}\x{819D}\x{81A0}\x{81A3}\x{81A4}\x{81A8}\x{81A9}\x{81B0}\x{81B3}' . +'\x{81B5}\x{81B8}\x{81BA}\x{81BD}\x{81BE}\x{81BF}\x{81C0}\x{81C2}\x{81C6}' . +'\x{81C8}\x{81C9}\x{81CD}\x{81D1}\x{81D3}\x{81D8}\x{81D9}\x{81DA}\x{81DF}' . +'\x{81E0}\x{81E3}\x{81E5}\x{81E7}\x{81E8}\x{81EA}\x{81ED}\x{81F3}\x{81F4}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FE}\x{8201}\x{8202}\x{8205}\x{8207}\x{8208}' . +'\x{8209}\x{820A}\x{820C}\x{820D}\x{820E}\x{8210}\x{8212}\x{8216}\x{8217}' . +'\x{8218}\x{821B}\x{821C}\x{821E}\x{821F}\x{8229}\x{822A}\x{822B}\x{822C}' . +'\x{822E}\x{8233}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{8240}\x{8247}' . +'\x{8258}\x{8259}\x{825A}\x{825D}\x{825F}\x{8262}\x{8264}\x{8266}\x{8268}' . +'\x{826A}\x{826B}\x{826E}\x{826F}\x{8271}\x{8272}\x{8276}\x{8277}\x{8278}' . +'\x{827E}\x{828B}\x{828D}\x{8292}\x{8299}\x{829D}\x{829F}\x{82A5}\x{82A6}' . +'\x{82AB}\x{82AC}\x{82AD}\x{82AF}\x{82B1}\x{82B3}\x{82B8}\x{82B9}\x{82BB}' . +'\x{82BD}\x{82C5}\x{82D1}\x{82D2}\x{82D3}\x{82D4}\x{82D7}\x{82D9}\x{82DB}' . +'\x{82DC}\x{82DE}\x{82DF}\x{82E1}\x{82E3}\x{82E5}\x{82E6}\x{82E7}\x{82EB}' . +'\x{82F1}\x{82F3}\x{82F4}\x{82F9}\x{82FA}\x{82FB}\x{8302}\x{8303}\x{8304}' . +'\x{8305}\x{8306}\x{8309}\x{830E}\x{8316}\x{8317}\x{8318}\x{831C}\x{8323}' . +'\x{8328}\x{832B}\x{832F}\x{8331}\x{8332}\x{8334}\x{8335}\x{8336}\x{8338}' . +'\x{8339}\x{8340}\x{8345}\x{8349}\x{834A}\x{834F}\x{8350}\x{8352}\x{8358}' . +'\x{8373}\x{8375}\x{8377}\x{837B}\x{837C}\x{8385}\x{8387}\x{8389}\x{838A}' . +'\x{838E}\x{8393}\x{8396}\x{839A}\x{839E}\x{839F}\x{83A0}\x{83A2}\x{83A8}' . +'\x{83AA}\x{83AB}\x{83B1}\x{83B5}\x{83BD}\x{83C1}\x{83C5}\x{83CA}\x{83CC}' . +'\x{83CE}\x{83D3}\x{83D6}\x{83D8}\x{83DC}\x{83DF}\x{83E0}\x{83E9}\x{83EB}' . +'\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F4}\x{83F7}\x{83FB}\x{83FD}\x{8403}' . +'\x{8404}\x{8407}\x{840B}\x{840C}\x{840D}\x{840E}\x{8413}\x{8420}\x{8422}' . +'\x{8429}\x{842A}\x{842C}\x{8431}\x{8435}\x{8438}\x{843C}\x{843D}\x{8446}' . +'\x{8449}\x{844E}\x{8457}\x{845B}\x{8461}\x{8462}\x{8463}\x{8466}\x{8469}' . +'\x{846B}\x{846C}\x{846D}\x{846E}\x{846F}\x{8471}\x{8475}\x{8477}\x{8479}' . +'\x{847A}\x{8482}\x{8484}\x{848B}\x{8490}\x{8494}\x{8499}\x{849C}\x{849F}' . +'\x{84A1}\x{84AD}\x{84B2}\x{84B8}\x{84B9}\x{84BB}\x{84BC}\x{84BF}\x{84C1}' . +'\x{84C4}\x{84C6}\x{84C9}\x{84CA}\x{84CB}\x{84CD}\x{84D0}\x{84D1}\x{84D6}' . +'\x{84D9}\x{84DA}\x{84EC}\x{84EE}\x{84F4}\x{84FC}\x{84FF}\x{8500}\x{8506}' . +'\x{8511}\x{8513}\x{8514}\x{8515}\x{8517}\x{8518}\x{851A}\x{851F}\x{8521}' . +'\x{8526}\x{852C}\x{852D}\x{8535}\x{853D}\x{8540}\x{8541}\x{8543}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854E}\x{8555}\x{8557}\x{8558}\x{855A}\x{8563}' . +'\x{8568}\x{8569}\x{856A}\x{856D}\x{8577}\x{857E}\x{8580}\x{8584}\x{8587}' . +'\x{8588}\x{858A}\x{8590}\x{8591}\x{8594}\x{8597}\x{8599}\x{859B}\x{859C}' . +'\x{85A4}\x{85A6}\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AE}\x{85AF}' . +'\x{85B9}\x{85BA}\x{85C1}\x{85C9}\x{85CD}\x{85CF}\x{85D0}\x{85D5}\x{85DC}' . +'\x{85DD}\x{85E4}\x{85E5}\x{85E9}\x{85EA}\x{85F7}\x{85F9}\x{85FA}\x{85FB}' . +'\x{85FE}\x{8602}\x{8606}\x{8607}\x{860A}\x{860B}\x{8613}\x{8616}\x{8617}' . +'\x{861A}\x{8622}\x{862D}\x{862F}\x{8630}\x{863F}\x{864D}\x{864E}\x{8650}' . +'\x{8654}\x{8655}\x{865A}\x{865C}\x{865E}\x{865F}\x{8667}\x{866B}\x{8671}' . +'\x{8679}\x{867B}\x{868A}\x{868B}\x{868C}\x{8693}\x{8695}\x{86A3}\x{86A4}' . +'\x{86A9}\x{86AA}\x{86AB}\x{86AF}\x{86B0}\x{86B6}\x{86C4}\x{86C6}\x{86C7}' . +'\x{86C9}\x{86CB}\x{86CD}\x{86CE}\x{86D4}\x{86D9}\x{86DB}\x{86DE}\x{86DF}' . +'\x{86E4}\x{86E9}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F8}\x{86F9}\x{86FB}' . +'\x{86FE}\x{8700}\x{8702}\x{8703}\x{8706}\x{8708}\x{8709}\x{870A}\x{870D}' . +'\x{8711}\x{8712}\x{8718}\x{871A}\x{871C}\x{8725}\x{8729}\x{8734}\x{8737}' . +'\x{873B}\x{873F}\x{8749}\x{874B}\x{874C}\x{874E}\x{8753}\x{8755}\x{8757}' . +'\x{8759}\x{875F}\x{8760}\x{8763}\x{8766}\x{8768}\x{876A}\x{876E}\x{8774}' . +'\x{8776}\x{8778}\x{877F}\x{8782}\x{878D}\x{879F}\x{87A2}\x{87AB}\x{87AF}' . +'\x{87B3}\x{87BA}\x{87BB}\x{87BD}\x{87C0}\x{87C4}\x{87C6}\x{87C7}\x{87CB}' . +'\x{87D0}\x{87D2}\x{87E0}\x{87EF}\x{87F2}\x{87F6}\x{87F7}\x{87F9}\x{87FB}' . +'\x{87FE}\x{8805}\x{880D}\x{880E}\x{880F}\x{8811}\x{8815}\x{8816}\x{8821}' . +'\x{8822}\x{8823}\x{8827}\x{8831}\x{8836}\x{8839}\x{883B}\x{8840}\x{8842}' . +'\x{8844}\x{8846}\x{884C}\x{884D}\x{8852}\x{8853}\x{8857}\x{8859}\x{885B}' . +'\x{885D}\x{885E}\x{8861}\x{8862}\x{8863}\x{8868}\x{886B}\x{8870}\x{8872}' . +'\x{8875}\x{8877}\x{887D}\x{887E}\x{887F}\x{8881}\x{8882}\x{8888}\x{888B}' . +'\x{888D}\x{8892}\x{8896}\x{8897}\x{8899}\x{889E}\x{88A2}\x{88A4}\x{88AB}' . +'\x{88AE}\x{88B0}\x{88B1}\x{88B4}\x{88B5}\x{88B7}\x{88BF}\x{88C1}\x{88C2}' . +'\x{88C3}\x{88C4}\x{88C5}\x{88CF}\x{88D4}\x{88D5}\x{88D8}\x{88D9}\x{88DC}' . +'\x{88DD}\x{88DF}\x{88E1}\x{88E8}\x{88F2}\x{88F3}\x{88F4}\x{88F8}\x{88F9}' . +'\x{88FC}\x{88FD}\x{88FE}\x{8902}\x{8904}\x{8907}\x{890A}\x{890C}\x{8910}' . +'\x{8912}\x{8913}\x{891D}\x{891E}\x{8925}\x{892A}\x{892B}\x{8936}\x{8938}' . +'\x{893B}\x{8941}\x{8943}\x{8944}\x{894C}\x{894D}\x{8956}\x{895E}\x{895F}' . +'\x{8960}\x{8964}\x{8966}\x{896A}\x{896D}\x{896F}\x{8972}\x{8974}\x{8977}' . +'\x{897E}\x{897F}\x{8981}\x{8983}\x{8986}\x{8987}\x{8988}\x{898A}\x{898B}' . +'\x{898F}\x{8993}\x{8996}\x{8997}\x{8998}\x{899A}\x{89A1}\x{89A6}\x{89A7}' . +'\x{89A9}\x{89AA}\x{89AC}\x{89AF}\x{89B2}\x{89B3}\x{89BA}\x{89BD}\x{89BF}' . +'\x{89C0}\x{89D2}\x{89DA}\x{89DC}\x{89DD}\x{89E3}\x{89E6}\x{89E7}\x{89F4}' . +'\x{89F8}\x{8A00}\x{8A02}\x{8A03}\x{8A08}\x{8A0A}\x{8A0C}\x{8A0E}\x{8A10}' . +'\x{8A13}\x{8A16}\x{8A17}\x{8A18}\x{8A1B}\x{8A1D}\x{8A1F}\x{8A23}\x{8A25}' . +'\x{8A2A}\x{8A2D}\x{8A31}\x{8A33}\x{8A34}\x{8A36}\x{8A3A}\x{8A3B}\x{8A3C}' . +'\x{8A41}\x{8A46}\x{8A48}\x{8A50}\x{8A51}\x{8A52}\x{8A54}\x{8A55}\x{8A5B}' . +'\x{8A5E}\x{8A60}\x{8A62}\x{8A63}\x{8A66}\x{8A69}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A7C}\x{8A82}\x{8A84}\x{8A85}' . +'\x{8A87}\x{8A89}\x{8A8C}\x{8A8D}\x{8A91}\x{8A93}\x{8A95}\x{8A98}\x{8A9A}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA8}\x{8AAC}' . +'\x{8AAD}\x{8AB0}\x{8AB2}\x{8AB9}\x{8ABC}\x{8ABF}\x{8AC2}\x{8AC4}\x{8AC7}' . +'\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACF}\x{8AD2}\x{8AD6}\x{8ADA}\x{8ADB}\x{8ADC}' . +'\x{8ADE}\x{8AE0}\x{8AE1}\x{8AE2}\x{8AE4}\x{8AE6}\x{8AE7}\x{8AEB}\x{8AED}' . +'\x{8AEE}\x{8AF1}\x{8AF3}\x{8AF7}\x{8AF8}\x{8AFA}\x{8AFE}\x{8B00}\x{8B01}' . +'\x{8B02}\x{8B04}\x{8B07}\x{8B0C}\x{8B0E}\x{8B10}\x{8B14}\x{8B16}\x{8B17}' . +'\x{8B19}\x{8B1A}\x{8B1B}\x{8B1D}\x{8B20}\x{8B21}\x{8B26}\x{8B28}\x{8B2B}' . +'\x{8B2C}\x{8B33}\x{8B39}\x{8B3E}\x{8B41}\x{8B49}\x{8B4C}\x{8B4E}\x{8B4F}' . +'\x{8B56}\x{8B58}\x{8B5A}\x{8B5B}\x{8B5C}\x{8B5F}\x{8B66}\x{8B6B}\x{8B6C}' . +'\x{8B6F}\x{8B70}\x{8B71}\x{8B72}\x{8B74}\x{8B77}\x{8B7D}\x{8B80}\x{8B83}' . +'\x{8B8A}\x{8B8C}\x{8B8E}\x{8B90}\x{8B92}\x{8B93}\x{8B96}\x{8B99}\x{8B9A}' . +'\x{8C37}\x{8C3A}\x{8C3F}\x{8C41}\x{8C46}\x{8C48}\x{8C4A}\x{8C4C}\x{8C4E}' . +'\x{8C50}\x{8C55}\x{8C5A}\x{8C61}\x{8C62}\x{8C6A}\x{8C6B}\x{8C6C}\x{8C78}' . +'\x{8C79}\x{8C7A}\x{8C7C}\x{8C82}\x{8C85}\x{8C89}\x{8C8A}\x{8C8C}\x{8C8D}' . +'\x{8C8E}\x{8C94}\x{8C98}\x{8C9D}\x{8C9E}\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA7}' . +'\x{8CA8}\x{8CA9}\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}' . +'\x{8CB2}\x{8CB3}\x{8CB4}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CBB}\x{8CBC}\x{8CBD}' . +'\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}\x{8CC7}\x{8CC8}\x{8CCA}' . +'\x{8CCD}\x{8CCE}\x{8CD1}\x{8CD3}\x{8CDA}\x{8CDB}\x{8CDC}\x{8CDE}\x{8CE0}' . +'\x{8CE2}\x{8CE3}\x{8CE4}\x{8CE6}\x{8CEA}\x{8CED}\x{8CFA}\x{8CFB}\x{8CFC}' . +'\x{8CFD}\x{8D04}\x{8D05}\x{8D07}\x{8D08}\x{8D0A}\x{8D0B}\x{8D0D}\x{8D0F}' . +'\x{8D10}\x{8D13}\x{8D14}\x{8D16}\x{8D64}\x{8D66}\x{8D67}\x{8D6B}\x{8D6D}' . +'\x{8D70}\x{8D71}\x{8D73}\x{8D74}\x{8D77}\x{8D81}\x{8D85}\x{8D8A}\x{8D99}' . +'\x{8DA3}\x{8DA8}\x{8DB3}\x{8DBA}\x{8DBE}\x{8DC2}\x{8DCB}\x{8DCC}\x{8DCF}' . +'\x{8DD6}\x{8DDA}\x{8DDB}\x{8DDD}\x{8DDF}\x{8DE1}\x{8DE3}\x{8DE8}\x{8DEA}' . +'\x{8DEB}\x{8DEF}\x{8DF3}\x{8DF5}\x{8DFC}\x{8DFF}\x{8E08}\x{8E09}\x{8E0A}' . +'\x{8E0F}\x{8E10}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E2A}\x{8E30}\x{8E34}\x{8E35}' . +'\x{8E42}\x{8E44}\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4C}\x{8E50}\x{8E55}' . +'\x{8E59}\x{8E5F}\x{8E60}\x{8E63}\x{8E64}\x{8E72}\x{8E74}\x{8E76}\x{8E7C}' . +'\x{8E81}\x{8E84}\x{8E85}\x{8E87}\x{8E8A}\x{8E8B}\x{8E8D}\x{8E91}\x{8E93}' . +'\x{8E94}\x{8E99}\x{8EA1}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EBE}\x{8EC5}\x{8EC6}\x{8EC8}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ED2}' . +'\x{8EDB}\x{8EDF}\x{8EE2}\x{8EE3}\x{8EEB}\x{8EF8}\x{8EFB}\x{8EFC}\x{8EFD}' . +'\x{8EFE}\x{8F03}\x{8F05}\x{8F09}\x{8F0A}\x{8F0C}\x{8F12}\x{8F13}\x{8F14}' . +'\x{8F15}\x{8F19}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1F}\x{8F26}\x{8F29}\x{8F2A}' . +'\x{8F2F}\x{8F33}\x{8F38}\x{8F39}\x{8F3B}\x{8F3E}\x{8F3F}\x{8F42}\x{8F44}' . +'\x{8F45}\x{8F46}\x{8F49}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F57}\x{8F5C}\x{8F5F}' . +'\x{8F61}\x{8F62}\x{8F63}\x{8F64}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA3}' . +'\x{8FA7}\x{8FA8}\x{8FAD}\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB7}' . +'\x{8FBA}\x{8FBB}\x{8FBC}\x{8FBF}\x{8FC2}\x{8FC4}\x{8FC5}\x{8FCE}\x{8FD1}' . +'\x{8FD4}\x{8FDA}\x{8FE2}\x{8FE5}\x{8FE6}\x{8FE9}\x{8FEA}\x{8FEB}\x{8FED}' . +'\x{8FEF}\x{8FF0}\x{8FF4}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}\x{8FFD}\x{9000}' . +'\x{9001}\x{9003}\x{9005}\x{9006}\x{900B}\x{900D}\x{900E}\x{900F}\x{9010}' . +'\x{9011}\x{9013}\x{9014}\x{9015}\x{9016}\x{9017}\x{9019}\x{901A}\x{901D}' . +'\x{901E}\x{901F}\x{9020}\x{9021}\x{9022}\x{9023}\x{9027}\x{902E}\x{9031}' . +'\x{9032}\x{9035}\x{9036}\x{9038}\x{9039}\x{903C}\x{903E}\x{9041}\x{9042}' . +'\x{9045}\x{9047}\x{9049}\x{904A}\x{904B}\x{904D}\x{904E}\x{904F}\x{9050}' . +'\x{9051}\x{9052}\x{9053}\x{9054}\x{9055}\x{9056}\x{9058}\x{9059}\x{905C}' . +'\x{905E}\x{9060}\x{9061}\x{9063}\x{9065}\x{9068}\x{9069}\x{906D}\x{906E}' . +'\x{906F}\x{9072}\x{9075}\x{9076}\x{9077}\x{9078}\x{907A}\x{907C}\x{907D}' . +'\x{907F}\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9087}\x{9089}\x{908A}' . +'\x{908F}\x{9091}\x{90A3}\x{90A6}\x{90A8}\x{90AA}\x{90AF}\x{90B1}\x{90B5}' . +'\x{90B8}\x{90C1}\x{90CA}\x{90CE}\x{90DB}\x{90E1}\x{90E2}\x{90E4}\x{90E8}' . +'\x{90ED}\x{90F5}\x{90F7}\x{90FD}\x{9102}\x{9112}\x{9119}\x{912D}\x{9130}' . +'\x{9132}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}\x{914E}\x{9152}\x{9154}' . +'\x{9156}\x{9158}\x{9162}\x{9163}\x{9165}\x{9169}\x{916A}\x{916C}\x{9172}' . +'\x{9173}\x{9175}\x{9177}\x{9178}\x{9182}\x{9187}\x{9189}\x{918B}\x{918D}' . +'\x{9190}\x{9192}\x{9197}\x{919C}\x{91A2}\x{91A4}\x{91AA}\x{91AB}\x{91AF}' . +'\x{91B4}\x{91B5}\x{91B8}\x{91BA}\x{91C0}\x{91C1}\x{91C6}\x{91C7}\x{91C8}' . +'\x{91C9}\x{91CB}\x{91CC}\x{91CD}\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D6}' . +'\x{91D8}\x{91DB}\x{91DC}\x{91DD}\x{91DF}\x{91E1}\x{91E3}\x{91E6}\x{91E7}' . +'\x{91F5}\x{91F6}\x{91FC}\x{91FF}\x{920D}\x{920E}\x{9211}\x{9214}\x{9215}' . +'\x{921E}\x{9229}\x{922C}\x{9234}\x{9237}\x{923F}\x{9244}\x{9245}\x{9248}' . +'\x{9249}\x{924B}\x{9250}\x{9257}\x{925A}\x{925B}\x{925E}\x{9262}\x{9264}' . +'\x{9266}\x{9271}\x{927E}\x{9280}\x{9283}\x{9285}\x{9291}\x{9293}\x{9295}' . +'\x{9296}\x{9298}\x{929A}\x{929B}\x{929C}\x{92AD}\x{92B7}\x{92B9}\x{92CF}' . +'\x{92D2}\x{92E4}\x{92E9}\x{92EA}\x{92ED}\x{92F2}\x{92F3}\x{92F8}\x{92FA}' . +'\x{92FC}\x{9306}\x{930F}\x{9310}\x{9318}\x{9319}\x{931A}\x{9320}\x{9322}' . +'\x{9323}\x{9326}\x{9328}\x{932B}\x{932C}\x{932E}\x{932F}\x{9332}\x{9335}' . +'\x{933A}\x{933B}\x{9344}\x{934B}\x{934D}\x{9354}\x{9356}\x{935B}\x{935C}' . +'\x{9360}\x{936C}\x{936E}\x{9375}\x{937C}\x{937E}\x{938C}\x{9394}\x{9396}' . +'\x{9397}\x{939A}\x{93A7}\x{93AC}\x{93AD}\x{93AE}\x{93B0}\x{93B9}\x{93C3}' . +'\x{93C8}\x{93D0}\x{93D1}\x{93D6}\x{93D7}\x{93D8}\x{93DD}\x{93E1}\x{93E4}' . +'\x{93E5}\x{93E8}\x{9403}\x{9407}\x{9410}\x{9413}\x{9414}\x{9418}\x{9419}' . +'\x{941A}\x{9421}\x{942B}\x{9435}\x{9436}\x{9438}\x{943A}\x{9441}\x{9444}' . +'\x{9451}\x{9452}\x{9453}\x{945A}\x{945B}\x{945E}\x{9460}\x{9462}\x{946A}' . +'\x{9470}\x{9475}\x{9477}\x{947C}\x{947D}\x{947E}\x{947F}\x{9481}\x{9577}' . +'\x{9580}\x{9582}\x{9583}\x{9587}\x{9589}\x{958A}\x{958B}\x{958F}\x{9591}' . +'\x{9593}\x{9594}\x{9596}\x{9598}\x{9599}\x{95A0}\x{95A2}\x{95A3}\x{95A4}' . +'\x{95A5}\x{95A7}\x{95A8}\x{95AD}\x{95B2}\x{95B9}\x{95BB}\x{95BC}\x{95BE}' . +'\x{95C3}\x{95C7}\x{95CA}\x{95CC}\x{95CD}\x{95D4}\x{95D5}\x{95D6}\x{95D8}' . +'\x{95DC}\x{95E1}\x{95E2}\x{95E5}\x{961C}\x{9621}\x{9628}\x{962A}\x{962E}' . +'\x{962F}\x{9632}\x{963B}\x{963F}\x{9640}\x{9642}\x{9644}\x{964B}\x{964C}' . +'\x{964D}\x{964F}\x{9650}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9662}' . +'\x{9663}\x{9664}\x{9665}\x{9666}\x{966A}\x{966C}\x{9670}\x{9672}\x{9673}' . +'\x{9675}\x{9676}\x{9677}\x{9678}\x{967A}\x{967D}\x{9685}\x{9686}\x{9688}' . +'\x{968A}\x{968B}\x{968D}\x{968E}\x{968F}\x{9694}\x{9695}\x{9697}\x{9698}' . +'\x{9699}\x{969B}\x{969C}\x{96A0}\x{96A3}\x{96A7}\x{96A8}\x{96AA}\x{96B0}' . +'\x{96B1}\x{96B2}\x{96B4}\x{96B6}\x{96B7}\x{96B8}\x{96B9}\x{96BB}\x{96BC}' . +'\x{96C0}\x{96C1}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C9}\x{96CB}\x{96CC}' . +'\x{96CD}\x{96CE}\x{96D1}\x{96D5}\x{96D6}\x{96D9}\x{96DB}\x{96DC}\x{96E2}' . +'\x{96E3}\x{96E8}\x{96EA}\x{96EB}\x{96F0}\x{96F2}\x{96F6}\x{96F7}\x{96F9}' . +'\x{96FB}\x{9700}\x{9704}\x{9706}\x{9707}\x{9708}\x{970A}\x{970D}\x{970E}' . +'\x{970F}\x{9711}\x{9713}\x{9716}\x{9719}\x{971C}\x{971E}\x{9724}\x{9727}' . +'\x{972A}\x{9730}\x{9732}\x{9738}\x{9739}\x{973D}\x{973E}\x{9742}\x{9744}' . +'\x{9746}\x{9748}\x{9749}\x{9752}\x{9756}\x{9759}\x{975C}\x{975E}\x{9760}' . +'\x{9761}\x{9762}\x{9764}\x{9766}\x{9768}\x{9769}\x{976B}\x{976D}\x{9771}' . +'\x{9774}\x{9779}\x{977A}\x{977C}\x{9781}\x{9784}\x{9785}\x{9786}\x{978B}' . +'\x{978D}\x{978F}\x{9790}\x{9798}\x{979C}\x{97A0}\x{97A3}\x{97A6}\x{97A8}' . +'\x{97AB}\x{97AD}\x{97B3}\x{97B4}\x{97C3}\x{97C6}\x{97C8}\x{97CB}\x{97D3}' . +'\x{97DC}\x{97ED}\x{97EE}\x{97F2}\x{97F3}\x{97F5}\x{97F6}\x{97FB}\x{97FF}' . +'\x{9801}\x{9802}\x{9803}\x{9805}\x{9806}\x{9808}\x{980C}\x{980F}\x{9810}' . +'\x{9811}\x{9812}\x{9813}\x{9817}\x{9818}\x{981A}\x{9821}\x{9824}\x{982C}' . +'\x{982D}\x{9834}\x{9837}\x{9838}\x{983B}\x{983C}\x{983D}\x{9846}\x{984B}' . +'\x{984C}\x{984D}\x{984E}\x{984F}\x{9854}\x{9855}\x{9858}\x{985B}\x{985E}' . +'\x{9867}\x{986B}\x{986F}\x{9870}\x{9871}\x{9873}\x{9874}\x{98A8}\x{98AA}' . +'\x{98AF}\x{98B1}\x{98B6}\x{98C3}\x{98C4}\x{98C6}\x{98DB}\x{98DC}\x{98DF}' . +'\x{98E2}\x{98E9}\x{98EB}\x{98ED}\x{98EE}\x{98EF}\x{98F2}\x{98F4}\x{98FC}' . +'\x{98FD}\x{98FE}\x{9903}\x{9905}\x{9909}\x{990A}\x{990C}\x{9910}\x{9912}' . +'\x{9913}\x{9914}\x{9918}\x{991D}\x{991E}\x{9920}\x{9921}\x{9924}\x{9928}' . +'\x{992C}\x{992E}\x{993D}\x{993E}\x{9942}\x{9945}\x{9949}\x{994B}\x{994C}' . +'\x{9950}\x{9951}\x{9952}\x{9955}\x{9957}\x{9996}\x{9997}\x{9998}\x{9999}' . +'\x{99A5}\x{99A8}\x{99AC}\x{99AD}\x{99AE}\x{99B3}\x{99B4}\x{99BC}\x{99C1}' . +'\x{99C4}\x{99C5}\x{99C6}\x{99C8}\x{99D0}\x{99D1}\x{99D2}\x{99D5}\x{99D8}' . +'\x{99DB}\x{99DD}\x{99DF}\x{99E2}\x{99ED}\x{99EE}\x{99F1}\x{99F2}\x{99F8}' . +'\x{99FB}\x{99FF}\x{9A01}\x{9A05}\x{9A0E}\x{9A0F}\x{9A12}\x{9A13}\x{9A19}' . +'\x{9A28}\x{9A2B}\x{9A30}\x{9A37}\x{9A3E}\x{9A40}\x{9A42}\x{9A43}\x{9A45}' . +'\x{9A4D}\x{9A55}\x{9A57}\x{9A5A}\x{9A5B}\x{9A5F}\x{9A62}\x{9A64}\x{9A65}' . +'\x{9A69}\x{9A6A}\x{9A6B}\x{9AA8}\x{9AAD}\x{9AB0}\x{9AB8}\x{9ABC}\x{9AC0}' . +'\x{9AC4}\x{9ACF}\x{9AD1}\x{9AD3}\x{9AD4}\x{9AD8}\x{9ADE}\x{9ADF}\x{9AE2}' . +'\x{9AE3}\x{9AE6}\x{9AEA}\x{9AEB}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF4}' . +'\x{9AF7}\x{9AFB}\x{9B06}\x{9B18}\x{9B1A}\x{9B1F}\x{9B22}\x{9B23}\x{9B25}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2E}\x{9B2F}\x{9B31}\x{9B32}\x{9B3B}' . +'\x{9B3C}\x{9B41}\x{9B42}\x{9B43}\x{9B44}\x{9B45}\x{9B4D}\x{9B4E}\x{9B4F}' . +'\x{9B51}\x{9B54}\x{9B58}\x{9B5A}\x{9B6F}\x{9B74}\x{9B83}\x{9B8E}\x{9B91}' . +'\x{9B92}\x{9B93}\x{9B96}\x{9B97}\x{9B9F}\x{9BA0}\x{9BA8}\x{9BAA}\x{9BAB}' . +'\x{9BAD}\x{9BAE}\x{9BB4}\x{9BB9}\x{9BC0}\x{9BC6}\x{9BC9}\x{9BCA}\x{9BCF}' . +'\x{9BD1}\x{9BD2}\x{9BD4}\x{9BD6}\x{9BDB}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}' . +'\x{9BE8}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF5}\x{9C04}\x{9C06}\x{9C08}\x{9C09}' . +'\x{9C0A}\x{9C0C}\x{9C0D}\x{9C10}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C1B}' . +'\x{9C21}\x{9C24}\x{9C25}\x{9C2D}\x{9C2E}\x{9C2F}\x{9C30}\x{9C32}\x{9C39}' . +'\x{9C3A}\x{9C3B}\x{9C3E}\x{9C46}\x{9C47}\x{9C48}\x{9C52}\x{9C57}\x{9C5A}' . +'\x{9C60}\x{9C67}\x{9C76}\x{9C78}\x{9CE5}\x{9CE7}\x{9CE9}\x{9CEB}\x{9CEC}' . +'\x{9CF0}\x{9CF3}\x{9CF4}\x{9CF6}\x{9D03}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0E}\x{9D12}\x{9D15}\x{9D1B}\x{9D1F}\x{9D23}\x{9D26}\x{9D28}\x{9D2A}' . +'\x{9D2B}\x{9D2C}\x{9D3B}\x{9D3E}\x{9D3F}\x{9D41}\x{9D44}\x{9D46}\x{9D48}' . +'\x{9D50}\x{9D51}\x{9D59}\x{9D5C}\x{9D5D}\x{9D5E}\x{9D60}\x{9D61}\x{9D64}' . +'\x{9D6C}\x{9D6F}\x{9D72}\x{9D7A}\x{9D87}\x{9D89}\x{9D8F}\x{9D9A}\x{9DA4}' . +'\x{9DA9}\x{9DAB}\x{9DAF}\x{9DB2}\x{9DB4}\x{9DB8}\x{9DBA}\x{9DBB}\x{9DC1}' . +'\x{9DC2}\x{9DC4}\x{9DC6}\x{9DCF}\x{9DD3}\x{9DD9}\x{9DE6}\x{9DED}\x{9DEF}' . +'\x{9DF2}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFD}\x{9E1A}\x{9E1B}\x{9E1E}\x{9E75}' . +'\x{9E78}\x{9E79}\x{9E7D}\x{9E7F}\x{9E81}\x{9E88}\x{9E8B}\x{9E8C}\x{9E91}' . +'\x{9E92}\x{9E93}\x{9E95}\x{9E97}\x{9E9D}\x{9E9F}\x{9EA5}\x{9EA6}\x{9EA9}' . +'\x{9EAA}\x{9EAD}\x{9EB8}\x{9EB9}\x{9EBA}\x{9EBB}\x{9EBC}\x{9EBE}\x{9EBF}' . +'\x{9EC4}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED2}\x{9ED4}\x{9ED8}' . +'\x{9ED9}\x{9EDB}\x{9EDC}\x{9EDD}\x{9EDE}\x{9EE0}\x{9EE5}\x{9EE8}\x{9EEF}' . +'\x{9EF4}\x{9EF6}\x{9EF7}\x{9EF9}\x{9EFB}\x{9EFC}\x{9EFD}\x{9F07}\x{9F08}' . +'\x{9F0E}\x{9F13}\x{9F15}\x{9F20}\x{9F21}\x{9F2C}\x{9F3B}\x{9F3E}\x{9F4A}' . +'\x{9F4B}\x{9F4E}\x{9F4F}\x{9F52}\x{9F54}\x{9F5F}\x{9F60}\x{9F61}\x{9F62}' . +'\x{9F63}\x{9F66}\x{9F67}\x{9F6A}\x{9F6C}\x{9F72}\x{9F76}\x{9F77}\x{9F8D}' . +'\x{9F95}\x{9F9C}\x{9F9D}\x{9FA0}]{1,15}$/iu', + 12 => '/^[\x{002d}0-9a-z\x{3447}\x{3473}\x{359E}\x{360E}\x{361A}\x{3918}\x{396E}\x{39CF}\x{39D0}' . +'\x{39DF}\x{3A73}\x{3B4E}\x{3C6E}\x{3CE0}\x{4056}\x{415F}\x{4337}\x{43AC}' . +'\x{43B1}\x{43DD}\x{44D6}\x{464C}\x{4661}\x{4723}\x{4729}\x{477C}\x{478D}' . +'\x{4947}\x{497A}\x{497D}\x{4982}\x{4983}\x{4985}\x{4986}\x{499B}\x{499F}' . +'\x{49B6}\x{49B7}\x{4C77}\x{4C9F}\x{4CA0}\x{4CA1}\x{4CA2}\x{4CA3}\x{4D13}' . +'\x{4D14}\x{4D15}\x{4D16}\x{4D17}\x{4D18}\x{4D19}\x{4DAE}\x{4E00}\x{4E01}' . +'\x{4E02}\x{4E03}\x{4E04}\x{4E05}\x{4E06}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0C}\x{4E0D}\x{4E0E}\x{4E0F}\x{4E10}\x{4E11}\x{4E13}\x{4E14}' . +'\x{4E15}\x{4E16}\x{4E17}\x{4E18}\x{4E19}\x{4E1A}\x{4E1B}\x{4E1C}\x{4E1D}' . +'\x{4E1E}\x{4E1F}\x{4E20}\x{4E21}\x{4E22}\x{4E23}\x{4E24}\x{4E25}\x{4E26}' . +'\x{4E27}\x{4E28}\x{4E2A}\x{4E2B}\x{4E2C}\x{4E2D}\x{4E2E}\x{4E2F}\x{4E30}' . +'\x{4E31}\x{4E32}\x{4E33}\x{4E34}\x{4E35}\x{4E36}\x{4E37}\x{4E38}\x{4E39}' . +'\x{4E3A}\x{4E3B}\x{4E3C}\x{4E3D}\x{4E3E}\x{4E3F}\x{4E40}\x{4E41}\x{4E42}' . +'\x{4E43}\x{4E44}\x{4E45}\x{4E46}\x{4E47}\x{4E48}\x{4E49}\x{4E4A}\x{4E4B}' . +'\x{4E4C}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E50}\x{4E51}\x{4E52}\x{4E53}\x{4E54}' . +'\x{4E56}\x{4E57}\x{4E58}\x{4E59}\x{4E5A}\x{4E5B}\x{4E5C}\x{4E5D}\x{4E5E}' . +'\x{4E5F}\x{4E60}\x{4E61}\x{4E62}\x{4E63}\x{4E64}\x{4E65}\x{4E66}\x{4E67}' . +'\x{4E69}\x{4E6A}\x{4E6B}\x{4E6C}\x{4E6D}\x{4E6E}\x{4E6F}\x{4E70}\x{4E71}' . +'\x{4E72}\x{4E73}\x{4E74}\x{4E75}\x{4E76}\x{4E77}\x{4E78}\x{4E7A}\x{4E7B}' . +'\x{4E7C}\x{4E7D}\x{4E7E}\x{4E7F}\x{4E80}\x{4E81}\x{4E82}\x{4E83}\x{4E84}' . +'\x{4E85}\x{4E86}\x{4E87}\x{4E88}\x{4E89}\x{4E8B}\x{4E8C}\x{4E8D}\x{4E8E}' . +'\x{4E8F}\x{4E90}\x{4E91}\x{4E92}\x{4E93}\x{4E94}\x{4E95}\x{4E97}\x{4E98}' . +'\x{4E99}\x{4E9A}\x{4E9B}\x{4E9C}\x{4E9D}\x{4E9E}\x{4E9F}\x{4EA0}\x{4EA1}' . +'\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA7}\x{4EA8}\x{4EA9}\x{4EAA}\x{4EAB}' . +'\x{4EAC}\x{4EAD}\x{4EAE}\x{4EAF}\x{4EB0}\x{4EB1}\x{4EB2}\x{4EB3}\x{4EB4}' . +'\x{4EB5}\x{4EB6}\x{4EB7}\x{4EB8}\x{4EB9}\x{4EBA}\x{4EBB}\x{4EBD}\x{4EBE}' . +'\x{4EBF}\x{4EC0}\x{4EC1}\x{4EC2}\x{4EC3}\x{4EC4}\x{4EC5}\x{4EC6}\x{4EC7}' . +'\x{4EC8}\x{4EC9}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED0}\x{4ED1}' . +'\x{4ED2}\x{4ED3}\x{4ED4}\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDA}' . +'\x{4EDB}\x{4EDC}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE0}\x{4EE1}\x{4EE2}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EE6}\x{4EE8}\x{4EE9}\x{4EEA}\x{4EEB}\x{4EEC}\x{4EEF}' . +'\x{4EF0}\x{4EF1}\x{4EF2}\x{4EF3}\x{4EF4}\x{4EF5}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4EFD}\x{4EFF}\x{4F00}\x{4F01}\x{4F02}\x{4F03}\x{4F04}\x{4F05}\x{4F06}' . +'\x{4F08}\x{4F09}\x{4F0A}\x{4F0B}\x{4F0C}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}' . +'\x{4F11}\x{4F12}\x{4F13}\x{4F14}\x{4F15}\x{4F17}\x{4F18}\x{4F19}\x{4F1A}' . +'\x{4F1B}\x{4F1C}\x{4F1D}\x{4F1E}\x{4F1F}\x{4F20}\x{4F21}\x{4F22}\x{4F23}' . +'\x{4F24}\x{4F25}\x{4F26}\x{4F27}\x{4F29}\x{4F2A}\x{4F2B}\x{4F2C}\x{4F2D}' . +'\x{4F2E}\x{4F2F}\x{4F30}\x{4F32}\x{4F33}\x{4F34}\x{4F36}\x{4F38}\x{4F39}' . +'\x{4F3A}\x{4F3B}\x{4F3C}\x{4F3D}\x{4F3E}\x{4F3F}\x{4F41}\x{4F42}\x{4F43}' . +'\x{4F45}\x{4F46}\x{4F47}\x{4F48}\x{4F49}\x{4F4A}\x{4F4B}\x{4F4C}\x{4F4D}' . +'\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}\x{4F52}\x{4F53}\x{4F54}\x{4F55}\x{4F56}' . +'\x{4F57}\x{4F58}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}\x{4F5F}' . +'\x{4F60}\x{4F61}\x{4F62}\x{4F63}\x{4F64}\x{4F65}\x{4F66}\x{4F67}\x{4F68}' . +'\x{4F69}\x{4F6A}\x{4F6B}\x{4F6C}\x{4F6D}\x{4F6E}\x{4F6F}\x{4F70}\x{4F72}' . +'\x{4F73}\x{4F74}\x{4F75}\x{4F76}\x{4F77}\x{4F78}\x{4F79}\x{4F7A}\x{4F7B}' . +'\x{4F7C}\x{4F7D}\x{4F7E}\x{4F7F}\x{4F80}\x{4F81}\x{4F82}\x{4F83}\x{4F84}' . +'\x{4F85}\x{4F86}\x{4F87}\x{4F88}\x{4F89}\x{4F8A}\x{4F8B}\x{4F8D}\x{4F8F}' . +'\x{4F90}\x{4F91}\x{4F92}\x{4F93}\x{4F94}\x{4F95}\x{4F96}\x{4F97}\x{4F98}' . +'\x{4F99}\x{4F9A}\x{4F9B}\x{4F9C}\x{4F9D}\x{4F9E}\x{4F9F}\x{4FA0}\x{4FA1}' . +'\x{4FA3}\x{4FA4}\x{4FA5}\x{4FA6}\x{4FA7}\x{4FA8}\x{4FA9}\x{4FAA}\x{4FAB}' . +'\x{4FAC}\x{4FAE}\x{4FAF}\x{4FB0}\x{4FB1}\x{4FB2}\x{4FB3}\x{4FB4}\x{4FB5}' . +'\x{4FB6}\x{4FB7}\x{4FB8}\x{4FB9}\x{4FBA}\x{4FBB}\x{4FBC}\x{4FBE}\x{4FBF}' . +'\x{4FC0}\x{4FC1}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FC5}\x{4FC7}\x{4FC9}\x{4FCA}' . +'\x{4FCB}\x{4FCD}\x{4FCE}\x{4FCF}\x{4FD0}\x{4FD1}\x{4FD2}\x{4FD3}\x{4FD4}' . +'\x{4FD5}\x{4FD6}\x{4FD7}\x{4FD8}\x{4FD9}\x{4FDA}\x{4FDB}\x{4FDC}\x{4FDD}' . +'\x{4FDE}\x{4FDF}\x{4FE0}\x{4FE1}\x{4FE3}\x{4FE4}\x{4FE5}\x{4FE6}\x{4FE7}' . +'\x{4FE8}\x{4FE9}\x{4FEA}\x{4FEB}\x{4FEC}\x{4FED}\x{4FEE}\x{4FEF}\x{4FF0}' . +'\x{4FF1}\x{4FF2}\x{4FF3}\x{4FF4}\x{4FF5}\x{4FF6}\x{4FF7}\x{4FF8}\x{4FF9}' . +'\x{4FFA}\x{4FFB}\x{4FFE}\x{4FFF}\x{5000}\x{5001}\x{5002}\x{5003}\x{5004}' . +'\x{5005}\x{5006}\x{5007}\x{5008}\x{5009}\x{500A}\x{500B}\x{500C}\x{500D}' . +'\x{500E}\x{500F}\x{5011}\x{5012}\x{5013}\x{5014}\x{5015}\x{5016}\x{5017}' . +'\x{5018}\x{5019}\x{501A}\x{501B}\x{501C}\x{501D}\x{501E}\x{501F}\x{5020}' . +'\x{5021}\x{5022}\x{5023}\x{5024}\x{5025}\x{5026}\x{5027}\x{5028}\x{5029}' . +'\x{502A}\x{502B}\x{502C}\x{502D}\x{502E}\x{502F}\x{5030}\x{5031}\x{5032}' . +'\x{5033}\x{5035}\x{5036}\x{5037}\x{5039}\x{503A}\x{503B}\x{503C}\x{503E}' . +'\x{503F}\x{5040}\x{5041}\x{5043}\x{5044}\x{5045}\x{5046}\x{5047}\x{5048}' . +'\x{5049}\x{504A}\x{504B}\x{504C}\x{504D}\x{504E}\x{504F}\x{5051}\x{5053}' . +'\x{5054}\x{5055}\x{5056}\x{5057}\x{5059}\x{505A}\x{505B}\x{505C}\x{505D}' . +'\x{505E}\x{505F}\x{5060}\x{5061}\x{5062}\x{5063}\x{5064}\x{5065}\x{5066}' . +'\x{5067}\x{5068}\x{5069}\x{506A}\x{506B}\x{506C}\x{506D}\x{506E}\x{506F}' . +'\x{5070}\x{5071}\x{5072}\x{5073}\x{5074}\x{5075}\x{5076}\x{5077}\x{5078}' . +'\x{5079}\x{507A}\x{507B}\x{507D}\x{507E}\x{507F}\x{5080}\x{5082}\x{5083}' . +'\x{5084}\x{5085}\x{5086}\x{5087}\x{5088}\x{5089}\x{508A}\x{508B}\x{508C}' . +'\x{508D}\x{508E}\x{508F}\x{5090}\x{5091}\x{5092}\x{5094}\x{5095}\x{5096}' . +'\x{5098}\x{5099}\x{509A}\x{509B}\x{509C}\x{509D}\x{509E}\x{50A2}\x{50A3}' . +'\x{50A4}\x{50A5}\x{50A6}\x{50A7}\x{50A8}\x{50A9}\x{50AA}\x{50AB}\x{50AC}' . +'\x{50AD}\x{50AE}\x{50AF}\x{50B0}\x{50B1}\x{50B2}\x{50B3}\x{50B4}\x{50B5}' . +'\x{50B6}\x{50B7}\x{50B8}\x{50BA}\x{50BB}\x{50BC}\x{50BD}\x{50BE}\x{50BF}' . +'\x{50C0}\x{50C1}\x{50C2}\x{50C4}\x{50C5}\x{50C6}\x{50C7}\x{50C8}\x{50C9}' . +'\x{50CA}\x{50CB}\x{50CC}\x{50CD}\x{50CE}\x{50CF}\x{50D0}\x{50D1}\x{50D2}' . +'\x{50D3}\x{50D4}\x{50D5}\x{50D6}\x{50D7}\x{50D9}\x{50DA}\x{50DB}\x{50DC}' . +'\x{50DD}\x{50DE}\x{50E0}\x{50E3}\x{50E4}\x{50E5}\x{50E6}\x{50E7}\x{50E8}' . +'\x{50E9}\x{50EA}\x{50EC}\x{50ED}\x{50EE}\x{50EF}\x{50F0}\x{50F1}\x{50F2}' . +'\x{50F3}\x{50F5}\x{50F6}\x{50F8}\x{50F9}\x{50FA}\x{50FB}\x{50FC}\x{50FD}' . +'\x{50FE}\x{50FF}\x{5100}\x{5101}\x{5102}\x{5103}\x{5104}\x{5105}\x{5106}' . +'\x{5107}\x{5108}\x{5109}\x{510A}\x{510B}\x{510C}\x{510D}\x{510E}\x{510F}' . +'\x{5110}\x{5111}\x{5112}\x{5113}\x{5114}\x{5115}\x{5116}\x{5117}\x{5118}' . +'\x{5119}\x{511A}\x{511C}\x{511D}\x{511E}\x{511F}\x{5120}\x{5121}\x{5122}' . +'\x{5123}\x{5124}\x{5125}\x{5126}\x{5127}\x{5129}\x{512A}\x{512C}\x{512D}' . +'\x{512E}\x{512F}\x{5130}\x{5131}\x{5132}\x{5133}\x{5134}\x{5135}\x{5136}' . +'\x{5137}\x{5138}\x{5139}\x{513A}\x{513B}\x{513C}\x{513D}\x{513E}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5151}\x{5152}\x{5154}\x{5155}' . +'\x{5156}\x{5157}\x{5159}\x{515A}\x{515B}\x{515C}\x{515D}\x{515E}\x{515F}' . +'\x{5161}\x{5162}\x{5163}\x{5165}\x{5166}\x{5167}\x{5168}\x{5169}\x{516A}' . +'\x{516B}\x{516C}\x{516D}\x{516E}\x{516F}\x{5170}\x{5171}\x{5173}\x{5174}' . +'\x{5175}\x{5176}\x{5177}\x{5178}\x{5179}\x{517A}\x{517B}\x{517C}\x{517D}' . +'\x{517F}\x{5180}\x{5181}\x{5182}\x{5185}\x{5186}\x{5187}\x{5188}\x{5189}' . +'\x{518A}\x{518B}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}\x{5193}' . +'\x{5194}\x{5195}\x{5196}\x{5197}\x{5198}\x{5199}\x{519A}\x{519B}\x{519C}' . +'\x{519D}\x{519E}\x{519F}\x{51A0}\x{51A2}\x{51A4}\x{51A5}\x{51A6}\x{51A7}' . +'\x{51A8}\x{51AA}\x{51AB}\x{51AC}\x{51AE}\x{51AF}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B5}\x{51B6}\x{51B7}\x{51B9}\x{51BB}\x{51BC}\x{51BD}\x{51BE}' . +'\x{51BF}\x{51C0}\x{51C1}\x{51C3}\x{51C4}\x{51C5}\x{51C6}\x{51C7}\x{51C8}' . +'\x{51C9}\x{51CA}\x{51CB}\x{51CC}\x{51CD}\x{51CE}\x{51CF}\x{51D0}\x{51D1}' . +'\x{51D4}\x{51D5}\x{51D6}\x{51D7}\x{51D8}\x{51D9}\x{51DA}\x{51DB}\x{51DC}' . +'\x{51DD}\x{51DE}\x{51E0}\x{51E1}\x{51E2}\x{51E3}\x{51E4}\x{51E5}\x{51E7}' . +'\x{51E8}\x{51E9}\x{51EA}\x{51EB}\x{51ED}\x{51EF}\x{51F0}\x{51F1}\x{51F3}' . +'\x{51F4}\x{51F5}\x{51F6}\x{51F7}\x{51F8}\x{51F9}\x{51FA}\x{51FB}\x{51FC}' . +'\x{51FD}\x{51FE}\x{51FF}\x{5200}\x{5201}\x{5202}\x{5203}\x{5204}\x{5205}' . +'\x{5206}\x{5207}\x{5208}\x{5209}\x{520A}\x{520B}\x{520C}\x{520D}\x{520E}' . +'\x{520F}\x{5210}\x{5211}\x{5212}\x{5213}\x{5214}\x{5215}\x{5216}\x{5217}' . +'\x{5218}\x{5219}\x{521A}\x{521B}\x{521C}\x{521D}\x{521E}\x{521F}\x{5220}' . +'\x{5221}\x{5222}\x{5223}\x{5224}\x{5225}\x{5226}\x{5228}\x{5229}\x{522A}' . +'\x{522B}\x{522C}\x{522D}\x{522E}\x{522F}\x{5230}\x{5231}\x{5232}\x{5233}' . +'\x{5234}\x{5235}\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{523C}' . +'\x{523D}\x{523E}\x{523F}\x{5240}\x{5241}\x{5242}\x{5243}\x{5244}\x{5245}' . +'\x{5246}\x{5247}\x{5248}\x{5249}\x{524A}\x{524B}\x{524C}\x{524D}\x{524E}' . +'\x{5250}\x{5251}\x{5252}\x{5254}\x{5255}\x{5256}\x{5257}\x{5258}\x{5259}' . +'\x{525A}\x{525B}\x{525C}\x{525D}\x{525E}\x{525F}\x{5260}\x{5261}\x{5262}' . +'\x{5263}\x{5264}\x{5265}\x{5267}\x{5268}\x{5269}\x{526A}\x{526B}\x{526C}' . +'\x{526D}\x{526E}\x{526F}\x{5270}\x{5272}\x{5273}\x{5274}\x{5275}\x{5276}' . +'\x{5277}\x{5278}\x{527A}\x{527B}\x{527C}\x{527D}\x{527E}\x{527F}\x{5280}' . +'\x{5281}\x{5282}\x{5283}\x{5284}\x{5286}\x{5287}\x{5288}\x{5289}\x{528A}' . +'\x{528B}\x{528C}\x{528D}\x{528F}\x{5290}\x{5291}\x{5292}\x{5293}\x{5294}' . +'\x{5295}\x{5296}\x{5297}\x{5298}\x{5299}\x{529A}\x{529B}\x{529C}\x{529D}' . +'\x{529E}\x{529F}\x{52A0}\x{52A1}\x{52A2}\x{52A3}\x{52A5}\x{52A6}\x{52A7}' . +'\x{52A8}\x{52A9}\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52AE}\x{52AF}\x{52B0}' . +'\x{52B1}\x{52B2}\x{52B3}\x{52B4}\x{52B5}\x{52B6}\x{52B7}\x{52B8}\x{52B9}' . +'\x{52BA}\x{52BB}\x{52BC}\x{52BD}\x{52BE}\x{52BF}\x{52C0}\x{52C1}\x{52C2}' . +'\x{52C3}\x{52C6}\x{52C7}\x{52C9}\x{52CA}\x{52CB}\x{52CD}\x{52CF}\x{52D0}' . +'\x{52D2}\x{52D3}\x{52D5}\x{52D6}\x{52D7}\x{52D8}\x{52D9}\x{52DA}\x{52DB}' . +'\x{52DC}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}\x{52E4}\x{52E6}' . +'\x{52E7}\x{52E8}\x{52E9}\x{52EA}\x{52EB}\x{52EC}\x{52ED}\x{52EF}\x{52F0}' . +'\x{52F1}\x{52F2}\x{52F3}\x{52F4}\x{52F5}\x{52F6}\x{52F7}\x{52F8}\x{52F9}' . +'\x{52FA}\x{52FB}\x{52FC}\x{52FD}\x{52FE}\x{52FF}\x{5300}\x{5301}\x{5302}' . +'\x{5305}\x{5306}\x{5307}\x{5308}\x{5309}\x{530A}\x{530B}\x{530C}\x{530D}' . +'\x{530E}\x{530F}\x{5310}\x{5311}\x{5312}\x{5313}\x{5314}\x{5315}\x{5316}' . +'\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}\x{5320}\x{5321}\x{5322}' . +'\x{5323}\x{5324}\x{5325}\x{5326}\x{5328}\x{532A}\x{532B}\x{532C}\x{532D}' . +'\x{532E}\x{532F}\x{5330}\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}\x{533A}' . +'\x{533B}\x{533C}\x{533D}\x{533E}\x{533F}\x{5340}\x{5341}\x{5343}\x{5344}' . +'\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}\x{534A}\x{534B}\x{534C}\x{534D}' . +'\x{534E}\x{534F}\x{5350}\x{5351}\x{5352}\x{5353}\x{5354}\x{5355}\x{5356}' . +'\x{5357}\x{5358}\x{5359}\x{535A}\x{535C}\x{535E}\x{535F}\x{5360}\x{5361}' . +'\x{5362}\x{5363}\x{5364}\x{5365}\x{5366}\x{5367}\x{5369}\x{536B}\x{536C}' . +'\x{536E}\x{536F}\x{5370}\x{5371}\x{5372}\x{5373}\x{5374}\x{5375}\x{5376}' . +'\x{5377}\x{5378}\x{5379}\x{537A}\x{537B}\x{537C}\x{537D}\x{537E}\x{537F}' . +'\x{5381}\x{5382}\x{5383}\x{5384}\x{5385}\x{5386}\x{5387}\x{5388}\x{5389}' . +'\x{538A}\x{538B}\x{538C}\x{538D}\x{538E}\x{538F}\x{5390}\x{5391}\x{5392}' . +'\x{5393}\x{5394}\x{5395}\x{5396}\x{5397}\x{5398}\x{5399}\x{539A}\x{539B}' . +'\x{539C}\x{539D}\x{539E}\x{539F}\x{53A0}\x{53A2}\x{53A3}\x{53A4}\x{53A5}' . +'\x{53A6}\x{53A7}\x{53A8}\x{53A9}\x{53AC}\x{53AD}\x{53AE}\x{53B0}\x{53B1}' . +'\x{53B2}\x{53B3}\x{53B4}\x{53B5}\x{53B6}\x{53B7}\x{53B8}\x{53B9}\x{53BB}' . +'\x{53BC}\x{53BD}\x{53BE}\x{53BF}\x{53C0}\x{53C1}\x{53C2}\x{53C3}\x{53C4}' . +'\x{53C6}\x{53C7}\x{53C8}\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}' . +'\x{53D0}\x{53D1}\x{53D2}\x{53D3}\x{53D4}\x{53D5}\x{53D6}\x{53D7}\x{53D8}' . +'\x{53D9}\x{53DB}\x{53DC}\x{53DF}\x{53E0}\x{53E1}\x{53E2}\x{53E3}\x{53E4}' . +'\x{53E5}\x{53E6}\x{53E8}\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}' . +'\x{53EF}\x{53F0}\x{53F1}\x{53F2}\x{53F3}\x{53F4}\x{53F5}\x{53F6}\x{53F7}' . +'\x{53F8}\x{53F9}\x{53FA}\x{53FB}\x{53FC}\x{53FD}\x{53FE}\x{5401}\x{5402}' . +'\x{5403}\x{5404}\x{5405}\x{5406}\x{5407}\x{5408}\x{5409}\x{540A}\x{540B}' . +'\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}\x{5411}\x{5412}\x{5413}\x{5414}' . +'\x{5415}\x{5416}\x{5417}\x{5418}\x{5419}\x{541B}\x{541C}\x{541D}\x{541E}' . +'\x{541F}\x{5420}\x{5421}\x{5423}\x{5424}\x{5425}\x{5426}\x{5427}\x{5428}' . +'\x{5429}\x{542A}\x{542B}\x{542C}\x{542D}\x{542E}\x{542F}\x{5430}\x{5431}' . +'\x{5432}\x{5433}\x{5434}\x{5435}\x{5436}\x{5437}\x{5438}\x{5439}\x{543A}' . +'\x{543B}\x{543C}\x{543D}\x{543E}\x{543F}\x{5440}\x{5441}\x{5442}\x{5443}' . +'\x{5444}\x{5445}\x{5446}\x{5447}\x{5448}\x{5449}\x{544A}\x{544B}\x{544D}' . +'\x{544E}\x{544F}\x{5450}\x{5451}\x{5452}\x{5453}\x{5454}\x{5455}\x{5456}' . +'\x{5457}\x{5458}\x{5459}\x{545A}\x{545B}\x{545C}\x{545E}\x{545F}\x{5460}' . +'\x{5461}\x{5462}\x{5463}\x{5464}\x{5465}\x{5466}\x{5467}\x{5468}\x{546A}' . +'\x{546B}\x{546C}\x{546D}\x{546E}\x{546F}\x{5470}\x{5471}\x{5472}\x{5473}' . +'\x{5474}\x{5475}\x{5476}\x{5477}\x{5478}\x{5479}\x{547A}\x{547B}\x{547C}' . +'\x{547D}\x{547E}\x{547F}\x{5480}\x{5481}\x{5482}\x{5483}\x{5484}\x{5485}' . +'\x{5486}\x{5487}\x{5488}\x{5489}\x{548B}\x{548C}\x{548D}\x{548E}\x{548F}' . +'\x{5490}\x{5491}\x{5492}\x{5493}\x{5494}\x{5495}\x{5496}\x{5497}\x{5498}' . +'\x{5499}\x{549A}\x{549B}\x{549C}\x{549D}\x{549E}\x{549F}\x{54A0}\x{54A1}' . +'\x{54A2}\x{54A3}\x{54A4}\x{54A5}\x{54A6}\x{54A7}\x{54A8}\x{54A9}\x{54AA}' . +'\x{54AB}\x{54AC}\x{54AD}\x{54AE}\x{54AF}\x{54B0}\x{54B1}\x{54B2}\x{54B3}' . +'\x{54B4}\x{54B6}\x{54B7}\x{54B8}\x{54B9}\x{54BA}\x{54BB}\x{54BC}\x{54BD}' . +'\x{54BE}\x{54BF}\x{54C0}\x{54C1}\x{54C2}\x{54C3}\x{54C4}\x{54C5}\x{54C6}' . +'\x{54C7}\x{54C8}\x{54C9}\x{54CA}\x{54CB}\x{54CC}\x{54CD}\x{54CE}\x{54CF}' . +'\x{54D0}\x{54D1}\x{54D2}\x{54D3}\x{54D4}\x{54D5}\x{54D6}\x{54D7}\x{54D8}' . +'\x{54D9}\x{54DA}\x{54DB}\x{54DC}\x{54DD}\x{54DE}\x{54DF}\x{54E0}\x{54E1}' . +'\x{54E2}\x{54E3}\x{54E4}\x{54E5}\x{54E6}\x{54E7}\x{54E8}\x{54E9}\x{54EA}' . +'\x{54EB}\x{54EC}\x{54ED}\x{54EE}\x{54EF}\x{54F0}\x{54F1}\x{54F2}\x{54F3}' . +'\x{54F4}\x{54F5}\x{54F7}\x{54F8}\x{54F9}\x{54FA}\x{54FB}\x{54FC}\x{54FD}' . +'\x{54FE}\x{54FF}\x{5500}\x{5501}\x{5502}\x{5503}\x{5504}\x{5505}\x{5506}' . +'\x{5507}\x{5508}\x{5509}\x{550A}\x{550B}\x{550C}\x{550D}\x{550E}\x{550F}' . +'\x{5510}\x{5511}\x{5512}\x{5513}\x{5514}\x{5516}\x{5517}\x{551A}\x{551B}' . +'\x{551C}\x{551D}\x{551E}\x{551F}\x{5520}\x{5521}\x{5522}\x{5523}\x{5524}' . +'\x{5525}\x{5526}\x{5527}\x{5528}\x{5529}\x{552A}\x{552B}\x{552C}\x{552D}' . +'\x{552E}\x{552F}\x{5530}\x{5531}\x{5532}\x{5533}\x{5534}\x{5535}\x{5536}' . +'\x{5537}\x{5538}\x{5539}\x{553A}\x{553B}\x{553C}\x{553D}\x{553E}\x{553F}' . +'\x{5540}\x{5541}\x{5542}\x{5543}\x{5544}\x{5545}\x{5546}\x{5548}\x{5549}' . +'\x{554A}\x{554B}\x{554C}\x{554D}\x{554E}\x{554F}\x{5550}\x{5551}\x{5552}' . +'\x{5553}\x{5554}\x{5555}\x{5556}\x{5557}\x{5558}\x{5559}\x{555A}\x{555B}' . +'\x{555C}\x{555D}\x{555E}\x{555F}\x{5561}\x{5562}\x{5563}\x{5564}\x{5565}' . +'\x{5566}\x{5567}\x{5568}\x{5569}\x{556A}\x{556B}\x{556C}\x{556D}\x{556E}' . +'\x{556F}\x{5570}\x{5571}\x{5572}\x{5573}\x{5574}\x{5575}\x{5576}\x{5577}' . +'\x{5578}\x{5579}\x{557B}\x{557C}\x{557D}\x{557E}\x{557F}\x{5580}\x{5581}' . +'\x{5582}\x{5583}\x{5584}\x{5585}\x{5586}\x{5587}\x{5588}\x{5589}\x{558A}' . +'\x{558B}\x{558C}\x{558D}\x{558E}\x{558F}\x{5590}\x{5591}\x{5592}\x{5593}' . +'\x{5594}\x{5595}\x{5596}\x{5597}\x{5598}\x{5599}\x{559A}\x{559B}\x{559C}' . +'\x{559D}\x{559E}\x{559F}\x{55A0}\x{55A1}\x{55A2}\x{55A3}\x{55A4}\x{55A5}' . +'\x{55A6}\x{55A7}\x{55A8}\x{55A9}\x{55AA}\x{55AB}\x{55AC}\x{55AD}\x{55AE}' . +'\x{55AF}\x{55B0}\x{55B1}\x{55B2}\x{55B3}\x{55B4}\x{55B5}\x{55B6}\x{55B7}' . +'\x{55B8}\x{55B9}\x{55BA}\x{55BB}\x{55BC}\x{55BD}\x{55BE}\x{55BF}\x{55C0}' . +'\x{55C1}\x{55C2}\x{55C3}\x{55C4}\x{55C5}\x{55C6}\x{55C7}\x{55C8}\x{55C9}' . +'\x{55CA}\x{55CB}\x{55CC}\x{55CD}\x{55CE}\x{55CF}\x{55D0}\x{55D1}\x{55D2}' . +'\x{55D3}\x{55D4}\x{55D5}\x{55D6}\x{55D7}\x{55D8}\x{55D9}\x{55DA}\x{55DB}' . +'\x{55DC}\x{55DD}\x{55DE}\x{55DF}\x{55E1}\x{55E2}\x{55E3}\x{55E4}\x{55E5}' . +'\x{55E6}\x{55E7}\x{55E8}\x{55E9}\x{55EA}\x{55EB}\x{55EC}\x{55ED}\x{55EE}' . +'\x{55EF}\x{55F0}\x{55F1}\x{55F2}\x{55F3}\x{55F4}\x{55F5}\x{55F6}\x{55F7}' . +'\x{55F9}\x{55FA}\x{55FB}\x{55FC}\x{55FD}\x{55FE}\x{55FF}\x{5600}\x{5601}' . +'\x{5602}\x{5603}\x{5604}\x{5606}\x{5607}\x{5608}\x{5609}\x{560C}\x{560D}' . +'\x{560E}\x{560F}\x{5610}\x{5611}\x{5612}\x{5613}\x{5614}\x{5615}\x{5616}' . +'\x{5617}\x{5618}\x{5619}\x{561A}\x{561B}\x{561C}\x{561D}\x{561E}\x{561F}' . +'\x{5621}\x{5622}\x{5623}\x{5624}\x{5625}\x{5626}\x{5627}\x{5628}\x{5629}' . +'\x{562A}\x{562C}\x{562D}\x{562E}\x{562F}\x{5630}\x{5631}\x{5632}\x{5633}' . +'\x{5634}\x{5635}\x{5636}\x{5638}\x{5639}\x{563A}\x{563B}\x{563D}\x{563E}' . +'\x{563F}\x{5640}\x{5641}\x{5642}\x{5643}\x{5645}\x{5646}\x{5647}\x{5648}' . +'\x{5649}\x{564A}\x{564C}\x{564D}\x{564E}\x{564F}\x{5650}\x{5652}\x{5653}' . +'\x{5654}\x{5655}\x{5657}\x{5658}\x{5659}\x{565A}\x{565B}\x{565C}\x{565D}' . +'\x{565E}\x{5660}\x{5662}\x{5663}\x{5664}\x{5665}\x{5666}\x{5667}\x{5668}' . +'\x{5669}\x{566A}\x{566B}\x{566C}\x{566D}\x{566E}\x{566F}\x{5670}\x{5671}' . +'\x{5672}\x{5673}\x{5674}\x{5676}\x{5677}\x{5678}\x{5679}\x{567A}\x{567B}' . +'\x{567C}\x{567E}\x{567F}\x{5680}\x{5681}\x{5682}\x{5683}\x{5684}\x{5685}' . +'\x{5686}\x{5687}\x{568A}\x{568C}\x{568D}\x{568E}\x{568F}\x{5690}\x{5691}' . +'\x{5692}\x{5693}\x{5694}\x{5695}\x{5697}\x{5698}\x{5699}\x{569A}\x{569B}' . +'\x{569C}\x{569D}\x{569F}\x{56A0}\x{56A1}\x{56A3}\x{56A4}\x{56A5}\x{56A6}' . +'\x{56A7}\x{56A8}\x{56A9}\x{56AA}\x{56AB}\x{56AC}\x{56AD}\x{56AE}\x{56AF}' . +'\x{56B0}\x{56B1}\x{56B2}\x{56B3}\x{56B4}\x{56B5}\x{56B6}\x{56B7}\x{56B8}' . +'\x{56B9}\x{56BB}\x{56BC}\x{56BD}\x{56BE}\x{56BF}\x{56C0}\x{56C1}\x{56C2}' . +'\x{56C3}\x{56C4}\x{56C5}\x{56C6}\x{56C7}\x{56C8}\x{56C9}\x{56CA}\x{56CB}' . +'\x{56CC}\x{56CD}\x{56CE}\x{56D0}\x{56D1}\x{56D2}\x{56D3}\x{56D4}\x{56D5}' . +'\x{56D6}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DC}\x{56DD}\x{56DE}\x{56DF}' . +'\x{56E0}\x{56E1}\x{56E2}\x{56E3}\x{56E4}\x{56E5}\x{56E7}\x{56E8}\x{56E9}' . +'\x{56EA}\x{56EB}\x{56EC}\x{56ED}\x{56EE}\x{56EF}\x{56F0}\x{56F1}\x{56F2}' . +'\x{56F3}\x{56F4}\x{56F5}\x{56F7}\x{56F9}\x{56FA}\x{56FD}\x{56FE}\x{56FF}' . +'\x{5700}\x{5701}\x{5702}\x{5703}\x{5704}\x{5706}\x{5707}\x{5708}\x{5709}' . +'\x{570A}\x{570B}\x{570C}\x{570D}\x{570E}\x{570F}\x{5710}\x{5712}\x{5713}' . +'\x{5714}\x{5715}\x{5716}\x{5718}\x{5719}\x{571A}\x{571B}\x{571C}\x{571D}' . +'\x{571E}\x{571F}\x{5720}\x{5722}\x{5723}\x{5725}\x{5726}\x{5727}\x{5728}' . +'\x{5729}\x{572A}\x{572B}\x{572C}\x{572D}\x{572E}\x{572F}\x{5730}\x{5731}' . +'\x{5732}\x{5733}\x{5734}\x{5735}\x{5736}\x{5737}\x{5738}\x{5739}\x{573A}' . +'\x{573B}\x{573C}\x{573E}\x{573F}\x{5740}\x{5741}\x{5742}\x{5744}\x{5745}' . +'\x{5746}\x{5747}\x{5749}\x{574A}\x{574B}\x{574C}\x{574D}\x{574E}\x{574F}' . +'\x{5750}\x{5751}\x{5752}\x{5753}\x{5754}\x{5757}\x{5759}\x{575A}\x{575B}' . +'\x{575C}\x{575D}\x{575E}\x{575F}\x{5760}\x{5761}\x{5762}\x{5764}\x{5765}' . +'\x{5766}\x{5767}\x{5768}\x{5769}\x{576A}\x{576B}\x{576C}\x{576D}\x{576F}' . +'\x{5770}\x{5771}\x{5772}\x{5773}\x{5774}\x{5775}\x{5776}\x{5777}\x{5779}' . +'\x{577A}\x{577B}\x{577C}\x{577D}\x{577E}\x{577F}\x{5780}\x{5782}\x{5783}' . +'\x{5784}\x{5785}\x{5786}\x{5788}\x{5789}\x{578A}\x{578B}\x{578C}\x{578D}' . +'\x{578E}\x{578F}\x{5790}\x{5791}\x{5792}\x{5793}\x{5794}\x{5795}\x{5797}' . +'\x{5798}\x{5799}\x{579A}\x{579B}\x{579C}\x{579D}\x{579E}\x{579F}\x{57A0}' . +'\x{57A1}\x{57A2}\x{57A3}\x{57A4}\x{57A5}\x{57A6}\x{57A7}\x{57A9}\x{57AA}' . +'\x{57AB}\x{57AC}\x{57AD}\x{57AE}\x{57AF}\x{57B0}\x{57B1}\x{57B2}\x{57B3}' . +'\x{57B4}\x{57B5}\x{57B6}\x{57B7}\x{57B8}\x{57B9}\x{57BA}\x{57BB}\x{57BC}' . +'\x{57BD}\x{57BE}\x{57BF}\x{57C0}\x{57C1}\x{57C2}\x{57C3}\x{57C4}\x{57C5}' . +'\x{57C6}\x{57C7}\x{57C8}\x{57C9}\x{57CB}\x{57CC}\x{57CD}\x{57CE}\x{57CF}' . +'\x{57D0}\x{57D2}\x{57D3}\x{57D4}\x{57D5}\x{57D6}\x{57D8}\x{57D9}\x{57DA}' . +'\x{57DC}\x{57DD}\x{57DF}\x{57E0}\x{57E1}\x{57E2}\x{57E3}\x{57E4}\x{57E5}' . +'\x{57E6}\x{57E7}\x{57E8}\x{57E9}\x{57EA}\x{57EB}\x{57EC}\x{57ED}\x{57EE}' . +'\x{57EF}\x{57F0}\x{57F1}\x{57F2}\x{57F3}\x{57F4}\x{57F5}\x{57F6}\x{57F7}' . +'\x{57F8}\x{57F9}\x{57FA}\x{57FB}\x{57FC}\x{57FD}\x{57FE}\x{57FF}\x{5800}' . +'\x{5801}\x{5802}\x{5803}\x{5804}\x{5805}\x{5806}\x{5807}\x{5808}\x{5809}' . +'\x{580A}\x{580B}\x{580C}\x{580D}\x{580E}\x{580F}\x{5810}\x{5811}\x{5812}' . +'\x{5813}\x{5814}\x{5815}\x{5816}\x{5819}\x{581A}\x{581B}\x{581C}\x{581D}' . +'\x{581E}\x{581F}\x{5820}\x{5821}\x{5822}\x{5823}\x{5824}\x{5825}\x{5826}' . +'\x{5827}\x{5828}\x{5829}\x{582A}\x{582B}\x{582C}\x{582D}\x{582E}\x{582F}' . +'\x{5830}\x{5831}\x{5832}\x{5833}\x{5834}\x{5835}\x{5836}\x{5837}\x{5838}' . +'\x{5839}\x{583A}\x{583B}\x{583C}\x{583D}\x{583E}\x{583F}\x{5840}\x{5842}' . +'\x{5843}\x{5844}\x{5845}\x{5846}\x{5847}\x{5848}\x{5849}\x{584A}\x{584B}' . +'\x{584C}\x{584D}\x{584E}\x{584F}\x{5851}\x{5852}\x{5853}\x{5854}\x{5855}' . +'\x{5857}\x{5858}\x{5859}\x{585A}\x{585B}\x{585C}\x{585D}\x{585E}\x{585F}' . +'\x{5861}\x{5862}\x{5863}\x{5864}\x{5865}\x{5868}\x{5869}\x{586A}\x{586B}' . +'\x{586C}\x{586D}\x{586E}\x{586F}\x{5870}\x{5871}\x{5872}\x{5873}\x{5874}' . +'\x{5875}\x{5876}\x{5878}\x{5879}\x{587A}\x{587B}\x{587C}\x{587D}\x{587E}' . +'\x{587F}\x{5880}\x{5881}\x{5882}\x{5883}\x{5884}\x{5885}\x{5886}\x{5887}' . +'\x{5888}\x{5889}\x{588A}\x{588B}\x{588C}\x{588D}\x{588E}\x{588F}\x{5890}' . +'\x{5891}\x{5892}\x{5893}\x{5894}\x{5896}\x{5897}\x{5898}\x{5899}\x{589A}' . +'\x{589B}\x{589C}\x{589D}\x{589E}\x{589F}\x{58A0}\x{58A1}\x{58A2}\x{58A3}' . +'\x{58A4}\x{58A5}\x{58A6}\x{58A7}\x{58A8}\x{58A9}\x{58AB}\x{58AC}\x{58AD}' . +'\x{58AE}\x{58AF}\x{58B0}\x{58B1}\x{58B2}\x{58B3}\x{58B4}\x{58B7}\x{58B8}' . +'\x{58B9}\x{58BA}\x{58BB}\x{58BC}\x{58BD}\x{58BE}\x{58BF}\x{58C1}\x{58C2}' . +'\x{58C5}\x{58C6}\x{58C7}\x{58C8}\x{58C9}\x{58CA}\x{58CB}\x{58CE}\x{58CF}' . +'\x{58D1}\x{58D2}\x{58D3}\x{58D4}\x{58D5}\x{58D6}\x{58D7}\x{58D8}\x{58D9}' . +'\x{58DA}\x{58DB}\x{58DD}\x{58DE}\x{58DF}\x{58E0}\x{58E2}\x{58E3}\x{58E4}' . +'\x{58E5}\x{58E7}\x{58E8}\x{58E9}\x{58EA}\x{58EB}\x{58EC}\x{58ED}\x{58EE}' . +'\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F3}\x{58F4}\x{58F6}\x{58F7}\x{58F8}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{58FE}\x{58FF}\x{5900}\x{5902}' . +'\x{5903}\x{5904}\x{5906}\x{5907}\x{5909}\x{590A}\x{590B}\x{590C}\x{590D}' . +'\x{590E}\x{590F}\x{5910}\x{5912}\x{5914}\x{5915}\x{5916}\x{5917}\x{5918}' . +'\x{5919}\x{591A}\x{591B}\x{591C}\x{591D}\x{591E}\x{591F}\x{5920}\x{5921}' . +'\x{5922}\x{5924}\x{5925}\x{5926}\x{5927}\x{5928}\x{5929}\x{592A}\x{592B}' . +'\x{592C}\x{592D}\x{592E}\x{592F}\x{5930}\x{5931}\x{5932}\x{5934}\x{5935}' . +'\x{5937}\x{5938}\x{5939}\x{593A}\x{593B}\x{593C}\x{593D}\x{593E}\x{593F}' . +'\x{5940}\x{5941}\x{5942}\x{5943}\x{5944}\x{5945}\x{5946}\x{5947}\x{5948}' . +'\x{5949}\x{594A}\x{594B}\x{594C}\x{594D}\x{594E}\x{594F}\x{5950}\x{5951}' . +'\x{5952}\x{5953}\x{5954}\x{5955}\x{5956}\x{5957}\x{5958}\x{595A}\x{595C}' . +'\x{595D}\x{595E}\x{595F}\x{5960}\x{5961}\x{5962}\x{5963}\x{5964}\x{5965}' . +'\x{5966}\x{5967}\x{5968}\x{5969}\x{596A}\x{596B}\x{596C}\x{596D}\x{596E}' . +'\x{596F}\x{5970}\x{5971}\x{5972}\x{5973}\x{5974}\x{5975}\x{5976}\x{5977}' . +'\x{5978}\x{5979}\x{597A}\x{597B}\x{597C}\x{597D}\x{597E}\x{597F}\x{5980}' . +'\x{5981}\x{5982}\x{5983}\x{5984}\x{5985}\x{5986}\x{5987}\x{5988}\x{5989}' . +'\x{598A}\x{598B}\x{598C}\x{598D}\x{598E}\x{598F}\x{5990}\x{5991}\x{5992}' . +'\x{5993}\x{5994}\x{5995}\x{5996}\x{5997}\x{5998}\x{5999}\x{599A}\x{599C}' . +'\x{599D}\x{599E}\x{599F}\x{59A0}\x{59A1}\x{59A2}\x{59A3}\x{59A4}\x{59A5}' . +'\x{59A6}\x{59A7}\x{59A8}\x{59A9}\x{59AA}\x{59AB}\x{59AC}\x{59AD}\x{59AE}' . +'\x{59AF}\x{59B0}\x{59B1}\x{59B2}\x{59B3}\x{59B4}\x{59B5}\x{59B6}\x{59B8}' . +'\x{59B9}\x{59BA}\x{59BB}\x{59BC}\x{59BD}\x{59BE}\x{59BF}\x{59C0}\x{59C1}' . +'\x{59C2}\x{59C3}\x{59C4}\x{59C5}\x{59C6}\x{59C7}\x{59C8}\x{59C9}\x{59CA}' . +'\x{59CB}\x{59CC}\x{59CD}\x{59CE}\x{59CF}\x{59D0}\x{59D1}\x{59D2}\x{59D3}' . +'\x{59D4}\x{59D5}\x{59D6}\x{59D7}\x{59D8}\x{59D9}\x{59DA}\x{59DB}\x{59DC}' . +'\x{59DD}\x{59DE}\x{59DF}\x{59E0}\x{59E1}\x{59E2}\x{59E3}\x{59E4}\x{59E5}' . +'\x{59E6}\x{59E8}\x{59E9}\x{59EA}\x{59EB}\x{59EC}\x{59ED}\x{59EE}\x{59EF}' . +'\x{59F0}\x{59F1}\x{59F2}\x{59F3}\x{59F4}\x{59F5}\x{59F6}\x{59F7}\x{59F8}' . +'\x{59F9}\x{59FA}\x{59FB}\x{59FC}\x{59FD}\x{59FE}\x{59FF}\x{5A00}\x{5A01}' . +'\x{5A02}\x{5A03}\x{5A04}\x{5A05}\x{5A06}\x{5A07}\x{5A08}\x{5A09}\x{5A0A}' . +'\x{5A0B}\x{5A0C}\x{5A0D}\x{5A0E}\x{5A0F}\x{5A10}\x{5A11}\x{5A12}\x{5A13}' . +'\x{5A14}\x{5A15}\x{5A16}\x{5A17}\x{5A18}\x{5A19}\x{5A1A}\x{5A1B}\x{5A1C}' . +'\x{5A1D}\x{5A1E}\x{5A1F}\x{5A20}\x{5A21}\x{5A22}\x{5A23}\x{5A25}\x{5A27}' . +'\x{5A28}\x{5A29}\x{5A2A}\x{5A2B}\x{5A2D}\x{5A2E}\x{5A2F}\x{5A31}\x{5A32}' . +'\x{5A33}\x{5A34}\x{5A35}\x{5A36}\x{5A37}\x{5A38}\x{5A39}\x{5A3A}\x{5A3B}' . +'\x{5A3C}\x{5A3D}\x{5A3E}\x{5A3F}\x{5A40}\x{5A41}\x{5A42}\x{5A43}\x{5A44}' . +'\x{5A45}\x{5A46}\x{5A47}\x{5A48}\x{5A49}\x{5A4A}\x{5A4B}\x{5A4C}\x{5A4D}' . +'\x{5A4E}\x{5A4F}\x{5A50}\x{5A51}\x{5A52}\x{5A53}\x{5A55}\x{5A56}\x{5A57}' . +'\x{5A58}\x{5A5A}\x{5A5B}\x{5A5C}\x{5A5D}\x{5A5E}\x{5A5F}\x{5A60}\x{5A61}' . +'\x{5A62}\x{5A63}\x{5A64}\x{5A65}\x{5A66}\x{5A67}\x{5A68}\x{5A69}\x{5A6A}' . +'\x{5A6B}\x{5A6C}\x{5A6D}\x{5A6E}\x{5A70}\x{5A72}\x{5A73}\x{5A74}\x{5A75}' . +'\x{5A76}\x{5A77}\x{5A78}\x{5A79}\x{5A7A}\x{5A7B}\x{5A7C}\x{5A7D}\x{5A7E}' . +'\x{5A7F}\x{5A80}\x{5A81}\x{5A82}\x{5A83}\x{5A84}\x{5A85}\x{5A86}\x{5A88}' . +'\x{5A89}\x{5A8A}\x{5A8B}\x{5A8C}\x{5A8E}\x{5A8F}\x{5A90}\x{5A91}\x{5A92}' . +'\x{5A93}\x{5A94}\x{5A95}\x{5A96}\x{5A97}\x{5A98}\x{5A99}\x{5A9A}\x{5A9B}' . +'\x{5A9C}\x{5A9D}\x{5A9E}\x{5A9F}\x{5AA0}\x{5AA1}\x{5AA2}\x{5AA3}\x{5AA4}' . +'\x{5AA5}\x{5AA6}\x{5AA7}\x{5AA8}\x{5AA9}\x{5AAA}\x{5AAC}\x{5AAD}\x{5AAE}' . +'\x{5AAF}\x{5AB0}\x{5AB1}\x{5AB2}\x{5AB3}\x{5AB4}\x{5AB5}\x{5AB6}\x{5AB7}' . +'\x{5AB8}\x{5AB9}\x{5ABA}\x{5ABB}\x{5ABC}\x{5ABD}\x{5ABE}\x{5ABF}\x{5AC0}' . +'\x{5AC1}\x{5AC2}\x{5AC3}\x{5AC4}\x{5AC5}\x{5AC6}\x{5AC7}\x{5AC8}\x{5AC9}' . +'\x{5ACA}\x{5ACB}\x{5ACC}\x{5ACD}\x{5ACE}\x{5ACF}\x{5AD1}\x{5AD2}\x{5AD4}' . +'\x{5AD5}\x{5AD6}\x{5AD7}\x{5AD8}\x{5AD9}\x{5ADA}\x{5ADB}\x{5ADC}\x{5ADD}' . +'\x{5ADE}\x{5ADF}\x{5AE0}\x{5AE1}\x{5AE2}\x{5AE3}\x{5AE4}\x{5AE5}\x{5AE6}' . +'\x{5AE7}\x{5AE8}\x{5AE9}\x{5AEA}\x{5AEB}\x{5AEC}\x{5AED}\x{5AEE}\x{5AF1}' . +'\x{5AF2}\x{5AF3}\x{5AF4}\x{5AF5}\x{5AF6}\x{5AF7}\x{5AF8}\x{5AF9}\x{5AFA}' . +'\x{5AFB}\x{5AFC}\x{5AFD}\x{5AFE}\x{5AFF}\x{5B00}\x{5B01}\x{5B02}\x{5B03}' . +'\x{5B04}\x{5B05}\x{5B06}\x{5B07}\x{5B08}\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}' . +'\x{5B0F}\x{5B10}\x{5B11}\x{5B12}\x{5B13}\x{5B14}\x{5B15}\x{5B16}\x{5B17}' . +'\x{5B18}\x{5B19}\x{5B1A}\x{5B1B}\x{5B1C}\x{5B1D}\x{5B1E}\x{5B1F}\x{5B20}' . +'\x{5B21}\x{5B22}\x{5B23}\x{5B24}\x{5B25}\x{5B26}\x{5B27}\x{5B28}\x{5B29}' . +'\x{5B2A}\x{5B2B}\x{5B2C}\x{5B2D}\x{5B2E}\x{5B2F}\x{5B30}\x{5B31}\x{5B32}' . +'\x{5B33}\x{5B34}\x{5B35}\x{5B36}\x{5B37}\x{5B38}\x{5B3A}\x{5B3B}\x{5B3C}' . +'\x{5B3D}\x{5B3E}\x{5B3F}\x{5B40}\x{5B41}\x{5B42}\x{5B43}\x{5B44}\x{5B45}' . +'\x{5B47}\x{5B48}\x{5B49}\x{5B4A}\x{5B4B}\x{5B4C}\x{5B4D}\x{5B4E}\x{5B50}' . +'\x{5B51}\x{5B53}\x{5B54}\x{5B55}\x{5B56}\x{5B57}\x{5B58}\x{5B59}\x{5B5A}' . +'\x{5B5B}\x{5B5C}\x{5B5D}\x{5B5E}\x{5B5F}\x{5B62}\x{5B63}\x{5B64}\x{5B65}' . +'\x{5B66}\x{5B67}\x{5B68}\x{5B69}\x{5B6A}\x{5B6B}\x{5B6C}\x{5B6D}\x{5B6E}' . +'\x{5B70}\x{5B71}\x{5B72}\x{5B73}\x{5B74}\x{5B75}\x{5B76}\x{5B77}\x{5B78}' . +'\x{5B7A}\x{5B7B}\x{5B7C}\x{5B7D}\x{5B7F}\x{5B80}\x{5B81}\x{5B82}\x{5B83}' . +'\x{5B84}\x{5B85}\x{5B87}\x{5B88}\x{5B89}\x{5B8A}\x{5B8B}\x{5B8C}\x{5B8D}' . +'\x{5B8E}\x{5B8F}\x{5B91}\x{5B92}\x{5B93}\x{5B94}\x{5B95}\x{5B96}\x{5B97}' . +'\x{5B98}\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9E}\x{5B9F}\x{5BA0}' . +'\x{5BA1}\x{5BA2}\x{5BA3}\x{5BA4}\x{5BA5}\x{5BA6}\x{5BA7}\x{5BA8}\x{5BAA}' . +'\x{5BAB}\x{5BAC}\x{5BAD}\x{5BAE}\x{5BAF}\x{5BB0}\x{5BB1}\x{5BB3}\x{5BB4}' . +'\x{5BB5}\x{5BB6}\x{5BB8}\x{5BB9}\x{5BBA}\x{5BBB}\x{5BBD}\x{5BBE}\x{5BBF}' . +'\x{5BC0}\x{5BC1}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BCA}' . +'\x{5BCB}\x{5BCC}\x{5BCD}\x{5BCE}\x{5BCF}\x{5BD0}\x{5BD1}\x{5BD2}\x{5BD3}' . +'\x{5BD4}\x{5BD5}\x{5BD6}\x{5BD8}\x{5BD9}\x{5BDB}\x{5BDC}\x{5BDD}\x{5BDE}' . +'\x{5BDF}\x{5BE0}\x{5BE1}\x{5BE2}\x{5BE3}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}' . +'\x{5BE8}\x{5BE9}\x{5BEA}\x{5BEB}\x{5BEC}\x{5BED}\x{5BEE}\x{5BEF}\x{5BF0}' . +'\x{5BF1}\x{5BF2}\x{5BF3}\x{5BF4}\x{5BF5}\x{5BF6}\x{5BF7}\x{5BF8}\x{5BF9}' . +'\x{5BFA}\x{5BFB}\x{5BFC}\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}\x{5C04}\x{5C05}' . +'\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}\x{5C0B}\x{5C0C}\x{5C0D}\x{5C0E}' . +'\x{5C0F}\x{5C10}\x{5C11}\x{5C12}\x{5C13}\x{5C14}\x{5C15}\x{5C16}\x{5C17}' . +'\x{5C18}\x{5C19}\x{5C1A}\x{5C1C}\x{5C1D}\x{5C1E}\x{5C1F}\x{5C20}\x{5C21}' . +'\x{5C22}\x{5C24}\x{5C25}\x{5C27}\x{5C28}\x{5C2A}\x{5C2B}\x{5C2C}\x{5C2D}' . +'\x{5C2E}\x{5C2F}\x{5C30}\x{5C31}\x{5C32}\x{5C33}\x{5C34}\x{5C35}\x{5C37}' . +'\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}' . +'\x{5C41}\x{5C42}\x{5C43}\x{5C44}\x{5C45}\x{5C46}\x{5C47}\x{5C48}\x{5C49}' . +'\x{5C4A}\x{5C4B}\x{5C4C}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C52}' . +'\x{5C53}\x{5C54}\x{5C55}\x{5C56}\x{5C57}\x{5C58}\x{5C59}\x{5C5B}\x{5C5C}' . +'\x{5C5D}\x{5C5E}\x{5C5F}\x{5C60}\x{5C61}\x{5C62}\x{5C63}\x{5C64}\x{5C65}' . +'\x{5C66}\x{5C67}\x{5C68}\x{5C69}\x{5C6A}\x{5C6B}\x{5C6C}\x{5C6D}\x{5C6E}' . +'\x{5C6F}\x{5C70}\x{5C71}\x{5C72}\x{5C73}\x{5C74}\x{5C75}\x{5C76}\x{5C77}' . +'\x{5C78}\x{5C79}\x{5C7A}\x{5C7B}\x{5C7C}\x{5C7D}\x{5C7E}\x{5C7F}\x{5C80}' . +'\x{5C81}\x{5C82}\x{5C83}\x{5C84}\x{5C86}\x{5C87}\x{5C88}\x{5C89}\x{5C8A}' . +'\x{5C8B}\x{5C8C}\x{5C8D}\x{5C8E}\x{5C8F}\x{5C90}\x{5C91}\x{5C92}\x{5C93}' . +'\x{5C94}\x{5C95}\x{5C96}\x{5C97}\x{5C98}\x{5C99}\x{5C9A}\x{5C9B}\x{5C9C}' . +'\x{5C9D}\x{5C9E}\x{5C9F}\x{5CA0}\x{5CA1}\x{5CA2}\x{5CA3}\x{5CA4}\x{5CA5}' . +'\x{5CA6}\x{5CA7}\x{5CA8}\x{5CA9}\x{5CAA}\x{5CAB}\x{5CAC}\x{5CAD}\x{5CAE}' . +'\x{5CAF}\x{5CB0}\x{5CB1}\x{5CB2}\x{5CB3}\x{5CB5}\x{5CB6}\x{5CB7}\x{5CB8}' . +'\x{5CBA}\x{5CBB}\x{5CBC}\x{5CBD}\x{5CBE}\x{5CBF}\x{5CC1}\x{5CC2}\x{5CC3}' . +'\x{5CC4}\x{5CC5}\x{5CC6}\x{5CC7}\x{5CC8}\x{5CC9}\x{5CCA}\x{5CCB}\x{5CCC}' . +'\x{5CCD}\x{5CCE}\x{5CCF}\x{5CD0}\x{5CD1}\x{5CD2}\x{5CD3}\x{5CD4}\x{5CD6}' . +'\x{5CD7}\x{5CD8}\x{5CD9}\x{5CDA}\x{5CDB}\x{5CDC}\x{5CDE}\x{5CDF}\x{5CE0}' . +'\x{5CE1}\x{5CE2}\x{5CE3}\x{5CE4}\x{5CE5}\x{5CE6}\x{5CE7}\x{5CE8}\x{5CE9}' . +'\x{5CEA}\x{5CEB}\x{5CEC}\x{5CED}\x{5CEE}\x{5CEF}\x{5CF0}\x{5CF1}\x{5CF2}' . +'\x{5CF3}\x{5CF4}\x{5CF6}\x{5CF7}\x{5CF8}\x{5CF9}\x{5CFA}\x{5CFB}\x{5CFC}' . +'\x{5CFD}\x{5CFE}\x{5CFF}\x{5D00}\x{5D01}\x{5D02}\x{5D03}\x{5D04}\x{5D05}' . +'\x{5D06}\x{5D07}\x{5D08}\x{5D09}\x{5D0A}\x{5D0B}\x{5D0C}\x{5D0D}\x{5D0E}' . +'\x{5D0F}\x{5D10}\x{5D11}\x{5D12}\x{5D13}\x{5D14}\x{5D15}\x{5D16}\x{5D17}' . +'\x{5D18}\x{5D19}\x{5D1A}\x{5D1B}\x{5D1C}\x{5D1D}\x{5D1E}\x{5D1F}\x{5D20}' . +'\x{5D21}\x{5D22}\x{5D23}\x{5D24}\x{5D25}\x{5D26}\x{5D27}\x{5D28}\x{5D29}' . +'\x{5D2A}\x{5D2C}\x{5D2D}\x{5D2E}\x{5D30}\x{5D31}\x{5D32}\x{5D33}\x{5D34}' . +'\x{5D35}\x{5D36}\x{5D37}\x{5D38}\x{5D39}\x{5D3A}\x{5D3C}\x{5D3D}\x{5D3E}' . +'\x{5D3F}\x{5D40}\x{5D41}\x{5D42}\x{5D43}\x{5D44}\x{5D45}\x{5D46}\x{5D47}' . +'\x{5D48}\x{5D49}\x{5D4A}\x{5D4B}\x{5D4C}\x{5D4D}\x{5D4E}\x{5D4F}\x{5D50}' . +'\x{5D51}\x{5D52}\x{5D54}\x{5D55}\x{5D56}\x{5D58}\x{5D59}\x{5D5A}\x{5D5B}' . +'\x{5D5D}\x{5D5E}\x{5D5F}\x{5D61}\x{5D62}\x{5D63}\x{5D64}\x{5D65}\x{5D66}' . +'\x{5D67}\x{5D68}\x{5D69}\x{5D6A}\x{5D6B}\x{5D6C}\x{5D6D}\x{5D6E}\x{5D6F}' . +'\x{5D70}\x{5D71}\x{5D72}\x{5D73}\x{5D74}\x{5D75}\x{5D76}\x{5D77}\x{5D78}' . +'\x{5D79}\x{5D7A}\x{5D7B}\x{5D7C}\x{5D7D}\x{5D7E}\x{5D7F}\x{5D80}\x{5D81}' . +'\x{5D82}\x{5D84}\x{5D85}\x{5D86}\x{5D87}\x{5D88}\x{5D89}\x{5D8A}\x{5D8B}' . +'\x{5D8C}\x{5D8D}\x{5D8E}\x{5D8F}\x{5D90}\x{5D91}\x{5D92}\x{5D93}\x{5D94}' . +'\x{5D95}\x{5D97}\x{5D98}\x{5D99}\x{5D9A}\x{5D9B}\x{5D9C}\x{5D9D}\x{5D9E}' . +'\x{5D9F}\x{5DA0}\x{5DA1}\x{5DA2}\x{5DA5}\x{5DA6}\x{5DA7}\x{5DA8}\x{5DA9}' . +'\x{5DAA}\x{5DAC}\x{5DAD}\x{5DAE}\x{5DAF}\x{5DB0}\x{5DB1}\x{5DB2}\x{5DB4}' . +'\x{5DB5}\x{5DB6}\x{5DB7}\x{5DB8}\x{5DBA}\x{5DBB}\x{5DBC}\x{5DBD}\x{5DBE}' . +'\x{5DBF}\x{5DC0}\x{5DC1}\x{5DC2}\x{5DC3}\x{5DC5}\x{5DC6}\x{5DC7}\x{5DC8}' . +'\x{5DC9}\x{5DCA}\x{5DCB}\x{5DCC}\x{5DCD}\x{5DCE}\x{5DCF}\x{5DD0}\x{5DD1}' . +'\x{5DD2}\x{5DD3}\x{5DD4}\x{5DD5}\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}' . +'\x{5DDE}\x{5DDF}\x{5DE0}\x{5DE1}\x{5DE2}\x{5DE3}\x{5DE4}\x{5DE5}\x{5DE6}' . +'\x{5DE7}\x{5DE8}\x{5DE9}\x{5DEA}\x{5DEB}\x{5DEC}\x{5DED}\x{5DEE}\x{5DEF}' . +'\x{5DF0}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DF8}\x{5DF9}' . +'\x{5DFA}\x{5DFB}\x{5DFC}\x{5DFD}\x{5DFE}\x{5DFF}\x{5E00}\x{5E01}\x{5E02}' . +'\x{5E03}\x{5E04}\x{5E05}\x{5E06}\x{5E07}\x{5E08}\x{5E09}\x{5E0A}\x{5E0B}' . +'\x{5E0C}\x{5E0D}\x{5E0E}\x{5E0F}\x{5E10}\x{5E11}\x{5E13}\x{5E14}\x{5E15}' . +'\x{5E16}\x{5E17}\x{5E18}\x{5E19}\x{5E1A}\x{5E1B}\x{5E1C}\x{5E1D}\x{5E1E}' . +'\x{5E1F}\x{5E20}\x{5E21}\x{5E22}\x{5E23}\x{5E24}\x{5E25}\x{5E26}\x{5E27}' . +'\x{5E28}\x{5E29}\x{5E2A}\x{5E2B}\x{5E2C}\x{5E2D}\x{5E2E}\x{5E2F}\x{5E30}' . +'\x{5E31}\x{5E32}\x{5E33}\x{5E34}\x{5E35}\x{5E36}\x{5E37}\x{5E38}\x{5E39}' . +'\x{5E3A}\x{5E3B}\x{5E3C}\x{5E3D}\x{5E3E}\x{5E40}\x{5E41}\x{5E42}\x{5E43}' . +'\x{5E44}\x{5E45}\x{5E46}\x{5E47}\x{5E49}\x{5E4A}\x{5E4B}\x{5E4C}\x{5E4D}' . +'\x{5E4E}\x{5E4F}\x{5E50}\x{5E52}\x{5E53}\x{5E54}\x{5E55}\x{5E56}\x{5E57}' . +'\x{5E58}\x{5E59}\x{5E5A}\x{5E5B}\x{5E5C}\x{5E5D}\x{5E5E}\x{5E5F}\x{5E60}' . +'\x{5E61}\x{5E62}\x{5E63}\x{5E64}\x{5E65}\x{5E66}\x{5E67}\x{5E68}\x{5E69}' . +'\x{5E6A}\x{5E6B}\x{5E6C}\x{5E6D}\x{5E6E}\x{5E6F}\x{5E70}\x{5E71}\x{5E72}' . +'\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E77}\x{5E78}\x{5E79}\x{5E7A}\x{5E7B}' . +'\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E80}\x{5E81}\x{5E82}\x{5E83}\x{5E84}' . +'\x{5E85}\x{5E86}\x{5E87}\x{5E88}\x{5E89}\x{5E8A}\x{5E8B}\x{5E8C}\x{5E8D}' . +'\x{5E8E}\x{5E8F}\x{5E90}\x{5E91}\x{5E93}\x{5E94}\x{5E95}\x{5E96}\x{5E97}' . +'\x{5E98}\x{5E99}\x{5E9A}\x{5E9B}\x{5E9C}\x{5E9D}\x{5E9E}\x{5E9F}\x{5EA0}' . +'\x{5EA1}\x{5EA2}\x{5EA3}\x{5EA4}\x{5EA5}\x{5EA6}\x{5EA7}\x{5EA8}\x{5EA9}' . +'\x{5EAA}\x{5EAB}\x{5EAC}\x{5EAD}\x{5EAE}\x{5EAF}\x{5EB0}\x{5EB1}\x{5EB2}' . +'\x{5EB3}\x{5EB4}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EB9}\x{5EBB}\x{5EBC}' . +'\x{5EBD}\x{5EBE}\x{5EBF}\x{5EC1}\x{5EC2}\x{5EC3}\x{5EC4}\x{5EC5}\x{5EC6}' . +'\x{5EC7}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECB}\x{5ECC}\x{5ECD}\x{5ECE}\x{5ECF}' . +'\x{5ED0}\x{5ED1}\x{5ED2}\x{5ED3}\x{5ED4}\x{5ED5}\x{5ED6}\x{5ED7}\x{5ED8}' . +'\x{5ED9}\x{5EDA}\x{5EDB}\x{5EDC}\x{5EDD}\x{5EDE}\x{5EDF}\x{5EE0}\x{5EE1}' . +'\x{5EE2}\x{5EE3}\x{5EE4}\x{5EE5}\x{5EE6}\x{5EE7}\x{5EE8}\x{5EE9}\x{5EEA}' . +'\x{5EEC}\x{5EED}\x{5EEE}\x{5EEF}\x{5EF0}\x{5EF1}\x{5EF2}\x{5EF3}\x{5EF4}' . +'\x{5EF5}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}\x{5EFB}\x{5EFC}\x{5EFD}\x{5EFE}' . +'\x{5EFF}\x{5F00}\x{5F01}\x{5F02}\x{5F03}\x{5F04}\x{5F05}\x{5F06}\x{5F07}' . +'\x{5F08}\x{5F0A}\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F11}\x{5F12}\x{5F13}' . +'\x{5F14}\x{5F15}\x{5F16}\x{5F17}\x{5F18}\x{5F19}\x{5F1A}\x{5F1B}\x{5F1C}' . +'\x{5F1D}\x{5F1E}\x{5F1F}\x{5F20}\x{5F21}\x{5F22}\x{5F23}\x{5F24}\x{5F25}' . +'\x{5F26}\x{5F27}\x{5F28}\x{5F29}\x{5F2A}\x{5F2B}\x{5F2C}\x{5F2D}\x{5F2E}' . +'\x{5F2F}\x{5F30}\x{5F31}\x{5F32}\x{5F33}\x{5F34}\x{5F35}\x{5F36}\x{5F37}' . +'\x{5F38}\x{5F39}\x{5F3A}\x{5F3C}\x{5F3E}\x{5F3F}\x{5F40}\x{5F41}\x{5F42}' . +'\x{5F43}\x{5F44}\x{5F45}\x{5F46}\x{5F47}\x{5F48}\x{5F49}\x{5F4A}\x{5F4B}' . +'\x{5F4C}\x{5F4D}\x{5F4E}\x{5F4F}\x{5F50}\x{5F51}\x{5F52}\x{5F53}\x{5F54}' . +'\x{5F55}\x{5F56}\x{5F57}\x{5F58}\x{5F59}\x{5F5A}\x{5F5B}\x{5F5C}\x{5F5D}' . +'\x{5F5E}\x{5F5F}\x{5F60}\x{5F61}\x{5F62}\x{5F63}\x{5F64}\x{5F65}\x{5F66}' . +'\x{5F67}\x{5F68}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}\x{5F6D}\x{5F6E}\x{5F6F}' . +'\x{5F70}\x{5F71}\x{5F72}\x{5F73}\x{5F74}\x{5F75}\x{5F76}\x{5F77}\x{5F78}' . +'\x{5F79}\x{5F7A}\x{5F7B}\x{5F7C}\x{5F7D}\x{5F7E}\x{5F7F}\x{5F80}\x{5F81}' . +'\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F86}\x{5F87}\x{5F88}\x{5F89}\x{5F8A}' . +'\x{5F8B}\x{5F8C}\x{5F8D}\x{5F8E}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F94}' . +'\x{5F95}\x{5F96}\x{5F97}\x{5F98}\x{5F99}\x{5F9B}\x{5F9C}\x{5F9D}\x{5F9E}' . +'\x{5F9F}\x{5FA0}\x{5FA1}\x{5FA2}\x{5FA5}\x{5FA6}\x{5FA7}\x{5FA8}\x{5FA9}' . +'\x{5FAA}\x{5FAB}\x{5FAC}\x{5FAD}\x{5FAE}\x{5FAF}\x{5FB1}\x{5FB2}\x{5FB3}' . +'\x{5FB4}\x{5FB5}\x{5FB6}\x{5FB7}\x{5FB8}\x{5FB9}\x{5FBA}\x{5FBB}\x{5FBC}' . +'\x{5FBD}\x{5FBE}\x{5FBF}\x{5FC0}\x{5FC1}\x{5FC3}\x{5FC4}\x{5FC5}\x{5FC6}' . +'\x{5FC7}\x{5FC8}\x{5FC9}\x{5FCA}\x{5FCB}\x{5FCC}\x{5FCD}\x{5FCF}\x{5FD0}' . +'\x{5FD1}\x{5FD2}\x{5FD3}\x{5FD4}\x{5FD5}\x{5FD6}\x{5FD7}\x{5FD8}\x{5FD9}' . +'\x{5FDA}\x{5FDC}\x{5FDD}\x{5FDE}\x{5FE0}\x{5FE1}\x{5FE3}\x{5FE4}\x{5FE5}' . +'\x{5FE6}\x{5FE7}\x{5FE8}\x{5FE9}\x{5FEA}\x{5FEB}\x{5FED}\x{5FEE}\x{5FEF}' . +'\x{5FF0}\x{5FF1}\x{5FF2}\x{5FF3}\x{5FF4}\x{5FF5}\x{5FF6}\x{5FF7}\x{5FF8}' . +'\x{5FF9}\x{5FFA}\x{5FFB}\x{5FFD}\x{5FFE}\x{5FFF}\x{6000}\x{6001}\x{6002}' . +'\x{6003}\x{6004}\x{6005}\x{6006}\x{6007}\x{6008}\x{6009}\x{600A}\x{600B}' . +'\x{600C}\x{600D}\x{600E}\x{600F}\x{6010}\x{6011}\x{6012}\x{6013}\x{6014}' . +'\x{6015}\x{6016}\x{6017}\x{6018}\x{6019}\x{601A}\x{601B}\x{601C}\x{601D}' . +'\x{601E}\x{601F}\x{6020}\x{6021}\x{6022}\x{6024}\x{6025}\x{6026}\x{6027}' . +'\x{6028}\x{6029}\x{602A}\x{602B}\x{602C}\x{602D}\x{602E}\x{602F}\x{6030}' . +'\x{6031}\x{6032}\x{6033}\x{6034}\x{6035}\x{6036}\x{6037}\x{6038}\x{6039}' . +'\x{603A}\x{603B}\x{603C}\x{603D}\x{603E}\x{603F}\x{6040}\x{6041}\x{6042}' . +'\x{6043}\x{6044}\x{6045}\x{6046}\x{6047}\x{6048}\x{6049}\x{604A}\x{604B}' . +'\x{604C}\x{604D}\x{604E}\x{604F}\x{6050}\x{6051}\x{6052}\x{6053}\x{6054}' . +'\x{6055}\x{6057}\x{6058}\x{6059}\x{605A}\x{605B}\x{605C}\x{605D}\x{605E}' . +'\x{605F}\x{6062}\x{6063}\x{6064}\x{6065}\x{6066}\x{6067}\x{6068}\x{6069}' . +'\x{606A}\x{606B}\x{606C}\x{606D}\x{606E}\x{606F}\x{6070}\x{6072}\x{6073}' . +'\x{6075}\x{6076}\x{6077}\x{6078}\x{6079}\x{607A}\x{607B}\x{607C}\x{607D}' . +'\x{607E}\x{607F}\x{6080}\x{6081}\x{6082}\x{6083}\x{6084}\x{6085}\x{6086}' . +'\x{6087}\x{6088}\x{6089}\x{608A}\x{608B}\x{608C}\x{608D}\x{608E}\x{608F}' . +'\x{6090}\x{6092}\x{6094}\x{6095}\x{6096}\x{6097}\x{6098}\x{6099}\x{609A}' . +'\x{609B}\x{609C}\x{609D}\x{609E}\x{609F}\x{60A0}\x{60A1}\x{60A2}\x{60A3}' . +'\x{60A4}\x{60A6}\x{60A7}\x{60A8}\x{60AA}\x{60AB}\x{60AC}\x{60AD}\x{60AE}' . +'\x{60AF}\x{60B0}\x{60B1}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B7}' . +'\x{60B8}\x{60B9}\x{60BA}\x{60BB}\x{60BC}\x{60BD}\x{60BE}\x{60BF}\x{60C0}' . +'\x{60C1}\x{60C2}\x{60C3}\x{60C4}\x{60C5}\x{60C6}\x{60C7}\x{60C8}\x{60C9}' . +'\x{60CA}\x{60CB}\x{60CC}\x{60CD}\x{60CE}\x{60CF}\x{60D0}\x{60D1}\x{60D3}' . +'\x{60D4}\x{60D5}\x{60D7}\x{60D8}\x{60D9}\x{60DA}\x{60DB}\x{60DC}\x{60DD}' . +'\x{60DF}\x{60E0}\x{60E1}\x{60E2}\x{60E4}\x{60E6}\x{60E7}\x{60E8}\x{60E9}' . +'\x{60EA}\x{60EB}\x{60EC}\x{60ED}\x{60EE}\x{60EF}\x{60F0}\x{60F1}\x{60F2}' . +'\x{60F3}\x{60F4}\x{60F5}\x{60F6}\x{60F7}\x{60F8}\x{60F9}\x{60FA}\x{60FB}' . +'\x{60FC}\x{60FE}\x{60FF}\x{6100}\x{6101}\x{6103}\x{6104}\x{6105}\x{6106}' . +'\x{6108}\x{6109}\x{610A}\x{610B}\x{610C}\x{610D}\x{610E}\x{610F}\x{6110}' . +'\x{6112}\x{6113}\x{6114}\x{6115}\x{6116}\x{6117}\x{6118}\x{6119}\x{611A}' . +'\x{611B}\x{611C}\x{611D}\x{611F}\x{6120}\x{6122}\x{6123}\x{6124}\x{6125}' . +'\x{6126}\x{6127}\x{6128}\x{6129}\x{612A}\x{612B}\x{612C}\x{612D}\x{612E}' . +'\x{612F}\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}\x{613B}\x{613C}' . +'\x{613D}\x{613E}\x{613F}\x{6140}\x{6141}\x{6142}\x{6143}\x{6144}\x{6145}' . +'\x{6146}\x{6147}\x{6148}\x{6149}\x{614A}\x{614B}\x{614C}\x{614D}\x{614E}' . +'\x{614F}\x{6150}\x{6151}\x{6152}\x{6153}\x{6154}\x{6155}\x{6156}\x{6157}' . +'\x{6158}\x{6159}\x{615A}\x{615B}\x{615C}\x{615D}\x{615E}\x{615F}\x{6161}' . +'\x{6162}\x{6163}\x{6164}\x{6165}\x{6166}\x{6167}\x{6168}\x{6169}\x{616A}' . +'\x{616B}\x{616C}\x{616D}\x{616E}\x{6170}\x{6171}\x{6172}\x{6173}\x{6174}' . +'\x{6175}\x{6176}\x{6177}\x{6178}\x{6179}\x{617A}\x{617C}\x{617E}\x{6180}' . +'\x{6181}\x{6182}\x{6183}\x{6184}\x{6185}\x{6187}\x{6188}\x{6189}\x{618A}' . +'\x{618B}\x{618C}\x{618D}\x{618E}\x{618F}\x{6190}\x{6191}\x{6192}\x{6193}' . +'\x{6194}\x{6195}\x{6196}\x{6198}\x{6199}\x{619A}\x{619B}\x{619D}\x{619E}' . +'\x{619F}\x{61A0}\x{61A1}\x{61A2}\x{61A3}\x{61A4}\x{61A5}\x{61A6}\x{61A7}' . +'\x{61A8}\x{61A9}\x{61AA}\x{61AB}\x{61AC}\x{61AD}\x{61AE}\x{61AF}\x{61B0}' . +'\x{61B1}\x{61B2}\x{61B3}\x{61B4}\x{61B5}\x{61B6}\x{61B7}\x{61B8}\x{61BA}' . +'\x{61BC}\x{61BD}\x{61BE}\x{61BF}\x{61C0}\x{61C1}\x{61C2}\x{61C3}\x{61C4}' . +'\x{61C5}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61CE}\x{61CF}\x{61D0}\x{61D1}\x{61D2}\x{61D4}\x{61D6}\x{61D7}\x{61D8}' . +'\x{61D9}\x{61DA}\x{61DB}\x{61DC}\x{61DD}\x{61DE}\x{61DF}\x{61E0}\x{61E1}' . +'\x{61E2}\x{61E3}\x{61E4}\x{61E5}\x{61E6}\x{61E7}\x{61E8}\x{61E9}\x{61EA}' . +'\x{61EB}\x{61ED}\x{61EE}\x{61F0}\x{61F1}\x{61F2}\x{61F3}\x{61F5}\x{61F6}' . +'\x{61F7}\x{61F8}\x{61F9}\x{61FA}\x{61FB}\x{61FC}\x{61FD}\x{61FE}\x{61FF}' . +'\x{6200}\x{6201}\x{6202}\x{6203}\x{6204}\x{6206}\x{6207}\x{6208}\x{6209}' . +'\x{620A}\x{620B}\x{620C}\x{620D}\x{620E}\x{620F}\x{6210}\x{6211}\x{6212}' . +'\x{6213}\x{6214}\x{6215}\x{6216}\x{6217}\x{6218}\x{6219}\x{621A}\x{621B}' . +'\x{621C}\x{621D}\x{621E}\x{621F}\x{6220}\x{6221}\x{6222}\x{6223}\x{6224}' . +'\x{6225}\x{6226}\x{6227}\x{6228}\x{6229}\x{622A}\x{622B}\x{622C}\x{622D}' . +'\x{622E}\x{622F}\x{6230}\x{6231}\x{6232}\x{6233}\x{6234}\x{6236}\x{6237}' . +'\x{6238}\x{623A}\x{623B}\x{623C}\x{623D}\x{623E}\x{623F}\x{6240}\x{6241}' . +'\x{6242}\x{6243}\x{6244}\x{6245}\x{6246}\x{6247}\x{6248}\x{6249}\x{624A}' . +'\x{624B}\x{624C}\x{624D}\x{624E}\x{624F}\x{6250}\x{6251}\x{6252}\x{6253}' . +'\x{6254}\x{6255}\x{6256}\x{6258}\x{6259}\x{625A}\x{625B}\x{625C}\x{625D}' . +'\x{625E}\x{625F}\x{6260}\x{6261}\x{6262}\x{6263}\x{6264}\x{6265}\x{6266}' . +'\x{6267}\x{6268}\x{6269}\x{626A}\x{626B}\x{626C}\x{626D}\x{626E}\x{626F}' . +'\x{6270}\x{6271}\x{6272}\x{6273}\x{6274}\x{6275}\x{6276}\x{6277}\x{6278}' . +'\x{6279}\x{627A}\x{627B}\x{627C}\x{627D}\x{627E}\x{627F}\x{6280}\x{6281}' . +'\x{6283}\x{6284}\x{6285}\x{6286}\x{6287}\x{6288}\x{6289}\x{628A}\x{628B}' . +'\x{628C}\x{628E}\x{628F}\x{6290}\x{6291}\x{6292}\x{6293}\x{6294}\x{6295}' . +'\x{6296}\x{6297}\x{6298}\x{6299}\x{629A}\x{629B}\x{629C}\x{629E}\x{629F}' . +'\x{62A0}\x{62A1}\x{62A2}\x{62A3}\x{62A4}\x{62A5}\x{62A7}\x{62A8}\x{62A9}' . +'\x{62AA}\x{62AB}\x{62AC}\x{62AD}\x{62AE}\x{62AF}\x{62B0}\x{62B1}\x{62B2}' . +'\x{62B3}\x{62B4}\x{62B5}\x{62B6}\x{62B7}\x{62B8}\x{62B9}\x{62BA}\x{62BB}' . +'\x{62BC}\x{62BD}\x{62BE}\x{62BF}\x{62C0}\x{62C1}\x{62C2}\x{62C3}\x{62C4}' . +'\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CB}\x{62CC}\x{62CD}' . +'\x{62CE}\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D5}\x{62D6}' . +'\x{62D7}\x{62D8}\x{62D9}\x{62DA}\x{62DB}\x{62DC}\x{62DD}\x{62DF}\x{62E0}' . +'\x{62E1}\x{62E2}\x{62E3}\x{62E4}\x{62E5}\x{62E6}\x{62E7}\x{62E8}\x{62E9}' . +'\x{62EB}\x{62EC}\x{62ED}\x{62EE}\x{62EF}\x{62F0}\x{62F1}\x{62F2}\x{62F3}' . +'\x{62F4}\x{62F5}\x{62F6}\x{62F7}\x{62F8}\x{62F9}\x{62FA}\x{62FB}\x{62FC}' . +'\x{62FD}\x{62FE}\x{62FF}\x{6300}\x{6301}\x{6302}\x{6303}\x{6304}\x{6305}' . +'\x{6306}\x{6307}\x{6308}\x{6309}\x{630B}\x{630C}\x{630D}\x{630E}\x{630F}' . +'\x{6310}\x{6311}\x{6312}\x{6313}\x{6314}\x{6315}\x{6316}\x{6318}\x{6319}' . +'\x{631A}\x{631B}\x{631C}\x{631D}\x{631E}\x{631F}\x{6320}\x{6321}\x{6322}' . +'\x{6323}\x{6324}\x{6325}\x{6326}\x{6327}\x{6328}\x{6329}\x{632A}\x{632B}' . +'\x{632C}\x{632D}\x{632E}\x{632F}\x{6330}\x{6332}\x{6333}\x{6334}\x{6336}' . +'\x{6338}\x{6339}\x{633A}\x{633B}\x{633C}\x{633D}\x{633E}\x{6340}\x{6341}' . +'\x{6342}\x{6343}\x{6344}\x{6345}\x{6346}\x{6347}\x{6348}\x{6349}\x{634A}' . +'\x{634B}\x{634C}\x{634D}\x{634E}\x{634F}\x{6350}\x{6351}\x{6352}\x{6353}' . +'\x{6354}\x{6355}\x{6356}\x{6357}\x{6358}\x{6359}\x{635A}\x{635C}\x{635D}' . +'\x{635E}\x{635F}\x{6360}\x{6361}\x{6362}\x{6363}\x{6364}\x{6365}\x{6366}' . +'\x{6367}\x{6368}\x{6369}\x{636A}\x{636B}\x{636C}\x{636D}\x{636E}\x{636F}' . +'\x{6370}\x{6371}\x{6372}\x{6373}\x{6374}\x{6375}\x{6376}\x{6377}\x{6378}' . +'\x{6379}\x{637A}\x{637B}\x{637C}\x{637D}\x{637E}\x{6380}\x{6381}\x{6382}' . +'\x{6383}\x{6384}\x{6385}\x{6386}\x{6387}\x{6388}\x{6389}\x{638A}\x{638C}' . +'\x{638D}\x{638E}\x{638F}\x{6390}\x{6391}\x{6392}\x{6394}\x{6395}\x{6396}' . +'\x{6397}\x{6398}\x{6399}\x{639A}\x{639B}\x{639C}\x{639D}\x{639E}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A4}\x{63A5}\x{63A6}\x{63A7}\x{63A8}' . +'\x{63A9}\x{63AA}\x{63AB}\x{63AC}\x{63AD}\x{63AE}\x{63AF}\x{63B0}\x{63B1}' . +'\x{63B2}\x{63B3}\x{63B4}\x{63B5}\x{63B6}\x{63B7}\x{63B8}\x{63B9}\x{63BA}' . +'\x{63BC}\x{63BD}\x{63BE}\x{63BF}\x{63C0}\x{63C1}\x{63C2}\x{63C3}\x{63C4}' . +'\x{63C5}\x{63C6}\x{63C7}\x{63C8}\x{63C9}\x{63CA}\x{63CB}\x{63CC}\x{63CD}' . +'\x{63CE}\x{63CF}\x{63D0}\x{63D2}\x{63D3}\x{63D4}\x{63D5}\x{63D6}\x{63D7}' . +'\x{63D8}\x{63D9}\x{63DA}\x{63DB}\x{63DC}\x{63DD}\x{63DE}\x{63DF}\x{63E0}' . +'\x{63E1}\x{63E2}\x{63E3}\x{63E4}\x{63E5}\x{63E6}\x{63E7}\x{63E8}\x{63E9}' . +'\x{63EA}\x{63EB}\x{63EC}\x{63ED}\x{63EE}\x{63EF}\x{63F0}\x{63F1}\x{63F2}' . +'\x{63F3}\x{63F4}\x{63F5}\x{63F6}\x{63F7}\x{63F8}\x{63F9}\x{63FA}\x{63FB}' . +'\x{63FC}\x{63FD}\x{63FE}\x{63FF}\x{6400}\x{6401}\x{6402}\x{6403}\x{6404}' . +'\x{6405}\x{6406}\x{6408}\x{6409}\x{640A}\x{640B}\x{640C}\x{640D}\x{640E}' . +'\x{640F}\x{6410}\x{6411}\x{6412}\x{6413}\x{6414}\x{6415}\x{6416}\x{6417}' . +'\x{6418}\x{6419}\x{641A}\x{641B}\x{641C}\x{641D}\x{641E}\x{641F}\x{6420}' . +'\x{6421}\x{6422}\x{6423}\x{6424}\x{6425}\x{6426}\x{6427}\x{6428}\x{6429}' . +'\x{642A}\x{642B}\x{642C}\x{642D}\x{642E}\x{642F}\x{6430}\x{6431}\x{6432}' . +'\x{6433}\x{6434}\x{6435}\x{6436}\x{6437}\x{6438}\x{6439}\x{643A}\x{643D}' . +'\x{643E}\x{643F}\x{6440}\x{6441}\x{6443}\x{6444}\x{6445}\x{6446}\x{6447}' . +'\x{6448}\x{644A}\x{644B}\x{644C}\x{644D}\x{644E}\x{644F}\x{6450}\x{6451}' . +'\x{6452}\x{6453}\x{6454}\x{6455}\x{6456}\x{6457}\x{6458}\x{6459}\x{645B}' . +'\x{645C}\x{645D}\x{645E}\x{645F}\x{6460}\x{6461}\x{6462}\x{6463}\x{6464}' . +'\x{6465}\x{6466}\x{6467}\x{6468}\x{6469}\x{646A}\x{646B}\x{646C}\x{646D}' . +'\x{646E}\x{646F}\x{6470}\x{6471}\x{6472}\x{6473}\x{6474}\x{6475}\x{6476}' . +'\x{6477}\x{6478}\x{6479}\x{647A}\x{647B}\x{647C}\x{647D}\x{647F}\x{6480}' . +'\x{6481}\x{6482}\x{6483}\x{6484}\x{6485}\x{6487}\x{6488}\x{6489}\x{648A}' . +'\x{648B}\x{648C}\x{648D}\x{648E}\x{648F}\x{6490}\x{6491}\x{6492}\x{6493}' . +'\x{6494}\x{6495}\x{6496}\x{6497}\x{6498}\x{6499}\x{649A}\x{649B}\x{649C}' . +'\x{649D}\x{649E}\x{649F}\x{64A0}\x{64A2}\x{64A3}\x{64A4}\x{64A5}\x{64A6}' . +'\x{64A7}\x{64A8}\x{64A9}\x{64AA}\x{64AB}\x{64AC}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B1}\x{64B2}\x{64B3}\x{64B4}\x{64B5}\x{64B7}\x{64B8}\x{64B9}\x{64BA}' . +'\x{64BB}\x{64BC}\x{64BD}\x{64BE}\x{64BF}\x{64C0}\x{64C1}\x{64C2}\x{64C3}' . +'\x{64C4}\x{64C5}\x{64C6}\x{64C7}\x{64C9}\x{64CA}\x{64CB}\x{64CC}\x{64CD}' . +'\x{64CE}\x{64CF}\x{64D0}\x{64D1}\x{64D2}\x{64D3}\x{64D4}\x{64D6}\x{64D7}' . +'\x{64D8}\x{64D9}\x{64DA}\x{64DB}\x{64DC}\x{64DD}\x{64DE}\x{64DF}\x{64E0}' . +'\x{64E2}\x{64E3}\x{64E4}\x{64E6}\x{64E7}\x{64E8}\x{64E9}\x{64EA}\x{64EB}' . +'\x{64EC}\x{64ED}\x{64EF}\x{64F0}\x{64F1}\x{64F2}\x{64F3}\x{64F4}\x{64F6}' . +'\x{64F7}\x{64F8}\x{64FA}\x{64FB}\x{64FC}\x{64FD}\x{64FE}\x{64FF}\x{6500}' . +'\x{6501}\x{6503}\x{6504}\x{6505}\x{6506}\x{6507}\x{6508}\x{6509}\x{650B}' . +'\x{650C}\x{650D}\x{650E}\x{650F}\x{6510}\x{6511}\x{6512}\x{6513}\x{6514}' . +'\x{6515}\x{6516}\x{6517}\x{6518}\x{6519}\x{651A}\x{651B}\x{651C}\x{651D}' . +'\x{651E}\x{6520}\x{6521}\x{6522}\x{6523}\x{6524}\x{6525}\x{6526}\x{6527}' . +'\x{6529}\x{652A}\x{652B}\x{652C}\x{652D}\x{652E}\x{652F}\x{6530}\x{6531}' . +'\x{6532}\x{6533}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}\x{653A}' . +'\x{653B}\x{653C}\x{653D}\x{653E}\x{653F}\x{6541}\x{6543}\x{6544}\x{6545}' . +'\x{6546}\x{6547}\x{6548}\x{6549}\x{654A}\x{654B}\x{654C}\x{654D}\x{654E}' . +'\x{654F}\x{6550}\x{6551}\x{6552}\x{6553}\x{6554}\x{6555}\x{6556}\x{6557}' . +'\x{6558}\x{6559}\x{655B}\x{655C}\x{655D}\x{655E}\x{6560}\x{6561}\x{6562}' . +'\x{6563}\x{6564}\x{6565}\x{6566}\x{6567}\x{6568}\x{6569}\x{656A}\x{656B}' . +'\x{656C}\x{656E}\x{656F}\x{6570}\x{6571}\x{6572}\x{6573}\x{6574}\x{6575}' . +'\x{6576}\x{6577}\x{6578}\x{6579}\x{657A}\x{657B}\x{657C}\x{657E}\x{657F}' . +'\x{6580}\x{6581}\x{6582}\x{6583}\x{6584}\x{6585}\x{6586}\x{6587}\x{6588}' . +'\x{6589}\x{658B}\x{658C}\x{658D}\x{658E}\x{658F}\x{6590}\x{6591}\x{6592}' . +'\x{6593}\x{6594}\x{6595}\x{6596}\x{6597}\x{6598}\x{6599}\x{659B}\x{659C}' . +'\x{659D}\x{659E}\x{659F}\x{65A0}\x{65A1}\x{65A2}\x{65A3}\x{65A4}\x{65A5}' . +'\x{65A6}\x{65A7}\x{65A8}\x{65A9}\x{65AA}\x{65AB}\x{65AC}\x{65AD}\x{65AE}' . +'\x{65AF}\x{65B0}\x{65B1}\x{65B2}\x{65B3}\x{65B4}\x{65B6}\x{65B7}\x{65B8}' . +'\x{65B9}\x{65BA}\x{65BB}\x{65BC}\x{65BD}\x{65BF}\x{65C0}\x{65C1}\x{65C2}' . +'\x{65C3}\x{65C4}\x{65C5}\x{65C6}\x{65C7}\x{65CA}\x{65CB}\x{65CC}\x{65CD}' . +'\x{65CE}\x{65CF}\x{65D0}\x{65D2}\x{65D3}\x{65D4}\x{65D5}\x{65D6}\x{65D7}' . +'\x{65DA}\x{65DB}\x{65DD}\x{65DE}\x{65DF}\x{65E0}\x{65E1}\x{65E2}\x{65E3}' . +'\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}\x{65EB}\x{65EC}\x{65ED}\x{65EE}' . +'\x{65EF}\x{65F0}\x{65F1}\x{65F2}\x{65F3}\x{65F4}\x{65F5}\x{65F6}\x{65F7}' . +'\x{65F8}\x{65FA}\x{65FB}\x{65FC}\x{65FD}\x{6600}\x{6601}\x{6602}\x{6603}' . +'\x{6604}\x{6605}\x{6606}\x{6607}\x{6608}\x{6609}\x{660A}\x{660B}\x{660C}' . +'\x{660D}\x{660E}\x{660F}\x{6610}\x{6611}\x{6612}\x{6613}\x{6614}\x{6615}' . +'\x{6616}\x{6618}\x{6619}\x{661A}\x{661B}\x{661C}\x{661D}\x{661F}\x{6620}' . +'\x{6621}\x{6622}\x{6623}\x{6624}\x{6625}\x{6626}\x{6627}\x{6628}\x{6629}' . +'\x{662A}\x{662B}\x{662D}\x{662E}\x{662F}\x{6630}\x{6631}\x{6632}\x{6633}' . +'\x{6634}\x{6635}\x{6636}\x{6639}\x{663A}\x{663C}\x{663D}\x{663E}\x{6640}' . +'\x{6641}\x{6642}\x{6643}\x{6644}\x{6645}\x{6646}\x{6647}\x{6649}\x{664A}' . +'\x{664B}\x{664C}\x{664E}\x{664F}\x{6650}\x{6651}\x{6652}\x{6653}\x{6654}' . +'\x{6655}\x{6656}\x{6657}\x{6658}\x{6659}\x{665A}\x{665B}\x{665C}\x{665D}' . +'\x{665E}\x{665F}\x{6661}\x{6662}\x{6664}\x{6665}\x{6666}\x{6668}\x{6669}' . +'\x{666A}\x{666B}\x{666C}\x{666D}\x{666E}\x{666F}\x{6670}\x{6671}\x{6672}' . +'\x{6673}\x{6674}\x{6675}\x{6676}\x{6677}\x{6678}\x{6679}\x{667A}\x{667B}' . +'\x{667C}\x{667D}\x{667E}\x{667F}\x{6680}\x{6681}\x{6682}\x{6683}\x{6684}' . +'\x{6685}\x{6686}\x{6687}\x{6688}\x{6689}\x{668A}\x{668B}\x{668C}\x{668D}' . +'\x{668E}\x{668F}\x{6690}\x{6691}\x{6693}\x{6694}\x{6695}\x{6696}\x{6697}' . +'\x{6698}\x{6699}\x{669A}\x{669B}\x{669D}\x{669F}\x{66A0}\x{66A1}\x{66A2}' . +'\x{66A3}\x{66A4}\x{66A5}\x{66A6}\x{66A7}\x{66A8}\x{66A9}\x{66AA}\x{66AB}' . +'\x{66AE}\x{66AF}\x{66B0}\x{66B1}\x{66B2}\x{66B3}\x{66B4}\x{66B5}\x{66B6}' . +'\x{66B7}\x{66B8}\x{66B9}\x{66BA}\x{66BB}\x{66BC}\x{66BD}\x{66BE}\x{66BF}' . +'\x{66C0}\x{66C1}\x{66C2}\x{66C3}\x{66C4}\x{66C5}\x{66C6}\x{66C7}\x{66C8}' . +'\x{66C9}\x{66CA}\x{66CB}\x{66CC}\x{66CD}\x{66CE}\x{66CF}\x{66D1}\x{66D2}' . +'\x{66D4}\x{66D5}\x{66D6}\x{66D8}\x{66D9}\x{66DA}\x{66DB}\x{66DC}\x{66DD}' . +'\x{66DE}\x{66E0}\x{66E1}\x{66E2}\x{66E3}\x{66E4}\x{66E5}\x{66E6}\x{66E7}' . +'\x{66E8}\x{66E9}\x{66EA}\x{66EB}\x{66EC}\x{66ED}\x{66EE}\x{66F0}\x{66F1}' . +'\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F6}\x{66F7}\x{66F8}\x{66F9}\x{66FA}' . +'\x{66FB}\x{66FC}\x{66FE}\x{66FF}\x{6700}\x{6701}\x{6703}\x{6704}\x{6705}' . +'\x{6706}\x{6708}\x{6709}\x{670A}\x{670B}\x{670C}\x{670D}\x{670E}\x{670F}' . +'\x{6710}\x{6711}\x{6712}\x{6713}\x{6714}\x{6715}\x{6716}\x{6717}\x{6718}' . +'\x{671A}\x{671B}\x{671C}\x{671D}\x{671E}\x{671F}\x{6720}\x{6721}\x{6722}' . +'\x{6723}\x{6725}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}\x{672D}' . +'\x{672E}\x{672F}\x{6730}\x{6731}\x{6732}\x{6733}\x{6734}\x{6735}\x{6736}' . +'\x{6737}\x{6738}\x{6739}\x{673A}\x{673B}\x{673C}\x{673D}\x{673E}\x{673F}' . +'\x{6740}\x{6741}\x{6742}\x{6743}\x{6744}\x{6745}\x{6746}\x{6747}\x{6748}' . +'\x{6749}\x{674A}\x{674B}\x{674C}\x{674D}\x{674E}\x{674F}\x{6750}\x{6751}' . +'\x{6752}\x{6753}\x{6754}\x{6755}\x{6756}\x{6757}\x{6758}\x{6759}\x{675A}' . +'\x{675B}\x{675C}\x{675D}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{6766}\x{6768}\x{6769}\x{676A}\x{676B}\x{676C}\x{676D}' . +'\x{676E}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}\x{6774}\x{6775}\x{6776}' . +'\x{6777}\x{6778}\x{6779}\x{677A}\x{677B}\x{677C}\x{677D}\x{677E}\x{677F}' . +'\x{6780}\x{6781}\x{6782}\x{6783}\x{6784}\x{6785}\x{6786}\x{6787}\x{6789}' . +'\x{678A}\x{678B}\x{678C}\x{678D}\x{678E}\x{678F}\x{6790}\x{6791}\x{6792}' . +'\x{6793}\x{6794}\x{6795}\x{6797}\x{6798}\x{6799}\x{679A}\x{679B}\x{679C}' . +'\x{679D}\x{679E}\x{679F}\x{67A0}\x{67A1}\x{67A2}\x{67A3}\x{67A4}\x{67A5}' . +'\x{67A6}\x{67A7}\x{67A8}\x{67AA}\x{67AB}\x{67AC}\x{67AD}\x{67AE}\x{67AF}' . +'\x{67B0}\x{67B1}\x{67B2}\x{67B3}\x{67B4}\x{67B5}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67BA}\x{67BB}\x{67BC}\x{67BE}\x{67C0}\x{67C1}\x{67C2}\x{67C3}' . +'\x{67C4}\x{67C5}\x{67C6}\x{67C7}\x{67C8}\x{67C9}\x{67CA}\x{67CB}\x{67CC}' . +'\x{67CD}\x{67CE}\x{67CF}\x{67D0}\x{67D1}\x{67D2}\x{67D3}\x{67D4}\x{67D6}' . +'\x{67D8}\x{67D9}\x{67DA}\x{67DB}\x{67DC}\x{67DD}\x{67DE}\x{67DF}\x{67E0}' . +'\x{67E1}\x{67E2}\x{67E3}\x{67E4}\x{67E5}\x{67E6}\x{67E7}\x{67E8}\x{67E9}' . +'\x{67EA}\x{67EB}\x{67EC}\x{67ED}\x{67EE}\x{67EF}\x{67F0}\x{67F1}\x{67F2}' . +'\x{67F3}\x{67F4}\x{67F5}\x{67F6}\x{67F7}\x{67F8}\x{67FA}\x{67FB}\x{67FC}' . +'\x{67FD}\x{67FE}\x{67FF}\x{6800}\x{6802}\x{6803}\x{6804}\x{6805}\x{6806}' . +'\x{6807}\x{6808}\x{6809}\x{680A}\x{680B}\x{680C}\x{680D}\x{680E}\x{680F}' . +'\x{6810}\x{6811}\x{6812}\x{6813}\x{6814}\x{6816}\x{6817}\x{6818}\x{6819}' . +'\x{681A}\x{681B}\x{681C}\x{681D}\x{681F}\x{6820}\x{6821}\x{6822}\x{6823}' . +'\x{6824}\x{6825}\x{6826}\x{6828}\x{6829}\x{682A}\x{682B}\x{682C}\x{682D}' . +'\x{682E}\x{682F}\x{6831}\x{6832}\x{6833}\x{6834}\x{6835}\x{6836}\x{6837}' . +'\x{6838}\x{6839}\x{683A}\x{683B}\x{683C}\x{683D}\x{683E}\x{683F}\x{6840}' . +'\x{6841}\x{6842}\x{6843}\x{6844}\x{6845}\x{6846}\x{6847}\x{6848}\x{6849}' . +'\x{684A}\x{684B}\x{684C}\x{684D}\x{684E}\x{684F}\x{6850}\x{6851}\x{6852}' . +'\x{6853}\x{6854}\x{6855}\x{6856}\x{6857}\x{685B}\x{685D}\x{6860}\x{6861}' . +'\x{6862}\x{6863}\x{6864}\x{6865}\x{6866}\x{6867}\x{6868}\x{6869}\x{686A}' . +'\x{686B}\x{686C}\x{686D}\x{686E}\x{686F}\x{6870}\x{6871}\x{6872}\x{6873}' . +'\x{6874}\x{6875}\x{6876}\x{6877}\x{6878}\x{6879}\x{687B}\x{687C}\x{687D}' . +'\x{687E}\x{687F}\x{6880}\x{6881}\x{6882}\x{6883}\x{6884}\x{6885}\x{6886}' . +'\x{6887}\x{6888}\x{6889}\x{688A}\x{688B}\x{688C}\x{688D}\x{688E}\x{688F}' . +'\x{6890}\x{6891}\x{6892}\x{6893}\x{6894}\x{6896}\x{6897}\x{6898}\x{689A}' . +'\x{689B}\x{689C}\x{689D}\x{689E}\x{689F}\x{68A0}\x{68A1}\x{68A2}\x{68A3}' . +'\x{68A4}\x{68A6}\x{68A7}\x{68A8}\x{68A9}\x{68AA}\x{68AB}\x{68AC}\x{68AD}' . +'\x{68AE}\x{68AF}\x{68B0}\x{68B1}\x{68B2}\x{68B3}\x{68B4}\x{68B5}\x{68B6}' . +'\x{68B7}\x{68B9}\x{68BB}\x{68BC}\x{68BD}\x{68BE}\x{68BF}\x{68C0}\x{68C1}' . +'\x{68C2}\x{68C4}\x{68C6}\x{68C7}\x{68C8}\x{68C9}\x{68CA}\x{68CB}\x{68CC}' . +'\x{68CD}\x{68CE}\x{68CF}\x{68D0}\x{68D1}\x{68D2}\x{68D3}\x{68D4}\x{68D5}' . +'\x{68D6}\x{68D7}\x{68D8}\x{68DA}\x{68DB}\x{68DC}\x{68DD}\x{68DE}\x{68DF}' . +'\x{68E0}\x{68E1}\x{68E3}\x{68E4}\x{68E6}\x{68E7}\x{68E8}\x{68E9}\x{68EA}' . +'\x{68EB}\x{68EC}\x{68ED}\x{68EE}\x{68EF}\x{68F0}\x{68F1}\x{68F2}\x{68F3}' . +'\x{68F4}\x{68F5}\x{68F6}\x{68F7}\x{68F8}\x{68F9}\x{68FA}\x{68FB}\x{68FC}' . +'\x{68FD}\x{68FE}\x{68FF}\x{6901}\x{6902}\x{6903}\x{6904}\x{6905}\x{6906}' . +'\x{6907}\x{6908}\x{690A}\x{690B}\x{690C}\x{690D}\x{690E}\x{690F}\x{6910}' . +'\x{6911}\x{6912}\x{6913}\x{6914}\x{6915}\x{6916}\x{6917}\x{6918}\x{6919}' . +'\x{691A}\x{691B}\x{691C}\x{691D}\x{691E}\x{691F}\x{6920}\x{6921}\x{6922}' . +'\x{6923}\x{6924}\x{6925}\x{6926}\x{6927}\x{6928}\x{6929}\x{692A}\x{692B}' . +'\x{692C}\x{692D}\x{692E}\x{692F}\x{6930}\x{6931}\x{6932}\x{6933}\x{6934}' . +'\x{6935}\x{6936}\x{6937}\x{6938}\x{6939}\x{693A}\x{693B}\x{693C}\x{693D}' . +'\x{693F}\x{6940}\x{6941}\x{6942}\x{6943}\x{6944}\x{6945}\x{6946}\x{6947}' . +'\x{6948}\x{6949}\x{694A}\x{694B}\x{694C}\x{694E}\x{694F}\x{6950}\x{6951}' . +'\x{6952}\x{6953}\x{6954}\x{6955}\x{6956}\x{6957}\x{6958}\x{6959}\x{695A}' . +'\x{695B}\x{695C}\x{695D}\x{695E}\x{695F}\x{6960}\x{6961}\x{6962}\x{6963}' . +'\x{6964}\x{6965}\x{6966}\x{6967}\x{6968}\x{6969}\x{696A}\x{696B}\x{696C}' . +'\x{696D}\x{696E}\x{696F}\x{6970}\x{6971}\x{6972}\x{6973}\x{6974}\x{6975}' . +'\x{6976}\x{6977}\x{6978}\x{6979}\x{697A}\x{697B}\x{697C}\x{697D}\x{697E}' . +'\x{697F}\x{6980}\x{6981}\x{6982}\x{6983}\x{6984}\x{6985}\x{6986}\x{6987}' . +'\x{6988}\x{6989}\x{698A}\x{698B}\x{698C}\x{698D}\x{698E}\x{698F}\x{6990}' . +'\x{6991}\x{6992}\x{6993}\x{6994}\x{6995}\x{6996}\x{6997}\x{6998}\x{6999}' . +'\x{699A}\x{699B}\x{699C}\x{699D}\x{699E}\x{69A0}\x{69A1}\x{69A3}\x{69A4}' . +'\x{69A5}\x{69A6}\x{69A7}\x{69A8}\x{69A9}\x{69AA}\x{69AB}\x{69AC}\x{69AD}' . +'\x{69AE}\x{69AF}\x{69B0}\x{69B1}\x{69B2}\x{69B3}\x{69B4}\x{69B5}\x{69B6}' . +'\x{69B7}\x{69B8}\x{69B9}\x{69BA}\x{69BB}\x{69BC}\x{69BD}\x{69BE}\x{69BF}' . +'\x{69C1}\x{69C2}\x{69C3}\x{69C4}\x{69C5}\x{69C6}\x{69C7}\x{69C8}\x{69C9}' . +'\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}\x{69CF}\x{69D0}\x{69D3}\x{69D4}' . +'\x{69D8}\x{69D9}\x{69DA}\x{69DB}\x{69DC}\x{69DD}\x{69DE}\x{69DF}\x{69E0}' . +'\x{69E1}\x{69E2}\x{69E3}\x{69E4}\x{69E5}\x{69E6}\x{69E7}\x{69E8}\x{69E9}' . +'\x{69EA}\x{69EB}\x{69EC}\x{69ED}\x{69EE}\x{69EF}\x{69F0}\x{69F1}\x{69F2}' . +'\x{69F3}\x{69F4}\x{69F5}\x{69F6}\x{69F7}\x{69F8}\x{69FA}\x{69FB}\x{69FC}' . +'\x{69FD}\x{69FE}\x{69FF}\x{6A00}\x{6A01}\x{6A02}\x{6A04}\x{6A05}\x{6A06}' . +'\x{6A07}\x{6A08}\x{6A09}\x{6A0A}\x{6A0B}\x{6A0D}\x{6A0E}\x{6A0F}\x{6A10}' . +'\x{6A11}\x{6A12}\x{6A13}\x{6A14}\x{6A15}\x{6A16}\x{6A17}\x{6A18}\x{6A19}' . +'\x{6A1A}\x{6A1B}\x{6A1D}\x{6A1E}\x{6A1F}\x{6A20}\x{6A21}\x{6A22}\x{6A23}' . +'\x{6A25}\x{6A26}\x{6A27}\x{6A28}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2C}\x{6A2D}' . +'\x{6A2E}\x{6A2F}\x{6A30}\x{6A31}\x{6A32}\x{6A33}\x{6A34}\x{6A35}\x{6A36}' . +'\x{6A38}\x{6A39}\x{6A3A}\x{6A3B}\x{6A3C}\x{6A3D}\x{6A3E}\x{6A3F}\x{6A40}' . +'\x{6A41}\x{6A42}\x{6A43}\x{6A44}\x{6A45}\x{6A46}\x{6A47}\x{6A48}\x{6A49}' . +'\x{6A4B}\x{6A4C}\x{6A4D}\x{6A4E}\x{6A4F}\x{6A50}\x{6A51}\x{6A52}\x{6A54}' . +'\x{6A55}\x{6A56}\x{6A57}\x{6A58}\x{6A59}\x{6A5A}\x{6A5B}\x{6A5D}\x{6A5E}' . +'\x{6A5F}\x{6A60}\x{6A61}\x{6A62}\x{6A63}\x{6A64}\x{6A65}\x{6A66}\x{6A67}' . +'\x{6A68}\x{6A69}\x{6A6A}\x{6A6B}\x{6A6C}\x{6A6D}\x{6A6F}\x{6A71}\x{6A72}' . +'\x{6A73}\x{6A74}\x{6A75}\x{6A76}\x{6A77}\x{6A78}\x{6A79}\x{6A7A}\x{6A7B}' . +'\x{6A7C}\x{6A7D}\x{6A7E}\x{6A7F}\x{6A80}\x{6A81}\x{6A82}\x{6A83}\x{6A84}' . +'\x{6A85}\x{6A87}\x{6A88}\x{6A89}\x{6A8B}\x{6A8C}\x{6A8D}\x{6A8E}\x{6A90}' . +'\x{6A91}\x{6A92}\x{6A93}\x{6A94}\x{6A95}\x{6A96}\x{6A97}\x{6A98}\x{6A9A}' . +'\x{6A9B}\x{6A9C}\x{6A9E}\x{6A9F}\x{6AA0}\x{6AA1}\x{6AA2}\x{6AA3}\x{6AA4}' . +'\x{6AA5}\x{6AA6}\x{6AA7}\x{6AA8}\x{6AA9}\x{6AAB}\x{6AAC}\x{6AAD}\x{6AAE}' . +'\x{6AAF}\x{6AB0}\x{6AB2}\x{6AB3}\x{6AB4}\x{6AB5}\x{6AB6}\x{6AB7}\x{6AB8}' . +'\x{6AB9}\x{6ABA}\x{6ABB}\x{6ABC}\x{6ABD}\x{6ABF}\x{6AC1}\x{6AC2}\x{6AC3}' . +'\x{6AC5}\x{6AC6}\x{6AC7}\x{6ACA}\x{6ACB}\x{6ACC}\x{6ACD}\x{6ACE}\x{6ACF}' . +'\x{6AD0}\x{6AD1}\x{6AD2}\x{6AD3}\x{6AD4}\x{6AD5}\x{6AD6}\x{6AD7}\x{6AD9}' . +'\x{6ADA}\x{6ADB}\x{6ADC}\x{6ADD}\x{6ADE}\x{6ADF}\x{6AE0}\x{6AE1}\x{6AE2}' . +'\x{6AE3}\x{6AE4}\x{6AE5}\x{6AE6}\x{6AE7}\x{6AE8}\x{6AEA}\x{6AEB}\x{6AEC}' . +'\x{6AED}\x{6AEE}\x{6AEF}\x{6AF0}\x{6AF1}\x{6AF2}\x{6AF3}\x{6AF4}\x{6AF5}' . +'\x{6AF6}\x{6AF7}\x{6AF8}\x{6AF9}\x{6AFA}\x{6AFB}\x{6AFC}\x{6AFD}\x{6AFE}' . +'\x{6AFF}\x{6B00}\x{6B01}\x{6B02}\x{6B03}\x{6B04}\x{6B05}\x{6B06}\x{6B07}' . +'\x{6B08}\x{6B09}\x{6B0A}\x{6B0B}\x{6B0C}\x{6B0D}\x{6B0F}\x{6B10}\x{6B11}' . +'\x{6B12}\x{6B13}\x{6B14}\x{6B15}\x{6B16}\x{6B17}\x{6B18}\x{6B19}\x{6B1A}' . +'\x{6B1C}\x{6B1D}\x{6B1E}\x{6B1F}\x{6B20}\x{6B21}\x{6B22}\x{6B23}\x{6B24}' . +'\x{6B25}\x{6B26}\x{6B27}\x{6B28}\x{6B29}\x{6B2A}\x{6B2B}\x{6B2C}\x{6B2D}' . +'\x{6B2F}\x{6B30}\x{6B31}\x{6B32}\x{6B33}\x{6B34}\x{6B36}\x{6B37}\x{6B38}' . +'\x{6B39}\x{6B3A}\x{6B3B}\x{6B3C}\x{6B3D}\x{6B3E}\x{6B3F}\x{6B41}\x{6B42}' . +'\x{6B43}\x{6B44}\x{6B45}\x{6B46}\x{6B47}\x{6B48}\x{6B49}\x{6B4A}\x{6B4B}' . +'\x{6B4C}\x{6B4D}\x{6B4E}\x{6B4F}\x{6B50}\x{6B51}\x{6B52}\x{6B53}\x{6B54}' . +'\x{6B55}\x{6B56}\x{6B59}\x{6B5A}\x{6B5B}\x{6B5C}\x{6B5E}\x{6B5F}\x{6B60}' . +'\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B65}\x{6B66}\x{6B67}\x{6B69}\x{6B6A}' . +'\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}\x{6B73}\x{6B74}\x{6B76}\x{6B77}' . +'\x{6B78}\x{6B79}\x{6B7A}\x{6B7B}\x{6B7C}\x{6B7E}\x{6B7F}\x{6B80}\x{6B81}' . +'\x{6B82}\x{6B83}\x{6B84}\x{6B85}\x{6B86}\x{6B87}\x{6B88}\x{6B89}\x{6B8A}' . +'\x{6B8B}\x{6B8C}\x{6B8D}\x{6B8E}\x{6B8F}\x{6B90}\x{6B91}\x{6B92}\x{6B93}' . +'\x{6B94}\x{6B95}\x{6B96}\x{6B97}\x{6B98}\x{6B99}\x{6B9A}\x{6B9B}\x{6B9C}' . +'\x{6B9D}\x{6B9E}\x{6B9F}\x{6BA0}\x{6BA1}\x{6BA2}\x{6BA3}\x{6BA4}\x{6BA5}' . +'\x{6BA6}\x{6BA7}\x{6BA8}\x{6BA9}\x{6BAA}\x{6BAB}\x{6BAC}\x{6BAD}\x{6BAE}' . +'\x{6BAF}\x{6BB0}\x{6BB2}\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB6}\x{6BB7}\x{6BB9}' . +'\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBD}\x{6BBE}\x{6BBF}\x{6BC0}\x{6BC1}\x{6BC2}' . +'\x{6BC3}\x{6BC4}\x{6BC5}\x{6BC6}\x{6BC7}\x{6BC8}\x{6BC9}\x{6BCA}\x{6BCB}' . +'\x{6BCC}\x{6BCD}\x{6BCE}\x{6BCF}\x{6BD0}\x{6BD1}\x{6BD2}\x{6BD3}\x{6BD4}' . +'\x{6BD5}\x{6BD6}\x{6BD7}\x{6BD8}\x{6BD9}\x{6BDA}\x{6BDB}\x{6BDC}\x{6BDD}' . +'\x{6BDE}\x{6BDF}\x{6BE0}\x{6BE1}\x{6BE2}\x{6BE3}\x{6BE4}\x{6BE5}\x{6BE6}' . +'\x{6BE7}\x{6BE8}\x{6BEA}\x{6BEB}\x{6BEC}\x{6BED}\x{6BEE}\x{6BEF}\x{6BF0}' . +'\x{6BF2}\x{6BF3}\x{6BF5}\x{6BF6}\x{6BF7}\x{6BF8}\x{6BF9}\x{6BFB}\x{6BFC}' . +'\x{6BFD}\x{6BFE}\x{6BFF}\x{6C00}\x{6C01}\x{6C02}\x{6C03}\x{6C04}\x{6C05}' . +'\x{6C06}\x{6C07}\x{6C08}\x{6C09}\x{6C0B}\x{6C0C}\x{6C0D}\x{6C0E}\x{6C0F}' . +'\x{6C10}\x{6C11}\x{6C12}\x{6C13}\x{6C14}\x{6C15}\x{6C16}\x{6C18}\x{6C19}' . +'\x{6C1A}\x{6C1B}\x{6C1D}\x{6C1E}\x{6C1F}\x{6C20}\x{6C21}\x{6C22}\x{6C23}' . +'\x{6C24}\x{6C25}\x{6C26}\x{6C27}\x{6C28}\x{6C29}\x{6C2A}\x{6C2B}\x{6C2C}' . +'\x{6C2E}\x{6C2F}\x{6C30}\x{6C31}\x{6C32}\x{6C33}\x{6C34}\x{6C35}\x{6C36}' . +'\x{6C37}\x{6C38}\x{6C3A}\x{6C3B}\x{6C3D}\x{6C3E}\x{6C3F}\x{6C40}\x{6C41}' . +'\x{6C42}\x{6C43}\x{6C44}\x{6C46}\x{6C47}\x{6C48}\x{6C49}\x{6C4A}\x{6C4B}' . +'\x{6C4C}\x{6C4D}\x{6C4E}\x{6C4F}\x{6C50}\x{6C51}\x{6C52}\x{6C53}\x{6C54}' . +'\x{6C55}\x{6C56}\x{6C57}\x{6C58}\x{6C59}\x{6C5A}\x{6C5B}\x{6C5C}\x{6C5D}' . +'\x{6C5E}\x{6C5F}\x{6C60}\x{6C61}\x{6C62}\x{6C63}\x{6C64}\x{6C65}\x{6C66}' . +'\x{6C67}\x{6C68}\x{6C69}\x{6C6A}\x{6C6B}\x{6C6D}\x{6C6F}\x{6C70}\x{6C71}' . +'\x{6C72}\x{6C73}\x{6C74}\x{6C75}\x{6C76}\x{6C77}\x{6C78}\x{6C79}\x{6C7A}' . +'\x{6C7B}\x{6C7C}\x{6C7D}\x{6C7E}\x{6C7F}\x{6C80}\x{6C81}\x{6C82}\x{6C83}' . +'\x{6C84}\x{6C85}\x{6C86}\x{6C87}\x{6C88}\x{6C89}\x{6C8A}\x{6C8B}\x{6C8C}' . +'\x{6C8D}\x{6C8E}\x{6C8F}\x{6C90}\x{6C91}\x{6C92}\x{6C93}\x{6C94}\x{6C95}' . +'\x{6C96}\x{6C97}\x{6C98}\x{6C99}\x{6C9A}\x{6C9B}\x{6C9C}\x{6C9D}\x{6C9E}' . +'\x{6C9F}\x{6CA1}\x{6CA2}\x{6CA3}\x{6CA4}\x{6CA5}\x{6CA6}\x{6CA7}\x{6CA8}' . +'\x{6CA9}\x{6CAA}\x{6CAB}\x{6CAC}\x{6CAD}\x{6CAE}\x{6CAF}\x{6CB0}\x{6CB1}' . +'\x{6CB2}\x{6CB3}\x{6CB4}\x{6CB5}\x{6CB6}\x{6CB7}\x{6CB8}\x{6CB9}\x{6CBA}' . +'\x{6CBB}\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC0}\x{6CC1}\x{6CC2}\x{6CC3}' . +'\x{6CC4}\x{6CC5}\x{6CC6}\x{6CC7}\x{6CC8}\x{6CC9}\x{6CCA}\x{6CCB}\x{6CCC}' . +'\x{6CCD}\x{6CCE}\x{6CCF}\x{6CD0}\x{6CD1}\x{6CD2}\x{6CD3}\x{6CD4}\x{6CD5}' . +'\x{6CD6}\x{6CD7}\x{6CD9}\x{6CDA}\x{6CDB}\x{6CDC}\x{6CDD}\x{6CDE}\x{6CDF}' . +'\x{6CE0}\x{6CE1}\x{6CE2}\x{6CE3}\x{6CE4}\x{6CE5}\x{6CE6}\x{6CE7}\x{6CE8}' . +'\x{6CE9}\x{6CEA}\x{6CEB}\x{6CEC}\x{6CED}\x{6CEE}\x{6CEF}\x{6CF0}\x{6CF1}' . +'\x{6CF2}\x{6CF3}\x{6CF5}\x{6CF6}\x{6CF7}\x{6CF8}\x{6CF9}\x{6CFA}\x{6CFB}' . +'\x{6CFC}\x{6CFD}\x{6CFE}\x{6CFF}\x{6D00}\x{6D01}\x{6D03}\x{6D04}\x{6D05}' . +'\x{6D06}\x{6D07}\x{6D08}\x{6D09}\x{6D0A}\x{6D0B}\x{6D0C}\x{6D0D}\x{6D0E}' . +'\x{6D0F}\x{6D10}\x{6D11}\x{6D12}\x{6D13}\x{6D14}\x{6D15}\x{6D16}\x{6D17}' . +'\x{6D18}\x{6D19}\x{6D1A}\x{6D1B}\x{6D1D}\x{6D1E}\x{6D1F}\x{6D20}\x{6D21}' . +'\x{6D22}\x{6D23}\x{6D25}\x{6D26}\x{6D27}\x{6D28}\x{6D29}\x{6D2A}\x{6D2B}' . +'\x{6D2C}\x{6D2D}\x{6D2E}\x{6D2F}\x{6D30}\x{6D31}\x{6D32}\x{6D33}\x{6D34}' . +'\x{6D35}\x{6D36}\x{6D37}\x{6D38}\x{6D39}\x{6D3A}\x{6D3B}\x{6D3C}\x{6D3D}' . +'\x{6D3E}\x{6D3F}\x{6D40}\x{6D41}\x{6D42}\x{6D43}\x{6D44}\x{6D45}\x{6D46}' . +'\x{6D47}\x{6D48}\x{6D49}\x{6D4A}\x{6D4B}\x{6D4C}\x{6D4D}\x{6D4E}\x{6D4F}' . +'\x{6D50}\x{6D51}\x{6D52}\x{6D53}\x{6D54}\x{6D55}\x{6D56}\x{6D57}\x{6D58}' . +'\x{6D59}\x{6D5A}\x{6D5B}\x{6D5C}\x{6D5D}\x{6D5E}\x{6D5F}\x{6D60}\x{6D61}' . +'\x{6D62}\x{6D63}\x{6D64}\x{6D65}\x{6D66}\x{6D67}\x{6D68}\x{6D69}\x{6D6A}' . +'\x{6D6B}\x{6D6C}\x{6D6D}\x{6D6E}\x{6D6F}\x{6D70}\x{6D72}\x{6D73}\x{6D74}' . +'\x{6D75}\x{6D76}\x{6D77}\x{6D78}\x{6D79}\x{6D7A}\x{6D7B}\x{6D7C}\x{6D7D}' . +'\x{6D7E}\x{6D7F}\x{6D80}\x{6D82}\x{6D83}\x{6D84}\x{6D85}\x{6D86}\x{6D87}' . +'\x{6D88}\x{6D89}\x{6D8A}\x{6D8B}\x{6D8C}\x{6D8D}\x{6D8E}\x{6D8F}\x{6D90}' . +'\x{6D91}\x{6D92}\x{6D93}\x{6D94}\x{6D95}\x{6D97}\x{6D98}\x{6D99}\x{6D9A}' . +'\x{6D9B}\x{6D9D}\x{6D9E}\x{6D9F}\x{6DA0}\x{6DA1}\x{6DA2}\x{6DA3}\x{6DA4}' . +'\x{6DA5}\x{6DA6}\x{6DA7}\x{6DA8}\x{6DA9}\x{6DAA}\x{6DAB}\x{6DAC}\x{6DAD}' . +'\x{6DAE}\x{6DAF}\x{6DB2}\x{6DB3}\x{6DB4}\x{6DB5}\x{6DB7}\x{6DB8}\x{6DB9}' . +'\x{6DBA}\x{6DBB}\x{6DBC}\x{6DBD}\x{6DBE}\x{6DBF}\x{6DC0}\x{6DC1}\x{6DC2}' . +'\x{6DC3}\x{6DC4}\x{6DC5}\x{6DC6}\x{6DC7}\x{6DC8}\x{6DC9}\x{6DCA}\x{6DCB}' . +'\x{6DCC}\x{6DCD}\x{6DCE}\x{6DCF}\x{6DD0}\x{6DD1}\x{6DD2}\x{6DD3}\x{6DD4}' . +'\x{6DD5}\x{6DD6}\x{6DD7}\x{6DD8}\x{6DD9}\x{6DDA}\x{6DDB}\x{6DDC}\x{6DDD}' . +'\x{6DDE}\x{6DDF}\x{6DE0}\x{6DE1}\x{6DE2}\x{6DE3}\x{6DE4}\x{6DE5}\x{6DE6}' . +'\x{6DE7}\x{6DE8}\x{6DE9}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DED}\x{6DEE}\x{6DEF}' . +'\x{6DF0}\x{6DF1}\x{6DF2}\x{6DF3}\x{6DF4}\x{6DF5}\x{6DF6}\x{6DF7}\x{6DF8}' . +'\x{6DF9}\x{6DFA}\x{6DFB}\x{6DFC}\x{6DFD}\x{6E00}\x{6E03}\x{6E04}\x{6E05}' . +'\x{6E07}\x{6E08}\x{6E09}\x{6E0A}\x{6E0B}\x{6E0C}\x{6E0D}\x{6E0E}\x{6E0F}' . +'\x{6E10}\x{6E11}\x{6E14}\x{6E15}\x{6E16}\x{6E17}\x{6E19}\x{6E1A}\x{6E1B}' . +'\x{6E1C}\x{6E1D}\x{6E1E}\x{6E1F}\x{6E20}\x{6E21}\x{6E22}\x{6E23}\x{6E24}' . +'\x{6E25}\x{6E26}\x{6E27}\x{6E28}\x{6E29}\x{6E2B}\x{6E2C}\x{6E2D}\x{6E2E}' . +'\x{6E2F}\x{6E30}\x{6E31}\x{6E32}\x{6E33}\x{6E34}\x{6E35}\x{6E36}\x{6E37}' . +'\x{6E38}\x{6E39}\x{6E3A}\x{6E3B}\x{6E3C}\x{6E3D}\x{6E3E}\x{6E3F}\x{6E40}' . +'\x{6E41}\x{6E42}\x{6E43}\x{6E44}\x{6E45}\x{6E46}\x{6E47}\x{6E48}\x{6E49}' . +'\x{6E4A}\x{6E4B}\x{6E4D}\x{6E4E}\x{6E4F}\x{6E50}\x{6E51}\x{6E52}\x{6E53}' . +'\x{6E54}\x{6E55}\x{6E56}\x{6E57}\x{6E58}\x{6E59}\x{6E5A}\x{6E5B}\x{6E5C}' . +'\x{6E5D}\x{6E5E}\x{6E5F}\x{6E60}\x{6E61}\x{6E62}\x{6E63}\x{6E64}\x{6E65}' . +'\x{6E66}\x{6E67}\x{6E68}\x{6E69}\x{6E6A}\x{6E6B}\x{6E6D}\x{6E6E}\x{6E6F}' . +'\x{6E70}\x{6E71}\x{6E72}\x{6E73}\x{6E74}\x{6E75}\x{6E77}\x{6E78}\x{6E79}' . +'\x{6E7E}\x{6E7F}\x{6E80}\x{6E81}\x{6E82}\x{6E83}\x{6E84}\x{6E85}\x{6E86}' . +'\x{6E87}\x{6E88}\x{6E89}\x{6E8A}\x{6E8D}\x{6E8E}\x{6E8F}\x{6E90}\x{6E91}' . +'\x{6E92}\x{6E93}\x{6E94}\x{6E96}\x{6E97}\x{6E98}\x{6E99}\x{6E9A}\x{6E9B}' . +'\x{6E9C}\x{6E9D}\x{6E9E}\x{6E9F}\x{6EA0}\x{6EA1}\x{6EA2}\x{6EA3}\x{6EA4}' . +'\x{6EA5}\x{6EA6}\x{6EA7}\x{6EA8}\x{6EA9}\x{6EAA}\x{6EAB}\x{6EAC}\x{6EAD}' . +'\x{6EAE}\x{6EAF}\x{6EB0}\x{6EB1}\x{6EB2}\x{6EB3}\x{6EB4}\x{6EB5}\x{6EB6}' . +'\x{6EB7}\x{6EB8}\x{6EB9}\x{6EBA}\x{6EBB}\x{6EBC}\x{6EBD}\x{6EBE}\x{6EBF}' . +'\x{6EC0}\x{6EC1}\x{6EC2}\x{6EC3}\x{6EC4}\x{6EC5}\x{6EC6}\x{6EC7}\x{6EC8}' . +'\x{6EC9}\x{6ECA}\x{6ECB}\x{6ECC}\x{6ECD}\x{6ECE}\x{6ECF}\x{6ED0}\x{6ED1}' . +'\x{6ED2}\x{6ED3}\x{6ED4}\x{6ED5}\x{6ED6}\x{6ED7}\x{6ED8}\x{6ED9}\x{6EDA}' . +'\x{6EDC}\x{6EDE}\x{6EDF}\x{6EE0}\x{6EE1}\x{6EE2}\x{6EE4}\x{6EE5}\x{6EE6}' . +'\x{6EE7}\x{6EE8}\x{6EE9}\x{6EEA}\x{6EEB}\x{6EEC}\x{6EED}\x{6EEE}\x{6EEF}' . +'\x{6EF0}\x{6EF1}\x{6EF2}\x{6EF3}\x{6EF4}\x{6EF5}\x{6EF6}\x{6EF7}\x{6EF8}' . +'\x{6EF9}\x{6EFA}\x{6EFB}\x{6EFC}\x{6EFD}\x{6EFE}\x{6EFF}\x{6F00}\x{6F01}' . +'\x{6F02}\x{6F03}\x{6F05}\x{6F06}\x{6F07}\x{6F08}\x{6F09}\x{6F0A}\x{6F0C}' . +'\x{6F0D}\x{6F0E}\x{6F0F}\x{6F10}\x{6F11}\x{6F12}\x{6F13}\x{6F14}\x{6F15}' . +'\x{6F16}\x{6F17}\x{6F18}\x{6F19}\x{6F1A}\x{6F1B}\x{6F1C}\x{6F1D}\x{6F1E}' . +'\x{6F1F}\x{6F20}\x{6F21}\x{6F22}\x{6F23}\x{6F24}\x{6F25}\x{6F26}\x{6F27}' . +'\x{6F28}\x{6F29}\x{6F2A}\x{6F2B}\x{6F2C}\x{6F2D}\x{6F2E}\x{6F2F}\x{6F30}' . +'\x{6F31}\x{6F32}\x{6F33}\x{6F34}\x{6F35}\x{6F36}\x{6F37}\x{6F38}\x{6F39}' . +'\x{6F3A}\x{6F3B}\x{6F3C}\x{6F3D}\x{6F3E}\x{6F3F}\x{6F40}\x{6F41}\x{6F43}' . +'\x{6F44}\x{6F45}\x{6F46}\x{6F47}\x{6F49}\x{6F4B}\x{6F4C}\x{6F4D}\x{6F4E}' . +'\x{6F4F}\x{6F50}\x{6F51}\x{6F52}\x{6F53}\x{6F54}\x{6F55}\x{6F56}\x{6F57}' . +'\x{6F58}\x{6F59}\x{6F5A}\x{6F5B}\x{6F5C}\x{6F5D}\x{6F5E}\x{6F5F}\x{6F60}' . +'\x{6F61}\x{6F62}\x{6F63}\x{6F64}\x{6F65}\x{6F66}\x{6F67}\x{6F68}\x{6F69}' . +'\x{6F6A}\x{6F6B}\x{6F6C}\x{6F6D}\x{6F6E}\x{6F6F}\x{6F70}\x{6F71}\x{6F72}' . +'\x{6F73}\x{6F74}\x{6F75}\x{6F76}\x{6F77}\x{6F78}\x{6F7A}\x{6F7B}\x{6F7C}' . +'\x{6F7D}\x{6F7E}\x{6F7F}\x{6F80}\x{6F81}\x{6F82}\x{6F83}\x{6F84}\x{6F85}' . +'\x{6F86}\x{6F87}\x{6F88}\x{6F89}\x{6F8A}\x{6F8B}\x{6F8C}\x{6F8D}\x{6F8E}' . +'\x{6F8F}\x{6F90}\x{6F91}\x{6F92}\x{6F93}\x{6F94}\x{6F95}\x{6F96}\x{6F97}' . +'\x{6F99}\x{6F9B}\x{6F9C}\x{6F9D}\x{6F9E}\x{6FA0}\x{6FA1}\x{6FA2}\x{6FA3}' . +'\x{6FA4}\x{6FA5}\x{6FA6}\x{6FA7}\x{6FA8}\x{6FA9}\x{6FAA}\x{6FAB}\x{6FAC}' . +'\x{6FAD}\x{6FAE}\x{6FAF}\x{6FB0}\x{6FB1}\x{6FB2}\x{6FB3}\x{6FB4}\x{6FB5}' . +'\x{6FB6}\x{6FB8}\x{6FB9}\x{6FBA}\x{6FBB}\x{6FBC}\x{6FBD}\x{6FBE}\x{6FBF}' . +'\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC4}\x{6FC6}\x{6FC7}\x{6FC8}\x{6FC9}' . +'\x{6FCA}\x{6FCB}\x{6FCC}\x{6FCD}\x{6FCE}\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}' . +'\x{6FD5}\x{6FD6}\x{6FD7}\x{6FD8}\x{6FD9}\x{6FDA}\x{6FDB}\x{6FDC}\x{6FDD}' . +'\x{6FDE}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE2}\x{6FE3}\x{6FE4}\x{6FE5}\x{6FE6}' . +'\x{6FE7}\x{6FE8}\x{6FE9}\x{6FEA}\x{6FEB}\x{6FEC}\x{6FED}\x{6FEE}\x{6FEF}' . +'\x{6FF0}\x{6FF1}\x{6FF2}\x{6FF3}\x{6FF4}\x{6FF6}\x{6FF7}\x{6FF8}\x{6FF9}' . +'\x{6FFA}\x{6FFB}\x{6FFC}\x{6FFE}\x{6FFF}\x{7000}\x{7001}\x{7002}\x{7003}' . +'\x{7004}\x{7005}\x{7006}\x{7007}\x{7008}\x{7009}\x{700A}\x{700B}\x{700C}' . +'\x{700D}\x{700E}\x{700F}\x{7011}\x{7012}\x{7014}\x{7015}\x{7016}\x{7017}' . +'\x{7018}\x{7019}\x{701A}\x{701B}\x{701C}\x{701D}\x{701F}\x{7020}\x{7021}' . +'\x{7022}\x{7023}\x{7024}\x{7025}\x{7026}\x{7027}\x{7028}\x{7029}\x{702A}' . +'\x{702B}\x{702C}\x{702D}\x{702E}\x{702F}\x{7030}\x{7031}\x{7032}\x{7033}' . +'\x{7034}\x{7035}\x{7036}\x{7037}\x{7038}\x{7039}\x{703A}\x{703B}\x{703C}' . +'\x{703D}\x{703E}\x{703F}\x{7040}\x{7041}\x{7042}\x{7043}\x{7044}\x{7045}' . +'\x{7046}\x{7048}\x{7049}\x{704A}\x{704C}\x{704D}\x{704F}\x{7050}\x{7051}' . +'\x{7052}\x{7053}\x{7054}\x{7055}\x{7056}\x{7057}\x{7058}\x{7059}\x{705A}' . +'\x{705B}\x{705C}\x{705D}\x{705E}\x{705F}\x{7060}\x{7061}\x{7062}\x{7063}' . +'\x{7064}\x{7065}\x{7066}\x{7067}\x{7068}\x{7069}\x{706A}\x{706B}\x{706C}' . +'\x{706D}\x{706E}\x{706F}\x{7070}\x{7071}\x{7074}\x{7075}\x{7076}\x{7077}' . +'\x{7078}\x{7079}\x{707A}\x{707C}\x{707D}\x{707E}\x{707F}\x{7080}\x{7082}' . +'\x{7083}\x{7084}\x{7085}\x{7086}\x{7087}\x{7088}\x{7089}\x{708A}\x{708B}' . +'\x{708C}\x{708E}\x{708F}\x{7090}\x{7091}\x{7092}\x{7093}\x{7094}\x{7095}' . +'\x{7096}\x{7098}\x{7099}\x{709A}\x{709C}\x{709D}\x{709E}\x{709F}\x{70A0}' . +'\x{70A1}\x{70A2}\x{70A3}\x{70A4}\x{70A5}\x{70A6}\x{70A7}\x{70A8}\x{70A9}' . +'\x{70AB}\x{70AC}\x{70AD}\x{70AE}\x{70AF}\x{70B0}\x{70B1}\x{70B3}\x{70B4}' . +'\x{70B5}\x{70B7}\x{70B8}\x{70B9}\x{70BA}\x{70BB}\x{70BC}\x{70BD}\x{70BE}' . +'\x{70BF}\x{70C0}\x{70C1}\x{70C2}\x{70C3}\x{70C4}\x{70C5}\x{70C6}\x{70C7}' . +'\x{70C8}\x{70C9}\x{70CA}\x{70CB}\x{70CC}\x{70CD}\x{70CE}\x{70CF}\x{70D0}' . +'\x{70D1}\x{70D2}\x{70D3}\x{70D4}\x{70D6}\x{70D7}\x{70D8}\x{70D9}\x{70DA}' . +'\x{70DB}\x{70DC}\x{70DD}\x{70DE}\x{70DF}\x{70E0}\x{70E1}\x{70E2}\x{70E3}' . +'\x{70E4}\x{70E5}\x{70E6}\x{70E7}\x{70E8}\x{70E9}\x{70EA}\x{70EB}\x{70EC}' . +'\x{70ED}\x{70EE}\x{70EF}\x{70F0}\x{70F1}\x{70F2}\x{70F3}\x{70F4}\x{70F5}' . +'\x{70F6}\x{70F7}\x{70F8}\x{70F9}\x{70FA}\x{70FB}\x{70FC}\x{70FD}\x{70FF}' . +'\x{7100}\x{7101}\x{7102}\x{7103}\x{7104}\x{7105}\x{7106}\x{7107}\x{7109}' . +'\x{710A}\x{710B}\x{710C}\x{710D}\x{710E}\x{710F}\x{7110}\x{7111}\x{7112}' . +'\x{7113}\x{7115}\x{7116}\x{7117}\x{7118}\x{7119}\x{711A}\x{711B}\x{711C}' . +'\x{711D}\x{711E}\x{711F}\x{7120}\x{7121}\x{7122}\x{7123}\x{7125}\x{7126}' . +'\x{7127}\x{7128}\x{7129}\x{712A}\x{712B}\x{712C}\x{712D}\x{712E}\x{712F}' . +'\x{7130}\x{7131}\x{7132}\x{7135}\x{7136}\x{7137}\x{7138}\x{7139}\x{713A}' . +'\x{713B}\x{713D}\x{713E}\x{713F}\x{7140}\x{7141}\x{7142}\x{7143}\x{7144}' . +'\x{7145}\x{7146}\x{7147}\x{7148}\x{7149}\x{714A}\x{714B}\x{714C}\x{714D}' . +'\x{714E}\x{714F}\x{7150}\x{7151}\x{7152}\x{7153}\x{7154}\x{7156}\x{7158}' . +'\x{7159}\x{715A}\x{715B}\x{715C}\x{715D}\x{715E}\x{715F}\x{7160}\x{7161}' . +'\x{7162}\x{7163}\x{7164}\x{7165}\x{7166}\x{7167}\x{7168}\x{7169}\x{716A}' . +'\x{716C}\x{716E}\x{716F}\x{7170}\x{7171}\x{7172}\x{7173}\x{7174}\x{7175}' . +'\x{7176}\x{7177}\x{7178}\x{7179}\x{717A}\x{717B}\x{717C}\x{717D}\x{717E}' . +'\x{717F}\x{7180}\x{7181}\x{7182}\x{7183}\x{7184}\x{7185}\x{7186}\x{7187}' . +'\x{7188}\x{7189}\x{718A}\x{718B}\x{718C}\x{718E}\x{718F}\x{7190}\x{7191}' . +'\x{7192}\x{7193}\x{7194}\x{7195}\x{7197}\x{7198}\x{7199}\x{719A}\x{719B}' . +'\x{719C}\x{719D}\x{719E}\x{719F}\x{71A0}\x{71A1}\x{71A2}\x{71A3}\x{71A4}' . +'\x{71A5}\x{71A7}\x{71A8}\x{71A9}\x{71AA}\x{71AC}\x{71AD}\x{71AE}\x{71AF}' . +'\x{71B0}\x{71B1}\x{71B2}\x{71B3}\x{71B4}\x{71B5}\x{71B7}\x{71B8}\x{71B9}' . +'\x{71BA}\x{71BB}\x{71BC}\x{71BD}\x{71BE}\x{71BF}\x{71C0}\x{71C1}\x{71C2}' . +'\x{71C3}\x{71C4}\x{71C5}\x{71C6}\x{71C7}\x{71C8}\x{71C9}\x{71CA}\x{71CB}' . +'\x{71CD}\x{71CE}\x{71CF}\x{71D0}\x{71D1}\x{71D2}\x{71D4}\x{71D5}\x{71D6}' . +'\x{71D7}\x{71D8}\x{71D9}\x{71DA}\x{71DB}\x{71DC}\x{71DD}\x{71DE}\x{71DF}' . +'\x{71E0}\x{71E1}\x{71E2}\x{71E3}\x{71E4}\x{71E5}\x{71E6}\x{71E7}\x{71E8}' . +'\x{71E9}\x{71EA}\x{71EB}\x{71EC}\x{71ED}\x{71EE}\x{71EF}\x{71F0}\x{71F1}' . +'\x{71F2}\x{71F4}\x{71F5}\x{71F6}\x{71F7}\x{71F8}\x{71F9}\x{71FB}\x{71FC}' . +'\x{71FD}\x{71FE}\x{71FF}\x{7201}\x{7202}\x{7203}\x{7204}\x{7205}\x{7206}' . +'\x{7207}\x{7208}\x{7209}\x{720A}\x{720C}\x{720D}\x{720E}\x{720F}\x{7210}' . +'\x{7212}\x{7213}\x{7214}\x{7216}\x{7218}\x{7219}\x{721A}\x{721B}\x{721C}' . +'\x{721D}\x{721E}\x{721F}\x{7221}\x{7222}\x{7223}\x{7226}\x{7227}\x{7228}' . +'\x{7229}\x{722A}\x{722B}\x{722C}\x{722D}\x{722E}\x{7230}\x{7231}\x{7232}' . +'\x{7233}\x{7235}\x{7236}\x{7237}\x{7238}\x{7239}\x{723A}\x{723B}\x{723C}' . +'\x{723D}\x{723E}\x{723F}\x{7240}\x{7241}\x{7242}\x{7243}\x{7244}\x{7246}' . +'\x{7247}\x{7248}\x{7249}\x{724A}\x{724B}\x{724C}\x{724D}\x{724F}\x{7251}' . +'\x{7252}\x{7253}\x{7254}\x{7256}\x{7257}\x{7258}\x{7259}\x{725A}\x{725B}' . +'\x{725C}\x{725D}\x{725E}\x{725F}\x{7260}\x{7261}\x{7262}\x{7263}\x{7264}' . +'\x{7265}\x{7266}\x{7267}\x{7268}\x{7269}\x{726A}\x{726B}\x{726C}\x{726D}' . +'\x{726E}\x{726F}\x{7270}\x{7271}\x{7272}\x{7273}\x{7274}\x{7275}\x{7276}' . +'\x{7277}\x{7278}\x{7279}\x{727A}\x{727B}\x{727C}\x{727D}\x{727E}\x{727F}' . +'\x{7280}\x{7281}\x{7282}\x{7283}\x{7284}\x{7285}\x{7286}\x{7287}\x{7288}' . +'\x{7289}\x{728A}\x{728B}\x{728C}\x{728D}\x{728E}\x{728F}\x{7290}\x{7291}' . +'\x{7292}\x{7293}\x{7294}\x{7295}\x{7296}\x{7297}\x{7298}\x{7299}\x{729A}' . +'\x{729B}\x{729C}\x{729D}\x{729E}\x{729F}\x{72A1}\x{72A2}\x{72A3}\x{72A4}' . +'\x{72A5}\x{72A6}\x{72A7}\x{72A8}\x{72A9}\x{72AA}\x{72AC}\x{72AD}\x{72AE}' . +'\x{72AF}\x{72B0}\x{72B1}\x{72B2}\x{72B3}\x{72B4}\x{72B5}\x{72B6}\x{72B7}' . +'\x{72B8}\x{72B9}\x{72BA}\x{72BB}\x{72BC}\x{72BD}\x{72BF}\x{72C0}\x{72C1}' . +'\x{72C2}\x{72C3}\x{72C4}\x{72C5}\x{72C6}\x{72C7}\x{72C8}\x{72C9}\x{72CA}' . +'\x{72CB}\x{72CC}\x{72CD}\x{72CE}\x{72CF}\x{72D0}\x{72D1}\x{72D2}\x{72D3}' . +'\x{72D4}\x{72D5}\x{72D6}\x{72D7}\x{72D8}\x{72D9}\x{72DA}\x{72DB}\x{72DC}' . +'\x{72DD}\x{72DE}\x{72DF}\x{72E0}\x{72E1}\x{72E2}\x{72E3}\x{72E4}\x{72E5}' . +'\x{72E6}\x{72E7}\x{72E8}\x{72E9}\x{72EA}\x{72EB}\x{72EC}\x{72ED}\x{72EE}' . +'\x{72EF}\x{72F0}\x{72F1}\x{72F2}\x{72F3}\x{72F4}\x{72F5}\x{72F6}\x{72F7}' . +'\x{72F8}\x{72F9}\x{72FA}\x{72FB}\x{72FC}\x{72FD}\x{72FE}\x{72FF}\x{7300}' . +'\x{7301}\x{7303}\x{7304}\x{7305}\x{7306}\x{7307}\x{7308}\x{7309}\x{730A}' . +'\x{730B}\x{730C}\x{730D}\x{730E}\x{730F}\x{7311}\x{7312}\x{7313}\x{7314}' . +'\x{7315}\x{7316}\x{7317}\x{7318}\x{7319}\x{731A}\x{731B}\x{731C}\x{731D}' . +'\x{731E}\x{7320}\x{7321}\x{7322}\x{7323}\x{7324}\x{7325}\x{7326}\x{7327}' . +'\x{7329}\x{732A}\x{732B}\x{732C}\x{732D}\x{732E}\x{7330}\x{7331}\x{7332}' . +'\x{7333}\x{7334}\x{7335}\x{7336}\x{7337}\x{7338}\x{7339}\x{733A}\x{733B}' . +'\x{733C}\x{733D}\x{733E}\x{733F}\x{7340}\x{7341}\x{7342}\x{7343}\x{7344}' . +'\x{7345}\x{7346}\x{7347}\x{7348}\x{7349}\x{734A}\x{734B}\x{734C}\x{734D}' . +'\x{734E}\x{7350}\x{7351}\x{7352}\x{7354}\x{7355}\x{7356}\x{7357}\x{7358}' . +'\x{7359}\x{735A}\x{735B}\x{735C}\x{735D}\x{735E}\x{735F}\x{7360}\x{7361}' . +'\x{7362}\x{7364}\x{7365}\x{7366}\x{7367}\x{7368}\x{7369}\x{736A}\x{736B}' . +'\x{736C}\x{736D}\x{736E}\x{736F}\x{7370}\x{7371}\x{7372}\x{7373}\x{7374}' . +'\x{7375}\x{7376}\x{7377}\x{7378}\x{7379}\x{737A}\x{737B}\x{737C}\x{737D}' . +'\x{737E}\x{737F}\x{7380}\x{7381}\x{7382}\x{7383}\x{7384}\x{7385}\x{7386}' . +'\x{7387}\x{7388}\x{7389}\x{738A}\x{738B}\x{738C}\x{738D}\x{738E}\x{738F}' . +'\x{7390}\x{7391}\x{7392}\x{7393}\x{7394}\x{7395}\x{7396}\x{7397}\x{7398}' . +'\x{7399}\x{739A}\x{739B}\x{739D}\x{739E}\x{739F}\x{73A0}\x{73A1}\x{73A2}' . +'\x{73A3}\x{73A4}\x{73A5}\x{73A6}\x{73A7}\x{73A8}\x{73A9}\x{73AA}\x{73AB}' . +'\x{73AC}\x{73AD}\x{73AE}\x{73AF}\x{73B0}\x{73B1}\x{73B2}\x{73B3}\x{73B4}' . +'\x{73B5}\x{73B6}\x{73B7}\x{73B8}\x{73B9}\x{73BA}\x{73BB}\x{73BC}\x{73BD}' . +'\x{73BE}\x{73BF}\x{73C0}\x{73C2}\x{73C3}\x{73C4}\x{73C5}\x{73C6}\x{73C7}' . +'\x{73C8}\x{73C9}\x{73CA}\x{73CB}\x{73CC}\x{73CD}\x{73CE}\x{73CF}\x{73D0}' . +'\x{73D1}\x{73D2}\x{73D3}\x{73D4}\x{73D5}\x{73D6}\x{73D7}\x{73D8}\x{73D9}' . +'\x{73DA}\x{73DB}\x{73DC}\x{73DD}\x{73DE}\x{73DF}\x{73E0}\x{73E2}\x{73E3}' . +'\x{73E5}\x{73E6}\x{73E7}\x{73E8}\x{73E9}\x{73EA}\x{73EB}\x{73EC}\x{73ED}' . +'\x{73EE}\x{73EF}\x{73F0}\x{73F1}\x{73F2}\x{73F4}\x{73F5}\x{73F6}\x{73F7}' . +'\x{73F8}\x{73F9}\x{73FA}\x{73FC}\x{73FD}\x{73FE}\x{73FF}\x{7400}\x{7401}' . +'\x{7402}\x{7403}\x{7404}\x{7405}\x{7406}\x{7407}\x{7408}\x{7409}\x{740A}' . +'\x{740B}\x{740C}\x{740D}\x{740E}\x{740F}\x{7410}\x{7411}\x{7412}\x{7413}' . +'\x{7414}\x{7415}\x{7416}\x{7417}\x{7419}\x{741A}\x{741B}\x{741C}\x{741D}' . +'\x{741E}\x{741F}\x{7420}\x{7421}\x{7422}\x{7423}\x{7424}\x{7425}\x{7426}' . +'\x{7427}\x{7428}\x{7429}\x{742A}\x{742B}\x{742C}\x{742D}\x{742E}\x{742F}' . +'\x{7430}\x{7431}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{7437}\x{7438}' . +'\x{743A}\x{743B}\x{743C}\x{743D}\x{743F}\x{7440}\x{7441}\x{7442}\x{7443}' . +'\x{7444}\x{7445}\x{7446}\x{7448}\x{744A}\x{744B}\x{744C}\x{744D}\x{744E}' . +'\x{744F}\x{7450}\x{7451}\x{7452}\x{7453}\x{7454}\x{7455}\x{7456}\x{7457}' . +'\x{7459}\x{745A}\x{745B}\x{745C}\x{745D}\x{745E}\x{745F}\x{7461}\x{7462}' . +'\x{7463}\x{7464}\x{7465}\x{7466}\x{7467}\x{7468}\x{7469}\x{746A}\x{746B}' . +'\x{746C}\x{746D}\x{746E}\x{746F}\x{7470}\x{7471}\x{7472}\x{7473}\x{7474}' . +'\x{7475}\x{7476}\x{7477}\x{7478}\x{7479}\x{747A}\x{747C}\x{747D}\x{747E}' . +'\x{747F}\x{7480}\x{7481}\x{7482}\x{7483}\x{7485}\x{7486}\x{7487}\x{7488}' . +'\x{7489}\x{748A}\x{748B}\x{748C}\x{748D}\x{748E}\x{748F}\x{7490}\x{7491}' . +'\x{7492}\x{7493}\x{7494}\x{7495}\x{7497}\x{7498}\x{7499}\x{749A}\x{749B}' . +'\x{749C}\x{749E}\x{749F}\x{74A0}\x{74A1}\x{74A3}\x{74A4}\x{74A5}\x{74A6}' . +'\x{74A7}\x{74A8}\x{74A9}\x{74AA}\x{74AB}\x{74AC}\x{74AD}\x{74AE}\x{74AF}' . +'\x{74B0}\x{74B1}\x{74B2}\x{74B3}\x{74B4}\x{74B5}\x{74B6}\x{74B7}\x{74B8}' . +'\x{74B9}\x{74BA}\x{74BB}\x{74BC}\x{74BD}\x{74BE}\x{74BF}\x{74C0}\x{74C1}' . +'\x{74C2}\x{74C3}\x{74C4}\x{74C5}\x{74C6}\x{74CA}\x{74CB}\x{74CD}\x{74CE}' . +'\x{74CF}\x{74D0}\x{74D1}\x{74D2}\x{74D3}\x{74D4}\x{74D5}\x{74D6}\x{74D7}' . +'\x{74D8}\x{74D9}\x{74DA}\x{74DB}\x{74DC}\x{74DD}\x{74DE}\x{74DF}\x{74E0}' . +'\x{74E1}\x{74E2}\x{74E3}\x{74E4}\x{74E5}\x{74E6}\x{74E7}\x{74E8}\x{74E9}' . +'\x{74EA}\x{74EC}\x{74ED}\x{74EE}\x{74EF}\x{74F0}\x{74F1}\x{74F2}\x{74F3}' . +'\x{74F4}\x{74F5}\x{74F6}\x{74F7}\x{74F8}\x{74F9}\x{74FA}\x{74FB}\x{74FC}' . +'\x{74FD}\x{74FE}\x{74FF}\x{7500}\x{7501}\x{7502}\x{7503}\x{7504}\x{7505}' . +'\x{7506}\x{7507}\x{7508}\x{7509}\x{750A}\x{750B}\x{750C}\x{750D}\x{750F}' . +'\x{7510}\x{7511}\x{7512}\x{7513}\x{7514}\x{7515}\x{7516}\x{7517}\x{7518}' . +'\x{7519}\x{751A}\x{751B}\x{751C}\x{751D}\x{751E}\x{751F}\x{7521}\x{7522}' . +'\x{7523}\x{7524}\x{7525}\x{7526}\x{7527}\x{7528}\x{7529}\x{752A}\x{752B}' . +'\x{752C}\x{752D}\x{752E}\x{752F}\x{7530}\x{7531}\x{7532}\x{7533}\x{7535}' . +'\x{7536}\x{7537}\x{7538}\x{7539}\x{753A}\x{753B}\x{753C}\x{753D}\x{753E}' . +'\x{753F}\x{7540}\x{7542}\x{7543}\x{7544}\x{7545}\x{7546}\x{7547}\x{7548}' . +'\x{7549}\x{754B}\x{754C}\x{754D}\x{754E}\x{754F}\x{7550}\x{7551}\x{7553}' . +'\x{7554}\x{7556}\x{7557}\x{7558}\x{7559}\x{755A}\x{755B}\x{755C}\x{755D}' . +'\x{755F}\x{7560}\x{7562}\x{7563}\x{7564}\x{7565}\x{7566}\x{7567}\x{7568}' . +'\x{7569}\x{756A}\x{756B}\x{756C}\x{756D}\x{756E}\x{756F}\x{7570}\x{7572}' . +'\x{7574}\x{7575}\x{7576}\x{7577}\x{7578}\x{7579}\x{757C}\x{757D}\x{757E}' . +'\x{757F}\x{7580}\x{7581}\x{7582}\x{7583}\x{7584}\x{7586}\x{7587}\x{7588}' . +'\x{7589}\x{758A}\x{758B}\x{758C}\x{758D}\x{758F}\x{7590}\x{7591}\x{7592}' . +'\x{7593}\x{7594}\x{7595}\x{7596}\x{7597}\x{7598}\x{7599}\x{759A}\x{759B}' . +'\x{759C}\x{759D}\x{759E}\x{759F}\x{75A0}\x{75A1}\x{75A2}\x{75A3}\x{75A4}' . +'\x{75A5}\x{75A6}\x{75A7}\x{75A8}\x{75AA}\x{75AB}\x{75AC}\x{75AD}\x{75AE}' . +'\x{75AF}\x{75B0}\x{75B1}\x{75B2}\x{75B3}\x{75B4}\x{75B5}\x{75B6}\x{75B8}' . +'\x{75B9}\x{75BA}\x{75BB}\x{75BC}\x{75BD}\x{75BE}\x{75BF}\x{75C0}\x{75C1}' . +'\x{75C2}\x{75C3}\x{75C4}\x{75C5}\x{75C6}\x{75C7}\x{75C8}\x{75C9}\x{75CA}' . +'\x{75CB}\x{75CC}\x{75CD}\x{75CE}\x{75CF}\x{75D0}\x{75D1}\x{75D2}\x{75D3}' . +'\x{75D4}\x{75D5}\x{75D6}\x{75D7}\x{75D8}\x{75D9}\x{75DA}\x{75DB}\x{75DD}' . +'\x{75DE}\x{75DF}\x{75E0}\x{75E1}\x{75E2}\x{75E3}\x{75E4}\x{75E5}\x{75E6}' . +'\x{75E7}\x{75E8}\x{75EA}\x{75EB}\x{75EC}\x{75ED}\x{75EF}\x{75F0}\x{75F1}' . +'\x{75F2}\x{75F3}\x{75F4}\x{75F5}\x{75F6}\x{75F7}\x{75F8}\x{75F9}\x{75FA}' . +'\x{75FB}\x{75FC}\x{75FD}\x{75FE}\x{75FF}\x{7600}\x{7601}\x{7602}\x{7603}' . +'\x{7604}\x{7605}\x{7606}\x{7607}\x{7608}\x{7609}\x{760A}\x{760B}\x{760C}' . +'\x{760D}\x{760E}\x{760F}\x{7610}\x{7611}\x{7612}\x{7613}\x{7614}\x{7615}' . +'\x{7616}\x{7617}\x{7618}\x{7619}\x{761A}\x{761B}\x{761C}\x{761D}\x{761E}' . +'\x{761F}\x{7620}\x{7621}\x{7622}\x{7623}\x{7624}\x{7625}\x{7626}\x{7627}' . +'\x{7628}\x{7629}\x{762A}\x{762B}\x{762D}\x{762E}\x{762F}\x{7630}\x{7631}' . +'\x{7632}\x{7633}\x{7634}\x{7635}\x{7636}\x{7637}\x{7638}\x{7639}\x{763A}' . +'\x{763B}\x{763C}\x{763D}\x{763E}\x{763F}\x{7640}\x{7641}\x{7642}\x{7643}' . +'\x{7646}\x{7647}\x{7648}\x{7649}\x{764A}\x{764B}\x{764C}\x{764D}\x{764F}' . +'\x{7650}\x{7652}\x{7653}\x{7654}\x{7656}\x{7657}\x{7658}\x{7659}\x{765A}' . +'\x{765B}\x{765C}\x{765D}\x{765E}\x{765F}\x{7660}\x{7661}\x{7662}\x{7663}' . +'\x{7664}\x{7665}\x{7666}\x{7667}\x{7668}\x{7669}\x{766A}\x{766B}\x{766C}' . +'\x{766D}\x{766E}\x{766F}\x{7670}\x{7671}\x{7672}\x{7674}\x{7675}\x{7676}' . +'\x{7677}\x{7678}\x{7679}\x{767B}\x{767C}\x{767D}\x{767E}\x{767F}\x{7680}' . +'\x{7681}\x{7682}\x{7683}\x{7684}\x{7685}\x{7686}\x{7687}\x{7688}\x{7689}' . +'\x{768A}\x{768B}\x{768C}\x{768E}\x{768F}\x{7690}\x{7691}\x{7692}\x{7693}' . +'\x{7694}\x{7695}\x{7696}\x{7697}\x{7698}\x{7699}\x{769A}\x{769B}\x{769C}' . +'\x{769D}\x{769E}\x{769F}\x{76A0}\x{76A3}\x{76A4}\x{76A6}\x{76A7}\x{76A9}' . +'\x{76AA}\x{76AB}\x{76AC}\x{76AD}\x{76AE}\x{76AF}\x{76B0}\x{76B1}\x{76B2}' . +'\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}\x{76BB}\x{76BC}\x{76BD}\x{76BE}' . +'\x{76BF}\x{76C0}\x{76C2}\x{76C3}\x{76C4}\x{76C5}\x{76C6}\x{76C7}\x{76C8}' . +'\x{76C9}\x{76CA}\x{76CD}\x{76CE}\x{76CF}\x{76D0}\x{76D1}\x{76D2}\x{76D3}' . +'\x{76D4}\x{76D5}\x{76D6}\x{76D7}\x{76D8}\x{76DA}\x{76DB}\x{76DC}\x{76DD}' . +'\x{76DE}\x{76DF}\x{76E0}\x{76E1}\x{76E2}\x{76E3}\x{76E4}\x{76E5}\x{76E6}' . +'\x{76E7}\x{76E8}\x{76E9}\x{76EA}\x{76EC}\x{76ED}\x{76EE}\x{76EF}\x{76F0}' . +'\x{76F1}\x{76F2}\x{76F3}\x{76F4}\x{76F5}\x{76F6}\x{76F7}\x{76F8}\x{76F9}' . +'\x{76FA}\x{76FB}\x{76FC}\x{76FD}\x{76FE}\x{76FF}\x{7701}\x{7703}\x{7704}' . +'\x{7705}\x{7706}\x{7707}\x{7708}\x{7709}\x{770A}\x{770B}\x{770C}\x{770D}' . +'\x{770F}\x{7710}\x{7711}\x{7712}\x{7713}\x{7714}\x{7715}\x{7716}\x{7717}' . +'\x{7718}\x{7719}\x{771A}\x{771B}\x{771C}\x{771D}\x{771E}\x{771F}\x{7720}' . +'\x{7722}\x{7723}\x{7725}\x{7726}\x{7727}\x{7728}\x{7729}\x{772A}\x{772C}' . +'\x{772D}\x{772E}\x{772F}\x{7730}\x{7731}\x{7732}\x{7733}\x{7734}\x{7735}' . +'\x{7736}\x{7737}\x{7738}\x{7739}\x{773A}\x{773B}\x{773C}\x{773D}\x{773E}' . +'\x{7740}\x{7741}\x{7743}\x{7744}\x{7745}\x{7746}\x{7747}\x{7748}\x{7749}' . +'\x{774A}\x{774B}\x{774C}\x{774D}\x{774E}\x{774F}\x{7750}\x{7751}\x{7752}' . +'\x{7753}\x{7754}\x{7755}\x{7756}\x{7757}\x{7758}\x{7759}\x{775A}\x{775B}' . +'\x{775C}\x{775D}\x{775E}\x{775F}\x{7760}\x{7761}\x{7762}\x{7763}\x{7765}' . +'\x{7766}\x{7767}\x{7768}\x{7769}\x{776A}\x{776B}\x{776C}\x{776D}\x{776E}' . +'\x{776F}\x{7770}\x{7771}\x{7772}\x{7773}\x{7774}\x{7775}\x{7776}\x{7777}' . +'\x{7778}\x{7779}\x{777A}\x{777B}\x{777C}\x{777D}\x{777E}\x{777F}\x{7780}' . +'\x{7781}\x{7782}\x{7783}\x{7784}\x{7785}\x{7786}\x{7787}\x{7788}\x{7789}' . +'\x{778A}\x{778B}\x{778C}\x{778D}\x{778E}\x{778F}\x{7790}\x{7791}\x{7792}' . +'\x{7793}\x{7794}\x{7795}\x{7797}\x{7798}\x{7799}\x{779A}\x{779B}\x{779C}' . +'\x{779D}\x{779E}\x{779F}\x{77A0}\x{77A1}\x{77A2}\x{77A3}\x{77A5}\x{77A6}' . +'\x{77A7}\x{77A8}\x{77A9}\x{77AA}\x{77AB}\x{77AC}\x{77AD}\x{77AE}\x{77AF}' . +'\x{77B0}\x{77B1}\x{77B2}\x{77B3}\x{77B4}\x{77B5}\x{77B6}\x{77B7}\x{77B8}' . +'\x{77B9}\x{77BA}\x{77BB}\x{77BC}\x{77BD}\x{77BF}\x{77C0}\x{77C2}\x{77C3}' . +'\x{77C4}\x{77C5}\x{77C6}\x{77C7}\x{77C8}\x{77C9}\x{77CA}\x{77CB}\x{77CC}' . +'\x{77CD}\x{77CE}\x{77CF}\x{77D0}\x{77D1}\x{77D3}\x{77D4}\x{77D5}\x{77D6}' . +'\x{77D7}\x{77D8}\x{77D9}\x{77DA}\x{77DB}\x{77DC}\x{77DE}\x{77DF}\x{77E0}' . +'\x{77E1}\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E8}\x{77E9}\x{77EA}\x{77EB}' . +'\x{77EC}\x{77ED}\x{77EE}\x{77EF}\x{77F0}\x{77F1}\x{77F2}\x{77F3}\x{77F6}' . +'\x{77F7}\x{77F8}\x{77F9}\x{77FA}\x{77FB}\x{77FC}\x{77FD}\x{77FE}\x{77FF}' . +'\x{7800}\x{7801}\x{7802}\x{7803}\x{7804}\x{7805}\x{7806}\x{7808}\x{7809}' . +'\x{780A}\x{780B}\x{780C}\x{780D}\x{780E}\x{780F}\x{7810}\x{7811}\x{7812}' . +'\x{7813}\x{7814}\x{7815}\x{7816}\x{7817}\x{7818}\x{7819}\x{781A}\x{781B}' . +'\x{781C}\x{781D}\x{781E}\x{781F}\x{7820}\x{7821}\x{7822}\x{7823}\x{7825}' . +'\x{7826}\x{7827}\x{7828}\x{7829}\x{782A}\x{782B}\x{782C}\x{782D}\x{782E}' . +'\x{782F}\x{7830}\x{7831}\x{7832}\x{7833}\x{7834}\x{7835}\x{7837}\x{7838}' . +'\x{7839}\x{783A}\x{783B}\x{783C}\x{783D}\x{783E}\x{7840}\x{7841}\x{7843}' . +'\x{7844}\x{7845}\x{7847}\x{7848}\x{7849}\x{784A}\x{784C}\x{784D}\x{784E}' . +'\x{7850}\x{7851}\x{7852}\x{7853}\x{7854}\x{7855}\x{7856}\x{7857}\x{7858}' . +'\x{7859}\x{785A}\x{785B}\x{785C}\x{785D}\x{785E}\x{785F}\x{7860}\x{7861}' . +'\x{7862}\x{7863}\x{7864}\x{7865}\x{7866}\x{7867}\x{7868}\x{7869}\x{786A}' . +'\x{786B}\x{786C}\x{786D}\x{786E}\x{786F}\x{7870}\x{7871}\x{7872}\x{7873}' . +'\x{7874}\x{7875}\x{7877}\x{7878}\x{7879}\x{787A}\x{787B}\x{787C}\x{787D}' . +'\x{787E}\x{787F}\x{7880}\x{7881}\x{7882}\x{7883}\x{7884}\x{7885}\x{7886}' . +'\x{7887}\x{7889}\x{788A}\x{788B}\x{788C}\x{788D}\x{788E}\x{788F}\x{7890}' . +'\x{7891}\x{7892}\x{7893}\x{7894}\x{7895}\x{7896}\x{7897}\x{7898}\x{7899}' . +'\x{789A}\x{789B}\x{789C}\x{789D}\x{789E}\x{789F}\x{78A0}\x{78A1}\x{78A2}' . +'\x{78A3}\x{78A4}\x{78A5}\x{78A6}\x{78A7}\x{78A8}\x{78A9}\x{78AA}\x{78AB}' . +'\x{78AC}\x{78AD}\x{78AE}\x{78AF}\x{78B0}\x{78B1}\x{78B2}\x{78B3}\x{78B4}' . +'\x{78B5}\x{78B6}\x{78B7}\x{78B8}\x{78B9}\x{78BA}\x{78BB}\x{78BC}\x{78BD}' . +'\x{78BE}\x{78BF}\x{78C0}\x{78C1}\x{78C3}\x{78C4}\x{78C5}\x{78C6}\x{78C8}' . +'\x{78C9}\x{78CA}\x{78CB}\x{78CC}\x{78CD}\x{78CE}\x{78CF}\x{78D0}\x{78D1}' . +'\x{78D3}\x{78D4}\x{78D5}\x{78D6}\x{78D7}\x{78D8}\x{78D9}\x{78DA}\x{78DB}' . +'\x{78DC}\x{78DD}\x{78DE}\x{78DF}\x{78E0}\x{78E1}\x{78E2}\x{78E3}\x{78E4}' . +'\x{78E5}\x{78E6}\x{78E7}\x{78E8}\x{78E9}\x{78EA}\x{78EB}\x{78EC}\x{78ED}' . +'\x{78EE}\x{78EF}\x{78F1}\x{78F2}\x{78F3}\x{78F4}\x{78F5}\x{78F6}\x{78F7}' . +'\x{78F9}\x{78FA}\x{78FB}\x{78FC}\x{78FD}\x{78FE}\x{78FF}\x{7901}\x{7902}' . +'\x{7903}\x{7904}\x{7905}\x{7906}\x{7907}\x{7909}\x{790A}\x{790B}\x{790C}' . +'\x{790E}\x{790F}\x{7910}\x{7911}\x{7912}\x{7913}\x{7914}\x{7916}\x{7917}' . +'\x{7918}\x{7919}\x{791A}\x{791B}\x{791C}\x{791D}\x{791E}\x{7921}\x{7922}' . +'\x{7923}\x{7924}\x{7925}\x{7926}\x{7927}\x{7928}\x{7929}\x{792A}\x{792B}' . +'\x{792C}\x{792D}\x{792E}\x{792F}\x{7930}\x{7931}\x{7933}\x{7934}\x{7935}' . +'\x{7937}\x{7938}\x{7939}\x{793A}\x{793B}\x{793C}\x{793D}\x{793E}\x{793F}' . +'\x{7940}\x{7941}\x{7942}\x{7943}\x{7944}\x{7945}\x{7946}\x{7947}\x{7948}' . +'\x{7949}\x{794A}\x{794B}\x{794C}\x{794D}\x{794E}\x{794F}\x{7950}\x{7951}' . +'\x{7952}\x{7953}\x{7954}\x{7955}\x{7956}\x{7957}\x{7958}\x{795A}\x{795B}' . +'\x{795C}\x{795D}\x{795E}\x{795F}\x{7960}\x{7961}\x{7962}\x{7963}\x{7964}' . +'\x{7965}\x{7966}\x{7967}\x{7968}\x{7969}\x{796A}\x{796B}\x{796D}\x{796F}' . +'\x{7970}\x{7971}\x{7972}\x{7973}\x{7974}\x{7977}\x{7978}\x{7979}\x{797A}' . +'\x{797B}\x{797C}\x{797D}\x{797E}\x{797F}\x{7980}\x{7981}\x{7982}\x{7983}' . +'\x{7984}\x{7985}\x{7988}\x{7989}\x{798A}\x{798B}\x{798C}\x{798D}\x{798E}' . +'\x{798F}\x{7990}\x{7991}\x{7992}\x{7993}\x{7994}\x{7995}\x{7996}\x{7997}' . +'\x{7998}\x{7999}\x{799A}\x{799B}\x{799C}\x{799F}\x{79A0}\x{79A1}\x{79A2}' . +'\x{79A3}\x{79A4}\x{79A5}\x{79A6}\x{79A7}\x{79A8}\x{79AA}\x{79AB}\x{79AC}' . +'\x{79AD}\x{79AE}\x{79AF}\x{79B0}\x{79B1}\x{79B2}\x{79B3}\x{79B4}\x{79B5}' . +'\x{79B6}\x{79B7}\x{79B8}\x{79B9}\x{79BA}\x{79BB}\x{79BD}\x{79BE}\x{79BF}' . +'\x{79C0}\x{79C1}\x{79C2}\x{79C3}\x{79C5}\x{79C6}\x{79C8}\x{79C9}\x{79CA}' . +'\x{79CB}\x{79CD}\x{79CE}\x{79CF}\x{79D0}\x{79D1}\x{79D2}\x{79D3}\x{79D5}' . +'\x{79D6}\x{79D8}\x{79D9}\x{79DA}\x{79DB}\x{79DC}\x{79DD}\x{79DE}\x{79DF}' . +'\x{79E0}\x{79E1}\x{79E2}\x{79E3}\x{79E4}\x{79E5}\x{79E6}\x{79E7}\x{79E8}' . +'\x{79E9}\x{79EA}\x{79EB}\x{79EC}\x{79ED}\x{79EE}\x{79EF}\x{79F0}\x{79F1}' . +'\x{79F2}\x{79F3}\x{79F4}\x{79F5}\x{79F6}\x{79F7}\x{79F8}\x{79F9}\x{79FA}' . +'\x{79FB}\x{79FC}\x{79FD}\x{79FE}\x{79FF}\x{7A00}\x{7A02}\x{7A03}\x{7A04}' . +'\x{7A05}\x{7A06}\x{7A08}\x{7A0A}\x{7A0B}\x{7A0C}\x{7A0D}\x{7A0E}\x{7A0F}' . +'\x{7A10}\x{7A11}\x{7A12}\x{7A13}\x{7A14}\x{7A15}\x{7A16}\x{7A17}\x{7A18}' . +'\x{7A19}\x{7A1A}\x{7A1B}\x{7A1C}\x{7A1D}\x{7A1E}\x{7A1F}\x{7A20}\x{7A21}' . +'\x{7A22}\x{7A23}\x{7A24}\x{7A25}\x{7A26}\x{7A27}\x{7A28}\x{7A29}\x{7A2A}' . +'\x{7A2B}\x{7A2D}\x{7A2E}\x{7A2F}\x{7A30}\x{7A31}\x{7A32}\x{7A33}\x{7A34}' . +'\x{7A35}\x{7A37}\x{7A39}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A41}\x{7A42}\x{7A43}\x{7A44}\x{7A45}\x{7A46}\x{7A47}\x{7A48}\x{7A49}' . +'\x{7A4A}\x{7A4B}\x{7A4C}\x{7A4D}\x{7A4E}\x{7A50}\x{7A51}\x{7A52}\x{7A53}' . +'\x{7A54}\x{7A55}\x{7A56}\x{7A57}\x{7A58}\x{7A59}\x{7A5A}\x{7A5B}\x{7A5C}' . +'\x{7A5D}\x{7A5E}\x{7A5F}\x{7A60}\x{7A61}\x{7A62}\x{7A65}\x{7A66}\x{7A67}' . +'\x{7A68}\x{7A69}\x{7A6B}\x{7A6C}\x{7A6D}\x{7A6E}\x{7A70}\x{7A71}\x{7A72}' . +'\x{7A73}\x{7A74}\x{7A75}\x{7A76}\x{7A77}\x{7A78}\x{7A79}\x{7A7A}\x{7A7B}' . +'\x{7A7C}\x{7A7D}\x{7A7E}\x{7A7F}\x{7A80}\x{7A81}\x{7A83}\x{7A84}\x{7A85}' . +'\x{7A86}\x{7A87}\x{7A88}\x{7A89}\x{7A8A}\x{7A8B}\x{7A8C}\x{7A8D}\x{7A8E}' . +'\x{7A8F}\x{7A90}\x{7A91}\x{7A92}\x{7A93}\x{7A94}\x{7A95}\x{7A96}\x{7A97}' . +'\x{7A98}\x{7A99}\x{7A9C}\x{7A9D}\x{7A9E}\x{7A9F}\x{7AA0}\x{7AA1}\x{7AA2}' . +'\x{7AA3}\x{7AA4}\x{7AA5}\x{7AA6}\x{7AA7}\x{7AA8}\x{7AA9}\x{7AAA}\x{7AAB}' . +'\x{7AAC}\x{7AAD}\x{7AAE}\x{7AAF}\x{7AB0}\x{7AB1}\x{7AB2}\x{7AB3}\x{7AB4}' . +'\x{7AB5}\x{7AB6}\x{7AB7}\x{7AB8}\x{7ABA}\x{7ABE}\x{7ABF}\x{7AC0}\x{7AC1}' . +'\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}\x{7AC9}\x{7ACA}\x{7ACB}\x{7ACC}\x{7ACD}' . +'\x{7ACE}\x{7ACF}\x{7AD0}\x{7AD1}\x{7AD2}\x{7AD3}\x{7AD4}\x{7AD5}\x{7AD6}' . +'\x{7AD8}\x{7AD9}\x{7ADB}\x{7ADC}\x{7ADD}\x{7ADE}\x{7ADF}\x{7AE0}\x{7AE1}' . +'\x{7AE2}\x{7AE3}\x{7AE4}\x{7AE5}\x{7AE6}\x{7AE7}\x{7AE8}\x{7AEA}\x{7AEB}' . +'\x{7AEC}\x{7AED}\x{7AEE}\x{7AEF}\x{7AF0}\x{7AF1}\x{7AF2}\x{7AF3}\x{7AF4}' . +'\x{7AF6}\x{7AF7}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFB}\x{7AFD}\x{7AFE}\x{7AFF}' . +'\x{7B00}\x{7B01}\x{7B02}\x{7B03}\x{7B04}\x{7B05}\x{7B06}\x{7B08}\x{7B09}' . +'\x{7B0A}\x{7B0B}\x{7B0C}\x{7B0D}\x{7B0E}\x{7B0F}\x{7B10}\x{7B11}\x{7B12}' . +'\x{7B13}\x{7B14}\x{7B15}\x{7B16}\x{7B17}\x{7B18}\x{7B19}\x{7B1A}\x{7B1B}' . +'\x{7B1C}\x{7B1D}\x{7B1E}\x{7B20}\x{7B21}\x{7B22}\x{7B23}\x{7B24}\x{7B25}' . +'\x{7B26}\x{7B28}\x{7B2A}\x{7B2B}\x{7B2C}\x{7B2D}\x{7B2E}\x{7B2F}\x{7B30}' . +'\x{7B31}\x{7B32}\x{7B33}\x{7B34}\x{7B35}\x{7B36}\x{7B37}\x{7B38}\x{7B39}' . +'\x{7B3A}\x{7B3B}\x{7B3C}\x{7B3D}\x{7B3E}\x{7B3F}\x{7B40}\x{7B41}\x{7B43}' . +'\x{7B44}\x{7B45}\x{7B46}\x{7B47}\x{7B48}\x{7B49}\x{7B4A}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4E}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B55}\x{7B56}' . +'\x{7B57}\x{7B58}\x{7B59}\x{7B5A}\x{7B5B}\x{7B5C}\x{7B5D}\x{7B5E}\x{7B5F}' . +'\x{7B60}\x{7B61}\x{7B62}\x{7B63}\x{7B64}\x{7B65}\x{7B66}\x{7B67}\x{7B68}' . +'\x{7B69}\x{7B6A}\x{7B6B}\x{7B6C}\x{7B6D}\x{7B6E}\x{7B70}\x{7B71}\x{7B72}' . +'\x{7B73}\x{7B74}\x{7B75}\x{7B76}\x{7B77}\x{7B78}\x{7B79}\x{7B7B}\x{7B7C}' . +'\x{7B7D}\x{7B7E}\x{7B7F}\x{7B80}\x{7B81}\x{7B82}\x{7B83}\x{7B84}\x{7B85}' . +'\x{7B87}\x{7B88}\x{7B89}\x{7B8A}\x{7B8B}\x{7B8C}\x{7B8D}\x{7B8E}\x{7B8F}' . +'\x{7B90}\x{7B91}\x{7B93}\x{7B94}\x{7B95}\x{7B96}\x{7B97}\x{7B98}\x{7B99}' . +'\x{7B9A}\x{7B9B}\x{7B9C}\x{7B9D}\x{7B9E}\x{7B9F}\x{7BA0}\x{7BA1}\x{7BA2}' . +'\x{7BA4}\x{7BA6}\x{7BA7}\x{7BA8}\x{7BA9}\x{7BAA}\x{7BAB}\x{7BAC}\x{7BAD}' . +'\x{7BAE}\x{7BAF}\x{7BB1}\x{7BB3}\x{7BB4}\x{7BB5}\x{7BB6}\x{7BB7}\x{7BB8}' . +'\x{7BB9}\x{7BBA}\x{7BBB}\x{7BBC}\x{7BBD}\x{7BBE}\x{7BBF}\x{7BC0}\x{7BC1}' . +'\x{7BC2}\x{7BC3}\x{7BC4}\x{7BC5}\x{7BC6}\x{7BC7}\x{7BC8}\x{7BC9}\x{7BCA}' . +'\x{7BCB}\x{7BCC}\x{7BCD}\x{7BCE}\x{7BD0}\x{7BD1}\x{7BD2}\x{7BD3}\x{7BD4}' . +'\x{7BD5}\x{7BD6}\x{7BD7}\x{7BD8}\x{7BD9}\x{7BDA}\x{7BDB}\x{7BDC}\x{7BDD}' . +'\x{7BDE}\x{7BDF}\x{7BE0}\x{7BE1}\x{7BE2}\x{7BE3}\x{7BE4}\x{7BE5}\x{7BE6}' . +'\x{7BE7}\x{7BE8}\x{7BE9}\x{7BEA}\x{7BEB}\x{7BEC}\x{7BED}\x{7BEE}\x{7BEF}' . +'\x{7BF0}\x{7BF1}\x{7BF2}\x{7BF3}\x{7BF4}\x{7BF5}\x{7BF6}\x{7BF7}\x{7BF8}' . +'\x{7BF9}\x{7BFB}\x{7BFC}\x{7BFD}\x{7BFE}\x{7BFF}\x{7C00}\x{7C01}\x{7C02}' . +'\x{7C03}\x{7C04}\x{7C05}\x{7C06}\x{7C07}\x{7C08}\x{7C09}\x{7C0A}\x{7C0B}' . +'\x{7C0C}\x{7C0D}\x{7C0E}\x{7C0F}\x{7C10}\x{7C11}\x{7C12}\x{7C13}\x{7C15}' . +'\x{7C16}\x{7C17}\x{7C18}\x{7C19}\x{7C1A}\x{7C1C}\x{7C1D}\x{7C1E}\x{7C1F}' . +'\x{7C20}\x{7C21}\x{7C22}\x{7C23}\x{7C24}\x{7C25}\x{7C26}\x{7C27}\x{7C28}' . +'\x{7C29}\x{7C2A}\x{7C2B}\x{7C2C}\x{7C2D}\x{7C30}\x{7C31}\x{7C32}\x{7C33}' . +'\x{7C34}\x{7C35}\x{7C36}\x{7C37}\x{7C38}\x{7C39}\x{7C3A}\x{7C3B}\x{7C3C}' . +'\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C41}\x{7C42}\x{7C43}\x{7C44}\x{7C45}' . +'\x{7C46}\x{7C47}\x{7C48}\x{7C49}\x{7C4A}\x{7C4B}\x{7C4C}\x{7C4D}\x{7C4E}' . +'\x{7C50}\x{7C51}\x{7C53}\x{7C54}\x{7C56}\x{7C57}\x{7C58}\x{7C59}\x{7C5A}' . +'\x{7C5B}\x{7C5C}\x{7C5E}\x{7C5F}\x{7C60}\x{7C61}\x{7C62}\x{7C63}\x{7C64}' . +'\x{7C65}\x{7C66}\x{7C67}\x{7C68}\x{7C69}\x{7C6A}\x{7C6B}\x{7C6C}\x{7C6D}' . +'\x{7C6E}\x{7C6F}\x{7C70}\x{7C71}\x{7C72}\x{7C73}\x{7C74}\x{7C75}\x{7C77}' . +'\x{7C78}\x{7C79}\x{7C7A}\x{7C7B}\x{7C7C}\x{7C7D}\x{7C7E}\x{7C7F}\x{7C80}' . +'\x{7C81}\x{7C82}\x{7C84}\x{7C85}\x{7C86}\x{7C88}\x{7C89}\x{7C8A}\x{7C8B}' . +'\x{7C8C}\x{7C8D}\x{7C8E}\x{7C8F}\x{7C90}\x{7C91}\x{7C92}\x{7C94}\x{7C95}' . +'\x{7C96}\x{7C97}\x{7C98}\x{7C99}\x{7C9B}\x{7C9C}\x{7C9D}\x{7C9E}\x{7C9F}' . +'\x{7CA0}\x{7CA1}\x{7CA2}\x{7CA3}\x{7CA4}\x{7CA5}\x{7CA6}\x{7CA7}\x{7CA8}' . +'\x{7CA9}\x{7CAA}\x{7CAD}\x{7CAE}\x{7CAF}\x{7CB0}\x{7CB1}\x{7CB2}\x{7CB3}' . +'\x{7CB4}\x{7CB5}\x{7CB6}\x{7CB7}\x{7CB8}\x{7CB9}\x{7CBA}\x{7CBB}\x{7CBC}' . +'\x{7CBD}\x{7CBE}\x{7CBF}\x{7CC0}\x{7CC1}\x{7CC2}\x{7CC3}\x{7CC4}\x{7CC5}' . +'\x{7CC6}\x{7CC7}\x{7CC8}\x{7CC9}\x{7CCA}\x{7CCB}\x{7CCC}\x{7CCD}\x{7CCE}' . +'\x{7CCF}\x{7CD0}\x{7CD1}\x{7CD2}\x{7CD4}\x{7CD5}\x{7CD6}\x{7CD7}\x{7CD8}' . +'\x{7CD9}\x{7CDC}\x{7CDD}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}' . +'\x{7CE8}\x{7CE9}\x{7CEA}\x{7CEB}\x{7CEC}\x{7CED}\x{7CEE}\x{7CEF}\x{7CF0}' . +'\x{7CF1}\x{7CF2}\x{7CF3}\x{7CF4}\x{7CF5}\x{7CF6}\x{7CF7}\x{7CF8}\x{7CF9}' . +'\x{7CFA}\x{7CFB}\x{7CFD}\x{7CFE}\x{7D00}\x{7D01}\x{7D02}\x{7D03}\x{7D04}' . +'\x{7D05}\x{7D06}\x{7D07}\x{7D08}\x{7D09}\x{7D0A}\x{7D0B}\x{7D0C}\x{7D0D}' . +'\x{7D0E}\x{7D0F}\x{7D10}\x{7D11}\x{7D12}\x{7D13}\x{7D14}\x{7D15}\x{7D16}' . +'\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D1D}\x{7D1E}\x{7D1F}' . +'\x{7D20}\x{7D21}\x{7D22}\x{7D24}\x{7D25}\x{7D26}\x{7D27}\x{7D28}\x{7D29}' . +'\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D31}\x{7D32}\x{7D33}\x{7D34}' . +'\x{7D35}\x{7D36}\x{7D37}\x{7D38}\x{7D39}\x{7D3A}\x{7D3B}\x{7D3C}\x{7D3D}' . +'\x{7D3E}\x{7D3F}\x{7D40}\x{7D41}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}' . +'\x{7D47}\x{7D49}\x{7D4A}\x{7D4B}\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D51}' . +'\x{7D52}\x{7D53}\x{7D54}\x{7D55}\x{7D56}\x{7D57}\x{7D58}\x{7D59}\x{7D5B}' . +'\x{7D5C}\x{7D5D}\x{7D5E}\x{7D5F}\x{7D60}\x{7D61}\x{7D62}\x{7D63}\x{7D65}' . +'\x{7D66}\x{7D67}\x{7D68}\x{7D69}\x{7D6A}\x{7D6B}\x{7D6C}\x{7D6D}\x{7D6E}' . +'\x{7D6F}\x{7D70}\x{7D71}\x{7D72}\x{7D73}\x{7D74}\x{7D75}\x{7D76}\x{7D77}' . +'\x{7D79}\x{7D7A}\x{7D7B}\x{7D7C}\x{7D7D}\x{7D7E}\x{7D7F}\x{7D80}\x{7D81}' . +'\x{7D83}\x{7D84}\x{7D85}\x{7D86}\x{7D87}\x{7D88}\x{7D89}\x{7D8A}\x{7D8B}' . +'\x{7D8C}\x{7D8D}\x{7D8E}\x{7D8F}\x{7D90}\x{7D91}\x{7D92}\x{7D93}\x{7D94}' . +'\x{7D96}\x{7D97}\x{7D99}\x{7D9B}\x{7D9C}\x{7D9D}\x{7D9E}\x{7D9F}\x{7DA0}' . +'\x{7DA1}\x{7DA2}\x{7DA3}\x{7DA5}\x{7DA6}\x{7DA7}\x{7DA9}\x{7DAA}\x{7DAB}' . +'\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}\x{7DB1}\x{7DB2}\x{7DB3}\x{7DB4}' . +'\x{7DB5}\x{7DB6}\x{7DB7}\x{7DB8}\x{7DB9}\x{7DBA}\x{7DBB}\x{7DBC}\x{7DBD}' . +'\x{7DBE}\x{7DBF}\x{7DC0}\x{7DC1}\x{7DC2}\x{7DC3}\x{7DC4}\x{7DC5}\x{7DC6}' . +'\x{7DC7}\x{7DC8}\x{7DC9}\x{7DCA}\x{7DCB}\x{7DCC}\x{7DCE}\x{7DCF}\x{7DD0}' . +'\x{7DD1}\x{7DD2}\x{7DD4}\x{7DD5}\x{7DD6}\x{7DD7}\x{7DD8}\x{7DD9}\x{7DDA}' . +'\x{7DDB}\x{7DDD}\x{7DDE}\x{7DDF}\x{7DE0}\x{7DE1}\x{7DE2}\x{7DE3}\x{7DE6}' . +'\x{7DE7}\x{7DE8}\x{7DE9}\x{7DEA}\x{7DEC}\x{7DED}\x{7DEE}\x{7DEF}\x{7DF0}' . +'\x{7DF1}\x{7DF2}\x{7DF3}\x{7DF4}\x{7DF5}\x{7DF6}\x{7DF7}\x{7DF8}\x{7DF9}' . +'\x{7DFA}\x{7DFB}\x{7DFC}\x{7E00}\x{7E01}\x{7E02}\x{7E03}\x{7E04}\x{7E05}' . +'\x{7E06}\x{7E07}\x{7E08}\x{7E09}\x{7E0A}\x{7E0B}\x{7E0C}\x{7E0D}\x{7E0E}' . +'\x{7E0F}\x{7E10}\x{7E11}\x{7E12}\x{7E13}\x{7E14}\x{7E15}\x{7E16}\x{7E17}' . +'\x{7E19}\x{7E1A}\x{7E1B}\x{7E1C}\x{7E1D}\x{7E1E}\x{7E1F}\x{7E20}\x{7E21}' . +'\x{7E22}\x{7E23}\x{7E24}\x{7E25}\x{7E26}\x{7E27}\x{7E28}\x{7E29}\x{7E2A}' . +'\x{7E2B}\x{7E2C}\x{7E2D}\x{7E2E}\x{7E2F}\x{7E30}\x{7E31}\x{7E32}\x{7E33}' . +'\x{7E34}\x{7E35}\x{7E36}\x{7E37}\x{7E38}\x{7E39}\x{7E3A}\x{7E3B}\x{7E3C}' . +'\x{7E3D}\x{7E3E}\x{7E3F}\x{7E40}\x{7E41}\x{7E42}\x{7E43}\x{7E44}\x{7E45}' . +'\x{7E46}\x{7E47}\x{7E48}\x{7E49}\x{7E4C}\x{7E4D}\x{7E4E}\x{7E4F}\x{7E50}' . +'\x{7E51}\x{7E52}\x{7E53}\x{7E54}\x{7E55}\x{7E56}\x{7E57}\x{7E58}\x{7E59}' . +'\x{7E5A}\x{7E5C}\x{7E5D}\x{7E5E}\x{7E5F}\x{7E60}\x{7E61}\x{7E62}\x{7E63}' . +'\x{7E65}\x{7E66}\x{7E67}\x{7E68}\x{7E69}\x{7E6A}\x{7E6B}\x{7E6C}\x{7E6D}' . +'\x{7E6E}\x{7E6F}\x{7E70}\x{7E71}\x{7E72}\x{7E73}\x{7E74}\x{7E75}\x{7E76}' . +'\x{7E77}\x{7E78}\x{7E79}\x{7E7A}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7E}\x{7E7F}' . +'\x{7E80}\x{7E81}\x{7E82}\x{7E83}\x{7E84}\x{7E85}\x{7E86}\x{7E87}\x{7E88}' . +'\x{7E89}\x{7E8A}\x{7E8B}\x{7E8C}\x{7E8D}\x{7E8E}\x{7E8F}\x{7E90}\x{7E91}' . +'\x{7E92}\x{7E93}\x{7E94}\x{7E95}\x{7E96}\x{7E97}\x{7E98}\x{7E99}\x{7E9A}' . +'\x{7E9B}\x{7E9C}\x{7E9E}\x{7E9F}\x{7EA0}\x{7EA1}\x{7EA2}\x{7EA3}\x{7EA4}' . +'\x{7EA5}\x{7EA6}\x{7EA7}\x{7EA8}\x{7EA9}\x{7EAA}\x{7EAB}\x{7EAC}\x{7EAD}' . +'\x{7EAE}\x{7EAF}\x{7EB0}\x{7EB1}\x{7EB2}\x{7EB3}\x{7EB4}\x{7EB5}\x{7EB6}' . +'\x{7EB7}\x{7EB8}\x{7EB9}\x{7EBA}\x{7EBB}\x{7EBC}\x{7EBD}\x{7EBE}\x{7EBF}' . +'\x{7EC0}\x{7EC1}\x{7EC2}\x{7EC3}\x{7EC4}\x{7EC5}\x{7EC6}\x{7EC7}\x{7EC8}' . +'\x{7EC9}\x{7ECA}\x{7ECB}\x{7ECC}\x{7ECD}\x{7ECE}\x{7ECF}\x{7ED0}\x{7ED1}' . +'\x{7ED2}\x{7ED3}\x{7ED4}\x{7ED5}\x{7ED6}\x{7ED7}\x{7ED8}\x{7ED9}\x{7EDA}' . +'\x{7EDB}\x{7EDC}\x{7EDD}\x{7EDE}\x{7EDF}\x{7EE0}\x{7EE1}\x{7EE2}\x{7EE3}' . +'\x{7EE4}\x{7EE5}\x{7EE6}\x{7EE7}\x{7EE8}\x{7EE9}\x{7EEA}\x{7EEB}\x{7EEC}' . +'\x{7EED}\x{7EEE}\x{7EEF}\x{7EF0}\x{7EF1}\x{7EF2}\x{7EF3}\x{7EF4}\x{7EF5}' . +'\x{7EF6}\x{7EF7}\x{7EF8}\x{7EF9}\x{7EFA}\x{7EFB}\x{7EFC}\x{7EFD}\x{7EFE}' . +'\x{7EFF}\x{7F00}\x{7F01}\x{7F02}\x{7F03}\x{7F04}\x{7F05}\x{7F06}\x{7F07}' . +'\x{7F08}\x{7F09}\x{7F0A}\x{7F0B}\x{7F0C}\x{7F0D}\x{7F0E}\x{7F0F}\x{7F10}' . +'\x{7F11}\x{7F12}\x{7F13}\x{7F14}\x{7F15}\x{7F16}\x{7F17}\x{7F18}\x{7F19}' . +'\x{7F1A}\x{7F1B}\x{7F1C}\x{7F1D}\x{7F1E}\x{7F1F}\x{7F20}\x{7F21}\x{7F22}' . +'\x{7F23}\x{7F24}\x{7F25}\x{7F26}\x{7F27}\x{7F28}\x{7F29}\x{7F2A}\x{7F2B}' . +'\x{7F2C}\x{7F2D}\x{7F2E}\x{7F2F}\x{7F30}\x{7F31}\x{7F32}\x{7F33}\x{7F34}' . +'\x{7F35}\x{7F36}\x{7F37}\x{7F38}\x{7F39}\x{7F3A}\x{7F3D}\x{7F3E}\x{7F3F}' . +'\x{7F40}\x{7F42}\x{7F43}\x{7F44}\x{7F45}\x{7F47}\x{7F48}\x{7F49}\x{7F4A}' . +'\x{7F4B}\x{7F4C}\x{7F4D}\x{7F4E}\x{7F4F}\x{7F50}\x{7F51}\x{7F52}\x{7F53}' . +'\x{7F54}\x{7F55}\x{7F56}\x{7F57}\x{7F58}\x{7F5A}\x{7F5B}\x{7F5C}\x{7F5D}' . +'\x{7F5E}\x{7F5F}\x{7F60}\x{7F61}\x{7F62}\x{7F63}\x{7F64}\x{7F65}\x{7F66}' . +'\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6C}\x{7F6D}\x{7F6E}\x{7F6F}' . +'\x{7F70}\x{7F71}\x{7F72}\x{7F73}\x{7F74}\x{7F75}\x{7F76}\x{7F77}\x{7F78}' . +'\x{7F79}\x{7F7A}\x{7F7B}\x{7F7C}\x{7F7D}\x{7F7E}\x{7F7F}\x{7F80}\x{7F81}' . +'\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}\x{7F88}\x{7F89}\x{7F8A}\x{7F8B}' . +'\x{7F8C}\x{7F8D}\x{7F8E}\x{7F8F}\x{7F91}\x{7F92}\x{7F93}\x{7F94}\x{7F95}' . +'\x{7F96}\x{7F98}\x{7F9A}\x{7F9B}\x{7F9C}\x{7F9D}\x{7F9E}\x{7F9F}\x{7FA0}' . +'\x{7FA1}\x{7FA2}\x{7FA3}\x{7FA4}\x{7FA5}\x{7FA6}\x{7FA7}\x{7FA8}\x{7FA9}' . +'\x{7FAA}\x{7FAB}\x{7FAC}\x{7FAD}\x{7FAE}\x{7FAF}\x{7FB0}\x{7FB1}\x{7FB2}' . +'\x{7FB3}\x{7FB5}\x{7FB6}\x{7FB7}\x{7FB8}\x{7FB9}\x{7FBA}\x{7FBB}\x{7FBC}' . +'\x{7FBD}\x{7FBE}\x{7FBF}\x{7FC0}\x{7FC1}\x{7FC2}\x{7FC3}\x{7FC4}\x{7FC5}' . +'\x{7FC6}\x{7FC7}\x{7FC8}\x{7FC9}\x{7FCA}\x{7FCB}\x{7FCC}\x{7FCD}\x{7FCE}' . +'\x{7FCF}\x{7FD0}\x{7FD1}\x{7FD2}\x{7FD3}\x{7FD4}\x{7FD5}\x{7FD7}\x{7FD8}' . +'\x{7FD9}\x{7FDA}\x{7FDB}\x{7FDC}\x{7FDE}\x{7FDF}\x{7FE0}\x{7FE1}\x{7FE2}' . +'\x{7FE3}\x{7FE5}\x{7FE6}\x{7FE7}\x{7FE8}\x{7FE9}\x{7FEA}\x{7FEB}\x{7FEC}' . +'\x{7FED}\x{7FEE}\x{7FEF}\x{7FF0}\x{7FF1}\x{7FF2}\x{7FF3}\x{7FF4}\x{7FF5}' . +'\x{7FF6}\x{7FF7}\x{7FF8}\x{7FF9}\x{7FFA}\x{7FFB}\x{7FFC}\x{7FFD}\x{7FFE}' . +'\x{7FFF}\x{8000}\x{8001}\x{8002}\x{8003}\x{8004}\x{8005}\x{8006}\x{8007}' . +'\x{8008}\x{8009}\x{800B}\x{800C}\x{800D}\x{800E}\x{800F}\x{8010}\x{8011}' . +'\x{8012}\x{8013}\x{8014}\x{8015}\x{8016}\x{8017}\x{8018}\x{8019}\x{801A}' . +'\x{801B}\x{801C}\x{801D}\x{801E}\x{801F}\x{8020}\x{8021}\x{8022}\x{8023}' . +'\x{8024}\x{8025}\x{8026}\x{8027}\x{8028}\x{8029}\x{802A}\x{802B}\x{802C}' . +'\x{802D}\x{802E}\x{8030}\x{8031}\x{8032}\x{8033}\x{8034}\x{8035}\x{8036}' . +'\x{8037}\x{8038}\x{8039}\x{803A}\x{803B}\x{803D}\x{803E}\x{803F}\x{8041}' . +'\x{8042}\x{8043}\x{8044}\x{8045}\x{8046}\x{8047}\x{8048}\x{8049}\x{804A}' . +'\x{804B}\x{804C}\x{804D}\x{804E}\x{804F}\x{8050}\x{8051}\x{8052}\x{8053}' . +'\x{8054}\x{8055}\x{8056}\x{8057}\x{8058}\x{8059}\x{805A}\x{805B}\x{805C}' . +'\x{805D}\x{805E}\x{805F}\x{8060}\x{8061}\x{8062}\x{8063}\x{8064}\x{8065}' . +'\x{8067}\x{8068}\x{8069}\x{806A}\x{806B}\x{806C}\x{806D}\x{806E}\x{806F}' . +'\x{8070}\x{8071}\x{8072}\x{8073}\x{8074}\x{8075}\x{8076}\x{8077}\x{8078}' . +'\x{8079}\x{807A}\x{807B}\x{807C}\x{807D}\x{807E}\x{807F}\x{8080}\x{8081}' . +'\x{8082}\x{8083}\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808A}\x{808B}' . +'\x{808C}\x{808D}\x{808F}\x{8090}\x{8091}\x{8092}\x{8093}\x{8095}\x{8096}' . +'\x{8097}\x{8098}\x{8099}\x{809A}\x{809B}\x{809C}\x{809D}\x{809E}\x{809F}' . +'\x{80A0}\x{80A1}\x{80A2}\x{80A3}\x{80A4}\x{80A5}\x{80A9}\x{80AA}\x{80AB}' . +'\x{80AD}\x{80AE}\x{80AF}\x{80B0}\x{80B1}\x{80B2}\x{80B4}\x{80B5}\x{80B6}' . +'\x{80B7}\x{80B8}\x{80BA}\x{80BB}\x{80BC}\x{80BD}\x{80BE}\x{80BF}\x{80C0}' . +'\x{80C1}\x{80C2}\x{80C3}\x{80C4}\x{80C5}\x{80C6}\x{80C7}\x{80C8}\x{80C9}' . +'\x{80CA}\x{80CB}\x{80CC}\x{80CD}\x{80CE}\x{80CF}\x{80D0}\x{80D1}\x{80D2}' . +'\x{80D3}\x{80D4}\x{80D5}\x{80D6}\x{80D7}\x{80D8}\x{80D9}\x{80DA}\x{80DB}' . +'\x{80DC}\x{80DD}\x{80DE}\x{80E0}\x{80E1}\x{80E2}\x{80E3}\x{80E4}\x{80E5}' . +'\x{80E6}\x{80E7}\x{80E8}\x{80E9}\x{80EA}\x{80EB}\x{80EC}\x{80ED}\x{80EE}' . +'\x{80EF}\x{80F0}\x{80F1}\x{80F2}\x{80F3}\x{80F4}\x{80F5}\x{80F6}\x{80F7}' . +'\x{80F8}\x{80F9}\x{80FA}\x{80FB}\x{80FC}\x{80FD}\x{80FE}\x{80FF}\x{8100}' . +'\x{8101}\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{810B}' . +'\x{810C}\x{810D}\x{810E}\x{810F}\x{8110}\x{8111}\x{8112}\x{8113}\x{8114}' . +'\x{8115}\x{8116}\x{8118}\x{8119}\x{811A}\x{811B}\x{811C}\x{811D}\x{811E}' . +'\x{811F}\x{8120}\x{8121}\x{8122}\x{8123}\x{8124}\x{8125}\x{8126}\x{8127}' . +'\x{8128}\x{8129}\x{812A}\x{812B}\x{812C}\x{812D}\x{812E}\x{812F}\x{8130}' . +'\x{8131}\x{8132}\x{8136}\x{8137}\x{8138}\x{8139}\x{813A}\x{813B}\x{813C}' . +'\x{813D}\x{813E}\x{813F}\x{8140}\x{8141}\x{8142}\x{8143}\x{8144}\x{8145}' . +'\x{8146}\x{8147}\x{8148}\x{8149}\x{814A}\x{814B}\x{814C}\x{814D}\x{814E}' . +'\x{814F}\x{8150}\x{8151}\x{8152}\x{8153}\x{8154}\x{8155}\x{8156}\x{8157}' . +'\x{8158}\x{8159}\x{815A}\x{815B}\x{815C}\x{815D}\x{815E}\x{8160}\x{8161}' . +'\x{8162}\x{8163}\x{8164}\x{8165}\x{8166}\x{8167}\x{8168}\x{8169}\x{816A}' . +'\x{816B}\x{816C}\x{816D}\x{816E}\x{816F}\x{8170}\x{8171}\x{8172}\x{8173}' . +'\x{8174}\x{8175}\x{8176}\x{8177}\x{8178}\x{8179}\x{817A}\x{817B}\x{817C}' . +'\x{817D}\x{817E}\x{817F}\x{8180}\x{8181}\x{8182}\x{8183}\x{8185}\x{8186}' . +'\x{8187}\x{8188}\x{8189}\x{818A}\x{818B}\x{818C}\x{818D}\x{818E}\x{818F}' . +'\x{8191}\x{8192}\x{8193}\x{8194}\x{8195}\x{8197}\x{8198}\x{8199}\x{819A}' . +'\x{819B}\x{819C}\x{819D}\x{819E}\x{819F}\x{81A0}\x{81A1}\x{81A2}\x{81A3}' . +'\x{81A4}\x{81A5}\x{81A6}\x{81A7}\x{81A8}\x{81A9}\x{81AA}\x{81AB}\x{81AC}' . +'\x{81AD}\x{81AE}\x{81AF}\x{81B0}\x{81B1}\x{81B2}\x{81B3}\x{81B4}\x{81B5}' . +'\x{81B6}\x{81B7}\x{81B8}\x{81B9}\x{81BA}\x{81BB}\x{81BC}\x{81BD}\x{81BE}' . +'\x{81BF}\x{81C0}\x{81C1}\x{81C2}\x{81C3}\x{81C4}\x{81C5}\x{81C6}\x{81C7}' . +'\x{81C8}\x{81C9}\x{81CA}\x{81CC}\x{81CD}\x{81CE}\x{81CF}\x{81D0}\x{81D1}' . +'\x{81D2}\x{81D4}\x{81D5}\x{81D6}\x{81D7}\x{81D8}\x{81D9}\x{81DA}\x{81DB}' . +'\x{81DC}\x{81DD}\x{81DE}\x{81DF}\x{81E0}\x{81E1}\x{81E2}\x{81E3}\x{81E5}' . +'\x{81E6}\x{81E7}\x{81E8}\x{81E9}\x{81EA}\x{81EB}\x{81EC}\x{81ED}\x{81EE}' . +'\x{81F1}\x{81F2}\x{81F3}\x{81F4}\x{81F5}\x{81F6}\x{81F7}\x{81F8}\x{81F9}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FD}\x{81FE}\x{81FF}\x{8200}\x{8201}\x{8202}' . +'\x{8203}\x{8204}\x{8205}\x{8206}\x{8207}\x{8208}\x{8209}\x{820A}\x{820B}' . +'\x{820C}\x{820D}\x{820E}\x{820F}\x{8210}\x{8211}\x{8212}\x{8214}\x{8215}' . +'\x{8216}\x{8218}\x{8219}\x{821A}\x{821B}\x{821C}\x{821D}\x{821E}\x{821F}' . +'\x{8220}\x{8221}\x{8222}\x{8223}\x{8225}\x{8226}\x{8227}\x{8228}\x{8229}' . +'\x{822A}\x{822B}\x{822C}\x{822D}\x{822F}\x{8230}\x{8231}\x{8232}\x{8233}' . +'\x{8234}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{823A}\x{823B}\x{823C}' . +'\x{823D}\x{823E}\x{823F}\x{8240}\x{8242}\x{8243}\x{8244}\x{8245}\x{8246}' . +'\x{8247}\x{8248}\x{8249}\x{824A}\x{824B}\x{824C}\x{824D}\x{824E}\x{824F}' . +'\x{8250}\x{8251}\x{8252}\x{8253}\x{8254}\x{8255}\x{8256}\x{8257}\x{8258}' . +'\x{8259}\x{825A}\x{825B}\x{825C}\x{825D}\x{825E}\x{825F}\x{8260}\x{8261}' . +'\x{8263}\x{8264}\x{8266}\x{8267}\x{8268}\x{8269}\x{826A}\x{826B}\x{826C}' . +'\x{826D}\x{826E}\x{826F}\x{8270}\x{8271}\x{8272}\x{8273}\x{8274}\x{8275}' . +'\x{8276}\x{8277}\x{8278}\x{8279}\x{827A}\x{827B}\x{827C}\x{827D}\x{827E}' . +'\x{827F}\x{8280}\x{8281}\x{8282}\x{8283}\x{8284}\x{8285}\x{8286}\x{8287}' . +'\x{8288}\x{8289}\x{828A}\x{828B}\x{828D}\x{828E}\x{828F}\x{8290}\x{8291}' . +'\x{8292}\x{8293}\x{8294}\x{8295}\x{8296}\x{8297}\x{8298}\x{8299}\x{829A}' . +'\x{829B}\x{829C}\x{829D}\x{829E}\x{829F}\x{82A0}\x{82A1}\x{82A2}\x{82A3}' . +'\x{82A4}\x{82A5}\x{82A6}\x{82A7}\x{82A8}\x{82A9}\x{82AA}\x{82AB}\x{82AC}' . +'\x{82AD}\x{82AE}\x{82AF}\x{82B0}\x{82B1}\x{82B3}\x{82B4}\x{82B5}\x{82B6}' . +'\x{82B7}\x{82B8}\x{82B9}\x{82BA}\x{82BB}\x{82BC}\x{82BD}\x{82BE}\x{82BF}' . +'\x{82C0}\x{82C1}\x{82C2}\x{82C3}\x{82C4}\x{82C5}\x{82C6}\x{82C7}\x{82C8}' . +'\x{82C9}\x{82CA}\x{82CB}\x{82CC}\x{82CD}\x{82CE}\x{82CF}\x{82D0}\x{82D1}' . +'\x{82D2}\x{82D3}\x{82D4}\x{82D5}\x{82D6}\x{82D7}\x{82D8}\x{82D9}\x{82DA}' . +'\x{82DB}\x{82DC}\x{82DD}\x{82DE}\x{82DF}\x{82E0}\x{82E1}\x{82E3}\x{82E4}' . +'\x{82E5}\x{82E6}\x{82E7}\x{82E8}\x{82E9}\x{82EA}\x{82EB}\x{82EC}\x{82ED}' . +'\x{82EE}\x{82EF}\x{82F0}\x{82F1}\x{82F2}\x{82F3}\x{82F4}\x{82F5}\x{82F6}' . +'\x{82F7}\x{82F8}\x{82F9}\x{82FA}\x{82FB}\x{82FD}\x{82FE}\x{82FF}\x{8300}' . +'\x{8301}\x{8302}\x{8303}\x{8304}\x{8305}\x{8306}\x{8307}\x{8308}\x{8309}' . +'\x{830B}\x{830C}\x{830D}\x{830E}\x{830F}\x{8311}\x{8312}\x{8313}\x{8314}' . +'\x{8315}\x{8316}\x{8317}\x{8318}\x{8319}\x{831A}\x{831B}\x{831C}\x{831D}' . +'\x{831E}\x{831F}\x{8320}\x{8321}\x{8322}\x{8323}\x{8324}\x{8325}\x{8326}' . +'\x{8327}\x{8328}\x{8329}\x{832A}\x{832B}\x{832C}\x{832D}\x{832E}\x{832F}' . +'\x{8331}\x{8332}\x{8333}\x{8334}\x{8335}\x{8336}\x{8337}\x{8338}\x{8339}' . +'\x{833A}\x{833B}\x{833C}\x{833D}\x{833E}\x{833F}\x{8340}\x{8341}\x{8342}' . +'\x{8343}\x{8344}\x{8345}\x{8346}\x{8347}\x{8348}\x{8349}\x{834A}\x{834B}' . +'\x{834C}\x{834D}\x{834E}\x{834F}\x{8350}\x{8351}\x{8352}\x{8353}\x{8354}' . +'\x{8356}\x{8357}\x{8358}\x{8359}\x{835A}\x{835B}\x{835C}\x{835D}\x{835E}' . +'\x{835F}\x{8360}\x{8361}\x{8362}\x{8363}\x{8364}\x{8365}\x{8366}\x{8367}' . +'\x{8368}\x{8369}\x{836A}\x{836B}\x{836C}\x{836D}\x{836E}\x{836F}\x{8370}' . +'\x{8371}\x{8372}\x{8373}\x{8374}\x{8375}\x{8376}\x{8377}\x{8378}\x{8379}' . +'\x{837A}\x{837B}\x{837C}\x{837D}\x{837E}\x{837F}\x{8380}\x{8381}\x{8382}' . +'\x{8383}\x{8384}\x{8385}\x{8386}\x{8387}\x{8388}\x{8389}\x{838A}\x{838B}' . +'\x{838C}\x{838D}\x{838E}\x{838F}\x{8390}\x{8391}\x{8392}\x{8393}\x{8394}' . +'\x{8395}\x{8396}\x{8397}\x{8398}\x{8399}\x{839A}\x{839B}\x{839C}\x{839D}' . +'\x{839E}\x{83A0}\x{83A1}\x{83A2}\x{83A3}\x{83A4}\x{83A5}\x{83A6}\x{83A7}' . +'\x{83A8}\x{83A9}\x{83AA}\x{83AB}\x{83AC}\x{83AD}\x{83AE}\x{83AF}\x{83B0}' . +'\x{83B1}\x{83B2}\x{83B3}\x{83B4}\x{83B6}\x{83B7}\x{83B8}\x{83B9}\x{83BA}' . +'\x{83BB}\x{83BC}\x{83BD}\x{83BF}\x{83C0}\x{83C1}\x{83C2}\x{83C3}\x{83C4}' . +'\x{83C5}\x{83C6}\x{83C7}\x{83C8}\x{83C9}\x{83CA}\x{83CB}\x{83CC}\x{83CD}' . +'\x{83CE}\x{83CF}\x{83D0}\x{83D1}\x{83D2}\x{83D3}\x{83D4}\x{83D5}\x{83D6}' . +'\x{83D7}\x{83D8}\x{83D9}\x{83DA}\x{83DB}\x{83DC}\x{83DD}\x{83DE}\x{83DF}' . +'\x{83E0}\x{83E1}\x{83E2}\x{83E3}\x{83E4}\x{83E5}\x{83E7}\x{83E8}\x{83E9}' . +'\x{83EA}\x{83EB}\x{83EC}\x{83EE}\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F3}' . +'\x{83F4}\x{83F5}\x{83F6}\x{83F7}\x{83F8}\x{83F9}\x{83FA}\x{83FB}\x{83FC}' . +'\x{83FD}\x{83FE}\x{83FF}\x{8400}\x{8401}\x{8402}\x{8403}\x{8404}\x{8405}' . +'\x{8406}\x{8407}\x{8408}\x{8409}\x{840A}\x{840B}\x{840C}\x{840D}\x{840E}' . +'\x{840F}\x{8410}\x{8411}\x{8412}\x{8413}\x{8415}\x{8418}\x{8419}\x{841A}' . +'\x{841B}\x{841C}\x{841D}\x{841E}\x{8421}\x{8422}\x{8423}\x{8424}\x{8425}' . +'\x{8426}\x{8427}\x{8428}\x{8429}\x{842A}\x{842B}\x{842C}\x{842D}\x{842E}' . +'\x{842F}\x{8430}\x{8431}\x{8432}\x{8433}\x{8434}\x{8435}\x{8436}\x{8437}' . +'\x{8438}\x{8439}\x{843A}\x{843B}\x{843C}\x{843D}\x{843E}\x{843F}\x{8440}' . +'\x{8441}\x{8442}\x{8443}\x{8444}\x{8445}\x{8446}\x{8447}\x{8448}\x{8449}' . +'\x{844A}\x{844B}\x{844C}\x{844D}\x{844E}\x{844F}\x{8450}\x{8451}\x{8452}' . +'\x{8453}\x{8454}\x{8455}\x{8456}\x{8457}\x{8459}\x{845A}\x{845B}\x{845C}' . +'\x{845D}\x{845E}\x{845F}\x{8460}\x{8461}\x{8462}\x{8463}\x{8464}\x{8465}' . +'\x{8466}\x{8467}\x{8468}\x{8469}\x{846A}\x{846B}\x{846C}\x{846D}\x{846E}' . +'\x{846F}\x{8470}\x{8471}\x{8472}\x{8473}\x{8474}\x{8475}\x{8476}\x{8477}' . +'\x{8478}\x{8479}\x{847A}\x{847B}\x{847C}\x{847D}\x{847E}\x{847F}\x{8480}' . +'\x{8481}\x{8482}\x{8484}\x{8485}\x{8486}\x{8487}\x{8488}\x{8489}\x{848A}' . +'\x{848B}\x{848C}\x{848D}\x{848E}\x{848F}\x{8490}\x{8491}\x{8492}\x{8493}' . +'\x{8494}\x{8496}\x{8497}\x{8498}\x{8499}\x{849A}\x{849B}\x{849C}\x{849D}' . +'\x{849E}\x{849F}\x{84A0}\x{84A1}\x{84A2}\x{84A3}\x{84A4}\x{84A5}\x{84A6}' . +'\x{84A7}\x{84A8}\x{84A9}\x{84AA}\x{84AB}\x{84AC}\x{84AE}\x{84AF}\x{84B0}' . +'\x{84B1}\x{84B2}\x{84B3}\x{84B4}\x{84B5}\x{84B6}\x{84B8}\x{84B9}\x{84BA}' . +'\x{84BB}\x{84BC}\x{84BD}\x{84BE}\x{84BF}\x{84C0}\x{84C1}\x{84C2}\x{84C4}' . +'\x{84C5}\x{84C6}\x{84C7}\x{84C8}\x{84C9}\x{84CA}\x{84CB}\x{84CC}\x{84CD}' . +'\x{84CE}\x{84CF}\x{84D0}\x{84D1}\x{84D2}\x{84D3}\x{84D4}\x{84D5}\x{84D6}' . +'\x{84D7}\x{84D8}\x{84D9}\x{84DB}\x{84DC}\x{84DD}\x{84DE}\x{84DF}\x{84E0}' . +'\x{84E1}\x{84E2}\x{84E3}\x{84E4}\x{84E5}\x{84E6}\x{84E7}\x{84E8}\x{84E9}' . +'\x{84EA}\x{84EB}\x{84EC}\x{84EE}\x{84EF}\x{84F0}\x{84F1}\x{84F2}\x{84F3}' . +'\x{84F4}\x{84F5}\x{84F6}\x{84F7}\x{84F8}\x{84F9}\x{84FA}\x{84FB}\x{84FC}' . +'\x{84FD}\x{84FE}\x{84FF}\x{8500}\x{8501}\x{8502}\x{8503}\x{8504}\x{8506}' . +'\x{8507}\x{8508}\x{8509}\x{850A}\x{850B}\x{850C}\x{850D}\x{850E}\x{850F}' . +'\x{8511}\x{8512}\x{8513}\x{8514}\x{8515}\x{8516}\x{8517}\x{8518}\x{8519}' . +'\x{851A}\x{851B}\x{851C}\x{851D}\x{851E}\x{851F}\x{8520}\x{8521}\x{8522}' . +'\x{8523}\x{8524}\x{8525}\x{8526}\x{8527}\x{8528}\x{8529}\x{852A}\x{852B}' . +'\x{852C}\x{852D}\x{852E}\x{852F}\x{8530}\x{8531}\x{8534}\x{8535}\x{8536}' . +'\x{8537}\x{8538}\x{8539}\x{853A}\x{853B}\x{853C}\x{853D}\x{853E}\x{853F}' . +'\x{8540}\x{8541}\x{8542}\x{8543}\x{8544}\x{8545}\x{8546}\x{8547}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854D}\x{854E}\x{854F}\x{8551}\x{8552}\x{8553}' . +'\x{8554}\x{8555}\x{8556}\x{8557}\x{8558}\x{8559}\x{855A}\x{855B}\x{855C}' . +'\x{855D}\x{855E}\x{855F}\x{8560}\x{8561}\x{8562}\x{8563}\x{8564}\x{8565}' . +'\x{8566}\x{8567}\x{8568}\x{8569}\x{856A}\x{856B}\x{856C}\x{856D}\x{856E}' . +'\x{856F}\x{8570}\x{8571}\x{8572}\x{8573}\x{8574}\x{8575}\x{8576}\x{8577}' . +'\x{8578}\x{8579}\x{857A}\x{857B}\x{857C}\x{857D}\x{857E}\x{8580}\x{8581}' . +'\x{8582}\x{8583}\x{8584}\x{8585}\x{8586}\x{8587}\x{8588}\x{8589}\x{858A}' . +'\x{858B}\x{858C}\x{858D}\x{858E}\x{858F}\x{8590}\x{8591}\x{8592}\x{8594}' . +'\x{8595}\x{8596}\x{8598}\x{8599}\x{859A}\x{859B}\x{859C}\x{859D}\x{859E}' . +'\x{859F}\x{85A0}\x{85A1}\x{85A2}\x{85A3}\x{85A4}\x{85A5}\x{85A6}\x{85A7}' . +'\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AD}\x{85AE}\x{85AF}\x{85B0}' . +'\x{85B1}\x{85B3}\x{85B4}\x{85B5}\x{85B6}\x{85B7}\x{85B8}\x{85B9}\x{85BA}' . +'\x{85BC}\x{85BD}\x{85BE}\x{85BF}\x{85C0}\x{85C1}\x{85C2}\x{85C3}\x{85C4}' . +'\x{85C5}\x{85C6}\x{85C7}\x{85C8}\x{85C9}\x{85CA}\x{85CB}\x{85CD}\x{85CE}' . +'\x{85CF}\x{85D0}\x{85D1}\x{85D2}\x{85D3}\x{85D4}\x{85D5}\x{85D6}\x{85D7}' . +'\x{85D8}\x{85D9}\x{85DA}\x{85DB}\x{85DC}\x{85DD}\x{85DE}\x{85DF}\x{85E0}' . +'\x{85E1}\x{85E2}\x{85E3}\x{85E4}\x{85E5}\x{85E6}\x{85E7}\x{85E8}\x{85E9}' . +'\x{85EA}\x{85EB}\x{85EC}\x{85ED}\x{85EF}\x{85F0}\x{85F1}\x{85F2}\x{85F4}' . +'\x{85F5}\x{85F6}\x{85F7}\x{85F8}\x{85F9}\x{85FA}\x{85FB}\x{85FD}\x{85FE}' . +'\x{85FF}\x{8600}\x{8601}\x{8602}\x{8604}\x{8605}\x{8606}\x{8607}\x{8608}' . +'\x{8609}\x{860A}\x{860B}\x{860C}\x{860F}\x{8611}\x{8612}\x{8613}\x{8614}' . +'\x{8616}\x{8617}\x{8618}\x{8619}\x{861A}\x{861B}\x{861C}\x{861E}\x{861F}' . +'\x{8620}\x{8621}\x{8622}\x{8623}\x{8624}\x{8625}\x{8626}\x{8627}\x{8628}' . +'\x{8629}\x{862A}\x{862B}\x{862C}\x{862D}\x{862E}\x{862F}\x{8630}\x{8631}' . +'\x{8632}\x{8633}\x{8634}\x{8635}\x{8636}\x{8638}\x{8639}\x{863A}\x{863B}' . +'\x{863C}\x{863D}\x{863E}\x{863F}\x{8640}\x{8641}\x{8642}\x{8643}\x{8644}' . +'\x{8645}\x{8646}\x{8647}\x{8648}\x{8649}\x{864A}\x{864B}\x{864C}\x{864D}' . +'\x{864E}\x{864F}\x{8650}\x{8651}\x{8652}\x{8653}\x{8654}\x{8655}\x{8656}' . +'\x{8658}\x{8659}\x{865A}\x{865B}\x{865C}\x{865D}\x{865E}\x{865F}\x{8660}' . +'\x{8661}\x{8662}\x{8663}\x{8664}\x{8665}\x{8666}\x{8667}\x{8668}\x{8669}' . +'\x{866A}\x{866B}\x{866C}\x{866D}\x{866E}\x{866F}\x{8670}\x{8671}\x{8672}' . +'\x{8673}\x{8674}\x{8676}\x{8677}\x{8678}\x{8679}\x{867A}\x{867B}\x{867C}' . +'\x{867D}\x{867E}\x{867F}\x{8680}\x{8681}\x{8682}\x{8683}\x{8684}\x{8685}' . +'\x{8686}\x{8687}\x{8688}\x{868A}\x{868B}\x{868C}\x{868D}\x{868E}\x{868F}' . +'\x{8690}\x{8691}\x{8693}\x{8694}\x{8695}\x{8696}\x{8697}\x{8698}\x{8699}' . +'\x{869A}\x{869B}\x{869C}\x{869D}\x{869E}\x{869F}\x{86A1}\x{86A2}\x{86A3}' . +'\x{86A4}\x{86A5}\x{86A7}\x{86A8}\x{86A9}\x{86AA}\x{86AB}\x{86AC}\x{86AD}' . +'\x{86AE}\x{86AF}\x{86B0}\x{86B1}\x{86B2}\x{86B3}\x{86B4}\x{86B5}\x{86B6}' . +'\x{86B7}\x{86B8}\x{86B9}\x{86BA}\x{86BB}\x{86BC}\x{86BD}\x{86BE}\x{86BF}' . +'\x{86C0}\x{86C1}\x{86C2}\x{86C3}\x{86C4}\x{86C5}\x{86C6}\x{86C7}\x{86C8}' . +'\x{86C9}\x{86CA}\x{86CB}\x{86CC}\x{86CE}\x{86CF}\x{86D0}\x{86D1}\x{86D2}' . +'\x{86D3}\x{86D4}\x{86D6}\x{86D7}\x{86D8}\x{86D9}\x{86DA}\x{86DB}\x{86DC}' . +'\x{86DD}\x{86DE}\x{86DF}\x{86E1}\x{86E2}\x{86E3}\x{86E4}\x{86E5}\x{86E6}' . +'\x{86E8}\x{86E9}\x{86EA}\x{86EB}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F0}' . +'\x{86F1}\x{86F2}\x{86F3}\x{86F4}\x{86F5}\x{86F6}\x{86F7}\x{86F8}\x{86F9}' . +'\x{86FA}\x{86FB}\x{86FC}\x{86FE}\x{86FF}\x{8700}\x{8701}\x{8702}\x{8703}' . +'\x{8704}\x{8705}\x{8706}\x{8707}\x{8708}\x{8709}\x{870A}\x{870B}\x{870C}' . +'\x{870D}\x{870E}\x{870F}\x{8710}\x{8711}\x{8712}\x{8713}\x{8714}\x{8715}' . +'\x{8716}\x{8717}\x{8718}\x{8719}\x{871A}\x{871B}\x{871C}\x{871E}\x{871F}' . +'\x{8720}\x{8721}\x{8722}\x{8723}\x{8724}\x{8725}\x{8726}\x{8727}\x{8728}' . +'\x{8729}\x{872A}\x{872B}\x{872C}\x{872D}\x{872E}\x{8730}\x{8731}\x{8732}' . +'\x{8733}\x{8734}\x{8735}\x{8736}\x{8737}\x{8738}\x{8739}\x{873A}\x{873B}' . +'\x{873C}\x{873E}\x{873F}\x{8740}\x{8741}\x{8742}\x{8743}\x{8744}\x{8746}' . +'\x{8747}\x{8748}\x{8749}\x{874A}\x{874C}\x{874D}\x{874E}\x{874F}\x{8750}' . +'\x{8751}\x{8752}\x{8753}\x{8754}\x{8755}\x{8756}\x{8757}\x{8758}\x{8759}' . +'\x{875A}\x{875B}\x{875C}\x{875D}\x{875E}\x{875F}\x{8760}\x{8761}\x{8762}' . +'\x{8763}\x{8764}\x{8765}\x{8766}\x{8767}\x{8768}\x{8769}\x{876A}\x{876B}' . +'\x{876C}\x{876D}\x{876E}\x{876F}\x{8770}\x{8772}\x{8773}\x{8774}\x{8775}' . +'\x{8776}\x{8777}\x{8778}\x{8779}\x{877A}\x{877B}\x{877C}\x{877D}\x{877E}' . +'\x{8780}\x{8781}\x{8782}\x{8783}\x{8784}\x{8785}\x{8786}\x{8787}\x{8788}' . +'\x{8789}\x{878A}\x{878B}\x{878C}\x{878D}\x{878F}\x{8790}\x{8791}\x{8792}' . +'\x{8793}\x{8794}\x{8795}\x{8796}\x{8797}\x{8798}\x{879A}\x{879B}\x{879C}' . +'\x{879D}\x{879E}\x{879F}\x{87A0}\x{87A1}\x{87A2}\x{87A3}\x{87A4}\x{87A5}' . +'\x{87A6}\x{87A7}\x{87A8}\x{87A9}\x{87AA}\x{87AB}\x{87AC}\x{87AD}\x{87AE}' . +'\x{87AF}\x{87B0}\x{87B1}\x{87B2}\x{87B3}\x{87B4}\x{87B5}\x{87B6}\x{87B7}' . +'\x{87B8}\x{87B9}\x{87BA}\x{87BB}\x{87BC}\x{87BD}\x{87BE}\x{87BF}\x{87C0}' . +'\x{87C1}\x{87C2}\x{87C3}\x{87C4}\x{87C5}\x{87C6}\x{87C7}\x{87C8}\x{87C9}' . +'\x{87CA}\x{87CB}\x{87CC}\x{87CD}\x{87CE}\x{87CF}\x{87D0}\x{87D1}\x{87D2}' . +'\x{87D3}\x{87D4}\x{87D5}\x{87D6}\x{87D7}\x{87D8}\x{87D9}\x{87DB}\x{87DC}' . +'\x{87DD}\x{87DE}\x{87DF}\x{87E0}\x{87E1}\x{87E2}\x{87E3}\x{87E4}\x{87E5}' . +'\x{87E6}\x{87E7}\x{87E8}\x{87E9}\x{87EA}\x{87EB}\x{87EC}\x{87ED}\x{87EE}' . +'\x{87EF}\x{87F1}\x{87F2}\x{87F3}\x{87F4}\x{87F5}\x{87F6}\x{87F7}\x{87F8}' . +'\x{87F9}\x{87FA}\x{87FB}\x{87FC}\x{87FD}\x{87FE}\x{87FF}\x{8800}\x{8801}' . +'\x{8802}\x{8803}\x{8804}\x{8805}\x{8806}\x{8808}\x{8809}\x{880A}\x{880B}' . +'\x{880C}\x{880D}\x{880E}\x{880F}\x{8810}\x{8811}\x{8813}\x{8814}\x{8815}' . +'\x{8816}\x{8817}\x{8818}\x{8819}\x{881A}\x{881B}\x{881C}\x{881D}\x{881E}' . +'\x{881F}\x{8820}\x{8821}\x{8822}\x{8823}\x{8824}\x{8825}\x{8826}\x{8827}' . +'\x{8828}\x{8829}\x{882A}\x{882B}\x{882C}\x{882E}\x{882F}\x{8830}\x{8831}' . +'\x{8832}\x{8833}\x{8834}\x{8835}\x{8836}\x{8837}\x{8838}\x{8839}\x{883B}' . +'\x{883C}\x{883D}\x{883E}\x{883F}\x{8840}\x{8841}\x{8842}\x{8843}\x{8844}' . +'\x{8845}\x{8846}\x{8848}\x{8849}\x{884A}\x{884B}\x{884C}\x{884D}\x{884E}' . +'\x{884F}\x{8850}\x{8851}\x{8852}\x{8853}\x{8854}\x{8855}\x{8856}\x{8857}' . +'\x{8859}\x{885A}\x{885B}\x{885D}\x{885E}\x{8860}\x{8861}\x{8862}\x{8863}' . +'\x{8864}\x{8865}\x{8866}\x{8867}\x{8868}\x{8869}\x{886A}\x{886B}\x{886C}' . +'\x{886D}\x{886E}\x{886F}\x{8870}\x{8871}\x{8872}\x{8873}\x{8874}\x{8875}' . +'\x{8876}\x{8877}\x{8878}\x{8879}\x{887B}\x{887C}\x{887D}\x{887E}\x{887F}' . +'\x{8880}\x{8881}\x{8882}\x{8883}\x{8884}\x{8885}\x{8886}\x{8887}\x{8888}' . +'\x{8889}\x{888A}\x{888B}\x{888C}\x{888D}\x{888E}\x{888F}\x{8890}\x{8891}' . +'\x{8892}\x{8893}\x{8894}\x{8895}\x{8896}\x{8897}\x{8898}\x{8899}\x{889A}' . +'\x{889B}\x{889C}\x{889D}\x{889E}\x{889F}\x{88A0}\x{88A1}\x{88A2}\x{88A3}' . +'\x{88A4}\x{88A5}\x{88A6}\x{88A7}\x{88A8}\x{88A9}\x{88AA}\x{88AB}\x{88AC}' . +'\x{88AD}\x{88AE}\x{88AF}\x{88B0}\x{88B1}\x{88B2}\x{88B3}\x{88B4}\x{88B6}' . +'\x{88B7}\x{88B8}\x{88B9}\x{88BA}\x{88BB}\x{88BC}\x{88BD}\x{88BE}\x{88BF}' . +'\x{88C0}\x{88C1}\x{88C2}\x{88C3}\x{88C4}\x{88C5}\x{88C6}\x{88C7}\x{88C8}' . +'\x{88C9}\x{88CA}\x{88CB}\x{88CC}\x{88CD}\x{88CE}\x{88CF}\x{88D0}\x{88D1}' . +'\x{88D2}\x{88D3}\x{88D4}\x{88D5}\x{88D6}\x{88D7}\x{88D8}\x{88D9}\x{88DA}' . +'\x{88DB}\x{88DC}\x{88DD}\x{88DE}\x{88DF}\x{88E0}\x{88E1}\x{88E2}\x{88E3}' . +'\x{88E4}\x{88E5}\x{88E7}\x{88E8}\x{88EA}\x{88EB}\x{88EC}\x{88EE}\x{88EF}' . +'\x{88F0}\x{88F1}\x{88F2}\x{88F3}\x{88F4}\x{88F5}\x{88F6}\x{88F7}\x{88F8}' . +'\x{88F9}\x{88FA}\x{88FB}\x{88FC}\x{88FD}\x{88FE}\x{88FF}\x{8900}\x{8901}' . +'\x{8902}\x{8904}\x{8905}\x{8906}\x{8907}\x{8908}\x{8909}\x{890A}\x{890B}' . +'\x{890C}\x{890D}\x{890E}\x{8910}\x{8911}\x{8912}\x{8913}\x{8914}\x{8915}' . +'\x{8916}\x{8917}\x{8918}\x{8919}\x{891A}\x{891B}\x{891C}\x{891D}\x{891E}' . +'\x{891F}\x{8920}\x{8921}\x{8922}\x{8923}\x{8925}\x{8926}\x{8927}\x{8928}' . +'\x{8929}\x{892A}\x{892B}\x{892C}\x{892D}\x{892E}\x{892F}\x{8930}\x{8931}' . +'\x{8932}\x{8933}\x{8934}\x{8935}\x{8936}\x{8937}\x{8938}\x{8939}\x{893A}' . +'\x{893B}\x{893C}\x{893D}\x{893E}\x{893F}\x{8940}\x{8941}\x{8942}\x{8943}' . +'\x{8944}\x{8945}\x{8946}\x{8947}\x{8948}\x{8949}\x{894A}\x{894B}\x{894C}' . +'\x{894E}\x{894F}\x{8950}\x{8951}\x{8952}\x{8953}\x{8954}\x{8955}\x{8956}' . +'\x{8957}\x{8958}\x{8959}\x{895A}\x{895B}\x{895C}\x{895D}\x{895E}\x{895F}' . +'\x{8960}\x{8961}\x{8962}\x{8963}\x{8964}\x{8966}\x{8967}\x{8968}\x{8969}' . +'\x{896A}\x{896B}\x{896C}\x{896D}\x{896E}\x{896F}\x{8970}\x{8971}\x{8972}' . +'\x{8973}\x{8974}\x{8976}\x{8977}\x{8978}\x{8979}\x{897A}\x{897B}\x{897C}' . +'\x{897E}\x{897F}\x{8980}\x{8981}\x{8982}\x{8983}\x{8984}\x{8985}\x{8986}' . +'\x{8987}\x{8988}\x{8989}\x{898A}\x{898B}\x{898C}\x{898E}\x{898F}\x{8991}' . +'\x{8992}\x{8993}\x{8995}\x{8996}\x{8997}\x{8998}\x{899A}\x{899B}\x{899C}' . +'\x{899D}\x{899E}\x{899F}\x{89A0}\x{89A1}\x{89A2}\x{89A3}\x{89A4}\x{89A5}' . +'\x{89A6}\x{89A7}\x{89A8}\x{89AA}\x{89AB}\x{89AC}\x{89AD}\x{89AE}\x{89AF}' . +'\x{89B1}\x{89B2}\x{89B3}\x{89B5}\x{89B6}\x{89B7}\x{89B8}\x{89B9}\x{89BA}' . +'\x{89BD}\x{89BE}\x{89BF}\x{89C0}\x{89C1}\x{89C2}\x{89C3}\x{89C4}\x{89C5}' . +'\x{89C6}\x{89C7}\x{89C8}\x{89C9}\x{89CA}\x{89CB}\x{89CC}\x{89CD}\x{89CE}' . +'\x{89CF}\x{89D0}\x{89D1}\x{89D2}\x{89D3}\x{89D4}\x{89D5}\x{89D6}\x{89D7}' . +'\x{89D8}\x{89D9}\x{89DA}\x{89DB}\x{89DC}\x{89DD}\x{89DE}\x{89DF}\x{89E0}' . +'\x{89E1}\x{89E2}\x{89E3}\x{89E4}\x{89E5}\x{89E6}\x{89E7}\x{89E8}\x{89E9}' . +'\x{89EA}\x{89EB}\x{89EC}\x{89ED}\x{89EF}\x{89F0}\x{89F1}\x{89F2}\x{89F3}' . +'\x{89F4}\x{89F6}\x{89F7}\x{89F8}\x{89FA}\x{89FB}\x{89FC}\x{89FE}\x{89FF}' . +'\x{8A00}\x{8A01}\x{8A02}\x{8A03}\x{8A04}\x{8A07}\x{8A08}\x{8A09}\x{8A0A}' . +'\x{8A0B}\x{8A0C}\x{8A0D}\x{8A0E}\x{8A0F}\x{8A10}\x{8A11}\x{8A12}\x{8A13}' . +'\x{8A15}\x{8A16}\x{8A17}\x{8A18}\x{8A1A}\x{8A1B}\x{8A1C}\x{8A1D}\x{8A1E}' . +'\x{8A1F}\x{8A22}\x{8A23}\x{8A24}\x{8A25}\x{8A26}\x{8A27}\x{8A28}\x{8A29}' . +'\x{8A2A}\x{8A2C}\x{8A2D}\x{8A2E}\x{8A2F}\x{8A30}\x{8A31}\x{8A32}\x{8A34}' . +'\x{8A35}\x{8A36}\x{8A37}\x{8A38}\x{8A39}\x{8A3A}\x{8A3B}\x{8A3C}\x{8A3E}' . +'\x{8A3F}\x{8A40}\x{8A41}\x{8A42}\x{8A43}\x{8A44}\x{8A45}\x{8A46}\x{8A47}' . +'\x{8A48}\x{8A49}\x{8A4A}\x{8A4C}\x{8A4D}\x{8A4E}\x{8A4F}\x{8A50}\x{8A51}' . +'\x{8A52}\x{8A53}\x{8A54}\x{8A55}\x{8A56}\x{8A57}\x{8A58}\x{8A59}\x{8A5A}' . +'\x{8A5B}\x{8A5C}\x{8A5D}\x{8A5E}\x{8A5F}\x{8A60}\x{8A61}\x{8A62}\x{8A63}' . +'\x{8A65}\x{8A66}\x{8A67}\x{8A68}\x{8A69}\x{8A6A}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A6F}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A74}\x{8A75}\x{8A76}' . +'\x{8A77}\x{8A79}\x{8A7A}\x{8A7B}\x{8A7C}\x{8A7E}\x{8A7F}\x{8A80}\x{8A81}' . +'\x{8A82}\x{8A83}\x{8A84}\x{8A85}\x{8A86}\x{8A87}\x{8A89}\x{8A8A}\x{8A8B}' . +'\x{8A8C}\x{8A8D}\x{8A8E}\x{8A8F}\x{8A90}\x{8A91}\x{8A92}\x{8A93}\x{8A94}' . +'\x{8A95}\x{8A96}\x{8A97}\x{8A98}\x{8A99}\x{8A9A}\x{8A9B}\x{8A9C}\x{8A9D}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA2}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA7}' . +'\x{8AA8}\x{8AA9}\x{8AAA}\x{8AAB}\x{8AAC}\x{8AAE}\x{8AB0}\x{8AB1}\x{8AB2}' . +'\x{8AB3}\x{8AB4}\x{8AB5}\x{8AB6}\x{8AB8}\x{8AB9}\x{8ABA}\x{8ABB}\x{8ABC}' . +'\x{8ABD}\x{8ABE}\x{8ABF}\x{8AC0}\x{8AC1}\x{8AC2}\x{8AC3}\x{8AC4}\x{8AC5}' . +'\x{8AC6}\x{8AC7}\x{8AC8}\x{8AC9}\x{8ACA}\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACE}' . +'\x{8ACF}\x{8AD1}\x{8AD2}\x{8AD3}\x{8AD4}\x{8AD5}\x{8AD6}\x{8AD7}\x{8AD8}' . +'\x{8AD9}\x{8ADA}\x{8ADB}\x{8ADC}\x{8ADD}\x{8ADE}\x{8ADF}\x{8AE0}\x{8AE1}' . +'\x{8AE2}\x{8AE3}\x{8AE4}\x{8AE5}\x{8AE6}\x{8AE7}\x{8AE8}\x{8AE9}\x{8AEA}' . +'\x{8AEB}\x{8AED}\x{8AEE}\x{8AEF}\x{8AF0}\x{8AF1}\x{8AF2}\x{8AF3}\x{8AF4}' . +'\x{8AF5}\x{8AF6}\x{8AF7}\x{8AF8}\x{8AF9}\x{8AFA}\x{8AFB}\x{8AFC}\x{8AFD}' . +'\x{8AFE}\x{8AFF}\x{8B00}\x{8B01}\x{8B02}\x{8B03}\x{8B04}\x{8B05}\x{8B06}' . +'\x{8B07}\x{8B08}\x{8B09}\x{8B0A}\x{8B0B}\x{8B0D}\x{8B0E}\x{8B0F}\x{8B10}' . +'\x{8B11}\x{8B12}\x{8B13}\x{8B14}\x{8B15}\x{8B16}\x{8B17}\x{8B18}\x{8B19}' . +'\x{8B1A}\x{8B1B}\x{8B1C}\x{8B1D}\x{8B1E}\x{8B1F}\x{8B20}\x{8B21}\x{8B22}' . +'\x{8B23}\x{8B24}\x{8B25}\x{8B26}\x{8B27}\x{8B28}\x{8B2A}\x{8B2B}\x{8B2C}' . +'\x{8B2D}\x{8B2E}\x{8B2F}\x{8B30}\x{8B31}\x{8B33}\x{8B34}\x{8B35}\x{8B36}' . +'\x{8B37}\x{8B39}\x{8B3A}\x{8B3B}\x{8B3C}\x{8B3D}\x{8B3E}\x{8B40}\x{8B41}' . +'\x{8B42}\x{8B43}\x{8B44}\x{8B45}\x{8B46}\x{8B47}\x{8B48}\x{8B49}\x{8B4A}' . +'\x{8B4B}\x{8B4C}\x{8B4D}\x{8B4E}\x{8B4F}\x{8B50}\x{8B51}\x{8B52}\x{8B53}' . +'\x{8B54}\x{8B55}\x{8B56}\x{8B57}\x{8B58}\x{8B59}\x{8B5A}\x{8B5B}\x{8B5C}' . +'\x{8B5D}\x{8B5E}\x{8B5F}\x{8B60}\x{8B63}\x{8B64}\x{8B65}\x{8B66}\x{8B67}' . +'\x{8B68}\x{8B6A}\x{8B6B}\x{8B6C}\x{8B6D}\x{8B6E}\x{8B6F}\x{8B70}\x{8B71}' . +'\x{8B73}\x{8B74}\x{8B76}\x{8B77}\x{8B78}\x{8B79}\x{8B7A}\x{8B7B}\x{8B7D}' . +'\x{8B7E}\x{8B7F}\x{8B80}\x{8B82}\x{8B83}\x{8B84}\x{8B85}\x{8B86}\x{8B88}' . +'\x{8B89}\x{8B8A}\x{8B8B}\x{8B8C}\x{8B8E}\x{8B90}\x{8B91}\x{8B92}\x{8B93}' . +'\x{8B94}\x{8B95}\x{8B96}\x{8B97}\x{8B98}\x{8B99}\x{8B9A}\x{8B9C}\x{8B9D}' . +'\x{8B9E}\x{8B9F}\x{8BA0}\x{8BA1}\x{8BA2}\x{8BA3}\x{8BA4}\x{8BA5}\x{8BA6}' . +'\x{8BA7}\x{8BA8}\x{8BA9}\x{8BAA}\x{8BAB}\x{8BAC}\x{8BAD}\x{8BAE}\x{8BAF}' . +'\x{8BB0}\x{8BB1}\x{8BB2}\x{8BB3}\x{8BB4}\x{8BB5}\x{8BB6}\x{8BB7}\x{8BB8}' . +'\x{8BB9}\x{8BBA}\x{8BBB}\x{8BBC}\x{8BBD}\x{8BBE}\x{8BBF}\x{8BC0}\x{8BC1}' . +'\x{8BC2}\x{8BC3}\x{8BC4}\x{8BC5}\x{8BC6}\x{8BC7}\x{8BC8}\x{8BC9}\x{8BCA}' . +'\x{8BCB}\x{8BCC}\x{8BCD}\x{8BCE}\x{8BCF}\x{8BD0}\x{8BD1}\x{8BD2}\x{8BD3}' . +'\x{8BD4}\x{8BD5}\x{8BD6}\x{8BD7}\x{8BD8}\x{8BD9}\x{8BDA}\x{8BDB}\x{8BDC}' . +'\x{8BDD}\x{8BDE}\x{8BDF}\x{8BE0}\x{8BE1}\x{8BE2}\x{8BE3}\x{8BE4}\x{8BE5}' . +'\x{8BE6}\x{8BE7}\x{8BE8}\x{8BE9}\x{8BEA}\x{8BEB}\x{8BEC}\x{8BED}\x{8BEE}' . +'\x{8BEF}\x{8BF0}\x{8BF1}\x{8BF2}\x{8BF3}\x{8BF4}\x{8BF5}\x{8BF6}\x{8BF7}' . +'\x{8BF8}\x{8BF9}\x{8BFA}\x{8BFB}\x{8BFC}\x{8BFD}\x{8BFE}\x{8BFF}\x{8C00}' . +'\x{8C01}\x{8C02}\x{8C03}\x{8C04}\x{8C05}\x{8C06}\x{8C07}\x{8C08}\x{8C09}' . +'\x{8C0A}\x{8C0B}\x{8C0C}\x{8C0D}\x{8C0E}\x{8C0F}\x{8C10}\x{8C11}\x{8C12}' . +'\x{8C13}\x{8C14}\x{8C15}\x{8C16}\x{8C17}\x{8C18}\x{8C19}\x{8C1A}\x{8C1B}' . +'\x{8C1C}\x{8C1D}\x{8C1E}\x{8C1F}\x{8C20}\x{8C21}\x{8C22}\x{8C23}\x{8C24}' . +'\x{8C25}\x{8C26}\x{8C27}\x{8C28}\x{8C29}\x{8C2A}\x{8C2B}\x{8C2C}\x{8C2D}' . +'\x{8C2E}\x{8C2F}\x{8C30}\x{8C31}\x{8C32}\x{8C33}\x{8C34}\x{8C35}\x{8C36}' . +'\x{8C37}\x{8C39}\x{8C3A}\x{8C3B}\x{8C3C}\x{8C3D}\x{8C3E}\x{8C3F}\x{8C41}' . +'\x{8C42}\x{8C43}\x{8C45}\x{8C46}\x{8C47}\x{8C48}\x{8C49}\x{8C4A}\x{8C4B}' . +'\x{8C4C}\x{8C4D}\x{8C4E}\x{8C4F}\x{8C50}\x{8C54}\x{8C55}\x{8C56}\x{8C57}' . +'\x{8C59}\x{8C5A}\x{8C5B}\x{8C5C}\x{8C5D}\x{8C5E}\x{8C5F}\x{8C60}\x{8C61}' . +'\x{8C62}\x{8C63}\x{8C64}\x{8C65}\x{8C66}\x{8C67}\x{8C68}\x{8C69}\x{8C6A}' . +'\x{8C6B}\x{8C6C}\x{8C6D}\x{8C6E}\x{8C6F}\x{8C70}\x{8C71}\x{8C72}\x{8C73}' . +'\x{8C75}\x{8C76}\x{8C77}\x{8C78}\x{8C79}\x{8C7A}\x{8C7B}\x{8C7D}\x{8C7E}' . +'\x{8C80}\x{8C81}\x{8C82}\x{8C84}\x{8C85}\x{8C86}\x{8C88}\x{8C89}\x{8C8A}' . +'\x{8C8C}\x{8C8D}\x{8C8F}\x{8C90}\x{8C91}\x{8C92}\x{8C93}\x{8C94}\x{8C95}' . +'\x{8C96}\x{8C97}\x{8C98}\x{8C99}\x{8C9A}\x{8C9C}\x{8C9D}\x{8C9E}\x{8C9F}' . +'\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA3}\x{8CA4}\x{8CA5}\x{8CA7}\x{8CA8}\x{8CA9}' . +'\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}\x{8CB1}\x{8CB2}' . +'\x{8CB3}\x{8CB4}\x{8CB5}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CB9}\x{8CBA}\x{8CBB}' . +'\x{8CBC}\x{8CBD}\x{8CBE}\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}' . +'\x{8CC5}\x{8CC6}\x{8CC7}\x{8CC8}\x{8CC9}\x{8CCA}\x{8CCC}\x{8CCE}\x{8CCF}' . +'\x{8CD0}\x{8CD1}\x{8CD2}\x{8CD3}\x{8CD4}\x{8CD5}\x{8CD7}\x{8CD9}\x{8CDA}' . +'\x{8CDB}\x{8CDC}\x{8CDD}\x{8CDE}\x{8CDF}\x{8CE0}\x{8CE1}\x{8CE2}\x{8CE3}' . +'\x{8CE4}\x{8CE5}\x{8CE6}\x{8CE7}\x{8CE8}\x{8CEA}\x{8CEB}\x{8CEC}\x{8CED}' . +'\x{8CEE}\x{8CEF}\x{8CF0}\x{8CF1}\x{8CF2}\x{8CF3}\x{8CF4}\x{8CF5}\x{8CF6}' . +'\x{8CF8}\x{8CF9}\x{8CFA}\x{8CFB}\x{8CFC}\x{8CFD}\x{8CFE}\x{8CFF}\x{8D00}' . +'\x{8D02}\x{8D03}\x{8D04}\x{8D05}\x{8D06}\x{8D07}\x{8D08}\x{8D09}\x{8D0A}' . +'\x{8D0B}\x{8D0C}\x{8D0D}\x{8D0E}\x{8D0F}\x{8D10}\x{8D13}\x{8D14}\x{8D15}' . +'\x{8D16}\x{8D17}\x{8D18}\x{8D19}\x{8D1A}\x{8D1B}\x{8D1C}\x{8D1D}\x{8D1E}' . +'\x{8D1F}\x{8D20}\x{8D21}\x{8D22}\x{8D23}\x{8D24}\x{8D25}\x{8D26}\x{8D27}' . +'\x{8D28}\x{8D29}\x{8D2A}\x{8D2B}\x{8D2C}\x{8D2D}\x{8D2E}\x{8D2F}\x{8D30}' . +'\x{8D31}\x{8D32}\x{8D33}\x{8D34}\x{8D35}\x{8D36}\x{8D37}\x{8D38}\x{8D39}' . +'\x{8D3A}\x{8D3B}\x{8D3C}\x{8D3D}\x{8D3E}\x{8D3F}\x{8D40}\x{8D41}\x{8D42}' . +'\x{8D43}\x{8D44}\x{8D45}\x{8D46}\x{8D47}\x{8D48}\x{8D49}\x{8D4A}\x{8D4B}' . +'\x{8D4C}\x{8D4D}\x{8D4E}\x{8D4F}\x{8D50}\x{8D51}\x{8D52}\x{8D53}\x{8D54}' . +'\x{8D55}\x{8D56}\x{8D57}\x{8D58}\x{8D59}\x{8D5A}\x{8D5B}\x{8D5C}\x{8D5D}' . +'\x{8D5E}\x{8D5F}\x{8D60}\x{8D61}\x{8D62}\x{8D63}\x{8D64}\x{8D65}\x{8D66}' . +'\x{8D67}\x{8D68}\x{8D69}\x{8D6A}\x{8D6B}\x{8D6C}\x{8D6D}\x{8D6E}\x{8D6F}' . +'\x{8D70}\x{8D71}\x{8D72}\x{8D73}\x{8D74}\x{8D75}\x{8D76}\x{8D77}\x{8D78}' . +'\x{8D79}\x{8D7A}\x{8D7B}\x{8D7D}\x{8D7E}\x{8D7F}\x{8D80}\x{8D81}\x{8D82}' . +'\x{8D83}\x{8D84}\x{8D85}\x{8D86}\x{8D87}\x{8D88}\x{8D89}\x{8D8A}\x{8D8B}' . +'\x{8D8C}\x{8D8D}\x{8D8E}\x{8D8F}\x{8D90}\x{8D91}\x{8D92}\x{8D93}\x{8D94}' . +'\x{8D95}\x{8D96}\x{8D97}\x{8D98}\x{8D99}\x{8D9A}\x{8D9B}\x{8D9C}\x{8D9D}' . +'\x{8D9E}\x{8D9F}\x{8DA0}\x{8DA1}\x{8DA2}\x{8DA3}\x{8DA4}\x{8DA5}\x{8DA7}' . +'\x{8DA8}\x{8DA9}\x{8DAA}\x{8DAB}\x{8DAC}\x{8DAD}\x{8DAE}\x{8DAF}\x{8DB0}' . +'\x{8DB1}\x{8DB2}\x{8DB3}\x{8DB4}\x{8DB5}\x{8DB6}\x{8DB7}\x{8DB8}\x{8DB9}' . +'\x{8DBA}\x{8DBB}\x{8DBC}\x{8DBD}\x{8DBE}\x{8DBF}\x{8DC1}\x{8DC2}\x{8DC3}' . +'\x{8DC4}\x{8DC5}\x{8DC6}\x{8DC7}\x{8DC8}\x{8DC9}\x{8DCA}\x{8DCB}\x{8DCC}' . +'\x{8DCD}\x{8DCE}\x{8DCF}\x{8DD0}\x{8DD1}\x{8DD2}\x{8DD3}\x{8DD4}\x{8DD5}' . +'\x{8DD6}\x{8DD7}\x{8DD8}\x{8DD9}\x{8DDA}\x{8DDB}\x{8DDC}\x{8DDD}\x{8DDE}' . +'\x{8DDF}\x{8DE0}\x{8DE1}\x{8DE2}\x{8DE3}\x{8DE4}\x{8DE6}\x{8DE7}\x{8DE8}' . +'\x{8DE9}\x{8DEA}\x{8DEB}\x{8DEC}\x{8DED}\x{8DEE}\x{8DEF}\x{8DF0}\x{8DF1}' . +'\x{8DF2}\x{8DF3}\x{8DF4}\x{8DF5}\x{8DF6}\x{8DF7}\x{8DF8}\x{8DF9}\x{8DFA}' . +'\x{8DFB}\x{8DFC}\x{8DFD}\x{8DFE}\x{8DFF}\x{8E00}\x{8E02}\x{8E03}\x{8E04}' . +'\x{8E05}\x{8E06}\x{8E07}\x{8E08}\x{8E09}\x{8E0A}\x{8E0C}\x{8E0D}\x{8E0E}' . +'\x{8E0F}\x{8E10}\x{8E11}\x{8E12}\x{8E13}\x{8E14}\x{8E15}\x{8E16}\x{8E17}' . +'\x{8E18}\x{8E19}\x{8E1A}\x{8E1B}\x{8E1C}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E20}' . +'\x{8E21}\x{8E22}\x{8E23}\x{8E24}\x{8E25}\x{8E26}\x{8E27}\x{8E28}\x{8E29}' . +'\x{8E2A}\x{8E2B}\x{8E2C}\x{8E2D}\x{8E2E}\x{8E2F}\x{8E30}\x{8E31}\x{8E33}' . +'\x{8E34}\x{8E35}\x{8E36}\x{8E37}\x{8E38}\x{8E39}\x{8E3A}\x{8E3B}\x{8E3C}' . +'\x{8E3D}\x{8E3E}\x{8E3F}\x{8E40}\x{8E41}\x{8E42}\x{8E43}\x{8E44}\x{8E45}' . +'\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4B}\x{8E4C}\x{8E4D}\x{8E4E}\x{8E50}' . +'\x{8E51}\x{8E52}\x{8E53}\x{8E54}\x{8E55}\x{8E56}\x{8E57}\x{8E58}\x{8E59}' . +'\x{8E5A}\x{8E5B}\x{8E5C}\x{8E5D}\x{8E5E}\x{8E5F}\x{8E60}\x{8E61}\x{8E62}' . +'\x{8E63}\x{8E64}\x{8E65}\x{8E66}\x{8E67}\x{8E68}\x{8E69}\x{8E6A}\x{8E6B}' . +'\x{8E6C}\x{8E6D}\x{8E6F}\x{8E70}\x{8E71}\x{8E72}\x{8E73}\x{8E74}\x{8E76}' . +'\x{8E78}\x{8E7A}\x{8E7B}\x{8E7C}\x{8E7D}\x{8E7E}\x{8E7F}\x{8E80}\x{8E81}' . +'\x{8E82}\x{8E83}\x{8E84}\x{8E85}\x{8E86}\x{8E87}\x{8E88}\x{8E89}\x{8E8A}' . +'\x{8E8B}\x{8E8C}\x{8E8D}\x{8E8E}\x{8E8F}\x{8E90}\x{8E91}\x{8E92}\x{8E93}' . +'\x{8E94}\x{8E95}\x{8E96}\x{8E97}\x{8E98}\x{8E9A}\x{8E9C}\x{8E9D}\x{8E9E}' . +'\x{8E9F}\x{8EA0}\x{8EA1}\x{8EA3}\x{8EA4}\x{8EA5}\x{8EA6}\x{8EA7}\x{8EA8}' . +'\x{8EA9}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAD}\x{8EAE}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EB2}\x{8EB4}\x{8EB5}\x{8EB8}\x{8EB9}\x{8EBA}\x{8EBB}\x{8EBC}\x{8EBD}' . +'\x{8EBE}\x{8EBF}\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}\x{8EC6}\x{8EC7}\x{8EC8}' . +'\x{8EC9}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ECE}\x{8ECF}\x{8ED0}\x{8ED1}' . +'\x{8ED2}\x{8ED3}\x{8ED4}\x{8ED5}\x{8ED6}\x{8ED7}\x{8ED8}\x{8EDA}\x{8EDB}' . +'\x{8EDC}\x{8EDD}\x{8EDE}\x{8EDF}\x{8EE0}\x{8EE1}\x{8EE4}\x{8EE5}\x{8EE6}' . +'\x{8EE7}\x{8EE8}\x{8EE9}\x{8EEA}\x{8EEB}\x{8EEC}\x{8EED}\x{8EEE}\x{8EEF}' . +'\x{8EF1}\x{8EF2}\x{8EF3}\x{8EF4}\x{8EF5}\x{8EF6}\x{8EF7}\x{8EF8}\x{8EF9}' . +'\x{8EFA}\x{8EFB}\x{8EFC}\x{8EFD}\x{8EFE}\x{8EFF}\x{8F00}\x{8F01}\x{8F02}' . +'\x{8F03}\x{8F04}\x{8F05}\x{8F06}\x{8F07}\x{8F08}\x{8F09}\x{8F0A}\x{8F0B}' . +'\x{8F0D}\x{8F0E}\x{8F10}\x{8F11}\x{8F12}\x{8F13}\x{8F14}\x{8F15}\x{8F16}' . +'\x{8F17}\x{8F18}\x{8F1A}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1E}\x{8F1F}\x{8F20}' . +'\x{8F21}\x{8F22}\x{8F23}\x{8F24}\x{8F25}\x{8F26}\x{8F27}\x{8F28}\x{8F29}' . +'\x{8F2A}\x{8F2B}\x{8F2C}\x{8F2E}\x{8F2F}\x{8F30}\x{8F31}\x{8F32}\x{8F33}' . +'\x{8F34}\x{8F35}\x{8F36}\x{8F37}\x{8F38}\x{8F39}\x{8F3B}\x{8F3C}\x{8F3D}' . +'\x{8F3E}\x{8F3F}\x{8F40}\x{8F42}\x{8F43}\x{8F44}\x{8F45}\x{8F46}\x{8F47}' . +'\x{8F48}\x{8F49}\x{8F4A}\x{8F4B}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F4F}\x{8F50}' . +'\x{8F51}\x{8F52}\x{8F53}\x{8F54}\x{8F55}\x{8F56}\x{8F57}\x{8F58}\x{8F59}' . +'\x{8F5A}\x{8F5B}\x{8F5D}\x{8F5E}\x{8F5F}\x{8F60}\x{8F61}\x{8F62}\x{8F63}' . +'\x{8F64}\x{8F65}\x{8F66}\x{8F67}\x{8F68}\x{8F69}\x{8F6A}\x{8F6B}\x{8F6C}' . +'\x{8F6D}\x{8F6E}\x{8F6F}\x{8F70}\x{8F71}\x{8F72}\x{8F73}\x{8F74}\x{8F75}' . +'\x{8F76}\x{8F77}\x{8F78}\x{8F79}\x{8F7A}\x{8F7B}\x{8F7C}\x{8F7D}\x{8F7E}' . +'\x{8F7F}\x{8F80}\x{8F81}\x{8F82}\x{8F83}\x{8F84}\x{8F85}\x{8F86}\x{8F87}' . +'\x{8F88}\x{8F89}\x{8F8A}\x{8F8B}\x{8F8C}\x{8F8D}\x{8F8E}\x{8F8F}\x{8F90}' . +'\x{8F91}\x{8F92}\x{8F93}\x{8F94}\x{8F95}\x{8F96}\x{8F97}\x{8F98}\x{8F99}' . +'\x{8F9A}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA0}\x{8FA1}\x{8FA2}\x{8FA3}' . +'\x{8FA5}\x{8FA6}\x{8FA7}\x{8FA8}\x{8FA9}\x{8FAA}\x{8FAB}\x{8FAC}\x{8FAD}' . +'\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB4}\x{8FB5}\x{8FB6}\x{8FB7}' . +'\x{8FB8}\x{8FB9}\x{8FBB}\x{8FBC}\x{8FBD}\x{8FBE}\x{8FBF}\x{8FC0}\x{8FC1}' . +'\x{8FC2}\x{8FC4}\x{8FC5}\x{8FC6}\x{8FC7}\x{8FC8}\x{8FC9}\x{8FCB}\x{8FCC}' . +'\x{8FCD}\x{8FCE}\x{8FCF}\x{8FD0}\x{8FD1}\x{8FD2}\x{8FD3}\x{8FD4}\x{8FD5}' . +'\x{8FD6}\x{8FD7}\x{8FD8}\x{8FD9}\x{8FDA}\x{8FDB}\x{8FDC}\x{8FDD}\x{8FDE}' . +'\x{8FDF}\x{8FE0}\x{8FE1}\x{8FE2}\x{8FE3}\x{8FE4}\x{8FE5}\x{8FE6}\x{8FE8}' . +'\x{8FE9}\x{8FEA}\x{8FEB}\x{8FEC}\x{8FED}\x{8FEE}\x{8FEF}\x{8FF0}\x{8FF1}' . +'\x{8FF2}\x{8FF3}\x{8FF4}\x{8FF5}\x{8FF6}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}' . +'\x{8FFB}\x{8FFC}\x{8FFD}\x{8FFE}\x{8FFF}\x{9000}\x{9001}\x{9002}\x{9003}' . +'\x{9004}\x{9005}\x{9006}\x{9007}\x{9008}\x{9009}\x{900A}\x{900B}\x{900C}' . +'\x{900D}\x{900F}\x{9010}\x{9011}\x{9012}\x{9013}\x{9014}\x{9015}\x{9016}' . +'\x{9017}\x{9018}\x{9019}\x{901A}\x{901B}\x{901C}\x{901D}\x{901E}\x{901F}' . +'\x{9020}\x{9021}\x{9022}\x{9023}\x{9024}\x{9025}\x{9026}\x{9027}\x{9028}' . +'\x{9029}\x{902B}\x{902D}\x{902E}\x{902F}\x{9030}\x{9031}\x{9032}\x{9033}' . +'\x{9034}\x{9035}\x{9036}\x{9038}\x{903A}\x{903B}\x{903C}\x{903D}\x{903E}' . +'\x{903F}\x{9041}\x{9042}\x{9043}\x{9044}\x{9045}\x{9047}\x{9048}\x{9049}' . +'\x{904A}\x{904B}\x{904C}\x{904D}\x{904E}\x{904F}\x{9050}\x{9051}\x{9052}' . +'\x{9053}\x{9054}\x{9055}\x{9056}\x{9057}\x{9058}\x{9059}\x{905A}\x{905B}' . +'\x{905C}\x{905D}\x{905E}\x{905F}\x{9060}\x{9061}\x{9062}\x{9063}\x{9064}' . +'\x{9065}\x{9066}\x{9067}\x{9068}\x{9069}\x{906A}\x{906B}\x{906C}\x{906D}' . +'\x{906E}\x{906F}\x{9070}\x{9071}\x{9072}\x{9073}\x{9074}\x{9075}\x{9076}' . +'\x{9077}\x{9078}\x{9079}\x{907A}\x{907B}\x{907C}\x{907D}\x{907E}\x{907F}' . +'\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9085}\x{9086}\x{9087}\x{9088}' . +'\x{9089}\x{908A}\x{908B}\x{908C}\x{908D}\x{908E}\x{908F}\x{9090}\x{9091}' . +'\x{9092}\x{9093}\x{9094}\x{9095}\x{9096}\x{9097}\x{9098}\x{9099}\x{909A}' . +'\x{909B}\x{909C}\x{909D}\x{909E}\x{909F}\x{90A0}\x{90A1}\x{90A2}\x{90A3}' . +'\x{90A4}\x{90A5}\x{90A6}\x{90A7}\x{90A8}\x{90A9}\x{90AA}\x{90AC}\x{90AD}' . +'\x{90AE}\x{90AF}\x{90B0}\x{90B1}\x{90B2}\x{90B3}\x{90B4}\x{90B5}\x{90B6}' . +'\x{90B7}\x{90B8}\x{90B9}\x{90BA}\x{90BB}\x{90BC}\x{90BD}\x{90BE}\x{90BF}' . +'\x{90C0}\x{90C1}\x{90C2}\x{90C3}\x{90C4}\x{90C5}\x{90C6}\x{90C7}\x{90C8}' . +'\x{90C9}\x{90CA}\x{90CB}\x{90CE}\x{90CF}\x{90D0}\x{90D1}\x{90D3}\x{90D4}' . +'\x{90D5}\x{90D6}\x{90D7}\x{90D8}\x{90D9}\x{90DA}\x{90DB}\x{90DC}\x{90DD}' . +'\x{90DE}\x{90DF}\x{90E0}\x{90E1}\x{90E2}\x{90E3}\x{90E4}\x{90E5}\x{90E6}' . +'\x{90E7}\x{90E8}\x{90E9}\x{90EA}\x{90EB}\x{90EC}\x{90ED}\x{90EE}\x{90EF}' . +'\x{90F0}\x{90F1}\x{90F2}\x{90F3}\x{90F4}\x{90F5}\x{90F7}\x{90F8}\x{90F9}' . +'\x{90FA}\x{90FB}\x{90FC}\x{90FD}\x{90FE}\x{90FF}\x{9100}\x{9101}\x{9102}' . +'\x{9103}\x{9104}\x{9105}\x{9106}\x{9107}\x{9108}\x{9109}\x{910B}\x{910C}' . +'\x{910D}\x{910E}\x{910F}\x{9110}\x{9111}\x{9112}\x{9113}\x{9114}\x{9115}' . +'\x{9116}\x{9117}\x{9118}\x{9119}\x{911A}\x{911B}\x{911C}\x{911D}\x{911E}' . +'\x{911F}\x{9120}\x{9121}\x{9122}\x{9123}\x{9124}\x{9125}\x{9126}\x{9127}' . +'\x{9128}\x{9129}\x{912A}\x{912B}\x{912C}\x{912D}\x{912E}\x{912F}\x{9130}' . +'\x{9131}\x{9132}\x{9133}\x{9134}\x{9135}\x{9136}\x{9137}\x{9138}\x{9139}' . +'\x{913A}\x{913B}\x{913E}\x{913F}\x{9140}\x{9141}\x{9142}\x{9143}\x{9144}' . +'\x{9145}\x{9146}\x{9147}\x{9148}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}' . +'\x{914E}\x{914F}\x{9150}\x{9151}\x{9152}\x{9153}\x{9154}\x{9155}\x{9156}' . +'\x{9157}\x{9158}\x{915A}\x{915B}\x{915C}\x{915D}\x{915E}\x{915F}\x{9160}' . +'\x{9161}\x{9162}\x{9163}\x{9164}\x{9165}\x{9166}\x{9167}\x{9168}\x{9169}' . +'\x{916A}\x{916B}\x{916C}\x{916D}\x{916E}\x{916F}\x{9170}\x{9171}\x{9172}' . +'\x{9173}\x{9174}\x{9175}\x{9176}\x{9177}\x{9178}\x{9179}\x{917A}\x{917C}' . +'\x{917D}\x{917E}\x{917F}\x{9180}\x{9181}\x{9182}\x{9183}\x{9184}\x{9185}' . +'\x{9186}\x{9187}\x{9188}\x{9189}\x{918A}\x{918B}\x{918C}\x{918D}\x{918E}' . +'\x{918F}\x{9190}\x{9191}\x{9192}\x{9193}\x{9194}\x{9196}\x{9199}\x{919A}' . +'\x{919B}\x{919C}\x{919D}\x{919E}\x{919F}\x{91A0}\x{91A1}\x{91A2}\x{91A3}' . +'\x{91A5}\x{91A6}\x{91A7}\x{91A8}\x{91AA}\x{91AB}\x{91AC}\x{91AD}\x{91AE}' . +'\x{91AF}\x{91B0}\x{91B1}\x{91B2}\x{91B3}\x{91B4}\x{91B5}\x{91B6}\x{91B7}' . +'\x{91B9}\x{91BA}\x{91BB}\x{91BC}\x{91BD}\x{91BE}\x{91C0}\x{91C1}\x{91C2}' . +'\x{91C3}\x{91C5}\x{91C6}\x{91C7}\x{91C9}\x{91CA}\x{91CB}\x{91CC}\x{91CD}' . +'\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D2}\x{91D3}\x{91D4}\x{91D5}\x{91D7}' . +'\x{91D8}\x{91D9}\x{91DA}\x{91DB}\x{91DC}\x{91DD}\x{91DE}\x{91DF}\x{91E2}' . +'\x{91E3}\x{91E4}\x{91E5}\x{91E6}\x{91E7}\x{91E8}\x{91E9}\x{91EA}\x{91EB}' . +'\x{91EC}\x{91ED}\x{91EE}\x{91F0}\x{91F1}\x{91F2}\x{91F3}\x{91F4}\x{91F5}' . +'\x{91F7}\x{91F8}\x{91F9}\x{91FA}\x{91FB}\x{91FD}\x{91FE}\x{91FF}\x{9200}' . +'\x{9201}\x{9202}\x{9203}\x{9204}\x{9205}\x{9206}\x{9207}\x{9208}\x{9209}' . +'\x{920A}\x{920B}\x{920C}\x{920D}\x{920E}\x{920F}\x{9210}\x{9211}\x{9212}' . +'\x{9214}\x{9215}\x{9216}\x{9217}\x{9218}\x{9219}\x{921A}\x{921B}\x{921C}' . +'\x{921D}\x{921E}\x{9220}\x{9221}\x{9223}\x{9224}\x{9225}\x{9226}\x{9227}' . +'\x{9228}\x{9229}\x{922A}\x{922B}\x{922D}\x{922E}\x{922F}\x{9230}\x{9231}' . +'\x{9232}\x{9233}\x{9234}\x{9235}\x{9236}\x{9237}\x{9238}\x{9239}\x{923A}' . +'\x{923B}\x{923C}\x{923D}\x{923E}\x{923F}\x{9240}\x{9241}\x{9242}\x{9245}' . +'\x{9246}\x{9247}\x{9248}\x{9249}\x{924A}\x{924B}\x{924C}\x{924D}\x{924E}' . +'\x{924F}\x{9250}\x{9251}\x{9252}\x{9253}\x{9254}\x{9255}\x{9256}\x{9257}' . +'\x{9258}\x{9259}\x{925A}\x{925B}\x{925C}\x{925D}\x{925E}\x{925F}\x{9260}' . +'\x{9261}\x{9262}\x{9263}\x{9264}\x{9265}\x{9266}\x{9267}\x{9268}\x{926B}' . +'\x{926C}\x{926D}\x{926E}\x{926F}\x{9270}\x{9272}\x{9273}\x{9274}\x{9275}' . +'\x{9276}\x{9277}\x{9278}\x{9279}\x{927A}\x{927B}\x{927C}\x{927D}\x{927E}' . +'\x{927F}\x{9280}\x{9282}\x{9283}\x{9285}\x{9286}\x{9287}\x{9288}\x{9289}' . +'\x{928A}\x{928B}\x{928C}\x{928D}\x{928E}\x{928F}\x{9290}\x{9291}\x{9292}' . +'\x{9293}\x{9294}\x{9295}\x{9296}\x{9297}\x{9298}\x{9299}\x{929A}\x{929B}' . +'\x{929C}\x{929D}\x{929F}\x{92A0}\x{92A1}\x{92A2}\x{92A3}\x{92A4}\x{92A5}' . +'\x{92A6}\x{92A7}\x{92A8}\x{92A9}\x{92AA}\x{92AB}\x{92AC}\x{92AD}\x{92AE}' . +'\x{92AF}\x{92B0}\x{92B1}\x{92B2}\x{92B3}\x{92B4}\x{92B5}\x{92B6}\x{92B7}' . +'\x{92B8}\x{92B9}\x{92BA}\x{92BB}\x{92BC}\x{92BE}\x{92BF}\x{92C0}\x{92C1}' . +'\x{92C2}\x{92C3}\x{92C4}\x{92C5}\x{92C6}\x{92C7}\x{92C8}\x{92C9}\x{92CA}' . +'\x{92CB}\x{92CC}\x{92CD}\x{92CE}\x{92CF}\x{92D0}\x{92D1}\x{92D2}\x{92D3}' . +'\x{92D5}\x{92D6}\x{92D7}\x{92D8}\x{92D9}\x{92DA}\x{92DC}\x{92DD}\x{92DE}' . +'\x{92DF}\x{92E0}\x{92E1}\x{92E3}\x{92E4}\x{92E5}\x{92E6}\x{92E7}\x{92E8}' . +'\x{92E9}\x{92EA}\x{92EB}\x{92EC}\x{92ED}\x{92EE}\x{92EF}\x{92F0}\x{92F1}' . +'\x{92F2}\x{92F3}\x{92F4}\x{92F5}\x{92F6}\x{92F7}\x{92F8}\x{92F9}\x{92FA}' . +'\x{92FB}\x{92FC}\x{92FD}\x{92FE}\x{92FF}\x{9300}\x{9301}\x{9302}\x{9303}' . +'\x{9304}\x{9305}\x{9306}\x{9307}\x{9308}\x{9309}\x{930A}\x{930B}\x{930C}' . +'\x{930D}\x{930E}\x{930F}\x{9310}\x{9311}\x{9312}\x{9313}\x{9314}\x{9315}' . +'\x{9316}\x{9317}\x{9318}\x{9319}\x{931A}\x{931B}\x{931D}\x{931E}\x{931F}' . +'\x{9320}\x{9321}\x{9322}\x{9323}\x{9324}\x{9325}\x{9326}\x{9327}\x{9328}' . +'\x{9329}\x{932A}\x{932B}\x{932D}\x{932E}\x{932F}\x{9332}\x{9333}\x{9334}' . +'\x{9335}\x{9336}\x{9337}\x{9338}\x{9339}\x{933A}\x{933B}\x{933C}\x{933D}' . +'\x{933E}\x{933F}\x{9340}\x{9341}\x{9342}\x{9343}\x{9344}\x{9345}\x{9346}' . +'\x{9347}\x{9348}\x{9349}\x{934A}\x{934B}\x{934C}\x{934D}\x{934E}\x{934F}' . +'\x{9350}\x{9351}\x{9352}\x{9353}\x{9354}\x{9355}\x{9356}\x{9357}\x{9358}' . +'\x{9359}\x{935A}\x{935B}\x{935C}\x{935D}\x{935E}\x{935F}\x{9360}\x{9361}' . +'\x{9363}\x{9364}\x{9365}\x{9366}\x{9367}\x{9369}\x{936A}\x{936C}\x{936D}' . +'\x{936E}\x{9370}\x{9371}\x{9372}\x{9374}\x{9375}\x{9376}\x{9377}\x{9379}' . +'\x{937A}\x{937B}\x{937C}\x{937D}\x{937E}\x{9380}\x{9382}\x{9383}\x{9384}' . +'\x{9385}\x{9386}\x{9387}\x{9388}\x{9389}\x{938A}\x{938C}\x{938D}\x{938E}' . +'\x{938F}\x{9390}\x{9391}\x{9392}\x{9393}\x{9394}\x{9395}\x{9396}\x{9397}' . +'\x{9398}\x{9399}\x{939A}\x{939B}\x{939D}\x{939E}\x{939F}\x{93A1}\x{93A2}' . +'\x{93A3}\x{93A4}\x{93A5}\x{93A6}\x{93A7}\x{93A8}\x{93A9}\x{93AA}\x{93AC}' . +'\x{93AD}\x{93AE}\x{93AF}\x{93B0}\x{93B1}\x{93B2}\x{93B3}\x{93B4}\x{93B5}' . +'\x{93B6}\x{93B7}\x{93B8}\x{93B9}\x{93BA}\x{93BC}\x{93BD}\x{93BE}\x{93BF}' . +'\x{93C0}\x{93C1}\x{93C2}\x{93C3}\x{93C4}\x{93C5}\x{93C6}\x{93C7}\x{93C8}' . +'\x{93C9}\x{93CA}\x{93CB}\x{93CC}\x{93CD}\x{93CE}\x{93CF}\x{93D0}\x{93D1}' . +'\x{93D2}\x{93D3}\x{93D4}\x{93D5}\x{93D6}\x{93D7}\x{93D8}\x{93D9}\x{93DA}' . +'\x{93DB}\x{93DC}\x{93DD}\x{93DE}\x{93DF}\x{93E1}\x{93E2}\x{93E3}\x{93E4}' . +'\x{93E6}\x{93E7}\x{93E8}\x{93E9}\x{93EA}\x{93EB}\x{93EC}\x{93ED}\x{93EE}' . +'\x{93EF}\x{93F0}\x{93F1}\x{93F2}\x{93F4}\x{93F5}\x{93F6}\x{93F7}\x{93F8}' . +'\x{93F9}\x{93FA}\x{93FB}\x{93FC}\x{93FD}\x{93FE}\x{93FF}\x{9400}\x{9401}' . +'\x{9403}\x{9404}\x{9405}\x{9406}\x{9407}\x{9408}\x{9409}\x{940A}\x{940B}' . +'\x{940C}\x{940D}\x{940E}\x{940F}\x{9410}\x{9411}\x{9412}\x{9413}\x{9414}' . +'\x{9415}\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}\x{9422}\x{9423}' . +'\x{9425}\x{9426}\x{9427}\x{9428}\x{9429}\x{942A}\x{942B}\x{942C}\x{942D}' . +'\x{942E}\x{942F}\x{9430}\x{9431}\x{9432}\x{9433}\x{9434}\x{9435}\x{9436}' . +'\x{9437}\x{9438}\x{9439}\x{943A}\x{943B}\x{943C}\x{943D}\x{943E}\x{943F}' . +'\x{9440}\x{9441}\x{9442}\x{9444}\x{9445}\x{9446}\x{9447}\x{9448}\x{9449}' . +'\x{944A}\x{944B}\x{944C}\x{944D}\x{944F}\x{9450}\x{9451}\x{9452}\x{9453}' . +'\x{9454}\x{9455}\x{9456}\x{9457}\x{9458}\x{9459}\x{945B}\x{945C}\x{945D}' . +'\x{945E}\x{945F}\x{9460}\x{9461}\x{9462}\x{9463}\x{9464}\x{9465}\x{9466}' . +'\x{9467}\x{9468}\x{9469}\x{946A}\x{946B}\x{946D}\x{946E}\x{946F}\x{9470}' . +'\x{9471}\x{9472}\x{9473}\x{9474}\x{9475}\x{9476}\x{9477}\x{9478}\x{9479}' . +'\x{947A}\x{947C}\x{947D}\x{947E}\x{947F}\x{9480}\x{9481}\x{9482}\x{9483}' . +'\x{9484}\x{9485}\x{9486}\x{9487}\x{9488}\x{9489}\x{948A}\x{948B}\x{948C}' . +'\x{948D}\x{948E}\x{948F}\x{9490}\x{9491}\x{9492}\x{9493}\x{9494}\x{9495}' . +'\x{9496}\x{9497}\x{9498}\x{9499}\x{949A}\x{949B}\x{949C}\x{949D}\x{949E}' . +'\x{949F}\x{94A0}\x{94A1}\x{94A2}\x{94A3}\x{94A4}\x{94A5}\x{94A6}\x{94A7}' . +'\x{94A8}\x{94A9}\x{94AA}\x{94AB}\x{94AC}\x{94AD}\x{94AE}\x{94AF}\x{94B0}' . +'\x{94B1}\x{94B2}\x{94B3}\x{94B4}\x{94B5}\x{94B6}\x{94B7}\x{94B8}\x{94B9}' . +'\x{94BA}\x{94BB}\x{94BC}\x{94BD}\x{94BE}\x{94BF}\x{94C0}\x{94C1}\x{94C2}' . +'\x{94C3}\x{94C4}\x{94C5}\x{94C6}\x{94C7}\x{94C8}\x{94C9}\x{94CA}\x{94CB}' . +'\x{94CC}\x{94CD}\x{94CE}\x{94CF}\x{94D0}\x{94D1}\x{94D2}\x{94D3}\x{94D4}' . +'\x{94D5}\x{94D6}\x{94D7}\x{94D8}\x{94D9}\x{94DA}\x{94DB}\x{94DC}\x{94DD}' . +'\x{94DE}\x{94DF}\x{94E0}\x{94E1}\x{94E2}\x{94E3}\x{94E4}\x{94E5}\x{94E6}' . +'\x{94E7}\x{94E8}\x{94E9}\x{94EA}\x{94EB}\x{94EC}\x{94ED}\x{94EE}\x{94EF}' . +'\x{94F0}\x{94F1}\x{94F2}\x{94F3}\x{94F4}\x{94F5}\x{94F6}\x{94F7}\x{94F8}' . +'\x{94F9}\x{94FA}\x{94FB}\x{94FC}\x{94FD}\x{94FE}\x{94FF}\x{9500}\x{9501}' . +'\x{9502}\x{9503}\x{9504}\x{9505}\x{9506}\x{9507}\x{9508}\x{9509}\x{950A}' . +'\x{950B}\x{950C}\x{950D}\x{950E}\x{950F}\x{9510}\x{9511}\x{9512}\x{9513}' . +'\x{9514}\x{9515}\x{9516}\x{9517}\x{9518}\x{9519}\x{951A}\x{951B}\x{951C}' . +'\x{951D}\x{951E}\x{951F}\x{9520}\x{9521}\x{9522}\x{9523}\x{9524}\x{9525}' . +'\x{9526}\x{9527}\x{9528}\x{9529}\x{952A}\x{952B}\x{952C}\x{952D}\x{952E}' . +'\x{952F}\x{9530}\x{9531}\x{9532}\x{9533}\x{9534}\x{9535}\x{9536}\x{9537}' . +'\x{9538}\x{9539}\x{953A}\x{953B}\x{953C}\x{953D}\x{953E}\x{953F}\x{9540}' . +'\x{9541}\x{9542}\x{9543}\x{9544}\x{9545}\x{9546}\x{9547}\x{9548}\x{9549}' . +'\x{954A}\x{954B}\x{954C}\x{954D}\x{954E}\x{954F}\x{9550}\x{9551}\x{9552}' . +'\x{9553}\x{9554}\x{9555}\x{9556}\x{9557}\x{9558}\x{9559}\x{955A}\x{955B}' . +'\x{955C}\x{955D}\x{955E}\x{955F}\x{9560}\x{9561}\x{9562}\x{9563}\x{9564}' . +'\x{9565}\x{9566}\x{9567}\x{9568}\x{9569}\x{956A}\x{956B}\x{956C}\x{956D}' . +'\x{956E}\x{956F}\x{9570}\x{9571}\x{9572}\x{9573}\x{9574}\x{9575}\x{9576}' . +'\x{9577}\x{957A}\x{957B}\x{957C}\x{957D}\x{957F}\x{9580}\x{9581}\x{9582}' . +'\x{9583}\x{9584}\x{9586}\x{9587}\x{9588}\x{9589}\x{958A}\x{958B}\x{958C}' . +'\x{958D}\x{958E}\x{958F}\x{9590}\x{9591}\x{9592}\x{9593}\x{9594}\x{9595}' . +'\x{9596}\x{9598}\x{9599}\x{959A}\x{959B}\x{959C}\x{959D}\x{959E}\x{959F}' . +'\x{95A1}\x{95A2}\x{95A3}\x{95A4}\x{95A5}\x{95A6}\x{95A7}\x{95A8}\x{95A9}' . +'\x{95AA}\x{95AB}\x{95AC}\x{95AD}\x{95AE}\x{95AF}\x{95B0}\x{95B1}\x{95B2}' . +'\x{95B5}\x{95B6}\x{95B7}\x{95B9}\x{95BA}\x{95BB}\x{95BC}\x{95BD}\x{95BE}' . +'\x{95BF}\x{95C0}\x{95C2}\x{95C3}\x{95C4}\x{95C5}\x{95C6}\x{95C7}\x{95C8}' . +'\x{95C9}\x{95CA}\x{95CB}\x{95CC}\x{95CD}\x{95CE}\x{95CF}\x{95D0}\x{95D1}' . +'\x{95D2}\x{95D3}\x{95D4}\x{95D5}\x{95D6}\x{95D7}\x{95D8}\x{95DA}\x{95DB}' . +'\x{95DC}\x{95DE}\x{95DF}\x{95E0}\x{95E1}\x{95E2}\x{95E3}\x{95E4}\x{95E5}' . +'\x{95E6}\x{95E7}\x{95E8}\x{95E9}\x{95EA}\x{95EB}\x{95EC}\x{95ED}\x{95EE}' . +'\x{95EF}\x{95F0}\x{95F1}\x{95F2}\x{95F3}\x{95F4}\x{95F5}\x{95F6}\x{95F7}' . +'\x{95F8}\x{95F9}\x{95FA}\x{95FB}\x{95FC}\x{95FD}\x{95FE}\x{95FF}\x{9600}' . +'\x{9601}\x{9602}\x{9603}\x{9604}\x{9605}\x{9606}\x{9607}\x{9608}\x{9609}' . +'\x{960A}\x{960B}\x{960C}\x{960D}\x{960E}\x{960F}\x{9610}\x{9611}\x{9612}' . +'\x{9613}\x{9614}\x{9615}\x{9616}\x{9617}\x{9618}\x{9619}\x{961A}\x{961B}' . +'\x{961C}\x{961D}\x{961E}\x{961F}\x{9620}\x{9621}\x{9622}\x{9623}\x{9624}' . +'\x{9627}\x{9628}\x{962A}\x{962B}\x{962C}\x{962D}\x{962E}\x{962F}\x{9630}' . +'\x{9631}\x{9632}\x{9633}\x{9634}\x{9635}\x{9636}\x{9637}\x{9638}\x{9639}' . +'\x{963A}\x{963B}\x{963C}\x{963D}\x{963F}\x{9640}\x{9641}\x{9642}\x{9643}' . +'\x{9644}\x{9645}\x{9646}\x{9647}\x{9648}\x{9649}\x{964A}\x{964B}\x{964C}' . +'\x{964D}\x{964E}\x{964F}\x{9650}\x{9651}\x{9652}\x{9653}\x{9654}\x{9655}' . +'\x{9658}\x{9659}\x{965A}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9660}' . +'\x{9661}\x{9662}\x{9663}\x{9664}\x{9666}\x{9667}\x{9668}\x{9669}\x{966A}' . +'\x{966B}\x{966C}\x{966D}\x{966E}\x{966F}\x{9670}\x{9671}\x{9672}\x{9673}' . +'\x{9674}\x{9675}\x{9676}\x{9677}\x{9678}\x{967C}\x{967D}\x{967E}\x{9680}' . +'\x{9683}\x{9684}\x{9685}\x{9686}\x{9687}\x{9688}\x{9689}\x{968A}\x{968B}' . +'\x{968D}\x{968E}\x{968F}\x{9690}\x{9691}\x{9692}\x{9693}\x{9694}\x{9695}' . +'\x{9697}\x{9698}\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}\x{96A1}\x{96A2}' . +'\x{96A3}\x{96A4}\x{96A5}\x{96A6}\x{96A7}\x{96A8}\x{96A9}\x{96AA}\x{96AC}' . +'\x{96AD}\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}\x{96B7}\x{96B8}' . +'\x{96B9}\x{96BA}\x{96BB}\x{96BC}\x{96BD}\x{96BE}\x{96BF}\x{96C0}\x{96C1}' . +'\x{96C2}\x{96C3}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C8}\x{96C9}\x{96CA}' . +'\x{96CB}\x{96CC}\x{96CD}\x{96CE}\x{96CF}\x{96D0}\x{96D1}\x{96D2}\x{96D3}' . +'\x{96D4}\x{96D5}\x{96D6}\x{96D7}\x{96D8}\x{96D9}\x{96DA}\x{96DB}\x{96DC}' . +'\x{96DD}\x{96DE}\x{96DF}\x{96E0}\x{96E1}\x{96E2}\x{96E3}\x{96E5}\x{96E8}' . +'\x{96E9}\x{96EA}\x{96EB}\x{96EC}\x{96ED}\x{96EE}\x{96EF}\x{96F0}\x{96F1}' . +'\x{96F2}\x{96F3}\x{96F4}\x{96F5}\x{96F6}\x{96F7}\x{96F8}\x{96F9}\x{96FA}' . +'\x{96FB}\x{96FD}\x{96FE}\x{96FF}\x{9700}\x{9701}\x{9702}\x{9703}\x{9704}' . +'\x{9705}\x{9706}\x{9707}\x{9708}\x{9709}\x{970A}\x{970B}\x{970C}\x{970D}' . +'\x{970E}\x{970F}\x{9710}\x{9711}\x{9712}\x{9713}\x{9715}\x{9716}\x{9718}' . +'\x{9719}\x{971C}\x{971D}\x{971E}\x{971F}\x{9720}\x{9721}\x{9722}\x{9723}' . +'\x{9724}\x{9725}\x{9726}\x{9727}\x{9728}\x{9729}\x{972A}\x{972B}\x{972C}' . +'\x{972D}\x{972E}\x{972F}\x{9730}\x{9731}\x{9732}\x{9735}\x{9736}\x{9738}' . +'\x{9739}\x{973A}\x{973B}\x{973C}\x{973D}\x{973E}\x{973F}\x{9742}\x{9743}' . +'\x{9744}\x{9745}\x{9746}\x{9747}\x{9748}\x{9749}\x{974A}\x{974B}\x{974C}' . +'\x{974E}\x{974F}\x{9750}\x{9751}\x{9752}\x{9753}\x{9754}\x{9755}\x{9756}' . +'\x{9758}\x{9759}\x{975A}\x{975B}\x{975C}\x{975D}\x{975E}\x{975F}\x{9760}' . +'\x{9761}\x{9762}\x{9765}\x{9766}\x{9767}\x{9768}\x{9769}\x{976A}\x{976B}' . +'\x{976C}\x{976D}\x{976E}\x{976F}\x{9770}\x{9772}\x{9773}\x{9774}\x{9776}' . +'\x{9777}\x{9778}\x{9779}\x{977A}\x{977B}\x{977C}\x{977D}\x{977E}\x{977F}' . +'\x{9780}\x{9781}\x{9782}\x{9783}\x{9784}\x{9785}\x{9786}\x{9788}\x{978A}' . +'\x{978B}\x{978C}\x{978D}\x{978E}\x{978F}\x{9790}\x{9791}\x{9792}\x{9793}' . +'\x{9794}\x{9795}\x{9796}\x{9797}\x{9798}\x{9799}\x{979A}\x{979C}\x{979D}' . +'\x{979E}\x{979F}\x{97A0}\x{97A1}\x{97A2}\x{97A3}\x{97A4}\x{97A5}\x{97A6}' . +'\x{97A7}\x{97A8}\x{97AA}\x{97AB}\x{97AC}\x{97AD}\x{97AE}\x{97AF}\x{97B2}' . +'\x{97B3}\x{97B4}\x{97B6}\x{97B7}\x{97B8}\x{97B9}\x{97BA}\x{97BB}\x{97BC}' . +'\x{97BD}\x{97BF}\x{97C1}\x{97C2}\x{97C3}\x{97C4}\x{97C5}\x{97C6}\x{97C7}' . +'\x{97C8}\x{97C9}\x{97CA}\x{97CB}\x{97CC}\x{97CD}\x{97CE}\x{97CF}\x{97D0}' . +'\x{97D1}\x{97D3}\x{97D4}\x{97D5}\x{97D6}\x{97D7}\x{97D8}\x{97D9}\x{97DA}' . +'\x{97DB}\x{97DC}\x{97DD}\x{97DE}\x{97DF}\x{97E0}\x{97E1}\x{97E2}\x{97E3}' . +'\x{97E4}\x{97E5}\x{97E6}\x{97E7}\x{97E8}\x{97E9}\x{97EA}\x{97EB}\x{97EC}' . +'\x{97ED}\x{97EE}\x{97EF}\x{97F0}\x{97F1}\x{97F2}\x{97F3}\x{97F4}\x{97F5}' . +'\x{97F6}\x{97F7}\x{97F8}\x{97F9}\x{97FA}\x{97FB}\x{97FD}\x{97FE}\x{97FF}' . +'\x{9800}\x{9801}\x{9802}\x{9803}\x{9804}\x{9805}\x{9806}\x{9807}\x{9808}' . +'\x{9809}\x{980A}\x{980B}\x{980C}\x{980D}\x{980E}\x{980F}\x{9810}\x{9811}' . +'\x{9812}\x{9813}\x{9814}\x{9815}\x{9816}\x{9817}\x{9818}\x{9819}\x{981A}' . +'\x{981B}\x{981C}\x{981D}\x{981E}\x{9820}\x{9821}\x{9822}\x{9823}\x{9824}' . +'\x{9826}\x{9827}\x{9828}\x{9829}\x{982B}\x{982D}\x{982E}\x{982F}\x{9830}' . +'\x{9831}\x{9832}\x{9834}\x{9835}\x{9836}\x{9837}\x{9838}\x{9839}\x{983B}' . +'\x{983C}\x{983D}\x{983F}\x{9840}\x{9841}\x{9843}\x{9844}\x{9845}\x{9846}' . +'\x{9848}\x{9849}\x{984A}\x{984C}\x{984D}\x{984E}\x{984F}\x{9850}\x{9851}' . +'\x{9852}\x{9853}\x{9854}\x{9855}\x{9857}\x{9858}\x{9859}\x{985A}\x{985B}' . +'\x{985C}\x{985D}\x{985E}\x{985F}\x{9860}\x{9861}\x{9862}\x{9863}\x{9864}' . +'\x{9865}\x{9867}\x{9869}\x{986A}\x{986B}\x{986C}\x{986D}\x{986E}\x{986F}' . +'\x{9870}\x{9871}\x{9872}\x{9873}\x{9874}\x{9875}\x{9876}\x{9877}\x{9878}' . +'\x{9879}\x{987A}\x{987B}\x{987C}\x{987D}\x{987E}\x{987F}\x{9880}\x{9881}' . +'\x{9882}\x{9883}\x{9884}\x{9885}\x{9886}\x{9887}\x{9888}\x{9889}\x{988A}' . +'\x{988B}\x{988C}\x{988D}\x{988E}\x{988F}\x{9890}\x{9891}\x{9892}\x{9893}' . +'\x{9894}\x{9895}\x{9896}\x{9897}\x{9898}\x{9899}\x{989A}\x{989B}\x{989C}' . +'\x{989D}\x{989E}\x{989F}\x{98A0}\x{98A1}\x{98A2}\x{98A3}\x{98A4}\x{98A5}' . +'\x{98A6}\x{98A7}\x{98A8}\x{98A9}\x{98AA}\x{98AB}\x{98AC}\x{98AD}\x{98AE}' . +'\x{98AF}\x{98B0}\x{98B1}\x{98B2}\x{98B3}\x{98B4}\x{98B5}\x{98B6}\x{98B8}' . +'\x{98B9}\x{98BA}\x{98BB}\x{98BC}\x{98BD}\x{98BE}\x{98BF}\x{98C0}\x{98C1}' . +'\x{98C2}\x{98C3}\x{98C4}\x{98C5}\x{98C6}\x{98C8}\x{98C9}\x{98CB}\x{98CC}' . +'\x{98CD}\x{98CE}\x{98CF}\x{98D0}\x{98D1}\x{98D2}\x{98D3}\x{98D4}\x{98D5}' . +'\x{98D6}\x{98D7}\x{98D8}\x{98D9}\x{98DA}\x{98DB}\x{98DC}\x{98DD}\x{98DE}' . +'\x{98DF}\x{98E0}\x{98E2}\x{98E3}\x{98E5}\x{98E6}\x{98E7}\x{98E8}\x{98E9}' . +'\x{98EA}\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}\x{98F3}\x{98F4}\x{98F5}' . +'\x{98F6}\x{98F7}\x{98F9}\x{98FA}\x{98FC}\x{98FD}\x{98FE}\x{98FF}\x{9900}' . +'\x{9901}\x{9902}\x{9903}\x{9904}\x{9905}\x{9906}\x{9907}\x{9908}\x{9909}' . +'\x{990A}\x{990B}\x{990C}\x{990D}\x{990E}\x{990F}\x{9910}\x{9911}\x{9912}' . +'\x{9913}\x{9914}\x{9915}\x{9916}\x{9917}\x{9918}\x{991A}\x{991B}\x{991C}' . +'\x{991D}\x{991E}\x{991F}\x{9920}\x{9921}\x{9922}\x{9923}\x{9924}\x{9925}' . +'\x{9926}\x{9927}\x{9928}\x{9929}\x{992A}\x{992B}\x{992C}\x{992D}\x{992E}' . +'\x{992F}\x{9930}\x{9931}\x{9932}\x{9933}\x{9934}\x{9935}\x{9936}\x{9937}' . +'\x{9938}\x{9939}\x{993A}\x{993C}\x{993D}\x{993E}\x{993F}\x{9940}\x{9941}' . +'\x{9942}\x{9943}\x{9945}\x{9946}\x{9947}\x{9948}\x{9949}\x{994A}\x{994B}' . +'\x{994C}\x{994E}\x{994F}\x{9950}\x{9951}\x{9952}\x{9953}\x{9954}\x{9955}' . +'\x{9956}\x{9957}\x{9958}\x{9959}\x{995B}\x{995C}\x{995E}\x{995F}\x{9960}' . +'\x{9961}\x{9962}\x{9963}\x{9964}\x{9965}\x{9966}\x{9967}\x{9968}\x{9969}' . +'\x{996A}\x{996B}\x{996C}\x{996D}\x{996E}\x{996F}\x{9970}\x{9971}\x{9972}' . +'\x{9973}\x{9974}\x{9975}\x{9976}\x{9977}\x{9978}\x{9979}\x{997A}\x{997B}' . +'\x{997C}\x{997D}\x{997E}\x{997F}\x{9980}\x{9981}\x{9982}\x{9983}\x{9984}' . +'\x{9985}\x{9986}\x{9987}\x{9988}\x{9989}\x{998A}\x{998B}\x{998C}\x{998D}' . +'\x{998E}\x{998F}\x{9990}\x{9991}\x{9992}\x{9993}\x{9994}\x{9995}\x{9996}' . +'\x{9997}\x{9998}\x{9999}\x{999A}\x{999B}\x{999C}\x{999D}\x{999E}\x{999F}' . +'\x{99A0}\x{99A1}\x{99A2}\x{99A3}\x{99A4}\x{99A5}\x{99A6}\x{99A7}\x{99A8}' . +'\x{99A9}\x{99AA}\x{99AB}\x{99AC}\x{99AD}\x{99AE}\x{99AF}\x{99B0}\x{99B1}' . +'\x{99B2}\x{99B3}\x{99B4}\x{99B5}\x{99B6}\x{99B7}\x{99B8}\x{99B9}\x{99BA}' . +'\x{99BB}\x{99BC}\x{99BD}\x{99BE}\x{99C0}\x{99C1}\x{99C2}\x{99C3}\x{99C4}' . +'\x{99C6}\x{99C7}\x{99C8}\x{99C9}\x{99CA}\x{99CB}\x{99CC}\x{99CD}\x{99CE}' . +'\x{99CF}\x{99D0}\x{99D1}\x{99D2}\x{99D3}\x{99D4}\x{99D5}\x{99D6}\x{99D7}' . +'\x{99D8}\x{99D9}\x{99DA}\x{99DB}\x{99DC}\x{99DD}\x{99DE}\x{99DF}\x{99E1}' . +'\x{99E2}\x{99E3}\x{99E4}\x{99E5}\x{99E7}\x{99E8}\x{99E9}\x{99EA}\x{99EC}' . +'\x{99ED}\x{99EE}\x{99EF}\x{99F0}\x{99F1}\x{99F2}\x{99F3}\x{99F4}\x{99F6}' . +'\x{99F7}\x{99F8}\x{99F9}\x{99FA}\x{99FB}\x{99FC}\x{99FD}\x{99FE}\x{99FF}' . +'\x{9A00}\x{9A01}\x{9A02}\x{9A03}\x{9A04}\x{9A05}\x{9A06}\x{9A07}\x{9A08}' . +'\x{9A09}\x{9A0A}\x{9A0B}\x{9A0C}\x{9A0D}\x{9A0E}\x{9A0F}\x{9A11}\x{9A14}' . +'\x{9A15}\x{9A16}\x{9A19}\x{9A1A}\x{9A1B}\x{9A1C}\x{9A1D}\x{9A1E}\x{9A1F}' . +'\x{9A20}\x{9A21}\x{9A22}\x{9A23}\x{9A24}\x{9A25}\x{9A26}\x{9A27}\x{9A29}' . +'\x{9A2A}\x{9A2B}\x{9A2C}\x{9A2D}\x{9A2E}\x{9A2F}\x{9A30}\x{9A31}\x{9A32}' . +'\x{9A33}\x{9A34}\x{9A35}\x{9A36}\x{9A37}\x{9A38}\x{9A39}\x{9A3A}\x{9A3C}' . +'\x{9A3D}\x{9A3E}\x{9A3F}\x{9A40}\x{9A41}\x{9A42}\x{9A43}\x{9A44}\x{9A45}' . +'\x{9A46}\x{9A47}\x{9A48}\x{9A49}\x{9A4A}\x{9A4B}\x{9A4C}\x{9A4D}\x{9A4E}' . +'\x{9A4F}\x{9A50}\x{9A52}\x{9A53}\x{9A54}\x{9A55}\x{9A56}\x{9A57}\x{9A59}' . +'\x{9A5A}\x{9A5B}\x{9A5C}\x{9A5E}\x{9A5F}\x{9A60}\x{9A61}\x{9A62}\x{9A64}' . +'\x{9A65}\x{9A66}\x{9A67}\x{9A68}\x{9A69}\x{9A6A}\x{9A6B}\x{9A6C}\x{9A6D}' . +'\x{9A6E}\x{9A6F}\x{9A70}\x{9A71}\x{9A72}\x{9A73}\x{9A74}\x{9A75}\x{9A76}' . +'\x{9A77}\x{9A78}\x{9A79}\x{9A7A}\x{9A7B}\x{9A7C}\x{9A7D}\x{9A7E}\x{9A7F}' . +'\x{9A80}\x{9A81}\x{9A82}\x{9A83}\x{9A84}\x{9A85}\x{9A86}\x{9A87}\x{9A88}' . +'\x{9A89}\x{9A8A}\x{9A8B}\x{9A8C}\x{9A8D}\x{9A8E}\x{9A8F}\x{9A90}\x{9A91}' . +'\x{9A92}\x{9A93}\x{9A94}\x{9A95}\x{9A96}\x{9A97}\x{9A98}\x{9A99}\x{9A9A}' . +'\x{9A9B}\x{9A9C}\x{9A9D}\x{9A9E}\x{9A9F}\x{9AA0}\x{9AA1}\x{9AA2}\x{9AA3}' . +'\x{9AA4}\x{9AA5}\x{9AA6}\x{9AA7}\x{9AA8}\x{9AAA}\x{9AAB}\x{9AAC}\x{9AAD}' . +'\x{9AAE}\x{9AAF}\x{9AB0}\x{9AB1}\x{9AB2}\x{9AB3}\x{9AB4}\x{9AB5}\x{9AB6}' . +'\x{9AB7}\x{9AB8}\x{9AB9}\x{9ABA}\x{9ABB}\x{9ABC}\x{9ABE}\x{9ABF}\x{9AC0}' . +'\x{9AC1}\x{9AC2}\x{9AC3}\x{9AC4}\x{9AC5}\x{9AC6}\x{9AC7}\x{9AC9}\x{9ACA}' . +'\x{9ACB}\x{9ACC}\x{9ACD}\x{9ACE}\x{9ACF}\x{9AD0}\x{9AD1}\x{9AD2}\x{9AD3}' . +'\x{9AD4}\x{9AD5}\x{9AD6}\x{9AD8}\x{9AD9}\x{9ADA}\x{9ADB}\x{9ADC}\x{9ADD}' . +'\x{9ADE}\x{9ADF}\x{9AE1}\x{9AE2}\x{9AE3}\x{9AE5}\x{9AE6}\x{9AE7}\x{9AEA}' . +'\x{9AEB}\x{9AEC}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF2}\x{9AF3}\x{9AF4}' . +'\x{9AF5}\x{9AF6}\x{9AF7}\x{9AF8}\x{9AF9}\x{9AFA}\x{9AFB}\x{9AFC}\x{9AFD}' . +'\x{9AFE}\x{9AFF}\x{9B01}\x{9B03}\x{9B04}\x{9B05}\x{9B06}\x{9B07}\x{9B08}' . +'\x{9B0A}\x{9B0B}\x{9B0C}\x{9B0D}\x{9B0E}\x{9B0F}\x{9B10}\x{9B11}\x{9B12}' . +'\x{9B13}\x{9B15}\x{9B16}\x{9B17}\x{9B18}\x{9B19}\x{9B1A}\x{9B1C}\x{9B1D}' . +'\x{9B1E}\x{9B1F}\x{9B20}\x{9B21}\x{9B22}\x{9B23}\x{9B24}\x{9B25}\x{9B26}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2B}\x{9B2C}\x{9B2D}\x{9B2E}\x{9B2F}' . +'\x{9B30}\x{9B31}\x{9B32}\x{9B33}\x{9B35}\x{9B36}\x{9B37}\x{9B38}\x{9B39}' . +'\x{9B3A}\x{9B3B}\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}\x{9B42}\x{9B43}\x{9B44}' . +'\x{9B45}\x{9B46}\x{9B47}\x{9B48}\x{9B49}\x{9B4A}\x{9B4B}\x{9B4C}\x{9B4D}' . +'\x{9B4E}\x{9B4F}\x{9B51}\x{9B52}\x{9B53}\x{9B54}\x{9B55}\x{9B56}\x{9B58}' . +'\x{9B59}\x{9B5A}\x{9B5B}\x{9B5C}\x{9B5D}\x{9B5E}\x{9B5F}\x{9B60}\x{9B61}' . +'\x{9B63}\x{9B64}\x{9B65}\x{9B66}\x{9B67}\x{9B68}\x{9B69}\x{9B6A}\x{9B6B}' . +'\x{9B6C}\x{9B6D}\x{9B6E}\x{9B6F}\x{9B70}\x{9B71}\x{9B73}\x{9B74}\x{9B75}' . +'\x{9B76}\x{9B77}\x{9B78}\x{9B79}\x{9B7A}\x{9B7B}\x{9B7C}\x{9B7D}\x{9B7E}' . +'\x{9B7F}\x{9B80}\x{9B81}\x{9B82}\x{9B83}\x{9B84}\x{9B85}\x{9B86}\x{9B87}' . +'\x{9B88}\x{9B8A}\x{9B8B}\x{9B8D}\x{9B8E}\x{9B8F}\x{9B90}\x{9B91}\x{9B92}' . +'\x{9B93}\x{9B94}\x{9B95}\x{9B96}\x{9B97}\x{9B98}\x{9B9A}\x{9B9B}\x{9B9C}' . +'\x{9B9D}\x{9B9E}\x{9B9F}\x{9BA0}\x{9BA1}\x{9BA2}\x{9BA3}\x{9BA4}\x{9BA5}' . +'\x{9BA6}\x{9BA7}\x{9BA8}\x{9BA9}\x{9BAA}\x{9BAB}\x{9BAC}\x{9BAD}\x{9BAE}' . +'\x{9BAF}\x{9BB0}\x{9BB1}\x{9BB2}\x{9BB3}\x{9BB4}\x{9BB5}\x{9BB6}\x{9BB7}' . +'\x{9BB8}\x{9BB9}\x{9BBA}\x{9BBB}\x{9BBC}\x{9BBD}\x{9BBE}\x{9BBF}\x{9BC0}' . +'\x{9BC1}\x{9BC3}\x{9BC4}\x{9BC5}\x{9BC6}\x{9BC7}\x{9BC8}\x{9BC9}\x{9BCA}' . +'\x{9BCB}\x{9BCC}\x{9BCD}\x{9BCE}\x{9BCF}\x{9BD0}\x{9BD1}\x{9BD2}\x{9BD3}' . +'\x{9BD4}\x{9BD5}\x{9BD6}\x{9BD7}\x{9BD8}\x{9BD9}\x{9BDA}\x{9BDB}\x{9BDC}' . +'\x{9BDD}\x{9BDE}\x{9BDF}\x{9BE0}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}\x{9BE5}' . +'\x{9BE6}\x{9BE7}\x{9BE8}\x{9BE9}\x{9BEA}\x{9BEB}\x{9BEC}\x{9BED}\x{9BEE}' . +'\x{9BEF}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF3}\x{9BF4}\x{9BF5}\x{9BF7}\x{9BF8}' . +'\x{9BF9}\x{9BFA}\x{9BFB}\x{9BFC}\x{9BFD}\x{9BFE}\x{9BFF}\x{9C02}\x{9C05}' . +'\x{9C06}\x{9C07}\x{9C08}\x{9C09}\x{9C0A}\x{9C0B}\x{9C0C}\x{9C0D}\x{9C0E}' . +'\x{9C0F}\x{9C10}\x{9C11}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C16}\x{9C17}' . +'\x{9C18}\x{9C19}\x{9C1A}\x{9C1B}\x{9C1C}\x{9C1D}\x{9C1E}\x{9C1F}\x{9C20}' . +'\x{9C21}\x{9C22}\x{9C23}\x{9C24}\x{9C25}\x{9C26}\x{9C27}\x{9C28}\x{9C29}' . +'\x{9C2A}\x{9C2B}\x{9C2C}\x{9C2D}\x{9C2F}\x{9C30}\x{9C31}\x{9C32}\x{9C33}' . +'\x{9C34}\x{9C35}\x{9C36}\x{9C37}\x{9C38}\x{9C39}\x{9C3A}\x{9C3B}\x{9C3C}' . +'\x{9C3D}\x{9C3E}\x{9C3F}\x{9C40}\x{9C41}\x{9C43}\x{9C44}\x{9C45}\x{9C46}' . +'\x{9C47}\x{9C48}\x{9C49}\x{9C4A}\x{9C4B}\x{9C4C}\x{9C4D}\x{9C4E}\x{9C50}' . +'\x{9C52}\x{9C53}\x{9C54}\x{9C55}\x{9C56}\x{9C57}\x{9C58}\x{9C59}\x{9C5A}' . +'\x{9C5B}\x{9C5C}\x{9C5D}\x{9C5E}\x{9C5F}\x{9C60}\x{9C62}\x{9C63}\x{9C65}' . +'\x{9C66}\x{9C67}\x{9C68}\x{9C69}\x{9C6A}\x{9C6B}\x{9C6C}\x{9C6D}\x{9C6E}' . +'\x{9C6F}\x{9C70}\x{9C71}\x{9C72}\x{9C73}\x{9C74}\x{9C75}\x{9C77}\x{9C78}' . +'\x{9C79}\x{9C7A}\x{9C7C}\x{9C7D}\x{9C7E}\x{9C7F}\x{9C80}\x{9C81}\x{9C82}' . +'\x{9C83}\x{9C84}\x{9C85}\x{9C86}\x{9C87}\x{9C88}\x{9C89}\x{9C8A}\x{9C8B}' . +'\x{9C8C}\x{9C8D}\x{9C8E}\x{9C8F}\x{9C90}\x{9C91}\x{9C92}\x{9C93}\x{9C94}' . +'\x{9C95}\x{9C96}\x{9C97}\x{9C98}\x{9C99}\x{9C9A}\x{9C9B}\x{9C9C}\x{9C9D}' . +'\x{9C9E}\x{9C9F}\x{9CA0}\x{9CA1}\x{9CA2}\x{9CA3}\x{9CA4}\x{9CA5}\x{9CA6}' . +'\x{9CA7}\x{9CA8}\x{9CA9}\x{9CAA}\x{9CAB}\x{9CAC}\x{9CAD}\x{9CAE}\x{9CAF}' . +'\x{9CB0}\x{9CB1}\x{9CB2}\x{9CB3}\x{9CB4}\x{9CB5}\x{9CB6}\x{9CB7}\x{9CB8}' . +'\x{9CB9}\x{9CBA}\x{9CBB}\x{9CBC}\x{9CBD}\x{9CBE}\x{9CBF}\x{9CC0}\x{9CC1}' . +'\x{9CC2}\x{9CC3}\x{9CC4}\x{9CC5}\x{9CC6}\x{9CC7}\x{9CC8}\x{9CC9}\x{9CCA}' . +'\x{9CCB}\x{9CCC}\x{9CCD}\x{9CCE}\x{9CCF}\x{9CD0}\x{9CD1}\x{9CD2}\x{9CD3}' . +'\x{9CD4}\x{9CD5}\x{9CD6}\x{9CD7}\x{9CD8}\x{9CD9}\x{9CDA}\x{9CDB}\x{9CDC}' . +'\x{9CDD}\x{9CDE}\x{9CDF}\x{9CE0}\x{9CE1}\x{9CE2}\x{9CE3}\x{9CE4}\x{9CE5}' . +'\x{9CE6}\x{9CE7}\x{9CE8}\x{9CE9}\x{9CEA}\x{9CEB}\x{9CEC}\x{9CED}\x{9CEE}' . +'\x{9CEF}\x{9CF0}\x{9CF1}\x{9CF2}\x{9CF3}\x{9CF4}\x{9CF5}\x{9CF6}\x{9CF7}' . +'\x{9CF8}\x{9CF9}\x{9CFA}\x{9CFB}\x{9CFC}\x{9CFD}\x{9CFE}\x{9CFF}\x{9D00}' . +'\x{9D01}\x{9D02}\x{9D03}\x{9D04}\x{9D05}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0A}\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}\x{9D13}\x{9D14}\x{9D15}\x{9D16}' . +'\x{9D17}\x{9D18}\x{9D19}\x{9D1A}\x{9D1B}\x{9D1C}\x{9D1D}\x{9D1E}\x{9D1F}' . +'\x{9D20}\x{9D21}\x{9D22}\x{9D23}\x{9D24}\x{9D25}\x{9D26}\x{9D28}\x{9D29}' . +'\x{9D2B}\x{9D2D}\x{9D2E}\x{9D2F}\x{9D30}\x{9D31}\x{9D32}\x{9D33}\x{9D34}' . +'\x{9D36}\x{9D37}\x{9D38}\x{9D39}\x{9D3A}\x{9D3B}\x{9D3D}\x{9D3E}\x{9D3F}' . +'\x{9D40}\x{9D41}\x{9D42}\x{9D43}\x{9D45}\x{9D46}\x{9D47}\x{9D48}\x{9D49}' . +'\x{9D4A}\x{9D4B}\x{9D4C}\x{9D4D}\x{9D4E}\x{9D4F}\x{9D50}\x{9D51}\x{9D52}' . +'\x{9D53}\x{9D54}\x{9D55}\x{9D56}\x{9D57}\x{9D58}\x{9D59}\x{9D5A}\x{9D5B}' . +'\x{9D5C}\x{9D5D}\x{9D5E}\x{9D5F}\x{9D60}\x{9D61}\x{9D62}\x{9D63}\x{9D64}' . +'\x{9D65}\x{9D66}\x{9D67}\x{9D68}\x{9D69}\x{9D6A}\x{9D6B}\x{9D6C}\x{9D6E}' . +'\x{9D6F}\x{9D70}\x{9D71}\x{9D72}\x{9D73}\x{9D74}\x{9D75}\x{9D76}\x{9D77}' . +'\x{9D78}\x{9D79}\x{9D7A}\x{9D7B}\x{9D7C}\x{9D7D}\x{9D7E}\x{9D7F}\x{9D80}' . +'\x{9D81}\x{9D82}\x{9D83}\x{9D84}\x{9D85}\x{9D86}\x{9D87}\x{9D88}\x{9D89}' . +'\x{9D8A}\x{9D8B}\x{9D8C}\x{9D8D}\x{9D8E}\x{9D90}\x{9D91}\x{9D92}\x{9D93}' . +'\x{9D94}\x{9D96}\x{9D97}\x{9D98}\x{9D99}\x{9D9A}\x{9D9B}\x{9D9C}\x{9D9D}' . +'\x{9D9E}\x{9D9F}\x{9DA0}\x{9DA1}\x{9DA2}\x{9DA3}\x{9DA4}\x{9DA5}\x{9DA6}' . +'\x{9DA7}\x{9DA8}\x{9DA9}\x{9DAA}\x{9DAB}\x{9DAC}\x{9DAD}\x{9DAF}\x{9DB0}' . +'\x{9DB1}\x{9DB2}\x{9DB3}\x{9DB4}\x{9DB5}\x{9DB6}\x{9DB7}\x{9DB8}\x{9DB9}' . +'\x{9DBA}\x{9DBB}\x{9DBC}\x{9DBE}\x{9DBF}\x{9DC1}\x{9DC2}\x{9DC3}\x{9DC4}' . +'\x{9DC5}\x{9DC7}\x{9DC8}\x{9DC9}\x{9DCA}\x{9DCB}\x{9DCC}\x{9DCD}\x{9DCE}' . +'\x{9DCF}\x{9DD0}\x{9DD1}\x{9DD2}\x{9DD3}\x{9DD4}\x{9DD5}\x{9DD6}\x{9DD7}' . +'\x{9DD8}\x{9DD9}\x{9DDA}\x{9DDB}\x{9DDC}\x{9DDD}\x{9DDE}\x{9DDF}\x{9DE0}' . +'\x{9DE1}\x{9DE2}\x{9DE3}\x{9DE4}\x{9DE5}\x{9DE6}\x{9DE7}\x{9DE8}\x{9DE9}' . +'\x{9DEB}\x{9DEC}\x{9DED}\x{9DEE}\x{9DEF}\x{9DF0}\x{9DF1}\x{9DF2}\x{9DF3}' . +'\x{9DF4}\x{9DF5}\x{9DF6}\x{9DF7}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFB}\x{9DFD}' . +'\x{9DFE}\x{9DFF}\x{9E00}\x{9E01}\x{9E02}\x{9E03}\x{9E04}\x{9E05}\x{9E06}' . +'\x{9E07}\x{9E08}\x{9E09}\x{9E0A}\x{9E0B}\x{9E0C}\x{9E0D}\x{9E0F}\x{9E10}' . +'\x{9E11}\x{9E12}\x{9E13}\x{9E14}\x{9E15}\x{9E17}\x{9E18}\x{9E19}\x{9E1A}' . +'\x{9E1B}\x{9E1D}\x{9E1E}\x{9E1F}\x{9E20}\x{9E21}\x{9E22}\x{9E23}\x{9E24}' . +'\x{9E25}\x{9E26}\x{9E27}\x{9E28}\x{9E29}\x{9E2A}\x{9E2B}\x{9E2C}\x{9E2D}' . +'\x{9E2E}\x{9E2F}\x{9E30}\x{9E31}\x{9E32}\x{9E33}\x{9E34}\x{9E35}\x{9E36}' . +'\x{9E37}\x{9E38}\x{9E39}\x{9E3A}\x{9E3B}\x{9E3C}\x{9E3D}\x{9E3E}\x{9E3F}' . +'\x{9E40}\x{9E41}\x{9E42}\x{9E43}\x{9E44}\x{9E45}\x{9E46}\x{9E47}\x{9E48}' . +'\x{9E49}\x{9E4A}\x{9E4B}\x{9E4C}\x{9E4D}\x{9E4E}\x{9E4F}\x{9E50}\x{9E51}' . +'\x{9E52}\x{9E53}\x{9E54}\x{9E55}\x{9E56}\x{9E57}\x{9E58}\x{9E59}\x{9E5A}' . +'\x{9E5B}\x{9E5C}\x{9E5D}\x{9E5E}\x{9E5F}\x{9E60}\x{9E61}\x{9E62}\x{9E63}' . +'\x{9E64}\x{9E65}\x{9E66}\x{9E67}\x{9E68}\x{9E69}\x{9E6A}\x{9E6B}\x{9E6C}' . +'\x{9E6D}\x{9E6E}\x{9E6F}\x{9E70}\x{9E71}\x{9E72}\x{9E73}\x{9E74}\x{9E75}' . +'\x{9E76}\x{9E77}\x{9E79}\x{9E7A}\x{9E7C}\x{9E7D}\x{9E7E}\x{9E7F}\x{9E80}' . +'\x{9E81}\x{9E82}\x{9E83}\x{9E84}\x{9E85}\x{9E86}\x{9E87}\x{9E88}\x{9E89}' . +'\x{9E8A}\x{9E8B}\x{9E8C}\x{9E8D}\x{9E8E}\x{9E91}\x{9E92}\x{9E93}\x{9E94}' . +'\x{9E96}\x{9E97}\x{9E99}\x{9E9A}\x{9E9B}\x{9E9C}\x{9E9D}\x{9E9F}\x{9EA0}' . +'\x{9EA1}\x{9EA3}\x{9EA4}\x{9EA5}\x{9EA6}\x{9EA7}\x{9EA8}\x{9EA9}\x{9EAA}' . +'\x{9EAD}\x{9EAE}\x{9EAF}\x{9EB0}\x{9EB2}\x{9EB3}\x{9EB4}\x{9EB5}\x{9EB6}' . +'\x{9EB7}\x{9EB8}\x{9EBB}\x{9EBC}\x{9EBD}\x{9EBE}\x{9EBF}\x{9EC0}\x{9EC1}' . +'\x{9EC2}\x{9EC3}\x{9EC4}\x{9EC5}\x{9EC6}\x{9EC7}\x{9EC8}\x{9EC9}\x{9ECA}' . +'\x{9ECB}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED1}\x{9ED2}\x{9ED3}' . +'\x{9ED4}\x{9ED5}\x{9ED6}\x{9ED7}\x{9ED8}\x{9ED9}\x{9EDA}\x{9EDB}\x{9EDC}' . +'\x{9EDD}\x{9EDE}\x{9EDF}\x{9EE0}\x{9EE1}\x{9EE2}\x{9EE3}\x{9EE4}\x{9EE5}' . +'\x{9EE6}\x{9EE7}\x{9EE8}\x{9EE9}\x{9EEA}\x{9EEB}\x{9EED}\x{9EEE}\x{9EEF}' . +'\x{9EF0}\x{9EF2}\x{9EF3}\x{9EF4}\x{9EF5}\x{9EF6}\x{9EF7}\x{9EF8}\x{9EF9}' . +'\x{9EFA}\x{9EFB}\x{9EFC}\x{9EFD}\x{9EFE}\x{9EFF}\x{9F00}\x{9F01}\x{9F02}' . +'\x{9F04}\x{9F05}\x{9F06}\x{9F07}\x{9F08}\x{9F09}\x{9F0A}\x{9F0B}\x{9F0C}' . +'\x{9F0D}\x{9F0E}\x{9F0F}\x{9F10}\x{9F12}\x{9F13}\x{9F15}\x{9F16}\x{9F17}' . +'\x{9F18}\x{9F19}\x{9F1A}\x{9F1B}\x{9F1C}\x{9F1D}\x{9F1E}\x{9F1F}\x{9F20}' . +'\x{9F22}\x{9F23}\x{9F24}\x{9F25}\x{9F27}\x{9F28}\x{9F29}\x{9F2A}\x{9F2B}' . +'\x{9F2C}\x{9F2D}\x{9F2E}\x{9F2F}\x{9F30}\x{9F31}\x{9F32}\x{9F33}\x{9F34}' . +'\x{9F35}\x{9F36}\x{9F37}\x{9F38}\x{9F39}\x{9F3A}\x{9F3B}\x{9F3C}\x{9F3D}' . +'\x{9F3E}\x{9F3F}\x{9F40}\x{9F41}\x{9F42}\x{9F43}\x{9F44}\x{9F46}\x{9F47}' . +'\x{9F48}\x{9F49}\x{9F4A}\x{9F4B}\x{9F4C}\x{9F4D}\x{9F4E}\x{9F4F}\x{9F50}' . +'\x{9F51}\x{9F52}\x{9F54}\x{9F55}\x{9F56}\x{9F57}\x{9F58}\x{9F59}\x{9F5A}' . +'\x{9F5B}\x{9F5C}\x{9F5D}\x{9F5E}\x{9F5F}\x{9F60}\x{9F61}\x{9F63}\x{9F64}' . +'\x{9F65}\x{9F66}\x{9F67}\x{9F68}\x{9F69}\x{9F6A}\x{9F6B}\x{9F6C}\x{9F6E}' . +'\x{9F6F}\x{9F70}\x{9F71}\x{9F72}\x{9F73}\x{9F74}\x{9F75}\x{9F76}\x{9F77}' . +'\x{9F78}\x{9F79}\x{9F7A}\x{9F7B}\x{9F7C}\x{9F7D}\x{9F7E}\x{9F7F}\x{9F80}' . +'\x{9F81}\x{9F82}\x{9F83}\x{9F84}\x{9F85}\x{9F86}\x{9F87}\x{9F88}\x{9F89}' . +'\x{9F8A}\x{9F8B}\x{9F8C}\x{9F8D}\x{9F8E}\x{9F8F}\x{9F90}\x{9F91}\x{9F92}' . +'\x{9F93}\x{9F94}\x{9F95}\x{9F96}\x{9F97}\x{9F98}\x{9F99}\x{9F9A}\x{9F9B}' . +'\x{9F9C}\x{9F9D}\x{9F9E}\x{9F9F}\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu'); diff --git a/library/vendor/Zend/Validate/Hostname/Cn.php b/library/vendor/Zend/Validate/Hostname/Cn.php new file mode 100644 index 000000000..254f292dd --- /dev/null +++ b/library/vendor/Zend/Validate/Hostname/Cn.php @@ -0,0 +1,2199 @@ + '/^[\x{002d}0-9a-z\x{3447}\x{3473}\x{359E}\x{360E}\x{361A}\x{3918}\x{396E}\x{39CF}\x{39D0}' . +'\x{39DF}\x{3A73}\x{3B4E}\x{3C6E}\x{3CE0}\x{4056}\x{415F}\x{4337}\x{43AC}' . +'\x{43B1}\x{43DD}\x{44D6}\x{464C}\x{4661}\x{4723}\x{4729}\x{477C}\x{478D}' . +'\x{4947}\x{497A}\x{497D}\x{4982}\x{4983}\x{4985}\x{4986}\x{499B}\x{499F}' . +'\x{49B6}\x{49B7}\x{4C77}\x{4C9F}\x{4CA0}\x{4CA1}\x{4CA2}\x{4CA3}\x{4D13}' . +'\x{4D14}\x{4D15}\x{4D16}\x{4D17}\x{4D18}\x{4D19}\x{4DAE}\x{4E00}\x{4E01}' . +'\x{4E02}\x{4E03}\x{4E04}\x{4E05}\x{4E06}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0C}\x{4E0D}\x{4E0E}\x{4E0F}\x{4E10}\x{4E11}\x{4E13}\x{4E14}' . +'\x{4E15}\x{4E16}\x{4E17}\x{4E18}\x{4E19}\x{4E1A}\x{4E1B}\x{4E1C}\x{4E1D}' . +'\x{4E1E}\x{4E1F}\x{4E20}\x{4E21}\x{4E22}\x{4E23}\x{4E24}\x{4E25}\x{4E26}' . +'\x{4E27}\x{4E28}\x{4E2A}\x{4E2B}\x{4E2C}\x{4E2D}\x{4E2E}\x{4E2F}\x{4E30}' . +'\x{4E31}\x{4E32}\x{4E33}\x{4E34}\x{4E35}\x{4E36}\x{4E37}\x{4E38}\x{4E39}' . +'\x{4E3A}\x{4E3B}\x{4E3C}\x{4E3D}\x{4E3E}\x{4E3F}\x{4E40}\x{4E41}\x{4E42}' . +'\x{4E43}\x{4E44}\x{4E45}\x{4E46}\x{4E47}\x{4E48}\x{4E49}\x{4E4A}\x{4E4B}' . +'\x{4E4C}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E50}\x{4E51}\x{4E52}\x{4E53}\x{4E54}' . +'\x{4E56}\x{4E57}\x{4E58}\x{4E59}\x{4E5A}\x{4E5B}\x{4E5C}\x{4E5D}\x{4E5E}' . +'\x{4E5F}\x{4E60}\x{4E61}\x{4E62}\x{4E63}\x{4E64}\x{4E65}\x{4E66}\x{4E67}' . +'\x{4E69}\x{4E6A}\x{4E6B}\x{4E6C}\x{4E6D}\x{4E6E}\x{4E6F}\x{4E70}\x{4E71}' . +'\x{4E72}\x{4E73}\x{4E74}\x{4E75}\x{4E76}\x{4E77}\x{4E78}\x{4E7A}\x{4E7B}' . +'\x{4E7C}\x{4E7D}\x{4E7E}\x{4E7F}\x{4E80}\x{4E81}\x{4E82}\x{4E83}\x{4E84}' . +'\x{4E85}\x{4E86}\x{4E87}\x{4E88}\x{4E89}\x{4E8B}\x{4E8C}\x{4E8D}\x{4E8E}' . +'\x{4E8F}\x{4E90}\x{4E91}\x{4E92}\x{4E93}\x{4E94}\x{4E95}\x{4E97}\x{4E98}' . +'\x{4E99}\x{4E9A}\x{4E9B}\x{4E9C}\x{4E9D}\x{4E9E}\x{4E9F}\x{4EA0}\x{4EA1}' . +'\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA7}\x{4EA8}\x{4EA9}\x{4EAA}\x{4EAB}' . +'\x{4EAC}\x{4EAD}\x{4EAE}\x{4EAF}\x{4EB0}\x{4EB1}\x{4EB2}\x{4EB3}\x{4EB4}' . +'\x{4EB5}\x{4EB6}\x{4EB7}\x{4EB8}\x{4EB9}\x{4EBA}\x{4EBB}\x{4EBD}\x{4EBE}' . +'\x{4EBF}\x{4EC0}\x{4EC1}\x{4EC2}\x{4EC3}\x{4EC4}\x{4EC5}\x{4EC6}\x{4EC7}' . +'\x{4EC8}\x{4EC9}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED0}\x{4ED1}' . +'\x{4ED2}\x{4ED3}\x{4ED4}\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDA}' . +'\x{4EDB}\x{4EDC}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE0}\x{4EE1}\x{4EE2}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EE6}\x{4EE8}\x{4EE9}\x{4EEA}\x{4EEB}\x{4EEC}\x{4EEF}' . +'\x{4EF0}\x{4EF1}\x{4EF2}\x{4EF3}\x{4EF4}\x{4EF5}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4EFD}\x{4EFF}\x{4F00}\x{4F01}\x{4F02}\x{4F03}\x{4F04}\x{4F05}\x{4F06}' . +'\x{4F08}\x{4F09}\x{4F0A}\x{4F0B}\x{4F0C}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}' . +'\x{4F11}\x{4F12}\x{4F13}\x{4F14}\x{4F15}\x{4F17}\x{4F18}\x{4F19}\x{4F1A}' . +'\x{4F1B}\x{4F1C}\x{4F1D}\x{4F1E}\x{4F1F}\x{4F20}\x{4F21}\x{4F22}\x{4F23}' . +'\x{4F24}\x{4F25}\x{4F26}\x{4F27}\x{4F29}\x{4F2A}\x{4F2B}\x{4F2C}\x{4F2D}' . +'\x{4F2E}\x{4F2F}\x{4F30}\x{4F32}\x{4F33}\x{4F34}\x{4F36}\x{4F38}\x{4F39}' . +'\x{4F3A}\x{4F3B}\x{4F3C}\x{4F3D}\x{4F3E}\x{4F3F}\x{4F41}\x{4F42}\x{4F43}' . +'\x{4F45}\x{4F46}\x{4F47}\x{4F48}\x{4F49}\x{4F4A}\x{4F4B}\x{4F4C}\x{4F4D}' . +'\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}\x{4F52}\x{4F53}\x{4F54}\x{4F55}\x{4F56}' . +'\x{4F57}\x{4F58}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}\x{4F5F}' . +'\x{4F60}\x{4F61}\x{4F62}\x{4F63}\x{4F64}\x{4F65}\x{4F66}\x{4F67}\x{4F68}' . +'\x{4F69}\x{4F6A}\x{4F6B}\x{4F6C}\x{4F6D}\x{4F6E}\x{4F6F}\x{4F70}\x{4F72}' . +'\x{4F73}\x{4F74}\x{4F75}\x{4F76}\x{4F77}\x{4F78}\x{4F79}\x{4F7A}\x{4F7B}' . +'\x{4F7C}\x{4F7D}\x{4F7E}\x{4F7F}\x{4F80}\x{4F81}\x{4F82}\x{4F83}\x{4F84}' . +'\x{4F85}\x{4F86}\x{4F87}\x{4F88}\x{4F89}\x{4F8A}\x{4F8B}\x{4F8D}\x{4F8F}' . +'\x{4F90}\x{4F91}\x{4F92}\x{4F93}\x{4F94}\x{4F95}\x{4F96}\x{4F97}\x{4F98}' . +'\x{4F99}\x{4F9A}\x{4F9B}\x{4F9C}\x{4F9D}\x{4F9E}\x{4F9F}\x{4FA0}\x{4FA1}' . +'\x{4FA3}\x{4FA4}\x{4FA5}\x{4FA6}\x{4FA7}\x{4FA8}\x{4FA9}\x{4FAA}\x{4FAB}' . +'\x{4FAC}\x{4FAE}\x{4FAF}\x{4FB0}\x{4FB1}\x{4FB2}\x{4FB3}\x{4FB4}\x{4FB5}' . +'\x{4FB6}\x{4FB7}\x{4FB8}\x{4FB9}\x{4FBA}\x{4FBB}\x{4FBC}\x{4FBE}\x{4FBF}' . +'\x{4FC0}\x{4FC1}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FC5}\x{4FC7}\x{4FC9}\x{4FCA}' . +'\x{4FCB}\x{4FCD}\x{4FCE}\x{4FCF}\x{4FD0}\x{4FD1}\x{4FD2}\x{4FD3}\x{4FD4}' . +'\x{4FD5}\x{4FD6}\x{4FD7}\x{4FD8}\x{4FD9}\x{4FDA}\x{4FDB}\x{4FDC}\x{4FDD}' . +'\x{4FDE}\x{4FDF}\x{4FE0}\x{4FE1}\x{4FE3}\x{4FE4}\x{4FE5}\x{4FE6}\x{4FE7}' . +'\x{4FE8}\x{4FE9}\x{4FEA}\x{4FEB}\x{4FEC}\x{4FED}\x{4FEE}\x{4FEF}\x{4FF0}' . +'\x{4FF1}\x{4FF2}\x{4FF3}\x{4FF4}\x{4FF5}\x{4FF6}\x{4FF7}\x{4FF8}\x{4FF9}' . +'\x{4FFA}\x{4FFB}\x{4FFE}\x{4FFF}\x{5000}\x{5001}\x{5002}\x{5003}\x{5004}' . +'\x{5005}\x{5006}\x{5007}\x{5008}\x{5009}\x{500A}\x{500B}\x{500C}\x{500D}' . +'\x{500E}\x{500F}\x{5011}\x{5012}\x{5013}\x{5014}\x{5015}\x{5016}\x{5017}' . +'\x{5018}\x{5019}\x{501A}\x{501B}\x{501C}\x{501D}\x{501E}\x{501F}\x{5020}' . +'\x{5021}\x{5022}\x{5023}\x{5024}\x{5025}\x{5026}\x{5027}\x{5028}\x{5029}' . +'\x{502A}\x{502B}\x{502C}\x{502D}\x{502E}\x{502F}\x{5030}\x{5031}\x{5032}' . +'\x{5033}\x{5035}\x{5036}\x{5037}\x{5039}\x{503A}\x{503B}\x{503C}\x{503E}' . +'\x{503F}\x{5040}\x{5041}\x{5043}\x{5044}\x{5045}\x{5046}\x{5047}\x{5048}' . +'\x{5049}\x{504A}\x{504B}\x{504C}\x{504D}\x{504E}\x{504F}\x{5051}\x{5053}' . +'\x{5054}\x{5055}\x{5056}\x{5057}\x{5059}\x{505A}\x{505B}\x{505C}\x{505D}' . +'\x{505E}\x{505F}\x{5060}\x{5061}\x{5062}\x{5063}\x{5064}\x{5065}\x{5066}' . +'\x{5067}\x{5068}\x{5069}\x{506A}\x{506B}\x{506C}\x{506D}\x{506E}\x{506F}' . +'\x{5070}\x{5071}\x{5072}\x{5073}\x{5074}\x{5075}\x{5076}\x{5077}\x{5078}' . +'\x{5079}\x{507A}\x{507B}\x{507D}\x{507E}\x{507F}\x{5080}\x{5082}\x{5083}' . +'\x{5084}\x{5085}\x{5086}\x{5087}\x{5088}\x{5089}\x{508A}\x{508B}\x{508C}' . +'\x{508D}\x{508E}\x{508F}\x{5090}\x{5091}\x{5092}\x{5094}\x{5095}\x{5096}' . +'\x{5098}\x{5099}\x{509A}\x{509B}\x{509C}\x{509D}\x{509E}\x{50A2}\x{50A3}' . +'\x{50A4}\x{50A5}\x{50A6}\x{50A7}\x{50A8}\x{50A9}\x{50AA}\x{50AB}\x{50AC}' . +'\x{50AD}\x{50AE}\x{50AF}\x{50B0}\x{50B1}\x{50B2}\x{50B3}\x{50B4}\x{50B5}' . +'\x{50B6}\x{50B7}\x{50B8}\x{50BA}\x{50BB}\x{50BC}\x{50BD}\x{50BE}\x{50BF}' . +'\x{50C0}\x{50C1}\x{50C2}\x{50C4}\x{50C5}\x{50C6}\x{50C7}\x{50C8}\x{50C9}' . +'\x{50CA}\x{50CB}\x{50CC}\x{50CD}\x{50CE}\x{50CF}\x{50D0}\x{50D1}\x{50D2}' . +'\x{50D3}\x{50D4}\x{50D5}\x{50D6}\x{50D7}\x{50D9}\x{50DA}\x{50DB}\x{50DC}' . +'\x{50DD}\x{50DE}\x{50E0}\x{50E3}\x{50E4}\x{50E5}\x{50E6}\x{50E7}\x{50E8}' . +'\x{50E9}\x{50EA}\x{50EC}\x{50ED}\x{50EE}\x{50EF}\x{50F0}\x{50F1}\x{50F2}' . +'\x{50F3}\x{50F5}\x{50F6}\x{50F8}\x{50F9}\x{50FA}\x{50FB}\x{50FC}\x{50FD}' . +'\x{50FE}\x{50FF}\x{5100}\x{5101}\x{5102}\x{5103}\x{5104}\x{5105}\x{5106}' . +'\x{5107}\x{5108}\x{5109}\x{510A}\x{510B}\x{510C}\x{510D}\x{510E}\x{510F}' . +'\x{5110}\x{5111}\x{5112}\x{5113}\x{5114}\x{5115}\x{5116}\x{5117}\x{5118}' . +'\x{5119}\x{511A}\x{511C}\x{511D}\x{511E}\x{511F}\x{5120}\x{5121}\x{5122}' . +'\x{5123}\x{5124}\x{5125}\x{5126}\x{5127}\x{5129}\x{512A}\x{512C}\x{512D}' . +'\x{512E}\x{512F}\x{5130}\x{5131}\x{5132}\x{5133}\x{5134}\x{5135}\x{5136}' . +'\x{5137}\x{5138}\x{5139}\x{513A}\x{513B}\x{513C}\x{513D}\x{513E}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5151}\x{5152}\x{5154}\x{5155}' . +'\x{5156}\x{5157}\x{5159}\x{515A}\x{515B}\x{515C}\x{515D}\x{515E}\x{515F}' . +'\x{5161}\x{5162}\x{5163}\x{5165}\x{5166}\x{5167}\x{5168}\x{5169}\x{516A}' . +'\x{516B}\x{516C}\x{516D}\x{516E}\x{516F}\x{5170}\x{5171}\x{5173}\x{5174}' . +'\x{5175}\x{5176}\x{5177}\x{5178}\x{5179}\x{517A}\x{517B}\x{517C}\x{517D}' . +'\x{517F}\x{5180}\x{5181}\x{5182}\x{5185}\x{5186}\x{5187}\x{5188}\x{5189}' . +'\x{518A}\x{518B}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}\x{5193}' . +'\x{5194}\x{5195}\x{5196}\x{5197}\x{5198}\x{5199}\x{519A}\x{519B}\x{519C}' . +'\x{519D}\x{519E}\x{519F}\x{51A0}\x{51A2}\x{51A4}\x{51A5}\x{51A6}\x{51A7}' . +'\x{51A8}\x{51AA}\x{51AB}\x{51AC}\x{51AE}\x{51AF}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B5}\x{51B6}\x{51B7}\x{51B9}\x{51BB}\x{51BC}\x{51BD}\x{51BE}' . +'\x{51BF}\x{51C0}\x{51C1}\x{51C3}\x{51C4}\x{51C5}\x{51C6}\x{51C7}\x{51C8}' . +'\x{51C9}\x{51CA}\x{51CB}\x{51CC}\x{51CD}\x{51CE}\x{51CF}\x{51D0}\x{51D1}' . +'\x{51D4}\x{51D5}\x{51D6}\x{51D7}\x{51D8}\x{51D9}\x{51DA}\x{51DB}\x{51DC}' . +'\x{51DD}\x{51DE}\x{51E0}\x{51E1}\x{51E2}\x{51E3}\x{51E4}\x{51E5}\x{51E7}' . +'\x{51E8}\x{51E9}\x{51EA}\x{51EB}\x{51ED}\x{51EF}\x{51F0}\x{51F1}\x{51F3}' . +'\x{51F4}\x{51F5}\x{51F6}\x{51F7}\x{51F8}\x{51F9}\x{51FA}\x{51FB}\x{51FC}' . +'\x{51FD}\x{51FE}\x{51FF}\x{5200}\x{5201}\x{5202}\x{5203}\x{5204}\x{5205}' . +'\x{5206}\x{5207}\x{5208}\x{5209}\x{520A}\x{520B}\x{520C}\x{520D}\x{520E}' . +'\x{520F}\x{5210}\x{5211}\x{5212}\x{5213}\x{5214}\x{5215}\x{5216}\x{5217}' . +'\x{5218}\x{5219}\x{521A}\x{521B}\x{521C}\x{521D}\x{521E}\x{521F}\x{5220}' . +'\x{5221}\x{5222}\x{5223}\x{5224}\x{5225}\x{5226}\x{5228}\x{5229}\x{522A}' . +'\x{522B}\x{522C}\x{522D}\x{522E}\x{522F}\x{5230}\x{5231}\x{5232}\x{5233}' . +'\x{5234}\x{5235}\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{523C}' . +'\x{523D}\x{523E}\x{523F}\x{5240}\x{5241}\x{5242}\x{5243}\x{5244}\x{5245}' . +'\x{5246}\x{5247}\x{5248}\x{5249}\x{524A}\x{524B}\x{524C}\x{524D}\x{524E}' . +'\x{5250}\x{5251}\x{5252}\x{5254}\x{5255}\x{5256}\x{5257}\x{5258}\x{5259}' . +'\x{525A}\x{525B}\x{525C}\x{525D}\x{525E}\x{525F}\x{5260}\x{5261}\x{5262}' . +'\x{5263}\x{5264}\x{5265}\x{5267}\x{5268}\x{5269}\x{526A}\x{526B}\x{526C}' . +'\x{526D}\x{526E}\x{526F}\x{5270}\x{5272}\x{5273}\x{5274}\x{5275}\x{5276}' . +'\x{5277}\x{5278}\x{527A}\x{527B}\x{527C}\x{527D}\x{527E}\x{527F}\x{5280}' . +'\x{5281}\x{5282}\x{5283}\x{5284}\x{5286}\x{5287}\x{5288}\x{5289}\x{528A}' . +'\x{528B}\x{528C}\x{528D}\x{528F}\x{5290}\x{5291}\x{5292}\x{5293}\x{5294}' . +'\x{5295}\x{5296}\x{5297}\x{5298}\x{5299}\x{529A}\x{529B}\x{529C}\x{529D}' . +'\x{529E}\x{529F}\x{52A0}\x{52A1}\x{52A2}\x{52A3}\x{52A5}\x{52A6}\x{52A7}' . +'\x{52A8}\x{52A9}\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52AE}\x{52AF}\x{52B0}' . +'\x{52B1}\x{52B2}\x{52B3}\x{52B4}\x{52B5}\x{52B6}\x{52B7}\x{52B8}\x{52B9}' . +'\x{52BA}\x{52BB}\x{52BC}\x{52BD}\x{52BE}\x{52BF}\x{52C0}\x{52C1}\x{52C2}' . +'\x{52C3}\x{52C6}\x{52C7}\x{52C9}\x{52CA}\x{52CB}\x{52CD}\x{52CF}\x{52D0}' . +'\x{52D2}\x{52D3}\x{52D5}\x{52D6}\x{52D7}\x{52D8}\x{52D9}\x{52DA}\x{52DB}' . +'\x{52DC}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}\x{52E4}\x{52E6}' . +'\x{52E7}\x{52E8}\x{52E9}\x{52EA}\x{52EB}\x{52EC}\x{52ED}\x{52EF}\x{52F0}' . +'\x{52F1}\x{52F2}\x{52F3}\x{52F4}\x{52F5}\x{52F6}\x{52F7}\x{52F8}\x{52F9}' . +'\x{52FA}\x{52FB}\x{52FC}\x{52FD}\x{52FE}\x{52FF}\x{5300}\x{5301}\x{5302}' . +'\x{5305}\x{5306}\x{5307}\x{5308}\x{5309}\x{530A}\x{530B}\x{530C}\x{530D}' . +'\x{530E}\x{530F}\x{5310}\x{5311}\x{5312}\x{5313}\x{5314}\x{5315}\x{5316}' . +'\x{5317}\x{5319}\x{531A}\x{531C}\x{531D}\x{531F}\x{5320}\x{5321}\x{5322}' . +'\x{5323}\x{5324}\x{5325}\x{5326}\x{5328}\x{532A}\x{532B}\x{532C}\x{532D}' . +'\x{532E}\x{532F}\x{5330}\x{5331}\x{5333}\x{5334}\x{5337}\x{5339}\x{533A}' . +'\x{533B}\x{533C}\x{533D}\x{533E}\x{533F}\x{5340}\x{5341}\x{5343}\x{5344}' . +'\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}\x{534A}\x{534B}\x{534C}\x{534D}' . +'\x{534E}\x{534F}\x{5350}\x{5351}\x{5352}\x{5353}\x{5354}\x{5355}\x{5356}' . +'\x{5357}\x{5358}\x{5359}\x{535A}\x{535C}\x{535E}\x{535F}\x{5360}\x{5361}' . +'\x{5362}\x{5363}\x{5364}\x{5365}\x{5366}\x{5367}\x{5369}\x{536B}\x{536C}' . +'\x{536E}\x{536F}\x{5370}\x{5371}\x{5372}\x{5373}\x{5374}\x{5375}\x{5376}' . +'\x{5377}\x{5378}\x{5379}\x{537A}\x{537B}\x{537C}\x{537D}\x{537E}\x{537F}' . +'\x{5381}\x{5382}\x{5383}\x{5384}\x{5385}\x{5386}\x{5387}\x{5388}\x{5389}' . +'\x{538A}\x{538B}\x{538C}\x{538D}\x{538E}\x{538F}\x{5390}\x{5391}\x{5392}' . +'\x{5393}\x{5394}\x{5395}\x{5396}\x{5397}\x{5398}\x{5399}\x{539A}\x{539B}' . +'\x{539C}\x{539D}\x{539E}\x{539F}\x{53A0}\x{53A2}\x{53A3}\x{53A4}\x{53A5}' . +'\x{53A6}\x{53A7}\x{53A8}\x{53A9}\x{53AC}\x{53AD}\x{53AE}\x{53B0}\x{53B1}' . +'\x{53B2}\x{53B3}\x{53B4}\x{53B5}\x{53B6}\x{53B7}\x{53B8}\x{53B9}\x{53BB}' . +'\x{53BC}\x{53BD}\x{53BE}\x{53BF}\x{53C0}\x{53C1}\x{53C2}\x{53C3}\x{53C4}' . +'\x{53C6}\x{53C7}\x{53C8}\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}' . +'\x{53D0}\x{53D1}\x{53D2}\x{53D3}\x{53D4}\x{53D5}\x{53D6}\x{53D7}\x{53D8}' . +'\x{53D9}\x{53DB}\x{53DC}\x{53DF}\x{53E0}\x{53E1}\x{53E2}\x{53E3}\x{53E4}' . +'\x{53E5}\x{53E6}\x{53E8}\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}' . +'\x{53EF}\x{53F0}\x{53F1}\x{53F2}\x{53F3}\x{53F4}\x{53F5}\x{53F6}\x{53F7}' . +'\x{53F8}\x{53F9}\x{53FA}\x{53FB}\x{53FC}\x{53FD}\x{53FE}\x{5401}\x{5402}' . +'\x{5403}\x{5404}\x{5405}\x{5406}\x{5407}\x{5408}\x{5409}\x{540A}\x{540B}' . +'\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}\x{5411}\x{5412}\x{5413}\x{5414}' . +'\x{5415}\x{5416}\x{5417}\x{5418}\x{5419}\x{541B}\x{541C}\x{541D}\x{541E}' . +'\x{541F}\x{5420}\x{5421}\x{5423}\x{5424}\x{5425}\x{5426}\x{5427}\x{5428}' . +'\x{5429}\x{542A}\x{542B}\x{542C}\x{542D}\x{542E}\x{542F}\x{5430}\x{5431}' . +'\x{5432}\x{5433}\x{5434}\x{5435}\x{5436}\x{5437}\x{5438}\x{5439}\x{543A}' . +'\x{543B}\x{543C}\x{543D}\x{543E}\x{543F}\x{5440}\x{5441}\x{5442}\x{5443}' . +'\x{5444}\x{5445}\x{5446}\x{5447}\x{5448}\x{5449}\x{544A}\x{544B}\x{544D}' . +'\x{544E}\x{544F}\x{5450}\x{5451}\x{5452}\x{5453}\x{5454}\x{5455}\x{5456}' . +'\x{5457}\x{5458}\x{5459}\x{545A}\x{545B}\x{545C}\x{545E}\x{545F}\x{5460}' . +'\x{5461}\x{5462}\x{5463}\x{5464}\x{5465}\x{5466}\x{5467}\x{5468}\x{546A}' . +'\x{546B}\x{546C}\x{546D}\x{546E}\x{546F}\x{5470}\x{5471}\x{5472}\x{5473}' . +'\x{5474}\x{5475}\x{5476}\x{5477}\x{5478}\x{5479}\x{547A}\x{547B}\x{547C}' . +'\x{547D}\x{547E}\x{547F}\x{5480}\x{5481}\x{5482}\x{5483}\x{5484}\x{5485}' . +'\x{5486}\x{5487}\x{5488}\x{5489}\x{548B}\x{548C}\x{548D}\x{548E}\x{548F}' . +'\x{5490}\x{5491}\x{5492}\x{5493}\x{5494}\x{5495}\x{5496}\x{5497}\x{5498}' . +'\x{5499}\x{549A}\x{549B}\x{549C}\x{549D}\x{549E}\x{549F}\x{54A0}\x{54A1}' . +'\x{54A2}\x{54A3}\x{54A4}\x{54A5}\x{54A6}\x{54A7}\x{54A8}\x{54A9}\x{54AA}' . +'\x{54AB}\x{54AC}\x{54AD}\x{54AE}\x{54AF}\x{54B0}\x{54B1}\x{54B2}\x{54B3}' . +'\x{54B4}\x{54B6}\x{54B7}\x{54B8}\x{54B9}\x{54BA}\x{54BB}\x{54BC}\x{54BD}' . +'\x{54BE}\x{54BF}\x{54C0}\x{54C1}\x{54C2}\x{54C3}\x{54C4}\x{54C5}\x{54C6}' . +'\x{54C7}\x{54C8}\x{54C9}\x{54CA}\x{54CB}\x{54CC}\x{54CD}\x{54CE}\x{54CF}' . +'\x{54D0}\x{54D1}\x{54D2}\x{54D3}\x{54D4}\x{54D5}\x{54D6}\x{54D7}\x{54D8}' . +'\x{54D9}\x{54DA}\x{54DB}\x{54DC}\x{54DD}\x{54DE}\x{54DF}\x{54E0}\x{54E1}' . +'\x{54E2}\x{54E3}\x{54E4}\x{54E5}\x{54E6}\x{54E7}\x{54E8}\x{54E9}\x{54EA}' . +'\x{54EB}\x{54EC}\x{54ED}\x{54EE}\x{54EF}\x{54F0}\x{54F1}\x{54F2}\x{54F3}' . +'\x{54F4}\x{54F5}\x{54F7}\x{54F8}\x{54F9}\x{54FA}\x{54FB}\x{54FC}\x{54FD}' . +'\x{54FE}\x{54FF}\x{5500}\x{5501}\x{5502}\x{5503}\x{5504}\x{5505}\x{5506}' . +'\x{5507}\x{5508}\x{5509}\x{550A}\x{550B}\x{550C}\x{550D}\x{550E}\x{550F}' . +'\x{5510}\x{5511}\x{5512}\x{5513}\x{5514}\x{5516}\x{5517}\x{551A}\x{551B}' . +'\x{551C}\x{551D}\x{551E}\x{551F}\x{5520}\x{5521}\x{5522}\x{5523}\x{5524}' . +'\x{5525}\x{5526}\x{5527}\x{5528}\x{5529}\x{552A}\x{552B}\x{552C}\x{552D}' . +'\x{552E}\x{552F}\x{5530}\x{5531}\x{5532}\x{5533}\x{5534}\x{5535}\x{5536}' . +'\x{5537}\x{5538}\x{5539}\x{553A}\x{553B}\x{553C}\x{553D}\x{553E}\x{553F}' . +'\x{5540}\x{5541}\x{5542}\x{5543}\x{5544}\x{5545}\x{5546}\x{5548}\x{5549}' . +'\x{554A}\x{554B}\x{554C}\x{554D}\x{554E}\x{554F}\x{5550}\x{5551}\x{5552}' . +'\x{5553}\x{5554}\x{5555}\x{5556}\x{5557}\x{5558}\x{5559}\x{555A}\x{555B}' . +'\x{555C}\x{555D}\x{555E}\x{555F}\x{5561}\x{5562}\x{5563}\x{5564}\x{5565}' . +'\x{5566}\x{5567}\x{5568}\x{5569}\x{556A}\x{556B}\x{556C}\x{556D}\x{556E}' . +'\x{556F}\x{5570}\x{5571}\x{5572}\x{5573}\x{5574}\x{5575}\x{5576}\x{5577}' . +'\x{5578}\x{5579}\x{557B}\x{557C}\x{557D}\x{557E}\x{557F}\x{5580}\x{5581}' . +'\x{5582}\x{5583}\x{5584}\x{5585}\x{5586}\x{5587}\x{5588}\x{5589}\x{558A}' . +'\x{558B}\x{558C}\x{558D}\x{558E}\x{558F}\x{5590}\x{5591}\x{5592}\x{5593}' . +'\x{5594}\x{5595}\x{5596}\x{5597}\x{5598}\x{5599}\x{559A}\x{559B}\x{559C}' . +'\x{559D}\x{559E}\x{559F}\x{55A0}\x{55A1}\x{55A2}\x{55A3}\x{55A4}\x{55A5}' . +'\x{55A6}\x{55A7}\x{55A8}\x{55A9}\x{55AA}\x{55AB}\x{55AC}\x{55AD}\x{55AE}' . +'\x{55AF}\x{55B0}\x{55B1}\x{55B2}\x{55B3}\x{55B4}\x{55B5}\x{55B6}\x{55B7}' . +'\x{55B8}\x{55B9}\x{55BA}\x{55BB}\x{55BC}\x{55BD}\x{55BE}\x{55BF}\x{55C0}' . +'\x{55C1}\x{55C2}\x{55C3}\x{55C4}\x{55C5}\x{55C6}\x{55C7}\x{55C8}\x{55C9}' . +'\x{55CA}\x{55CB}\x{55CC}\x{55CD}\x{55CE}\x{55CF}\x{55D0}\x{55D1}\x{55D2}' . +'\x{55D3}\x{55D4}\x{55D5}\x{55D6}\x{55D7}\x{55D8}\x{55D9}\x{55DA}\x{55DB}' . +'\x{55DC}\x{55DD}\x{55DE}\x{55DF}\x{55E1}\x{55E2}\x{55E3}\x{55E4}\x{55E5}' . +'\x{55E6}\x{55E7}\x{55E8}\x{55E9}\x{55EA}\x{55EB}\x{55EC}\x{55ED}\x{55EE}' . +'\x{55EF}\x{55F0}\x{55F1}\x{55F2}\x{55F3}\x{55F4}\x{55F5}\x{55F6}\x{55F7}' . +'\x{55F9}\x{55FA}\x{55FB}\x{55FC}\x{55FD}\x{55FE}\x{55FF}\x{5600}\x{5601}' . +'\x{5602}\x{5603}\x{5604}\x{5606}\x{5607}\x{5608}\x{5609}\x{560C}\x{560D}' . +'\x{560E}\x{560F}\x{5610}\x{5611}\x{5612}\x{5613}\x{5614}\x{5615}\x{5616}' . +'\x{5617}\x{5618}\x{5619}\x{561A}\x{561B}\x{561C}\x{561D}\x{561E}\x{561F}' . +'\x{5621}\x{5622}\x{5623}\x{5624}\x{5625}\x{5626}\x{5627}\x{5628}\x{5629}' . +'\x{562A}\x{562C}\x{562D}\x{562E}\x{562F}\x{5630}\x{5631}\x{5632}\x{5633}' . +'\x{5634}\x{5635}\x{5636}\x{5638}\x{5639}\x{563A}\x{563B}\x{563D}\x{563E}' . +'\x{563F}\x{5640}\x{5641}\x{5642}\x{5643}\x{5645}\x{5646}\x{5647}\x{5648}' . +'\x{5649}\x{564A}\x{564C}\x{564D}\x{564E}\x{564F}\x{5650}\x{5652}\x{5653}' . +'\x{5654}\x{5655}\x{5657}\x{5658}\x{5659}\x{565A}\x{565B}\x{565C}\x{565D}' . +'\x{565E}\x{5660}\x{5662}\x{5663}\x{5664}\x{5665}\x{5666}\x{5667}\x{5668}' . +'\x{5669}\x{566A}\x{566B}\x{566C}\x{566D}\x{566E}\x{566F}\x{5670}\x{5671}' . +'\x{5672}\x{5673}\x{5674}\x{5676}\x{5677}\x{5678}\x{5679}\x{567A}\x{567B}' . +'\x{567C}\x{567E}\x{567F}\x{5680}\x{5681}\x{5682}\x{5683}\x{5684}\x{5685}' . +'\x{5686}\x{5687}\x{568A}\x{568C}\x{568D}\x{568E}\x{568F}\x{5690}\x{5691}' . +'\x{5692}\x{5693}\x{5694}\x{5695}\x{5697}\x{5698}\x{5699}\x{569A}\x{569B}' . +'\x{569C}\x{569D}\x{569F}\x{56A0}\x{56A1}\x{56A3}\x{56A4}\x{56A5}\x{56A6}' . +'\x{56A7}\x{56A8}\x{56A9}\x{56AA}\x{56AB}\x{56AC}\x{56AD}\x{56AE}\x{56AF}' . +'\x{56B0}\x{56B1}\x{56B2}\x{56B3}\x{56B4}\x{56B5}\x{56B6}\x{56B7}\x{56B8}' . +'\x{56B9}\x{56BB}\x{56BC}\x{56BD}\x{56BE}\x{56BF}\x{56C0}\x{56C1}\x{56C2}' . +'\x{56C3}\x{56C4}\x{56C5}\x{56C6}\x{56C7}\x{56C8}\x{56C9}\x{56CA}\x{56CB}' . +'\x{56CC}\x{56CD}\x{56CE}\x{56D0}\x{56D1}\x{56D2}\x{56D3}\x{56D4}\x{56D5}' . +'\x{56D6}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DC}\x{56DD}\x{56DE}\x{56DF}' . +'\x{56E0}\x{56E1}\x{56E2}\x{56E3}\x{56E4}\x{56E5}\x{56E7}\x{56E8}\x{56E9}' . +'\x{56EA}\x{56EB}\x{56EC}\x{56ED}\x{56EE}\x{56EF}\x{56F0}\x{56F1}\x{56F2}' . +'\x{56F3}\x{56F4}\x{56F5}\x{56F7}\x{56F9}\x{56FA}\x{56FD}\x{56FE}\x{56FF}' . +'\x{5700}\x{5701}\x{5702}\x{5703}\x{5704}\x{5706}\x{5707}\x{5708}\x{5709}' . +'\x{570A}\x{570B}\x{570C}\x{570D}\x{570E}\x{570F}\x{5710}\x{5712}\x{5713}' . +'\x{5714}\x{5715}\x{5716}\x{5718}\x{5719}\x{571A}\x{571B}\x{571C}\x{571D}' . +'\x{571E}\x{571F}\x{5720}\x{5722}\x{5723}\x{5725}\x{5726}\x{5727}\x{5728}' . +'\x{5729}\x{572A}\x{572B}\x{572C}\x{572D}\x{572E}\x{572F}\x{5730}\x{5731}' . +'\x{5732}\x{5733}\x{5734}\x{5735}\x{5736}\x{5737}\x{5738}\x{5739}\x{573A}' . +'\x{573B}\x{573C}\x{573E}\x{573F}\x{5740}\x{5741}\x{5742}\x{5744}\x{5745}' . +'\x{5746}\x{5747}\x{5749}\x{574A}\x{574B}\x{574C}\x{574D}\x{574E}\x{574F}' . +'\x{5750}\x{5751}\x{5752}\x{5753}\x{5754}\x{5757}\x{5759}\x{575A}\x{575B}' . +'\x{575C}\x{575D}\x{575E}\x{575F}\x{5760}\x{5761}\x{5762}\x{5764}\x{5765}' . +'\x{5766}\x{5767}\x{5768}\x{5769}\x{576A}\x{576B}\x{576C}\x{576D}\x{576F}' . +'\x{5770}\x{5771}\x{5772}\x{5773}\x{5774}\x{5775}\x{5776}\x{5777}\x{5779}' . +'\x{577A}\x{577B}\x{577C}\x{577D}\x{577E}\x{577F}\x{5780}\x{5782}\x{5783}' . +'\x{5784}\x{5785}\x{5786}\x{5788}\x{5789}\x{578A}\x{578B}\x{578C}\x{578D}' . +'\x{578E}\x{578F}\x{5790}\x{5791}\x{5792}\x{5793}\x{5794}\x{5795}\x{5797}' . +'\x{5798}\x{5799}\x{579A}\x{579B}\x{579C}\x{579D}\x{579E}\x{579F}\x{57A0}' . +'\x{57A1}\x{57A2}\x{57A3}\x{57A4}\x{57A5}\x{57A6}\x{57A7}\x{57A9}\x{57AA}' . +'\x{57AB}\x{57AC}\x{57AD}\x{57AE}\x{57AF}\x{57B0}\x{57B1}\x{57B2}\x{57B3}' . +'\x{57B4}\x{57B5}\x{57B6}\x{57B7}\x{57B8}\x{57B9}\x{57BA}\x{57BB}\x{57BC}' . +'\x{57BD}\x{57BE}\x{57BF}\x{57C0}\x{57C1}\x{57C2}\x{57C3}\x{57C4}\x{57C5}' . +'\x{57C6}\x{57C7}\x{57C8}\x{57C9}\x{57CB}\x{57CC}\x{57CD}\x{57CE}\x{57CF}' . +'\x{57D0}\x{57D2}\x{57D3}\x{57D4}\x{57D5}\x{57D6}\x{57D8}\x{57D9}\x{57DA}' . +'\x{57DC}\x{57DD}\x{57DF}\x{57E0}\x{57E1}\x{57E2}\x{57E3}\x{57E4}\x{57E5}' . +'\x{57E6}\x{57E7}\x{57E8}\x{57E9}\x{57EA}\x{57EB}\x{57EC}\x{57ED}\x{57EE}' . +'\x{57EF}\x{57F0}\x{57F1}\x{57F2}\x{57F3}\x{57F4}\x{57F5}\x{57F6}\x{57F7}' . +'\x{57F8}\x{57F9}\x{57FA}\x{57FB}\x{57FC}\x{57FD}\x{57FE}\x{57FF}\x{5800}' . +'\x{5801}\x{5802}\x{5803}\x{5804}\x{5805}\x{5806}\x{5807}\x{5808}\x{5809}' . +'\x{580A}\x{580B}\x{580C}\x{580D}\x{580E}\x{580F}\x{5810}\x{5811}\x{5812}' . +'\x{5813}\x{5814}\x{5815}\x{5816}\x{5819}\x{581A}\x{581B}\x{581C}\x{581D}' . +'\x{581E}\x{581F}\x{5820}\x{5821}\x{5822}\x{5823}\x{5824}\x{5825}\x{5826}' . +'\x{5827}\x{5828}\x{5829}\x{582A}\x{582B}\x{582C}\x{582D}\x{582E}\x{582F}' . +'\x{5830}\x{5831}\x{5832}\x{5833}\x{5834}\x{5835}\x{5836}\x{5837}\x{5838}' . +'\x{5839}\x{583A}\x{583B}\x{583C}\x{583D}\x{583E}\x{583F}\x{5840}\x{5842}' . +'\x{5843}\x{5844}\x{5845}\x{5846}\x{5847}\x{5848}\x{5849}\x{584A}\x{584B}' . +'\x{584C}\x{584D}\x{584E}\x{584F}\x{5851}\x{5852}\x{5853}\x{5854}\x{5855}' . +'\x{5857}\x{5858}\x{5859}\x{585A}\x{585B}\x{585C}\x{585D}\x{585E}\x{585F}' . +'\x{5861}\x{5862}\x{5863}\x{5864}\x{5865}\x{5868}\x{5869}\x{586A}\x{586B}' . +'\x{586C}\x{586D}\x{586E}\x{586F}\x{5870}\x{5871}\x{5872}\x{5873}\x{5874}' . +'\x{5875}\x{5876}\x{5878}\x{5879}\x{587A}\x{587B}\x{587C}\x{587D}\x{587E}' . +'\x{587F}\x{5880}\x{5881}\x{5882}\x{5883}\x{5884}\x{5885}\x{5886}\x{5887}' . +'\x{5888}\x{5889}\x{588A}\x{588B}\x{588C}\x{588D}\x{588E}\x{588F}\x{5890}' . +'\x{5891}\x{5892}\x{5893}\x{5894}\x{5896}\x{5897}\x{5898}\x{5899}\x{589A}' . +'\x{589B}\x{589C}\x{589D}\x{589E}\x{589F}\x{58A0}\x{58A1}\x{58A2}\x{58A3}' . +'\x{58A4}\x{58A5}\x{58A6}\x{58A7}\x{58A8}\x{58A9}\x{58AB}\x{58AC}\x{58AD}' . +'\x{58AE}\x{58AF}\x{58B0}\x{58B1}\x{58B2}\x{58B3}\x{58B4}\x{58B7}\x{58B8}' . +'\x{58B9}\x{58BA}\x{58BB}\x{58BC}\x{58BD}\x{58BE}\x{58BF}\x{58C1}\x{58C2}' . +'\x{58C5}\x{58C6}\x{58C7}\x{58C8}\x{58C9}\x{58CA}\x{58CB}\x{58CE}\x{58CF}' . +'\x{58D1}\x{58D2}\x{58D3}\x{58D4}\x{58D5}\x{58D6}\x{58D7}\x{58D8}\x{58D9}' . +'\x{58DA}\x{58DB}\x{58DD}\x{58DE}\x{58DF}\x{58E0}\x{58E2}\x{58E3}\x{58E4}' . +'\x{58E5}\x{58E7}\x{58E8}\x{58E9}\x{58EA}\x{58EB}\x{58EC}\x{58ED}\x{58EE}' . +'\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F3}\x{58F4}\x{58F6}\x{58F7}\x{58F8}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{58FE}\x{58FF}\x{5900}\x{5902}' . +'\x{5903}\x{5904}\x{5906}\x{5907}\x{5909}\x{590A}\x{590B}\x{590C}\x{590D}' . +'\x{590E}\x{590F}\x{5910}\x{5912}\x{5914}\x{5915}\x{5916}\x{5917}\x{5918}' . +'\x{5919}\x{591A}\x{591B}\x{591C}\x{591D}\x{591E}\x{591F}\x{5920}\x{5921}' . +'\x{5922}\x{5924}\x{5925}\x{5926}\x{5927}\x{5928}\x{5929}\x{592A}\x{592B}' . +'\x{592C}\x{592D}\x{592E}\x{592F}\x{5930}\x{5931}\x{5932}\x{5934}\x{5935}' . +'\x{5937}\x{5938}\x{5939}\x{593A}\x{593B}\x{593C}\x{593D}\x{593E}\x{593F}' . +'\x{5940}\x{5941}\x{5942}\x{5943}\x{5944}\x{5945}\x{5946}\x{5947}\x{5948}' . +'\x{5949}\x{594A}\x{594B}\x{594C}\x{594D}\x{594E}\x{594F}\x{5950}\x{5951}' . +'\x{5952}\x{5953}\x{5954}\x{5955}\x{5956}\x{5957}\x{5958}\x{595A}\x{595C}' . +'\x{595D}\x{595E}\x{595F}\x{5960}\x{5961}\x{5962}\x{5963}\x{5964}\x{5965}' . +'\x{5966}\x{5967}\x{5968}\x{5969}\x{596A}\x{596B}\x{596C}\x{596D}\x{596E}' . +'\x{596F}\x{5970}\x{5971}\x{5972}\x{5973}\x{5974}\x{5975}\x{5976}\x{5977}' . +'\x{5978}\x{5979}\x{597A}\x{597B}\x{597C}\x{597D}\x{597E}\x{597F}\x{5980}' . +'\x{5981}\x{5982}\x{5983}\x{5984}\x{5985}\x{5986}\x{5987}\x{5988}\x{5989}' . +'\x{598A}\x{598B}\x{598C}\x{598D}\x{598E}\x{598F}\x{5990}\x{5991}\x{5992}' . +'\x{5993}\x{5994}\x{5995}\x{5996}\x{5997}\x{5998}\x{5999}\x{599A}\x{599C}' . +'\x{599D}\x{599E}\x{599F}\x{59A0}\x{59A1}\x{59A2}\x{59A3}\x{59A4}\x{59A5}' . +'\x{59A6}\x{59A7}\x{59A8}\x{59A9}\x{59AA}\x{59AB}\x{59AC}\x{59AD}\x{59AE}' . +'\x{59AF}\x{59B0}\x{59B1}\x{59B2}\x{59B3}\x{59B4}\x{59B5}\x{59B6}\x{59B8}' . +'\x{59B9}\x{59BA}\x{59BB}\x{59BC}\x{59BD}\x{59BE}\x{59BF}\x{59C0}\x{59C1}' . +'\x{59C2}\x{59C3}\x{59C4}\x{59C5}\x{59C6}\x{59C7}\x{59C8}\x{59C9}\x{59CA}' . +'\x{59CB}\x{59CC}\x{59CD}\x{59CE}\x{59CF}\x{59D0}\x{59D1}\x{59D2}\x{59D3}' . +'\x{59D4}\x{59D5}\x{59D6}\x{59D7}\x{59D8}\x{59D9}\x{59DA}\x{59DB}\x{59DC}' . +'\x{59DD}\x{59DE}\x{59DF}\x{59E0}\x{59E1}\x{59E2}\x{59E3}\x{59E4}\x{59E5}' . +'\x{59E6}\x{59E8}\x{59E9}\x{59EA}\x{59EB}\x{59EC}\x{59ED}\x{59EE}\x{59EF}' . +'\x{59F0}\x{59F1}\x{59F2}\x{59F3}\x{59F4}\x{59F5}\x{59F6}\x{59F7}\x{59F8}' . +'\x{59F9}\x{59FA}\x{59FB}\x{59FC}\x{59FD}\x{59FE}\x{59FF}\x{5A00}\x{5A01}' . +'\x{5A02}\x{5A03}\x{5A04}\x{5A05}\x{5A06}\x{5A07}\x{5A08}\x{5A09}\x{5A0A}' . +'\x{5A0B}\x{5A0C}\x{5A0D}\x{5A0E}\x{5A0F}\x{5A10}\x{5A11}\x{5A12}\x{5A13}' . +'\x{5A14}\x{5A15}\x{5A16}\x{5A17}\x{5A18}\x{5A19}\x{5A1A}\x{5A1B}\x{5A1C}' . +'\x{5A1D}\x{5A1E}\x{5A1F}\x{5A20}\x{5A21}\x{5A22}\x{5A23}\x{5A25}\x{5A27}' . +'\x{5A28}\x{5A29}\x{5A2A}\x{5A2B}\x{5A2D}\x{5A2E}\x{5A2F}\x{5A31}\x{5A32}' . +'\x{5A33}\x{5A34}\x{5A35}\x{5A36}\x{5A37}\x{5A38}\x{5A39}\x{5A3A}\x{5A3B}' . +'\x{5A3C}\x{5A3D}\x{5A3E}\x{5A3F}\x{5A40}\x{5A41}\x{5A42}\x{5A43}\x{5A44}' . +'\x{5A45}\x{5A46}\x{5A47}\x{5A48}\x{5A49}\x{5A4A}\x{5A4B}\x{5A4C}\x{5A4D}' . +'\x{5A4E}\x{5A4F}\x{5A50}\x{5A51}\x{5A52}\x{5A53}\x{5A55}\x{5A56}\x{5A57}' . +'\x{5A58}\x{5A5A}\x{5A5B}\x{5A5C}\x{5A5D}\x{5A5E}\x{5A5F}\x{5A60}\x{5A61}' . +'\x{5A62}\x{5A63}\x{5A64}\x{5A65}\x{5A66}\x{5A67}\x{5A68}\x{5A69}\x{5A6A}' . +'\x{5A6B}\x{5A6C}\x{5A6D}\x{5A6E}\x{5A70}\x{5A72}\x{5A73}\x{5A74}\x{5A75}' . +'\x{5A76}\x{5A77}\x{5A78}\x{5A79}\x{5A7A}\x{5A7B}\x{5A7C}\x{5A7D}\x{5A7E}' . +'\x{5A7F}\x{5A80}\x{5A81}\x{5A82}\x{5A83}\x{5A84}\x{5A85}\x{5A86}\x{5A88}' . +'\x{5A89}\x{5A8A}\x{5A8B}\x{5A8C}\x{5A8E}\x{5A8F}\x{5A90}\x{5A91}\x{5A92}' . +'\x{5A93}\x{5A94}\x{5A95}\x{5A96}\x{5A97}\x{5A98}\x{5A99}\x{5A9A}\x{5A9B}' . +'\x{5A9C}\x{5A9D}\x{5A9E}\x{5A9F}\x{5AA0}\x{5AA1}\x{5AA2}\x{5AA3}\x{5AA4}' . +'\x{5AA5}\x{5AA6}\x{5AA7}\x{5AA8}\x{5AA9}\x{5AAA}\x{5AAC}\x{5AAD}\x{5AAE}' . +'\x{5AAF}\x{5AB0}\x{5AB1}\x{5AB2}\x{5AB3}\x{5AB4}\x{5AB5}\x{5AB6}\x{5AB7}' . +'\x{5AB8}\x{5AB9}\x{5ABA}\x{5ABB}\x{5ABC}\x{5ABD}\x{5ABE}\x{5ABF}\x{5AC0}' . +'\x{5AC1}\x{5AC2}\x{5AC3}\x{5AC4}\x{5AC5}\x{5AC6}\x{5AC7}\x{5AC8}\x{5AC9}' . +'\x{5ACA}\x{5ACB}\x{5ACC}\x{5ACD}\x{5ACE}\x{5ACF}\x{5AD1}\x{5AD2}\x{5AD4}' . +'\x{5AD5}\x{5AD6}\x{5AD7}\x{5AD8}\x{5AD9}\x{5ADA}\x{5ADB}\x{5ADC}\x{5ADD}' . +'\x{5ADE}\x{5ADF}\x{5AE0}\x{5AE1}\x{5AE2}\x{5AE3}\x{5AE4}\x{5AE5}\x{5AE6}' . +'\x{5AE7}\x{5AE8}\x{5AE9}\x{5AEA}\x{5AEB}\x{5AEC}\x{5AED}\x{5AEE}\x{5AF1}' . +'\x{5AF2}\x{5AF3}\x{5AF4}\x{5AF5}\x{5AF6}\x{5AF7}\x{5AF8}\x{5AF9}\x{5AFA}' . +'\x{5AFB}\x{5AFC}\x{5AFD}\x{5AFE}\x{5AFF}\x{5B00}\x{5B01}\x{5B02}\x{5B03}' . +'\x{5B04}\x{5B05}\x{5B06}\x{5B07}\x{5B08}\x{5B09}\x{5B0B}\x{5B0C}\x{5B0E}' . +'\x{5B0F}\x{5B10}\x{5B11}\x{5B12}\x{5B13}\x{5B14}\x{5B15}\x{5B16}\x{5B17}' . +'\x{5B18}\x{5B19}\x{5B1A}\x{5B1B}\x{5B1C}\x{5B1D}\x{5B1E}\x{5B1F}\x{5B20}' . +'\x{5B21}\x{5B22}\x{5B23}\x{5B24}\x{5B25}\x{5B26}\x{5B27}\x{5B28}\x{5B29}' . +'\x{5B2A}\x{5B2B}\x{5B2C}\x{5B2D}\x{5B2E}\x{5B2F}\x{5B30}\x{5B31}\x{5B32}' . +'\x{5B33}\x{5B34}\x{5B35}\x{5B36}\x{5B37}\x{5B38}\x{5B3A}\x{5B3B}\x{5B3C}' . +'\x{5B3D}\x{5B3E}\x{5B3F}\x{5B40}\x{5B41}\x{5B42}\x{5B43}\x{5B44}\x{5B45}' . +'\x{5B47}\x{5B48}\x{5B49}\x{5B4A}\x{5B4B}\x{5B4C}\x{5B4D}\x{5B4E}\x{5B50}' . +'\x{5B51}\x{5B53}\x{5B54}\x{5B55}\x{5B56}\x{5B57}\x{5B58}\x{5B59}\x{5B5A}' . +'\x{5B5B}\x{5B5C}\x{5B5D}\x{5B5E}\x{5B5F}\x{5B62}\x{5B63}\x{5B64}\x{5B65}' . +'\x{5B66}\x{5B67}\x{5B68}\x{5B69}\x{5B6A}\x{5B6B}\x{5B6C}\x{5B6D}\x{5B6E}' . +'\x{5B70}\x{5B71}\x{5B72}\x{5B73}\x{5B74}\x{5B75}\x{5B76}\x{5B77}\x{5B78}' . +'\x{5B7A}\x{5B7B}\x{5B7C}\x{5B7D}\x{5B7F}\x{5B80}\x{5B81}\x{5B82}\x{5B83}' . +'\x{5B84}\x{5B85}\x{5B87}\x{5B88}\x{5B89}\x{5B8A}\x{5B8B}\x{5B8C}\x{5B8D}' . +'\x{5B8E}\x{5B8F}\x{5B91}\x{5B92}\x{5B93}\x{5B94}\x{5B95}\x{5B96}\x{5B97}' . +'\x{5B98}\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9E}\x{5B9F}\x{5BA0}' . +'\x{5BA1}\x{5BA2}\x{5BA3}\x{5BA4}\x{5BA5}\x{5BA6}\x{5BA7}\x{5BA8}\x{5BAA}' . +'\x{5BAB}\x{5BAC}\x{5BAD}\x{5BAE}\x{5BAF}\x{5BB0}\x{5BB1}\x{5BB3}\x{5BB4}' . +'\x{5BB5}\x{5BB6}\x{5BB8}\x{5BB9}\x{5BBA}\x{5BBB}\x{5BBD}\x{5BBE}\x{5BBF}' . +'\x{5BC0}\x{5BC1}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BCA}' . +'\x{5BCB}\x{5BCC}\x{5BCD}\x{5BCE}\x{5BCF}\x{5BD0}\x{5BD1}\x{5BD2}\x{5BD3}' . +'\x{5BD4}\x{5BD5}\x{5BD6}\x{5BD8}\x{5BD9}\x{5BDB}\x{5BDC}\x{5BDD}\x{5BDE}' . +'\x{5BDF}\x{5BE0}\x{5BE1}\x{5BE2}\x{5BE3}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}' . +'\x{5BE8}\x{5BE9}\x{5BEA}\x{5BEB}\x{5BEC}\x{5BED}\x{5BEE}\x{5BEF}\x{5BF0}' . +'\x{5BF1}\x{5BF2}\x{5BF3}\x{5BF4}\x{5BF5}\x{5BF6}\x{5BF7}\x{5BF8}\x{5BF9}' . +'\x{5BFA}\x{5BFB}\x{5BFC}\x{5BFD}\x{5BFF}\x{5C01}\x{5C03}\x{5C04}\x{5C05}' . +'\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}\x{5C0B}\x{5C0C}\x{5C0D}\x{5C0E}' . +'\x{5C0F}\x{5C10}\x{5C11}\x{5C12}\x{5C13}\x{5C14}\x{5C15}\x{5C16}\x{5C17}' . +'\x{5C18}\x{5C19}\x{5C1A}\x{5C1C}\x{5C1D}\x{5C1E}\x{5C1F}\x{5C20}\x{5C21}' . +'\x{5C22}\x{5C24}\x{5C25}\x{5C27}\x{5C28}\x{5C2A}\x{5C2B}\x{5C2C}\x{5C2D}' . +'\x{5C2E}\x{5C2F}\x{5C30}\x{5C31}\x{5C32}\x{5C33}\x{5C34}\x{5C35}\x{5C37}' . +'\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}' . +'\x{5C41}\x{5C42}\x{5C43}\x{5C44}\x{5C45}\x{5C46}\x{5C47}\x{5C48}\x{5C49}' . +'\x{5C4A}\x{5C4B}\x{5C4C}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C52}' . +'\x{5C53}\x{5C54}\x{5C55}\x{5C56}\x{5C57}\x{5C58}\x{5C59}\x{5C5B}\x{5C5C}' . +'\x{5C5D}\x{5C5E}\x{5C5F}\x{5C60}\x{5C61}\x{5C62}\x{5C63}\x{5C64}\x{5C65}' . +'\x{5C66}\x{5C67}\x{5C68}\x{5C69}\x{5C6A}\x{5C6B}\x{5C6C}\x{5C6D}\x{5C6E}' . +'\x{5C6F}\x{5C70}\x{5C71}\x{5C72}\x{5C73}\x{5C74}\x{5C75}\x{5C76}\x{5C77}' . +'\x{5C78}\x{5C79}\x{5C7A}\x{5C7B}\x{5C7C}\x{5C7D}\x{5C7E}\x{5C7F}\x{5C80}' . +'\x{5C81}\x{5C82}\x{5C83}\x{5C84}\x{5C86}\x{5C87}\x{5C88}\x{5C89}\x{5C8A}' . +'\x{5C8B}\x{5C8C}\x{5C8D}\x{5C8E}\x{5C8F}\x{5C90}\x{5C91}\x{5C92}\x{5C93}' . +'\x{5C94}\x{5C95}\x{5C96}\x{5C97}\x{5C98}\x{5C99}\x{5C9A}\x{5C9B}\x{5C9C}' . +'\x{5C9D}\x{5C9E}\x{5C9F}\x{5CA0}\x{5CA1}\x{5CA2}\x{5CA3}\x{5CA4}\x{5CA5}' . +'\x{5CA6}\x{5CA7}\x{5CA8}\x{5CA9}\x{5CAA}\x{5CAB}\x{5CAC}\x{5CAD}\x{5CAE}' . +'\x{5CAF}\x{5CB0}\x{5CB1}\x{5CB2}\x{5CB3}\x{5CB5}\x{5CB6}\x{5CB7}\x{5CB8}' . +'\x{5CBA}\x{5CBB}\x{5CBC}\x{5CBD}\x{5CBE}\x{5CBF}\x{5CC1}\x{5CC2}\x{5CC3}' . +'\x{5CC4}\x{5CC5}\x{5CC6}\x{5CC7}\x{5CC8}\x{5CC9}\x{5CCA}\x{5CCB}\x{5CCC}' . +'\x{5CCD}\x{5CCE}\x{5CCF}\x{5CD0}\x{5CD1}\x{5CD2}\x{5CD3}\x{5CD4}\x{5CD6}' . +'\x{5CD7}\x{5CD8}\x{5CD9}\x{5CDA}\x{5CDB}\x{5CDC}\x{5CDE}\x{5CDF}\x{5CE0}' . +'\x{5CE1}\x{5CE2}\x{5CE3}\x{5CE4}\x{5CE5}\x{5CE6}\x{5CE7}\x{5CE8}\x{5CE9}' . +'\x{5CEA}\x{5CEB}\x{5CEC}\x{5CED}\x{5CEE}\x{5CEF}\x{5CF0}\x{5CF1}\x{5CF2}' . +'\x{5CF3}\x{5CF4}\x{5CF6}\x{5CF7}\x{5CF8}\x{5CF9}\x{5CFA}\x{5CFB}\x{5CFC}' . +'\x{5CFD}\x{5CFE}\x{5CFF}\x{5D00}\x{5D01}\x{5D02}\x{5D03}\x{5D04}\x{5D05}' . +'\x{5D06}\x{5D07}\x{5D08}\x{5D09}\x{5D0A}\x{5D0B}\x{5D0C}\x{5D0D}\x{5D0E}' . +'\x{5D0F}\x{5D10}\x{5D11}\x{5D12}\x{5D13}\x{5D14}\x{5D15}\x{5D16}\x{5D17}' . +'\x{5D18}\x{5D19}\x{5D1A}\x{5D1B}\x{5D1C}\x{5D1D}\x{5D1E}\x{5D1F}\x{5D20}' . +'\x{5D21}\x{5D22}\x{5D23}\x{5D24}\x{5D25}\x{5D26}\x{5D27}\x{5D28}\x{5D29}' . +'\x{5D2A}\x{5D2C}\x{5D2D}\x{5D2E}\x{5D30}\x{5D31}\x{5D32}\x{5D33}\x{5D34}' . +'\x{5D35}\x{5D36}\x{5D37}\x{5D38}\x{5D39}\x{5D3A}\x{5D3C}\x{5D3D}\x{5D3E}' . +'\x{5D3F}\x{5D40}\x{5D41}\x{5D42}\x{5D43}\x{5D44}\x{5D45}\x{5D46}\x{5D47}' . +'\x{5D48}\x{5D49}\x{5D4A}\x{5D4B}\x{5D4C}\x{5D4D}\x{5D4E}\x{5D4F}\x{5D50}' . +'\x{5D51}\x{5D52}\x{5D54}\x{5D55}\x{5D56}\x{5D58}\x{5D59}\x{5D5A}\x{5D5B}' . +'\x{5D5D}\x{5D5E}\x{5D5F}\x{5D61}\x{5D62}\x{5D63}\x{5D64}\x{5D65}\x{5D66}' . +'\x{5D67}\x{5D68}\x{5D69}\x{5D6A}\x{5D6B}\x{5D6C}\x{5D6D}\x{5D6E}\x{5D6F}' . +'\x{5D70}\x{5D71}\x{5D72}\x{5D73}\x{5D74}\x{5D75}\x{5D76}\x{5D77}\x{5D78}' . +'\x{5D79}\x{5D7A}\x{5D7B}\x{5D7C}\x{5D7D}\x{5D7E}\x{5D7F}\x{5D80}\x{5D81}' . +'\x{5D82}\x{5D84}\x{5D85}\x{5D86}\x{5D87}\x{5D88}\x{5D89}\x{5D8A}\x{5D8B}' . +'\x{5D8C}\x{5D8D}\x{5D8E}\x{5D8F}\x{5D90}\x{5D91}\x{5D92}\x{5D93}\x{5D94}' . +'\x{5D95}\x{5D97}\x{5D98}\x{5D99}\x{5D9A}\x{5D9B}\x{5D9C}\x{5D9D}\x{5D9E}' . +'\x{5D9F}\x{5DA0}\x{5DA1}\x{5DA2}\x{5DA5}\x{5DA6}\x{5DA7}\x{5DA8}\x{5DA9}' . +'\x{5DAA}\x{5DAC}\x{5DAD}\x{5DAE}\x{5DAF}\x{5DB0}\x{5DB1}\x{5DB2}\x{5DB4}' . +'\x{5DB5}\x{5DB6}\x{5DB7}\x{5DB8}\x{5DBA}\x{5DBB}\x{5DBC}\x{5DBD}\x{5DBE}' . +'\x{5DBF}\x{5DC0}\x{5DC1}\x{5DC2}\x{5DC3}\x{5DC5}\x{5DC6}\x{5DC7}\x{5DC8}' . +'\x{5DC9}\x{5DCA}\x{5DCB}\x{5DCC}\x{5DCD}\x{5DCE}\x{5DCF}\x{5DD0}\x{5DD1}' . +'\x{5DD2}\x{5DD3}\x{5DD4}\x{5DD5}\x{5DD6}\x{5DD8}\x{5DD9}\x{5DDB}\x{5DDD}' . +'\x{5DDE}\x{5DDF}\x{5DE0}\x{5DE1}\x{5DE2}\x{5DE3}\x{5DE4}\x{5DE5}\x{5DE6}' . +'\x{5DE7}\x{5DE8}\x{5DE9}\x{5DEA}\x{5DEB}\x{5DEC}\x{5DED}\x{5DEE}\x{5DEF}' . +'\x{5DF0}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DF8}\x{5DF9}' . +'\x{5DFA}\x{5DFB}\x{5DFC}\x{5DFD}\x{5DFE}\x{5DFF}\x{5E00}\x{5E01}\x{5E02}' . +'\x{5E03}\x{5E04}\x{5E05}\x{5E06}\x{5E07}\x{5E08}\x{5E09}\x{5E0A}\x{5E0B}' . +'\x{5E0C}\x{5E0D}\x{5E0E}\x{5E0F}\x{5E10}\x{5E11}\x{5E13}\x{5E14}\x{5E15}' . +'\x{5E16}\x{5E17}\x{5E18}\x{5E19}\x{5E1A}\x{5E1B}\x{5E1C}\x{5E1D}\x{5E1E}' . +'\x{5E1F}\x{5E20}\x{5E21}\x{5E22}\x{5E23}\x{5E24}\x{5E25}\x{5E26}\x{5E27}' . +'\x{5E28}\x{5E29}\x{5E2A}\x{5E2B}\x{5E2C}\x{5E2D}\x{5E2E}\x{5E2F}\x{5E30}' . +'\x{5E31}\x{5E32}\x{5E33}\x{5E34}\x{5E35}\x{5E36}\x{5E37}\x{5E38}\x{5E39}' . +'\x{5E3A}\x{5E3B}\x{5E3C}\x{5E3D}\x{5E3E}\x{5E40}\x{5E41}\x{5E42}\x{5E43}' . +'\x{5E44}\x{5E45}\x{5E46}\x{5E47}\x{5E49}\x{5E4A}\x{5E4B}\x{5E4C}\x{5E4D}' . +'\x{5E4E}\x{5E4F}\x{5E50}\x{5E52}\x{5E53}\x{5E54}\x{5E55}\x{5E56}\x{5E57}' . +'\x{5E58}\x{5E59}\x{5E5A}\x{5E5B}\x{5E5C}\x{5E5D}\x{5E5E}\x{5E5F}\x{5E60}' . +'\x{5E61}\x{5E62}\x{5E63}\x{5E64}\x{5E65}\x{5E66}\x{5E67}\x{5E68}\x{5E69}' . +'\x{5E6A}\x{5E6B}\x{5E6C}\x{5E6D}\x{5E6E}\x{5E6F}\x{5E70}\x{5E71}\x{5E72}' . +'\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E77}\x{5E78}\x{5E79}\x{5E7A}\x{5E7B}' . +'\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E80}\x{5E81}\x{5E82}\x{5E83}\x{5E84}' . +'\x{5E85}\x{5E86}\x{5E87}\x{5E88}\x{5E89}\x{5E8A}\x{5E8B}\x{5E8C}\x{5E8D}' . +'\x{5E8E}\x{5E8F}\x{5E90}\x{5E91}\x{5E93}\x{5E94}\x{5E95}\x{5E96}\x{5E97}' . +'\x{5E98}\x{5E99}\x{5E9A}\x{5E9B}\x{5E9C}\x{5E9D}\x{5E9E}\x{5E9F}\x{5EA0}' . +'\x{5EA1}\x{5EA2}\x{5EA3}\x{5EA4}\x{5EA5}\x{5EA6}\x{5EA7}\x{5EA8}\x{5EA9}' . +'\x{5EAA}\x{5EAB}\x{5EAC}\x{5EAD}\x{5EAE}\x{5EAF}\x{5EB0}\x{5EB1}\x{5EB2}' . +'\x{5EB3}\x{5EB4}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EB9}\x{5EBB}\x{5EBC}' . +'\x{5EBD}\x{5EBE}\x{5EBF}\x{5EC1}\x{5EC2}\x{5EC3}\x{5EC4}\x{5EC5}\x{5EC6}' . +'\x{5EC7}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECB}\x{5ECC}\x{5ECD}\x{5ECE}\x{5ECF}' . +'\x{5ED0}\x{5ED1}\x{5ED2}\x{5ED3}\x{5ED4}\x{5ED5}\x{5ED6}\x{5ED7}\x{5ED8}' . +'\x{5ED9}\x{5EDA}\x{5EDB}\x{5EDC}\x{5EDD}\x{5EDE}\x{5EDF}\x{5EE0}\x{5EE1}' . +'\x{5EE2}\x{5EE3}\x{5EE4}\x{5EE5}\x{5EE6}\x{5EE7}\x{5EE8}\x{5EE9}\x{5EEA}' . +'\x{5EEC}\x{5EED}\x{5EEE}\x{5EEF}\x{5EF0}\x{5EF1}\x{5EF2}\x{5EF3}\x{5EF4}' . +'\x{5EF5}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}\x{5EFB}\x{5EFC}\x{5EFD}\x{5EFE}' . +'\x{5EFF}\x{5F00}\x{5F01}\x{5F02}\x{5F03}\x{5F04}\x{5F05}\x{5F06}\x{5F07}' . +'\x{5F08}\x{5F0A}\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F11}\x{5F12}\x{5F13}' . +'\x{5F14}\x{5F15}\x{5F16}\x{5F17}\x{5F18}\x{5F19}\x{5F1A}\x{5F1B}\x{5F1C}' . +'\x{5F1D}\x{5F1E}\x{5F1F}\x{5F20}\x{5F21}\x{5F22}\x{5F23}\x{5F24}\x{5F25}' . +'\x{5F26}\x{5F27}\x{5F28}\x{5F29}\x{5F2A}\x{5F2B}\x{5F2C}\x{5F2D}\x{5F2E}' . +'\x{5F2F}\x{5F30}\x{5F31}\x{5F32}\x{5F33}\x{5F34}\x{5F35}\x{5F36}\x{5F37}' . +'\x{5F38}\x{5F39}\x{5F3A}\x{5F3C}\x{5F3E}\x{5F3F}\x{5F40}\x{5F41}\x{5F42}' . +'\x{5F43}\x{5F44}\x{5F45}\x{5F46}\x{5F47}\x{5F48}\x{5F49}\x{5F4A}\x{5F4B}' . +'\x{5F4C}\x{5F4D}\x{5F4E}\x{5F4F}\x{5F50}\x{5F51}\x{5F52}\x{5F53}\x{5F54}' . +'\x{5F55}\x{5F56}\x{5F57}\x{5F58}\x{5F59}\x{5F5A}\x{5F5B}\x{5F5C}\x{5F5D}' . +'\x{5F5E}\x{5F5F}\x{5F60}\x{5F61}\x{5F62}\x{5F63}\x{5F64}\x{5F65}\x{5F66}' . +'\x{5F67}\x{5F68}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}\x{5F6D}\x{5F6E}\x{5F6F}' . +'\x{5F70}\x{5F71}\x{5F72}\x{5F73}\x{5F74}\x{5F75}\x{5F76}\x{5F77}\x{5F78}' . +'\x{5F79}\x{5F7A}\x{5F7B}\x{5F7C}\x{5F7D}\x{5F7E}\x{5F7F}\x{5F80}\x{5F81}' . +'\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F86}\x{5F87}\x{5F88}\x{5F89}\x{5F8A}' . +'\x{5F8B}\x{5F8C}\x{5F8D}\x{5F8E}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F94}' . +'\x{5F95}\x{5F96}\x{5F97}\x{5F98}\x{5F99}\x{5F9B}\x{5F9C}\x{5F9D}\x{5F9E}' . +'\x{5F9F}\x{5FA0}\x{5FA1}\x{5FA2}\x{5FA5}\x{5FA6}\x{5FA7}\x{5FA8}\x{5FA9}' . +'\x{5FAA}\x{5FAB}\x{5FAC}\x{5FAD}\x{5FAE}\x{5FAF}\x{5FB1}\x{5FB2}\x{5FB3}' . +'\x{5FB4}\x{5FB5}\x{5FB6}\x{5FB7}\x{5FB8}\x{5FB9}\x{5FBA}\x{5FBB}\x{5FBC}' . +'\x{5FBD}\x{5FBE}\x{5FBF}\x{5FC0}\x{5FC1}\x{5FC3}\x{5FC4}\x{5FC5}\x{5FC6}' . +'\x{5FC7}\x{5FC8}\x{5FC9}\x{5FCA}\x{5FCB}\x{5FCC}\x{5FCD}\x{5FCF}\x{5FD0}' . +'\x{5FD1}\x{5FD2}\x{5FD3}\x{5FD4}\x{5FD5}\x{5FD6}\x{5FD7}\x{5FD8}\x{5FD9}' . +'\x{5FDA}\x{5FDC}\x{5FDD}\x{5FDE}\x{5FE0}\x{5FE1}\x{5FE3}\x{5FE4}\x{5FE5}' . +'\x{5FE6}\x{5FE7}\x{5FE8}\x{5FE9}\x{5FEA}\x{5FEB}\x{5FED}\x{5FEE}\x{5FEF}' . +'\x{5FF0}\x{5FF1}\x{5FF2}\x{5FF3}\x{5FF4}\x{5FF5}\x{5FF6}\x{5FF7}\x{5FF8}' . +'\x{5FF9}\x{5FFA}\x{5FFB}\x{5FFD}\x{5FFE}\x{5FFF}\x{6000}\x{6001}\x{6002}' . +'\x{6003}\x{6004}\x{6005}\x{6006}\x{6007}\x{6008}\x{6009}\x{600A}\x{600B}' . +'\x{600C}\x{600D}\x{600E}\x{600F}\x{6010}\x{6011}\x{6012}\x{6013}\x{6014}' . +'\x{6015}\x{6016}\x{6017}\x{6018}\x{6019}\x{601A}\x{601B}\x{601C}\x{601D}' . +'\x{601E}\x{601F}\x{6020}\x{6021}\x{6022}\x{6024}\x{6025}\x{6026}\x{6027}' . +'\x{6028}\x{6029}\x{602A}\x{602B}\x{602C}\x{602D}\x{602E}\x{602F}\x{6030}' . +'\x{6031}\x{6032}\x{6033}\x{6034}\x{6035}\x{6036}\x{6037}\x{6038}\x{6039}' . +'\x{603A}\x{603B}\x{603C}\x{603D}\x{603E}\x{603F}\x{6040}\x{6041}\x{6042}' . +'\x{6043}\x{6044}\x{6045}\x{6046}\x{6047}\x{6048}\x{6049}\x{604A}\x{604B}' . +'\x{604C}\x{604D}\x{604E}\x{604F}\x{6050}\x{6051}\x{6052}\x{6053}\x{6054}' . +'\x{6055}\x{6057}\x{6058}\x{6059}\x{605A}\x{605B}\x{605C}\x{605D}\x{605E}' . +'\x{605F}\x{6062}\x{6063}\x{6064}\x{6065}\x{6066}\x{6067}\x{6068}\x{6069}' . +'\x{606A}\x{606B}\x{606C}\x{606D}\x{606E}\x{606F}\x{6070}\x{6072}\x{6073}' . +'\x{6075}\x{6076}\x{6077}\x{6078}\x{6079}\x{607A}\x{607B}\x{607C}\x{607D}' . +'\x{607E}\x{607F}\x{6080}\x{6081}\x{6082}\x{6083}\x{6084}\x{6085}\x{6086}' . +'\x{6087}\x{6088}\x{6089}\x{608A}\x{608B}\x{608C}\x{608D}\x{608E}\x{608F}' . +'\x{6090}\x{6092}\x{6094}\x{6095}\x{6096}\x{6097}\x{6098}\x{6099}\x{609A}' . +'\x{609B}\x{609C}\x{609D}\x{609E}\x{609F}\x{60A0}\x{60A1}\x{60A2}\x{60A3}' . +'\x{60A4}\x{60A6}\x{60A7}\x{60A8}\x{60AA}\x{60AB}\x{60AC}\x{60AD}\x{60AE}' . +'\x{60AF}\x{60B0}\x{60B1}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B7}' . +'\x{60B8}\x{60B9}\x{60BA}\x{60BB}\x{60BC}\x{60BD}\x{60BE}\x{60BF}\x{60C0}' . +'\x{60C1}\x{60C2}\x{60C3}\x{60C4}\x{60C5}\x{60C6}\x{60C7}\x{60C8}\x{60C9}' . +'\x{60CA}\x{60CB}\x{60CC}\x{60CD}\x{60CE}\x{60CF}\x{60D0}\x{60D1}\x{60D3}' . +'\x{60D4}\x{60D5}\x{60D7}\x{60D8}\x{60D9}\x{60DA}\x{60DB}\x{60DC}\x{60DD}' . +'\x{60DF}\x{60E0}\x{60E1}\x{60E2}\x{60E4}\x{60E6}\x{60E7}\x{60E8}\x{60E9}' . +'\x{60EA}\x{60EB}\x{60EC}\x{60ED}\x{60EE}\x{60EF}\x{60F0}\x{60F1}\x{60F2}' . +'\x{60F3}\x{60F4}\x{60F5}\x{60F6}\x{60F7}\x{60F8}\x{60F9}\x{60FA}\x{60FB}' . +'\x{60FC}\x{60FE}\x{60FF}\x{6100}\x{6101}\x{6103}\x{6104}\x{6105}\x{6106}' . +'\x{6108}\x{6109}\x{610A}\x{610B}\x{610C}\x{610D}\x{610E}\x{610F}\x{6110}' . +'\x{6112}\x{6113}\x{6114}\x{6115}\x{6116}\x{6117}\x{6118}\x{6119}\x{611A}' . +'\x{611B}\x{611C}\x{611D}\x{611F}\x{6120}\x{6122}\x{6123}\x{6124}\x{6125}' . +'\x{6126}\x{6127}\x{6128}\x{6129}\x{612A}\x{612B}\x{612C}\x{612D}\x{612E}' . +'\x{612F}\x{6130}\x{6132}\x{6134}\x{6136}\x{6137}\x{613A}\x{613B}\x{613C}' . +'\x{613D}\x{613E}\x{613F}\x{6140}\x{6141}\x{6142}\x{6143}\x{6144}\x{6145}' . +'\x{6146}\x{6147}\x{6148}\x{6149}\x{614A}\x{614B}\x{614C}\x{614D}\x{614E}' . +'\x{614F}\x{6150}\x{6151}\x{6152}\x{6153}\x{6154}\x{6155}\x{6156}\x{6157}' . +'\x{6158}\x{6159}\x{615A}\x{615B}\x{615C}\x{615D}\x{615E}\x{615F}\x{6161}' . +'\x{6162}\x{6163}\x{6164}\x{6165}\x{6166}\x{6167}\x{6168}\x{6169}\x{616A}' . +'\x{616B}\x{616C}\x{616D}\x{616E}\x{6170}\x{6171}\x{6172}\x{6173}\x{6174}' . +'\x{6175}\x{6176}\x{6177}\x{6178}\x{6179}\x{617A}\x{617C}\x{617E}\x{6180}' . +'\x{6181}\x{6182}\x{6183}\x{6184}\x{6185}\x{6187}\x{6188}\x{6189}\x{618A}' . +'\x{618B}\x{618C}\x{618D}\x{618E}\x{618F}\x{6190}\x{6191}\x{6192}\x{6193}' . +'\x{6194}\x{6195}\x{6196}\x{6198}\x{6199}\x{619A}\x{619B}\x{619D}\x{619E}' . +'\x{619F}\x{61A0}\x{61A1}\x{61A2}\x{61A3}\x{61A4}\x{61A5}\x{61A6}\x{61A7}' . +'\x{61A8}\x{61A9}\x{61AA}\x{61AB}\x{61AC}\x{61AD}\x{61AE}\x{61AF}\x{61B0}' . +'\x{61B1}\x{61B2}\x{61B3}\x{61B4}\x{61B5}\x{61B6}\x{61B7}\x{61B8}\x{61BA}' . +'\x{61BC}\x{61BD}\x{61BE}\x{61BF}\x{61C0}\x{61C1}\x{61C2}\x{61C3}\x{61C4}' . +'\x{61C5}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61CE}\x{61CF}\x{61D0}\x{61D1}\x{61D2}\x{61D4}\x{61D6}\x{61D7}\x{61D8}' . +'\x{61D9}\x{61DA}\x{61DB}\x{61DC}\x{61DD}\x{61DE}\x{61DF}\x{61E0}\x{61E1}' . +'\x{61E2}\x{61E3}\x{61E4}\x{61E5}\x{61E6}\x{61E7}\x{61E8}\x{61E9}\x{61EA}' . +'\x{61EB}\x{61ED}\x{61EE}\x{61F0}\x{61F1}\x{61F2}\x{61F3}\x{61F5}\x{61F6}' . +'\x{61F7}\x{61F8}\x{61F9}\x{61FA}\x{61FB}\x{61FC}\x{61FD}\x{61FE}\x{61FF}' . +'\x{6200}\x{6201}\x{6202}\x{6203}\x{6204}\x{6206}\x{6207}\x{6208}\x{6209}' . +'\x{620A}\x{620B}\x{620C}\x{620D}\x{620E}\x{620F}\x{6210}\x{6211}\x{6212}' . +'\x{6213}\x{6214}\x{6215}\x{6216}\x{6217}\x{6218}\x{6219}\x{621A}\x{621B}' . +'\x{621C}\x{621D}\x{621E}\x{621F}\x{6220}\x{6221}\x{6222}\x{6223}\x{6224}' . +'\x{6225}\x{6226}\x{6227}\x{6228}\x{6229}\x{622A}\x{622B}\x{622C}\x{622D}' . +'\x{622E}\x{622F}\x{6230}\x{6231}\x{6232}\x{6233}\x{6234}\x{6236}\x{6237}' . +'\x{6238}\x{623A}\x{623B}\x{623C}\x{623D}\x{623E}\x{623F}\x{6240}\x{6241}' . +'\x{6242}\x{6243}\x{6244}\x{6245}\x{6246}\x{6247}\x{6248}\x{6249}\x{624A}' . +'\x{624B}\x{624C}\x{624D}\x{624E}\x{624F}\x{6250}\x{6251}\x{6252}\x{6253}' . +'\x{6254}\x{6255}\x{6256}\x{6258}\x{6259}\x{625A}\x{625B}\x{625C}\x{625D}' . +'\x{625E}\x{625F}\x{6260}\x{6261}\x{6262}\x{6263}\x{6264}\x{6265}\x{6266}' . +'\x{6267}\x{6268}\x{6269}\x{626A}\x{626B}\x{626C}\x{626D}\x{626E}\x{626F}' . +'\x{6270}\x{6271}\x{6272}\x{6273}\x{6274}\x{6275}\x{6276}\x{6277}\x{6278}' . +'\x{6279}\x{627A}\x{627B}\x{627C}\x{627D}\x{627E}\x{627F}\x{6280}\x{6281}' . +'\x{6283}\x{6284}\x{6285}\x{6286}\x{6287}\x{6288}\x{6289}\x{628A}\x{628B}' . +'\x{628C}\x{628E}\x{628F}\x{6290}\x{6291}\x{6292}\x{6293}\x{6294}\x{6295}' . +'\x{6296}\x{6297}\x{6298}\x{6299}\x{629A}\x{629B}\x{629C}\x{629E}\x{629F}' . +'\x{62A0}\x{62A1}\x{62A2}\x{62A3}\x{62A4}\x{62A5}\x{62A7}\x{62A8}\x{62A9}' . +'\x{62AA}\x{62AB}\x{62AC}\x{62AD}\x{62AE}\x{62AF}\x{62B0}\x{62B1}\x{62B2}' . +'\x{62B3}\x{62B4}\x{62B5}\x{62B6}\x{62B7}\x{62B8}\x{62B9}\x{62BA}\x{62BB}' . +'\x{62BC}\x{62BD}\x{62BE}\x{62BF}\x{62C0}\x{62C1}\x{62C2}\x{62C3}\x{62C4}' . +'\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CB}\x{62CC}\x{62CD}' . +'\x{62CE}\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D5}\x{62D6}' . +'\x{62D7}\x{62D8}\x{62D9}\x{62DA}\x{62DB}\x{62DC}\x{62DD}\x{62DF}\x{62E0}' . +'\x{62E1}\x{62E2}\x{62E3}\x{62E4}\x{62E5}\x{62E6}\x{62E7}\x{62E8}\x{62E9}' . +'\x{62EB}\x{62EC}\x{62ED}\x{62EE}\x{62EF}\x{62F0}\x{62F1}\x{62F2}\x{62F3}' . +'\x{62F4}\x{62F5}\x{62F6}\x{62F7}\x{62F8}\x{62F9}\x{62FA}\x{62FB}\x{62FC}' . +'\x{62FD}\x{62FE}\x{62FF}\x{6300}\x{6301}\x{6302}\x{6303}\x{6304}\x{6305}' . +'\x{6306}\x{6307}\x{6308}\x{6309}\x{630B}\x{630C}\x{630D}\x{630E}\x{630F}' . +'\x{6310}\x{6311}\x{6312}\x{6313}\x{6314}\x{6315}\x{6316}\x{6318}\x{6319}' . +'\x{631A}\x{631B}\x{631C}\x{631D}\x{631E}\x{631F}\x{6320}\x{6321}\x{6322}' . +'\x{6323}\x{6324}\x{6325}\x{6326}\x{6327}\x{6328}\x{6329}\x{632A}\x{632B}' . +'\x{632C}\x{632D}\x{632E}\x{632F}\x{6330}\x{6332}\x{6333}\x{6334}\x{6336}' . +'\x{6338}\x{6339}\x{633A}\x{633B}\x{633C}\x{633D}\x{633E}\x{6340}\x{6341}' . +'\x{6342}\x{6343}\x{6344}\x{6345}\x{6346}\x{6347}\x{6348}\x{6349}\x{634A}' . +'\x{634B}\x{634C}\x{634D}\x{634E}\x{634F}\x{6350}\x{6351}\x{6352}\x{6353}' . +'\x{6354}\x{6355}\x{6356}\x{6357}\x{6358}\x{6359}\x{635A}\x{635C}\x{635D}' . +'\x{635E}\x{635F}\x{6360}\x{6361}\x{6362}\x{6363}\x{6364}\x{6365}\x{6366}' . +'\x{6367}\x{6368}\x{6369}\x{636A}\x{636B}\x{636C}\x{636D}\x{636E}\x{636F}' . +'\x{6370}\x{6371}\x{6372}\x{6373}\x{6374}\x{6375}\x{6376}\x{6377}\x{6378}' . +'\x{6379}\x{637A}\x{637B}\x{637C}\x{637D}\x{637E}\x{6380}\x{6381}\x{6382}' . +'\x{6383}\x{6384}\x{6385}\x{6386}\x{6387}\x{6388}\x{6389}\x{638A}\x{638C}' . +'\x{638D}\x{638E}\x{638F}\x{6390}\x{6391}\x{6392}\x{6394}\x{6395}\x{6396}' . +'\x{6397}\x{6398}\x{6399}\x{639A}\x{639B}\x{639C}\x{639D}\x{639E}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A4}\x{63A5}\x{63A6}\x{63A7}\x{63A8}' . +'\x{63A9}\x{63AA}\x{63AB}\x{63AC}\x{63AD}\x{63AE}\x{63AF}\x{63B0}\x{63B1}' . +'\x{63B2}\x{63B3}\x{63B4}\x{63B5}\x{63B6}\x{63B7}\x{63B8}\x{63B9}\x{63BA}' . +'\x{63BC}\x{63BD}\x{63BE}\x{63BF}\x{63C0}\x{63C1}\x{63C2}\x{63C3}\x{63C4}' . +'\x{63C5}\x{63C6}\x{63C7}\x{63C8}\x{63C9}\x{63CA}\x{63CB}\x{63CC}\x{63CD}' . +'\x{63CE}\x{63CF}\x{63D0}\x{63D2}\x{63D3}\x{63D4}\x{63D5}\x{63D6}\x{63D7}' . +'\x{63D8}\x{63D9}\x{63DA}\x{63DB}\x{63DC}\x{63DD}\x{63DE}\x{63DF}\x{63E0}' . +'\x{63E1}\x{63E2}\x{63E3}\x{63E4}\x{63E5}\x{63E6}\x{63E7}\x{63E8}\x{63E9}' . +'\x{63EA}\x{63EB}\x{63EC}\x{63ED}\x{63EE}\x{63EF}\x{63F0}\x{63F1}\x{63F2}' . +'\x{63F3}\x{63F4}\x{63F5}\x{63F6}\x{63F7}\x{63F8}\x{63F9}\x{63FA}\x{63FB}' . +'\x{63FC}\x{63FD}\x{63FE}\x{63FF}\x{6400}\x{6401}\x{6402}\x{6403}\x{6404}' . +'\x{6405}\x{6406}\x{6408}\x{6409}\x{640A}\x{640B}\x{640C}\x{640D}\x{640E}' . +'\x{640F}\x{6410}\x{6411}\x{6412}\x{6413}\x{6414}\x{6415}\x{6416}\x{6417}' . +'\x{6418}\x{6419}\x{641A}\x{641B}\x{641C}\x{641D}\x{641E}\x{641F}\x{6420}' . +'\x{6421}\x{6422}\x{6423}\x{6424}\x{6425}\x{6426}\x{6427}\x{6428}\x{6429}' . +'\x{642A}\x{642B}\x{642C}\x{642D}\x{642E}\x{642F}\x{6430}\x{6431}\x{6432}' . +'\x{6433}\x{6434}\x{6435}\x{6436}\x{6437}\x{6438}\x{6439}\x{643A}\x{643D}' . +'\x{643E}\x{643F}\x{6440}\x{6441}\x{6443}\x{6444}\x{6445}\x{6446}\x{6447}' . +'\x{6448}\x{644A}\x{644B}\x{644C}\x{644D}\x{644E}\x{644F}\x{6450}\x{6451}' . +'\x{6452}\x{6453}\x{6454}\x{6455}\x{6456}\x{6457}\x{6458}\x{6459}\x{645B}' . +'\x{645C}\x{645D}\x{645E}\x{645F}\x{6460}\x{6461}\x{6462}\x{6463}\x{6464}' . +'\x{6465}\x{6466}\x{6467}\x{6468}\x{6469}\x{646A}\x{646B}\x{646C}\x{646D}' . +'\x{646E}\x{646F}\x{6470}\x{6471}\x{6472}\x{6473}\x{6474}\x{6475}\x{6476}' . +'\x{6477}\x{6478}\x{6479}\x{647A}\x{647B}\x{647C}\x{647D}\x{647F}\x{6480}' . +'\x{6481}\x{6482}\x{6483}\x{6484}\x{6485}\x{6487}\x{6488}\x{6489}\x{648A}' . +'\x{648B}\x{648C}\x{648D}\x{648E}\x{648F}\x{6490}\x{6491}\x{6492}\x{6493}' . +'\x{6494}\x{6495}\x{6496}\x{6497}\x{6498}\x{6499}\x{649A}\x{649B}\x{649C}' . +'\x{649D}\x{649E}\x{649F}\x{64A0}\x{64A2}\x{64A3}\x{64A4}\x{64A5}\x{64A6}' . +'\x{64A7}\x{64A8}\x{64A9}\x{64AA}\x{64AB}\x{64AC}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B1}\x{64B2}\x{64B3}\x{64B4}\x{64B5}\x{64B7}\x{64B8}\x{64B9}\x{64BA}' . +'\x{64BB}\x{64BC}\x{64BD}\x{64BE}\x{64BF}\x{64C0}\x{64C1}\x{64C2}\x{64C3}' . +'\x{64C4}\x{64C5}\x{64C6}\x{64C7}\x{64C9}\x{64CA}\x{64CB}\x{64CC}\x{64CD}' . +'\x{64CE}\x{64CF}\x{64D0}\x{64D1}\x{64D2}\x{64D3}\x{64D4}\x{64D6}\x{64D7}' . +'\x{64D8}\x{64D9}\x{64DA}\x{64DB}\x{64DC}\x{64DD}\x{64DE}\x{64DF}\x{64E0}' . +'\x{64E2}\x{64E3}\x{64E4}\x{64E6}\x{64E7}\x{64E8}\x{64E9}\x{64EA}\x{64EB}' . +'\x{64EC}\x{64ED}\x{64EF}\x{64F0}\x{64F1}\x{64F2}\x{64F3}\x{64F4}\x{64F6}' . +'\x{64F7}\x{64F8}\x{64FA}\x{64FB}\x{64FC}\x{64FD}\x{64FE}\x{64FF}\x{6500}' . +'\x{6501}\x{6503}\x{6504}\x{6505}\x{6506}\x{6507}\x{6508}\x{6509}\x{650B}' . +'\x{650C}\x{650D}\x{650E}\x{650F}\x{6510}\x{6511}\x{6512}\x{6513}\x{6514}' . +'\x{6515}\x{6516}\x{6517}\x{6518}\x{6519}\x{651A}\x{651B}\x{651C}\x{651D}' . +'\x{651E}\x{6520}\x{6521}\x{6522}\x{6523}\x{6524}\x{6525}\x{6526}\x{6527}' . +'\x{6529}\x{652A}\x{652B}\x{652C}\x{652D}\x{652E}\x{652F}\x{6530}\x{6531}' . +'\x{6532}\x{6533}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}\x{653A}' . +'\x{653B}\x{653C}\x{653D}\x{653E}\x{653F}\x{6541}\x{6543}\x{6544}\x{6545}' . +'\x{6546}\x{6547}\x{6548}\x{6549}\x{654A}\x{654B}\x{654C}\x{654D}\x{654E}' . +'\x{654F}\x{6550}\x{6551}\x{6552}\x{6553}\x{6554}\x{6555}\x{6556}\x{6557}' . +'\x{6558}\x{6559}\x{655B}\x{655C}\x{655D}\x{655E}\x{6560}\x{6561}\x{6562}' . +'\x{6563}\x{6564}\x{6565}\x{6566}\x{6567}\x{6568}\x{6569}\x{656A}\x{656B}' . +'\x{656C}\x{656E}\x{656F}\x{6570}\x{6571}\x{6572}\x{6573}\x{6574}\x{6575}' . +'\x{6576}\x{6577}\x{6578}\x{6579}\x{657A}\x{657B}\x{657C}\x{657E}\x{657F}' . +'\x{6580}\x{6581}\x{6582}\x{6583}\x{6584}\x{6585}\x{6586}\x{6587}\x{6588}' . +'\x{6589}\x{658B}\x{658C}\x{658D}\x{658E}\x{658F}\x{6590}\x{6591}\x{6592}' . +'\x{6593}\x{6594}\x{6595}\x{6596}\x{6597}\x{6598}\x{6599}\x{659B}\x{659C}' . +'\x{659D}\x{659E}\x{659F}\x{65A0}\x{65A1}\x{65A2}\x{65A3}\x{65A4}\x{65A5}' . +'\x{65A6}\x{65A7}\x{65A8}\x{65A9}\x{65AA}\x{65AB}\x{65AC}\x{65AD}\x{65AE}' . +'\x{65AF}\x{65B0}\x{65B1}\x{65B2}\x{65B3}\x{65B4}\x{65B6}\x{65B7}\x{65B8}' . +'\x{65B9}\x{65BA}\x{65BB}\x{65BC}\x{65BD}\x{65BF}\x{65C0}\x{65C1}\x{65C2}' . +'\x{65C3}\x{65C4}\x{65C5}\x{65C6}\x{65C7}\x{65CA}\x{65CB}\x{65CC}\x{65CD}' . +'\x{65CE}\x{65CF}\x{65D0}\x{65D2}\x{65D3}\x{65D4}\x{65D5}\x{65D6}\x{65D7}' . +'\x{65DA}\x{65DB}\x{65DD}\x{65DE}\x{65DF}\x{65E0}\x{65E1}\x{65E2}\x{65E3}' . +'\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}\x{65EB}\x{65EC}\x{65ED}\x{65EE}' . +'\x{65EF}\x{65F0}\x{65F1}\x{65F2}\x{65F3}\x{65F4}\x{65F5}\x{65F6}\x{65F7}' . +'\x{65F8}\x{65FA}\x{65FB}\x{65FC}\x{65FD}\x{6600}\x{6601}\x{6602}\x{6603}' . +'\x{6604}\x{6605}\x{6606}\x{6607}\x{6608}\x{6609}\x{660A}\x{660B}\x{660C}' . +'\x{660D}\x{660E}\x{660F}\x{6610}\x{6611}\x{6612}\x{6613}\x{6614}\x{6615}' . +'\x{6616}\x{6618}\x{6619}\x{661A}\x{661B}\x{661C}\x{661D}\x{661F}\x{6620}' . +'\x{6621}\x{6622}\x{6623}\x{6624}\x{6625}\x{6626}\x{6627}\x{6628}\x{6629}' . +'\x{662A}\x{662B}\x{662D}\x{662E}\x{662F}\x{6630}\x{6631}\x{6632}\x{6633}' . +'\x{6634}\x{6635}\x{6636}\x{6639}\x{663A}\x{663C}\x{663D}\x{663E}\x{6640}' . +'\x{6641}\x{6642}\x{6643}\x{6644}\x{6645}\x{6646}\x{6647}\x{6649}\x{664A}' . +'\x{664B}\x{664C}\x{664E}\x{664F}\x{6650}\x{6651}\x{6652}\x{6653}\x{6654}' . +'\x{6655}\x{6656}\x{6657}\x{6658}\x{6659}\x{665A}\x{665B}\x{665C}\x{665D}' . +'\x{665E}\x{665F}\x{6661}\x{6662}\x{6664}\x{6665}\x{6666}\x{6668}\x{6669}' . +'\x{666A}\x{666B}\x{666C}\x{666D}\x{666E}\x{666F}\x{6670}\x{6671}\x{6672}' . +'\x{6673}\x{6674}\x{6675}\x{6676}\x{6677}\x{6678}\x{6679}\x{667A}\x{667B}' . +'\x{667C}\x{667D}\x{667E}\x{667F}\x{6680}\x{6681}\x{6682}\x{6683}\x{6684}' . +'\x{6685}\x{6686}\x{6687}\x{6688}\x{6689}\x{668A}\x{668B}\x{668C}\x{668D}' . +'\x{668E}\x{668F}\x{6690}\x{6691}\x{6693}\x{6694}\x{6695}\x{6696}\x{6697}' . +'\x{6698}\x{6699}\x{669A}\x{669B}\x{669D}\x{669F}\x{66A0}\x{66A1}\x{66A2}' . +'\x{66A3}\x{66A4}\x{66A5}\x{66A6}\x{66A7}\x{66A8}\x{66A9}\x{66AA}\x{66AB}' . +'\x{66AE}\x{66AF}\x{66B0}\x{66B1}\x{66B2}\x{66B3}\x{66B4}\x{66B5}\x{66B6}' . +'\x{66B7}\x{66B8}\x{66B9}\x{66BA}\x{66BB}\x{66BC}\x{66BD}\x{66BE}\x{66BF}' . +'\x{66C0}\x{66C1}\x{66C2}\x{66C3}\x{66C4}\x{66C5}\x{66C6}\x{66C7}\x{66C8}' . +'\x{66C9}\x{66CA}\x{66CB}\x{66CC}\x{66CD}\x{66CE}\x{66CF}\x{66D1}\x{66D2}' . +'\x{66D4}\x{66D5}\x{66D6}\x{66D8}\x{66D9}\x{66DA}\x{66DB}\x{66DC}\x{66DD}' . +'\x{66DE}\x{66E0}\x{66E1}\x{66E2}\x{66E3}\x{66E4}\x{66E5}\x{66E6}\x{66E7}' . +'\x{66E8}\x{66E9}\x{66EA}\x{66EB}\x{66EC}\x{66ED}\x{66EE}\x{66F0}\x{66F1}' . +'\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F6}\x{66F7}\x{66F8}\x{66F9}\x{66FA}' . +'\x{66FB}\x{66FC}\x{66FE}\x{66FF}\x{6700}\x{6701}\x{6703}\x{6704}\x{6705}' . +'\x{6706}\x{6708}\x{6709}\x{670A}\x{670B}\x{670C}\x{670D}\x{670E}\x{670F}' . +'\x{6710}\x{6711}\x{6712}\x{6713}\x{6714}\x{6715}\x{6716}\x{6717}\x{6718}' . +'\x{671A}\x{671B}\x{671C}\x{671D}\x{671E}\x{671F}\x{6720}\x{6721}\x{6722}' . +'\x{6723}\x{6725}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}\x{672D}' . +'\x{672E}\x{672F}\x{6730}\x{6731}\x{6732}\x{6733}\x{6734}\x{6735}\x{6736}' . +'\x{6737}\x{6738}\x{6739}\x{673A}\x{673B}\x{673C}\x{673D}\x{673E}\x{673F}' . +'\x{6740}\x{6741}\x{6742}\x{6743}\x{6744}\x{6745}\x{6746}\x{6747}\x{6748}' . +'\x{6749}\x{674A}\x{674B}\x{674C}\x{674D}\x{674E}\x{674F}\x{6750}\x{6751}' . +'\x{6752}\x{6753}\x{6754}\x{6755}\x{6756}\x{6757}\x{6758}\x{6759}\x{675A}' . +'\x{675B}\x{675C}\x{675D}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{6766}\x{6768}\x{6769}\x{676A}\x{676B}\x{676C}\x{676D}' . +'\x{676E}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}\x{6774}\x{6775}\x{6776}' . +'\x{6777}\x{6778}\x{6779}\x{677A}\x{677B}\x{677C}\x{677D}\x{677E}\x{677F}' . +'\x{6780}\x{6781}\x{6782}\x{6783}\x{6784}\x{6785}\x{6786}\x{6787}\x{6789}' . +'\x{678A}\x{678B}\x{678C}\x{678D}\x{678E}\x{678F}\x{6790}\x{6791}\x{6792}' . +'\x{6793}\x{6794}\x{6795}\x{6797}\x{6798}\x{6799}\x{679A}\x{679B}\x{679C}' . +'\x{679D}\x{679E}\x{679F}\x{67A0}\x{67A1}\x{67A2}\x{67A3}\x{67A4}\x{67A5}' . +'\x{67A6}\x{67A7}\x{67A8}\x{67AA}\x{67AB}\x{67AC}\x{67AD}\x{67AE}\x{67AF}' . +'\x{67B0}\x{67B1}\x{67B2}\x{67B3}\x{67B4}\x{67B5}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67BA}\x{67BB}\x{67BC}\x{67BE}\x{67C0}\x{67C1}\x{67C2}\x{67C3}' . +'\x{67C4}\x{67C5}\x{67C6}\x{67C7}\x{67C8}\x{67C9}\x{67CA}\x{67CB}\x{67CC}' . +'\x{67CD}\x{67CE}\x{67CF}\x{67D0}\x{67D1}\x{67D2}\x{67D3}\x{67D4}\x{67D6}' . +'\x{67D8}\x{67D9}\x{67DA}\x{67DB}\x{67DC}\x{67DD}\x{67DE}\x{67DF}\x{67E0}' . +'\x{67E1}\x{67E2}\x{67E3}\x{67E4}\x{67E5}\x{67E6}\x{67E7}\x{67E8}\x{67E9}' . +'\x{67EA}\x{67EB}\x{67EC}\x{67ED}\x{67EE}\x{67EF}\x{67F0}\x{67F1}\x{67F2}' . +'\x{67F3}\x{67F4}\x{67F5}\x{67F6}\x{67F7}\x{67F8}\x{67FA}\x{67FB}\x{67FC}' . +'\x{67FD}\x{67FE}\x{67FF}\x{6800}\x{6802}\x{6803}\x{6804}\x{6805}\x{6806}' . +'\x{6807}\x{6808}\x{6809}\x{680A}\x{680B}\x{680C}\x{680D}\x{680E}\x{680F}' . +'\x{6810}\x{6811}\x{6812}\x{6813}\x{6814}\x{6816}\x{6817}\x{6818}\x{6819}' . +'\x{681A}\x{681B}\x{681C}\x{681D}\x{681F}\x{6820}\x{6821}\x{6822}\x{6823}' . +'\x{6824}\x{6825}\x{6826}\x{6828}\x{6829}\x{682A}\x{682B}\x{682C}\x{682D}' . +'\x{682E}\x{682F}\x{6831}\x{6832}\x{6833}\x{6834}\x{6835}\x{6836}\x{6837}' . +'\x{6838}\x{6839}\x{683A}\x{683B}\x{683C}\x{683D}\x{683E}\x{683F}\x{6840}' . +'\x{6841}\x{6842}\x{6843}\x{6844}\x{6845}\x{6846}\x{6847}\x{6848}\x{6849}' . +'\x{684A}\x{684B}\x{684C}\x{684D}\x{684E}\x{684F}\x{6850}\x{6851}\x{6852}' . +'\x{6853}\x{6854}\x{6855}\x{6856}\x{6857}\x{685B}\x{685D}\x{6860}\x{6861}' . +'\x{6862}\x{6863}\x{6864}\x{6865}\x{6866}\x{6867}\x{6868}\x{6869}\x{686A}' . +'\x{686B}\x{686C}\x{686D}\x{686E}\x{686F}\x{6870}\x{6871}\x{6872}\x{6873}' . +'\x{6874}\x{6875}\x{6876}\x{6877}\x{6878}\x{6879}\x{687B}\x{687C}\x{687D}' . +'\x{687E}\x{687F}\x{6880}\x{6881}\x{6882}\x{6883}\x{6884}\x{6885}\x{6886}' . +'\x{6887}\x{6888}\x{6889}\x{688A}\x{688B}\x{688C}\x{688D}\x{688E}\x{688F}' . +'\x{6890}\x{6891}\x{6892}\x{6893}\x{6894}\x{6896}\x{6897}\x{6898}\x{689A}' . +'\x{689B}\x{689C}\x{689D}\x{689E}\x{689F}\x{68A0}\x{68A1}\x{68A2}\x{68A3}' . +'\x{68A4}\x{68A6}\x{68A7}\x{68A8}\x{68A9}\x{68AA}\x{68AB}\x{68AC}\x{68AD}' . +'\x{68AE}\x{68AF}\x{68B0}\x{68B1}\x{68B2}\x{68B3}\x{68B4}\x{68B5}\x{68B6}' . +'\x{68B7}\x{68B9}\x{68BB}\x{68BC}\x{68BD}\x{68BE}\x{68BF}\x{68C0}\x{68C1}' . +'\x{68C2}\x{68C4}\x{68C6}\x{68C7}\x{68C8}\x{68C9}\x{68CA}\x{68CB}\x{68CC}' . +'\x{68CD}\x{68CE}\x{68CF}\x{68D0}\x{68D1}\x{68D2}\x{68D3}\x{68D4}\x{68D5}' . +'\x{68D6}\x{68D7}\x{68D8}\x{68DA}\x{68DB}\x{68DC}\x{68DD}\x{68DE}\x{68DF}' . +'\x{68E0}\x{68E1}\x{68E3}\x{68E4}\x{68E6}\x{68E7}\x{68E8}\x{68E9}\x{68EA}' . +'\x{68EB}\x{68EC}\x{68ED}\x{68EE}\x{68EF}\x{68F0}\x{68F1}\x{68F2}\x{68F3}' . +'\x{68F4}\x{68F5}\x{68F6}\x{68F7}\x{68F8}\x{68F9}\x{68FA}\x{68FB}\x{68FC}' . +'\x{68FD}\x{68FE}\x{68FF}\x{6901}\x{6902}\x{6903}\x{6904}\x{6905}\x{6906}' . +'\x{6907}\x{6908}\x{690A}\x{690B}\x{690C}\x{690D}\x{690E}\x{690F}\x{6910}' . +'\x{6911}\x{6912}\x{6913}\x{6914}\x{6915}\x{6916}\x{6917}\x{6918}\x{6919}' . +'\x{691A}\x{691B}\x{691C}\x{691D}\x{691E}\x{691F}\x{6920}\x{6921}\x{6922}' . +'\x{6923}\x{6924}\x{6925}\x{6926}\x{6927}\x{6928}\x{6929}\x{692A}\x{692B}' . +'\x{692C}\x{692D}\x{692E}\x{692F}\x{6930}\x{6931}\x{6932}\x{6933}\x{6934}' . +'\x{6935}\x{6936}\x{6937}\x{6938}\x{6939}\x{693A}\x{693B}\x{693C}\x{693D}' . +'\x{693F}\x{6940}\x{6941}\x{6942}\x{6943}\x{6944}\x{6945}\x{6946}\x{6947}' . +'\x{6948}\x{6949}\x{694A}\x{694B}\x{694C}\x{694E}\x{694F}\x{6950}\x{6951}' . +'\x{6952}\x{6953}\x{6954}\x{6955}\x{6956}\x{6957}\x{6958}\x{6959}\x{695A}' . +'\x{695B}\x{695C}\x{695D}\x{695E}\x{695F}\x{6960}\x{6961}\x{6962}\x{6963}' . +'\x{6964}\x{6965}\x{6966}\x{6967}\x{6968}\x{6969}\x{696A}\x{696B}\x{696C}' . +'\x{696D}\x{696E}\x{696F}\x{6970}\x{6971}\x{6972}\x{6973}\x{6974}\x{6975}' . +'\x{6976}\x{6977}\x{6978}\x{6979}\x{697A}\x{697B}\x{697C}\x{697D}\x{697E}' . +'\x{697F}\x{6980}\x{6981}\x{6982}\x{6983}\x{6984}\x{6985}\x{6986}\x{6987}' . +'\x{6988}\x{6989}\x{698A}\x{698B}\x{698C}\x{698D}\x{698E}\x{698F}\x{6990}' . +'\x{6991}\x{6992}\x{6993}\x{6994}\x{6995}\x{6996}\x{6997}\x{6998}\x{6999}' . +'\x{699A}\x{699B}\x{699C}\x{699D}\x{699E}\x{69A0}\x{69A1}\x{69A3}\x{69A4}' . +'\x{69A5}\x{69A6}\x{69A7}\x{69A8}\x{69A9}\x{69AA}\x{69AB}\x{69AC}\x{69AD}' . +'\x{69AE}\x{69AF}\x{69B0}\x{69B1}\x{69B2}\x{69B3}\x{69B4}\x{69B5}\x{69B6}' . +'\x{69B7}\x{69B8}\x{69B9}\x{69BA}\x{69BB}\x{69BC}\x{69BD}\x{69BE}\x{69BF}' . +'\x{69C1}\x{69C2}\x{69C3}\x{69C4}\x{69C5}\x{69C6}\x{69C7}\x{69C8}\x{69C9}' . +'\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}\x{69CF}\x{69D0}\x{69D3}\x{69D4}' . +'\x{69D8}\x{69D9}\x{69DA}\x{69DB}\x{69DC}\x{69DD}\x{69DE}\x{69DF}\x{69E0}' . +'\x{69E1}\x{69E2}\x{69E3}\x{69E4}\x{69E5}\x{69E6}\x{69E7}\x{69E8}\x{69E9}' . +'\x{69EA}\x{69EB}\x{69EC}\x{69ED}\x{69EE}\x{69EF}\x{69F0}\x{69F1}\x{69F2}' . +'\x{69F3}\x{69F4}\x{69F5}\x{69F6}\x{69F7}\x{69F8}\x{69FA}\x{69FB}\x{69FC}' . +'\x{69FD}\x{69FE}\x{69FF}\x{6A00}\x{6A01}\x{6A02}\x{6A04}\x{6A05}\x{6A06}' . +'\x{6A07}\x{6A08}\x{6A09}\x{6A0A}\x{6A0B}\x{6A0D}\x{6A0E}\x{6A0F}\x{6A10}' . +'\x{6A11}\x{6A12}\x{6A13}\x{6A14}\x{6A15}\x{6A16}\x{6A17}\x{6A18}\x{6A19}' . +'\x{6A1A}\x{6A1B}\x{6A1D}\x{6A1E}\x{6A1F}\x{6A20}\x{6A21}\x{6A22}\x{6A23}' . +'\x{6A25}\x{6A26}\x{6A27}\x{6A28}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2C}\x{6A2D}' . +'\x{6A2E}\x{6A2F}\x{6A30}\x{6A31}\x{6A32}\x{6A33}\x{6A34}\x{6A35}\x{6A36}' . +'\x{6A38}\x{6A39}\x{6A3A}\x{6A3B}\x{6A3C}\x{6A3D}\x{6A3E}\x{6A3F}\x{6A40}' . +'\x{6A41}\x{6A42}\x{6A43}\x{6A44}\x{6A45}\x{6A46}\x{6A47}\x{6A48}\x{6A49}' . +'\x{6A4B}\x{6A4C}\x{6A4D}\x{6A4E}\x{6A4F}\x{6A50}\x{6A51}\x{6A52}\x{6A54}' . +'\x{6A55}\x{6A56}\x{6A57}\x{6A58}\x{6A59}\x{6A5A}\x{6A5B}\x{6A5D}\x{6A5E}' . +'\x{6A5F}\x{6A60}\x{6A61}\x{6A62}\x{6A63}\x{6A64}\x{6A65}\x{6A66}\x{6A67}' . +'\x{6A68}\x{6A69}\x{6A6A}\x{6A6B}\x{6A6C}\x{6A6D}\x{6A6F}\x{6A71}\x{6A72}' . +'\x{6A73}\x{6A74}\x{6A75}\x{6A76}\x{6A77}\x{6A78}\x{6A79}\x{6A7A}\x{6A7B}' . +'\x{6A7C}\x{6A7D}\x{6A7E}\x{6A7F}\x{6A80}\x{6A81}\x{6A82}\x{6A83}\x{6A84}' . +'\x{6A85}\x{6A87}\x{6A88}\x{6A89}\x{6A8B}\x{6A8C}\x{6A8D}\x{6A8E}\x{6A90}' . +'\x{6A91}\x{6A92}\x{6A93}\x{6A94}\x{6A95}\x{6A96}\x{6A97}\x{6A98}\x{6A9A}' . +'\x{6A9B}\x{6A9C}\x{6A9E}\x{6A9F}\x{6AA0}\x{6AA1}\x{6AA2}\x{6AA3}\x{6AA4}' . +'\x{6AA5}\x{6AA6}\x{6AA7}\x{6AA8}\x{6AA9}\x{6AAB}\x{6AAC}\x{6AAD}\x{6AAE}' . +'\x{6AAF}\x{6AB0}\x{6AB2}\x{6AB3}\x{6AB4}\x{6AB5}\x{6AB6}\x{6AB7}\x{6AB8}' . +'\x{6AB9}\x{6ABA}\x{6ABB}\x{6ABC}\x{6ABD}\x{6ABF}\x{6AC1}\x{6AC2}\x{6AC3}' . +'\x{6AC5}\x{6AC6}\x{6AC7}\x{6ACA}\x{6ACB}\x{6ACC}\x{6ACD}\x{6ACE}\x{6ACF}' . +'\x{6AD0}\x{6AD1}\x{6AD2}\x{6AD3}\x{6AD4}\x{6AD5}\x{6AD6}\x{6AD7}\x{6AD9}' . +'\x{6ADA}\x{6ADB}\x{6ADC}\x{6ADD}\x{6ADE}\x{6ADF}\x{6AE0}\x{6AE1}\x{6AE2}' . +'\x{6AE3}\x{6AE4}\x{6AE5}\x{6AE6}\x{6AE7}\x{6AE8}\x{6AEA}\x{6AEB}\x{6AEC}' . +'\x{6AED}\x{6AEE}\x{6AEF}\x{6AF0}\x{6AF1}\x{6AF2}\x{6AF3}\x{6AF4}\x{6AF5}' . +'\x{6AF6}\x{6AF7}\x{6AF8}\x{6AF9}\x{6AFA}\x{6AFB}\x{6AFC}\x{6AFD}\x{6AFE}' . +'\x{6AFF}\x{6B00}\x{6B01}\x{6B02}\x{6B03}\x{6B04}\x{6B05}\x{6B06}\x{6B07}' . +'\x{6B08}\x{6B09}\x{6B0A}\x{6B0B}\x{6B0C}\x{6B0D}\x{6B0F}\x{6B10}\x{6B11}' . +'\x{6B12}\x{6B13}\x{6B14}\x{6B15}\x{6B16}\x{6B17}\x{6B18}\x{6B19}\x{6B1A}' . +'\x{6B1C}\x{6B1D}\x{6B1E}\x{6B1F}\x{6B20}\x{6B21}\x{6B22}\x{6B23}\x{6B24}' . +'\x{6B25}\x{6B26}\x{6B27}\x{6B28}\x{6B29}\x{6B2A}\x{6B2B}\x{6B2C}\x{6B2D}' . +'\x{6B2F}\x{6B30}\x{6B31}\x{6B32}\x{6B33}\x{6B34}\x{6B36}\x{6B37}\x{6B38}' . +'\x{6B39}\x{6B3A}\x{6B3B}\x{6B3C}\x{6B3D}\x{6B3E}\x{6B3F}\x{6B41}\x{6B42}' . +'\x{6B43}\x{6B44}\x{6B45}\x{6B46}\x{6B47}\x{6B48}\x{6B49}\x{6B4A}\x{6B4B}' . +'\x{6B4C}\x{6B4D}\x{6B4E}\x{6B4F}\x{6B50}\x{6B51}\x{6B52}\x{6B53}\x{6B54}' . +'\x{6B55}\x{6B56}\x{6B59}\x{6B5A}\x{6B5B}\x{6B5C}\x{6B5E}\x{6B5F}\x{6B60}' . +'\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B65}\x{6B66}\x{6B67}\x{6B69}\x{6B6A}' . +'\x{6B6B}\x{6B6D}\x{6B6F}\x{6B70}\x{6B72}\x{6B73}\x{6B74}\x{6B76}\x{6B77}' . +'\x{6B78}\x{6B79}\x{6B7A}\x{6B7B}\x{6B7C}\x{6B7E}\x{6B7F}\x{6B80}\x{6B81}' . +'\x{6B82}\x{6B83}\x{6B84}\x{6B85}\x{6B86}\x{6B87}\x{6B88}\x{6B89}\x{6B8A}' . +'\x{6B8B}\x{6B8C}\x{6B8D}\x{6B8E}\x{6B8F}\x{6B90}\x{6B91}\x{6B92}\x{6B93}' . +'\x{6B94}\x{6B95}\x{6B96}\x{6B97}\x{6B98}\x{6B99}\x{6B9A}\x{6B9B}\x{6B9C}' . +'\x{6B9D}\x{6B9E}\x{6B9F}\x{6BA0}\x{6BA1}\x{6BA2}\x{6BA3}\x{6BA4}\x{6BA5}' . +'\x{6BA6}\x{6BA7}\x{6BA8}\x{6BA9}\x{6BAA}\x{6BAB}\x{6BAC}\x{6BAD}\x{6BAE}' . +'\x{6BAF}\x{6BB0}\x{6BB2}\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB6}\x{6BB7}\x{6BB9}' . +'\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBD}\x{6BBE}\x{6BBF}\x{6BC0}\x{6BC1}\x{6BC2}' . +'\x{6BC3}\x{6BC4}\x{6BC5}\x{6BC6}\x{6BC7}\x{6BC8}\x{6BC9}\x{6BCA}\x{6BCB}' . +'\x{6BCC}\x{6BCD}\x{6BCE}\x{6BCF}\x{6BD0}\x{6BD1}\x{6BD2}\x{6BD3}\x{6BD4}' . +'\x{6BD5}\x{6BD6}\x{6BD7}\x{6BD8}\x{6BD9}\x{6BDA}\x{6BDB}\x{6BDC}\x{6BDD}' . +'\x{6BDE}\x{6BDF}\x{6BE0}\x{6BE1}\x{6BE2}\x{6BE3}\x{6BE4}\x{6BE5}\x{6BE6}' . +'\x{6BE7}\x{6BE8}\x{6BEA}\x{6BEB}\x{6BEC}\x{6BED}\x{6BEE}\x{6BEF}\x{6BF0}' . +'\x{6BF2}\x{6BF3}\x{6BF5}\x{6BF6}\x{6BF7}\x{6BF8}\x{6BF9}\x{6BFB}\x{6BFC}' . +'\x{6BFD}\x{6BFE}\x{6BFF}\x{6C00}\x{6C01}\x{6C02}\x{6C03}\x{6C04}\x{6C05}' . +'\x{6C06}\x{6C07}\x{6C08}\x{6C09}\x{6C0B}\x{6C0C}\x{6C0D}\x{6C0E}\x{6C0F}' . +'\x{6C10}\x{6C11}\x{6C12}\x{6C13}\x{6C14}\x{6C15}\x{6C16}\x{6C18}\x{6C19}' . +'\x{6C1A}\x{6C1B}\x{6C1D}\x{6C1E}\x{6C1F}\x{6C20}\x{6C21}\x{6C22}\x{6C23}' . +'\x{6C24}\x{6C25}\x{6C26}\x{6C27}\x{6C28}\x{6C29}\x{6C2A}\x{6C2B}\x{6C2C}' . +'\x{6C2E}\x{6C2F}\x{6C30}\x{6C31}\x{6C32}\x{6C33}\x{6C34}\x{6C35}\x{6C36}' . +'\x{6C37}\x{6C38}\x{6C3A}\x{6C3B}\x{6C3D}\x{6C3E}\x{6C3F}\x{6C40}\x{6C41}' . +'\x{6C42}\x{6C43}\x{6C44}\x{6C46}\x{6C47}\x{6C48}\x{6C49}\x{6C4A}\x{6C4B}' . +'\x{6C4C}\x{6C4D}\x{6C4E}\x{6C4F}\x{6C50}\x{6C51}\x{6C52}\x{6C53}\x{6C54}' . +'\x{6C55}\x{6C56}\x{6C57}\x{6C58}\x{6C59}\x{6C5A}\x{6C5B}\x{6C5C}\x{6C5D}' . +'\x{6C5E}\x{6C5F}\x{6C60}\x{6C61}\x{6C62}\x{6C63}\x{6C64}\x{6C65}\x{6C66}' . +'\x{6C67}\x{6C68}\x{6C69}\x{6C6A}\x{6C6B}\x{6C6D}\x{6C6F}\x{6C70}\x{6C71}' . +'\x{6C72}\x{6C73}\x{6C74}\x{6C75}\x{6C76}\x{6C77}\x{6C78}\x{6C79}\x{6C7A}' . +'\x{6C7B}\x{6C7C}\x{6C7D}\x{6C7E}\x{6C7F}\x{6C80}\x{6C81}\x{6C82}\x{6C83}' . +'\x{6C84}\x{6C85}\x{6C86}\x{6C87}\x{6C88}\x{6C89}\x{6C8A}\x{6C8B}\x{6C8C}' . +'\x{6C8D}\x{6C8E}\x{6C8F}\x{6C90}\x{6C91}\x{6C92}\x{6C93}\x{6C94}\x{6C95}' . +'\x{6C96}\x{6C97}\x{6C98}\x{6C99}\x{6C9A}\x{6C9B}\x{6C9C}\x{6C9D}\x{6C9E}' . +'\x{6C9F}\x{6CA1}\x{6CA2}\x{6CA3}\x{6CA4}\x{6CA5}\x{6CA6}\x{6CA7}\x{6CA8}' . +'\x{6CA9}\x{6CAA}\x{6CAB}\x{6CAC}\x{6CAD}\x{6CAE}\x{6CAF}\x{6CB0}\x{6CB1}' . +'\x{6CB2}\x{6CB3}\x{6CB4}\x{6CB5}\x{6CB6}\x{6CB7}\x{6CB8}\x{6CB9}\x{6CBA}' . +'\x{6CBB}\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC0}\x{6CC1}\x{6CC2}\x{6CC3}' . +'\x{6CC4}\x{6CC5}\x{6CC6}\x{6CC7}\x{6CC8}\x{6CC9}\x{6CCA}\x{6CCB}\x{6CCC}' . +'\x{6CCD}\x{6CCE}\x{6CCF}\x{6CD0}\x{6CD1}\x{6CD2}\x{6CD3}\x{6CD4}\x{6CD5}' . +'\x{6CD6}\x{6CD7}\x{6CD9}\x{6CDA}\x{6CDB}\x{6CDC}\x{6CDD}\x{6CDE}\x{6CDF}' . +'\x{6CE0}\x{6CE1}\x{6CE2}\x{6CE3}\x{6CE4}\x{6CE5}\x{6CE6}\x{6CE7}\x{6CE8}' . +'\x{6CE9}\x{6CEA}\x{6CEB}\x{6CEC}\x{6CED}\x{6CEE}\x{6CEF}\x{6CF0}\x{6CF1}' . +'\x{6CF2}\x{6CF3}\x{6CF5}\x{6CF6}\x{6CF7}\x{6CF8}\x{6CF9}\x{6CFA}\x{6CFB}' . +'\x{6CFC}\x{6CFD}\x{6CFE}\x{6CFF}\x{6D00}\x{6D01}\x{6D03}\x{6D04}\x{6D05}' . +'\x{6D06}\x{6D07}\x{6D08}\x{6D09}\x{6D0A}\x{6D0B}\x{6D0C}\x{6D0D}\x{6D0E}' . +'\x{6D0F}\x{6D10}\x{6D11}\x{6D12}\x{6D13}\x{6D14}\x{6D15}\x{6D16}\x{6D17}' . +'\x{6D18}\x{6D19}\x{6D1A}\x{6D1B}\x{6D1D}\x{6D1E}\x{6D1F}\x{6D20}\x{6D21}' . +'\x{6D22}\x{6D23}\x{6D25}\x{6D26}\x{6D27}\x{6D28}\x{6D29}\x{6D2A}\x{6D2B}' . +'\x{6D2C}\x{6D2D}\x{6D2E}\x{6D2F}\x{6D30}\x{6D31}\x{6D32}\x{6D33}\x{6D34}' . +'\x{6D35}\x{6D36}\x{6D37}\x{6D38}\x{6D39}\x{6D3A}\x{6D3B}\x{6D3C}\x{6D3D}' . +'\x{6D3E}\x{6D3F}\x{6D40}\x{6D41}\x{6D42}\x{6D43}\x{6D44}\x{6D45}\x{6D46}' . +'\x{6D47}\x{6D48}\x{6D49}\x{6D4A}\x{6D4B}\x{6D4C}\x{6D4D}\x{6D4E}\x{6D4F}' . +'\x{6D50}\x{6D51}\x{6D52}\x{6D53}\x{6D54}\x{6D55}\x{6D56}\x{6D57}\x{6D58}' . +'\x{6D59}\x{6D5A}\x{6D5B}\x{6D5C}\x{6D5D}\x{6D5E}\x{6D5F}\x{6D60}\x{6D61}' . +'\x{6D62}\x{6D63}\x{6D64}\x{6D65}\x{6D66}\x{6D67}\x{6D68}\x{6D69}\x{6D6A}' . +'\x{6D6B}\x{6D6C}\x{6D6D}\x{6D6E}\x{6D6F}\x{6D70}\x{6D72}\x{6D73}\x{6D74}' . +'\x{6D75}\x{6D76}\x{6D77}\x{6D78}\x{6D79}\x{6D7A}\x{6D7B}\x{6D7C}\x{6D7D}' . +'\x{6D7E}\x{6D7F}\x{6D80}\x{6D82}\x{6D83}\x{6D84}\x{6D85}\x{6D86}\x{6D87}' . +'\x{6D88}\x{6D89}\x{6D8A}\x{6D8B}\x{6D8C}\x{6D8D}\x{6D8E}\x{6D8F}\x{6D90}' . +'\x{6D91}\x{6D92}\x{6D93}\x{6D94}\x{6D95}\x{6D97}\x{6D98}\x{6D99}\x{6D9A}' . +'\x{6D9B}\x{6D9D}\x{6D9E}\x{6D9F}\x{6DA0}\x{6DA1}\x{6DA2}\x{6DA3}\x{6DA4}' . +'\x{6DA5}\x{6DA6}\x{6DA7}\x{6DA8}\x{6DA9}\x{6DAA}\x{6DAB}\x{6DAC}\x{6DAD}' . +'\x{6DAE}\x{6DAF}\x{6DB2}\x{6DB3}\x{6DB4}\x{6DB5}\x{6DB7}\x{6DB8}\x{6DB9}' . +'\x{6DBA}\x{6DBB}\x{6DBC}\x{6DBD}\x{6DBE}\x{6DBF}\x{6DC0}\x{6DC1}\x{6DC2}' . +'\x{6DC3}\x{6DC4}\x{6DC5}\x{6DC6}\x{6DC7}\x{6DC8}\x{6DC9}\x{6DCA}\x{6DCB}' . +'\x{6DCC}\x{6DCD}\x{6DCE}\x{6DCF}\x{6DD0}\x{6DD1}\x{6DD2}\x{6DD3}\x{6DD4}' . +'\x{6DD5}\x{6DD6}\x{6DD7}\x{6DD8}\x{6DD9}\x{6DDA}\x{6DDB}\x{6DDC}\x{6DDD}' . +'\x{6DDE}\x{6DDF}\x{6DE0}\x{6DE1}\x{6DE2}\x{6DE3}\x{6DE4}\x{6DE5}\x{6DE6}' . +'\x{6DE7}\x{6DE8}\x{6DE9}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DED}\x{6DEE}\x{6DEF}' . +'\x{6DF0}\x{6DF1}\x{6DF2}\x{6DF3}\x{6DF4}\x{6DF5}\x{6DF6}\x{6DF7}\x{6DF8}' . +'\x{6DF9}\x{6DFA}\x{6DFB}\x{6DFC}\x{6DFD}\x{6E00}\x{6E03}\x{6E04}\x{6E05}' . +'\x{6E07}\x{6E08}\x{6E09}\x{6E0A}\x{6E0B}\x{6E0C}\x{6E0D}\x{6E0E}\x{6E0F}' . +'\x{6E10}\x{6E11}\x{6E14}\x{6E15}\x{6E16}\x{6E17}\x{6E19}\x{6E1A}\x{6E1B}' . +'\x{6E1C}\x{6E1D}\x{6E1E}\x{6E1F}\x{6E20}\x{6E21}\x{6E22}\x{6E23}\x{6E24}' . +'\x{6E25}\x{6E26}\x{6E27}\x{6E28}\x{6E29}\x{6E2B}\x{6E2C}\x{6E2D}\x{6E2E}' . +'\x{6E2F}\x{6E30}\x{6E31}\x{6E32}\x{6E33}\x{6E34}\x{6E35}\x{6E36}\x{6E37}' . +'\x{6E38}\x{6E39}\x{6E3A}\x{6E3B}\x{6E3C}\x{6E3D}\x{6E3E}\x{6E3F}\x{6E40}' . +'\x{6E41}\x{6E42}\x{6E43}\x{6E44}\x{6E45}\x{6E46}\x{6E47}\x{6E48}\x{6E49}' . +'\x{6E4A}\x{6E4B}\x{6E4D}\x{6E4E}\x{6E4F}\x{6E50}\x{6E51}\x{6E52}\x{6E53}' . +'\x{6E54}\x{6E55}\x{6E56}\x{6E57}\x{6E58}\x{6E59}\x{6E5A}\x{6E5B}\x{6E5C}' . +'\x{6E5D}\x{6E5E}\x{6E5F}\x{6E60}\x{6E61}\x{6E62}\x{6E63}\x{6E64}\x{6E65}' . +'\x{6E66}\x{6E67}\x{6E68}\x{6E69}\x{6E6A}\x{6E6B}\x{6E6D}\x{6E6E}\x{6E6F}' . +'\x{6E70}\x{6E71}\x{6E72}\x{6E73}\x{6E74}\x{6E75}\x{6E77}\x{6E78}\x{6E79}' . +'\x{6E7E}\x{6E7F}\x{6E80}\x{6E81}\x{6E82}\x{6E83}\x{6E84}\x{6E85}\x{6E86}' . +'\x{6E87}\x{6E88}\x{6E89}\x{6E8A}\x{6E8D}\x{6E8E}\x{6E8F}\x{6E90}\x{6E91}' . +'\x{6E92}\x{6E93}\x{6E94}\x{6E96}\x{6E97}\x{6E98}\x{6E99}\x{6E9A}\x{6E9B}' . +'\x{6E9C}\x{6E9D}\x{6E9E}\x{6E9F}\x{6EA0}\x{6EA1}\x{6EA2}\x{6EA3}\x{6EA4}' . +'\x{6EA5}\x{6EA6}\x{6EA7}\x{6EA8}\x{6EA9}\x{6EAA}\x{6EAB}\x{6EAC}\x{6EAD}' . +'\x{6EAE}\x{6EAF}\x{6EB0}\x{6EB1}\x{6EB2}\x{6EB3}\x{6EB4}\x{6EB5}\x{6EB6}' . +'\x{6EB7}\x{6EB8}\x{6EB9}\x{6EBA}\x{6EBB}\x{6EBC}\x{6EBD}\x{6EBE}\x{6EBF}' . +'\x{6EC0}\x{6EC1}\x{6EC2}\x{6EC3}\x{6EC4}\x{6EC5}\x{6EC6}\x{6EC7}\x{6EC8}' . +'\x{6EC9}\x{6ECA}\x{6ECB}\x{6ECC}\x{6ECD}\x{6ECE}\x{6ECF}\x{6ED0}\x{6ED1}' . +'\x{6ED2}\x{6ED3}\x{6ED4}\x{6ED5}\x{6ED6}\x{6ED7}\x{6ED8}\x{6ED9}\x{6EDA}' . +'\x{6EDC}\x{6EDE}\x{6EDF}\x{6EE0}\x{6EE1}\x{6EE2}\x{6EE4}\x{6EE5}\x{6EE6}' . +'\x{6EE7}\x{6EE8}\x{6EE9}\x{6EEA}\x{6EEB}\x{6EEC}\x{6EED}\x{6EEE}\x{6EEF}' . +'\x{6EF0}\x{6EF1}\x{6EF2}\x{6EF3}\x{6EF4}\x{6EF5}\x{6EF6}\x{6EF7}\x{6EF8}' . +'\x{6EF9}\x{6EFA}\x{6EFB}\x{6EFC}\x{6EFD}\x{6EFE}\x{6EFF}\x{6F00}\x{6F01}' . +'\x{6F02}\x{6F03}\x{6F05}\x{6F06}\x{6F07}\x{6F08}\x{6F09}\x{6F0A}\x{6F0C}' . +'\x{6F0D}\x{6F0E}\x{6F0F}\x{6F10}\x{6F11}\x{6F12}\x{6F13}\x{6F14}\x{6F15}' . +'\x{6F16}\x{6F17}\x{6F18}\x{6F19}\x{6F1A}\x{6F1B}\x{6F1C}\x{6F1D}\x{6F1E}' . +'\x{6F1F}\x{6F20}\x{6F21}\x{6F22}\x{6F23}\x{6F24}\x{6F25}\x{6F26}\x{6F27}' . +'\x{6F28}\x{6F29}\x{6F2A}\x{6F2B}\x{6F2C}\x{6F2D}\x{6F2E}\x{6F2F}\x{6F30}' . +'\x{6F31}\x{6F32}\x{6F33}\x{6F34}\x{6F35}\x{6F36}\x{6F37}\x{6F38}\x{6F39}' . +'\x{6F3A}\x{6F3B}\x{6F3C}\x{6F3D}\x{6F3E}\x{6F3F}\x{6F40}\x{6F41}\x{6F43}' . +'\x{6F44}\x{6F45}\x{6F46}\x{6F47}\x{6F49}\x{6F4B}\x{6F4C}\x{6F4D}\x{6F4E}' . +'\x{6F4F}\x{6F50}\x{6F51}\x{6F52}\x{6F53}\x{6F54}\x{6F55}\x{6F56}\x{6F57}' . +'\x{6F58}\x{6F59}\x{6F5A}\x{6F5B}\x{6F5C}\x{6F5D}\x{6F5E}\x{6F5F}\x{6F60}' . +'\x{6F61}\x{6F62}\x{6F63}\x{6F64}\x{6F65}\x{6F66}\x{6F67}\x{6F68}\x{6F69}' . +'\x{6F6A}\x{6F6B}\x{6F6C}\x{6F6D}\x{6F6E}\x{6F6F}\x{6F70}\x{6F71}\x{6F72}' . +'\x{6F73}\x{6F74}\x{6F75}\x{6F76}\x{6F77}\x{6F78}\x{6F7A}\x{6F7B}\x{6F7C}' . +'\x{6F7D}\x{6F7E}\x{6F7F}\x{6F80}\x{6F81}\x{6F82}\x{6F83}\x{6F84}\x{6F85}' . +'\x{6F86}\x{6F87}\x{6F88}\x{6F89}\x{6F8A}\x{6F8B}\x{6F8C}\x{6F8D}\x{6F8E}' . +'\x{6F8F}\x{6F90}\x{6F91}\x{6F92}\x{6F93}\x{6F94}\x{6F95}\x{6F96}\x{6F97}' . +'\x{6F99}\x{6F9B}\x{6F9C}\x{6F9D}\x{6F9E}\x{6FA0}\x{6FA1}\x{6FA2}\x{6FA3}' . +'\x{6FA4}\x{6FA5}\x{6FA6}\x{6FA7}\x{6FA8}\x{6FA9}\x{6FAA}\x{6FAB}\x{6FAC}' . +'\x{6FAD}\x{6FAE}\x{6FAF}\x{6FB0}\x{6FB1}\x{6FB2}\x{6FB3}\x{6FB4}\x{6FB5}' . +'\x{6FB6}\x{6FB8}\x{6FB9}\x{6FBA}\x{6FBB}\x{6FBC}\x{6FBD}\x{6FBE}\x{6FBF}' . +'\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC4}\x{6FC6}\x{6FC7}\x{6FC8}\x{6FC9}' . +'\x{6FCA}\x{6FCB}\x{6FCC}\x{6FCD}\x{6FCE}\x{6FCF}\x{6FD1}\x{6FD2}\x{6FD4}' . +'\x{6FD5}\x{6FD6}\x{6FD7}\x{6FD8}\x{6FD9}\x{6FDA}\x{6FDB}\x{6FDC}\x{6FDD}' . +'\x{6FDE}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE2}\x{6FE3}\x{6FE4}\x{6FE5}\x{6FE6}' . +'\x{6FE7}\x{6FE8}\x{6FE9}\x{6FEA}\x{6FEB}\x{6FEC}\x{6FED}\x{6FEE}\x{6FEF}' . +'\x{6FF0}\x{6FF1}\x{6FF2}\x{6FF3}\x{6FF4}\x{6FF6}\x{6FF7}\x{6FF8}\x{6FF9}' . +'\x{6FFA}\x{6FFB}\x{6FFC}\x{6FFE}\x{6FFF}\x{7000}\x{7001}\x{7002}\x{7003}' . +'\x{7004}\x{7005}\x{7006}\x{7007}\x{7008}\x{7009}\x{700A}\x{700B}\x{700C}' . +'\x{700D}\x{700E}\x{700F}\x{7011}\x{7012}\x{7014}\x{7015}\x{7016}\x{7017}' . +'\x{7018}\x{7019}\x{701A}\x{701B}\x{701C}\x{701D}\x{701F}\x{7020}\x{7021}' . +'\x{7022}\x{7023}\x{7024}\x{7025}\x{7026}\x{7027}\x{7028}\x{7029}\x{702A}' . +'\x{702B}\x{702C}\x{702D}\x{702E}\x{702F}\x{7030}\x{7031}\x{7032}\x{7033}' . +'\x{7034}\x{7035}\x{7036}\x{7037}\x{7038}\x{7039}\x{703A}\x{703B}\x{703C}' . +'\x{703D}\x{703E}\x{703F}\x{7040}\x{7041}\x{7042}\x{7043}\x{7044}\x{7045}' . +'\x{7046}\x{7048}\x{7049}\x{704A}\x{704C}\x{704D}\x{704F}\x{7050}\x{7051}' . +'\x{7052}\x{7053}\x{7054}\x{7055}\x{7056}\x{7057}\x{7058}\x{7059}\x{705A}' . +'\x{705B}\x{705C}\x{705D}\x{705E}\x{705F}\x{7060}\x{7061}\x{7062}\x{7063}' . +'\x{7064}\x{7065}\x{7066}\x{7067}\x{7068}\x{7069}\x{706A}\x{706B}\x{706C}' . +'\x{706D}\x{706E}\x{706F}\x{7070}\x{7071}\x{7074}\x{7075}\x{7076}\x{7077}' . +'\x{7078}\x{7079}\x{707A}\x{707C}\x{707D}\x{707E}\x{707F}\x{7080}\x{7082}' . +'\x{7083}\x{7084}\x{7085}\x{7086}\x{7087}\x{7088}\x{7089}\x{708A}\x{708B}' . +'\x{708C}\x{708E}\x{708F}\x{7090}\x{7091}\x{7092}\x{7093}\x{7094}\x{7095}' . +'\x{7096}\x{7098}\x{7099}\x{709A}\x{709C}\x{709D}\x{709E}\x{709F}\x{70A0}' . +'\x{70A1}\x{70A2}\x{70A3}\x{70A4}\x{70A5}\x{70A6}\x{70A7}\x{70A8}\x{70A9}' . +'\x{70AB}\x{70AC}\x{70AD}\x{70AE}\x{70AF}\x{70B0}\x{70B1}\x{70B3}\x{70B4}' . +'\x{70B5}\x{70B7}\x{70B8}\x{70B9}\x{70BA}\x{70BB}\x{70BC}\x{70BD}\x{70BE}' . +'\x{70BF}\x{70C0}\x{70C1}\x{70C2}\x{70C3}\x{70C4}\x{70C5}\x{70C6}\x{70C7}' . +'\x{70C8}\x{70C9}\x{70CA}\x{70CB}\x{70CC}\x{70CD}\x{70CE}\x{70CF}\x{70D0}' . +'\x{70D1}\x{70D2}\x{70D3}\x{70D4}\x{70D6}\x{70D7}\x{70D8}\x{70D9}\x{70DA}' . +'\x{70DB}\x{70DC}\x{70DD}\x{70DE}\x{70DF}\x{70E0}\x{70E1}\x{70E2}\x{70E3}' . +'\x{70E4}\x{70E5}\x{70E6}\x{70E7}\x{70E8}\x{70E9}\x{70EA}\x{70EB}\x{70EC}' . +'\x{70ED}\x{70EE}\x{70EF}\x{70F0}\x{70F1}\x{70F2}\x{70F3}\x{70F4}\x{70F5}' . +'\x{70F6}\x{70F7}\x{70F8}\x{70F9}\x{70FA}\x{70FB}\x{70FC}\x{70FD}\x{70FF}' . +'\x{7100}\x{7101}\x{7102}\x{7103}\x{7104}\x{7105}\x{7106}\x{7107}\x{7109}' . +'\x{710A}\x{710B}\x{710C}\x{710D}\x{710E}\x{710F}\x{7110}\x{7111}\x{7112}' . +'\x{7113}\x{7115}\x{7116}\x{7117}\x{7118}\x{7119}\x{711A}\x{711B}\x{711C}' . +'\x{711D}\x{711E}\x{711F}\x{7120}\x{7121}\x{7122}\x{7123}\x{7125}\x{7126}' . +'\x{7127}\x{7128}\x{7129}\x{712A}\x{712B}\x{712C}\x{712D}\x{712E}\x{712F}' . +'\x{7130}\x{7131}\x{7132}\x{7135}\x{7136}\x{7137}\x{7138}\x{7139}\x{713A}' . +'\x{713B}\x{713D}\x{713E}\x{713F}\x{7140}\x{7141}\x{7142}\x{7143}\x{7144}' . +'\x{7145}\x{7146}\x{7147}\x{7148}\x{7149}\x{714A}\x{714B}\x{714C}\x{714D}' . +'\x{714E}\x{714F}\x{7150}\x{7151}\x{7152}\x{7153}\x{7154}\x{7156}\x{7158}' . +'\x{7159}\x{715A}\x{715B}\x{715C}\x{715D}\x{715E}\x{715F}\x{7160}\x{7161}' . +'\x{7162}\x{7163}\x{7164}\x{7165}\x{7166}\x{7167}\x{7168}\x{7169}\x{716A}' . +'\x{716C}\x{716E}\x{716F}\x{7170}\x{7171}\x{7172}\x{7173}\x{7174}\x{7175}' . +'\x{7176}\x{7177}\x{7178}\x{7179}\x{717A}\x{717B}\x{717C}\x{717D}\x{717E}' . +'\x{717F}\x{7180}\x{7181}\x{7182}\x{7183}\x{7184}\x{7185}\x{7186}\x{7187}' . +'\x{7188}\x{7189}\x{718A}\x{718B}\x{718C}\x{718E}\x{718F}\x{7190}\x{7191}' . +'\x{7192}\x{7193}\x{7194}\x{7195}\x{7197}\x{7198}\x{7199}\x{719A}\x{719B}' . +'\x{719C}\x{719D}\x{719E}\x{719F}\x{71A0}\x{71A1}\x{71A2}\x{71A3}\x{71A4}' . +'\x{71A5}\x{71A7}\x{71A8}\x{71A9}\x{71AA}\x{71AC}\x{71AD}\x{71AE}\x{71AF}' . +'\x{71B0}\x{71B1}\x{71B2}\x{71B3}\x{71B4}\x{71B5}\x{71B7}\x{71B8}\x{71B9}' . +'\x{71BA}\x{71BB}\x{71BC}\x{71BD}\x{71BE}\x{71BF}\x{71C0}\x{71C1}\x{71C2}' . +'\x{71C3}\x{71C4}\x{71C5}\x{71C6}\x{71C7}\x{71C8}\x{71C9}\x{71CA}\x{71CB}' . +'\x{71CD}\x{71CE}\x{71CF}\x{71D0}\x{71D1}\x{71D2}\x{71D4}\x{71D5}\x{71D6}' . +'\x{71D7}\x{71D8}\x{71D9}\x{71DA}\x{71DB}\x{71DC}\x{71DD}\x{71DE}\x{71DF}' . +'\x{71E0}\x{71E1}\x{71E2}\x{71E3}\x{71E4}\x{71E5}\x{71E6}\x{71E7}\x{71E8}' . +'\x{71E9}\x{71EA}\x{71EB}\x{71EC}\x{71ED}\x{71EE}\x{71EF}\x{71F0}\x{71F1}' . +'\x{71F2}\x{71F4}\x{71F5}\x{71F6}\x{71F7}\x{71F8}\x{71F9}\x{71FB}\x{71FC}' . +'\x{71FD}\x{71FE}\x{71FF}\x{7201}\x{7202}\x{7203}\x{7204}\x{7205}\x{7206}' . +'\x{7207}\x{7208}\x{7209}\x{720A}\x{720C}\x{720D}\x{720E}\x{720F}\x{7210}' . +'\x{7212}\x{7213}\x{7214}\x{7216}\x{7218}\x{7219}\x{721A}\x{721B}\x{721C}' . +'\x{721D}\x{721E}\x{721F}\x{7221}\x{7222}\x{7223}\x{7226}\x{7227}\x{7228}' . +'\x{7229}\x{722A}\x{722B}\x{722C}\x{722D}\x{722E}\x{7230}\x{7231}\x{7232}' . +'\x{7233}\x{7235}\x{7236}\x{7237}\x{7238}\x{7239}\x{723A}\x{723B}\x{723C}' . +'\x{723D}\x{723E}\x{723F}\x{7240}\x{7241}\x{7242}\x{7243}\x{7244}\x{7246}' . +'\x{7247}\x{7248}\x{7249}\x{724A}\x{724B}\x{724C}\x{724D}\x{724F}\x{7251}' . +'\x{7252}\x{7253}\x{7254}\x{7256}\x{7257}\x{7258}\x{7259}\x{725A}\x{725B}' . +'\x{725C}\x{725D}\x{725E}\x{725F}\x{7260}\x{7261}\x{7262}\x{7263}\x{7264}' . +'\x{7265}\x{7266}\x{7267}\x{7268}\x{7269}\x{726A}\x{726B}\x{726C}\x{726D}' . +'\x{726E}\x{726F}\x{7270}\x{7271}\x{7272}\x{7273}\x{7274}\x{7275}\x{7276}' . +'\x{7277}\x{7278}\x{7279}\x{727A}\x{727B}\x{727C}\x{727D}\x{727E}\x{727F}' . +'\x{7280}\x{7281}\x{7282}\x{7283}\x{7284}\x{7285}\x{7286}\x{7287}\x{7288}' . +'\x{7289}\x{728A}\x{728B}\x{728C}\x{728D}\x{728E}\x{728F}\x{7290}\x{7291}' . +'\x{7292}\x{7293}\x{7294}\x{7295}\x{7296}\x{7297}\x{7298}\x{7299}\x{729A}' . +'\x{729B}\x{729C}\x{729D}\x{729E}\x{729F}\x{72A1}\x{72A2}\x{72A3}\x{72A4}' . +'\x{72A5}\x{72A6}\x{72A7}\x{72A8}\x{72A9}\x{72AA}\x{72AC}\x{72AD}\x{72AE}' . +'\x{72AF}\x{72B0}\x{72B1}\x{72B2}\x{72B3}\x{72B4}\x{72B5}\x{72B6}\x{72B7}' . +'\x{72B8}\x{72B9}\x{72BA}\x{72BB}\x{72BC}\x{72BD}\x{72BF}\x{72C0}\x{72C1}' . +'\x{72C2}\x{72C3}\x{72C4}\x{72C5}\x{72C6}\x{72C7}\x{72C8}\x{72C9}\x{72CA}' . +'\x{72CB}\x{72CC}\x{72CD}\x{72CE}\x{72CF}\x{72D0}\x{72D1}\x{72D2}\x{72D3}' . +'\x{72D4}\x{72D5}\x{72D6}\x{72D7}\x{72D8}\x{72D9}\x{72DA}\x{72DB}\x{72DC}' . +'\x{72DD}\x{72DE}\x{72DF}\x{72E0}\x{72E1}\x{72E2}\x{72E3}\x{72E4}\x{72E5}' . +'\x{72E6}\x{72E7}\x{72E8}\x{72E9}\x{72EA}\x{72EB}\x{72EC}\x{72ED}\x{72EE}' . +'\x{72EF}\x{72F0}\x{72F1}\x{72F2}\x{72F3}\x{72F4}\x{72F5}\x{72F6}\x{72F7}' . +'\x{72F8}\x{72F9}\x{72FA}\x{72FB}\x{72FC}\x{72FD}\x{72FE}\x{72FF}\x{7300}' . +'\x{7301}\x{7303}\x{7304}\x{7305}\x{7306}\x{7307}\x{7308}\x{7309}\x{730A}' . +'\x{730B}\x{730C}\x{730D}\x{730E}\x{730F}\x{7311}\x{7312}\x{7313}\x{7314}' . +'\x{7315}\x{7316}\x{7317}\x{7318}\x{7319}\x{731A}\x{731B}\x{731C}\x{731D}' . +'\x{731E}\x{7320}\x{7321}\x{7322}\x{7323}\x{7324}\x{7325}\x{7326}\x{7327}' . +'\x{7329}\x{732A}\x{732B}\x{732C}\x{732D}\x{732E}\x{7330}\x{7331}\x{7332}' . +'\x{7333}\x{7334}\x{7335}\x{7336}\x{7337}\x{7338}\x{7339}\x{733A}\x{733B}' . +'\x{733C}\x{733D}\x{733E}\x{733F}\x{7340}\x{7341}\x{7342}\x{7343}\x{7344}' . +'\x{7345}\x{7346}\x{7347}\x{7348}\x{7349}\x{734A}\x{734B}\x{734C}\x{734D}' . +'\x{734E}\x{7350}\x{7351}\x{7352}\x{7354}\x{7355}\x{7356}\x{7357}\x{7358}' . +'\x{7359}\x{735A}\x{735B}\x{735C}\x{735D}\x{735E}\x{735F}\x{7360}\x{7361}' . +'\x{7362}\x{7364}\x{7365}\x{7366}\x{7367}\x{7368}\x{7369}\x{736A}\x{736B}' . +'\x{736C}\x{736D}\x{736E}\x{736F}\x{7370}\x{7371}\x{7372}\x{7373}\x{7374}' . +'\x{7375}\x{7376}\x{7377}\x{7378}\x{7379}\x{737A}\x{737B}\x{737C}\x{737D}' . +'\x{737E}\x{737F}\x{7380}\x{7381}\x{7382}\x{7383}\x{7384}\x{7385}\x{7386}' . +'\x{7387}\x{7388}\x{7389}\x{738A}\x{738B}\x{738C}\x{738D}\x{738E}\x{738F}' . +'\x{7390}\x{7391}\x{7392}\x{7393}\x{7394}\x{7395}\x{7396}\x{7397}\x{7398}' . +'\x{7399}\x{739A}\x{739B}\x{739D}\x{739E}\x{739F}\x{73A0}\x{73A1}\x{73A2}' . +'\x{73A3}\x{73A4}\x{73A5}\x{73A6}\x{73A7}\x{73A8}\x{73A9}\x{73AA}\x{73AB}' . +'\x{73AC}\x{73AD}\x{73AE}\x{73AF}\x{73B0}\x{73B1}\x{73B2}\x{73B3}\x{73B4}' . +'\x{73B5}\x{73B6}\x{73B7}\x{73B8}\x{73B9}\x{73BA}\x{73BB}\x{73BC}\x{73BD}' . +'\x{73BE}\x{73BF}\x{73C0}\x{73C2}\x{73C3}\x{73C4}\x{73C5}\x{73C6}\x{73C7}' . +'\x{73C8}\x{73C9}\x{73CA}\x{73CB}\x{73CC}\x{73CD}\x{73CE}\x{73CF}\x{73D0}' . +'\x{73D1}\x{73D2}\x{73D3}\x{73D4}\x{73D5}\x{73D6}\x{73D7}\x{73D8}\x{73D9}' . +'\x{73DA}\x{73DB}\x{73DC}\x{73DD}\x{73DE}\x{73DF}\x{73E0}\x{73E2}\x{73E3}' . +'\x{73E5}\x{73E6}\x{73E7}\x{73E8}\x{73E9}\x{73EA}\x{73EB}\x{73EC}\x{73ED}' . +'\x{73EE}\x{73EF}\x{73F0}\x{73F1}\x{73F2}\x{73F4}\x{73F5}\x{73F6}\x{73F7}' . +'\x{73F8}\x{73F9}\x{73FA}\x{73FC}\x{73FD}\x{73FE}\x{73FF}\x{7400}\x{7401}' . +'\x{7402}\x{7403}\x{7404}\x{7405}\x{7406}\x{7407}\x{7408}\x{7409}\x{740A}' . +'\x{740B}\x{740C}\x{740D}\x{740E}\x{740F}\x{7410}\x{7411}\x{7412}\x{7413}' . +'\x{7414}\x{7415}\x{7416}\x{7417}\x{7419}\x{741A}\x{741B}\x{741C}\x{741D}' . +'\x{741E}\x{741F}\x{7420}\x{7421}\x{7422}\x{7423}\x{7424}\x{7425}\x{7426}' . +'\x{7427}\x{7428}\x{7429}\x{742A}\x{742B}\x{742C}\x{742D}\x{742E}\x{742F}' . +'\x{7430}\x{7431}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{7437}\x{7438}' . +'\x{743A}\x{743B}\x{743C}\x{743D}\x{743F}\x{7440}\x{7441}\x{7442}\x{7443}' . +'\x{7444}\x{7445}\x{7446}\x{7448}\x{744A}\x{744B}\x{744C}\x{744D}\x{744E}' . +'\x{744F}\x{7450}\x{7451}\x{7452}\x{7453}\x{7454}\x{7455}\x{7456}\x{7457}' . +'\x{7459}\x{745A}\x{745B}\x{745C}\x{745D}\x{745E}\x{745F}\x{7461}\x{7462}' . +'\x{7463}\x{7464}\x{7465}\x{7466}\x{7467}\x{7468}\x{7469}\x{746A}\x{746B}' . +'\x{746C}\x{746D}\x{746E}\x{746F}\x{7470}\x{7471}\x{7472}\x{7473}\x{7474}' . +'\x{7475}\x{7476}\x{7477}\x{7478}\x{7479}\x{747A}\x{747C}\x{747D}\x{747E}' . +'\x{747F}\x{7480}\x{7481}\x{7482}\x{7483}\x{7485}\x{7486}\x{7487}\x{7488}' . +'\x{7489}\x{748A}\x{748B}\x{748C}\x{748D}\x{748E}\x{748F}\x{7490}\x{7491}' . +'\x{7492}\x{7493}\x{7494}\x{7495}\x{7497}\x{7498}\x{7499}\x{749A}\x{749B}' . +'\x{749C}\x{749E}\x{749F}\x{74A0}\x{74A1}\x{74A3}\x{74A4}\x{74A5}\x{74A6}' . +'\x{74A7}\x{74A8}\x{74A9}\x{74AA}\x{74AB}\x{74AC}\x{74AD}\x{74AE}\x{74AF}' . +'\x{74B0}\x{74B1}\x{74B2}\x{74B3}\x{74B4}\x{74B5}\x{74B6}\x{74B7}\x{74B8}' . +'\x{74B9}\x{74BA}\x{74BB}\x{74BC}\x{74BD}\x{74BE}\x{74BF}\x{74C0}\x{74C1}' . +'\x{74C2}\x{74C3}\x{74C4}\x{74C5}\x{74C6}\x{74CA}\x{74CB}\x{74CD}\x{74CE}' . +'\x{74CF}\x{74D0}\x{74D1}\x{74D2}\x{74D3}\x{74D4}\x{74D5}\x{74D6}\x{74D7}' . +'\x{74D8}\x{74D9}\x{74DA}\x{74DB}\x{74DC}\x{74DD}\x{74DE}\x{74DF}\x{74E0}' . +'\x{74E1}\x{74E2}\x{74E3}\x{74E4}\x{74E5}\x{74E6}\x{74E7}\x{74E8}\x{74E9}' . +'\x{74EA}\x{74EC}\x{74ED}\x{74EE}\x{74EF}\x{74F0}\x{74F1}\x{74F2}\x{74F3}' . +'\x{74F4}\x{74F5}\x{74F6}\x{74F7}\x{74F8}\x{74F9}\x{74FA}\x{74FB}\x{74FC}' . +'\x{74FD}\x{74FE}\x{74FF}\x{7500}\x{7501}\x{7502}\x{7503}\x{7504}\x{7505}' . +'\x{7506}\x{7507}\x{7508}\x{7509}\x{750A}\x{750B}\x{750C}\x{750D}\x{750F}' . +'\x{7510}\x{7511}\x{7512}\x{7513}\x{7514}\x{7515}\x{7516}\x{7517}\x{7518}' . +'\x{7519}\x{751A}\x{751B}\x{751C}\x{751D}\x{751E}\x{751F}\x{7521}\x{7522}' . +'\x{7523}\x{7524}\x{7525}\x{7526}\x{7527}\x{7528}\x{7529}\x{752A}\x{752B}' . +'\x{752C}\x{752D}\x{752E}\x{752F}\x{7530}\x{7531}\x{7532}\x{7533}\x{7535}' . +'\x{7536}\x{7537}\x{7538}\x{7539}\x{753A}\x{753B}\x{753C}\x{753D}\x{753E}' . +'\x{753F}\x{7540}\x{7542}\x{7543}\x{7544}\x{7545}\x{7546}\x{7547}\x{7548}' . +'\x{7549}\x{754B}\x{754C}\x{754D}\x{754E}\x{754F}\x{7550}\x{7551}\x{7553}' . +'\x{7554}\x{7556}\x{7557}\x{7558}\x{7559}\x{755A}\x{755B}\x{755C}\x{755D}' . +'\x{755F}\x{7560}\x{7562}\x{7563}\x{7564}\x{7565}\x{7566}\x{7567}\x{7568}' . +'\x{7569}\x{756A}\x{756B}\x{756C}\x{756D}\x{756E}\x{756F}\x{7570}\x{7572}' . +'\x{7574}\x{7575}\x{7576}\x{7577}\x{7578}\x{7579}\x{757C}\x{757D}\x{757E}' . +'\x{757F}\x{7580}\x{7581}\x{7582}\x{7583}\x{7584}\x{7586}\x{7587}\x{7588}' . +'\x{7589}\x{758A}\x{758B}\x{758C}\x{758D}\x{758F}\x{7590}\x{7591}\x{7592}' . +'\x{7593}\x{7594}\x{7595}\x{7596}\x{7597}\x{7598}\x{7599}\x{759A}\x{759B}' . +'\x{759C}\x{759D}\x{759E}\x{759F}\x{75A0}\x{75A1}\x{75A2}\x{75A3}\x{75A4}' . +'\x{75A5}\x{75A6}\x{75A7}\x{75A8}\x{75AA}\x{75AB}\x{75AC}\x{75AD}\x{75AE}' . +'\x{75AF}\x{75B0}\x{75B1}\x{75B2}\x{75B3}\x{75B4}\x{75B5}\x{75B6}\x{75B8}' . +'\x{75B9}\x{75BA}\x{75BB}\x{75BC}\x{75BD}\x{75BE}\x{75BF}\x{75C0}\x{75C1}' . +'\x{75C2}\x{75C3}\x{75C4}\x{75C5}\x{75C6}\x{75C7}\x{75C8}\x{75C9}\x{75CA}' . +'\x{75CB}\x{75CC}\x{75CD}\x{75CE}\x{75CF}\x{75D0}\x{75D1}\x{75D2}\x{75D3}' . +'\x{75D4}\x{75D5}\x{75D6}\x{75D7}\x{75D8}\x{75D9}\x{75DA}\x{75DB}\x{75DD}' . +'\x{75DE}\x{75DF}\x{75E0}\x{75E1}\x{75E2}\x{75E3}\x{75E4}\x{75E5}\x{75E6}' . +'\x{75E7}\x{75E8}\x{75EA}\x{75EB}\x{75EC}\x{75ED}\x{75EF}\x{75F0}\x{75F1}' . +'\x{75F2}\x{75F3}\x{75F4}\x{75F5}\x{75F6}\x{75F7}\x{75F8}\x{75F9}\x{75FA}' . +'\x{75FB}\x{75FC}\x{75FD}\x{75FE}\x{75FF}\x{7600}\x{7601}\x{7602}\x{7603}' . +'\x{7604}\x{7605}\x{7606}\x{7607}\x{7608}\x{7609}\x{760A}\x{760B}\x{760C}' . +'\x{760D}\x{760E}\x{760F}\x{7610}\x{7611}\x{7612}\x{7613}\x{7614}\x{7615}' . +'\x{7616}\x{7617}\x{7618}\x{7619}\x{761A}\x{761B}\x{761C}\x{761D}\x{761E}' . +'\x{761F}\x{7620}\x{7621}\x{7622}\x{7623}\x{7624}\x{7625}\x{7626}\x{7627}' . +'\x{7628}\x{7629}\x{762A}\x{762B}\x{762D}\x{762E}\x{762F}\x{7630}\x{7631}' . +'\x{7632}\x{7633}\x{7634}\x{7635}\x{7636}\x{7637}\x{7638}\x{7639}\x{763A}' . +'\x{763B}\x{763C}\x{763D}\x{763E}\x{763F}\x{7640}\x{7641}\x{7642}\x{7643}' . +'\x{7646}\x{7647}\x{7648}\x{7649}\x{764A}\x{764B}\x{764C}\x{764D}\x{764F}' . +'\x{7650}\x{7652}\x{7653}\x{7654}\x{7656}\x{7657}\x{7658}\x{7659}\x{765A}' . +'\x{765B}\x{765C}\x{765D}\x{765E}\x{765F}\x{7660}\x{7661}\x{7662}\x{7663}' . +'\x{7664}\x{7665}\x{7666}\x{7667}\x{7668}\x{7669}\x{766A}\x{766B}\x{766C}' . +'\x{766D}\x{766E}\x{766F}\x{7670}\x{7671}\x{7672}\x{7674}\x{7675}\x{7676}' . +'\x{7677}\x{7678}\x{7679}\x{767B}\x{767C}\x{767D}\x{767E}\x{767F}\x{7680}' . +'\x{7681}\x{7682}\x{7683}\x{7684}\x{7685}\x{7686}\x{7687}\x{7688}\x{7689}' . +'\x{768A}\x{768B}\x{768C}\x{768E}\x{768F}\x{7690}\x{7691}\x{7692}\x{7693}' . +'\x{7694}\x{7695}\x{7696}\x{7697}\x{7698}\x{7699}\x{769A}\x{769B}\x{769C}' . +'\x{769D}\x{769E}\x{769F}\x{76A0}\x{76A3}\x{76A4}\x{76A6}\x{76A7}\x{76A9}' . +'\x{76AA}\x{76AB}\x{76AC}\x{76AD}\x{76AE}\x{76AF}\x{76B0}\x{76B1}\x{76B2}' . +'\x{76B4}\x{76B5}\x{76B7}\x{76B8}\x{76BA}\x{76BB}\x{76BC}\x{76BD}\x{76BE}' . +'\x{76BF}\x{76C0}\x{76C2}\x{76C3}\x{76C4}\x{76C5}\x{76C6}\x{76C7}\x{76C8}' . +'\x{76C9}\x{76CA}\x{76CD}\x{76CE}\x{76CF}\x{76D0}\x{76D1}\x{76D2}\x{76D3}' . +'\x{76D4}\x{76D5}\x{76D6}\x{76D7}\x{76D8}\x{76DA}\x{76DB}\x{76DC}\x{76DD}' . +'\x{76DE}\x{76DF}\x{76E0}\x{76E1}\x{76E2}\x{76E3}\x{76E4}\x{76E5}\x{76E6}' . +'\x{76E7}\x{76E8}\x{76E9}\x{76EA}\x{76EC}\x{76ED}\x{76EE}\x{76EF}\x{76F0}' . +'\x{76F1}\x{76F2}\x{76F3}\x{76F4}\x{76F5}\x{76F6}\x{76F7}\x{76F8}\x{76F9}' . +'\x{76FA}\x{76FB}\x{76FC}\x{76FD}\x{76FE}\x{76FF}\x{7701}\x{7703}\x{7704}' . +'\x{7705}\x{7706}\x{7707}\x{7708}\x{7709}\x{770A}\x{770B}\x{770C}\x{770D}' . +'\x{770F}\x{7710}\x{7711}\x{7712}\x{7713}\x{7714}\x{7715}\x{7716}\x{7717}' . +'\x{7718}\x{7719}\x{771A}\x{771B}\x{771C}\x{771D}\x{771E}\x{771F}\x{7720}' . +'\x{7722}\x{7723}\x{7725}\x{7726}\x{7727}\x{7728}\x{7729}\x{772A}\x{772C}' . +'\x{772D}\x{772E}\x{772F}\x{7730}\x{7731}\x{7732}\x{7733}\x{7734}\x{7735}' . +'\x{7736}\x{7737}\x{7738}\x{7739}\x{773A}\x{773B}\x{773C}\x{773D}\x{773E}' . +'\x{7740}\x{7741}\x{7743}\x{7744}\x{7745}\x{7746}\x{7747}\x{7748}\x{7749}' . +'\x{774A}\x{774B}\x{774C}\x{774D}\x{774E}\x{774F}\x{7750}\x{7751}\x{7752}' . +'\x{7753}\x{7754}\x{7755}\x{7756}\x{7757}\x{7758}\x{7759}\x{775A}\x{775B}' . +'\x{775C}\x{775D}\x{775E}\x{775F}\x{7760}\x{7761}\x{7762}\x{7763}\x{7765}' . +'\x{7766}\x{7767}\x{7768}\x{7769}\x{776A}\x{776B}\x{776C}\x{776D}\x{776E}' . +'\x{776F}\x{7770}\x{7771}\x{7772}\x{7773}\x{7774}\x{7775}\x{7776}\x{7777}' . +'\x{7778}\x{7779}\x{777A}\x{777B}\x{777C}\x{777D}\x{777E}\x{777F}\x{7780}' . +'\x{7781}\x{7782}\x{7783}\x{7784}\x{7785}\x{7786}\x{7787}\x{7788}\x{7789}' . +'\x{778A}\x{778B}\x{778C}\x{778D}\x{778E}\x{778F}\x{7790}\x{7791}\x{7792}' . +'\x{7793}\x{7794}\x{7795}\x{7797}\x{7798}\x{7799}\x{779A}\x{779B}\x{779C}' . +'\x{779D}\x{779E}\x{779F}\x{77A0}\x{77A1}\x{77A2}\x{77A3}\x{77A5}\x{77A6}' . +'\x{77A7}\x{77A8}\x{77A9}\x{77AA}\x{77AB}\x{77AC}\x{77AD}\x{77AE}\x{77AF}' . +'\x{77B0}\x{77B1}\x{77B2}\x{77B3}\x{77B4}\x{77B5}\x{77B6}\x{77B7}\x{77B8}' . +'\x{77B9}\x{77BA}\x{77BB}\x{77BC}\x{77BD}\x{77BF}\x{77C0}\x{77C2}\x{77C3}' . +'\x{77C4}\x{77C5}\x{77C6}\x{77C7}\x{77C8}\x{77C9}\x{77CA}\x{77CB}\x{77CC}' . +'\x{77CD}\x{77CE}\x{77CF}\x{77D0}\x{77D1}\x{77D3}\x{77D4}\x{77D5}\x{77D6}' . +'\x{77D7}\x{77D8}\x{77D9}\x{77DA}\x{77DB}\x{77DC}\x{77DE}\x{77DF}\x{77E0}' . +'\x{77E1}\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E8}\x{77E9}\x{77EA}\x{77EB}' . +'\x{77EC}\x{77ED}\x{77EE}\x{77EF}\x{77F0}\x{77F1}\x{77F2}\x{77F3}\x{77F6}' . +'\x{77F7}\x{77F8}\x{77F9}\x{77FA}\x{77FB}\x{77FC}\x{77FD}\x{77FE}\x{77FF}' . +'\x{7800}\x{7801}\x{7802}\x{7803}\x{7804}\x{7805}\x{7806}\x{7808}\x{7809}' . +'\x{780A}\x{780B}\x{780C}\x{780D}\x{780E}\x{780F}\x{7810}\x{7811}\x{7812}' . +'\x{7813}\x{7814}\x{7815}\x{7816}\x{7817}\x{7818}\x{7819}\x{781A}\x{781B}' . +'\x{781C}\x{781D}\x{781E}\x{781F}\x{7820}\x{7821}\x{7822}\x{7823}\x{7825}' . +'\x{7826}\x{7827}\x{7828}\x{7829}\x{782A}\x{782B}\x{782C}\x{782D}\x{782E}' . +'\x{782F}\x{7830}\x{7831}\x{7832}\x{7833}\x{7834}\x{7835}\x{7837}\x{7838}' . +'\x{7839}\x{783A}\x{783B}\x{783C}\x{783D}\x{783E}\x{7840}\x{7841}\x{7843}' . +'\x{7844}\x{7845}\x{7847}\x{7848}\x{7849}\x{784A}\x{784C}\x{784D}\x{784E}' . +'\x{7850}\x{7851}\x{7852}\x{7853}\x{7854}\x{7855}\x{7856}\x{7857}\x{7858}' . +'\x{7859}\x{785A}\x{785B}\x{785C}\x{785D}\x{785E}\x{785F}\x{7860}\x{7861}' . +'\x{7862}\x{7863}\x{7864}\x{7865}\x{7866}\x{7867}\x{7868}\x{7869}\x{786A}' . +'\x{786B}\x{786C}\x{786D}\x{786E}\x{786F}\x{7870}\x{7871}\x{7872}\x{7873}' . +'\x{7874}\x{7875}\x{7877}\x{7878}\x{7879}\x{787A}\x{787B}\x{787C}\x{787D}' . +'\x{787E}\x{787F}\x{7880}\x{7881}\x{7882}\x{7883}\x{7884}\x{7885}\x{7886}' . +'\x{7887}\x{7889}\x{788A}\x{788B}\x{788C}\x{788D}\x{788E}\x{788F}\x{7890}' . +'\x{7891}\x{7892}\x{7893}\x{7894}\x{7895}\x{7896}\x{7897}\x{7898}\x{7899}' . +'\x{789A}\x{789B}\x{789C}\x{789D}\x{789E}\x{789F}\x{78A0}\x{78A1}\x{78A2}' . +'\x{78A3}\x{78A4}\x{78A5}\x{78A6}\x{78A7}\x{78A8}\x{78A9}\x{78AA}\x{78AB}' . +'\x{78AC}\x{78AD}\x{78AE}\x{78AF}\x{78B0}\x{78B1}\x{78B2}\x{78B3}\x{78B4}' . +'\x{78B5}\x{78B6}\x{78B7}\x{78B8}\x{78B9}\x{78BA}\x{78BB}\x{78BC}\x{78BD}' . +'\x{78BE}\x{78BF}\x{78C0}\x{78C1}\x{78C3}\x{78C4}\x{78C5}\x{78C6}\x{78C8}' . +'\x{78C9}\x{78CA}\x{78CB}\x{78CC}\x{78CD}\x{78CE}\x{78CF}\x{78D0}\x{78D1}' . +'\x{78D3}\x{78D4}\x{78D5}\x{78D6}\x{78D7}\x{78D8}\x{78D9}\x{78DA}\x{78DB}' . +'\x{78DC}\x{78DD}\x{78DE}\x{78DF}\x{78E0}\x{78E1}\x{78E2}\x{78E3}\x{78E4}' . +'\x{78E5}\x{78E6}\x{78E7}\x{78E8}\x{78E9}\x{78EA}\x{78EB}\x{78EC}\x{78ED}' . +'\x{78EE}\x{78EF}\x{78F1}\x{78F2}\x{78F3}\x{78F4}\x{78F5}\x{78F6}\x{78F7}' . +'\x{78F9}\x{78FA}\x{78FB}\x{78FC}\x{78FD}\x{78FE}\x{78FF}\x{7901}\x{7902}' . +'\x{7903}\x{7904}\x{7905}\x{7906}\x{7907}\x{7909}\x{790A}\x{790B}\x{790C}' . +'\x{790E}\x{790F}\x{7910}\x{7911}\x{7912}\x{7913}\x{7914}\x{7916}\x{7917}' . +'\x{7918}\x{7919}\x{791A}\x{791B}\x{791C}\x{791D}\x{791E}\x{7921}\x{7922}' . +'\x{7923}\x{7924}\x{7925}\x{7926}\x{7927}\x{7928}\x{7929}\x{792A}\x{792B}' . +'\x{792C}\x{792D}\x{792E}\x{792F}\x{7930}\x{7931}\x{7933}\x{7934}\x{7935}' . +'\x{7937}\x{7938}\x{7939}\x{793A}\x{793B}\x{793C}\x{793D}\x{793E}\x{793F}' . +'\x{7940}\x{7941}\x{7942}\x{7943}\x{7944}\x{7945}\x{7946}\x{7947}\x{7948}' . +'\x{7949}\x{794A}\x{794B}\x{794C}\x{794D}\x{794E}\x{794F}\x{7950}\x{7951}' . +'\x{7952}\x{7953}\x{7954}\x{7955}\x{7956}\x{7957}\x{7958}\x{795A}\x{795B}' . +'\x{795C}\x{795D}\x{795E}\x{795F}\x{7960}\x{7961}\x{7962}\x{7963}\x{7964}' . +'\x{7965}\x{7966}\x{7967}\x{7968}\x{7969}\x{796A}\x{796B}\x{796D}\x{796F}' . +'\x{7970}\x{7971}\x{7972}\x{7973}\x{7974}\x{7977}\x{7978}\x{7979}\x{797A}' . +'\x{797B}\x{797C}\x{797D}\x{797E}\x{797F}\x{7980}\x{7981}\x{7982}\x{7983}' . +'\x{7984}\x{7985}\x{7988}\x{7989}\x{798A}\x{798B}\x{798C}\x{798D}\x{798E}' . +'\x{798F}\x{7990}\x{7991}\x{7992}\x{7993}\x{7994}\x{7995}\x{7996}\x{7997}' . +'\x{7998}\x{7999}\x{799A}\x{799B}\x{799C}\x{799F}\x{79A0}\x{79A1}\x{79A2}' . +'\x{79A3}\x{79A4}\x{79A5}\x{79A6}\x{79A7}\x{79A8}\x{79AA}\x{79AB}\x{79AC}' . +'\x{79AD}\x{79AE}\x{79AF}\x{79B0}\x{79B1}\x{79B2}\x{79B3}\x{79B4}\x{79B5}' . +'\x{79B6}\x{79B7}\x{79B8}\x{79B9}\x{79BA}\x{79BB}\x{79BD}\x{79BE}\x{79BF}' . +'\x{79C0}\x{79C1}\x{79C2}\x{79C3}\x{79C5}\x{79C6}\x{79C8}\x{79C9}\x{79CA}' . +'\x{79CB}\x{79CD}\x{79CE}\x{79CF}\x{79D0}\x{79D1}\x{79D2}\x{79D3}\x{79D5}' . +'\x{79D6}\x{79D8}\x{79D9}\x{79DA}\x{79DB}\x{79DC}\x{79DD}\x{79DE}\x{79DF}' . +'\x{79E0}\x{79E1}\x{79E2}\x{79E3}\x{79E4}\x{79E5}\x{79E6}\x{79E7}\x{79E8}' . +'\x{79E9}\x{79EA}\x{79EB}\x{79EC}\x{79ED}\x{79EE}\x{79EF}\x{79F0}\x{79F1}' . +'\x{79F2}\x{79F3}\x{79F4}\x{79F5}\x{79F6}\x{79F7}\x{79F8}\x{79F9}\x{79FA}' . +'\x{79FB}\x{79FC}\x{79FD}\x{79FE}\x{79FF}\x{7A00}\x{7A02}\x{7A03}\x{7A04}' . +'\x{7A05}\x{7A06}\x{7A08}\x{7A0A}\x{7A0B}\x{7A0C}\x{7A0D}\x{7A0E}\x{7A0F}' . +'\x{7A10}\x{7A11}\x{7A12}\x{7A13}\x{7A14}\x{7A15}\x{7A16}\x{7A17}\x{7A18}' . +'\x{7A19}\x{7A1A}\x{7A1B}\x{7A1C}\x{7A1D}\x{7A1E}\x{7A1F}\x{7A20}\x{7A21}' . +'\x{7A22}\x{7A23}\x{7A24}\x{7A25}\x{7A26}\x{7A27}\x{7A28}\x{7A29}\x{7A2A}' . +'\x{7A2B}\x{7A2D}\x{7A2E}\x{7A2F}\x{7A30}\x{7A31}\x{7A32}\x{7A33}\x{7A34}' . +'\x{7A35}\x{7A37}\x{7A39}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A41}\x{7A42}\x{7A43}\x{7A44}\x{7A45}\x{7A46}\x{7A47}\x{7A48}\x{7A49}' . +'\x{7A4A}\x{7A4B}\x{7A4C}\x{7A4D}\x{7A4E}\x{7A50}\x{7A51}\x{7A52}\x{7A53}' . +'\x{7A54}\x{7A55}\x{7A56}\x{7A57}\x{7A58}\x{7A59}\x{7A5A}\x{7A5B}\x{7A5C}' . +'\x{7A5D}\x{7A5E}\x{7A5F}\x{7A60}\x{7A61}\x{7A62}\x{7A65}\x{7A66}\x{7A67}' . +'\x{7A68}\x{7A69}\x{7A6B}\x{7A6C}\x{7A6D}\x{7A6E}\x{7A70}\x{7A71}\x{7A72}' . +'\x{7A73}\x{7A74}\x{7A75}\x{7A76}\x{7A77}\x{7A78}\x{7A79}\x{7A7A}\x{7A7B}' . +'\x{7A7C}\x{7A7D}\x{7A7E}\x{7A7F}\x{7A80}\x{7A81}\x{7A83}\x{7A84}\x{7A85}' . +'\x{7A86}\x{7A87}\x{7A88}\x{7A89}\x{7A8A}\x{7A8B}\x{7A8C}\x{7A8D}\x{7A8E}' . +'\x{7A8F}\x{7A90}\x{7A91}\x{7A92}\x{7A93}\x{7A94}\x{7A95}\x{7A96}\x{7A97}' . +'\x{7A98}\x{7A99}\x{7A9C}\x{7A9D}\x{7A9E}\x{7A9F}\x{7AA0}\x{7AA1}\x{7AA2}' . +'\x{7AA3}\x{7AA4}\x{7AA5}\x{7AA6}\x{7AA7}\x{7AA8}\x{7AA9}\x{7AAA}\x{7AAB}' . +'\x{7AAC}\x{7AAD}\x{7AAE}\x{7AAF}\x{7AB0}\x{7AB1}\x{7AB2}\x{7AB3}\x{7AB4}' . +'\x{7AB5}\x{7AB6}\x{7AB7}\x{7AB8}\x{7ABA}\x{7ABE}\x{7ABF}\x{7AC0}\x{7AC1}' . +'\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}\x{7AC9}\x{7ACA}\x{7ACB}\x{7ACC}\x{7ACD}' . +'\x{7ACE}\x{7ACF}\x{7AD0}\x{7AD1}\x{7AD2}\x{7AD3}\x{7AD4}\x{7AD5}\x{7AD6}' . +'\x{7AD8}\x{7AD9}\x{7ADB}\x{7ADC}\x{7ADD}\x{7ADE}\x{7ADF}\x{7AE0}\x{7AE1}' . +'\x{7AE2}\x{7AE3}\x{7AE4}\x{7AE5}\x{7AE6}\x{7AE7}\x{7AE8}\x{7AEA}\x{7AEB}' . +'\x{7AEC}\x{7AED}\x{7AEE}\x{7AEF}\x{7AF0}\x{7AF1}\x{7AF2}\x{7AF3}\x{7AF4}' . +'\x{7AF6}\x{7AF7}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFB}\x{7AFD}\x{7AFE}\x{7AFF}' . +'\x{7B00}\x{7B01}\x{7B02}\x{7B03}\x{7B04}\x{7B05}\x{7B06}\x{7B08}\x{7B09}' . +'\x{7B0A}\x{7B0B}\x{7B0C}\x{7B0D}\x{7B0E}\x{7B0F}\x{7B10}\x{7B11}\x{7B12}' . +'\x{7B13}\x{7B14}\x{7B15}\x{7B16}\x{7B17}\x{7B18}\x{7B19}\x{7B1A}\x{7B1B}' . +'\x{7B1C}\x{7B1D}\x{7B1E}\x{7B20}\x{7B21}\x{7B22}\x{7B23}\x{7B24}\x{7B25}' . +'\x{7B26}\x{7B28}\x{7B2A}\x{7B2B}\x{7B2C}\x{7B2D}\x{7B2E}\x{7B2F}\x{7B30}' . +'\x{7B31}\x{7B32}\x{7B33}\x{7B34}\x{7B35}\x{7B36}\x{7B37}\x{7B38}\x{7B39}' . +'\x{7B3A}\x{7B3B}\x{7B3C}\x{7B3D}\x{7B3E}\x{7B3F}\x{7B40}\x{7B41}\x{7B43}' . +'\x{7B44}\x{7B45}\x{7B46}\x{7B47}\x{7B48}\x{7B49}\x{7B4A}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4E}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B55}\x{7B56}' . +'\x{7B57}\x{7B58}\x{7B59}\x{7B5A}\x{7B5B}\x{7B5C}\x{7B5D}\x{7B5E}\x{7B5F}' . +'\x{7B60}\x{7B61}\x{7B62}\x{7B63}\x{7B64}\x{7B65}\x{7B66}\x{7B67}\x{7B68}' . +'\x{7B69}\x{7B6A}\x{7B6B}\x{7B6C}\x{7B6D}\x{7B6E}\x{7B70}\x{7B71}\x{7B72}' . +'\x{7B73}\x{7B74}\x{7B75}\x{7B76}\x{7B77}\x{7B78}\x{7B79}\x{7B7B}\x{7B7C}' . +'\x{7B7D}\x{7B7E}\x{7B7F}\x{7B80}\x{7B81}\x{7B82}\x{7B83}\x{7B84}\x{7B85}' . +'\x{7B87}\x{7B88}\x{7B89}\x{7B8A}\x{7B8B}\x{7B8C}\x{7B8D}\x{7B8E}\x{7B8F}' . +'\x{7B90}\x{7B91}\x{7B93}\x{7B94}\x{7B95}\x{7B96}\x{7B97}\x{7B98}\x{7B99}' . +'\x{7B9A}\x{7B9B}\x{7B9C}\x{7B9D}\x{7B9E}\x{7B9F}\x{7BA0}\x{7BA1}\x{7BA2}' . +'\x{7BA4}\x{7BA6}\x{7BA7}\x{7BA8}\x{7BA9}\x{7BAA}\x{7BAB}\x{7BAC}\x{7BAD}' . +'\x{7BAE}\x{7BAF}\x{7BB1}\x{7BB3}\x{7BB4}\x{7BB5}\x{7BB6}\x{7BB7}\x{7BB8}' . +'\x{7BB9}\x{7BBA}\x{7BBB}\x{7BBC}\x{7BBD}\x{7BBE}\x{7BBF}\x{7BC0}\x{7BC1}' . +'\x{7BC2}\x{7BC3}\x{7BC4}\x{7BC5}\x{7BC6}\x{7BC7}\x{7BC8}\x{7BC9}\x{7BCA}' . +'\x{7BCB}\x{7BCC}\x{7BCD}\x{7BCE}\x{7BD0}\x{7BD1}\x{7BD2}\x{7BD3}\x{7BD4}' . +'\x{7BD5}\x{7BD6}\x{7BD7}\x{7BD8}\x{7BD9}\x{7BDA}\x{7BDB}\x{7BDC}\x{7BDD}' . +'\x{7BDE}\x{7BDF}\x{7BE0}\x{7BE1}\x{7BE2}\x{7BE3}\x{7BE4}\x{7BE5}\x{7BE6}' . +'\x{7BE7}\x{7BE8}\x{7BE9}\x{7BEA}\x{7BEB}\x{7BEC}\x{7BED}\x{7BEE}\x{7BEF}' . +'\x{7BF0}\x{7BF1}\x{7BF2}\x{7BF3}\x{7BF4}\x{7BF5}\x{7BF6}\x{7BF7}\x{7BF8}' . +'\x{7BF9}\x{7BFB}\x{7BFC}\x{7BFD}\x{7BFE}\x{7BFF}\x{7C00}\x{7C01}\x{7C02}' . +'\x{7C03}\x{7C04}\x{7C05}\x{7C06}\x{7C07}\x{7C08}\x{7C09}\x{7C0A}\x{7C0B}' . +'\x{7C0C}\x{7C0D}\x{7C0E}\x{7C0F}\x{7C10}\x{7C11}\x{7C12}\x{7C13}\x{7C15}' . +'\x{7C16}\x{7C17}\x{7C18}\x{7C19}\x{7C1A}\x{7C1C}\x{7C1D}\x{7C1E}\x{7C1F}' . +'\x{7C20}\x{7C21}\x{7C22}\x{7C23}\x{7C24}\x{7C25}\x{7C26}\x{7C27}\x{7C28}' . +'\x{7C29}\x{7C2A}\x{7C2B}\x{7C2C}\x{7C2D}\x{7C30}\x{7C31}\x{7C32}\x{7C33}' . +'\x{7C34}\x{7C35}\x{7C36}\x{7C37}\x{7C38}\x{7C39}\x{7C3A}\x{7C3B}\x{7C3C}' . +'\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C41}\x{7C42}\x{7C43}\x{7C44}\x{7C45}' . +'\x{7C46}\x{7C47}\x{7C48}\x{7C49}\x{7C4A}\x{7C4B}\x{7C4C}\x{7C4D}\x{7C4E}' . +'\x{7C50}\x{7C51}\x{7C53}\x{7C54}\x{7C56}\x{7C57}\x{7C58}\x{7C59}\x{7C5A}' . +'\x{7C5B}\x{7C5C}\x{7C5E}\x{7C5F}\x{7C60}\x{7C61}\x{7C62}\x{7C63}\x{7C64}' . +'\x{7C65}\x{7C66}\x{7C67}\x{7C68}\x{7C69}\x{7C6A}\x{7C6B}\x{7C6C}\x{7C6D}' . +'\x{7C6E}\x{7C6F}\x{7C70}\x{7C71}\x{7C72}\x{7C73}\x{7C74}\x{7C75}\x{7C77}' . +'\x{7C78}\x{7C79}\x{7C7A}\x{7C7B}\x{7C7C}\x{7C7D}\x{7C7E}\x{7C7F}\x{7C80}' . +'\x{7C81}\x{7C82}\x{7C84}\x{7C85}\x{7C86}\x{7C88}\x{7C89}\x{7C8A}\x{7C8B}' . +'\x{7C8C}\x{7C8D}\x{7C8E}\x{7C8F}\x{7C90}\x{7C91}\x{7C92}\x{7C94}\x{7C95}' . +'\x{7C96}\x{7C97}\x{7C98}\x{7C99}\x{7C9B}\x{7C9C}\x{7C9D}\x{7C9E}\x{7C9F}' . +'\x{7CA0}\x{7CA1}\x{7CA2}\x{7CA3}\x{7CA4}\x{7CA5}\x{7CA6}\x{7CA7}\x{7CA8}' . +'\x{7CA9}\x{7CAA}\x{7CAD}\x{7CAE}\x{7CAF}\x{7CB0}\x{7CB1}\x{7CB2}\x{7CB3}' . +'\x{7CB4}\x{7CB5}\x{7CB6}\x{7CB7}\x{7CB8}\x{7CB9}\x{7CBA}\x{7CBB}\x{7CBC}' . +'\x{7CBD}\x{7CBE}\x{7CBF}\x{7CC0}\x{7CC1}\x{7CC2}\x{7CC3}\x{7CC4}\x{7CC5}' . +'\x{7CC6}\x{7CC7}\x{7CC8}\x{7CC9}\x{7CCA}\x{7CCB}\x{7CCC}\x{7CCD}\x{7CCE}' . +'\x{7CCF}\x{7CD0}\x{7CD1}\x{7CD2}\x{7CD4}\x{7CD5}\x{7CD6}\x{7CD7}\x{7CD8}' . +'\x{7CD9}\x{7CDC}\x{7CDD}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE4}\x{7CE7}' . +'\x{7CE8}\x{7CE9}\x{7CEA}\x{7CEB}\x{7CEC}\x{7CED}\x{7CEE}\x{7CEF}\x{7CF0}' . +'\x{7CF1}\x{7CF2}\x{7CF3}\x{7CF4}\x{7CF5}\x{7CF6}\x{7CF7}\x{7CF8}\x{7CF9}' . +'\x{7CFA}\x{7CFB}\x{7CFD}\x{7CFE}\x{7D00}\x{7D01}\x{7D02}\x{7D03}\x{7D04}' . +'\x{7D05}\x{7D06}\x{7D07}\x{7D08}\x{7D09}\x{7D0A}\x{7D0B}\x{7D0C}\x{7D0D}' . +'\x{7D0E}\x{7D0F}\x{7D10}\x{7D11}\x{7D12}\x{7D13}\x{7D14}\x{7D15}\x{7D16}' . +'\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D1D}\x{7D1E}\x{7D1F}' . +'\x{7D20}\x{7D21}\x{7D22}\x{7D24}\x{7D25}\x{7D26}\x{7D27}\x{7D28}\x{7D29}' . +'\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D31}\x{7D32}\x{7D33}\x{7D34}' . +'\x{7D35}\x{7D36}\x{7D37}\x{7D38}\x{7D39}\x{7D3A}\x{7D3B}\x{7D3C}\x{7D3D}' . +'\x{7D3E}\x{7D3F}\x{7D40}\x{7D41}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}' . +'\x{7D47}\x{7D49}\x{7D4A}\x{7D4B}\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D51}' . +'\x{7D52}\x{7D53}\x{7D54}\x{7D55}\x{7D56}\x{7D57}\x{7D58}\x{7D59}\x{7D5B}' . +'\x{7D5C}\x{7D5D}\x{7D5E}\x{7D5F}\x{7D60}\x{7D61}\x{7D62}\x{7D63}\x{7D65}' . +'\x{7D66}\x{7D67}\x{7D68}\x{7D69}\x{7D6A}\x{7D6B}\x{7D6C}\x{7D6D}\x{7D6E}' . +'\x{7D6F}\x{7D70}\x{7D71}\x{7D72}\x{7D73}\x{7D74}\x{7D75}\x{7D76}\x{7D77}' . +'\x{7D79}\x{7D7A}\x{7D7B}\x{7D7C}\x{7D7D}\x{7D7E}\x{7D7F}\x{7D80}\x{7D81}' . +'\x{7D83}\x{7D84}\x{7D85}\x{7D86}\x{7D87}\x{7D88}\x{7D89}\x{7D8A}\x{7D8B}' . +'\x{7D8C}\x{7D8D}\x{7D8E}\x{7D8F}\x{7D90}\x{7D91}\x{7D92}\x{7D93}\x{7D94}' . +'\x{7D96}\x{7D97}\x{7D99}\x{7D9B}\x{7D9C}\x{7D9D}\x{7D9E}\x{7D9F}\x{7DA0}' . +'\x{7DA1}\x{7DA2}\x{7DA3}\x{7DA5}\x{7DA6}\x{7DA7}\x{7DA9}\x{7DAA}\x{7DAB}' . +'\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}\x{7DB1}\x{7DB2}\x{7DB3}\x{7DB4}' . +'\x{7DB5}\x{7DB6}\x{7DB7}\x{7DB8}\x{7DB9}\x{7DBA}\x{7DBB}\x{7DBC}\x{7DBD}' . +'\x{7DBE}\x{7DBF}\x{7DC0}\x{7DC1}\x{7DC2}\x{7DC3}\x{7DC4}\x{7DC5}\x{7DC6}' . +'\x{7DC7}\x{7DC8}\x{7DC9}\x{7DCA}\x{7DCB}\x{7DCC}\x{7DCE}\x{7DCF}\x{7DD0}' . +'\x{7DD1}\x{7DD2}\x{7DD4}\x{7DD5}\x{7DD6}\x{7DD7}\x{7DD8}\x{7DD9}\x{7DDA}' . +'\x{7DDB}\x{7DDD}\x{7DDE}\x{7DDF}\x{7DE0}\x{7DE1}\x{7DE2}\x{7DE3}\x{7DE6}' . +'\x{7DE7}\x{7DE8}\x{7DE9}\x{7DEA}\x{7DEC}\x{7DED}\x{7DEE}\x{7DEF}\x{7DF0}' . +'\x{7DF1}\x{7DF2}\x{7DF3}\x{7DF4}\x{7DF5}\x{7DF6}\x{7DF7}\x{7DF8}\x{7DF9}' . +'\x{7DFA}\x{7DFB}\x{7DFC}\x{7E00}\x{7E01}\x{7E02}\x{7E03}\x{7E04}\x{7E05}' . +'\x{7E06}\x{7E07}\x{7E08}\x{7E09}\x{7E0A}\x{7E0B}\x{7E0C}\x{7E0D}\x{7E0E}' . +'\x{7E0F}\x{7E10}\x{7E11}\x{7E12}\x{7E13}\x{7E14}\x{7E15}\x{7E16}\x{7E17}' . +'\x{7E19}\x{7E1A}\x{7E1B}\x{7E1C}\x{7E1D}\x{7E1E}\x{7E1F}\x{7E20}\x{7E21}' . +'\x{7E22}\x{7E23}\x{7E24}\x{7E25}\x{7E26}\x{7E27}\x{7E28}\x{7E29}\x{7E2A}' . +'\x{7E2B}\x{7E2C}\x{7E2D}\x{7E2E}\x{7E2F}\x{7E30}\x{7E31}\x{7E32}\x{7E33}' . +'\x{7E34}\x{7E35}\x{7E36}\x{7E37}\x{7E38}\x{7E39}\x{7E3A}\x{7E3B}\x{7E3C}' . +'\x{7E3D}\x{7E3E}\x{7E3F}\x{7E40}\x{7E41}\x{7E42}\x{7E43}\x{7E44}\x{7E45}' . +'\x{7E46}\x{7E47}\x{7E48}\x{7E49}\x{7E4C}\x{7E4D}\x{7E4E}\x{7E4F}\x{7E50}' . +'\x{7E51}\x{7E52}\x{7E53}\x{7E54}\x{7E55}\x{7E56}\x{7E57}\x{7E58}\x{7E59}' . +'\x{7E5A}\x{7E5C}\x{7E5D}\x{7E5E}\x{7E5F}\x{7E60}\x{7E61}\x{7E62}\x{7E63}' . +'\x{7E65}\x{7E66}\x{7E67}\x{7E68}\x{7E69}\x{7E6A}\x{7E6B}\x{7E6C}\x{7E6D}' . +'\x{7E6E}\x{7E6F}\x{7E70}\x{7E71}\x{7E72}\x{7E73}\x{7E74}\x{7E75}\x{7E76}' . +'\x{7E77}\x{7E78}\x{7E79}\x{7E7A}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7E}\x{7E7F}' . +'\x{7E80}\x{7E81}\x{7E82}\x{7E83}\x{7E84}\x{7E85}\x{7E86}\x{7E87}\x{7E88}' . +'\x{7E89}\x{7E8A}\x{7E8B}\x{7E8C}\x{7E8D}\x{7E8E}\x{7E8F}\x{7E90}\x{7E91}' . +'\x{7E92}\x{7E93}\x{7E94}\x{7E95}\x{7E96}\x{7E97}\x{7E98}\x{7E99}\x{7E9A}' . +'\x{7E9B}\x{7E9C}\x{7E9E}\x{7E9F}\x{7EA0}\x{7EA1}\x{7EA2}\x{7EA3}\x{7EA4}' . +'\x{7EA5}\x{7EA6}\x{7EA7}\x{7EA8}\x{7EA9}\x{7EAA}\x{7EAB}\x{7EAC}\x{7EAD}' . +'\x{7EAE}\x{7EAF}\x{7EB0}\x{7EB1}\x{7EB2}\x{7EB3}\x{7EB4}\x{7EB5}\x{7EB6}' . +'\x{7EB7}\x{7EB8}\x{7EB9}\x{7EBA}\x{7EBB}\x{7EBC}\x{7EBD}\x{7EBE}\x{7EBF}' . +'\x{7EC0}\x{7EC1}\x{7EC2}\x{7EC3}\x{7EC4}\x{7EC5}\x{7EC6}\x{7EC7}\x{7EC8}' . +'\x{7EC9}\x{7ECA}\x{7ECB}\x{7ECC}\x{7ECD}\x{7ECE}\x{7ECF}\x{7ED0}\x{7ED1}' . +'\x{7ED2}\x{7ED3}\x{7ED4}\x{7ED5}\x{7ED6}\x{7ED7}\x{7ED8}\x{7ED9}\x{7EDA}' . +'\x{7EDB}\x{7EDC}\x{7EDD}\x{7EDE}\x{7EDF}\x{7EE0}\x{7EE1}\x{7EE2}\x{7EE3}' . +'\x{7EE4}\x{7EE5}\x{7EE6}\x{7EE7}\x{7EE8}\x{7EE9}\x{7EEA}\x{7EEB}\x{7EEC}' . +'\x{7EED}\x{7EEE}\x{7EEF}\x{7EF0}\x{7EF1}\x{7EF2}\x{7EF3}\x{7EF4}\x{7EF5}' . +'\x{7EF6}\x{7EF7}\x{7EF8}\x{7EF9}\x{7EFA}\x{7EFB}\x{7EFC}\x{7EFD}\x{7EFE}' . +'\x{7EFF}\x{7F00}\x{7F01}\x{7F02}\x{7F03}\x{7F04}\x{7F05}\x{7F06}\x{7F07}' . +'\x{7F08}\x{7F09}\x{7F0A}\x{7F0B}\x{7F0C}\x{7F0D}\x{7F0E}\x{7F0F}\x{7F10}' . +'\x{7F11}\x{7F12}\x{7F13}\x{7F14}\x{7F15}\x{7F16}\x{7F17}\x{7F18}\x{7F19}' . +'\x{7F1A}\x{7F1B}\x{7F1C}\x{7F1D}\x{7F1E}\x{7F1F}\x{7F20}\x{7F21}\x{7F22}' . +'\x{7F23}\x{7F24}\x{7F25}\x{7F26}\x{7F27}\x{7F28}\x{7F29}\x{7F2A}\x{7F2B}' . +'\x{7F2C}\x{7F2D}\x{7F2E}\x{7F2F}\x{7F30}\x{7F31}\x{7F32}\x{7F33}\x{7F34}' . +'\x{7F35}\x{7F36}\x{7F37}\x{7F38}\x{7F39}\x{7F3A}\x{7F3D}\x{7F3E}\x{7F3F}' . +'\x{7F40}\x{7F42}\x{7F43}\x{7F44}\x{7F45}\x{7F47}\x{7F48}\x{7F49}\x{7F4A}' . +'\x{7F4B}\x{7F4C}\x{7F4D}\x{7F4E}\x{7F4F}\x{7F50}\x{7F51}\x{7F52}\x{7F53}' . +'\x{7F54}\x{7F55}\x{7F56}\x{7F57}\x{7F58}\x{7F5A}\x{7F5B}\x{7F5C}\x{7F5D}' . +'\x{7F5E}\x{7F5F}\x{7F60}\x{7F61}\x{7F62}\x{7F63}\x{7F64}\x{7F65}\x{7F66}' . +'\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6C}\x{7F6D}\x{7F6E}\x{7F6F}' . +'\x{7F70}\x{7F71}\x{7F72}\x{7F73}\x{7F74}\x{7F75}\x{7F76}\x{7F77}\x{7F78}' . +'\x{7F79}\x{7F7A}\x{7F7B}\x{7F7C}\x{7F7D}\x{7F7E}\x{7F7F}\x{7F80}\x{7F81}' . +'\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}\x{7F88}\x{7F89}\x{7F8A}\x{7F8B}' . +'\x{7F8C}\x{7F8D}\x{7F8E}\x{7F8F}\x{7F91}\x{7F92}\x{7F93}\x{7F94}\x{7F95}' . +'\x{7F96}\x{7F98}\x{7F9A}\x{7F9B}\x{7F9C}\x{7F9D}\x{7F9E}\x{7F9F}\x{7FA0}' . +'\x{7FA1}\x{7FA2}\x{7FA3}\x{7FA4}\x{7FA5}\x{7FA6}\x{7FA7}\x{7FA8}\x{7FA9}' . +'\x{7FAA}\x{7FAB}\x{7FAC}\x{7FAD}\x{7FAE}\x{7FAF}\x{7FB0}\x{7FB1}\x{7FB2}' . +'\x{7FB3}\x{7FB5}\x{7FB6}\x{7FB7}\x{7FB8}\x{7FB9}\x{7FBA}\x{7FBB}\x{7FBC}' . +'\x{7FBD}\x{7FBE}\x{7FBF}\x{7FC0}\x{7FC1}\x{7FC2}\x{7FC3}\x{7FC4}\x{7FC5}' . +'\x{7FC6}\x{7FC7}\x{7FC8}\x{7FC9}\x{7FCA}\x{7FCB}\x{7FCC}\x{7FCD}\x{7FCE}' . +'\x{7FCF}\x{7FD0}\x{7FD1}\x{7FD2}\x{7FD3}\x{7FD4}\x{7FD5}\x{7FD7}\x{7FD8}' . +'\x{7FD9}\x{7FDA}\x{7FDB}\x{7FDC}\x{7FDE}\x{7FDF}\x{7FE0}\x{7FE1}\x{7FE2}' . +'\x{7FE3}\x{7FE5}\x{7FE6}\x{7FE7}\x{7FE8}\x{7FE9}\x{7FEA}\x{7FEB}\x{7FEC}' . +'\x{7FED}\x{7FEE}\x{7FEF}\x{7FF0}\x{7FF1}\x{7FF2}\x{7FF3}\x{7FF4}\x{7FF5}' . +'\x{7FF6}\x{7FF7}\x{7FF8}\x{7FF9}\x{7FFA}\x{7FFB}\x{7FFC}\x{7FFD}\x{7FFE}' . +'\x{7FFF}\x{8000}\x{8001}\x{8002}\x{8003}\x{8004}\x{8005}\x{8006}\x{8007}' . +'\x{8008}\x{8009}\x{800B}\x{800C}\x{800D}\x{800E}\x{800F}\x{8010}\x{8011}' . +'\x{8012}\x{8013}\x{8014}\x{8015}\x{8016}\x{8017}\x{8018}\x{8019}\x{801A}' . +'\x{801B}\x{801C}\x{801D}\x{801E}\x{801F}\x{8020}\x{8021}\x{8022}\x{8023}' . +'\x{8024}\x{8025}\x{8026}\x{8027}\x{8028}\x{8029}\x{802A}\x{802B}\x{802C}' . +'\x{802D}\x{802E}\x{8030}\x{8031}\x{8032}\x{8033}\x{8034}\x{8035}\x{8036}' . +'\x{8037}\x{8038}\x{8039}\x{803A}\x{803B}\x{803D}\x{803E}\x{803F}\x{8041}' . +'\x{8042}\x{8043}\x{8044}\x{8045}\x{8046}\x{8047}\x{8048}\x{8049}\x{804A}' . +'\x{804B}\x{804C}\x{804D}\x{804E}\x{804F}\x{8050}\x{8051}\x{8052}\x{8053}' . +'\x{8054}\x{8055}\x{8056}\x{8057}\x{8058}\x{8059}\x{805A}\x{805B}\x{805C}' . +'\x{805D}\x{805E}\x{805F}\x{8060}\x{8061}\x{8062}\x{8063}\x{8064}\x{8065}' . +'\x{8067}\x{8068}\x{8069}\x{806A}\x{806B}\x{806C}\x{806D}\x{806E}\x{806F}' . +'\x{8070}\x{8071}\x{8072}\x{8073}\x{8074}\x{8075}\x{8076}\x{8077}\x{8078}' . +'\x{8079}\x{807A}\x{807B}\x{807C}\x{807D}\x{807E}\x{807F}\x{8080}\x{8081}' . +'\x{8082}\x{8083}\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808A}\x{808B}' . +'\x{808C}\x{808D}\x{808F}\x{8090}\x{8091}\x{8092}\x{8093}\x{8095}\x{8096}' . +'\x{8097}\x{8098}\x{8099}\x{809A}\x{809B}\x{809C}\x{809D}\x{809E}\x{809F}' . +'\x{80A0}\x{80A1}\x{80A2}\x{80A3}\x{80A4}\x{80A5}\x{80A9}\x{80AA}\x{80AB}' . +'\x{80AD}\x{80AE}\x{80AF}\x{80B0}\x{80B1}\x{80B2}\x{80B4}\x{80B5}\x{80B6}' . +'\x{80B7}\x{80B8}\x{80BA}\x{80BB}\x{80BC}\x{80BD}\x{80BE}\x{80BF}\x{80C0}' . +'\x{80C1}\x{80C2}\x{80C3}\x{80C4}\x{80C5}\x{80C6}\x{80C7}\x{80C8}\x{80C9}' . +'\x{80CA}\x{80CB}\x{80CC}\x{80CD}\x{80CE}\x{80CF}\x{80D0}\x{80D1}\x{80D2}' . +'\x{80D3}\x{80D4}\x{80D5}\x{80D6}\x{80D7}\x{80D8}\x{80D9}\x{80DA}\x{80DB}' . +'\x{80DC}\x{80DD}\x{80DE}\x{80E0}\x{80E1}\x{80E2}\x{80E3}\x{80E4}\x{80E5}' . +'\x{80E6}\x{80E7}\x{80E8}\x{80E9}\x{80EA}\x{80EB}\x{80EC}\x{80ED}\x{80EE}' . +'\x{80EF}\x{80F0}\x{80F1}\x{80F2}\x{80F3}\x{80F4}\x{80F5}\x{80F6}\x{80F7}' . +'\x{80F8}\x{80F9}\x{80FA}\x{80FB}\x{80FC}\x{80FD}\x{80FE}\x{80FF}\x{8100}' . +'\x{8101}\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{810B}' . +'\x{810C}\x{810D}\x{810E}\x{810F}\x{8110}\x{8111}\x{8112}\x{8113}\x{8114}' . +'\x{8115}\x{8116}\x{8118}\x{8119}\x{811A}\x{811B}\x{811C}\x{811D}\x{811E}' . +'\x{811F}\x{8120}\x{8121}\x{8122}\x{8123}\x{8124}\x{8125}\x{8126}\x{8127}' . +'\x{8128}\x{8129}\x{812A}\x{812B}\x{812C}\x{812D}\x{812E}\x{812F}\x{8130}' . +'\x{8131}\x{8132}\x{8136}\x{8137}\x{8138}\x{8139}\x{813A}\x{813B}\x{813C}' . +'\x{813D}\x{813E}\x{813F}\x{8140}\x{8141}\x{8142}\x{8143}\x{8144}\x{8145}' . +'\x{8146}\x{8147}\x{8148}\x{8149}\x{814A}\x{814B}\x{814C}\x{814D}\x{814E}' . +'\x{814F}\x{8150}\x{8151}\x{8152}\x{8153}\x{8154}\x{8155}\x{8156}\x{8157}' . +'\x{8158}\x{8159}\x{815A}\x{815B}\x{815C}\x{815D}\x{815E}\x{8160}\x{8161}' . +'\x{8162}\x{8163}\x{8164}\x{8165}\x{8166}\x{8167}\x{8168}\x{8169}\x{816A}' . +'\x{816B}\x{816C}\x{816D}\x{816E}\x{816F}\x{8170}\x{8171}\x{8172}\x{8173}' . +'\x{8174}\x{8175}\x{8176}\x{8177}\x{8178}\x{8179}\x{817A}\x{817B}\x{817C}' . +'\x{817D}\x{817E}\x{817F}\x{8180}\x{8181}\x{8182}\x{8183}\x{8185}\x{8186}' . +'\x{8187}\x{8188}\x{8189}\x{818A}\x{818B}\x{818C}\x{818D}\x{818E}\x{818F}' . +'\x{8191}\x{8192}\x{8193}\x{8194}\x{8195}\x{8197}\x{8198}\x{8199}\x{819A}' . +'\x{819B}\x{819C}\x{819D}\x{819E}\x{819F}\x{81A0}\x{81A1}\x{81A2}\x{81A3}' . +'\x{81A4}\x{81A5}\x{81A6}\x{81A7}\x{81A8}\x{81A9}\x{81AA}\x{81AB}\x{81AC}' . +'\x{81AD}\x{81AE}\x{81AF}\x{81B0}\x{81B1}\x{81B2}\x{81B3}\x{81B4}\x{81B5}' . +'\x{81B6}\x{81B7}\x{81B8}\x{81B9}\x{81BA}\x{81BB}\x{81BC}\x{81BD}\x{81BE}' . +'\x{81BF}\x{81C0}\x{81C1}\x{81C2}\x{81C3}\x{81C4}\x{81C5}\x{81C6}\x{81C7}' . +'\x{81C8}\x{81C9}\x{81CA}\x{81CC}\x{81CD}\x{81CE}\x{81CF}\x{81D0}\x{81D1}' . +'\x{81D2}\x{81D4}\x{81D5}\x{81D6}\x{81D7}\x{81D8}\x{81D9}\x{81DA}\x{81DB}' . +'\x{81DC}\x{81DD}\x{81DE}\x{81DF}\x{81E0}\x{81E1}\x{81E2}\x{81E3}\x{81E5}' . +'\x{81E6}\x{81E7}\x{81E8}\x{81E9}\x{81EA}\x{81EB}\x{81EC}\x{81ED}\x{81EE}' . +'\x{81F1}\x{81F2}\x{81F3}\x{81F4}\x{81F5}\x{81F6}\x{81F7}\x{81F8}\x{81F9}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FD}\x{81FE}\x{81FF}\x{8200}\x{8201}\x{8202}' . +'\x{8203}\x{8204}\x{8205}\x{8206}\x{8207}\x{8208}\x{8209}\x{820A}\x{820B}' . +'\x{820C}\x{820D}\x{820E}\x{820F}\x{8210}\x{8211}\x{8212}\x{8214}\x{8215}' . +'\x{8216}\x{8218}\x{8219}\x{821A}\x{821B}\x{821C}\x{821D}\x{821E}\x{821F}' . +'\x{8220}\x{8221}\x{8222}\x{8223}\x{8225}\x{8226}\x{8227}\x{8228}\x{8229}' . +'\x{822A}\x{822B}\x{822C}\x{822D}\x{822F}\x{8230}\x{8231}\x{8232}\x{8233}' . +'\x{8234}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{823A}\x{823B}\x{823C}' . +'\x{823D}\x{823E}\x{823F}\x{8240}\x{8242}\x{8243}\x{8244}\x{8245}\x{8246}' . +'\x{8247}\x{8248}\x{8249}\x{824A}\x{824B}\x{824C}\x{824D}\x{824E}\x{824F}' . +'\x{8250}\x{8251}\x{8252}\x{8253}\x{8254}\x{8255}\x{8256}\x{8257}\x{8258}' . +'\x{8259}\x{825A}\x{825B}\x{825C}\x{825D}\x{825E}\x{825F}\x{8260}\x{8261}' . +'\x{8263}\x{8264}\x{8266}\x{8267}\x{8268}\x{8269}\x{826A}\x{826B}\x{826C}' . +'\x{826D}\x{826E}\x{826F}\x{8270}\x{8271}\x{8272}\x{8273}\x{8274}\x{8275}' . +'\x{8276}\x{8277}\x{8278}\x{8279}\x{827A}\x{827B}\x{827C}\x{827D}\x{827E}' . +'\x{827F}\x{8280}\x{8281}\x{8282}\x{8283}\x{8284}\x{8285}\x{8286}\x{8287}' . +'\x{8288}\x{8289}\x{828A}\x{828B}\x{828D}\x{828E}\x{828F}\x{8290}\x{8291}' . +'\x{8292}\x{8293}\x{8294}\x{8295}\x{8296}\x{8297}\x{8298}\x{8299}\x{829A}' . +'\x{829B}\x{829C}\x{829D}\x{829E}\x{829F}\x{82A0}\x{82A1}\x{82A2}\x{82A3}' . +'\x{82A4}\x{82A5}\x{82A6}\x{82A7}\x{82A8}\x{82A9}\x{82AA}\x{82AB}\x{82AC}' . +'\x{82AD}\x{82AE}\x{82AF}\x{82B0}\x{82B1}\x{82B3}\x{82B4}\x{82B5}\x{82B6}' . +'\x{82B7}\x{82B8}\x{82B9}\x{82BA}\x{82BB}\x{82BC}\x{82BD}\x{82BE}\x{82BF}' . +'\x{82C0}\x{82C1}\x{82C2}\x{82C3}\x{82C4}\x{82C5}\x{82C6}\x{82C7}\x{82C8}' . +'\x{82C9}\x{82CA}\x{82CB}\x{82CC}\x{82CD}\x{82CE}\x{82CF}\x{82D0}\x{82D1}' . +'\x{82D2}\x{82D3}\x{82D4}\x{82D5}\x{82D6}\x{82D7}\x{82D8}\x{82D9}\x{82DA}' . +'\x{82DB}\x{82DC}\x{82DD}\x{82DE}\x{82DF}\x{82E0}\x{82E1}\x{82E3}\x{82E4}' . +'\x{82E5}\x{82E6}\x{82E7}\x{82E8}\x{82E9}\x{82EA}\x{82EB}\x{82EC}\x{82ED}' . +'\x{82EE}\x{82EF}\x{82F0}\x{82F1}\x{82F2}\x{82F3}\x{82F4}\x{82F5}\x{82F6}' . +'\x{82F7}\x{82F8}\x{82F9}\x{82FA}\x{82FB}\x{82FD}\x{82FE}\x{82FF}\x{8300}' . +'\x{8301}\x{8302}\x{8303}\x{8304}\x{8305}\x{8306}\x{8307}\x{8308}\x{8309}' . +'\x{830B}\x{830C}\x{830D}\x{830E}\x{830F}\x{8311}\x{8312}\x{8313}\x{8314}' . +'\x{8315}\x{8316}\x{8317}\x{8318}\x{8319}\x{831A}\x{831B}\x{831C}\x{831D}' . +'\x{831E}\x{831F}\x{8320}\x{8321}\x{8322}\x{8323}\x{8324}\x{8325}\x{8326}' . +'\x{8327}\x{8328}\x{8329}\x{832A}\x{832B}\x{832C}\x{832D}\x{832E}\x{832F}' . +'\x{8331}\x{8332}\x{8333}\x{8334}\x{8335}\x{8336}\x{8337}\x{8338}\x{8339}' . +'\x{833A}\x{833B}\x{833C}\x{833D}\x{833E}\x{833F}\x{8340}\x{8341}\x{8342}' . +'\x{8343}\x{8344}\x{8345}\x{8346}\x{8347}\x{8348}\x{8349}\x{834A}\x{834B}' . +'\x{834C}\x{834D}\x{834E}\x{834F}\x{8350}\x{8351}\x{8352}\x{8353}\x{8354}' . +'\x{8356}\x{8357}\x{8358}\x{8359}\x{835A}\x{835B}\x{835C}\x{835D}\x{835E}' . +'\x{835F}\x{8360}\x{8361}\x{8362}\x{8363}\x{8364}\x{8365}\x{8366}\x{8367}' . +'\x{8368}\x{8369}\x{836A}\x{836B}\x{836C}\x{836D}\x{836E}\x{836F}\x{8370}' . +'\x{8371}\x{8372}\x{8373}\x{8374}\x{8375}\x{8376}\x{8377}\x{8378}\x{8379}' . +'\x{837A}\x{837B}\x{837C}\x{837D}\x{837E}\x{837F}\x{8380}\x{8381}\x{8382}' . +'\x{8383}\x{8384}\x{8385}\x{8386}\x{8387}\x{8388}\x{8389}\x{838A}\x{838B}' . +'\x{838C}\x{838D}\x{838E}\x{838F}\x{8390}\x{8391}\x{8392}\x{8393}\x{8394}' . +'\x{8395}\x{8396}\x{8397}\x{8398}\x{8399}\x{839A}\x{839B}\x{839C}\x{839D}' . +'\x{839E}\x{83A0}\x{83A1}\x{83A2}\x{83A3}\x{83A4}\x{83A5}\x{83A6}\x{83A7}' . +'\x{83A8}\x{83A9}\x{83AA}\x{83AB}\x{83AC}\x{83AD}\x{83AE}\x{83AF}\x{83B0}' . +'\x{83B1}\x{83B2}\x{83B3}\x{83B4}\x{83B6}\x{83B7}\x{83B8}\x{83B9}\x{83BA}' . +'\x{83BB}\x{83BC}\x{83BD}\x{83BF}\x{83C0}\x{83C1}\x{83C2}\x{83C3}\x{83C4}' . +'\x{83C5}\x{83C6}\x{83C7}\x{83C8}\x{83C9}\x{83CA}\x{83CB}\x{83CC}\x{83CD}' . +'\x{83CE}\x{83CF}\x{83D0}\x{83D1}\x{83D2}\x{83D3}\x{83D4}\x{83D5}\x{83D6}' . +'\x{83D7}\x{83D8}\x{83D9}\x{83DA}\x{83DB}\x{83DC}\x{83DD}\x{83DE}\x{83DF}' . +'\x{83E0}\x{83E1}\x{83E2}\x{83E3}\x{83E4}\x{83E5}\x{83E7}\x{83E8}\x{83E9}' . +'\x{83EA}\x{83EB}\x{83EC}\x{83EE}\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F3}' . +'\x{83F4}\x{83F5}\x{83F6}\x{83F7}\x{83F8}\x{83F9}\x{83FA}\x{83FB}\x{83FC}' . +'\x{83FD}\x{83FE}\x{83FF}\x{8400}\x{8401}\x{8402}\x{8403}\x{8404}\x{8405}' . +'\x{8406}\x{8407}\x{8408}\x{8409}\x{840A}\x{840B}\x{840C}\x{840D}\x{840E}' . +'\x{840F}\x{8410}\x{8411}\x{8412}\x{8413}\x{8415}\x{8418}\x{8419}\x{841A}' . +'\x{841B}\x{841C}\x{841D}\x{841E}\x{8421}\x{8422}\x{8423}\x{8424}\x{8425}' . +'\x{8426}\x{8427}\x{8428}\x{8429}\x{842A}\x{842B}\x{842C}\x{842D}\x{842E}' . +'\x{842F}\x{8430}\x{8431}\x{8432}\x{8433}\x{8434}\x{8435}\x{8436}\x{8437}' . +'\x{8438}\x{8439}\x{843A}\x{843B}\x{843C}\x{843D}\x{843E}\x{843F}\x{8440}' . +'\x{8441}\x{8442}\x{8443}\x{8444}\x{8445}\x{8446}\x{8447}\x{8448}\x{8449}' . +'\x{844A}\x{844B}\x{844C}\x{844D}\x{844E}\x{844F}\x{8450}\x{8451}\x{8452}' . +'\x{8453}\x{8454}\x{8455}\x{8456}\x{8457}\x{8459}\x{845A}\x{845B}\x{845C}' . +'\x{845D}\x{845E}\x{845F}\x{8460}\x{8461}\x{8462}\x{8463}\x{8464}\x{8465}' . +'\x{8466}\x{8467}\x{8468}\x{8469}\x{846A}\x{846B}\x{846C}\x{846D}\x{846E}' . +'\x{846F}\x{8470}\x{8471}\x{8472}\x{8473}\x{8474}\x{8475}\x{8476}\x{8477}' . +'\x{8478}\x{8479}\x{847A}\x{847B}\x{847C}\x{847D}\x{847E}\x{847F}\x{8480}' . +'\x{8481}\x{8482}\x{8484}\x{8485}\x{8486}\x{8487}\x{8488}\x{8489}\x{848A}' . +'\x{848B}\x{848C}\x{848D}\x{848E}\x{848F}\x{8490}\x{8491}\x{8492}\x{8493}' . +'\x{8494}\x{8496}\x{8497}\x{8498}\x{8499}\x{849A}\x{849B}\x{849C}\x{849D}' . +'\x{849E}\x{849F}\x{84A0}\x{84A1}\x{84A2}\x{84A3}\x{84A4}\x{84A5}\x{84A6}' . +'\x{84A7}\x{84A8}\x{84A9}\x{84AA}\x{84AB}\x{84AC}\x{84AE}\x{84AF}\x{84B0}' . +'\x{84B1}\x{84B2}\x{84B3}\x{84B4}\x{84B5}\x{84B6}\x{84B8}\x{84B9}\x{84BA}' . +'\x{84BB}\x{84BC}\x{84BD}\x{84BE}\x{84BF}\x{84C0}\x{84C1}\x{84C2}\x{84C4}' . +'\x{84C5}\x{84C6}\x{84C7}\x{84C8}\x{84C9}\x{84CA}\x{84CB}\x{84CC}\x{84CD}' . +'\x{84CE}\x{84CF}\x{84D0}\x{84D1}\x{84D2}\x{84D3}\x{84D4}\x{84D5}\x{84D6}' . +'\x{84D7}\x{84D8}\x{84D9}\x{84DB}\x{84DC}\x{84DD}\x{84DE}\x{84DF}\x{84E0}' . +'\x{84E1}\x{84E2}\x{84E3}\x{84E4}\x{84E5}\x{84E6}\x{84E7}\x{84E8}\x{84E9}' . +'\x{84EA}\x{84EB}\x{84EC}\x{84EE}\x{84EF}\x{84F0}\x{84F1}\x{84F2}\x{84F3}' . +'\x{84F4}\x{84F5}\x{84F6}\x{84F7}\x{84F8}\x{84F9}\x{84FA}\x{84FB}\x{84FC}' . +'\x{84FD}\x{84FE}\x{84FF}\x{8500}\x{8501}\x{8502}\x{8503}\x{8504}\x{8506}' . +'\x{8507}\x{8508}\x{8509}\x{850A}\x{850B}\x{850C}\x{850D}\x{850E}\x{850F}' . +'\x{8511}\x{8512}\x{8513}\x{8514}\x{8515}\x{8516}\x{8517}\x{8518}\x{8519}' . +'\x{851A}\x{851B}\x{851C}\x{851D}\x{851E}\x{851F}\x{8520}\x{8521}\x{8522}' . +'\x{8523}\x{8524}\x{8525}\x{8526}\x{8527}\x{8528}\x{8529}\x{852A}\x{852B}' . +'\x{852C}\x{852D}\x{852E}\x{852F}\x{8530}\x{8531}\x{8534}\x{8535}\x{8536}' . +'\x{8537}\x{8538}\x{8539}\x{853A}\x{853B}\x{853C}\x{853D}\x{853E}\x{853F}' . +'\x{8540}\x{8541}\x{8542}\x{8543}\x{8544}\x{8545}\x{8546}\x{8547}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854D}\x{854E}\x{854F}\x{8551}\x{8552}\x{8553}' . +'\x{8554}\x{8555}\x{8556}\x{8557}\x{8558}\x{8559}\x{855A}\x{855B}\x{855C}' . +'\x{855D}\x{855E}\x{855F}\x{8560}\x{8561}\x{8562}\x{8563}\x{8564}\x{8565}' . +'\x{8566}\x{8567}\x{8568}\x{8569}\x{856A}\x{856B}\x{856C}\x{856D}\x{856E}' . +'\x{856F}\x{8570}\x{8571}\x{8572}\x{8573}\x{8574}\x{8575}\x{8576}\x{8577}' . +'\x{8578}\x{8579}\x{857A}\x{857B}\x{857C}\x{857D}\x{857E}\x{8580}\x{8581}' . +'\x{8582}\x{8583}\x{8584}\x{8585}\x{8586}\x{8587}\x{8588}\x{8589}\x{858A}' . +'\x{858B}\x{858C}\x{858D}\x{858E}\x{858F}\x{8590}\x{8591}\x{8592}\x{8594}' . +'\x{8595}\x{8596}\x{8598}\x{8599}\x{859A}\x{859B}\x{859C}\x{859D}\x{859E}' . +'\x{859F}\x{85A0}\x{85A1}\x{85A2}\x{85A3}\x{85A4}\x{85A5}\x{85A6}\x{85A7}' . +'\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AD}\x{85AE}\x{85AF}\x{85B0}' . +'\x{85B1}\x{85B3}\x{85B4}\x{85B5}\x{85B6}\x{85B7}\x{85B8}\x{85B9}\x{85BA}' . +'\x{85BC}\x{85BD}\x{85BE}\x{85BF}\x{85C0}\x{85C1}\x{85C2}\x{85C3}\x{85C4}' . +'\x{85C5}\x{85C6}\x{85C7}\x{85C8}\x{85C9}\x{85CA}\x{85CB}\x{85CD}\x{85CE}' . +'\x{85CF}\x{85D0}\x{85D1}\x{85D2}\x{85D3}\x{85D4}\x{85D5}\x{85D6}\x{85D7}' . +'\x{85D8}\x{85D9}\x{85DA}\x{85DB}\x{85DC}\x{85DD}\x{85DE}\x{85DF}\x{85E0}' . +'\x{85E1}\x{85E2}\x{85E3}\x{85E4}\x{85E5}\x{85E6}\x{85E7}\x{85E8}\x{85E9}' . +'\x{85EA}\x{85EB}\x{85EC}\x{85ED}\x{85EF}\x{85F0}\x{85F1}\x{85F2}\x{85F4}' . +'\x{85F5}\x{85F6}\x{85F7}\x{85F8}\x{85F9}\x{85FA}\x{85FB}\x{85FD}\x{85FE}' . +'\x{85FF}\x{8600}\x{8601}\x{8602}\x{8604}\x{8605}\x{8606}\x{8607}\x{8608}' . +'\x{8609}\x{860A}\x{860B}\x{860C}\x{860F}\x{8611}\x{8612}\x{8613}\x{8614}' . +'\x{8616}\x{8617}\x{8618}\x{8619}\x{861A}\x{861B}\x{861C}\x{861E}\x{861F}' . +'\x{8620}\x{8621}\x{8622}\x{8623}\x{8624}\x{8625}\x{8626}\x{8627}\x{8628}' . +'\x{8629}\x{862A}\x{862B}\x{862C}\x{862D}\x{862E}\x{862F}\x{8630}\x{8631}' . +'\x{8632}\x{8633}\x{8634}\x{8635}\x{8636}\x{8638}\x{8639}\x{863A}\x{863B}' . +'\x{863C}\x{863D}\x{863E}\x{863F}\x{8640}\x{8641}\x{8642}\x{8643}\x{8644}' . +'\x{8645}\x{8646}\x{8647}\x{8648}\x{8649}\x{864A}\x{864B}\x{864C}\x{864D}' . +'\x{864E}\x{864F}\x{8650}\x{8651}\x{8652}\x{8653}\x{8654}\x{8655}\x{8656}' . +'\x{8658}\x{8659}\x{865A}\x{865B}\x{865C}\x{865D}\x{865E}\x{865F}\x{8660}' . +'\x{8661}\x{8662}\x{8663}\x{8664}\x{8665}\x{8666}\x{8667}\x{8668}\x{8669}' . +'\x{866A}\x{866B}\x{866C}\x{866D}\x{866E}\x{866F}\x{8670}\x{8671}\x{8672}' . +'\x{8673}\x{8674}\x{8676}\x{8677}\x{8678}\x{8679}\x{867A}\x{867B}\x{867C}' . +'\x{867D}\x{867E}\x{867F}\x{8680}\x{8681}\x{8682}\x{8683}\x{8684}\x{8685}' . +'\x{8686}\x{8687}\x{8688}\x{868A}\x{868B}\x{868C}\x{868D}\x{868E}\x{868F}' . +'\x{8690}\x{8691}\x{8693}\x{8694}\x{8695}\x{8696}\x{8697}\x{8698}\x{8699}' . +'\x{869A}\x{869B}\x{869C}\x{869D}\x{869E}\x{869F}\x{86A1}\x{86A2}\x{86A3}' . +'\x{86A4}\x{86A5}\x{86A7}\x{86A8}\x{86A9}\x{86AA}\x{86AB}\x{86AC}\x{86AD}' . +'\x{86AE}\x{86AF}\x{86B0}\x{86B1}\x{86B2}\x{86B3}\x{86B4}\x{86B5}\x{86B6}' . +'\x{86B7}\x{86B8}\x{86B9}\x{86BA}\x{86BB}\x{86BC}\x{86BD}\x{86BE}\x{86BF}' . +'\x{86C0}\x{86C1}\x{86C2}\x{86C3}\x{86C4}\x{86C5}\x{86C6}\x{86C7}\x{86C8}' . +'\x{86C9}\x{86CA}\x{86CB}\x{86CC}\x{86CE}\x{86CF}\x{86D0}\x{86D1}\x{86D2}' . +'\x{86D3}\x{86D4}\x{86D6}\x{86D7}\x{86D8}\x{86D9}\x{86DA}\x{86DB}\x{86DC}' . +'\x{86DD}\x{86DE}\x{86DF}\x{86E1}\x{86E2}\x{86E3}\x{86E4}\x{86E5}\x{86E6}' . +'\x{86E8}\x{86E9}\x{86EA}\x{86EB}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F0}' . +'\x{86F1}\x{86F2}\x{86F3}\x{86F4}\x{86F5}\x{86F6}\x{86F7}\x{86F8}\x{86F9}' . +'\x{86FA}\x{86FB}\x{86FC}\x{86FE}\x{86FF}\x{8700}\x{8701}\x{8702}\x{8703}' . +'\x{8704}\x{8705}\x{8706}\x{8707}\x{8708}\x{8709}\x{870A}\x{870B}\x{870C}' . +'\x{870D}\x{870E}\x{870F}\x{8710}\x{8711}\x{8712}\x{8713}\x{8714}\x{8715}' . +'\x{8716}\x{8717}\x{8718}\x{8719}\x{871A}\x{871B}\x{871C}\x{871E}\x{871F}' . +'\x{8720}\x{8721}\x{8722}\x{8723}\x{8724}\x{8725}\x{8726}\x{8727}\x{8728}' . +'\x{8729}\x{872A}\x{872B}\x{872C}\x{872D}\x{872E}\x{8730}\x{8731}\x{8732}' . +'\x{8733}\x{8734}\x{8735}\x{8736}\x{8737}\x{8738}\x{8739}\x{873A}\x{873B}' . +'\x{873C}\x{873E}\x{873F}\x{8740}\x{8741}\x{8742}\x{8743}\x{8744}\x{8746}' . +'\x{8747}\x{8748}\x{8749}\x{874A}\x{874C}\x{874D}\x{874E}\x{874F}\x{8750}' . +'\x{8751}\x{8752}\x{8753}\x{8754}\x{8755}\x{8756}\x{8757}\x{8758}\x{8759}' . +'\x{875A}\x{875B}\x{875C}\x{875D}\x{875E}\x{875F}\x{8760}\x{8761}\x{8762}' . +'\x{8763}\x{8764}\x{8765}\x{8766}\x{8767}\x{8768}\x{8769}\x{876A}\x{876B}' . +'\x{876C}\x{876D}\x{876E}\x{876F}\x{8770}\x{8772}\x{8773}\x{8774}\x{8775}' . +'\x{8776}\x{8777}\x{8778}\x{8779}\x{877A}\x{877B}\x{877C}\x{877D}\x{877E}' . +'\x{8780}\x{8781}\x{8782}\x{8783}\x{8784}\x{8785}\x{8786}\x{8787}\x{8788}' . +'\x{8789}\x{878A}\x{878B}\x{878C}\x{878D}\x{878F}\x{8790}\x{8791}\x{8792}' . +'\x{8793}\x{8794}\x{8795}\x{8796}\x{8797}\x{8798}\x{879A}\x{879B}\x{879C}' . +'\x{879D}\x{879E}\x{879F}\x{87A0}\x{87A1}\x{87A2}\x{87A3}\x{87A4}\x{87A5}' . +'\x{87A6}\x{87A7}\x{87A8}\x{87A9}\x{87AA}\x{87AB}\x{87AC}\x{87AD}\x{87AE}' . +'\x{87AF}\x{87B0}\x{87B1}\x{87B2}\x{87B3}\x{87B4}\x{87B5}\x{87B6}\x{87B7}' . +'\x{87B8}\x{87B9}\x{87BA}\x{87BB}\x{87BC}\x{87BD}\x{87BE}\x{87BF}\x{87C0}' . +'\x{87C1}\x{87C2}\x{87C3}\x{87C4}\x{87C5}\x{87C6}\x{87C7}\x{87C8}\x{87C9}' . +'\x{87CA}\x{87CB}\x{87CC}\x{87CD}\x{87CE}\x{87CF}\x{87D0}\x{87D1}\x{87D2}' . +'\x{87D3}\x{87D4}\x{87D5}\x{87D6}\x{87D7}\x{87D8}\x{87D9}\x{87DB}\x{87DC}' . +'\x{87DD}\x{87DE}\x{87DF}\x{87E0}\x{87E1}\x{87E2}\x{87E3}\x{87E4}\x{87E5}' . +'\x{87E6}\x{87E7}\x{87E8}\x{87E9}\x{87EA}\x{87EB}\x{87EC}\x{87ED}\x{87EE}' . +'\x{87EF}\x{87F1}\x{87F2}\x{87F3}\x{87F4}\x{87F5}\x{87F6}\x{87F7}\x{87F8}' . +'\x{87F9}\x{87FA}\x{87FB}\x{87FC}\x{87FD}\x{87FE}\x{87FF}\x{8800}\x{8801}' . +'\x{8802}\x{8803}\x{8804}\x{8805}\x{8806}\x{8808}\x{8809}\x{880A}\x{880B}' . +'\x{880C}\x{880D}\x{880E}\x{880F}\x{8810}\x{8811}\x{8813}\x{8814}\x{8815}' . +'\x{8816}\x{8817}\x{8818}\x{8819}\x{881A}\x{881B}\x{881C}\x{881D}\x{881E}' . +'\x{881F}\x{8820}\x{8821}\x{8822}\x{8823}\x{8824}\x{8825}\x{8826}\x{8827}' . +'\x{8828}\x{8829}\x{882A}\x{882B}\x{882C}\x{882E}\x{882F}\x{8830}\x{8831}' . +'\x{8832}\x{8833}\x{8834}\x{8835}\x{8836}\x{8837}\x{8838}\x{8839}\x{883B}' . +'\x{883C}\x{883D}\x{883E}\x{883F}\x{8840}\x{8841}\x{8842}\x{8843}\x{8844}' . +'\x{8845}\x{8846}\x{8848}\x{8849}\x{884A}\x{884B}\x{884C}\x{884D}\x{884E}' . +'\x{884F}\x{8850}\x{8851}\x{8852}\x{8853}\x{8854}\x{8855}\x{8856}\x{8857}' . +'\x{8859}\x{885A}\x{885B}\x{885D}\x{885E}\x{8860}\x{8861}\x{8862}\x{8863}' . +'\x{8864}\x{8865}\x{8866}\x{8867}\x{8868}\x{8869}\x{886A}\x{886B}\x{886C}' . +'\x{886D}\x{886E}\x{886F}\x{8870}\x{8871}\x{8872}\x{8873}\x{8874}\x{8875}' . +'\x{8876}\x{8877}\x{8878}\x{8879}\x{887B}\x{887C}\x{887D}\x{887E}\x{887F}' . +'\x{8880}\x{8881}\x{8882}\x{8883}\x{8884}\x{8885}\x{8886}\x{8887}\x{8888}' . +'\x{8889}\x{888A}\x{888B}\x{888C}\x{888D}\x{888E}\x{888F}\x{8890}\x{8891}' . +'\x{8892}\x{8893}\x{8894}\x{8895}\x{8896}\x{8897}\x{8898}\x{8899}\x{889A}' . +'\x{889B}\x{889C}\x{889D}\x{889E}\x{889F}\x{88A0}\x{88A1}\x{88A2}\x{88A3}' . +'\x{88A4}\x{88A5}\x{88A6}\x{88A7}\x{88A8}\x{88A9}\x{88AA}\x{88AB}\x{88AC}' . +'\x{88AD}\x{88AE}\x{88AF}\x{88B0}\x{88B1}\x{88B2}\x{88B3}\x{88B4}\x{88B6}' . +'\x{88B7}\x{88B8}\x{88B9}\x{88BA}\x{88BB}\x{88BC}\x{88BD}\x{88BE}\x{88BF}' . +'\x{88C0}\x{88C1}\x{88C2}\x{88C3}\x{88C4}\x{88C5}\x{88C6}\x{88C7}\x{88C8}' . +'\x{88C9}\x{88CA}\x{88CB}\x{88CC}\x{88CD}\x{88CE}\x{88CF}\x{88D0}\x{88D1}' . +'\x{88D2}\x{88D3}\x{88D4}\x{88D5}\x{88D6}\x{88D7}\x{88D8}\x{88D9}\x{88DA}' . +'\x{88DB}\x{88DC}\x{88DD}\x{88DE}\x{88DF}\x{88E0}\x{88E1}\x{88E2}\x{88E3}' . +'\x{88E4}\x{88E5}\x{88E7}\x{88E8}\x{88EA}\x{88EB}\x{88EC}\x{88EE}\x{88EF}' . +'\x{88F0}\x{88F1}\x{88F2}\x{88F3}\x{88F4}\x{88F5}\x{88F6}\x{88F7}\x{88F8}' . +'\x{88F9}\x{88FA}\x{88FB}\x{88FC}\x{88FD}\x{88FE}\x{88FF}\x{8900}\x{8901}' . +'\x{8902}\x{8904}\x{8905}\x{8906}\x{8907}\x{8908}\x{8909}\x{890A}\x{890B}' . +'\x{890C}\x{890D}\x{890E}\x{8910}\x{8911}\x{8912}\x{8913}\x{8914}\x{8915}' . +'\x{8916}\x{8917}\x{8918}\x{8919}\x{891A}\x{891B}\x{891C}\x{891D}\x{891E}' . +'\x{891F}\x{8920}\x{8921}\x{8922}\x{8923}\x{8925}\x{8926}\x{8927}\x{8928}' . +'\x{8929}\x{892A}\x{892B}\x{892C}\x{892D}\x{892E}\x{892F}\x{8930}\x{8931}' . +'\x{8932}\x{8933}\x{8934}\x{8935}\x{8936}\x{8937}\x{8938}\x{8939}\x{893A}' . +'\x{893B}\x{893C}\x{893D}\x{893E}\x{893F}\x{8940}\x{8941}\x{8942}\x{8943}' . +'\x{8944}\x{8945}\x{8946}\x{8947}\x{8948}\x{8949}\x{894A}\x{894B}\x{894C}' . +'\x{894E}\x{894F}\x{8950}\x{8951}\x{8952}\x{8953}\x{8954}\x{8955}\x{8956}' . +'\x{8957}\x{8958}\x{8959}\x{895A}\x{895B}\x{895C}\x{895D}\x{895E}\x{895F}' . +'\x{8960}\x{8961}\x{8962}\x{8963}\x{8964}\x{8966}\x{8967}\x{8968}\x{8969}' . +'\x{896A}\x{896B}\x{896C}\x{896D}\x{896E}\x{896F}\x{8970}\x{8971}\x{8972}' . +'\x{8973}\x{8974}\x{8976}\x{8977}\x{8978}\x{8979}\x{897A}\x{897B}\x{897C}' . +'\x{897E}\x{897F}\x{8980}\x{8981}\x{8982}\x{8983}\x{8984}\x{8985}\x{8986}' . +'\x{8987}\x{8988}\x{8989}\x{898A}\x{898B}\x{898C}\x{898E}\x{898F}\x{8991}' . +'\x{8992}\x{8993}\x{8995}\x{8996}\x{8997}\x{8998}\x{899A}\x{899B}\x{899C}' . +'\x{899D}\x{899E}\x{899F}\x{89A0}\x{89A1}\x{89A2}\x{89A3}\x{89A4}\x{89A5}' . +'\x{89A6}\x{89A7}\x{89A8}\x{89AA}\x{89AB}\x{89AC}\x{89AD}\x{89AE}\x{89AF}' . +'\x{89B1}\x{89B2}\x{89B3}\x{89B5}\x{89B6}\x{89B7}\x{89B8}\x{89B9}\x{89BA}' . +'\x{89BD}\x{89BE}\x{89BF}\x{89C0}\x{89C1}\x{89C2}\x{89C3}\x{89C4}\x{89C5}' . +'\x{89C6}\x{89C7}\x{89C8}\x{89C9}\x{89CA}\x{89CB}\x{89CC}\x{89CD}\x{89CE}' . +'\x{89CF}\x{89D0}\x{89D1}\x{89D2}\x{89D3}\x{89D4}\x{89D5}\x{89D6}\x{89D7}' . +'\x{89D8}\x{89D9}\x{89DA}\x{89DB}\x{89DC}\x{89DD}\x{89DE}\x{89DF}\x{89E0}' . +'\x{89E1}\x{89E2}\x{89E3}\x{89E4}\x{89E5}\x{89E6}\x{89E7}\x{89E8}\x{89E9}' . +'\x{89EA}\x{89EB}\x{89EC}\x{89ED}\x{89EF}\x{89F0}\x{89F1}\x{89F2}\x{89F3}' . +'\x{89F4}\x{89F6}\x{89F7}\x{89F8}\x{89FA}\x{89FB}\x{89FC}\x{89FE}\x{89FF}' . +'\x{8A00}\x{8A01}\x{8A02}\x{8A03}\x{8A04}\x{8A07}\x{8A08}\x{8A09}\x{8A0A}' . +'\x{8A0B}\x{8A0C}\x{8A0D}\x{8A0E}\x{8A0F}\x{8A10}\x{8A11}\x{8A12}\x{8A13}' . +'\x{8A15}\x{8A16}\x{8A17}\x{8A18}\x{8A1A}\x{8A1B}\x{8A1C}\x{8A1D}\x{8A1E}' . +'\x{8A1F}\x{8A22}\x{8A23}\x{8A24}\x{8A25}\x{8A26}\x{8A27}\x{8A28}\x{8A29}' . +'\x{8A2A}\x{8A2C}\x{8A2D}\x{8A2E}\x{8A2F}\x{8A30}\x{8A31}\x{8A32}\x{8A34}' . +'\x{8A35}\x{8A36}\x{8A37}\x{8A38}\x{8A39}\x{8A3A}\x{8A3B}\x{8A3C}\x{8A3E}' . +'\x{8A3F}\x{8A40}\x{8A41}\x{8A42}\x{8A43}\x{8A44}\x{8A45}\x{8A46}\x{8A47}' . +'\x{8A48}\x{8A49}\x{8A4A}\x{8A4C}\x{8A4D}\x{8A4E}\x{8A4F}\x{8A50}\x{8A51}' . +'\x{8A52}\x{8A53}\x{8A54}\x{8A55}\x{8A56}\x{8A57}\x{8A58}\x{8A59}\x{8A5A}' . +'\x{8A5B}\x{8A5C}\x{8A5D}\x{8A5E}\x{8A5F}\x{8A60}\x{8A61}\x{8A62}\x{8A63}' . +'\x{8A65}\x{8A66}\x{8A67}\x{8A68}\x{8A69}\x{8A6A}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A6F}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A74}\x{8A75}\x{8A76}' . +'\x{8A77}\x{8A79}\x{8A7A}\x{8A7B}\x{8A7C}\x{8A7E}\x{8A7F}\x{8A80}\x{8A81}' . +'\x{8A82}\x{8A83}\x{8A84}\x{8A85}\x{8A86}\x{8A87}\x{8A89}\x{8A8A}\x{8A8B}' . +'\x{8A8C}\x{8A8D}\x{8A8E}\x{8A8F}\x{8A90}\x{8A91}\x{8A92}\x{8A93}\x{8A94}' . +'\x{8A95}\x{8A96}\x{8A97}\x{8A98}\x{8A99}\x{8A9A}\x{8A9B}\x{8A9C}\x{8A9D}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA2}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA7}' . +'\x{8AA8}\x{8AA9}\x{8AAA}\x{8AAB}\x{8AAC}\x{8AAE}\x{8AB0}\x{8AB1}\x{8AB2}' . +'\x{8AB3}\x{8AB4}\x{8AB5}\x{8AB6}\x{8AB8}\x{8AB9}\x{8ABA}\x{8ABB}\x{8ABC}' . +'\x{8ABD}\x{8ABE}\x{8ABF}\x{8AC0}\x{8AC1}\x{8AC2}\x{8AC3}\x{8AC4}\x{8AC5}' . +'\x{8AC6}\x{8AC7}\x{8AC8}\x{8AC9}\x{8ACA}\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACE}' . +'\x{8ACF}\x{8AD1}\x{8AD2}\x{8AD3}\x{8AD4}\x{8AD5}\x{8AD6}\x{8AD7}\x{8AD8}' . +'\x{8AD9}\x{8ADA}\x{8ADB}\x{8ADC}\x{8ADD}\x{8ADE}\x{8ADF}\x{8AE0}\x{8AE1}' . +'\x{8AE2}\x{8AE3}\x{8AE4}\x{8AE5}\x{8AE6}\x{8AE7}\x{8AE8}\x{8AE9}\x{8AEA}' . +'\x{8AEB}\x{8AED}\x{8AEE}\x{8AEF}\x{8AF0}\x{8AF1}\x{8AF2}\x{8AF3}\x{8AF4}' . +'\x{8AF5}\x{8AF6}\x{8AF7}\x{8AF8}\x{8AF9}\x{8AFA}\x{8AFB}\x{8AFC}\x{8AFD}' . +'\x{8AFE}\x{8AFF}\x{8B00}\x{8B01}\x{8B02}\x{8B03}\x{8B04}\x{8B05}\x{8B06}' . +'\x{8B07}\x{8B08}\x{8B09}\x{8B0A}\x{8B0B}\x{8B0D}\x{8B0E}\x{8B0F}\x{8B10}' . +'\x{8B11}\x{8B12}\x{8B13}\x{8B14}\x{8B15}\x{8B16}\x{8B17}\x{8B18}\x{8B19}' . +'\x{8B1A}\x{8B1B}\x{8B1C}\x{8B1D}\x{8B1E}\x{8B1F}\x{8B20}\x{8B21}\x{8B22}' . +'\x{8B23}\x{8B24}\x{8B25}\x{8B26}\x{8B27}\x{8B28}\x{8B2A}\x{8B2B}\x{8B2C}' . +'\x{8B2D}\x{8B2E}\x{8B2F}\x{8B30}\x{8B31}\x{8B33}\x{8B34}\x{8B35}\x{8B36}' . +'\x{8B37}\x{8B39}\x{8B3A}\x{8B3B}\x{8B3C}\x{8B3D}\x{8B3E}\x{8B40}\x{8B41}' . +'\x{8B42}\x{8B43}\x{8B44}\x{8B45}\x{8B46}\x{8B47}\x{8B48}\x{8B49}\x{8B4A}' . +'\x{8B4B}\x{8B4C}\x{8B4D}\x{8B4E}\x{8B4F}\x{8B50}\x{8B51}\x{8B52}\x{8B53}' . +'\x{8B54}\x{8B55}\x{8B56}\x{8B57}\x{8B58}\x{8B59}\x{8B5A}\x{8B5B}\x{8B5C}' . +'\x{8B5D}\x{8B5E}\x{8B5F}\x{8B60}\x{8B63}\x{8B64}\x{8B65}\x{8B66}\x{8B67}' . +'\x{8B68}\x{8B6A}\x{8B6B}\x{8B6C}\x{8B6D}\x{8B6E}\x{8B6F}\x{8B70}\x{8B71}' . +'\x{8B73}\x{8B74}\x{8B76}\x{8B77}\x{8B78}\x{8B79}\x{8B7A}\x{8B7B}\x{8B7D}' . +'\x{8B7E}\x{8B7F}\x{8B80}\x{8B82}\x{8B83}\x{8B84}\x{8B85}\x{8B86}\x{8B88}' . +'\x{8B89}\x{8B8A}\x{8B8B}\x{8B8C}\x{8B8E}\x{8B90}\x{8B91}\x{8B92}\x{8B93}' . +'\x{8B94}\x{8B95}\x{8B96}\x{8B97}\x{8B98}\x{8B99}\x{8B9A}\x{8B9C}\x{8B9D}' . +'\x{8B9E}\x{8B9F}\x{8BA0}\x{8BA1}\x{8BA2}\x{8BA3}\x{8BA4}\x{8BA5}\x{8BA6}' . +'\x{8BA7}\x{8BA8}\x{8BA9}\x{8BAA}\x{8BAB}\x{8BAC}\x{8BAD}\x{8BAE}\x{8BAF}' . +'\x{8BB0}\x{8BB1}\x{8BB2}\x{8BB3}\x{8BB4}\x{8BB5}\x{8BB6}\x{8BB7}\x{8BB8}' . +'\x{8BB9}\x{8BBA}\x{8BBB}\x{8BBC}\x{8BBD}\x{8BBE}\x{8BBF}\x{8BC0}\x{8BC1}' . +'\x{8BC2}\x{8BC3}\x{8BC4}\x{8BC5}\x{8BC6}\x{8BC7}\x{8BC8}\x{8BC9}\x{8BCA}' . +'\x{8BCB}\x{8BCC}\x{8BCD}\x{8BCE}\x{8BCF}\x{8BD0}\x{8BD1}\x{8BD2}\x{8BD3}' . +'\x{8BD4}\x{8BD5}\x{8BD6}\x{8BD7}\x{8BD8}\x{8BD9}\x{8BDA}\x{8BDB}\x{8BDC}' . +'\x{8BDD}\x{8BDE}\x{8BDF}\x{8BE0}\x{8BE1}\x{8BE2}\x{8BE3}\x{8BE4}\x{8BE5}' . +'\x{8BE6}\x{8BE7}\x{8BE8}\x{8BE9}\x{8BEA}\x{8BEB}\x{8BEC}\x{8BED}\x{8BEE}' . +'\x{8BEF}\x{8BF0}\x{8BF1}\x{8BF2}\x{8BF3}\x{8BF4}\x{8BF5}\x{8BF6}\x{8BF7}' . +'\x{8BF8}\x{8BF9}\x{8BFA}\x{8BFB}\x{8BFC}\x{8BFD}\x{8BFE}\x{8BFF}\x{8C00}' . +'\x{8C01}\x{8C02}\x{8C03}\x{8C04}\x{8C05}\x{8C06}\x{8C07}\x{8C08}\x{8C09}' . +'\x{8C0A}\x{8C0B}\x{8C0C}\x{8C0D}\x{8C0E}\x{8C0F}\x{8C10}\x{8C11}\x{8C12}' . +'\x{8C13}\x{8C14}\x{8C15}\x{8C16}\x{8C17}\x{8C18}\x{8C19}\x{8C1A}\x{8C1B}' . +'\x{8C1C}\x{8C1D}\x{8C1E}\x{8C1F}\x{8C20}\x{8C21}\x{8C22}\x{8C23}\x{8C24}' . +'\x{8C25}\x{8C26}\x{8C27}\x{8C28}\x{8C29}\x{8C2A}\x{8C2B}\x{8C2C}\x{8C2D}' . +'\x{8C2E}\x{8C2F}\x{8C30}\x{8C31}\x{8C32}\x{8C33}\x{8C34}\x{8C35}\x{8C36}' . +'\x{8C37}\x{8C39}\x{8C3A}\x{8C3B}\x{8C3C}\x{8C3D}\x{8C3E}\x{8C3F}\x{8C41}' . +'\x{8C42}\x{8C43}\x{8C45}\x{8C46}\x{8C47}\x{8C48}\x{8C49}\x{8C4A}\x{8C4B}' . +'\x{8C4C}\x{8C4D}\x{8C4E}\x{8C4F}\x{8C50}\x{8C54}\x{8C55}\x{8C56}\x{8C57}' . +'\x{8C59}\x{8C5A}\x{8C5B}\x{8C5C}\x{8C5D}\x{8C5E}\x{8C5F}\x{8C60}\x{8C61}' . +'\x{8C62}\x{8C63}\x{8C64}\x{8C65}\x{8C66}\x{8C67}\x{8C68}\x{8C69}\x{8C6A}' . +'\x{8C6B}\x{8C6C}\x{8C6D}\x{8C6E}\x{8C6F}\x{8C70}\x{8C71}\x{8C72}\x{8C73}' . +'\x{8C75}\x{8C76}\x{8C77}\x{8C78}\x{8C79}\x{8C7A}\x{8C7B}\x{8C7D}\x{8C7E}' . +'\x{8C80}\x{8C81}\x{8C82}\x{8C84}\x{8C85}\x{8C86}\x{8C88}\x{8C89}\x{8C8A}' . +'\x{8C8C}\x{8C8D}\x{8C8F}\x{8C90}\x{8C91}\x{8C92}\x{8C93}\x{8C94}\x{8C95}' . +'\x{8C96}\x{8C97}\x{8C98}\x{8C99}\x{8C9A}\x{8C9C}\x{8C9D}\x{8C9E}\x{8C9F}' . +'\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA3}\x{8CA4}\x{8CA5}\x{8CA7}\x{8CA8}\x{8CA9}' . +'\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}\x{8CB1}\x{8CB2}' . +'\x{8CB3}\x{8CB4}\x{8CB5}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CB9}\x{8CBA}\x{8CBB}' . +'\x{8CBC}\x{8CBD}\x{8CBE}\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}' . +'\x{8CC5}\x{8CC6}\x{8CC7}\x{8CC8}\x{8CC9}\x{8CCA}\x{8CCC}\x{8CCE}\x{8CCF}' . +'\x{8CD0}\x{8CD1}\x{8CD2}\x{8CD3}\x{8CD4}\x{8CD5}\x{8CD7}\x{8CD9}\x{8CDA}' . +'\x{8CDB}\x{8CDC}\x{8CDD}\x{8CDE}\x{8CDF}\x{8CE0}\x{8CE1}\x{8CE2}\x{8CE3}' . +'\x{8CE4}\x{8CE5}\x{8CE6}\x{8CE7}\x{8CE8}\x{8CEA}\x{8CEB}\x{8CEC}\x{8CED}' . +'\x{8CEE}\x{8CEF}\x{8CF0}\x{8CF1}\x{8CF2}\x{8CF3}\x{8CF4}\x{8CF5}\x{8CF6}' . +'\x{8CF8}\x{8CF9}\x{8CFA}\x{8CFB}\x{8CFC}\x{8CFD}\x{8CFE}\x{8CFF}\x{8D00}' . +'\x{8D02}\x{8D03}\x{8D04}\x{8D05}\x{8D06}\x{8D07}\x{8D08}\x{8D09}\x{8D0A}' . +'\x{8D0B}\x{8D0C}\x{8D0D}\x{8D0E}\x{8D0F}\x{8D10}\x{8D13}\x{8D14}\x{8D15}' . +'\x{8D16}\x{8D17}\x{8D18}\x{8D19}\x{8D1A}\x{8D1B}\x{8D1C}\x{8D1D}\x{8D1E}' . +'\x{8D1F}\x{8D20}\x{8D21}\x{8D22}\x{8D23}\x{8D24}\x{8D25}\x{8D26}\x{8D27}' . +'\x{8D28}\x{8D29}\x{8D2A}\x{8D2B}\x{8D2C}\x{8D2D}\x{8D2E}\x{8D2F}\x{8D30}' . +'\x{8D31}\x{8D32}\x{8D33}\x{8D34}\x{8D35}\x{8D36}\x{8D37}\x{8D38}\x{8D39}' . +'\x{8D3A}\x{8D3B}\x{8D3C}\x{8D3D}\x{8D3E}\x{8D3F}\x{8D40}\x{8D41}\x{8D42}' . +'\x{8D43}\x{8D44}\x{8D45}\x{8D46}\x{8D47}\x{8D48}\x{8D49}\x{8D4A}\x{8D4B}' . +'\x{8D4C}\x{8D4D}\x{8D4E}\x{8D4F}\x{8D50}\x{8D51}\x{8D52}\x{8D53}\x{8D54}' . +'\x{8D55}\x{8D56}\x{8D57}\x{8D58}\x{8D59}\x{8D5A}\x{8D5B}\x{8D5C}\x{8D5D}' . +'\x{8D5E}\x{8D5F}\x{8D60}\x{8D61}\x{8D62}\x{8D63}\x{8D64}\x{8D65}\x{8D66}' . +'\x{8D67}\x{8D68}\x{8D69}\x{8D6A}\x{8D6B}\x{8D6C}\x{8D6D}\x{8D6E}\x{8D6F}' . +'\x{8D70}\x{8D71}\x{8D72}\x{8D73}\x{8D74}\x{8D75}\x{8D76}\x{8D77}\x{8D78}' . +'\x{8D79}\x{8D7A}\x{8D7B}\x{8D7D}\x{8D7E}\x{8D7F}\x{8D80}\x{8D81}\x{8D82}' . +'\x{8D83}\x{8D84}\x{8D85}\x{8D86}\x{8D87}\x{8D88}\x{8D89}\x{8D8A}\x{8D8B}' . +'\x{8D8C}\x{8D8D}\x{8D8E}\x{8D8F}\x{8D90}\x{8D91}\x{8D92}\x{8D93}\x{8D94}' . +'\x{8D95}\x{8D96}\x{8D97}\x{8D98}\x{8D99}\x{8D9A}\x{8D9B}\x{8D9C}\x{8D9D}' . +'\x{8D9E}\x{8D9F}\x{8DA0}\x{8DA1}\x{8DA2}\x{8DA3}\x{8DA4}\x{8DA5}\x{8DA7}' . +'\x{8DA8}\x{8DA9}\x{8DAA}\x{8DAB}\x{8DAC}\x{8DAD}\x{8DAE}\x{8DAF}\x{8DB0}' . +'\x{8DB1}\x{8DB2}\x{8DB3}\x{8DB4}\x{8DB5}\x{8DB6}\x{8DB7}\x{8DB8}\x{8DB9}' . +'\x{8DBA}\x{8DBB}\x{8DBC}\x{8DBD}\x{8DBE}\x{8DBF}\x{8DC1}\x{8DC2}\x{8DC3}' . +'\x{8DC4}\x{8DC5}\x{8DC6}\x{8DC7}\x{8DC8}\x{8DC9}\x{8DCA}\x{8DCB}\x{8DCC}' . +'\x{8DCD}\x{8DCE}\x{8DCF}\x{8DD0}\x{8DD1}\x{8DD2}\x{8DD3}\x{8DD4}\x{8DD5}' . +'\x{8DD6}\x{8DD7}\x{8DD8}\x{8DD9}\x{8DDA}\x{8DDB}\x{8DDC}\x{8DDD}\x{8DDE}' . +'\x{8DDF}\x{8DE0}\x{8DE1}\x{8DE2}\x{8DE3}\x{8DE4}\x{8DE6}\x{8DE7}\x{8DE8}' . +'\x{8DE9}\x{8DEA}\x{8DEB}\x{8DEC}\x{8DED}\x{8DEE}\x{8DEF}\x{8DF0}\x{8DF1}' . +'\x{8DF2}\x{8DF3}\x{8DF4}\x{8DF5}\x{8DF6}\x{8DF7}\x{8DF8}\x{8DF9}\x{8DFA}' . +'\x{8DFB}\x{8DFC}\x{8DFD}\x{8DFE}\x{8DFF}\x{8E00}\x{8E02}\x{8E03}\x{8E04}' . +'\x{8E05}\x{8E06}\x{8E07}\x{8E08}\x{8E09}\x{8E0A}\x{8E0C}\x{8E0D}\x{8E0E}' . +'\x{8E0F}\x{8E10}\x{8E11}\x{8E12}\x{8E13}\x{8E14}\x{8E15}\x{8E16}\x{8E17}' . +'\x{8E18}\x{8E19}\x{8E1A}\x{8E1B}\x{8E1C}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E20}' . +'\x{8E21}\x{8E22}\x{8E23}\x{8E24}\x{8E25}\x{8E26}\x{8E27}\x{8E28}\x{8E29}' . +'\x{8E2A}\x{8E2B}\x{8E2C}\x{8E2D}\x{8E2E}\x{8E2F}\x{8E30}\x{8E31}\x{8E33}' . +'\x{8E34}\x{8E35}\x{8E36}\x{8E37}\x{8E38}\x{8E39}\x{8E3A}\x{8E3B}\x{8E3C}' . +'\x{8E3D}\x{8E3E}\x{8E3F}\x{8E40}\x{8E41}\x{8E42}\x{8E43}\x{8E44}\x{8E45}' . +'\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4B}\x{8E4C}\x{8E4D}\x{8E4E}\x{8E50}' . +'\x{8E51}\x{8E52}\x{8E53}\x{8E54}\x{8E55}\x{8E56}\x{8E57}\x{8E58}\x{8E59}' . +'\x{8E5A}\x{8E5B}\x{8E5C}\x{8E5D}\x{8E5E}\x{8E5F}\x{8E60}\x{8E61}\x{8E62}' . +'\x{8E63}\x{8E64}\x{8E65}\x{8E66}\x{8E67}\x{8E68}\x{8E69}\x{8E6A}\x{8E6B}' . +'\x{8E6C}\x{8E6D}\x{8E6F}\x{8E70}\x{8E71}\x{8E72}\x{8E73}\x{8E74}\x{8E76}' . +'\x{8E78}\x{8E7A}\x{8E7B}\x{8E7C}\x{8E7D}\x{8E7E}\x{8E7F}\x{8E80}\x{8E81}' . +'\x{8E82}\x{8E83}\x{8E84}\x{8E85}\x{8E86}\x{8E87}\x{8E88}\x{8E89}\x{8E8A}' . +'\x{8E8B}\x{8E8C}\x{8E8D}\x{8E8E}\x{8E8F}\x{8E90}\x{8E91}\x{8E92}\x{8E93}' . +'\x{8E94}\x{8E95}\x{8E96}\x{8E97}\x{8E98}\x{8E9A}\x{8E9C}\x{8E9D}\x{8E9E}' . +'\x{8E9F}\x{8EA0}\x{8EA1}\x{8EA3}\x{8EA4}\x{8EA5}\x{8EA6}\x{8EA7}\x{8EA8}' . +'\x{8EA9}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAD}\x{8EAE}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EB2}\x{8EB4}\x{8EB5}\x{8EB8}\x{8EB9}\x{8EBA}\x{8EBB}\x{8EBC}\x{8EBD}' . +'\x{8EBE}\x{8EBF}\x{8EC0}\x{8EC2}\x{8EC3}\x{8EC5}\x{8EC6}\x{8EC7}\x{8EC8}' . +'\x{8EC9}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ECE}\x{8ECF}\x{8ED0}\x{8ED1}' . +'\x{8ED2}\x{8ED3}\x{8ED4}\x{8ED5}\x{8ED6}\x{8ED7}\x{8ED8}\x{8EDA}\x{8EDB}' . +'\x{8EDC}\x{8EDD}\x{8EDE}\x{8EDF}\x{8EE0}\x{8EE1}\x{8EE4}\x{8EE5}\x{8EE6}' . +'\x{8EE7}\x{8EE8}\x{8EE9}\x{8EEA}\x{8EEB}\x{8EEC}\x{8EED}\x{8EEE}\x{8EEF}' . +'\x{8EF1}\x{8EF2}\x{8EF3}\x{8EF4}\x{8EF5}\x{8EF6}\x{8EF7}\x{8EF8}\x{8EF9}' . +'\x{8EFA}\x{8EFB}\x{8EFC}\x{8EFD}\x{8EFE}\x{8EFF}\x{8F00}\x{8F01}\x{8F02}' . +'\x{8F03}\x{8F04}\x{8F05}\x{8F06}\x{8F07}\x{8F08}\x{8F09}\x{8F0A}\x{8F0B}' . +'\x{8F0D}\x{8F0E}\x{8F10}\x{8F11}\x{8F12}\x{8F13}\x{8F14}\x{8F15}\x{8F16}' . +'\x{8F17}\x{8F18}\x{8F1A}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1E}\x{8F1F}\x{8F20}' . +'\x{8F21}\x{8F22}\x{8F23}\x{8F24}\x{8F25}\x{8F26}\x{8F27}\x{8F28}\x{8F29}' . +'\x{8F2A}\x{8F2B}\x{8F2C}\x{8F2E}\x{8F2F}\x{8F30}\x{8F31}\x{8F32}\x{8F33}' . +'\x{8F34}\x{8F35}\x{8F36}\x{8F37}\x{8F38}\x{8F39}\x{8F3B}\x{8F3C}\x{8F3D}' . +'\x{8F3E}\x{8F3F}\x{8F40}\x{8F42}\x{8F43}\x{8F44}\x{8F45}\x{8F46}\x{8F47}' . +'\x{8F48}\x{8F49}\x{8F4A}\x{8F4B}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F4F}\x{8F50}' . +'\x{8F51}\x{8F52}\x{8F53}\x{8F54}\x{8F55}\x{8F56}\x{8F57}\x{8F58}\x{8F59}' . +'\x{8F5A}\x{8F5B}\x{8F5D}\x{8F5E}\x{8F5F}\x{8F60}\x{8F61}\x{8F62}\x{8F63}' . +'\x{8F64}\x{8F65}\x{8F66}\x{8F67}\x{8F68}\x{8F69}\x{8F6A}\x{8F6B}\x{8F6C}' . +'\x{8F6D}\x{8F6E}\x{8F6F}\x{8F70}\x{8F71}\x{8F72}\x{8F73}\x{8F74}\x{8F75}' . +'\x{8F76}\x{8F77}\x{8F78}\x{8F79}\x{8F7A}\x{8F7B}\x{8F7C}\x{8F7D}\x{8F7E}' . +'\x{8F7F}\x{8F80}\x{8F81}\x{8F82}\x{8F83}\x{8F84}\x{8F85}\x{8F86}\x{8F87}' . +'\x{8F88}\x{8F89}\x{8F8A}\x{8F8B}\x{8F8C}\x{8F8D}\x{8F8E}\x{8F8F}\x{8F90}' . +'\x{8F91}\x{8F92}\x{8F93}\x{8F94}\x{8F95}\x{8F96}\x{8F97}\x{8F98}\x{8F99}' . +'\x{8F9A}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA0}\x{8FA1}\x{8FA2}\x{8FA3}' . +'\x{8FA5}\x{8FA6}\x{8FA7}\x{8FA8}\x{8FA9}\x{8FAA}\x{8FAB}\x{8FAC}\x{8FAD}' . +'\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB4}\x{8FB5}\x{8FB6}\x{8FB7}' . +'\x{8FB8}\x{8FB9}\x{8FBB}\x{8FBC}\x{8FBD}\x{8FBE}\x{8FBF}\x{8FC0}\x{8FC1}' . +'\x{8FC2}\x{8FC4}\x{8FC5}\x{8FC6}\x{8FC7}\x{8FC8}\x{8FC9}\x{8FCB}\x{8FCC}' . +'\x{8FCD}\x{8FCE}\x{8FCF}\x{8FD0}\x{8FD1}\x{8FD2}\x{8FD3}\x{8FD4}\x{8FD5}' . +'\x{8FD6}\x{8FD7}\x{8FD8}\x{8FD9}\x{8FDA}\x{8FDB}\x{8FDC}\x{8FDD}\x{8FDE}' . +'\x{8FDF}\x{8FE0}\x{8FE1}\x{8FE2}\x{8FE3}\x{8FE4}\x{8FE5}\x{8FE6}\x{8FE8}' . +'\x{8FE9}\x{8FEA}\x{8FEB}\x{8FEC}\x{8FED}\x{8FEE}\x{8FEF}\x{8FF0}\x{8FF1}' . +'\x{8FF2}\x{8FF3}\x{8FF4}\x{8FF5}\x{8FF6}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}' . +'\x{8FFB}\x{8FFC}\x{8FFD}\x{8FFE}\x{8FFF}\x{9000}\x{9001}\x{9002}\x{9003}' . +'\x{9004}\x{9005}\x{9006}\x{9007}\x{9008}\x{9009}\x{900A}\x{900B}\x{900C}' . +'\x{900D}\x{900F}\x{9010}\x{9011}\x{9012}\x{9013}\x{9014}\x{9015}\x{9016}' . +'\x{9017}\x{9018}\x{9019}\x{901A}\x{901B}\x{901C}\x{901D}\x{901E}\x{901F}' . +'\x{9020}\x{9021}\x{9022}\x{9023}\x{9024}\x{9025}\x{9026}\x{9027}\x{9028}' . +'\x{9029}\x{902B}\x{902D}\x{902E}\x{902F}\x{9030}\x{9031}\x{9032}\x{9033}' . +'\x{9034}\x{9035}\x{9036}\x{9038}\x{903A}\x{903B}\x{903C}\x{903D}\x{903E}' . +'\x{903F}\x{9041}\x{9042}\x{9043}\x{9044}\x{9045}\x{9047}\x{9048}\x{9049}' . +'\x{904A}\x{904B}\x{904C}\x{904D}\x{904E}\x{904F}\x{9050}\x{9051}\x{9052}' . +'\x{9053}\x{9054}\x{9055}\x{9056}\x{9057}\x{9058}\x{9059}\x{905A}\x{905B}' . +'\x{905C}\x{905D}\x{905E}\x{905F}\x{9060}\x{9061}\x{9062}\x{9063}\x{9064}' . +'\x{9065}\x{9066}\x{9067}\x{9068}\x{9069}\x{906A}\x{906B}\x{906C}\x{906D}' . +'\x{906E}\x{906F}\x{9070}\x{9071}\x{9072}\x{9073}\x{9074}\x{9075}\x{9076}' . +'\x{9077}\x{9078}\x{9079}\x{907A}\x{907B}\x{907C}\x{907D}\x{907E}\x{907F}' . +'\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9085}\x{9086}\x{9087}\x{9088}' . +'\x{9089}\x{908A}\x{908B}\x{908C}\x{908D}\x{908E}\x{908F}\x{9090}\x{9091}' . +'\x{9092}\x{9093}\x{9094}\x{9095}\x{9096}\x{9097}\x{9098}\x{9099}\x{909A}' . +'\x{909B}\x{909C}\x{909D}\x{909E}\x{909F}\x{90A0}\x{90A1}\x{90A2}\x{90A3}' . +'\x{90A4}\x{90A5}\x{90A6}\x{90A7}\x{90A8}\x{90A9}\x{90AA}\x{90AC}\x{90AD}' . +'\x{90AE}\x{90AF}\x{90B0}\x{90B1}\x{90B2}\x{90B3}\x{90B4}\x{90B5}\x{90B6}' . +'\x{90B7}\x{90B8}\x{90B9}\x{90BA}\x{90BB}\x{90BC}\x{90BD}\x{90BE}\x{90BF}' . +'\x{90C0}\x{90C1}\x{90C2}\x{90C3}\x{90C4}\x{90C5}\x{90C6}\x{90C7}\x{90C8}' . +'\x{90C9}\x{90CA}\x{90CB}\x{90CE}\x{90CF}\x{90D0}\x{90D1}\x{90D3}\x{90D4}' . +'\x{90D5}\x{90D6}\x{90D7}\x{90D8}\x{90D9}\x{90DA}\x{90DB}\x{90DC}\x{90DD}' . +'\x{90DE}\x{90DF}\x{90E0}\x{90E1}\x{90E2}\x{90E3}\x{90E4}\x{90E5}\x{90E6}' . +'\x{90E7}\x{90E8}\x{90E9}\x{90EA}\x{90EB}\x{90EC}\x{90ED}\x{90EE}\x{90EF}' . +'\x{90F0}\x{90F1}\x{90F2}\x{90F3}\x{90F4}\x{90F5}\x{90F7}\x{90F8}\x{90F9}' . +'\x{90FA}\x{90FB}\x{90FC}\x{90FD}\x{90FE}\x{90FF}\x{9100}\x{9101}\x{9102}' . +'\x{9103}\x{9104}\x{9105}\x{9106}\x{9107}\x{9108}\x{9109}\x{910B}\x{910C}' . +'\x{910D}\x{910E}\x{910F}\x{9110}\x{9111}\x{9112}\x{9113}\x{9114}\x{9115}' . +'\x{9116}\x{9117}\x{9118}\x{9119}\x{911A}\x{911B}\x{911C}\x{911D}\x{911E}' . +'\x{911F}\x{9120}\x{9121}\x{9122}\x{9123}\x{9124}\x{9125}\x{9126}\x{9127}' . +'\x{9128}\x{9129}\x{912A}\x{912B}\x{912C}\x{912D}\x{912E}\x{912F}\x{9130}' . +'\x{9131}\x{9132}\x{9133}\x{9134}\x{9135}\x{9136}\x{9137}\x{9138}\x{9139}' . +'\x{913A}\x{913B}\x{913E}\x{913F}\x{9140}\x{9141}\x{9142}\x{9143}\x{9144}' . +'\x{9145}\x{9146}\x{9147}\x{9148}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}' . +'\x{914E}\x{914F}\x{9150}\x{9151}\x{9152}\x{9153}\x{9154}\x{9155}\x{9156}' . +'\x{9157}\x{9158}\x{915A}\x{915B}\x{915C}\x{915D}\x{915E}\x{915F}\x{9160}' . +'\x{9161}\x{9162}\x{9163}\x{9164}\x{9165}\x{9166}\x{9167}\x{9168}\x{9169}' . +'\x{916A}\x{916B}\x{916C}\x{916D}\x{916E}\x{916F}\x{9170}\x{9171}\x{9172}' . +'\x{9173}\x{9174}\x{9175}\x{9176}\x{9177}\x{9178}\x{9179}\x{917A}\x{917C}' . +'\x{917D}\x{917E}\x{917F}\x{9180}\x{9181}\x{9182}\x{9183}\x{9184}\x{9185}' . +'\x{9186}\x{9187}\x{9188}\x{9189}\x{918A}\x{918B}\x{918C}\x{918D}\x{918E}' . +'\x{918F}\x{9190}\x{9191}\x{9192}\x{9193}\x{9194}\x{9196}\x{9199}\x{919A}' . +'\x{919B}\x{919C}\x{919D}\x{919E}\x{919F}\x{91A0}\x{91A1}\x{91A2}\x{91A3}' . +'\x{91A5}\x{91A6}\x{91A7}\x{91A8}\x{91AA}\x{91AB}\x{91AC}\x{91AD}\x{91AE}' . +'\x{91AF}\x{91B0}\x{91B1}\x{91B2}\x{91B3}\x{91B4}\x{91B5}\x{91B6}\x{91B7}' . +'\x{91B9}\x{91BA}\x{91BB}\x{91BC}\x{91BD}\x{91BE}\x{91C0}\x{91C1}\x{91C2}' . +'\x{91C3}\x{91C5}\x{91C6}\x{91C7}\x{91C9}\x{91CA}\x{91CB}\x{91CC}\x{91CD}' . +'\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D2}\x{91D3}\x{91D4}\x{91D5}\x{91D7}' . +'\x{91D8}\x{91D9}\x{91DA}\x{91DB}\x{91DC}\x{91DD}\x{91DE}\x{91DF}\x{91E2}' . +'\x{91E3}\x{91E4}\x{91E5}\x{91E6}\x{91E7}\x{91E8}\x{91E9}\x{91EA}\x{91EB}' . +'\x{91EC}\x{91ED}\x{91EE}\x{91F0}\x{91F1}\x{91F2}\x{91F3}\x{91F4}\x{91F5}' . +'\x{91F7}\x{91F8}\x{91F9}\x{91FA}\x{91FB}\x{91FD}\x{91FE}\x{91FF}\x{9200}' . +'\x{9201}\x{9202}\x{9203}\x{9204}\x{9205}\x{9206}\x{9207}\x{9208}\x{9209}' . +'\x{920A}\x{920B}\x{920C}\x{920D}\x{920E}\x{920F}\x{9210}\x{9211}\x{9212}' . +'\x{9214}\x{9215}\x{9216}\x{9217}\x{9218}\x{9219}\x{921A}\x{921B}\x{921C}' . +'\x{921D}\x{921E}\x{9220}\x{9221}\x{9223}\x{9224}\x{9225}\x{9226}\x{9227}' . +'\x{9228}\x{9229}\x{922A}\x{922B}\x{922D}\x{922E}\x{922F}\x{9230}\x{9231}' . +'\x{9232}\x{9233}\x{9234}\x{9235}\x{9236}\x{9237}\x{9238}\x{9239}\x{923A}' . +'\x{923B}\x{923C}\x{923D}\x{923E}\x{923F}\x{9240}\x{9241}\x{9242}\x{9245}' . +'\x{9246}\x{9247}\x{9248}\x{9249}\x{924A}\x{924B}\x{924C}\x{924D}\x{924E}' . +'\x{924F}\x{9250}\x{9251}\x{9252}\x{9253}\x{9254}\x{9255}\x{9256}\x{9257}' . +'\x{9258}\x{9259}\x{925A}\x{925B}\x{925C}\x{925D}\x{925E}\x{925F}\x{9260}' . +'\x{9261}\x{9262}\x{9263}\x{9264}\x{9265}\x{9266}\x{9267}\x{9268}\x{926B}' . +'\x{926C}\x{926D}\x{926E}\x{926F}\x{9270}\x{9272}\x{9273}\x{9274}\x{9275}' . +'\x{9276}\x{9277}\x{9278}\x{9279}\x{927A}\x{927B}\x{927C}\x{927D}\x{927E}' . +'\x{927F}\x{9280}\x{9282}\x{9283}\x{9285}\x{9286}\x{9287}\x{9288}\x{9289}' . +'\x{928A}\x{928B}\x{928C}\x{928D}\x{928E}\x{928F}\x{9290}\x{9291}\x{9292}' . +'\x{9293}\x{9294}\x{9295}\x{9296}\x{9297}\x{9298}\x{9299}\x{929A}\x{929B}' . +'\x{929C}\x{929D}\x{929F}\x{92A0}\x{92A1}\x{92A2}\x{92A3}\x{92A4}\x{92A5}' . +'\x{92A6}\x{92A7}\x{92A8}\x{92A9}\x{92AA}\x{92AB}\x{92AC}\x{92AD}\x{92AE}' . +'\x{92AF}\x{92B0}\x{92B1}\x{92B2}\x{92B3}\x{92B4}\x{92B5}\x{92B6}\x{92B7}' . +'\x{92B8}\x{92B9}\x{92BA}\x{92BB}\x{92BC}\x{92BE}\x{92BF}\x{92C0}\x{92C1}' . +'\x{92C2}\x{92C3}\x{92C4}\x{92C5}\x{92C6}\x{92C7}\x{92C8}\x{92C9}\x{92CA}' . +'\x{92CB}\x{92CC}\x{92CD}\x{92CE}\x{92CF}\x{92D0}\x{92D1}\x{92D2}\x{92D3}' . +'\x{92D5}\x{92D6}\x{92D7}\x{92D8}\x{92D9}\x{92DA}\x{92DC}\x{92DD}\x{92DE}' . +'\x{92DF}\x{92E0}\x{92E1}\x{92E3}\x{92E4}\x{92E5}\x{92E6}\x{92E7}\x{92E8}' . +'\x{92E9}\x{92EA}\x{92EB}\x{92EC}\x{92ED}\x{92EE}\x{92EF}\x{92F0}\x{92F1}' . +'\x{92F2}\x{92F3}\x{92F4}\x{92F5}\x{92F6}\x{92F7}\x{92F8}\x{92F9}\x{92FA}' . +'\x{92FB}\x{92FC}\x{92FD}\x{92FE}\x{92FF}\x{9300}\x{9301}\x{9302}\x{9303}' . +'\x{9304}\x{9305}\x{9306}\x{9307}\x{9308}\x{9309}\x{930A}\x{930B}\x{930C}' . +'\x{930D}\x{930E}\x{930F}\x{9310}\x{9311}\x{9312}\x{9313}\x{9314}\x{9315}' . +'\x{9316}\x{9317}\x{9318}\x{9319}\x{931A}\x{931B}\x{931D}\x{931E}\x{931F}' . +'\x{9320}\x{9321}\x{9322}\x{9323}\x{9324}\x{9325}\x{9326}\x{9327}\x{9328}' . +'\x{9329}\x{932A}\x{932B}\x{932D}\x{932E}\x{932F}\x{9332}\x{9333}\x{9334}' . +'\x{9335}\x{9336}\x{9337}\x{9338}\x{9339}\x{933A}\x{933B}\x{933C}\x{933D}' . +'\x{933E}\x{933F}\x{9340}\x{9341}\x{9342}\x{9343}\x{9344}\x{9345}\x{9346}' . +'\x{9347}\x{9348}\x{9349}\x{934A}\x{934B}\x{934C}\x{934D}\x{934E}\x{934F}' . +'\x{9350}\x{9351}\x{9352}\x{9353}\x{9354}\x{9355}\x{9356}\x{9357}\x{9358}' . +'\x{9359}\x{935A}\x{935B}\x{935C}\x{935D}\x{935E}\x{935F}\x{9360}\x{9361}' . +'\x{9363}\x{9364}\x{9365}\x{9366}\x{9367}\x{9369}\x{936A}\x{936C}\x{936D}' . +'\x{936E}\x{9370}\x{9371}\x{9372}\x{9374}\x{9375}\x{9376}\x{9377}\x{9379}' . +'\x{937A}\x{937B}\x{937C}\x{937D}\x{937E}\x{9380}\x{9382}\x{9383}\x{9384}' . +'\x{9385}\x{9386}\x{9387}\x{9388}\x{9389}\x{938A}\x{938C}\x{938D}\x{938E}' . +'\x{938F}\x{9390}\x{9391}\x{9392}\x{9393}\x{9394}\x{9395}\x{9396}\x{9397}' . +'\x{9398}\x{9399}\x{939A}\x{939B}\x{939D}\x{939E}\x{939F}\x{93A1}\x{93A2}' . +'\x{93A3}\x{93A4}\x{93A5}\x{93A6}\x{93A7}\x{93A8}\x{93A9}\x{93AA}\x{93AC}' . +'\x{93AD}\x{93AE}\x{93AF}\x{93B0}\x{93B1}\x{93B2}\x{93B3}\x{93B4}\x{93B5}' . +'\x{93B6}\x{93B7}\x{93B8}\x{93B9}\x{93BA}\x{93BC}\x{93BD}\x{93BE}\x{93BF}' . +'\x{93C0}\x{93C1}\x{93C2}\x{93C3}\x{93C4}\x{93C5}\x{93C6}\x{93C7}\x{93C8}' . +'\x{93C9}\x{93CA}\x{93CB}\x{93CC}\x{93CD}\x{93CE}\x{93CF}\x{93D0}\x{93D1}' . +'\x{93D2}\x{93D3}\x{93D4}\x{93D5}\x{93D6}\x{93D7}\x{93D8}\x{93D9}\x{93DA}' . +'\x{93DB}\x{93DC}\x{93DD}\x{93DE}\x{93DF}\x{93E1}\x{93E2}\x{93E3}\x{93E4}' . +'\x{93E6}\x{93E7}\x{93E8}\x{93E9}\x{93EA}\x{93EB}\x{93EC}\x{93ED}\x{93EE}' . +'\x{93EF}\x{93F0}\x{93F1}\x{93F2}\x{93F4}\x{93F5}\x{93F6}\x{93F7}\x{93F8}' . +'\x{93F9}\x{93FA}\x{93FB}\x{93FC}\x{93FD}\x{93FE}\x{93FF}\x{9400}\x{9401}' . +'\x{9403}\x{9404}\x{9405}\x{9406}\x{9407}\x{9408}\x{9409}\x{940A}\x{940B}' . +'\x{940C}\x{940D}\x{940E}\x{940F}\x{9410}\x{9411}\x{9412}\x{9413}\x{9414}' . +'\x{9415}\x{9416}\x{9418}\x{9419}\x{941B}\x{941D}\x{9420}\x{9422}\x{9423}' . +'\x{9425}\x{9426}\x{9427}\x{9428}\x{9429}\x{942A}\x{942B}\x{942C}\x{942D}' . +'\x{942E}\x{942F}\x{9430}\x{9431}\x{9432}\x{9433}\x{9434}\x{9435}\x{9436}' . +'\x{9437}\x{9438}\x{9439}\x{943A}\x{943B}\x{943C}\x{943D}\x{943E}\x{943F}' . +'\x{9440}\x{9441}\x{9442}\x{9444}\x{9445}\x{9446}\x{9447}\x{9448}\x{9449}' . +'\x{944A}\x{944B}\x{944C}\x{944D}\x{944F}\x{9450}\x{9451}\x{9452}\x{9453}' . +'\x{9454}\x{9455}\x{9456}\x{9457}\x{9458}\x{9459}\x{945B}\x{945C}\x{945D}' . +'\x{945E}\x{945F}\x{9460}\x{9461}\x{9462}\x{9463}\x{9464}\x{9465}\x{9466}' . +'\x{9467}\x{9468}\x{9469}\x{946A}\x{946B}\x{946D}\x{946E}\x{946F}\x{9470}' . +'\x{9471}\x{9472}\x{9473}\x{9474}\x{9475}\x{9476}\x{9477}\x{9478}\x{9479}' . +'\x{947A}\x{947C}\x{947D}\x{947E}\x{947F}\x{9480}\x{9481}\x{9482}\x{9483}' . +'\x{9484}\x{9485}\x{9486}\x{9487}\x{9488}\x{9489}\x{948A}\x{948B}\x{948C}' . +'\x{948D}\x{948E}\x{948F}\x{9490}\x{9491}\x{9492}\x{9493}\x{9494}\x{9495}' . +'\x{9496}\x{9497}\x{9498}\x{9499}\x{949A}\x{949B}\x{949C}\x{949D}\x{949E}' . +'\x{949F}\x{94A0}\x{94A1}\x{94A2}\x{94A3}\x{94A4}\x{94A5}\x{94A6}\x{94A7}' . +'\x{94A8}\x{94A9}\x{94AA}\x{94AB}\x{94AC}\x{94AD}\x{94AE}\x{94AF}\x{94B0}' . +'\x{94B1}\x{94B2}\x{94B3}\x{94B4}\x{94B5}\x{94B6}\x{94B7}\x{94B8}\x{94B9}' . +'\x{94BA}\x{94BB}\x{94BC}\x{94BD}\x{94BE}\x{94BF}\x{94C0}\x{94C1}\x{94C2}' . +'\x{94C3}\x{94C4}\x{94C5}\x{94C6}\x{94C7}\x{94C8}\x{94C9}\x{94CA}\x{94CB}' . +'\x{94CC}\x{94CD}\x{94CE}\x{94CF}\x{94D0}\x{94D1}\x{94D2}\x{94D3}\x{94D4}' . +'\x{94D5}\x{94D6}\x{94D7}\x{94D8}\x{94D9}\x{94DA}\x{94DB}\x{94DC}\x{94DD}' . +'\x{94DE}\x{94DF}\x{94E0}\x{94E1}\x{94E2}\x{94E3}\x{94E4}\x{94E5}\x{94E6}' . +'\x{94E7}\x{94E8}\x{94E9}\x{94EA}\x{94EB}\x{94EC}\x{94ED}\x{94EE}\x{94EF}' . +'\x{94F0}\x{94F1}\x{94F2}\x{94F3}\x{94F4}\x{94F5}\x{94F6}\x{94F7}\x{94F8}' . +'\x{94F9}\x{94FA}\x{94FB}\x{94FC}\x{94FD}\x{94FE}\x{94FF}\x{9500}\x{9501}' . +'\x{9502}\x{9503}\x{9504}\x{9505}\x{9506}\x{9507}\x{9508}\x{9509}\x{950A}' . +'\x{950B}\x{950C}\x{950D}\x{950E}\x{950F}\x{9510}\x{9511}\x{9512}\x{9513}' . +'\x{9514}\x{9515}\x{9516}\x{9517}\x{9518}\x{9519}\x{951A}\x{951B}\x{951C}' . +'\x{951D}\x{951E}\x{951F}\x{9520}\x{9521}\x{9522}\x{9523}\x{9524}\x{9525}' . +'\x{9526}\x{9527}\x{9528}\x{9529}\x{952A}\x{952B}\x{952C}\x{952D}\x{952E}' . +'\x{952F}\x{9530}\x{9531}\x{9532}\x{9533}\x{9534}\x{9535}\x{9536}\x{9537}' . +'\x{9538}\x{9539}\x{953A}\x{953B}\x{953C}\x{953D}\x{953E}\x{953F}\x{9540}' . +'\x{9541}\x{9542}\x{9543}\x{9544}\x{9545}\x{9546}\x{9547}\x{9548}\x{9549}' . +'\x{954A}\x{954B}\x{954C}\x{954D}\x{954E}\x{954F}\x{9550}\x{9551}\x{9552}' . +'\x{9553}\x{9554}\x{9555}\x{9556}\x{9557}\x{9558}\x{9559}\x{955A}\x{955B}' . +'\x{955C}\x{955D}\x{955E}\x{955F}\x{9560}\x{9561}\x{9562}\x{9563}\x{9564}' . +'\x{9565}\x{9566}\x{9567}\x{9568}\x{9569}\x{956A}\x{956B}\x{956C}\x{956D}' . +'\x{956E}\x{956F}\x{9570}\x{9571}\x{9572}\x{9573}\x{9574}\x{9575}\x{9576}' . +'\x{9577}\x{957A}\x{957B}\x{957C}\x{957D}\x{957F}\x{9580}\x{9581}\x{9582}' . +'\x{9583}\x{9584}\x{9586}\x{9587}\x{9588}\x{9589}\x{958A}\x{958B}\x{958C}' . +'\x{958D}\x{958E}\x{958F}\x{9590}\x{9591}\x{9592}\x{9593}\x{9594}\x{9595}' . +'\x{9596}\x{9598}\x{9599}\x{959A}\x{959B}\x{959C}\x{959D}\x{959E}\x{959F}' . +'\x{95A1}\x{95A2}\x{95A3}\x{95A4}\x{95A5}\x{95A6}\x{95A7}\x{95A8}\x{95A9}' . +'\x{95AA}\x{95AB}\x{95AC}\x{95AD}\x{95AE}\x{95AF}\x{95B0}\x{95B1}\x{95B2}' . +'\x{95B5}\x{95B6}\x{95B7}\x{95B9}\x{95BA}\x{95BB}\x{95BC}\x{95BD}\x{95BE}' . +'\x{95BF}\x{95C0}\x{95C2}\x{95C3}\x{95C4}\x{95C5}\x{95C6}\x{95C7}\x{95C8}' . +'\x{95C9}\x{95CA}\x{95CB}\x{95CC}\x{95CD}\x{95CE}\x{95CF}\x{95D0}\x{95D1}' . +'\x{95D2}\x{95D3}\x{95D4}\x{95D5}\x{95D6}\x{95D7}\x{95D8}\x{95DA}\x{95DB}' . +'\x{95DC}\x{95DE}\x{95DF}\x{95E0}\x{95E1}\x{95E2}\x{95E3}\x{95E4}\x{95E5}' . +'\x{95E6}\x{95E7}\x{95E8}\x{95E9}\x{95EA}\x{95EB}\x{95EC}\x{95ED}\x{95EE}' . +'\x{95EF}\x{95F0}\x{95F1}\x{95F2}\x{95F3}\x{95F4}\x{95F5}\x{95F6}\x{95F7}' . +'\x{95F8}\x{95F9}\x{95FA}\x{95FB}\x{95FC}\x{95FD}\x{95FE}\x{95FF}\x{9600}' . +'\x{9601}\x{9602}\x{9603}\x{9604}\x{9605}\x{9606}\x{9607}\x{9608}\x{9609}' . +'\x{960A}\x{960B}\x{960C}\x{960D}\x{960E}\x{960F}\x{9610}\x{9611}\x{9612}' . +'\x{9613}\x{9614}\x{9615}\x{9616}\x{9617}\x{9618}\x{9619}\x{961A}\x{961B}' . +'\x{961C}\x{961D}\x{961E}\x{961F}\x{9620}\x{9621}\x{9622}\x{9623}\x{9624}' . +'\x{9627}\x{9628}\x{962A}\x{962B}\x{962C}\x{962D}\x{962E}\x{962F}\x{9630}' . +'\x{9631}\x{9632}\x{9633}\x{9634}\x{9635}\x{9636}\x{9637}\x{9638}\x{9639}' . +'\x{963A}\x{963B}\x{963C}\x{963D}\x{963F}\x{9640}\x{9641}\x{9642}\x{9643}' . +'\x{9644}\x{9645}\x{9646}\x{9647}\x{9648}\x{9649}\x{964A}\x{964B}\x{964C}' . +'\x{964D}\x{964E}\x{964F}\x{9650}\x{9651}\x{9652}\x{9653}\x{9654}\x{9655}' . +'\x{9658}\x{9659}\x{965A}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9660}' . +'\x{9661}\x{9662}\x{9663}\x{9664}\x{9666}\x{9667}\x{9668}\x{9669}\x{966A}' . +'\x{966B}\x{966C}\x{966D}\x{966E}\x{966F}\x{9670}\x{9671}\x{9672}\x{9673}' . +'\x{9674}\x{9675}\x{9676}\x{9677}\x{9678}\x{967C}\x{967D}\x{967E}\x{9680}' . +'\x{9683}\x{9684}\x{9685}\x{9686}\x{9687}\x{9688}\x{9689}\x{968A}\x{968B}' . +'\x{968D}\x{968E}\x{968F}\x{9690}\x{9691}\x{9692}\x{9693}\x{9694}\x{9695}' . +'\x{9697}\x{9698}\x{9699}\x{969B}\x{969C}\x{969E}\x{96A0}\x{96A1}\x{96A2}' . +'\x{96A3}\x{96A4}\x{96A5}\x{96A6}\x{96A7}\x{96A8}\x{96A9}\x{96AA}\x{96AC}' . +'\x{96AD}\x{96AE}\x{96B0}\x{96B1}\x{96B3}\x{96B4}\x{96B6}\x{96B7}\x{96B8}' . +'\x{96B9}\x{96BA}\x{96BB}\x{96BC}\x{96BD}\x{96BE}\x{96BF}\x{96C0}\x{96C1}' . +'\x{96C2}\x{96C3}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C8}\x{96C9}\x{96CA}' . +'\x{96CB}\x{96CC}\x{96CD}\x{96CE}\x{96CF}\x{96D0}\x{96D1}\x{96D2}\x{96D3}' . +'\x{96D4}\x{96D5}\x{96D6}\x{96D7}\x{96D8}\x{96D9}\x{96DA}\x{96DB}\x{96DC}' . +'\x{96DD}\x{96DE}\x{96DF}\x{96E0}\x{96E1}\x{96E2}\x{96E3}\x{96E5}\x{96E8}' . +'\x{96E9}\x{96EA}\x{96EB}\x{96EC}\x{96ED}\x{96EE}\x{96EF}\x{96F0}\x{96F1}' . +'\x{96F2}\x{96F3}\x{96F4}\x{96F5}\x{96F6}\x{96F7}\x{96F8}\x{96F9}\x{96FA}' . +'\x{96FB}\x{96FD}\x{96FE}\x{96FF}\x{9700}\x{9701}\x{9702}\x{9703}\x{9704}' . +'\x{9705}\x{9706}\x{9707}\x{9708}\x{9709}\x{970A}\x{970B}\x{970C}\x{970D}' . +'\x{970E}\x{970F}\x{9710}\x{9711}\x{9712}\x{9713}\x{9715}\x{9716}\x{9718}' . +'\x{9719}\x{971C}\x{971D}\x{971E}\x{971F}\x{9720}\x{9721}\x{9722}\x{9723}' . +'\x{9724}\x{9725}\x{9726}\x{9727}\x{9728}\x{9729}\x{972A}\x{972B}\x{972C}' . +'\x{972D}\x{972E}\x{972F}\x{9730}\x{9731}\x{9732}\x{9735}\x{9736}\x{9738}' . +'\x{9739}\x{973A}\x{973B}\x{973C}\x{973D}\x{973E}\x{973F}\x{9742}\x{9743}' . +'\x{9744}\x{9745}\x{9746}\x{9747}\x{9748}\x{9749}\x{974A}\x{974B}\x{974C}' . +'\x{974E}\x{974F}\x{9750}\x{9751}\x{9752}\x{9753}\x{9754}\x{9755}\x{9756}' . +'\x{9758}\x{9759}\x{975A}\x{975B}\x{975C}\x{975D}\x{975E}\x{975F}\x{9760}' . +'\x{9761}\x{9762}\x{9765}\x{9766}\x{9767}\x{9768}\x{9769}\x{976A}\x{976B}' . +'\x{976C}\x{976D}\x{976E}\x{976F}\x{9770}\x{9772}\x{9773}\x{9774}\x{9776}' . +'\x{9777}\x{9778}\x{9779}\x{977A}\x{977B}\x{977C}\x{977D}\x{977E}\x{977F}' . +'\x{9780}\x{9781}\x{9782}\x{9783}\x{9784}\x{9785}\x{9786}\x{9788}\x{978A}' . +'\x{978B}\x{978C}\x{978D}\x{978E}\x{978F}\x{9790}\x{9791}\x{9792}\x{9793}' . +'\x{9794}\x{9795}\x{9796}\x{9797}\x{9798}\x{9799}\x{979A}\x{979C}\x{979D}' . +'\x{979E}\x{979F}\x{97A0}\x{97A1}\x{97A2}\x{97A3}\x{97A4}\x{97A5}\x{97A6}' . +'\x{97A7}\x{97A8}\x{97AA}\x{97AB}\x{97AC}\x{97AD}\x{97AE}\x{97AF}\x{97B2}' . +'\x{97B3}\x{97B4}\x{97B6}\x{97B7}\x{97B8}\x{97B9}\x{97BA}\x{97BB}\x{97BC}' . +'\x{97BD}\x{97BF}\x{97C1}\x{97C2}\x{97C3}\x{97C4}\x{97C5}\x{97C6}\x{97C7}' . +'\x{97C8}\x{97C9}\x{97CA}\x{97CB}\x{97CC}\x{97CD}\x{97CE}\x{97CF}\x{97D0}' . +'\x{97D1}\x{97D3}\x{97D4}\x{97D5}\x{97D6}\x{97D7}\x{97D8}\x{97D9}\x{97DA}' . +'\x{97DB}\x{97DC}\x{97DD}\x{97DE}\x{97DF}\x{97E0}\x{97E1}\x{97E2}\x{97E3}' . +'\x{97E4}\x{97E5}\x{97E6}\x{97E7}\x{97E8}\x{97E9}\x{97EA}\x{97EB}\x{97EC}' . +'\x{97ED}\x{97EE}\x{97EF}\x{97F0}\x{97F1}\x{97F2}\x{97F3}\x{97F4}\x{97F5}' . +'\x{97F6}\x{97F7}\x{97F8}\x{97F9}\x{97FA}\x{97FB}\x{97FD}\x{97FE}\x{97FF}' . +'\x{9800}\x{9801}\x{9802}\x{9803}\x{9804}\x{9805}\x{9806}\x{9807}\x{9808}' . +'\x{9809}\x{980A}\x{980B}\x{980C}\x{980D}\x{980E}\x{980F}\x{9810}\x{9811}' . +'\x{9812}\x{9813}\x{9814}\x{9815}\x{9816}\x{9817}\x{9818}\x{9819}\x{981A}' . +'\x{981B}\x{981C}\x{981D}\x{981E}\x{9820}\x{9821}\x{9822}\x{9823}\x{9824}' . +'\x{9826}\x{9827}\x{9828}\x{9829}\x{982B}\x{982D}\x{982E}\x{982F}\x{9830}' . +'\x{9831}\x{9832}\x{9834}\x{9835}\x{9836}\x{9837}\x{9838}\x{9839}\x{983B}' . +'\x{983C}\x{983D}\x{983F}\x{9840}\x{9841}\x{9843}\x{9844}\x{9845}\x{9846}' . +'\x{9848}\x{9849}\x{984A}\x{984C}\x{984D}\x{984E}\x{984F}\x{9850}\x{9851}' . +'\x{9852}\x{9853}\x{9854}\x{9855}\x{9857}\x{9858}\x{9859}\x{985A}\x{985B}' . +'\x{985C}\x{985D}\x{985E}\x{985F}\x{9860}\x{9861}\x{9862}\x{9863}\x{9864}' . +'\x{9865}\x{9867}\x{9869}\x{986A}\x{986B}\x{986C}\x{986D}\x{986E}\x{986F}' . +'\x{9870}\x{9871}\x{9872}\x{9873}\x{9874}\x{9875}\x{9876}\x{9877}\x{9878}' . +'\x{9879}\x{987A}\x{987B}\x{987C}\x{987D}\x{987E}\x{987F}\x{9880}\x{9881}' . +'\x{9882}\x{9883}\x{9884}\x{9885}\x{9886}\x{9887}\x{9888}\x{9889}\x{988A}' . +'\x{988B}\x{988C}\x{988D}\x{988E}\x{988F}\x{9890}\x{9891}\x{9892}\x{9893}' . +'\x{9894}\x{9895}\x{9896}\x{9897}\x{9898}\x{9899}\x{989A}\x{989B}\x{989C}' . +'\x{989D}\x{989E}\x{989F}\x{98A0}\x{98A1}\x{98A2}\x{98A3}\x{98A4}\x{98A5}' . +'\x{98A6}\x{98A7}\x{98A8}\x{98A9}\x{98AA}\x{98AB}\x{98AC}\x{98AD}\x{98AE}' . +'\x{98AF}\x{98B0}\x{98B1}\x{98B2}\x{98B3}\x{98B4}\x{98B5}\x{98B6}\x{98B8}' . +'\x{98B9}\x{98BA}\x{98BB}\x{98BC}\x{98BD}\x{98BE}\x{98BF}\x{98C0}\x{98C1}' . +'\x{98C2}\x{98C3}\x{98C4}\x{98C5}\x{98C6}\x{98C8}\x{98C9}\x{98CB}\x{98CC}' . +'\x{98CD}\x{98CE}\x{98CF}\x{98D0}\x{98D1}\x{98D2}\x{98D3}\x{98D4}\x{98D5}' . +'\x{98D6}\x{98D7}\x{98D8}\x{98D9}\x{98DA}\x{98DB}\x{98DC}\x{98DD}\x{98DE}' . +'\x{98DF}\x{98E0}\x{98E2}\x{98E3}\x{98E5}\x{98E6}\x{98E7}\x{98E8}\x{98E9}' . +'\x{98EA}\x{98EB}\x{98ED}\x{98EF}\x{98F0}\x{98F2}\x{98F3}\x{98F4}\x{98F5}' . +'\x{98F6}\x{98F7}\x{98F9}\x{98FA}\x{98FC}\x{98FD}\x{98FE}\x{98FF}\x{9900}' . +'\x{9901}\x{9902}\x{9903}\x{9904}\x{9905}\x{9906}\x{9907}\x{9908}\x{9909}' . +'\x{990A}\x{990B}\x{990C}\x{990D}\x{990E}\x{990F}\x{9910}\x{9911}\x{9912}' . +'\x{9913}\x{9914}\x{9915}\x{9916}\x{9917}\x{9918}\x{991A}\x{991B}\x{991C}' . +'\x{991D}\x{991E}\x{991F}\x{9920}\x{9921}\x{9922}\x{9923}\x{9924}\x{9925}' . +'\x{9926}\x{9927}\x{9928}\x{9929}\x{992A}\x{992B}\x{992C}\x{992D}\x{992E}' . +'\x{992F}\x{9930}\x{9931}\x{9932}\x{9933}\x{9934}\x{9935}\x{9936}\x{9937}' . +'\x{9938}\x{9939}\x{993A}\x{993C}\x{993D}\x{993E}\x{993F}\x{9940}\x{9941}' . +'\x{9942}\x{9943}\x{9945}\x{9946}\x{9947}\x{9948}\x{9949}\x{994A}\x{994B}' . +'\x{994C}\x{994E}\x{994F}\x{9950}\x{9951}\x{9952}\x{9953}\x{9954}\x{9955}' . +'\x{9956}\x{9957}\x{9958}\x{9959}\x{995B}\x{995C}\x{995E}\x{995F}\x{9960}' . +'\x{9961}\x{9962}\x{9963}\x{9964}\x{9965}\x{9966}\x{9967}\x{9968}\x{9969}' . +'\x{996A}\x{996B}\x{996C}\x{996D}\x{996E}\x{996F}\x{9970}\x{9971}\x{9972}' . +'\x{9973}\x{9974}\x{9975}\x{9976}\x{9977}\x{9978}\x{9979}\x{997A}\x{997B}' . +'\x{997C}\x{997D}\x{997E}\x{997F}\x{9980}\x{9981}\x{9982}\x{9983}\x{9984}' . +'\x{9985}\x{9986}\x{9987}\x{9988}\x{9989}\x{998A}\x{998B}\x{998C}\x{998D}' . +'\x{998E}\x{998F}\x{9990}\x{9991}\x{9992}\x{9993}\x{9994}\x{9995}\x{9996}' . +'\x{9997}\x{9998}\x{9999}\x{999A}\x{999B}\x{999C}\x{999D}\x{999E}\x{999F}' . +'\x{99A0}\x{99A1}\x{99A2}\x{99A3}\x{99A4}\x{99A5}\x{99A6}\x{99A7}\x{99A8}' . +'\x{99A9}\x{99AA}\x{99AB}\x{99AC}\x{99AD}\x{99AE}\x{99AF}\x{99B0}\x{99B1}' . +'\x{99B2}\x{99B3}\x{99B4}\x{99B5}\x{99B6}\x{99B7}\x{99B8}\x{99B9}\x{99BA}' . +'\x{99BB}\x{99BC}\x{99BD}\x{99BE}\x{99C0}\x{99C1}\x{99C2}\x{99C3}\x{99C4}' . +'\x{99C6}\x{99C7}\x{99C8}\x{99C9}\x{99CA}\x{99CB}\x{99CC}\x{99CD}\x{99CE}' . +'\x{99CF}\x{99D0}\x{99D1}\x{99D2}\x{99D3}\x{99D4}\x{99D5}\x{99D6}\x{99D7}' . +'\x{99D8}\x{99D9}\x{99DA}\x{99DB}\x{99DC}\x{99DD}\x{99DE}\x{99DF}\x{99E1}' . +'\x{99E2}\x{99E3}\x{99E4}\x{99E5}\x{99E7}\x{99E8}\x{99E9}\x{99EA}\x{99EC}' . +'\x{99ED}\x{99EE}\x{99EF}\x{99F0}\x{99F1}\x{99F2}\x{99F3}\x{99F4}\x{99F6}' . +'\x{99F7}\x{99F8}\x{99F9}\x{99FA}\x{99FB}\x{99FC}\x{99FD}\x{99FE}\x{99FF}' . +'\x{9A00}\x{9A01}\x{9A02}\x{9A03}\x{9A04}\x{9A05}\x{9A06}\x{9A07}\x{9A08}' . +'\x{9A09}\x{9A0A}\x{9A0B}\x{9A0C}\x{9A0D}\x{9A0E}\x{9A0F}\x{9A11}\x{9A14}' . +'\x{9A15}\x{9A16}\x{9A19}\x{9A1A}\x{9A1B}\x{9A1C}\x{9A1D}\x{9A1E}\x{9A1F}' . +'\x{9A20}\x{9A21}\x{9A22}\x{9A23}\x{9A24}\x{9A25}\x{9A26}\x{9A27}\x{9A29}' . +'\x{9A2A}\x{9A2B}\x{9A2C}\x{9A2D}\x{9A2E}\x{9A2F}\x{9A30}\x{9A31}\x{9A32}' . +'\x{9A33}\x{9A34}\x{9A35}\x{9A36}\x{9A37}\x{9A38}\x{9A39}\x{9A3A}\x{9A3C}' . +'\x{9A3D}\x{9A3E}\x{9A3F}\x{9A40}\x{9A41}\x{9A42}\x{9A43}\x{9A44}\x{9A45}' . +'\x{9A46}\x{9A47}\x{9A48}\x{9A49}\x{9A4A}\x{9A4B}\x{9A4C}\x{9A4D}\x{9A4E}' . +'\x{9A4F}\x{9A50}\x{9A52}\x{9A53}\x{9A54}\x{9A55}\x{9A56}\x{9A57}\x{9A59}' . +'\x{9A5A}\x{9A5B}\x{9A5C}\x{9A5E}\x{9A5F}\x{9A60}\x{9A61}\x{9A62}\x{9A64}' . +'\x{9A65}\x{9A66}\x{9A67}\x{9A68}\x{9A69}\x{9A6A}\x{9A6B}\x{9A6C}\x{9A6D}' . +'\x{9A6E}\x{9A6F}\x{9A70}\x{9A71}\x{9A72}\x{9A73}\x{9A74}\x{9A75}\x{9A76}' . +'\x{9A77}\x{9A78}\x{9A79}\x{9A7A}\x{9A7B}\x{9A7C}\x{9A7D}\x{9A7E}\x{9A7F}' . +'\x{9A80}\x{9A81}\x{9A82}\x{9A83}\x{9A84}\x{9A85}\x{9A86}\x{9A87}\x{9A88}' . +'\x{9A89}\x{9A8A}\x{9A8B}\x{9A8C}\x{9A8D}\x{9A8E}\x{9A8F}\x{9A90}\x{9A91}' . +'\x{9A92}\x{9A93}\x{9A94}\x{9A95}\x{9A96}\x{9A97}\x{9A98}\x{9A99}\x{9A9A}' . +'\x{9A9B}\x{9A9C}\x{9A9D}\x{9A9E}\x{9A9F}\x{9AA0}\x{9AA1}\x{9AA2}\x{9AA3}' . +'\x{9AA4}\x{9AA5}\x{9AA6}\x{9AA7}\x{9AA8}\x{9AAA}\x{9AAB}\x{9AAC}\x{9AAD}' . +'\x{9AAE}\x{9AAF}\x{9AB0}\x{9AB1}\x{9AB2}\x{9AB3}\x{9AB4}\x{9AB5}\x{9AB6}' . +'\x{9AB7}\x{9AB8}\x{9AB9}\x{9ABA}\x{9ABB}\x{9ABC}\x{9ABE}\x{9ABF}\x{9AC0}' . +'\x{9AC1}\x{9AC2}\x{9AC3}\x{9AC4}\x{9AC5}\x{9AC6}\x{9AC7}\x{9AC9}\x{9ACA}' . +'\x{9ACB}\x{9ACC}\x{9ACD}\x{9ACE}\x{9ACF}\x{9AD0}\x{9AD1}\x{9AD2}\x{9AD3}' . +'\x{9AD4}\x{9AD5}\x{9AD6}\x{9AD8}\x{9AD9}\x{9ADA}\x{9ADB}\x{9ADC}\x{9ADD}' . +'\x{9ADE}\x{9ADF}\x{9AE1}\x{9AE2}\x{9AE3}\x{9AE5}\x{9AE6}\x{9AE7}\x{9AEA}' . +'\x{9AEB}\x{9AEC}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF2}\x{9AF3}\x{9AF4}' . +'\x{9AF5}\x{9AF6}\x{9AF7}\x{9AF8}\x{9AF9}\x{9AFA}\x{9AFB}\x{9AFC}\x{9AFD}' . +'\x{9AFE}\x{9AFF}\x{9B01}\x{9B03}\x{9B04}\x{9B05}\x{9B06}\x{9B07}\x{9B08}' . +'\x{9B0A}\x{9B0B}\x{9B0C}\x{9B0D}\x{9B0E}\x{9B0F}\x{9B10}\x{9B11}\x{9B12}' . +'\x{9B13}\x{9B15}\x{9B16}\x{9B17}\x{9B18}\x{9B19}\x{9B1A}\x{9B1C}\x{9B1D}' . +'\x{9B1E}\x{9B1F}\x{9B20}\x{9B21}\x{9B22}\x{9B23}\x{9B24}\x{9B25}\x{9B26}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2B}\x{9B2C}\x{9B2D}\x{9B2E}\x{9B2F}' . +'\x{9B30}\x{9B31}\x{9B32}\x{9B33}\x{9B35}\x{9B36}\x{9B37}\x{9B38}\x{9B39}' . +'\x{9B3A}\x{9B3B}\x{9B3C}\x{9B3E}\x{9B3F}\x{9B41}\x{9B42}\x{9B43}\x{9B44}' . +'\x{9B45}\x{9B46}\x{9B47}\x{9B48}\x{9B49}\x{9B4A}\x{9B4B}\x{9B4C}\x{9B4D}' . +'\x{9B4E}\x{9B4F}\x{9B51}\x{9B52}\x{9B53}\x{9B54}\x{9B55}\x{9B56}\x{9B58}' . +'\x{9B59}\x{9B5A}\x{9B5B}\x{9B5C}\x{9B5D}\x{9B5E}\x{9B5F}\x{9B60}\x{9B61}' . +'\x{9B63}\x{9B64}\x{9B65}\x{9B66}\x{9B67}\x{9B68}\x{9B69}\x{9B6A}\x{9B6B}' . +'\x{9B6C}\x{9B6D}\x{9B6E}\x{9B6F}\x{9B70}\x{9B71}\x{9B73}\x{9B74}\x{9B75}' . +'\x{9B76}\x{9B77}\x{9B78}\x{9B79}\x{9B7A}\x{9B7B}\x{9B7C}\x{9B7D}\x{9B7E}' . +'\x{9B7F}\x{9B80}\x{9B81}\x{9B82}\x{9B83}\x{9B84}\x{9B85}\x{9B86}\x{9B87}' . +'\x{9B88}\x{9B8A}\x{9B8B}\x{9B8D}\x{9B8E}\x{9B8F}\x{9B90}\x{9B91}\x{9B92}' . +'\x{9B93}\x{9B94}\x{9B95}\x{9B96}\x{9B97}\x{9B98}\x{9B9A}\x{9B9B}\x{9B9C}' . +'\x{9B9D}\x{9B9E}\x{9B9F}\x{9BA0}\x{9BA1}\x{9BA2}\x{9BA3}\x{9BA4}\x{9BA5}' . +'\x{9BA6}\x{9BA7}\x{9BA8}\x{9BA9}\x{9BAA}\x{9BAB}\x{9BAC}\x{9BAD}\x{9BAE}' . +'\x{9BAF}\x{9BB0}\x{9BB1}\x{9BB2}\x{9BB3}\x{9BB4}\x{9BB5}\x{9BB6}\x{9BB7}' . +'\x{9BB8}\x{9BB9}\x{9BBA}\x{9BBB}\x{9BBC}\x{9BBD}\x{9BBE}\x{9BBF}\x{9BC0}' . +'\x{9BC1}\x{9BC3}\x{9BC4}\x{9BC5}\x{9BC6}\x{9BC7}\x{9BC8}\x{9BC9}\x{9BCA}' . +'\x{9BCB}\x{9BCC}\x{9BCD}\x{9BCE}\x{9BCF}\x{9BD0}\x{9BD1}\x{9BD2}\x{9BD3}' . +'\x{9BD4}\x{9BD5}\x{9BD6}\x{9BD7}\x{9BD8}\x{9BD9}\x{9BDA}\x{9BDB}\x{9BDC}' . +'\x{9BDD}\x{9BDE}\x{9BDF}\x{9BE0}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}\x{9BE5}' . +'\x{9BE6}\x{9BE7}\x{9BE8}\x{9BE9}\x{9BEA}\x{9BEB}\x{9BEC}\x{9BED}\x{9BEE}' . +'\x{9BEF}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF3}\x{9BF4}\x{9BF5}\x{9BF7}\x{9BF8}' . +'\x{9BF9}\x{9BFA}\x{9BFB}\x{9BFC}\x{9BFD}\x{9BFE}\x{9BFF}\x{9C02}\x{9C05}' . +'\x{9C06}\x{9C07}\x{9C08}\x{9C09}\x{9C0A}\x{9C0B}\x{9C0C}\x{9C0D}\x{9C0E}' . +'\x{9C0F}\x{9C10}\x{9C11}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C16}\x{9C17}' . +'\x{9C18}\x{9C19}\x{9C1A}\x{9C1B}\x{9C1C}\x{9C1D}\x{9C1E}\x{9C1F}\x{9C20}' . +'\x{9C21}\x{9C22}\x{9C23}\x{9C24}\x{9C25}\x{9C26}\x{9C27}\x{9C28}\x{9C29}' . +'\x{9C2A}\x{9C2B}\x{9C2C}\x{9C2D}\x{9C2F}\x{9C30}\x{9C31}\x{9C32}\x{9C33}' . +'\x{9C34}\x{9C35}\x{9C36}\x{9C37}\x{9C38}\x{9C39}\x{9C3A}\x{9C3B}\x{9C3C}' . +'\x{9C3D}\x{9C3E}\x{9C3F}\x{9C40}\x{9C41}\x{9C43}\x{9C44}\x{9C45}\x{9C46}' . +'\x{9C47}\x{9C48}\x{9C49}\x{9C4A}\x{9C4B}\x{9C4C}\x{9C4D}\x{9C4E}\x{9C50}' . +'\x{9C52}\x{9C53}\x{9C54}\x{9C55}\x{9C56}\x{9C57}\x{9C58}\x{9C59}\x{9C5A}' . +'\x{9C5B}\x{9C5C}\x{9C5D}\x{9C5E}\x{9C5F}\x{9C60}\x{9C62}\x{9C63}\x{9C65}' . +'\x{9C66}\x{9C67}\x{9C68}\x{9C69}\x{9C6A}\x{9C6B}\x{9C6C}\x{9C6D}\x{9C6E}' . +'\x{9C6F}\x{9C70}\x{9C71}\x{9C72}\x{9C73}\x{9C74}\x{9C75}\x{9C77}\x{9C78}' . +'\x{9C79}\x{9C7A}\x{9C7C}\x{9C7D}\x{9C7E}\x{9C7F}\x{9C80}\x{9C81}\x{9C82}' . +'\x{9C83}\x{9C84}\x{9C85}\x{9C86}\x{9C87}\x{9C88}\x{9C89}\x{9C8A}\x{9C8B}' . +'\x{9C8C}\x{9C8D}\x{9C8E}\x{9C8F}\x{9C90}\x{9C91}\x{9C92}\x{9C93}\x{9C94}' . +'\x{9C95}\x{9C96}\x{9C97}\x{9C98}\x{9C99}\x{9C9A}\x{9C9B}\x{9C9C}\x{9C9D}' . +'\x{9C9E}\x{9C9F}\x{9CA0}\x{9CA1}\x{9CA2}\x{9CA3}\x{9CA4}\x{9CA5}\x{9CA6}' . +'\x{9CA7}\x{9CA8}\x{9CA9}\x{9CAA}\x{9CAB}\x{9CAC}\x{9CAD}\x{9CAE}\x{9CAF}' . +'\x{9CB0}\x{9CB1}\x{9CB2}\x{9CB3}\x{9CB4}\x{9CB5}\x{9CB6}\x{9CB7}\x{9CB8}' . +'\x{9CB9}\x{9CBA}\x{9CBB}\x{9CBC}\x{9CBD}\x{9CBE}\x{9CBF}\x{9CC0}\x{9CC1}' . +'\x{9CC2}\x{9CC3}\x{9CC4}\x{9CC5}\x{9CC6}\x{9CC7}\x{9CC8}\x{9CC9}\x{9CCA}' . +'\x{9CCB}\x{9CCC}\x{9CCD}\x{9CCE}\x{9CCF}\x{9CD0}\x{9CD1}\x{9CD2}\x{9CD3}' . +'\x{9CD4}\x{9CD5}\x{9CD6}\x{9CD7}\x{9CD8}\x{9CD9}\x{9CDA}\x{9CDB}\x{9CDC}' . +'\x{9CDD}\x{9CDE}\x{9CDF}\x{9CE0}\x{9CE1}\x{9CE2}\x{9CE3}\x{9CE4}\x{9CE5}' . +'\x{9CE6}\x{9CE7}\x{9CE8}\x{9CE9}\x{9CEA}\x{9CEB}\x{9CEC}\x{9CED}\x{9CEE}' . +'\x{9CEF}\x{9CF0}\x{9CF1}\x{9CF2}\x{9CF3}\x{9CF4}\x{9CF5}\x{9CF6}\x{9CF7}' . +'\x{9CF8}\x{9CF9}\x{9CFA}\x{9CFB}\x{9CFC}\x{9CFD}\x{9CFE}\x{9CFF}\x{9D00}' . +'\x{9D01}\x{9D02}\x{9D03}\x{9D04}\x{9D05}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0A}\x{9D0B}\x{9D0F}\x{9D10}\x{9D12}\x{9D13}\x{9D14}\x{9D15}\x{9D16}' . +'\x{9D17}\x{9D18}\x{9D19}\x{9D1A}\x{9D1B}\x{9D1C}\x{9D1D}\x{9D1E}\x{9D1F}' . +'\x{9D20}\x{9D21}\x{9D22}\x{9D23}\x{9D24}\x{9D25}\x{9D26}\x{9D28}\x{9D29}' . +'\x{9D2B}\x{9D2D}\x{9D2E}\x{9D2F}\x{9D30}\x{9D31}\x{9D32}\x{9D33}\x{9D34}' . +'\x{9D36}\x{9D37}\x{9D38}\x{9D39}\x{9D3A}\x{9D3B}\x{9D3D}\x{9D3E}\x{9D3F}' . +'\x{9D40}\x{9D41}\x{9D42}\x{9D43}\x{9D45}\x{9D46}\x{9D47}\x{9D48}\x{9D49}' . +'\x{9D4A}\x{9D4B}\x{9D4C}\x{9D4D}\x{9D4E}\x{9D4F}\x{9D50}\x{9D51}\x{9D52}' . +'\x{9D53}\x{9D54}\x{9D55}\x{9D56}\x{9D57}\x{9D58}\x{9D59}\x{9D5A}\x{9D5B}' . +'\x{9D5C}\x{9D5D}\x{9D5E}\x{9D5F}\x{9D60}\x{9D61}\x{9D62}\x{9D63}\x{9D64}' . +'\x{9D65}\x{9D66}\x{9D67}\x{9D68}\x{9D69}\x{9D6A}\x{9D6B}\x{9D6C}\x{9D6E}' . +'\x{9D6F}\x{9D70}\x{9D71}\x{9D72}\x{9D73}\x{9D74}\x{9D75}\x{9D76}\x{9D77}' . +'\x{9D78}\x{9D79}\x{9D7A}\x{9D7B}\x{9D7C}\x{9D7D}\x{9D7E}\x{9D7F}\x{9D80}' . +'\x{9D81}\x{9D82}\x{9D83}\x{9D84}\x{9D85}\x{9D86}\x{9D87}\x{9D88}\x{9D89}' . +'\x{9D8A}\x{9D8B}\x{9D8C}\x{9D8D}\x{9D8E}\x{9D90}\x{9D91}\x{9D92}\x{9D93}' . +'\x{9D94}\x{9D96}\x{9D97}\x{9D98}\x{9D99}\x{9D9A}\x{9D9B}\x{9D9C}\x{9D9D}' . +'\x{9D9E}\x{9D9F}\x{9DA0}\x{9DA1}\x{9DA2}\x{9DA3}\x{9DA4}\x{9DA5}\x{9DA6}' . +'\x{9DA7}\x{9DA8}\x{9DA9}\x{9DAA}\x{9DAB}\x{9DAC}\x{9DAD}\x{9DAF}\x{9DB0}' . +'\x{9DB1}\x{9DB2}\x{9DB3}\x{9DB4}\x{9DB5}\x{9DB6}\x{9DB7}\x{9DB8}\x{9DB9}' . +'\x{9DBA}\x{9DBB}\x{9DBC}\x{9DBE}\x{9DBF}\x{9DC1}\x{9DC2}\x{9DC3}\x{9DC4}' . +'\x{9DC5}\x{9DC7}\x{9DC8}\x{9DC9}\x{9DCA}\x{9DCB}\x{9DCC}\x{9DCD}\x{9DCE}' . +'\x{9DCF}\x{9DD0}\x{9DD1}\x{9DD2}\x{9DD3}\x{9DD4}\x{9DD5}\x{9DD6}\x{9DD7}' . +'\x{9DD8}\x{9DD9}\x{9DDA}\x{9DDB}\x{9DDC}\x{9DDD}\x{9DDE}\x{9DDF}\x{9DE0}' . +'\x{9DE1}\x{9DE2}\x{9DE3}\x{9DE4}\x{9DE5}\x{9DE6}\x{9DE7}\x{9DE8}\x{9DE9}' . +'\x{9DEB}\x{9DEC}\x{9DED}\x{9DEE}\x{9DEF}\x{9DF0}\x{9DF1}\x{9DF2}\x{9DF3}' . +'\x{9DF4}\x{9DF5}\x{9DF6}\x{9DF7}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFB}\x{9DFD}' . +'\x{9DFE}\x{9DFF}\x{9E00}\x{9E01}\x{9E02}\x{9E03}\x{9E04}\x{9E05}\x{9E06}' . +'\x{9E07}\x{9E08}\x{9E09}\x{9E0A}\x{9E0B}\x{9E0C}\x{9E0D}\x{9E0F}\x{9E10}' . +'\x{9E11}\x{9E12}\x{9E13}\x{9E14}\x{9E15}\x{9E17}\x{9E18}\x{9E19}\x{9E1A}' . +'\x{9E1B}\x{9E1D}\x{9E1E}\x{9E1F}\x{9E20}\x{9E21}\x{9E22}\x{9E23}\x{9E24}' . +'\x{9E25}\x{9E26}\x{9E27}\x{9E28}\x{9E29}\x{9E2A}\x{9E2B}\x{9E2C}\x{9E2D}' . +'\x{9E2E}\x{9E2F}\x{9E30}\x{9E31}\x{9E32}\x{9E33}\x{9E34}\x{9E35}\x{9E36}' . +'\x{9E37}\x{9E38}\x{9E39}\x{9E3A}\x{9E3B}\x{9E3C}\x{9E3D}\x{9E3E}\x{9E3F}' . +'\x{9E40}\x{9E41}\x{9E42}\x{9E43}\x{9E44}\x{9E45}\x{9E46}\x{9E47}\x{9E48}' . +'\x{9E49}\x{9E4A}\x{9E4B}\x{9E4C}\x{9E4D}\x{9E4E}\x{9E4F}\x{9E50}\x{9E51}' . +'\x{9E52}\x{9E53}\x{9E54}\x{9E55}\x{9E56}\x{9E57}\x{9E58}\x{9E59}\x{9E5A}' . +'\x{9E5B}\x{9E5C}\x{9E5D}\x{9E5E}\x{9E5F}\x{9E60}\x{9E61}\x{9E62}\x{9E63}' . +'\x{9E64}\x{9E65}\x{9E66}\x{9E67}\x{9E68}\x{9E69}\x{9E6A}\x{9E6B}\x{9E6C}' . +'\x{9E6D}\x{9E6E}\x{9E6F}\x{9E70}\x{9E71}\x{9E72}\x{9E73}\x{9E74}\x{9E75}' . +'\x{9E76}\x{9E77}\x{9E79}\x{9E7A}\x{9E7C}\x{9E7D}\x{9E7E}\x{9E7F}\x{9E80}' . +'\x{9E81}\x{9E82}\x{9E83}\x{9E84}\x{9E85}\x{9E86}\x{9E87}\x{9E88}\x{9E89}' . +'\x{9E8A}\x{9E8B}\x{9E8C}\x{9E8D}\x{9E8E}\x{9E91}\x{9E92}\x{9E93}\x{9E94}' . +'\x{9E96}\x{9E97}\x{9E99}\x{9E9A}\x{9E9B}\x{9E9C}\x{9E9D}\x{9E9F}\x{9EA0}' . +'\x{9EA1}\x{9EA3}\x{9EA4}\x{9EA5}\x{9EA6}\x{9EA7}\x{9EA8}\x{9EA9}\x{9EAA}' . +'\x{9EAD}\x{9EAE}\x{9EAF}\x{9EB0}\x{9EB2}\x{9EB3}\x{9EB4}\x{9EB5}\x{9EB6}' . +'\x{9EB7}\x{9EB8}\x{9EBB}\x{9EBC}\x{9EBD}\x{9EBE}\x{9EBF}\x{9EC0}\x{9EC1}' . +'\x{9EC2}\x{9EC3}\x{9EC4}\x{9EC5}\x{9EC6}\x{9EC7}\x{9EC8}\x{9EC9}\x{9ECA}' . +'\x{9ECB}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED1}\x{9ED2}\x{9ED3}' . +'\x{9ED4}\x{9ED5}\x{9ED6}\x{9ED7}\x{9ED8}\x{9ED9}\x{9EDA}\x{9EDB}\x{9EDC}' . +'\x{9EDD}\x{9EDE}\x{9EDF}\x{9EE0}\x{9EE1}\x{9EE2}\x{9EE3}\x{9EE4}\x{9EE5}' . +'\x{9EE6}\x{9EE7}\x{9EE8}\x{9EE9}\x{9EEA}\x{9EEB}\x{9EED}\x{9EEE}\x{9EEF}' . +'\x{9EF0}\x{9EF2}\x{9EF3}\x{9EF4}\x{9EF5}\x{9EF6}\x{9EF7}\x{9EF8}\x{9EF9}' . +'\x{9EFA}\x{9EFB}\x{9EFC}\x{9EFD}\x{9EFE}\x{9EFF}\x{9F00}\x{9F01}\x{9F02}' . +'\x{9F04}\x{9F05}\x{9F06}\x{9F07}\x{9F08}\x{9F09}\x{9F0A}\x{9F0B}\x{9F0C}' . +'\x{9F0D}\x{9F0E}\x{9F0F}\x{9F10}\x{9F12}\x{9F13}\x{9F15}\x{9F16}\x{9F17}' . +'\x{9F18}\x{9F19}\x{9F1A}\x{9F1B}\x{9F1C}\x{9F1D}\x{9F1E}\x{9F1F}\x{9F20}' . +'\x{9F22}\x{9F23}\x{9F24}\x{9F25}\x{9F27}\x{9F28}\x{9F29}\x{9F2A}\x{9F2B}' . +'\x{9F2C}\x{9F2D}\x{9F2E}\x{9F2F}\x{9F30}\x{9F31}\x{9F32}\x{9F33}\x{9F34}' . +'\x{9F35}\x{9F36}\x{9F37}\x{9F38}\x{9F39}\x{9F3A}\x{9F3B}\x{9F3C}\x{9F3D}' . +'\x{9F3E}\x{9F3F}\x{9F40}\x{9F41}\x{9F42}\x{9F43}\x{9F44}\x{9F46}\x{9F47}' . +'\x{9F48}\x{9F49}\x{9F4A}\x{9F4B}\x{9F4C}\x{9F4D}\x{9F4E}\x{9F4F}\x{9F50}' . +'\x{9F51}\x{9F52}\x{9F54}\x{9F55}\x{9F56}\x{9F57}\x{9F58}\x{9F59}\x{9F5A}' . +'\x{9F5B}\x{9F5C}\x{9F5D}\x{9F5E}\x{9F5F}\x{9F60}\x{9F61}\x{9F63}\x{9F64}' . +'\x{9F65}\x{9F66}\x{9F67}\x{9F68}\x{9F69}\x{9F6A}\x{9F6B}\x{9F6C}\x{9F6E}' . +'\x{9F6F}\x{9F70}\x{9F71}\x{9F72}\x{9F73}\x{9F74}\x{9F75}\x{9F76}\x{9F77}' . +'\x{9F78}\x{9F79}\x{9F7A}\x{9F7B}\x{9F7C}\x{9F7D}\x{9F7E}\x{9F7F}\x{9F80}' . +'\x{9F81}\x{9F82}\x{9F83}\x{9F84}\x{9F85}\x{9F86}\x{9F87}\x{9F88}\x{9F89}' . +'\x{9F8A}\x{9F8B}\x{9F8C}\x{9F8D}\x{9F8E}\x{9F8F}\x{9F90}\x{9F91}\x{9F92}' . +'\x{9F93}\x{9F94}\x{9F95}\x{9F96}\x{9F97}\x{9F98}\x{9F99}\x{9F9A}\x{9F9B}' . +'\x{9F9C}\x{9F9D}\x{9F9E}\x{9F9F}\x{9FA0}\x{9FA2}\x{9FA4}\x{9FA5}]{1,20}$/iu'); diff --git a/library/vendor/Zend/Validate/Hostname/Com.php b/library/vendor/Zend/Validate/Hostname/Com.php new file mode 100644 index 000000000..3111fe07a --- /dev/null +++ b/library/vendor/Zend/Validate/Hostname/Com.php @@ -0,0 +1,198 @@ + '/^[\x{002d}0-9\x{0400}-\x{052f}]{1,63}$/iu', + 2 => '/^[\x{002d}0-9\x{0370}-\x{03ff}]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-z\x{ac00}-\x{d7a3}]{1,17}$/iu', + 4 => '/^[\x{002d}0-9a-z·à-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 5 => '/^[\x{002d}0-9A-Za-z\x{3400}-\x{3401}\x{3404}-\x{3406}\x{340C}\x{3416}\x{341C}' . +'\x{3421}\x{3424}\x{3428}-\x{3429}\x{342B}-\x{342E}\x{3430}-\x{3434}\x{3436}' . +'\x{3438}-\x{343C}\x{343E}\x{3441}-\x{3445}\x{3447}\x{3449}-\x{3451}\x{3453}' . +'\x{3457}-\x{345F}\x{3463}-\x{3467}\x{346E}-\x{3471}\x{3473}-\x{3477}\x{3479}-\x{348E}\x{3491}-\x{3497}' . +'\x{3499}-\x{34A1}\x{34A4}-\x{34AD}\x{34AF}-\x{34B0}\x{34B2}-\x{34BF}\x{34C2}-\x{34C5}\x{34C7}-\x{34CC}' . +'\x{34CE}-\x{34D1}\x{34D3}-\x{34D8}\x{34DA}-\x{34E4}\x{34E7}-\x{34E9}\x{34EC}-\x{34EF}\x{34F1}-\x{34FE}' . +'\x{3500}-\x{3507}\x{350A}-\x{3513}\x{3515}\x{3517}-\x{351A}\x{351C}-\x{351E}\x{3520}-\x{352A}' . +'\x{352C}-\x{3552}\x{3554}-\x{355C}\x{355E}-\x{3567}\x{3569}-\x{3573}\x{3575}-\x{357C}\x{3580}-\x{3588}' . +'\x{358F}-\x{3598}\x{359E}-\x{35AB}\x{35B4}-\x{35CD}\x{35D0}\x{35D3}-\x{35DC}\x{35E2}-\x{35ED}' . +'\x{35F0}-\x{35F6}\x{35FB}-\x{3602}\x{3605}-\x{360E}\x{3610}-\x{3611}\x{3613}-\x{3616}\x{3619}-\x{362D}' . +'\x{362F}-\x{3634}\x{3636}-\x{363B}\x{363F}-\x{3645}\x{3647}-\x{364B}\x{364D}-\x{3653}\x{3655}' . +'\x{3659}-\x{365E}\x{3660}-\x{3665}\x{3667}-\x{367C}\x{367E}\x{3680}-\x{3685}\x{3687}' . +'\x{3689}-\x{3690}\x{3692}-\x{3698}\x{369A}\x{369C}-\x{36AE}\x{36B0}-\x{36BF}\x{36C1}-\x{36C5}' . +'\x{36C9}-\x{36CA}\x{36CD}-\x{36DE}\x{36E1}-\x{36E2}\x{36E5}-\x{36FE}\x{3701}-\x{3713}\x{3715}-\x{371E}' . +'\x{3720}-\x{372C}\x{372E}-\x{3745}\x{3747}-\x{3748}\x{374A}\x{374C}-\x{3759}\x{375B}-\x{3760}' . +'\x{3762}-\x{3767}\x{3769}-\x{3772}\x{3774}-\x{378C}\x{378F}-\x{379C}\x{379F}\x{37A1}-\x{37AD}' . +'\x{37AF}-\x{37B7}\x{37B9}-\x{37C1}\x{37C3}-\x{37C5}\x{37C7}-\x{37D4}\x{37D6}-\x{37E0}\x{37E2}' . +'\x{37E5}-\x{37ED}\x{37EF}-\x{37F6}\x{37F8}-\x{3802}\x{3804}-\x{381D}\x{3820}-\x{3822}\x{3825}-\x{382A}' . +'\x{382D}-\x{382F}\x{3831}-\x{3832}\x{3834}-\x{384C}\x{384E}-\x{3860}\x{3862}-\x{3863}\x{3865}-\x{386B}' . +'\x{386D}-\x{3886}\x{3888}-\x{38A1}\x{38A3}\x{38A5}-\x{38AA}\x{38AC}\x{38AE}-\x{38B0}' . +'\x{38B2}-\x{38B6}\x{38B8}\x{38BA}-\x{38BE}\x{38C0}-\x{38C9}\x{38CB}-\x{38D4}\x{38D8}-\x{38E0}' . +'\x{38E2}-\x{38E6}\x{38EB}-\x{38ED}\x{38EF}-\x{38F2}\x{38F5}-\x{38F7}\x{38FA}-\x{38FF}\x{3901}-\x{392A}' . +'\x{392C}\x{392E}-\x{393B}\x{393E}-\x{3956}\x{395A}-\x{3969}\x{396B}-\x{397A}\x{397C}-\x{3987}' . +'\x{3989}-\x{3998}\x{399A}-\x{39B0}\x{39B2}\x{39B4}-\x{39D0}\x{39D2}-\x{39DA}\x{39DE}-\x{39DF}' . +'\x{39E1}-\x{39EF}\x{39F1}-\x{3A17}\x{3A19}-\x{3A2A}\x{3A2D}-\x{3A40}\x{3A43}-\x{3A4E}\x{3A50}' . +'\x{3A52}-\x{3A5E}\x{3A60}-\x{3A6D}\x{3A6F}-\x{3A77}\x{3A79}-\x{3A82}\x{3A84}-\x{3A85}\x{3A87}-\x{3A89}' . +'\x{3A8B}-\x{3A8F}\x{3A91}-\x{3A93}\x{3A95}-\x{3A96}\x{3A9A}\x{3A9C}-\x{3AA6}\x{3AA8}-\x{3AA9}' . +'\x{3AAB}-\x{3AB1}\x{3AB4}-\x{3ABC}\x{3ABE}-\x{3AC5}\x{3ACA}-\x{3ACB}\x{3ACD}-\x{3AD5}\x{3AD7}-\x{3AE1}' . +'\x{3AE4}-\x{3AE7}\x{3AE9}-\x{3AEC}\x{3AEE}-\x{3AFD}\x{3B01}-\x{3B10}\x{3B12}-\x{3B15}\x{3B17}-\x{3B1E}' . +'\x{3B20}-\x{3B23}\x{3B25}-\x{3B27}\x{3B29}-\x{3B36}\x{3B38}-\x{3B39}\x{3B3B}-\x{3B3C}\x{3B3F}' . +'\x{3B41}-\x{3B44}\x{3B47}-\x{3B4C}\x{3B4E}\x{3B51}-\x{3B55}\x{3B58}-\x{3B62}\x{3B68}-\x{3B72}' . +'\x{3B78}-\x{3B88}\x{3B8B}-\x{3B9F}\x{3BA1}\x{3BA3}-\x{3BBA}\x{3BBC}\x{3BBF}-\x{3BD0}' . +'\x{3BD3}-\x{3BE6}\x{3BEA}-\x{3BFB}\x{3BFE}-\x{3C12}\x{3C14}-\x{3C1B}\x{3C1D}-\x{3C37}\x{3C39}-\x{3C4F}' . +'\x{3C52}\x{3C54}-\x{3C5C}\x{3C5E}-\x{3C68}\x{3C6A}-\x{3C76}\x{3C78}-\x{3C8F}\x{3C91}-\x{3CA8}' . +'\x{3CAA}-\x{3CAD}\x{3CAF}-\x{3CBE}\x{3CC0}-\x{3CC8}\x{3CCA}-\x{3CD3}\x{3CD6}-\x{3CE0}\x{3CE4}-\x{3CEE}' . +'\x{3CF3}-\x{3D0A}\x{3D0E}-\x{3D1E}\x{3D20}-\x{3D21}\x{3D25}-\x{3D38}\x{3D3B}-\x{3D46}\x{3D4A}-\x{3D59}' . +'\x{3D5D}-\x{3D7B}\x{3D7D}-\x{3D81}\x{3D84}-\x{3D88}\x{3D8C}-\x{3D8F}\x{3D91}-\x{3D98}\x{3D9A}-\x{3D9C}' . +'\x{3D9E}-\x{3DA1}\x{3DA3}-\x{3DB0}\x{3DB2}-\x{3DB5}\x{3DB9}-\x{3DBC}\x{3DBE}-\x{3DCB}\x{3DCD}-\x{3DDB}' . +'\x{3DDF}-\x{3DE8}\x{3DEB}-\x{3DF0}\x{3DF3}-\x{3DF9}\x{3DFB}-\x{3DFC}\x{3DFE}-\x{3E05}\x{3E08}-\x{3E33}' . +'\x{3E35}-\x{3E3E}\x{3E40}-\x{3E47}\x{3E49}-\x{3E67}\x{3E6B}-\x{3E6F}\x{3E71}-\x{3E85}\x{3E87}-\x{3E8C}' . +'\x{3E8E}-\x{3E98}\x{3E9A}-\x{3EA1}\x{3EA3}-\x{3EAE}\x{3EB0}-\x{3EB5}\x{3EB7}-\x{3EBA}\x{3EBD}' . +'\x{3EBF}-\x{3EC4}\x{3EC7}-\x{3ECE}\x{3ED1}-\x{3ED7}\x{3ED9}-\x{3EDA}\x{3EDD}-\x{3EE3}\x{3EE7}-\x{3EE8}' . +'\x{3EEB}-\x{3EF2}\x{3EF5}-\x{3EFF}\x{3F01}-\x{3F02}\x{3F04}-\x{3F07}\x{3F09}-\x{3F44}\x{3F46}-\x{3F4E}' . +'\x{3F50}-\x{3F53}\x{3F55}-\x{3F72}\x{3F74}-\x{3F75}\x{3F77}-\x{3F7B}\x{3F7D}-\x{3FB0}\x{3FB6}-\x{3FBF}' . +'\x{3FC1}-\x{3FCF}\x{3FD1}-\x{3FD3}\x{3FD5}-\x{3FDF}\x{3FE1}-\x{400B}\x{400D}-\x{401C}\x{401E}-\x{4024}' . +'\x{4027}-\x{403F}\x{4041}-\x{4060}\x{4062}-\x{4069}\x{406B}-\x{408A}\x{408C}-\x{40A7}\x{40A9}-\x{40B4}' . +'\x{40B6}-\x{40C2}\x{40C7}-\x{40CF}\x{40D1}-\x{40DE}\x{40E0}-\x{40E7}\x{40E9}-\x{40EE}\x{40F0}-\x{40FB}' . +'\x{40FD}-\x{4109}\x{410B}-\x{4115}\x{4118}-\x{411D}\x{411F}-\x{4122}\x{4124}-\x{4133}\x{4136}-\x{4138}' . +'\x{413A}-\x{4148}\x{414A}-\x{4169}\x{416C}-\x{4185}\x{4188}-\x{418B}\x{418D}-\x{41AD}\x{41AF}-\x{41B3}' . +'\x{41B5}-\x{41C3}\x{41C5}-\x{41C9}\x{41CB}-\x{41F2}\x{41F5}-\x{41FE}\x{4200}-\x{4227}\x{422A}-\x{4246}' . +'\x{4248}-\x{4263}\x{4265}-\x{428B}\x{428D}-\x{42A1}\x{42A3}-\x{42C4}\x{42C8}-\x{42DC}\x{42DE}-\x{430A}' . +'\x{430C}-\x{4335}\x{4337}\x{4342}-\x{435F}\x{4361}-\x{439A}\x{439C}-\x{439D}\x{439F}-\x{43A4}' . +'\x{43A6}-\x{43EC}\x{43EF}-\x{4405}\x{4407}-\x{4429}\x{442B}-\x{4455}\x{4457}-\x{4468}\x{446A}-\x{446D}' . +'\x{446F}-\x{4476}\x{4479}-\x{447D}\x{447F}-\x{4486}\x{4488}-\x{4490}\x{4492}-\x{4498}\x{449A}-\x{44AD}' . +'\x{44B0}-\x{44BD}\x{44C1}-\x{44D3}\x{44D6}-\x{44E7}\x{44EA}\x{44EC}-\x{44FA}\x{44FC}-\x{4541}' . +'\x{4543}-\x{454F}\x{4551}-\x{4562}\x{4564}-\x{4575}\x{4577}-\x{45AB}\x{45AD}-\x{45BD}\x{45BF}-\x{45D5}' . +'\x{45D7}-\x{45EC}\x{45EE}-\x{45F2}\x{45F4}-\x{45FA}\x{45FC}-\x{461A}\x{461C}-\x{461D}\x{461F}-\x{4631}' . +'\x{4633}-\x{4649}\x{464C}\x{464E}-\x{4652}\x{4654}-\x{466A}\x{466C}-\x{4675}\x{4677}-\x{467A}' . +'\x{467C}-\x{4694}\x{4696}-\x{46A3}\x{46A5}-\x{46AB}\x{46AD}-\x{46D2}\x{46D4}-\x{4723}\x{4729}-\x{4732}' . +'\x{4734}-\x{4758}\x{475A}\x{475C}-\x{478B}\x{478D}\x{4791}-\x{47B1}\x{47B3}-\x{47F1}' . +'\x{47F3}-\x{480B}\x{480D}-\x{4815}\x{4817}-\x{4839}\x{483B}-\x{4870}\x{4872}-\x{487A}\x{487C}-\x{487F}' . +'\x{4883}-\x{488E}\x{4890}-\x{4896}\x{4899}-\x{48A2}\x{48A4}-\x{48B9}\x{48BB}-\x{48C8}\x{48CA}-\x{48D1}' . +'\x{48D3}-\x{48E5}\x{48E7}-\x{48F2}\x{48F4}-\x{48FF}\x{4901}-\x{4922}\x{4924}-\x{4928}\x{492A}-\x{4931}' . +'\x{4933}-\x{495B}\x{495D}-\x{4978}\x{497A}\x{497D}\x{4982}-\x{4983}\x{4985}-\x{49A8}' . +'\x{49AA}-\x{49AF}\x{49B1}-\x{49B7}\x{49B9}-\x{49BD}\x{49C1}-\x{49C7}\x{49C9}-\x{49CE}\x{49D0}-\x{49E8}' . +'\x{49EA}\x{49EC}\x{49EE}-\x{4A19}\x{4A1B}-\x{4A43}\x{4A45}-\x{4A4D}\x{4A4F}-\x{4A9E}' . +'\x{4AA0}-\x{4AA9}\x{4AAB}-\x{4B4E}\x{4B50}-\x{4B5B}\x{4B5D}-\x{4B69}\x{4B6B}-\x{4BC2}\x{4BC6}-\x{4BE8}' . +'\x{4BEA}-\x{4BFA}\x{4BFC}-\x{4C06}\x{4C08}-\x{4C2D}\x{4C2F}-\x{4C32}\x{4C34}-\x{4C35}\x{4C37}-\x{4C69}' . +'\x{4C6B}-\x{4C73}\x{4C75}-\x{4C86}\x{4C88}-\x{4C97}\x{4C99}-\x{4C9C}\x{4C9F}-\x{4CA3}\x{4CA5}-\x{4CB5}' . +'\x{4CB7}-\x{4CF8}\x{4CFA}-\x{4D27}\x{4D29}-\x{4DAC}\x{4DAE}-\x{4DB1}\x{4DB3}-\x{4DB5}\x{4E00}-\x{4E54}' . +'\x{4E56}-\x{4E89}\x{4E8B}-\x{4EEC}\x{4EEE}-\x{4FAC}\x{4FAE}-\x{503C}\x{503E}-\x{51E5}\x{51E7}-\x{5270}' . +'\x{5272}-\x{56A1}\x{56A3}-\x{5840}\x{5842}-\x{58B5}\x{58B7}-\x{58CB}\x{58CD}-\x{5BC8}\x{5BCA}-\x{5C01}' . +'\x{5C03}-\x{5C25}\x{5C27}-\x{5D5B}\x{5D5D}-\x{5F08}\x{5F0A}-\x{61F3}\x{61F5}-\x{63BA}\x{63BC}-\x{6441}' . +'\x{6443}-\x{657C}\x{657E}-\x{663E}\x{6640}-\x{66FC}\x{66FE}-\x{6728}\x{672A}-\x{6766}\x{6768}-\x{67A8}' . +'\x{67AA}-\x{685B}\x{685D}-\x{685E}\x{6860}-\x{68B9}\x{68BB}-\x{6AC8}\x{6ACA}-\x{6BB0}\x{6BB2}-\x{6C16}' . +'\x{6C18}-\x{6D9B}\x{6D9D}-\x{6E12}\x{6E14}-\x{6E8B}\x{6E8D}-\x{704D}\x{704F}-\x{7113}\x{7115}-\x{713B}' . +'\x{713D}-\x{7154}\x{7156}-\x{729F}\x{72A1}-\x{731E}\x{7320}-\x{7362}\x{7364}-\x{7533}\x{7535}-\x{7551}' . +'\x{7553}-\x{7572}\x{7574}-\x{75E8}\x{75EA}-\x{7679}\x{767B}-\x{783E}\x{7840}-\x{7A62}\x{7A64}-\x{7AC2}' . +'\x{7AC4}-\x{7B06}\x{7B08}-\x{7B79}\x{7B7B}-\x{7BCE}\x{7BD0}-\x{7D99}\x{7D9B}-\x{7E49}\x{7E4C}-\x{8132}' . +'\x{8134}\x{8136}-\x{81D2}\x{81D4}-\x{8216}\x{8218}-\x{822D}\x{822F}-\x{83B4}\x{83B6}-\x{841F}' . +'\x{8421}-\x{86CC}\x{86CE}-\x{874A}\x{874C}-\x{877E}\x{8780}-\x{8A32}\x{8A34}-\x{8B71}\x{8B73}-\x{8B8E}' . +'\x{8B90}-\x{8DE4}\x{8DE6}-\x{8E9A}\x{8E9C}-\x{8EE1}\x{8EE4}-\x{8F0B}\x{8F0D}-\x{8FB9}\x{8FBB}-\x{9038}' . +'\x{903A}-\x{9196}\x{9198}-\x{91A3}\x{91A5}-\x{91B7}\x{91B9}-\x{91C7}\x{91C9}-\x{91E0}\x{91E2}-\x{91FB}' . +'\x{91FD}-\x{922B}\x{922D}-\x{9270}\x{9272}-\x{9420}\x{9422}-\x{9664}\x{9666}-\x{9679}\x{967B}-\x{9770}' . +'\x{9772}-\x{982B}\x{982D}-\x{98ED}\x{98EF}-\x{99C4}\x{99C6}-\x{9A11}\x{9A14}-\x{9A27}\x{9A29}-\x{9D0D}' . +'\x{9D0F}-\x{9D2B}\x{9D2D}-\x{9D8E}\x{9D90}-\x{9DC5}\x{9DC7}-\x{9E77}\x{9E79}-\x{9EB8}\x{9EBB}-\x{9F20}' . +'\x{9F22}-\x{9F61}\x{9F63}-\x{9FA5}\x{FA28}]{1,20}$/iu', + 6 => '/^[\x{002d}0-9A-Za-z]{1,63}$/iu', + 7 => '/^[\x{00A1}-\x{00FF}]{1,63}$/iu', + 8 => '/^[\x{0100}-\x{017f}]{1,63}$/iu', + 9 => '/^[\x{0180}-\x{024f}]{1,63}$/iu', + 10 => '/^[\x{0250}-\x{02af}]{1,63}$/iu', + 11 => '/^[\x{02b0}-\x{02ff}]{1,63}$/iu', + 12 => '/^[\x{0300}-\x{036f}]{1,63}$/iu', + 13 => '/^[\x{0370}-\x{03ff}]{1,63}$/iu', + 14 => '/^[\x{0400}-\x{04ff}]{1,63}$/iu', + 15 => '/^[\x{0500}-\x{052f}]{1,63}$/iu', + 16 => '/^[\x{0530}-\x{058F}]{1,63}$/iu', + 17 => '/^[\x{0590}-\x{05FF}]{1,63}$/iu', + 18 => '/^[\x{0600}-\x{06FF}]{1,63}$/iu', + 19 => '/^[\x{0700}-\x{074F}]{1,63}$/iu', + 20 => '/^[\x{0780}-\x{07BF}]{1,63}$/iu', + 21 => '/^[\x{0900}-\x{097F}]{1,63}$/iu', + 22 => '/^[\x{0980}-\x{09FF}]{1,63}$/iu', + 23 => '/^[\x{0A00}-\x{0A7F}]{1,63}$/iu', + 24 => '/^[\x{0A80}-\x{0AFF}]{1,63}$/iu', + 25 => '/^[\x{0B00}-\x{0B7F}]{1,63}$/iu', + 26 => '/^[\x{0B80}-\x{0BFF}]{1,63}$/iu', + 27 => '/^[\x{0C00}-\x{0C7F}]{1,63}$/iu', + 28 => '/^[\x{0C80}-\x{0CFF}]{1,63}$/iu', + 29 => '/^[\x{0D00}-\x{0D7F}]{1,63}$/iu', + 30 => '/^[\x{0D80}-\x{0DFF}]{1,63}$/iu', + 31 => '/^[\x{0E00}-\x{0E7F}]{1,63}$/iu', + 32 => '/^[\x{0E80}-\x{0EFF}]{1,63}$/iu', + 33 => '/^[\x{0F00}-\x{0FFF}]{1,63}$/iu', + 34 => '/^[\x{1000}-\x{109F}]{1,63}$/iu', + 35 => '/^[\x{10A0}-\x{10FF}]{1,63}$/iu', + 36 => '/^[\x{1100}-\x{11FF}]{1,63}$/iu', + 37 => '/^[\x{1200}-\x{137F}]{1,63}$/iu', + 38 => '/^[\x{13A0}-\x{13FF}]{1,63}$/iu', + 39 => '/^[\x{1400}-\x{167F}]{1,63}$/iu', + 40 => '/^[\x{1680}-\x{169F}]{1,63}$/iu', + 41 => '/^[\x{16A0}-\x{16FF}]{1,63}$/iu', + 42 => '/^[\x{1700}-\x{171F}]{1,63}$/iu', + 43 => '/^[\x{1720}-\x{173F}]{1,63}$/iu', + 44 => '/^[\x{1740}-\x{175F}]{1,63}$/iu', + 45 => '/^[\x{1760}-\x{177F}]{1,63}$/iu', + 46 => '/^[\x{1780}-\x{17FF}]{1,63}$/iu', + 47 => '/^[\x{1800}-\x{18AF}]{1,63}$/iu', + 48 => '/^[\x{1E00}-\x{1EFF}]{1,63}$/iu', + 49 => '/^[\x{1F00}-\x{1FFF}]{1,63}$/iu', + 50 => '/^[\x{2070}-\x{209F}]{1,63}$/iu', + 51 => '/^[\x{2100}-\x{214F}]{1,63}$/iu', + 52 => '/^[\x{2150}-\x{218F}]{1,63}$/iu', + 53 => '/^[\x{2460}-\x{24FF}]{1,63}$/iu', + 54 => '/^[\x{2E80}-\x{2EFF}]{1,63}$/iu', + 55 => '/^[\x{2F00}-\x{2FDF}]{1,63}$/iu', + 56 => '/^[\x{2FF0}-\x{2FFF}]{1,63}$/iu', + 57 => '/^[\x{3040}-\x{309F}]{1,63}$/iu', + 58 => '/^[\x{30A0}-\x{30FF}]{1,63}$/iu', + 59 => '/^[\x{3100}-\x{312F}]{1,63}$/iu', + 60 => '/^[\x{3130}-\x{318F}]{1,63}$/iu', + 61 => '/^[\x{3190}-\x{319F}]{1,63}$/iu', + 62 => '/^[\x{31A0}-\x{31BF}]{1,63}$/iu', + 63 => '/^[\x{31F0}-\x{31FF}]{1,63}$/iu', + 64 => '/^[\x{3200}-\x{32FF}]{1,63}$/iu', + 65 => '/^[\x{3300}-\x{33FF}]{1,63}$/iu', + 66 => '/^[\x{3400}-\x{4DBF}]{1,63}$/iu', + 67 => '/^[\x{4E00}-\x{9FFF}]{1,63}$/iu', + 68 => '/^[\x{A000}-\x{A48F}]{1,63}$/iu', + 69 => '/^[\x{A490}-\x{A4CF}]{1,63}$/iu', + 70 => '/^[\x{AC00}-\x{D7AF}]{1,63}$/iu', + 71 => '/^[\x{D800}-\x{DB7F}]{1,63}$/iu', + 72 => '/^[\x{DC00}-\x{DFFF}]{1,63}$/iu', + 73 => '/^[\x{F900}-\x{FAFF}]{1,63}$/iu', + 74 => '/^[\x{FB00}-\x{FB4F}]{1,63}$/iu', + 75 => '/^[\x{FB50}-\x{FDFF}]{1,63}$/iu', + 76 => '/^[\x{FE20}-\x{FE2F}]{1,63}$/iu', + 77 => '/^[\x{FE70}-\x{FEFF}]{1,63}$/iu', + 78 => '/^[\x{FF00}-\x{FFEF}]{1,63}$/iu', + 79 => '/^[\x{20000}-\x{2A6DF}]{1,63}$/iu', + 80 => '/^[\x{2F800}-\x{2FA1F}]{1,63}$/iu' + +); diff --git a/library/vendor/Zend/Validate/Hostname/Jp.php b/library/vendor/Zend/Validate/Hostname/Jp.php new file mode 100644 index 000000000..a66ca39c7 --- /dev/null +++ b/library/vendor/Zend/Validate/Hostname/Jp.php @@ -0,0 +1,739 @@ + '/^[\x{002d}0-9a-z\x{3005}-\x{3007}\x{3041}-\x{3093}\x{309D}\x{309E}' . +'\x{30A1}-\x{30F6}\x{30FC}' . +'\x{30FD}\x{30FE}\x{4E00}\x{4E01}\x{4E03}\x{4E07}\x{4E08}\x{4E09}\x{4E0A}' . +'\x{4E0B}\x{4E0D}\x{4E0E}\x{4E10}\x{4E11}\x{4E14}\x{4E15}\x{4E16}\x{4E17}' . +'\x{4E18}\x{4E19}\x{4E1E}\x{4E21}\x{4E26}\x{4E2A}\x{4E2D}\x{4E31}\x{4E32}' . +'\x{4E36}\x{4E38}\x{4E39}\x{4E3B}\x{4E3C}\x{4E3F}\x{4E42}\x{4E43}\x{4E45}' . +'\x{4E4B}\x{4E4D}\x{4E4E}\x{4E4F}\x{4E55}\x{4E56}\x{4E57}\x{4E58}\x{4E59}' . +'\x{4E5D}\x{4E5E}\x{4E5F}\x{4E62}\x{4E71}\x{4E73}\x{4E7E}\x{4E80}\x{4E82}' . +'\x{4E85}\x{4E86}\x{4E88}\x{4E89}\x{4E8A}\x{4E8B}\x{4E8C}\x{4E8E}\x{4E91}' . +'\x{4E92}\x{4E94}\x{4E95}\x{4E98}\x{4E99}\x{4E9B}\x{4E9C}\x{4E9E}\x{4E9F}' . +'\x{4EA0}\x{4EA1}\x{4EA2}\x{4EA4}\x{4EA5}\x{4EA6}\x{4EA8}\x{4EAB}\x{4EAC}' . +'\x{4EAD}\x{4EAE}\x{4EB0}\x{4EB3}\x{4EB6}\x{4EBA}\x{4EC0}\x{4EC1}\x{4EC2}' . +'\x{4EC4}\x{4EC6}\x{4EC7}\x{4ECA}\x{4ECB}\x{4ECD}\x{4ECE}\x{4ECF}\x{4ED4}' . +'\x{4ED5}\x{4ED6}\x{4ED7}\x{4ED8}\x{4ED9}\x{4EDD}\x{4EDE}\x{4EDF}\x{4EE3}' . +'\x{4EE4}\x{4EE5}\x{4EED}\x{4EEE}\x{4EF0}\x{4EF2}\x{4EF6}\x{4EF7}\x{4EFB}' . +'\x{4F01}\x{4F09}\x{4F0A}\x{4F0D}\x{4F0E}\x{4F0F}\x{4F10}\x{4F11}\x{4F1A}' . +'\x{4F1C}\x{4F1D}\x{4F2F}\x{4F30}\x{4F34}\x{4F36}\x{4F38}\x{4F3A}\x{4F3C}' . +'\x{4F3D}\x{4F43}\x{4F46}\x{4F47}\x{4F4D}\x{4F4E}\x{4F4F}\x{4F50}\x{4F51}' . +'\x{4F53}\x{4F55}\x{4F57}\x{4F59}\x{4F5A}\x{4F5B}\x{4F5C}\x{4F5D}\x{4F5E}' . +'\x{4F69}\x{4F6F}\x{4F70}\x{4F73}\x{4F75}\x{4F76}\x{4F7B}\x{4F7C}\x{4F7F}' . +'\x{4F83}\x{4F86}\x{4F88}\x{4F8B}\x{4F8D}\x{4F8F}\x{4F91}\x{4F96}\x{4F98}' . +'\x{4F9B}\x{4F9D}\x{4FA0}\x{4FA1}\x{4FAB}\x{4FAD}\x{4FAE}\x{4FAF}\x{4FB5}' . +'\x{4FB6}\x{4FBF}\x{4FC2}\x{4FC3}\x{4FC4}\x{4FCA}\x{4FCE}\x{4FD0}\x{4FD1}' . +'\x{4FD4}\x{4FD7}\x{4FD8}\x{4FDA}\x{4FDB}\x{4FDD}\x{4FDF}\x{4FE1}\x{4FE3}' . +'\x{4FE4}\x{4FE5}\x{4FEE}\x{4FEF}\x{4FF3}\x{4FF5}\x{4FF6}\x{4FF8}\x{4FFA}' . +'\x{4FFE}\x{5005}\x{5006}\x{5009}\x{500B}\x{500D}\x{500F}\x{5011}\x{5012}' . +'\x{5014}\x{5016}\x{5019}\x{501A}\x{501F}\x{5021}\x{5023}\x{5024}\x{5025}' . +'\x{5026}\x{5028}\x{5029}\x{502A}\x{502B}\x{502C}\x{502D}\x{5036}\x{5039}' . +'\x{5043}\x{5047}\x{5048}\x{5049}\x{504F}\x{5050}\x{5055}\x{5056}\x{505A}' . +'\x{505C}\x{5065}\x{506C}\x{5072}\x{5074}\x{5075}\x{5076}\x{5078}\x{507D}' . +'\x{5080}\x{5085}\x{508D}\x{5091}\x{5098}\x{5099}\x{509A}\x{50AC}\x{50AD}' . +'\x{50B2}\x{50B3}\x{50B4}\x{50B5}\x{50B7}\x{50BE}\x{50C2}\x{50C5}\x{50C9}' . +'\x{50CA}\x{50CD}\x{50CF}\x{50D1}\x{50D5}\x{50D6}\x{50DA}\x{50DE}\x{50E3}' . +'\x{50E5}\x{50E7}\x{50ED}\x{50EE}\x{50F5}\x{50F9}\x{50FB}\x{5100}\x{5101}' . +'\x{5102}\x{5104}\x{5109}\x{5112}\x{5114}\x{5115}\x{5116}\x{5118}\x{511A}' . +'\x{511F}\x{5121}\x{512A}\x{5132}\x{5137}\x{513A}\x{513B}\x{513C}\x{513F}' . +'\x{5140}\x{5141}\x{5143}\x{5144}\x{5145}\x{5146}\x{5147}\x{5148}\x{5149}' . +'\x{514B}\x{514C}\x{514D}\x{514E}\x{5150}\x{5152}\x{5154}\x{515A}\x{515C}' . +'\x{5162}\x{5165}\x{5168}\x{5169}\x{516A}\x{516B}\x{516C}\x{516D}\x{516E}' . +'\x{5171}\x{5175}\x{5176}\x{5177}\x{5178}\x{517C}\x{5180}\x{5182}\x{5185}' . +'\x{5186}\x{5189}\x{518A}\x{518C}\x{518D}\x{518F}\x{5190}\x{5191}\x{5192}' . +'\x{5193}\x{5195}\x{5196}\x{5197}\x{5199}\x{51A0}\x{51A2}\x{51A4}\x{51A5}' . +'\x{51A6}\x{51A8}\x{51A9}\x{51AA}\x{51AB}\x{51AC}\x{51B0}\x{51B1}\x{51B2}' . +'\x{51B3}\x{51B4}\x{51B5}\x{51B6}\x{51B7}\x{51BD}\x{51C4}\x{51C5}\x{51C6}' . +'\x{51C9}\x{51CB}\x{51CC}\x{51CD}\x{51D6}\x{51DB}\x{51DC}\x{51DD}\x{51E0}' . +'\x{51E1}\x{51E6}\x{51E7}\x{51E9}\x{51EA}\x{51ED}\x{51F0}\x{51F1}\x{51F5}' . +'\x{51F6}\x{51F8}\x{51F9}\x{51FA}\x{51FD}\x{51FE}\x{5200}\x{5203}\x{5204}' . +'\x{5206}\x{5207}\x{5208}\x{520A}\x{520B}\x{520E}\x{5211}\x{5214}\x{5217}' . +'\x{521D}\x{5224}\x{5225}\x{5227}\x{5229}\x{522A}\x{522E}\x{5230}\x{5233}' . +'\x{5236}\x{5237}\x{5238}\x{5239}\x{523A}\x{523B}\x{5243}\x{5244}\x{5247}' . +'\x{524A}\x{524B}\x{524C}\x{524D}\x{524F}\x{5254}\x{5256}\x{525B}\x{525E}' . +'\x{5263}\x{5264}\x{5265}\x{5269}\x{526A}\x{526F}\x{5270}\x{5271}\x{5272}' . +'\x{5273}\x{5274}\x{5275}\x{527D}\x{527F}\x{5283}\x{5287}\x{5288}\x{5289}' . +'\x{528D}\x{5291}\x{5292}\x{5294}\x{529B}\x{529F}\x{52A0}\x{52A3}\x{52A9}' . +'\x{52AA}\x{52AB}\x{52AC}\x{52AD}\x{52B1}\x{52B4}\x{52B5}\x{52B9}\x{52BC}' . +'\x{52BE}\x{52C1}\x{52C3}\x{52C5}\x{52C7}\x{52C9}\x{52CD}\x{52D2}\x{52D5}' . +'\x{52D7}\x{52D8}\x{52D9}\x{52DD}\x{52DE}\x{52DF}\x{52E0}\x{52E2}\x{52E3}' . +'\x{52E4}\x{52E6}\x{52E7}\x{52F2}\x{52F3}\x{52F5}\x{52F8}\x{52F9}\x{52FA}' . +'\x{52FE}\x{52FF}\x{5301}\x{5302}\x{5305}\x{5306}\x{5308}\x{530D}\x{530F}' . +'\x{5310}\x{5315}\x{5316}\x{5317}\x{5319}\x{531A}\x{531D}\x{5320}\x{5321}' . +'\x{5323}\x{532A}\x{532F}\x{5331}\x{5333}\x{5338}\x{5339}\x{533A}\x{533B}' . +'\x{533F}\x{5340}\x{5341}\x{5343}\x{5345}\x{5346}\x{5347}\x{5348}\x{5349}' . +'\x{534A}\x{534D}\x{5351}\x{5352}\x{5353}\x{5354}\x{5357}\x{5358}\x{535A}' . +'\x{535C}\x{535E}\x{5360}\x{5366}\x{5369}\x{536E}\x{536F}\x{5370}\x{5371}' . +'\x{5373}\x{5374}\x{5375}\x{5377}\x{5378}\x{537B}\x{537F}\x{5382}\x{5384}' . +'\x{5396}\x{5398}\x{539A}\x{539F}\x{53A0}\x{53A5}\x{53A6}\x{53A8}\x{53A9}' . +'\x{53AD}\x{53AE}\x{53B0}\x{53B3}\x{53B6}\x{53BB}\x{53C2}\x{53C3}\x{53C8}' . +'\x{53C9}\x{53CA}\x{53CB}\x{53CC}\x{53CD}\x{53CE}\x{53D4}\x{53D6}\x{53D7}' . +'\x{53D9}\x{53DB}\x{53DF}\x{53E1}\x{53E2}\x{53E3}\x{53E4}\x{53E5}\x{53E8}' . +'\x{53E9}\x{53EA}\x{53EB}\x{53EC}\x{53ED}\x{53EE}\x{53EF}\x{53F0}\x{53F1}' . +'\x{53F2}\x{53F3}\x{53F6}\x{53F7}\x{53F8}\x{53FA}\x{5401}\x{5403}\x{5404}' . +'\x{5408}\x{5409}\x{540A}\x{540B}\x{540C}\x{540D}\x{540E}\x{540F}\x{5410}' . +'\x{5411}\x{541B}\x{541D}\x{541F}\x{5420}\x{5426}\x{5429}\x{542B}\x{542C}' . +'\x{542D}\x{542E}\x{5436}\x{5438}\x{5439}\x{543B}\x{543C}\x{543D}\x{543E}' . +'\x{5440}\x{5442}\x{5446}\x{5448}\x{5449}\x{544A}\x{544E}\x{5451}\x{545F}' . +'\x{5468}\x{546A}\x{5470}\x{5471}\x{5473}\x{5475}\x{5476}\x{5477}\x{547B}' . +'\x{547C}\x{547D}\x{5480}\x{5484}\x{5486}\x{548B}\x{548C}\x{548E}\x{548F}' . +'\x{5490}\x{5492}\x{54A2}\x{54A4}\x{54A5}\x{54A8}\x{54AB}\x{54AC}\x{54AF}' . +'\x{54B2}\x{54B3}\x{54B8}\x{54BC}\x{54BD}\x{54BE}\x{54C0}\x{54C1}\x{54C2}' . +'\x{54C4}\x{54C7}\x{54C8}\x{54C9}\x{54D8}\x{54E1}\x{54E2}\x{54E5}\x{54E6}' . +'\x{54E8}\x{54E9}\x{54ED}\x{54EE}\x{54F2}\x{54FA}\x{54FD}\x{5504}\x{5506}' . +'\x{5507}\x{550F}\x{5510}\x{5514}\x{5516}\x{552E}\x{552F}\x{5531}\x{5533}' . +'\x{5538}\x{5539}\x{553E}\x{5540}\x{5544}\x{5545}\x{5546}\x{554C}\x{554F}' . +'\x{5553}\x{5556}\x{5557}\x{555C}\x{555D}\x{5563}\x{557B}\x{557C}\x{557E}' . +'\x{5580}\x{5583}\x{5584}\x{5587}\x{5589}\x{558A}\x{558B}\x{5598}\x{5599}' . +'\x{559A}\x{559C}\x{559D}\x{559E}\x{559F}\x{55A7}\x{55A8}\x{55A9}\x{55AA}' . +'\x{55AB}\x{55AC}\x{55AE}\x{55B0}\x{55B6}\x{55C4}\x{55C5}\x{55C7}\x{55D4}' . +'\x{55DA}\x{55DC}\x{55DF}\x{55E3}\x{55E4}\x{55F7}\x{55F9}\x{55FD}\x{55FE}' . +'\x{5606}\x{5609}\x{5614}\x{5616}\x{5617}\x{5618}\x{561B}\x{5629}\x{562F}' . +'\x{5631}\x{5632}\x{5634}\x{5636}\x{5638}\x{5642}\x{564C}\x{564E}\x{5650}' . +'\x{565B}\x{5664}\x{5668}\x{566A}\x{566B}\x{566C}\x{5674}\x{5678}\x{567A}' . +'\x{5680}\x{5686}\x{5687}\x{568A}\x{568F}\x{5694}\x{56A0}\x{56A2}\x{56A5}' . +'\x{56AE}\x{56B4}\x{56B6}\x{56BC}\x{56C0}\x{56C1}\x{56C2}\x{56C3}\x{56C8}' . +'\x{56CE}\x{56D1}\x{56D3}\x{56D7}\x{56D8}\x{56DA}\x{56DB}\x{56DE}\x{56E0}' . +'\x{56E3}\x{56EE}\x{56F0}\x{56F2}\x{56F3}\x{56F9}\x{56FA}\x{56FD}\x{56FF}' . +'\x{5700}\x{5703}\x{5704}\x{5708}\x{5709}\x{570B}\x{570D}\x{570F}\x{5712}' . +'\x{5713}\x{5716}\x{5718}\x{571C}\x{571F}\x{5726}\x{5727}\x{5728}\x{572D}' . +'\x{5730}\x{5737}\x{5738}\x{573B}\x{5740}\x{5742}\x{5747}\x{574A}\x{574E}' . +'\x{574F}\x{5750}\x{5751}\x{5761}\x{5764}\x{5766}\x{5769}\x{576A}\x{577F}' . +'\x{5782}\x{5788}\x{5789}\x{578B}\x{5793}\x{57A0}\x{57A2}\x{57A3}\x{57A4}' . +'\x{57AA}\x{57B0}\x{57B3}\x{57C0}\x{57C3}\x{57C6}\x{57CB}\x{57CE}\x{57D2}' . +'\x{57D3}\x{57D4}\x{57D6}\x{57DC}\x{57DF}\x{57E0}\x{57E3}\x{57F4}\x{57F7}' . +'\x{57F9}\x{57FA}\x{57FC}\x{5800}\x{5802}\x{5805}\x{5806}\x{580A}\x{580B}' . +'\x{5815}\x{5819}\x{581D}\x{5821}\x{5824}\x{582A}\x{582F}\x{5830}\x{5831}' . +'\x{5834}\x{5835}\x{583A}\x{583D}\x{5840}\x{5841}\x{584A}\x{584B}\x{5851}' . +'\x{5852}\x{5854}\x{5857}\x{5858}\x{5859}\x{585A}\x{585E}\x{5862}\x{5869}' . +'\x{586B}\x{5870}\x{5872}\x{5875}\x{5879}\x{587E}\x{5883}\x{5885}\x{5893}' . +'\x{5897}\x{589C}\x{589F}\x{58A8}\x{58AB}\x{58AE}\x{58B3}\x{58B8}\x{58B9}' . +'\x{58BA}\x{58BB}\x{58BE}\x{58C1}\x{58C5}\x{58C7}\x{58CA}\x{58CC}\x{58D1}' . +'\x{58D3}\x{58D5}\x{58D7}\x{58D8}\x{58D9}\x{58DC}\x{58DE}\x{58DF}\x{58E4}' . +'\x{58E5}\x{58EB}\x{58EC}\x{58EE}\x{58EF}\x{58F0}\x{58F1}\x{58F2}\x{58F7}' . +'\x{58F9}\x{58FA}\x{58FB}\x{58FC}\x{58FD}\x{5902}\x{5909}\x{590A}\x{590F}' . +'\x{5910}\x{5915}\x{5916}\x{5918}\x{5919}\x{591A}\x{591B}\x{591C}\x{5922}' . +'\x{5925}\x{5927}\x{5929}\x{592A}\x{592B}\x{592C}\x{592D}\x{592E}\x{5931}' . +'\x{5932}\x{5937}\x{5938}\x{593E}\x{5944}\x{5947}\x{5948}\x{5949}\x{594E}' . +'\x{594F}\x{5950}\x{5951}\x{5954}\x{5955}\x{5957}\x{5958}\x{595A}\x{5960}' . +'\x{5962}\x{5965}\x{5967}\x{5968}\x{5969}\x{596A}\x{596C}\x{596E}\x{5973}' . +'\x{5974}\x{5978}\x{597D}\x{5981}\x{5982}\x{5983}\x{5984}\x{598A}\x{598D}' . +'\x{5993}\x{5996}\x{5999}\x{599B}\x{599D}\x{59A3}\x{59A5}\x{59A8}\x{59AC}' . +'\x{59B2}\x{59B9}\x{59BB}\x{59BE}\x{59C6}\x{59C9}\x{59CB}\x{59D0}\x{59D1}' . +'\x{59D3}\x{59D4}\x{59D9}\x{59DA}\x{59DC}\x{59E5}\x{59E6}\x{59E8}\x{59EA}' . +'\x{59EB}\x{59F6}\x{59FB}\x{59FF}\x{5A01}\x{5A03}\x{5A09}\x{5A11}\x{5A18}' . +'\x{5A1A}\x{5A1C}\x{5A1F}\x{5A20}\x{5A25}\x{5A29}\x{5A2F}\x{5A35}\x{5A36}' . +'\x{5A3C}\x{5A40}\x{5A41}\x{5A46}\x{5A49}\x{5A5A}\x{5A62}\x{5A66}\x{5A6A}' . +'\x{5A6C}\x{5A7F}\x{5A92}\x{5A9A}\x{5A9B}\x{5ABC}\x{5ABD}\x{5ABE}\x{5AC1}' . +'\x{5AC2}\x{5AC9}\x{5ACB}\x{5ACC}\x{5AD0}\x{5AD6}\x{5AD7}\x{5AE1}\x{5AE3}' . +'\x{5AE6}\x{5AE9}\x{5AFA}\x{5AFB}\x{5B09}\x{5B0B}\x{5B0C}\x{5B16}\x{5B22}' . +'\x{5B2A}\x{5B2C}\x{5B30}\x{5B32}\x{5B36}\x{5B3E}\x{5B40}\x{5B43}\x{5B45}' . +'\x{5B50}\x{5B51}\x{5B54}\x{5B55}\x{5B57}\x{5B58}\x{5B5A}\x{5B5B}\x{5B5C}' . +'\x{5B5D}\x{5B5F}\x{5B63}\x{5B64}\x{5B65}\x{5B66}\x{5B69}\x{5B6B}\x{5B70}' . +'\x{5B71}\x{5B73}\x{5B75}\x{5B78}\x{5B7A}\x{5B80}\x{5B83}\x{5B85}\x{5B87}' . +'\x{5B88}\x{5B89}\x{5B8B}\x{5B8C}\x{5B8D}\x{5B8F}\x{5B95}\x{5B97}\x{5B98}' . +'\x{5B99}\x{5B9A}\x{5B9B}\x{5B9C}\x{5B9D}\x{5B9F}\x{5BA2}\x{5BA3}\x{5BA4}' . +'\x{5BA5}\x{5BA6}\x{5BAE}\x{5BB0}\x{5BB3}\x{5BB4}\x{5BB5}\x{5BB6}\x{5BB8}' . +'\x{5BB9}\x{5BBF}\x{5BC2}\x{5BC3}\x{5BC4}\x{5BC5}\x{5BC6}\x{5BC7}\x{5BC9}' . +'\x{5BCC}\x{5BD0}\x{5BD2}\x{5BD3}\x{5BD4}\x{5BDB}\x{5BDD}\x{5BDE}\x{5BDF}' . +'\x{5BE1}\x{5BE2}\x{5BE4}\x{5BE5}\x{5BE6}\x{5BE7}\x{5BE8}\x{5BE9}\x{5BEB}' . +'\x{5BEE}\x{5BF0}\x{5BF3}\x{5BF5}\x{5BF6}\x{5BF8}\x{5BFA}\x{5BFE}\x{5BFF}' . +'\x{5C01}\x{5C02}\x{5C04}\x{5C05}\x{5C06}\x{5C07}\x{5C08}\x{5C09}\x{5C0A}' . +'\x{5C0B}\x{5C0D}\x{5C0E}\x{5C0F}\x{5C11}\x{5C13}\x{5C16}\x{5C1A}\x{5C20}' . +'\x{5C22}\x{5C24}\x{5C28}\x{5C2D}\x{5C31}\x{5C38}\x{5C39}\x{5C3A}\x{5C3B}' . +'\x{5C3C}\x{5C3D}\x{5C3E}\x{5C3F}\x{5C40}\x{5C41}\x{5C45}\x{5C46}\x{5C48}' . +'\x{5C4A}\x{5C4B}\x{5C4D}\x{5C4E}\x{5C4F}\x{5C50}\x{5C51}\x{5C53}\x{5C55}' . +'\x{5C5E}\x{5C60}\x{5C61}\x{5C64}\x{5C65}\x{5C6C}\x{5C6E}\x{5C6F}\x{5C71}' . +'\x{5C76}\x{5C79}\x{5C8C}\x{5C90}\x{5C91}\x{5C94}\x{5CA1}\x{5CA8}\x{5CA9}' . +'\x{5CAB}\x{5CAC}\x{5CB1}\x{5CB3}\x{5CB6}\x{5CB7}\x{5CB8}\x{5CBB}\x{5CBC}' . +'\x{5CBE}\x{5CC5}\x{5CC7}\x{5CD9}\x{5CE0}\x{5CE1}\x{5CE8}\x{5CE9}\x{5CEA}' . +'\x{5CED}\x{5CEF}\x{5CF0}\x{5CF6}\x{5CFA}\x{5CFB}\x{5CFD}\x{5D07}\x{5D0B}' . +'\x{5D0E}\x{5D11}\x{5D14}\x{5D15}\x{5D16}\x{5D17}\x{5D18}\x{5D19}\x{5D1A}' . +'\x{5D1B}\x{5D1F}\x{5D22}\x{5D29}\x{5D4B}\x{5D4C}\x{5D4E}\x{5D50}\x{5D52}' . +'\x{5D5C}\x{5D69}\x{5D6C}\x{5D6F}\x{5D73}\x{5D76}\x{5D82}\x{5D84}\x{5D87}' . +'\x{5D8B}\x{5D8C}\x{5D90}\x{5D9D}\x{5DA2}\x{5DAC}\x{5DAE}\x{5DB7}\x{5DBA}' . +'\x{5DBC}\x{5DBD}\x{5DC9}\x{5DCC}\x{5DCD}\x{5DD2}\x{5DD3}\x{5DD6}\x{5DDB}' . +'\x{5DDD}\x{5DDE}\x{5DE1}\x{5DE3}\x{5DE5}\x{5DE6}\x{5DE7}\x{5DE8}\x{5DEB}' . +'\x{5DEE}\x{5DF1}\x{5DF2}\x{5DF3}\x{5DF4}\x{5DF5}\x{5DF7}\x{5DFB}\x{5DFD}' . +'\x{5DFE}\x{5E02}\x{5E03}\x{5E06}\x{5E0B}\x{5E0C}\x{5E11}\x{5E16}\x{5E19}' . +'\x{5E1A}\x{5E1B}\x{5E1D}\x{5E25}\x{5E2B}\x{5E2D}\x{5E2F}\x{5E30}\x{5E33}' . +'\x{5E36}\x{5E37}\x{5E38}\x{5E3D}\x{5E40}\x{5E43}\x{5E44}\x{5E45}\x{5E47}' . +'\x{5E4C}\x{5E4E}\x{5E54}\x{5E55}\x{5E57}\x{5E5F}\x{5E61}\x{5E62}\x{5E63}' . +'\x{5E64}\x{5E72}\x{5E73}\x{5E74}\x{5E75}\x{5E76}\x{5E78}\x{5E79}\x{5E7A}' . +'\x{5E7B}\x{5E7C}\x{5E7D}\x{5E7E}\x{5E7F}\x{5E81}\x{5E83}\x{5E84}\x{5E87}' . +'\x{5E8A}\x{5E8F}\x{5E95}\x{5E96}\x{5E97}\x{5E9A}\x{5E9C}\x{5EA0}\x{5EA6}' . +'\x{5EA7}\x{5EAB}\x{5EAD}\x{5EB5}\x{5EB6}\x{5EB7}\x{5EB8}\x{5EC1}\x{5EC2}' . +'\x{5EC3}\x{5EC8}\x{5EC9}\x{5ECA}\x{5ECF}\x{5ED0}\x{5ED3}\x{5ED6}\x{5EDA}' . +'\x{5EDB}\x{5EDD}\x{5EDF}\x{5EE0}\x{5EE1}\x{5EE2}\x{5EE3}\x{5EE8}\x{5EE9}' . +'\x{5EEC}\x{5EF0}\x{5EF1}\x{5EF3}\x{5EF4}\x{5EF6}\x{5EF7}\x{5EF8}\x{5EFA}' . +'\x{5EFB}\x{5EFC}\x{5EFE}\x{5EFF}\x{5F01}\x{5F03}\x{5F04}\x{5F09}\x{5F0A}' . +'\x{5F0B}\x{5F0C}\x{5F0D}\x{5F0F}\x{5F10}\x{5F11}\x{5F13}\x{5F14}\x{5F15}' . +'\x{5F16}\x{5F17}\x{5F18}\x{5F1B}\x{5F1F}\x{5F25}\x{5F26}\x{5F27}\x{5F29}' . +'\x{5F2D}\x{5F2F}\x{5F31}\x{5F35}\x{5F37}\x{5F38}\x{5F3C}\x{5F3E}\x{5F41}' . +'\x{5F48}\x{5F4A}\x{5F4C}\x{5F4E}\x{5F51}\x{5F53}\x{5F56}\x{5F57}\x{5F59}' . +'\x{5F5C}\x{5F5D}\x{5F61}\x{5F62}\x{5F66}\x{5F69}\x{5F6A}\x{5F6B}\x{5F6C}' . +'\x{5F6D}\x{5F70}\x{5F71}\x{5F73}\x{5F77}\x{5F79}\x{5F7C}\x{5F7F}\x{5F80}' . +'\x{5F81}\x{5F82}\x{5F83}\x{5F84}\x{5F85}\x{5F87}\x{5F88}\x{5F8A}\x{5F8B}' . +'\x{5F8C}\x{5F90}\x{5F91}\x{5F92}\x{5F93}\x{5F97}\x{5F98}\x{5F99}\x{5F9E}' . +'\x{5FA0}\x{5FA1}\x{5FA8}\x{5FA9}\x{5FAA}\x{5FAD}\x{5FAE}\x{5FB3}\x{5FB4}' . +'\x{5FB9}\x{5FBC}\x{5FBD}\x{5FC3}\x{5FC5}\x{5FCC}\x{5FCD}\x{5FD6}\x{5FD7}' . +'\x{5FD8}\x{5FD9}\x{5FDC}\x{5FDD}\x{5FE0}\x{5FE4}\x{5FEB}\x{5FF0}\x{5FF1}' . +'\x{5FF5}\x{5FF8}\x{5FFB}\x{5FFD}\x{5FFF}\x{600E}\x{600F}\x{6010}\x{6012}' . +'\x{6015}\x{6016}\x{6019}\x{601B}\x{601C}\x{601D}\x{6020}\x{6021}\x{6025}' . +'\x{6026}\x{6027}\x{6028}\x{6029}\x{602A}\x{602B}\x{602F}\x{6031}\x{603A}' . +'\x{6041}\x{6042}\x{6043}\x{6046}\x{604A}\x{604B}\x{604D}\x{6050}\x{6052}' . +'\x{6055}\x{6059}\x{605A}\x{605F}\x{6060}\x{6062}\x{6063}\x{6064}\x{6065}' . +'\x{6068}\x{6069}\x{606A}\x{606B}\x{606C}\x{606D}\x{606F}\x{6070}\x{6075}' . +'\x{6077}\x{6081}\x{6083}\x{6084}\x{6089}\x{608B}\x{608C}\x{608D}\x{6092}' . +'\x{6094}\x{6096}\x{6097}\x{609A}\x{609B}\x{609F}\x{60A0}\x{60A3}\x{60A6}' . +'\x{60A7}\x{60A9}\x{60AA}\x{60B2}\x{60B3}\x{60B4}\x{60B5}\x{60B6}\x{60B8}' . +'\x{60BC}\x{60BD}\x{60C5}\x{60C6}\x{60C7}\x{60D1}\x{60D3}\x{60D8}\x{60DA}' . +'\x{60DC}\x{60DF}\x{60E0}\x{60E1}\x{60E3}\x{60E7}\x{60E8}\x{60F0}\x{60F1}' . +'\x{60F3}\x{60F4}\x{60F6}\x{60F7}\x{60F9}\x{60FA}\x{60FB}\x{6100}\x{6101}' . +'\x{6103}\x{6106}\x{6108}\x{6109}\x{610D}\x{610E}\x{610F}\x{6115}\x{611A}' . +'\x{611B}\x{611F}\x{6121}\x{6127}\x{6128}\x{612C}\x{6134}\x{613C}\x{613D}' . +'\x{613E}\x{613F}\x{6142}\x{6144}\x{6147}\x{6148}\x{614A}\x{614B}\x{614C}' . +'\x{614D}\x{614E}\x{6153}\x{6155}\x{6158}\x{6159}\x{615A}\x{615D}\x{615F}' . +'\x{6162}\x{6163}\x{6165}\x{6167}\x{6168}\x{616B}\x{616E}\x{616F}\x{6170}' . +'\x{6171}\x{6173}\x{6174}\x{6175}\x{6176}\x{6177}\x{617E}\x{6182}\x{6187}' . +'\x{618A}\x{618E}\x{6190}\x{6191}\x{6194}\x{6196}\x{6199}\x{619A}\x{61A4}' . +'\x{61A7}\x{61A9}\x{61AB}\x{61AC}\x{61AE}\x{61B2}\x{61B6}\x{61BA}\x{61BE}' . +'\x{61C3}\x{61C6}\x{61C7}\x{61C8}\x{61C9}\x{61CA}\x{61CB}\x{61CC}\x{61CD}' . +'\x{61D0}\x{61E3}\x{61E6}\x{61F2}\x{61F4}\x{61F6}\x{61F7}\x{61F8}\x{61FA}' . +'\x{61FC}\x{61FD}\x{61FE}\x{61FF}\x{6200}\x{6208}\x{6209}\x{620A}\x{620C}' . +'\x{620D}\x{620E}\x{6210}\x{6211}\x{6212}\x{6214}\x{6216}\x{621A}\x{621B}' . +'\x{621D}\x{621E}\x{621F}\x{6221}\x{6226}\x{622A}\x{622E}\x{622F}\x{6230}' . +'\x{6232}\x{6233}\x{6234}\x{6238}\x{623B}\x{623F}\x{6240}\x{6241}\x{6247}' . +'\x{6248}\x{6249}\x{624B}\x{624D}\x{624E}\x{6253}\x{6255}\x{6258}\x{625B}' . +'\x{625E}\x{6260}\x{6263}\x{6268}\x{626E}\x{6271}\x{6276}\x{6279}\x{627C}' . +'\x{627E}\x{627F}\x{6280}\x{6282}\x{6283}\x{6284}\x{6289}\x{628A}\x{6291}' . +'\x{6292}\x{6293}\x{6294}\x{6295}\x{6296}\x{6297}\x{6298}\x{629B}\x{629C}' . +'\x{629E}\x{62AB}\x{62AC}\x{62B1}\x{62B5}\x{62B9}\x{62BB}\x{62BC}\x{62BD}' . +'\x{62C2}\x{62C5}\x{62C6}\x{62C7}\x{62C8}\x{62C9}\x{62CA}\x{62CC}\x{62CD}' . +'\x{62CF}\x{62D0}\x{62D1}\x{62D2}\x{62D3}\x{62D4}\x{62D7}\x{62D8}\x{62D9}' . +'\x{62DB}\x{62DC}\x{62DD}\x{62E0}\x{62E1}\x{62EC}\x{62ED}\x{62EE}\x{62EF}' . +'\x{62F1}\x{62F3}\x{62F5}\x{62F6}\x{62F7}\x{62FE}\x{62FF}\x{6301}\x{6302}' . +'\x{6307}\x{6308}\x{6309}\x{630C}\x{6311}\x{6319}\x{631F}\x{6327}\x{6328}' . +'\x{632B}\x{632F}\x{633A}\x{633D}\x{633E}\x{633F}\x{6349}\x{634C}\x{634D}' . +'\x{634F}\x{6350}\x{6355}\x{6357}\x{635C}\x{6367}\x{6368}\x{6369}\x{636B}' . +'\x{636E}\x{6372}\x{6376}\x{6377}\x{637A}\x{637B}\x{6380}\x{6383}\x{6388}' . +'\x{6389}\x{638C}\x{638E}\x{638F}\x{6392}\x{6396}\x{6398}\x{639B}\x{639F}' . +'\x{63A0}\x{63A1}\x{63A2}\x{63A3}\x{63A5}\x{63A7}\x{63A8}\x{63A9}\x{63AA}' . +'\x{63AB}\x{63AC}\x{63B2}\x{63B4}\x{63B5}\x{63BB}\x{63BE}\x{63C0}\x{63C3}' . +'\x{63C4}\x{63C6}\x{63C9}\x{63CF}\x{63D0}\x{63D2}\x{63D6}\x{63DA}\x{63DB}' . +'\x{63E1}\x{63E3}\x{63E9}\x{63EE}\x{63F4}\x{63F6}\x{63FA}\x{6406}\x{640D}' . +'\x{640F}\x{6413}\x{6416}\x{6417}\x{641C}\x{6426}\x{6428}\x{642C}\x{642D}' . +'\x{6434}\x{6436}\x{643A}\x{643E}\x{6442}\x{644E}\x{6458}\x{6467}\x{6469}' . +'\x{646F}\x{6476}\x{6478}\x{647A}\x{6483}\x{6488}\x{6492}\x{6493}\x{6495}' . +'\x{649A}\x{649E}\x{64A4}\x{64A5}\x{64A9}\x{64AB}\x{64AD}\x{64AE}\x{64B0}' . +'\x{64B2}\x{64B9}\x{64BB}\x{64BC}\x{64C1}\x{64C2}\x{64C5}\x{64C7}\x{64CD}' . +'\x{64D2}\x{64D4}\x{64D8}\x{64DA}\x{64E0}\x{64E1}\x{64E2}\x{64E3}\x{64E6}' . +'\x{64E7}\x{64EC}\x{64EF}\x{64F1}\x{64F2}\x{64F4}\x{64F6}\x{64FA}\x{64FD}' . +'\x{64FE}\x{6500}\x{6505}\x{6518}\x{651C}\x{651D}\x{6523}\x{6524}\x{652A}' . +'\x{652B}\x{652C}\x{652F}\x{6534}\x{6535}\x{6536}\x{6537}\x{6538}\x{6539}' . +'\x{653B}\x{653E}\x{653F}\x{6545}\x{6548}\x{654D}\x{654F}\x{6551}\x{6555}' . +'\x{6556}\x{6557}\x{6558}\x{6559}\x{655D}\x{655E}\x{6562}\x{6563}\x{6566}' . +'\x{656C}\x{6570}\x{6572}\x{6574}\x{6575}\x{6577}\x{6578}\x{6582}\x{6583}' . +'\x{6587}\x{6588}\x{6589}\x{658C}\x{658E}\x{6590}\x{6591}\x{6597}\x{6599}' . +'\x{659B}\x{659C}\x{659F}\x{65A1}\x{65A4}\x{65A5}\x{65A7}\x{65AB}\x{65AC}' . +'\x{65AD}\x{65AF}\x{65B0}\x{65B7}\x{65B9}\x{65BC}\x{65BD}\x{65C1}\x{65C3}' . +'\x{65C4}\x{65C5}\x{65C6}\x{65CB}\x{65CC}\x{65CF}\x{65D2}\x{65D7}\x{65D9}' . +'\x{65DB}\x{65E0}\x{65E1}\x{65E2}\x{65E5}\x{65E6}\x{65E7}\x{65E8}\x{65E9}' . +'\x{65EC}\x{65ED}\x{65F1}\x{65FA}\x{65FB}\x{6602}\x{6603}\x{6606}\x{6607}' . +'\x{660A}\x{660C}\x{660E}\x{660F}\x{6613}\x{6614}\x{661C}\x{661F}\x{6620}' . +'\x{6625}\x{6627}\x{6628}\x{662D}\x{662F}\x{6634}\x{6635}\x{6636}\x{663C}' . +'\x{663F}\x{6641}\x{6642}\x{6643}\x{6644}\x{6649}\x{664B}\x{664F}\x{6652}' . +'\x{665D}\x{665E}\x{665F}\x{6662}\x{6664}\x{6666}\x{6667}\x{6668}\x{6669}' . +'\x{666E}\x{666F}\x{6670}\x{6674}\x{6676}\x{667A}\x{6681}\x{6683}\x{6684}' . +'\x{6687}\x{6688}\x{6689}\x{668E}\x{6691}\x{6696}\x{6697}\x{6698}\x{669D}' . +'\x{66A2}\x{66A6}\x{66AB}\x{66AE}\x{66B4}\x{66B8}\x{66B9}\x{66BC}\x{66BE}' . +'\x{66C1}\x{66C4}\x{66C7}\x{66C9}\x{66D6}\x{66D9}\x{66DA}\x{66DC}\x{66DD}' . +'\x{66E0}\x{66E6}\x{66E9}\x{66F0}\x{66F2}\x{66F3}\x{66F4}\x{66F5}\x{66F7}' . +'\x{66F8}\x{66F9}\x{66FC}\x{66FD}\x{66FE}\x{66FF}\x{6700}\x{6703}\x{6708}' . +'\x{6709}\x{670B}\x{670D}\x{670F}\x{6714}\x{6715}\x{6716}\x{6717}\x{671B}' . +'\x{671D}\x{671E}\x{671F}\x{6726}\x{6727}\x{6728}\x{672A}\x{672B}\x{672C}' . +'\x{672D}\x{672E}\x{6731}\x{6734}\x{6736}\x{6737}\x{6738}\x{673A}\x{673D}' . +'\x{673F}\x{6741}\x{6746}\x{6749}\x{674E}\x{674F}\x{6750}\x{6751}\x{6753}' . +'\x{6756}\x{6759}\x{675C}\x{675E}\x{675F}\x{6760}\x{6761}\x{6762}\x{6763}' . +'\x{6764}\x{6765}\x{676A}\x{676D}\x{676F}\x{6770}\x{6771}\x{6772}\x{6773}' . +'\x{6775}\x{6777}\x{677C}\x{677E}\x{677F}\x{6785}\x{6787}\x{6789}\x{678B}' . +'\x{678C}\x{6790}\x{6795}\x{6797}\x{679A}\x{679C}\x{679D}\x{67A0}\x{67A1}' . +'\x{67A2}\x{67A6}\x{67A9}\x{67AF}\x{67B3}\x{67B4}\x{67B6}\x{67B7}\x{67B8}' . +'\x{67B9}\x{67C1}\x{67C4}\x{67C6}\x{67CA}\x{67CE}\x{67CF}\x{67D0}\x{67D1}' . +'\x{67D3}\x{67D4}\x{67D8}\x{67DA}\x{67DD}\x{67DE}\x{67E2}\x{67E4}\x{67E7}' . +'\x{67E9}\x{67EC}\x{67EE}\x{67EF}\x{67F1}\x{67F3}\x{67F4}\x{67F5}\x{67FB}' . +'\x{67FE}\x{67FF}\x{6802}\x{6803}\x{6804}\x{6813}\x{6816}\x{6817}\x{681E}' . +'\x{6821}\x{6822}\x{6829}\x{682A}\x{682B}\x{6832}\x{6834}\x{6838}\x{6839}' . +'\x{683C}\x{683D}\x{6840}\x{6841}\x{6842}\x{6843}\x{6846}\x{6848}\x{684D}' . +'\x{684E}\x{6850}\x{6851}\x{6853}\x{6854}\x{6859}\x{685C}\x{685D}\x{685F}' . +'\x{6863}\x{6867}\x{6874}\x{6876}\x{6877}\x{687E}\x{687F}\x{6881}\x{6883}' . +'\x{6885}\x{688D}\x{688F}\x{6893}\x{6894}\x{6897}\x{689B}\x{689D}\x{689F}' . +'\x{68A0}\x{68A2}\x{68A6}\x{68A7}\x{68A8}\x{68AD}\x{68AF}\x{68B0}\x{68B1}' . +'\x{68B3}\x{68B5}\x{68B6}\x{68B9}\x{68BA}\x{68BC}\x{68C4}\x{68C6}\x{68C9}' . +'\x{68CA}\x{68CB}\x{68CD}\x{68D2}\x{68D4}\x{68D5}\x{68D7}\x{68D8}\x{68DA}' . +'\x{68DF}\x{68E0}\x{68E1}\x{68E3}\x{68E7}\x{68EE}\x{68EF}\x{68F2}\x{68F9}' . +'\x{68FA}\x{6900}\x{6901}\x{6904}\x{6905}\x{6908}\x{690B}\x{690C}\x{690D}' . +'\x{690E}\x{690F}\x{6912}\x{6919}\x{691A}\x{691B}\x{691C}\x{6921}\x{6922}' . +'\x{6923}\x{6925}\x{6926}\x{6928}\x{692A}\x{6930}\x{6934}\x{6936}\x{6939}' . +'\x{693D}\x{693F}\x{694A}\x{6953}\x{6954}\x{6955}\x{6959}\x{695A}\x{695C}' . +'\x{695D}\x{695E}\x{6960}\x{6961}\x{6962}\x{696A}\x{696B}\x{696D}\x{696E}' . +'\x{696F}\x{6973}\x{6974}\x{6975}\x{6977}\x{6978}\x{6979}\x{697C}\x{697D}' . +'\x{697E}\x{6981}\x{6982}\x{698A}\x{698E}\x{6991}\x{6994}\x{6995}\x{699B}' . +'\x{699C}\x{69A0}\x{69A7}\x{69AE}\x{69B1}\x{69B2}\x{69B4}\x{69BB}\x{69BE}' . +'\x{69BF}\x{69C1}\x{69C3}\x{69C7}\x{69CA}\x{69CB}\x{69CC}\x{69CD}\x{69CE}' . +'\x{69D0}\x{69D3}\x{69D8}\x{69D9}\x{69DD}\x{69DE}\x{69E7}\x{69E8}\x{69EB}' . +'\x{69ED}\x{69F2}\x{69F9}\x{69FB}\x{69FD}\x{69FF}\x{6A02}\x{6A05}\x{6A0A}' . +'\x{6A0B}\x{6A0C}\x{6A12}\x{6A13}\x{6A14}\x{6A17}\x{6A19}\x{6A1B}\x{6A1E}' . +'\x{6A1F}\x{6A21}\x{6A22}\x{6A23}\x{6A29}\x{6A2A}\x{6A2B}\x{6A2E}\x{6A35}' . +'\x{6A36}\x{6A38}\x{6A39}\x{6A3A}\x{6A3D}\x{6A44}\x{6A47}\x{6A48}\x{6A4B}' . +'\x{6A58}\x{6A59}\x{6A5F}\x{6A61}\x{6A62}\x{6A66}\x{6A72}\x{6A78}\x{6A7F}' . +'\x{6A80}\x{6A84}\x{6A8D}\x{6A8E}\x{6A90}\x{6A97}\x{6A9C}\x{6AA0}\x{6AA2}' . +'\x{6AA3}\x{6AAA}\x{6AAC}\x{6AAE}\x{6AB3}\x{6AB8}\x{6ABB}\x{6AC1}\x{6AC2}' . +'\x{6AC3}\x{6AD1}\x{6AD3}\x{6ADA}\x{6ADB}\x{6ADE}\x{6ADF}\x{6AE8}\x{6AEA}' . +'\x{6AFA}\x{6AFB}\x{6B04}\x{6B05}\x{6B0A}\x{6B12}\x{6B16}\x{6B1D}\x{6B1F}' . +'\x{6B20}\x{6B21}\x{6B23}\x{6B27}\x{6B32}\x{6B37}\x{6B38}\x{6B39}\x{6B3A}' . +'\x{6B3D}\x{6B3E}\x{6B43}\x{6B47}\x{6B49}\x{6B4C}\x{6B4E}\x{6B50}\x{6B53}' . +'\x{6B54}\x{6B59}\x{6B5B}\x{6B5F}\x{6B61}\x{6B62}\x{6B63}\x{6B64}\x{6B66}' . +'\x{6B69}\x{6B6A}\x{6B6F}\x{6B73}\x{6B74}\x{6B78}\x{6B79}\x{6B7B}\x{6B7F}' . +'\x{6B80}\x{6B83}\x{6B84}\x{6B86}\x{6B89}\x{6B8A}\x{6B8B}\x{6B8D}\x{6B95}' . +'\x{6B96}\x{6B98}\x{6B9E}\x{6BA4}\x{6BAA}\x{6BAB}\x{6BAF}\x{6BB1}\x{6BB2}' . +'\x{6BB3}\x{6BB4}\x{6BB5}\x{6BB7}\x{6BBA}\x{6BBB}\x{6BBC}\x{6BBF}\x{6BC0}' . +'\x{6BC5}\x{6BC6}\x{6BCB}\x{6BCD}\x{6BCE}\x{6BD2}\x{6BD3}\x{6BD4}\x{6BD8}' . +'\x{6BDB}\x{6BDF}\x{6BEB}\x{6BEC}\x{6BEF}\x{6BF3}\x{6C08}\x{6C0F}\x{6C11}' . +'\x{6C13}\x{6C14}\x{6C17}\x{6C1B}\x{6C23}\x{6C24}\x{6C34}\x{6C37}\x{6C38}' . +'\x{6C3E}\x{6C40}\x{6C41}\x{6C42}\x{6C4E}\x{6C50}\x{6C55}\x{6C57}\x{6C5A}' . +'\x{6C5D}\x{6C5E}\x{6C5F}\x{6C60}\x{6C62}\x{6C68}\x{6C6A}\x{6C70}\x{6C72}' . +'\x{6C73}\x{6C7A}\x{6C7D}\x{6C7E}\x{6C81}\x{6C82}\x{6C83}\x{6C88}\x{6C8C}' . +'\x{6C8D}\x{6C90}\x{6C92}\x{6C93}\x{6C96}\x{6C99}\x{6C9A}\x{6C9B}\x{6CA1}' . +'\x{6CA2}\x{6CAB}\x{6CAE}\x{6CB1}\x{6CB3}\x{6CB8}\x{6CB9}\x{6CBA}\x{6CBB}' . +'\x{6CBC}\x{6CBD}\x{6CBE}\x{6CBF}\x{6CC1}\x{6CC4}\x{6CC5}\x{6CC9}\x{6CCA}' . +'\x{6CCC}\x{6CD3}\x{6CD5}\x{6CD7}\x{6CD9}\x{6CDB}\x{6CDD}\x{6CE1}\x{6CE2}' . +'\x{6CE3}\x{6CE5}\x{6CE8}\x{6CEA}\x{6CEF}\x{6CF0}\x{6CF1}\x{6CF3}\x{6D0B}' . +'\x{6D0C}\x{6D12}\x{6D17}\x{6D19}\x{6D1B}\x{6D1E}\x{6D1F}\x{6D25}\x{6D29}' . +'\x{6D2A}\x{6D2B}\x{6D32}\x{6D33}\x{6D35}\x{6D36}\x{6D38}\x{6D3B}\x{6D3D}' . +'\x{6D3E}\x{6D41}\x{6D44}\x{6D45}\x{6D59}\x{6D5A}\x{6D5C}\x{6D63}\x{6D64}' . +'\x{6D66}\x{6D69}\x{6D6A}\x{6D6C}\x{6D6E}\x{6D74}\x{6D77}\x{6D78}\x{6D79}' . +'\x{6D85}\x{6D88}\x{6D8C}\x{6D8E}\x{6D93}\x{6D95}\x{6D99}\x{6D9B}\x{6D9C}' . +'\x{6DAF}\x{6DB2}\x{6DB5}\x{6DB8}\x{6DBC}\x{6DC0}\x{6DC5}\x{6DC6}\x{6DC7}' . +'\x{6DCB}\x{6DCC}\x{6DD1}\x{6DD2}\x{6DD5}\x{6DD8}\x{6DD9}\x{6DDE}\x{6DE1}' . +'\x{6DE4}\x{6DE6}\x{6DE8}\x{6DEA}\x{6DEB}\x{6DEC}\x{6DEE}\x{6DF1}\x{6DF3}' . +'\x{6DF5}\x{6DF7}\x{6DF9}\x{6DFA}\x{6DFB}\x{6E05}\x{6E07}\x{6E08}\x{6E09}' . +'\x{6E0A}\x{6E0B}\x{6E13}\x{6E15}\x{6E19}\x{6E1A}\x{6E1B}\x{6E1D}\x{6E1F}' . +'\x{6E20}\x{6E21}\x{6E23}\x{6E24}\x{6E25}\x{6E26}\x{6E29}\x{6E2B}\x{6E2C}' . +'\x{6E2D}\x{6E2E}\x{6E2F}\x{6E38}\x{6E3A}\x{6E3E}\x{6E43}\x{6E4A}\x{6E4D}' . +'\x{6E4E}\x{6E56}\x{6E58}\x{6E5B}\x{6E5F}\x{6E67}\x{6E6B}\x{6E6E}\x{6E6F}' . +'\x{6E72}\x{6E76}\x{6E7E}\x{6E7F}\x{6E80}\x{6E82}\x{6E8C}\x{6E8F}\x{6E90}' . +'\x{6E96}\x{6E98}\x{6E9C}\x{6E9D}\x{6E9F}\x{6EA2}\x{6EA5}\x{6EAA}\x{6EAF}' . +'\x{6EB2}\x{6EB6}\x{6EB7}\x{6EBA}\x{6EBD}\x{6EC2}\x{6EC4}\x{6EC5}\x{6EC9}' . +'\x{6ECB}\x{6ECC}\x{6ED1}\x{6ED3}\x{6ED4}\x{6ED5}\x{6EDD}\x{6EDE}\x{6EEC}' . +'\x{6EEF}\x{6EF2}\x{6EF4}\x{6EF7}\x{6EF8}\x{6EFE}\x{6EFF}\x{6F01}\x{6F02}' . +'\x{6F06}\x{6F09}\x{6F0F}\x{6F11}\x{6F13}\x{6F14}\x{6F15}\x{6F20}\x{6F22}' . +'\x{6F23}\x{6F2B}\x{6F2C}\x{6F31}\x{6F32}\x{6F38}\x{6F3E}\x{6F3F}\x{6F41}' . +'\x{6F45}\x{6F54}\x{6F58}\x{6F5B}\x{6F5C}\x{6F5F}\x{6F64}\x{6F66}\x{6F6D}' . +'\x{6F6E}\x{6F6F}\x{6F70}\x{6F74}\x{6F78}\x{6F7A}\x{6F7C}\x{6F80}\x{6F81}' . +'\x{6F82}\x{6F84}\x{6F86}\x{6F8E}\x{6F91}\x{6F97}\x{6FA1}\x{6FA3}\x{6FA4}' . +'\x{6FAA}\x{6FB1}\x{6FB3}\x{6FB9}\x{6FC0}\x{6FC1}\x{6FC2}\x{6FC3}\x{6FC6}' . +'\x{6FD4}\x{6FD5}\x{6FD8}\x{6FDB}\x{6FDF}\x{6FE0}\x{6FE1}\x{6FE4}\x{6FEB}' . +'\x{6FEC}\x{6FEE}\x{6FEF}\x{6FF1}\x{6FF3}\x{6FF6}\x{6FFA}\x{6FFE}\x{7001}' . +'\x{7009}\x{700B}\x{700F}\x{7011}\x{7015}\x{7018}\x{701A}\x{701B}\x{701D}' . +'\x{701E}\x{701F}\x{7026}\x{7027}\x{702C}\x{7030}\x{7032}\x{703E}\x{704C}' . +'\x{7051}\x{7058}\x{7063}\x{706B}\x{706F}\x{7070}\x{7078}\x{707C}\x{707D}' . +'\x{7089}\x{708A}\x{708E}\x{7092}\x{7099}\x{70AC}\x{70AD}\x{70AE}\x{70AF}' . +'\x{70B3}\x{70B8}\x{70B9}\x{70BA}\x{70C8}\x{70CB}\x{70CF}\x{70D9}\x{70DD}' . +'\x{70DF}\x{70F1}\x{70F9}\x{70FD}\x{7109}\x{7114}\x{7119}\x{711A}\x{711C}' . +'\x{7121}\x{7126}\x{7136}\x{713C}\x{7149}\x{714C}\x{714E}\x{7155}\x{7156}' . +'\x{7159}\x{7162}\x{7164}\x{7165}\x{7166}\x{7167}\x{7169}\x{716C}\x{716E}' . +'\x{717D}\x{7184}\x{7188}\x{718A}\x{718F}\x{7194}\x{7195}\x{7199}\x{719F}' . +'\x{71A8}\x{71AC}\x{71B1}\x{71B9}\x{71BE}\x{71C3}\x{71C8}\x{71C9}\x{71CE}' . +'\x{71D0}\x{71D2}\x{71D4}\x{71D5}\x{71D7}\x{71DF}\x{71E0}\x{71E5}\x{71E6}' . +'\x{71E7}\x{71EC}\x{71ED}\x{71EE}\x{71F5}\x{71F9}\x{71FB}\x{71FC}\x{71FF}' . +'\x{7206}\x{720D}\x{7210}\x{721B}\x{7228}\x{722A}\x{722C}\x{722D}\x{7230}' . +'\x{7232}\x{7235}\x{7236}\x{723A}\x{723B}\x{723C}\x{723D}\x{723E}\x{723F}' . +'\x{7240}\x{7246}\x{7247}\x{7248}\x{724B}\x{724C}\x{7252}\x{7258}\x{7259}' . +'\x{725B}\x{725D}\x{725F}\x{7261}\x{7262}\x{7267}\x{7269}\x{7272}\x{7274}' . +'\x{7279}\x{727D}\x{727E}\x{7280}\x{7281}\x{7282}\x{7287}\x{7292}\x{7296}' . +'\x{72A0}\x{72A2}\x{72A7}\x{72AC}\x{72AF}\x{72B2}\x{72B6}\x{72B9}\x{72C2}' . +'\x{72C3}\x{72C4}\x{72C6}\x{72CE}\x{72D0}\x{72D2}\x{72D7}\x{72D9}\x{72DB}' . +'\x{72E0}\x{72E1}\x{72E2}\x{72E9}\x{72EC}\x{72ED}\x{72F7}\x{72F8}\x{72F9}' . +'\x{72FC}\x{72FD}\x{730A}\x{7316}\x{7317}\x{731B}\x{731C}\x{731D}\x{731F}' . +'\x{7325}\x{7329}\x{732A}\x{732B}\x{732E}\x{732F}\x{7334}\x{7336}\x{7337}' . +'\x{733E}\x{733F}\x{7344}\x{7345}\x{734E}\x{734F}\x{7357}\x{7363}\x{7368}' . +'\x{736A}\x{7370}\x{7372}\x{7375}\x{7378}\x{737A}\x{737B}\x{7384}\x{7387}' . +'\x{7389}\x{738B}\x{7396}\x{73A9}\x{73B2}\x{73B3}\x{73BB}\x{73C0}\x{73C2}' . +'\x{73C8}\x{73CA}\x{73CD}\x{73CE}\x{73DE}\x{73E0}\x{73E5}\x{73EA}\x{73ED}' . +'\x{73EE}\x{73F1}\x{73F8}\x{73FE}\x{7403}\x{7405}\x{7406}\x{7409}\x{7422}' . +'\x{7425}\x{7432}\x{7433}\x{7434}\x{7435}\x{7436}\x{743A}\x{743F}\x{7441}' . +'\x{7455}\x{7459}\x{745A}\x{745B}\x{745C}\x{745E}\x{745F}\x{7460}\x{7463}' . +'\x{7464}\x{7469}\x{746A}\x{746F}\x{7470}\x{7473}\x{7476}\x{747E}\x{7483}' . +'\x{748B}\x{749E}\x{74A2}\x{74A7}\x{74B0}\x{74BD}\x{74CA}\x{74CF}\x{74D4}' . +'\x{74DC}\x{74E0}\x{74E2}\x{74E3}\x{74E6}\x{74E7}\x{74E9}\x{74EE}\x{74F0}' . +'\x{74F1}\x{74F2}\x{74F6}\x{74F7}\x{74F8}\x{7503}\x{7504}\x{7505}\x{750C}' . +'\x{750D}\x{750E}\x{7511}\x{7513}\x{7515}\x{7518}\x{751A}\x{751C}\x{751E}' . +'\x{751F}\x{7523}\x{7525}\x{7526}\x{7528}\x{752B}\x{752C}\x{7530}\x{7531}' . +'\x{7532}\x{7533}\x{7537}\x{7538}\x{753A}\x{753B}\x{753C}\x{7544}\x{7546}' . +'\x{7549}\x{754A}\x{754B}\x{754C}\x{754D}\x{754F}\x{7551}\x{7554}\x{7559}' . +'\x{755A}\x{755B}\x{755C}\x{755D}\x{7560}\x{7562}\x{7564}\x{7565}\x{7566}' . +'\x{7567}\x{7569}\x{756A}\x{756B}\x{756D}\x{7570}\x{7573}\x{7574}\x{7576}' . +'\x{7577}\x{7578}\x{757F}\x{7582}\x{7586}\x{7587}\x{7589}\x{758A}\x{758B}' . +'\x{758E}\x{758F}\x{7591}\x{7594}\x{759A}\x{759D}\x{75A3}\x{75A5}\x{75AB}' . +'\x{75B1}\x{75B2}\x{75B3}\x{75B5}\x{75B8}\x{75B9}\x{75BC}\x{75BD}\x{75BE}' . +'\x{75C2}\x{75C3}\x{75C5}\x{75C7}\x{75CA}\x{75CD}\x{75D2}\x{75D4}\x{75D5}' . +'\x{75D8}\x{75D9}\x{75DB}\x{75DE}\x{75E2}\x{75E3}\x{75E9}\x{75F0}\x{75F2}' . +'\x{75F3}\x{75F4}\x{75FA}\x{75FC}\x{75FE}\x{75FF}\x{7601}\x{7609}\x{760B}' . +'\x{760D}\x{761F}\x{7620}\x{7621}\x{7622}\x{7624}\x{7627}\x{7630}\x{7634}' . +'\x{763B}\x{7642}\x{7646}\x{7647}\x{7648}\x{764C}\x{7652}\x{7656}\x{7658}' . +'\x{765C}\x{7661}\x{7662}\x{7667}\x{7668}\x{7669}\x{766A}\x{766C}\x{7670}' . +'\x{7672}\x{7676}\x{7678}\x{767A}\x{767B}\x{767C}\x{767D}\x{767E}\x{7680}' . +'\x{7683}\x{7684}\x{7686}\x{7687}\x{7688}\x{768B}\x{768E}\x{7690}\x{7693}' . +'\x{7696}\x{7699}\x{769A}\x{76AE}\x{76B0}\x{76B4}\x{76B7}\x{76B8}\x{76B9}' . +'\x{76BA}\x{76BF}\x{76C2}\x{76C3}\x{76C6}\x{76C8}\x{76CA}\x{76CD}\x{76D2}' . +'\x{76D6}\x{76D7}\x{76DB}\x{76DC}\x{76DE}\x{76DF}\x{76E1}\x{76E3}\x{76E4}' . +'\x{76E5}\x{76E7}\x{76EA}\x{76EE}\x{76F2}\x{76F4}\x{76F8}\x{76FB}\x{76FE}' . +'\x{7701}\x{7704}\x{7707}\x{7708}\x{7709}\x{770B}\x{770C}\x{771B}\x{771E}' . +'\x{771F}\x{7720}\x{7724}\x{7725}\x{7726}\x{7729}\x{7737}\x{7738}\x{773A}' . +'\x{773C}\x{7740}\x{7747}\x{775A}\x{775B}\x{7761}\x{7763}\x{7765}\x{7766}' . +'\x{7768}\x{776B}\x{7779}\x{777E}\x{777F}\x{778B}\x{778E}\x{7791}\x{779E}' . +'\x{77A0}\x{77A5}\x{77AC}\x{77AD}\x{77B0}\x{77B3}\x{77B6}\x{77B9}\x{77BB}' . +'\x{77BC}\x{77BD}\x{77BF}\x{77C7}\x{77CD}\x{77D7}\x{77DA}\x{77DB}\x{77DC}' . +'\x{77E2}\x{77E3}\x{77E5}\x{77E7}\x{77E9}\x{77ED}\x{77EE}\x{77EF}\x{77F3}' . +'\x{77FC}\x{7802}\x{780C}\x{7812}\x{7814}\x{7815}\x{7820}\x{7825}\x{7826}' . +'\x{7827}\x{7832}\x{7834}\x{783A}\x{783F}\x{7845}\x{785D}\x{786B}\x{786C}' . +'\x{786F}\x{7872}\x{7874}\x{787C}\x{7881}\x{7886}\x{7887}\x{788C}\x{788D}' . +'\x{788E}\x{7891}\x{7893}\x{7895}\x{7897}\x{789A}\x{78A3}\x{78A7}\x{78A9}' . +'\x{78AA}\x{78AF}\x{78B5}\x{78BA}\x{78BC}\x{78BE}\x{78C1}\x{78C5}\x{78C6}' . +'\x{78CA}\x{78CB}\x{78D0}\x{78D1}\x{78D4}\x{78DA}\x{78E7}\x{78E8}\x{78EC}' . +'\x{78EF}\x{78F4}\x{78FD}\x{7901}\x{7907}\x{790E}\x{7911}\x{7912}\x{7919}' . +'\x{7926}\x{792A}\x{792B}\x{792C}\x{793A}\x{793C}\x{793E}\x{7940}\x{7941}' . +'\x{7947}\x{7948}\x{7949}\x{7950}\x{7953}\x{7955}\x{7956}\x{7957}\x{795A}' . +'\x{795D}\x{795E}\x{795F}\x{7960}\x{7962}\x{7965}\x{7968}\x{796D}\x{7977}' . +'\x{797A}\x{797F}\x{7980}\x{7981}\x{7984}\x{7985}\x{798A}\x{798D}\x{798E}' . +'\x{798F}\x{799D}\x{79A6}\x{79A7}\x{79AA}\x{79AE}\x{79B0}\x{79B3}\x{79B9}' . +'\x{79BA}\x{79BD}\x{79BE}\x{79BF}\x{79C0}\x{79C1}\x{79C9}\x{79CB}\x{79D1}' . +'\x{79D2}\x{79D5}\x{79D8}\x{79DF}\x{79E1}\x{79E3}\x{79E4}\x{79E6}\x{79E7}' . +'\x{79E9}\x{79EC}\x{79F0}\x{79FB}\x{7A00}\x{7A08}\x{7A0B}\x{7A0D}\x{7A0E}' . +'\x{7A14}\x{7A17}\x{7A18}\x{7A19}\x{7A1A}\x{7A1C}\x{7A1F}\x{7A20}\x{7A2E}' . +'\x{7A31}\x{7A32}\x{7A37}\x{7A3B}\x{7A3C}\x{7A3D}\x{7A3E}\x{7A3F}\x{7A40}' . +'\x{7A42}\x{7A43}\x{7A46}\x{7A49}\x{7A4D}\x{7A4E}\x{7A4F}\x{7A50}\x{7A57}' . +'\x{7A61}\x{7A62}\x{7A63}\x{7A69}\x{7A6B}\x{7A70}\x{7A74}\x{7A76}\x{7A79}' . +'\x{7A7A}\x{7A7D}\x{7A7F}\x{7A81}\x{7A83}\x{7A84}\x{7A88}\x{7A92}\x{7A93}' . +'\x{7A95}\x{7A96}\x{7A97}\x{7A98}\x{7A9F}\x{7AA9}\x{7AAA}\x{7AAE}\x{7AAF}' . +'\x{7AB0}\x{7AB6}\x{7ABA}\x{7ABF}\x{7AC3}\x{7AC4}\x{7AC5}\x{7AC7}\x{7AC8}' . +'\x{7ACA}\x{7ACB}\x{7ACD}\x{7ACF}\x{7AD2}\x{7AD3}\x{7AD5}\x{7AD9}\x{7ADA}' . +'\x{7ADC}\x{7ADD}\x{7ADF}\x{7AE0}\x{7AE1}\x{7AE2}\x{7AE3}\x{7AE5}\x{7AE6}' . +'\x{7AEA}\x{7AED}\x{7AEF}\x{7AF0}\x{7AF6}\x{7AF8}\x{7AF9}\x{7AFA}\x{7AFF}' . +'\x{7B02}\x{7B04}\x{7B06}\x{7B08}\x{7B0A}\x{7B0B}\x{7B0F}\x{7B11}\x{7B18}' . +'\x{7B19}\x{7B1B}\x{7B1E}\x{7B20}\x{7B25}\x{7B26}\x{7B28}\x{7B2C}\x{7B33}' . +'\x{7B35}\x{7B36}\x{7B39}\x{7B45}\x{7B46}\x{7B48}\x{7B49}\x{7B4B}\x{7B4C}' . +'\x{7B4D}\x{7B4F}\x{7B50}\x{7B51}\x{7B52}\x{7B54}\x{7B56}\x{7B5D}\x{7B65}' . +'\x{7B67}\x{7B6C}\x{7B6E}\x{7B70}\x{7B71}\x{7B74}\x{7B75}\x{7B7A}\x{7B86}' . +'\x{7B87}\x{7B8B}\x{7B8D}\x{7B8F}\x{7B92}\x{7B94}\x{7B95}\x{7B97}\x{7B98}' . +'\x{7B99}\x{7B9A}\x{7B9C}\x{7B9D}\x{7B9F}\x{7BA1}\x{7BAA}\x{7BAD}\x{7BB1}' . +'\x{7BB4}\x{7BB8}\x{7BC0}\x{7BC1}\x{7BC4}\x{7BC6}\x{7BC7}\x{7BC9}\x{7BCB}' . +'\x{7BCC}\x{7BCF}\x{7BDD}\x{7BE0}\x{7BE4}\x{7BE5}\x{7BE6}\x{7BE9}\x{7BED}' . +'\x{7BF3}\x{7BF6}\x{7BF7}\x{7C00}\x{7C07}\x{7C0D}\x{7C11}\x{7C12}\x{7C13}' . +'\x{7C14}\x{7C17}\x{7C1F}\x{7C21}\x{7C23}\x{7C27}\x{7C2A}\x{7C2B}\x{7C37}' . +'\x{7C38}\x{7C3D}\x{7C3E}\x{7C3F}\x{7C40}\x{7C43}\x{7C4C}\x{7C4D}\x{7C4F}' . +'\x{7C50}\x{7C54}\x{7C56}\x{7C58}\x{7C5F}\x{7C60}\x{7C64}\x{7C65}\x{7C6C}' . +'\x{7C73}\x{7C75}\x{7C7E}\x{7C81}\x{7C82}\x{7C83}\x{7C89}\x{7C8B}\x{7C8D}' . +'\x{7C90}\x{7C92}\x{7C95}\x{7C97}\x{7C98}\x{7C9B}\x{7C9F}\x{7CA1}\x{7CA2}' . +'\x{7CA4}\x{7CA5}\x{7CA7}\x{7CA8}\x{7CAB}\x{7CAD}\x{7CAE}\x{7CB1}\x{7CB2}' . +'\x{7CB3}\x{7CB9}\x{7CBD}\x{7CBE}\x{7CC0}\x{7CC2}\x{7CC5}\x{7CCA}\x{7CCE}' . +'\x{7CD2}\x{7CD6}\x{7CD8}\x{7CDC}\x{7CDE}\x{7CDF}\x{7CE0}\x{7CE2}\x{7CE7}' . +'\x{7CEF}\x{7CF2}\x{7CF4}\x{7CF6}\x{7CF8}\x{7CFA}\x{7CFB}\x{7CFE}\x{7D00}' . +'\x{7D02}\x{7D04}\x{7D05}\x{7D06}\x{7D0A}\x{7D0B}\x{7D0D}\x{7D10}\x{7D14}' . +'\x{7D15}\x{7D17}\x{7D18}\x{7D19}\x{7D1A}\x{7D1B}\x{7D1C}\x{7D20}\x{7D21}' . +'\x{7D22}\x{7D2B}\x{7D2C}\x{7D2E}\x{7D2F}\x{7D30}\x{7D32}\x{7D33}\x{7D35}' . +'\x{7D39}\x{7D3A}\x{7D3F}\x{7D42}\x{7D43}\x{7D44}\x{7D45}\x{7D46}\x{7D4B}' . +'\x{7D4C}\x{7D4E}\x{7D4F}\x{7D50}\x{7D56}\x{7D5B}\x{7D5E}\x{7D61}\x{7D62}' . +'\x{7D63}\x{7D66}\x{7D68}\x{7D6E}\x{7D71}\x{7D72}\x{7D73}\x{7D75}\x{7D76}' . +'\x{7D79}\x{7D7D}\x{7D89}\x{7D8F}\x{7D93}\x{7D99}\x{7D9A}\x{7D9B}\x{7D9C}' . +'\x{7D9F}\x{7DA2}\x{7DA3}\x{7DAB}\x{7DAC}\x{7DAD}\x{7DAE}\x{7DAF}\x{7DB0}' . +'\x{7DB1}\x{7DB2}\x{7DB4}\x{7DB5}\x{7DB8}\x{7DBA}\x{7DBB}\x{7DBD}\x{7DBE}' . +'\x{7DBF}\x{7DC7}\x{7DCA}\x{7DCB}\x{7DCF}\x{7DD1}\x{7DD2}\x{7DD5}\x{7DD8}' . +'\x{7DDA}\x{7DDC}\x{7DDD}\x{7DDE}\x{7DE0}\x{7DE1}\x{7DE4}\x{7DE8}\x{7DE9}' . +'\x{7DEC}\x{7DEF}\x{7DF2}\x{7DF4}\x{7DFB}\x{7E01}\x{7E04}\x{7E05}\x{7E09}' . +'\x{7E0A}\x{7E0B}\x{7E12}\x{7E1B}\x{7E1E}\x{7E1F}\x{7E21}\x{7E22}\x{7E23}' . +'\x{7E26}\x{7E2B}\x{7E2E}\x{7E31}\x{7E32}\x{7E35}\x{7E37}\x{7E39}\x{7E3A}' . +'\x{7E3B}\x{7E3D}\x{7E3E}\x{7E41}\x{7E43}\x{7E46}\x{7E4A}\x{7E4B}\x{7E4D}' . +'\x{7E54}\x{7E55}\x{7E56}\x{7E59}\x{7E5A}\x{7E5D}\x{7E5E}\x{7E66}\x{7E67}' . +'\x{7E69}\x{7E6A}\x{7E6D}\x{7E70}\x{7E79}\x{7E7B}\x{7E7C}\x{7E7D}\x{7E7F}' . +'\x{7E82}\x{7E83}\x{7E88}\x{7E89}\x{7E8C}\x{7E8E}\x{7E8F}\x{7E90}\x{7E92}' . +'\x{7E93}\x{7E94}\x{7E96}\x{7E9B}\x{7E9C}\x{7F36}\x{7F38}\x{7F3A}\x{7F45}' . +'\x{7F4C}\x{7F4D}\x{7F4E}\x{7F50}\x{7F51}\x{7F54}\x{7F55}\x{7F58}\x{7F5F}' . +'\x{7F60}\x{7F67}\x{7F68}\x{7F69}\x{7F6A}\x{7F6B}\x{7F6E}\x{7F70}\x{7F72}' . +'\x{7F75}\x{7F77}\x{7F78}\x{7F79}\x{7F82}\x{7F83}\x{7F85}\x{7F86}\x{7F87}' . +'\x{7F88}\x{7F8A}\x{7F8C}\x{7F8E}\x{7F94}\x{7F9A}\x{7F9D}\x{7F9E}\x{7FA3}' . +'\x{7FA4}\x{7FA8}\x{7FA9}\x{7FAE}\x{7FAF}\x{7FB2}\x{7FB6}\x{7FB8}\x{7FB9}' . +'\x{7FBD}\x{7FC1}\x{7FC5}\x{7FC6}\x{7FCA}\x{7FCC}\x{7FD2}\x{7FD4}\x{7FD5}' . +'\x{7FE0}\x{7FE1}\x{7FE6}\x{7FE9}\x{7FEB}\x{7FF0}\x{7FF3}\x{7FF9}\x{7FFB}' . +'\x{7FFC}\x{8000}\x{8001}\x{8003}\x{8004}\x{8005}\x{8006}\x{800B}\x{800C}' . +'\x{8010}\x{8012}\x{8015}\x{8017}\x{8018}\x{8019}\x{801C}\x{8021}\x{8028}' . +'\x{8033}\x{8036}\x{803B}\x{803D}\x{803F}\x{8046}\x{804A}\x{8052}\x{8056}' . +'\x{8058}\x{805A}\x{805E}\x{805F}\x{8061}\x{8062}\x{8068}\x{806F}\x{8070}' . +'\x{8072}\x{8073}\x{8074}\x{8076}\x{8077}\x{8079}\x{807D}\x{807E}\x{807F}' . +'\x{8084}\x{8085}\x{8086}\x{8087}\x{8089}\x{808B}\x{808C}\x{8093}\x{8096}' . +'\x{8098}\x{809A}\x{809B}\x{809D}\x{80A1}\x{80A2}\x{80A5}\x{80A9}\x{80AA}' . +'\x{80AC}\x{80AD}\x{80AF}\x{80B1}\x{80B2}\x{80B4}\x{80BA}\x{80C3}\x{80C4}' . +'\x{80C6}\x{80CC}\x{80CE}\x{80D6}\x{80D9}\x{80DA}\x{80DB}\x{80DD}\x{80DE}' . +'\x{80E1}\x{80E4}\x{80E5}\x{80EF}\x{80F1}\x{80F4}\x{80F8}\x{80FC}\x{80FD}' . +'\x{8102}\x{8105}\x{8106}\x{8107}\x{8108}\x{8109}\x{810A}\x{811A}\x{811B}' . +'\x{8123}\x{8129}\x{812F}\x{8131}\x{8133}\x{8139}\x{813E}\x{8146}\x{814B}' . +'\x{814E}\x{8150}\x{8151}\x{8153}\x{8154}\x{8155}\x{815F}\x{8165}\x{8166}' . +'\x{816B}\x{816E}\x{8170}\x{8171}\x{8174}\x{8178}\x{8179}\x{817A}\x{817F}' . +'\x{8180}\x{8182}\x{8183}\x{8188}\x{818A}\x{818F}\x{8193}\x{8195}\x{819A}' . +'\x{819C}\x{819D}\x{81A0}\x{81A3}\x{81A4}\x{81A8}\x{81A9}\x{81B0}\x{81B3}' . +'\x{81B5}\x{81B8}\x{81BA}\x{81BD}\x{81BE}\x{81BF}\x{81C0}\x{81C2}\x{81C6}' . +'\x{81C8}\x{81C9}\x{81CD}\x{81D1}\x{81D3}\x{81D8}\x{81D9}\x{81DA}\x{81DF}' . +'\x{81E0}\x{81E3}\x{81E5}\x{81E7}\x{81E8}\x{81EA}\x{81ED}\x{81F3}\x{81F4}' . +'\x{81FA}\x{81FB}\x{81FC}\x{81FE}\x{8201}\x{8202}\x{8205}\x{8207}\x{8208}' . +'\x{8209}\x{820A}\x{820C}\x{820D}\x{820E}\x{8210}\x{8212}\x{8216}\x{8217}' . +'\x{8218}\x{821B}\x{821C}\x{821E}\x{821F}\x{8229}\x{822A}\x{822B}\x{822C}' . +'\x{822E}\x{8233}\x{8235}\x{8236}\x{8237}\x{8238}\x{8239}\x{8240}\x{8247}' . +'\x{8258}\x{8259}\x{825A}\x{825D}\x{825F}\x{8262}\x{8264}\x{8266}\x{8268}' . +'\x{826A}\x{826B}\x{826E}\x{826F}\x{8271}\x{8272}\x{8276}\x{8277}\x{8278}' . +'\x{827E}\x{828B}\x{828D}\x{8292}\x{8299}\x{829D}\x{829F}\x{82A5}\x{82A6}' . +'\x{82AB}\x{82AC}\x{82AD}\x{82AF}\x{82B1}\x{82B3}\x{82B8}\x{82B9}\x{82BB}' . +'\x{82BD}\x{82C5}\x{82D1}\x{82D2}\x{82D3}\x{82D4}\x{82D7}\x{82D9}\x{82DB}' . +'\x{82DC}\x{82DE}\x{82DF}\x{82E1}\x{82E3}\x{82E5}\x{82E6}\x{82E7}\x{82EB}' . +'\x{82F1}\x{82F3}\x{82F4}\x{82F9}\x{82FA}\x{82FB}\x{8302}\x{8303}\x{8304}' . +'\x{8305}\x{8306}\x{8309}\x{830E}\x{8316}\x{8317}\x{8318}\x{831C}\x{8323}' . +'\x{8328}\x{832B}\x{832F}\x{8331}\x{8332}\x{8334}\x{8335}\x{8336}\x{8338}' . +'\x{8339}\x{8340}\x{8345}\x{8349}\x{834A}\x{834F}\x{8350}\x{8352}\x{8358}' . +'\x{8373}\x{8375}\x{8377}\x{837B}\x{837C}\x{8385}\x{8387}\x{8389}\x{838A}' . +'\x{838E}\x{8393}\x{8396}\x{839A}\x{839E}\x{839F}\x{83A0}\x{83A2}\x{83A8}' . +'\x{83AA}\x{83AB}\x{83B1}\x{83B5}\x{83BD}\x{83C1}\x{83C5}\x{83CA}\x{83CC}' . +'\x{83CE}\x{83D3}\x{83D6}\x{83D8}\x{83DC}\x{83DF}\x{83E0}\x{83E9}\x{83EB}' . +'\x{83EF}\x{83F0}\x{83F1}\x{83F2}\x{83F4}\x{83F7}\x{83FB}\x{83FD}\x{8403}' . +'\x{8404}\x{8407}\x{840B}\x{840C}\x{840D}\x{840E}\x{8413}\x{8420}\x{8422}' . +'\x{8429}\x{842A}\x{842C}\x{8431}\x{8435}\x{8438}\x{843C}\x{843D}\x{8446}' . +'\x{8449}\x{844E}\x{8457}\x{845B}\x{8461}\x{8462}\x{8463}\x{8466}\x{8469}' . +'\x{846B}\x{846C}\x{846D}\x{846E}\x{846F}\x{8471}\x{8475}\x{8477}\x{8479}' . +'\x{847A}\x{8482}\x{8484}\x{848B}\x{8490}\x{8494}\x{8499}\x{849C}\x{849F}' . +'\x{84A1}\x{84AD}\x{84B2}\x{84B8}\x{84B9}\x{84BB}\x{84BC}\x{84BF}\x{84C1}' . +'\x{84C4}\x{84C6}\x{84C9}\x{84CA}\x{84CB}\x{84CD}\x{84D0}\x{84D1}\x{84D6}' . +'\x{84D9}\x{84DA}\x{84EC}\x{84EE}\x{84F4}\x{84FC}\x{84FF}\x{8500}\x{8506}' . +'\x{8511}\x{8513}\x{8514}\x{8515}\x{8517}\x{8518}\x{851A}\x{851F}\x{8521}' . +'\x{8526}\x{852C}\x{852D}\x{8535}\x{853D}\x{8540}\x{8541}\x{8543}\x{8548}' . +'\x{8549}\x{854A}\x{854B}\x{854E}\x{8555}\x{8557}\x{8558}\x{855A}\x{8563}' . +'\x{8568}\x{8569}\x{856A}\x{856D}\x{8577}\x{857E}\x{8580}\x{8584}\x{8587}' . +'\x{8588}\x{858A}\x{8590}\x{8591}\x{8594}\x{8597}\x{8599}\x{859B}\x{859C}' . +'\x{85A4}\x{85A6}\x{85A8}\x{85A9}\x{85AA}\x{85AB}\x{85AC}\x{85AE}\x{85AF}' . +'\x{85B9}\x{85BA}\x{85C1}\x{85C9}\x{85CD}\x{85CF}\x{85D0}\x{85D5}\x{85DC}' . +'\x{85DD}\x{85E4}\x{85E5}\x{85E9}\x{85EA}\x{85F7}\x{85F9}\x{85FA}\x{85FB}' . +'\x{85FE}\x{8602}\x{8606}\x{8607}\x{860A}\x{860B}\x{8613}\x{8616}\x{8617}' . +'\x{861A}\x{8622}\x{862D}\x{862F}\x{8630}\x{863F}\x{864D}\x{864E}\x{8650}' . +'\x{8654}\x{8655}\x{865A}\x{865C}\x{865E}\x{865F}\x{8667}\x{866B}\x{8671}' . +'\x{8679}\x{867B}\x{868A}\x{868B}\x{868C}\x{8693}\x{8695}\x{86A3}\x{86A4}' . +'\x{86A9}\x{86AA}\x{86AB}\x{86AF}\x{86B0}\x{86B6}\x{86C4}\x{86C6}\x{86C7}' . +'\x{86C9}\x{86CB}\x{86CD}\x{86CE}\x{86D4}\x{86D9}\x{86DB}\x{86DE}\x{86DF}' . +'\x{86E4}\x{86E9}\x{86EC}\x{86ED}\x{86EE}\x{86EF}\x{86F8}\x{86F9}\x{86FB}' . +'\x{86FE}\x{8700}\x{8702}\x{8703}\x{8706}\x{8708}\x{8709}\x{870A}\x{870D}' . +'\x{8711}\x{8712}\x{8718}\x{871A}\x{871C}\x{8725}\x{8729}\x{8734}\x{8737}' . +'\x{873B}\x{873F}\x{8749}\x{874B}\x{874C}\x{874E}\x{8753}\x{8755}\x{8757}' . +'\x{8759}\x{875F}\x{8760}\x{8763}\x{8766}\x{8768}\x{876A}\x{876E}\x{8774}' . +'\x{8776}\x{8778}\x{877F}\x{8782}\x{878D}\x{879F}\x{87A2}\x{87AB}\x{87AF}' . +'\x{87B3}\x{87BA}\x{87BB}\x{87BD}\x{87C0}\x{87C4}\x{87C6}\x{87C7}\x{87CB}' . +'\x{87D0}\x{87D2}\x{87E0}\x{87EF}\x{87F2}\x{87F6}\x{87F7}\x{87F9}\x{87FB}' . +'\x{87FE}\x{8805}\x{880D}\x{880E}\x{880F}\x{8811}\x{8815}\x{8816}\x{8821}' . +'\x{8822}\x{8823}\x{8827}\x{8831}\x{8836}\x{8839}\x{883B}\x{8840}\x{8842}' . +'\x{8844}\x{8846}\x{884C}\x{884D}\x{8852}\x{8853}\x{8857}\x{8859}\x{885B}' . +'\x{885D}\x{885E}\x{8861}\x{8862}\x{8863}\x{8868}\x{886B}\x{8870}\x{8872}' . +'\x{8875}\x{8877}\x{887D}\x{887E}\x{887F}\x{8881}\x{8882}\x{8888}\x{888B}' . +'\x{888D}\x{8892}\x{8896}\x{8897}\x{8899}\x{889E}\x{88A2}\x{88A4}\x{88AB}' . +'\x{88AE}\x{88B0}\x{88B1}\x{88B4}\x{88B5}\x{88B7}\x{88BF}\x{88C1}\x{88C2}' . +'\x{88C3}\x{88C4}\x{88C5}\x{88CF}\x{88D4}\x{88D5}\x{88D8}\x{88D9}\x{88DC}' . +'\x{88DD}\x{88DF}\x{88E1}\x{88E8}\x{88F2}\x{88F3}\x{88F4}\x{88F8}\x{88F9}' . +'\x{88FC}\x{88FD}\x{88FE}\x{8902}\x{8904}\x{8907}\x{890A}\x{890C}\x{8910}' . +'\x{8912}\x{8913}\x{891D}\x{891E}\x{8925}\x{892A}\x{892B}\x{8936}\x{8938}' . +'\x{893B}\x{8941}\x{8943}\x{8944}\x{894C}\x{894D}\x{8956}\x{895E}\x{895F}' . +'\x{8960}\x{8964}\x{8966}\x{896A}\x{896D}\x{896F}\x{8972}\x{8974}\x{8977}' . +'\x{897E}\x{897F}\x{8981}\x{8983}\x{8986}\x{8987}\x{8988}\x{898A}\x{898B}' . +'\x{898F}\x{8993}\x{8996}\x{8997}\x{8998}\x{899A}\x{89A1}\x{89A6}\x{89A7}' . +'\x{89A9}\x{89AA}\x{89AC}\x{89AF}\x{89B2}\x{89B3}\x{89BA}\x{89BD}\x{89BF}' . +'\x{89C0}\x{89D2}\x{89DA}\x{89DC}\x{89DD}\x{89E3}\x{89E6}\x{89E7}\x{89F4}' . +'\x{89F8}\x{8A00}\x{8A02}\x{8A03}\x{8A08}\x{8A0A}\x{8A0C}\x{8A0E}\x{8A10}' . +'\x{8A13}\x{8A16}\x{8A17}\x{8A18}\x{8A1B}\x{8A1D}\x{8A1F}\x{8A23}\x{8A25}' . +'\x{8A2A}\x{8A2D}\x{8A31}\x{8A33}\x{8A34}\x{8A36}\x{8A3A}\x{8A3B}\x{8A3C}' . +'\x{8A41}\x{8A46}\x{8A48}\x{8A50}\x{8A51}\x{8A52}\x{8A54}\x{8A55}\x{8A5B}' . +'\x{8A5E}\x{8A60}\x{8A62}\x{8A63}\x{8A66}\x{8A69}\x{8A6B}\x{8A6C}\x{8A6D}' . +'\x{8A6E}\x{8A70}\x{8A71}\x{8A72}\x{8A73}\x{8A7C}\x{8A82}\x{8A84}\x{8A85}' . +'\x{8A87}\x{8A89}\x{8A8C}\x{8A8D}\x{8A91}\x{8A93}\x{8A95}\x{8A98}\x{8A9A}' . +'\x{8A9E}\x{8AA0}\x{8AA1}\x{8AA3}\x{8AA4}\x{8AA5}\x{8AA6}\x{8AA8}\x{8AAC}' . +'\x{8AAD}\x{8AB0}\x{8AB2}\x{8AB9}\x{8ABC}\x{8ABF}\x{8AC2}\x{8AC4}\x{8AC7}' . +'\x{8ACB}\x{8ACC}\x{8ACD}\x{8ACF}\x{8AD2}\x{8AD6}\x{8ADA}\x{8ADB}\x{8ADC}' . +'\x{8ADE}\x{8AE0}\x{8AE1}\x{8AE2}\x{8AE4}\x{8AE6}\x{8AE7}\x{8AEB}\x{8AED}' . +'\x{8AEE}\x{8AF1}\x{8AF3}\x{8AF7}\x{8AF8}\x{8AFA}\x{8AFE}\x{8B00}\x{8B01}' . +'\x{8B02}\x{8B04}\x{8B07}\x{8B0C}\x{8B0E}\x{8B10}\x{8B14}\x{8B16}\x{8B17}' . +'\x{8B19}\x{8B1A}\x{8B1B}\x{8B1D}\x{8B20}\x{8B21}\x{8B26}\x{8B28}\x{8B2B}' . +'\x{8B2C}\x{8B33}\x{8B39}\x{8B3E}\x{8B41}\x{8B49}\x{8B4C}\x{8B4E}\x{8B4F}' . +'\x{8B56}\x{8B58}\x{8B5A}\x{8B5B}\x{8B5C}\x{8B5F}\x{8B66}\x{8B6B}\x{8B6C}' . +'\x{8B6F}\x{8B70}\x{8B71}\x{8B72}\x{8B74}\x{8B77}\x{8B7D}\x{8B80}\x{8B83}' . +'\x{8B8A}\x{8B8C}\x{8B8E}\x{8B90}\x{8B92}\x{8B93}\x{8B96}\x{8B99}\x{8B9A}' . +'\x{8C37}\x{8C3A}\x{8C3F}\x{8C41}\x{8C46}\x{8C48}\x{8C4A}\x{8C4C}\x{8C4E}' . +'\x{8C50}\x{8C55}\x{8C5A}\x{8C61}\x{8C62}\x{8C6A}\x{8C6B}\x{8C6C}\x{8C78}' . +'\x{8C79}\x{8C7A}\x{8C7C}\x{8C82}\x{8C85}\x{8C89}\x{8C8A}\x{8C8C}\x{8C8D}' . +'\x{8C8E}\x{8C94}\x{8C98}\x{8C9D}\x{8C9E}\x{8CA0}\x{8CA1}\x{8CA2}\x{8CA7}' . +'\x{8CA8}\x{8CA9}\x{8CAA}\x{8CAB}\x{8CAC}\x{8CAD}\x{8CAE}\x{8CAF}\x{8CB0}' . +'\x{8CB2}\x{8CB3}\x{8CB4}\x{8CB6}\x{8CB7}\x{8CB8}\x{8CBB}\x{8CBC}\x{8CBD}' . +'\x{8CBF}\x{8CC0}\x{8CC1}\x{8CC2}\x{8CC3}\x{8CC4}\x{8CC7}\x{8CC8}\x{8CCA}' . +'\x{8CCD}\x{8CCE}\x{8CD1}\x{8CD3}\x{8CDA}\x{8CDB}\x{8CDC}\x{8CDE}\x{8CE0}' . +'\x{8CE2}\x{8CE3}\x{8CE4}\x{8CE6}\x{8CEA}\x{8CED}\x{8CFA}\x{8CFB}\x{8CFC}' . +'\x{8CFD}\x{8D04}\x{8D05}\x{8D07}\x{8D08}\x{8D0A}\x{8D0B}\x{8D0D}\x{8D0F}' . +'\x{8D10}\x{8D13}\x{8D14}\x{8D16}\x{8D64}\x{8D66}\x{8D67}\x{8D6B}\x{8D6D}' . +'\x{8D70}\x{8D71}\x{8D73}\x{8D74}\x{8D77}\x{8D81}\x{8D85}\x{8D8A}\x{8D99}' . +'\x{8DA3}\x{8DA8}\x{8DB3}\x{8DBA}\x{8DBE}\x{8DC2}\x{8DCB}\x{8DCC}\x{8DCF}' . +'\x{8DD6}\x{8DDA}\x{8DDB}\x{8DDD}\x{8DDF}\x{8DE1}\x{8DE3}\x{8DE8}\x{8DEA}' . +'\x{8DEB}\x{8DEF}\x{8DF3}\x{8DF5}\x{8DFC}\x{8DFF}\x{8E08}\x{8E09}\x{8E0A}' . +'\x{8E0F}\x{8E10}\x{8E1D}\x{8E1E}\x{8E1F}\x{8E2A}\x{8E30}\x{8E34}\x{8E35}' . +'\x{8E42}\x{8E44}\x{8E47}\x{8E48}\x{8E49}\x{8E4A}\x{8E4C}\x{8E50}\x{8E55}' . +'\x{8E59}\x{8E5F}\x{8E60}\x{8E63}\x{8E64}\x{8E72}\x{8E74}\x{8E76}\x{8E7C}' . +'\x{8E81}\x{8E84}\x{8E85}\x{8E87}\x{8E8A}\x{8E8B}\x{8E8D}\x{8E91}\x{8E93}' . +'\x{8E94}\x{8E99}\x{8EA1}\x{8EAA}\x{8EAB}\x{8EAC}\x{8EAF}\x{8EB0}\x{8EB1}' . +'\x{8EBE}\x{8EC5}\x{8EC6}\x{8EC8}\x{8ECA}\x{8ECB}\x{8ECC}\x{8ECD}\x{8ED2}' . +'\x{8EDB}\x{8EDF}\x{8EE2}\x{8EE3}\x{8EEB}\x{8EF8}\x{8EFB}\x{8EFC}\x{8EFD}' . +'\x{8EFE}\x{8F03}\x{8F05}\x{8F09}\x{8F0A}\x{8F0C}\x{8F12}\x{8F13}\x{8F14}' . +'\x{8F15}\x{8F19}\x{8F1B}\x{8F1C}\x{8F1D}\x{8F1F}\x{8F26}\x{8F29}\x{8F2A}' . +'\x{8F2F}\x{8F33}\x{8F38}\x{8F39}\x{8F3B}\x{8F3E}\x{8F3F}\x{8F42}\x{8F44}' . +'\x{8F45}\x{8F46}\x{8F49}\x{8F4C}\x{8F4D}\x{8F4E}\x{8F57}\x{8F5C}\x{8F5F}' . +'\x{8F61}\x{8F62}\x{8F63}\x{8F64}\x{8F9B}\x{8F9C}\x{8F9E}\x{8F9F}\x{8FA3}' . +'\x{8FA7}\x{8FA8}\x{8FAD}\x{8FAE}\x{8FAF}\x{8FB0}\x{8FB1}\x{8FB2}\x{8FB7}' . +'\x{8FBA}\x{8FBB}\x{8FBC}\x{8FBF}\x{8FC2}\x{8FC4}\x{8FC5}\x{8FCE}\x{8FD1}' . +'\x{8FD4}\x{8FDA}\x{8FE2}\x{8FE5}\x{8FE6}\x{8FE9}\x{8FEA}\x{8FEB}\x{8FED}' . +'\x{8FEF}\x{8FF0}\x{8FF4}\x{8FF7}\x{8FF8}\x{8FF9}\x{8FFA}\x{8FFD}\x{9000}' . +'\x{9001}\x{9003}\x{9005}\x{9006}\x{900B}\x{900D}\x{900E}\x{900F}\x{9010}' . +'\x{9011}\x{9013}\x{9014}\x{9015}\x{9016}\x{9017}\x{9019}\x{901A}\x{901D}' . +'\x{901E}\x{901F}\x{9020}\x{9021}\x{9022}\x{9023}\x{9027}\x{902E}\x{9031}' . +'\x{9032}\x{9035}\x{9036}\x{9038}\x{9039}\x{903C}\x{903E}\x{9041}\x{9042}' . +'\x{9045}\x{9047}\x{9049}\x{904A}\x{904B}\x{904D}\x{904E}\x{904F}\x{9050}' . +'\x{9051}\x{9052}\x{9053}\x{9054}\x{9055}\x{9056}\x{9058}\x{9059}\x{905C}' . +'\x{905E}\x{9060}\x{9061}\x{9063}\x{9065}\x{9068}\x{9069}\x{906D}\x{906E}' . +'\x{906F}\x{9072}\x{9075}\x{9076}\x{9077}\x{9078}\x{907A}\x{907C}\x{907D}' . +'\x{907F}\x{9080}\x{9081}\x{9082}\x{9083}\x{9084}\x{9087}\x{9089}\x{908A}' . +'\x{908F}\x{9091}\x{90A3}\x{90A6}\x{90A8}\x{90AA}\x{90AF}\x{90B1}\x{90B5}' . +'\x{90B8}\x{90C1}\x{90CA}\x{90CE}\x{90DB}\x{90E1}\x{90E2}\x{90E4}\x{90E8}' . +'\x{90ED}\x{90F5}\x{90F7}\x{90FD}\x{9102}\x{9112}\x{9119}\x{912D}\x{9130}' . +'\x{9132}\x{9149}\x{914A}\x{914B}\x{914C}\x{914D}\x{914E}\x{9152}\x{9154}' . +'\x{9156}\x{9158}\x{9162}\x{9163}\x{9165}\x{9169}\x{916A}\x{916C}\x{9172}' . +'\x{9173}\x{9175}\x{9177}\x{9178}\x{9182}\x{9187}\x{9189}\x{918B}\x{918D}' . +'\x{9190}\x{9192}\x{9197}\x{919C}\x{91A2}\x{91A4}\x{91AA}\x{91AB}\x{91AF}' . +'\x{91B4}\x{91B5}\x{91B8}\x{91BA}\x{91C0}\x{91C1}\x{91C6}\x{91C7}\x{91C8}' . +'\x{91C9}\x{91CB}\x{91CC}\x{91CD}\x{91CE}\x{91CF}\x{91D0}\x{91D1}\x{91D6}' . +'\x{91D8}\x{91DB}\x{91DC}\x{91DD}\x{91DF}\x{91E1}\x{91E3}\x{91E6}\x{91E7}' . +'\x{91F5}\x{91F6}\x{91FC}\x{91FF}\x{920D}\x{920E}\x{9211}\x{9214}\x{9215}' . +'\x{921E}\x{9229}\x{922C}\x{9234}\x{9237}\x{923F}\x{9244}\x{9245}\x{9248}' . +'\x{9249}\x{924B}\x{9250}\x{9257}\x{925A}\x{925B}\x{925E}\x{9262}\x{9264}' . +'\x{9266}\x{9271}\x{927E}\x{9280}\x{9283}\x{9285}\x{9291}\x{9293}\x{9295}' . +'\x{9296}\x{9298}\x{929A}\x{929B}\x{929C}\x{92AD}\x{92B7}\x{92B9}\x{92CF}' . +'\x{92D2}\x{92E4}\x{92E9}\x{92EA}\x{92ED}\x{92F2}\x{92F3}\x{92F8}\x{92FA}' . +'\x{92FC}\x{9306}\x{930F}\x{9310}\x{9318}\x{9319}\x{931A}\x{9320}\x{9322}' . +'\x{9323}\x{9326}\x{9328}\x{932B}\x{932C}\x{932E}\x{932F}\x{9332}\x{9335}' . +'\x{933A}\x{933B}\x{9344}\x{934B}\x{934D}\x{9354}\x{9356}\x{935B}\x{935C}' . +'\x{9360}\x{936C}\x{936E}\x{9375}\x{937C}\x{937E}\x{938C}\x{9394}\x{9396}' . +'\x{9397}\x{939A}\x{93A7}\x{93AC}\x{93AD}\x{93AE}\x{93B0}\x{93B9}\x{93C3}' . +'\x{93C8}\x{93D0}\x{93D1}\x{93D6}\x{93D7}\x{93D8}\x{93DD}\x{93E1}\x{93E4}' . +'\x{93E5}\x{93E8}\x{9403}\x{9407}\x{9410}\x{9413}\x{9414}\x{9418}\x{9419}' . +'\x{941A}\x{9421}\x{942B}\x{9435}\x{9436}\x{9438}\x{943A}\x{9441}\x{9444}' . +'\x{9451}\x{9452}\x{9453}\x{945A}\x{945B}\x{945E}\x{9460}\x{9462}\x{946A}' . +'\x{9470}\x{9475}\x{9477}\x{947C}\x{947D}\x{947E}\x{947F}\x{9481}\x{9577}' . +'\x{9580}\x{9582}\x{9583}\x{9587}\x{9589}\x{958A}\x{958B}\x{958F}\x{9591}' . +'\x{9593}\x{9594}\x{9596}\x{9598}\x{9599}\x{95A0}\x{95A2}\x{95A3}\x{95A4}' . +'\x{95A5}\x{95A7}\x{95A8}\x{95AD}\x{95B2}\x{95B9}\x{95BB}\x{95BC}\x{95BE}' . +'\x{95C3}\x{95C7}\x{95CA}\x{95CC}\x{95CD}\x{95D4}\x{95D5}\x{95D6}\x{95D8}' . +'\x{95DC}\x{95E1}\x{95E2}\x{95E5}\x{961C}\x{9621}\x{9628}\x{962A}\x{962E}' . +'\x{962F}\x{9632}\x{963B}\x{963F}\x{9640}\x{9642}\x{9644}\x{964B}\x{964C}' . +'\x{964D}\x{964F}\x{9650}\x{965B}\x{965C}\x{965D}\x{965E}\x{965F}\x{9662}' . +'\x{9663}\x{9664}\x{9665}\x{9666}\x{966A}\x{966C}\x{9670}\x{9672}\x{9673}' . +'\x{9675}\x{9676}\x{9677}\x{9678}\x{967A}\x{967D}\x{9685}\x{9686}\x{9688}' . +'\x{968A}\x{968B}\x{968D}\x{968E}\x{968F}\x{9694}\x{9695}\x{9697}\x{9698}' . +'\x{9699}\x{969B}\x{969C}\x{96A0}\x{96A3}\x{96A7}\x{96A8}\x{96AA}\x{96B0}' . +'\x{96B1}\x{96B2}\x{96B4}\x{96B6}\x{96B7}\x{96B8}\x{96B9}\x{96BB}\x{96BC}' . +'\x{96C0}\x{96C1}\x{96C4}\x{96C5}\x{96C6}\x{96C7}\x{96C9}\x{96CB}\x{96CC}' . +'\x{96CD}\x{96CE}\x{96D1}\x{96D5}\x{96D6}\x{96D9}\x{96DB}\x{96DC}\x{96E2}' . +'\x{96E3}\x{96E8}\x{96EA}\x{96EB}\x{96F0}\x{96F2}\x{96F6}\x{96F7}\x{96F9}' . +'\x{96FB}\x{9700}\x{9704}\x{9706}\x{9707}\x{9708}\x{970A}\x{970D}\x{970E}' . +'\x{970F}\x{9711}\x{9713}\x{9716}\x{9719}\x{971C}\x{971E}\x{9724}\x{9727}' . +'\x{972A}\x{9730}\x{9732}\x{9738}\x{9739}\x{973D}\x{973E}\x{9742}\x{9744}' . +'\x{9746}\x{9748}\x{9749}\x{9752}\x{9756}\x{9759}\x{975C}\x{975E}\x{9760}' . +'\x{9761}\x{9762}\x{9764}\x{9766}\x{9768}\x{9769}\x{976B}\x{976D}\x{9771}' . +'\x{9774}\x{9779}\x{977A}\x{977C}\x{9781}\x{9784}\x{9785}\x{9786}\x{978B}' . +'\x{978D}\x{978F}\x{9790}\x{9798}\x{979C}\x{97A0}\x{97A3}\x{97A6}\x{97A8}' . +'\x{97AB}\x{97AD}\x{97B3}\x{97B4}\x{97C3}\x{97C6}\x{97C8}\x{97CB}\x{97D3}' . +'\x{97DC}\x{97ED}\x{97EE}\x{97F2}\x{97F3}\x{97F5}\x{97F6}\x{97FB}\x{97FF}' . +'\x{9801}\x{9802}\x{9803}\x{9805}\x{9806}\x{9808}\x{980C}\x{980F}\x{9810}' . +'\x{9811}\x{9812}\x{9813}\x{9817}\x{9818}\x{981A}\x{9821}\x{9824}\x{982C}' . +'\x{982D}\x{9834}\x{9837}\x{9838}\x{983B}\x{983C}\x{983D}\x{9846}\x{984B}' . +'\x{984C}\x{984D}\x{984E}\x{984F}\x{9854}\x{9855}\x{9858}\x{985B}\x{985E}' . +'\x{9867}\x{986B}\x{986F}\x{9870}\x{9871}\x{9873}\x{9874}\x{98A8}\x{98AA}' . +'\x{98AF}\x{98B1}\x{98B6}\x{98C3}\x{98C4}\x{98C6}\x{98DB}\x{98DC}\x{98DF}' . +'\x{98E2}\x{98E9}\x{98EB}\x{98ED}\x{98EE}\x{98EF}\x{98F2}\x{98F4}\x{98FC}' . +'\x{98FD}\x{98FE}\x{9903}\x{9905}\x{9909}\x{990A}\x{990C}\x{9910}\x{9912}' . +'\x{9913}\x{9914}\x{9918}\x{991D}\x{991E}\x{9920}\x{9921}\x{9924}\x{9928}' . +'\x{992C}\x{992E}\x{993D}\x{993E}\x{9942}\x{9945}\x{9949}\x{994B}\x{994C}' . +'\x{9950}\x{9951}\x{9952}\x{9955}\x{9957}\x{9996}\x{9997}\x{9998}\x{9999}' . +'\x{99A5}\x{99A8}\x{99AC}\x{99AD}\x{99AE}\x{99B3}\x{99B4}\x{99BC}\x{99C1}' . +'\x{99C4}\x{99C5}\x{99C6}\x{99C8}\x{99D0}\x{99D1}\x{99D2}\x{99D5}\x{99D8}' . +'\x{99DB}\x{99DD}\x{99DF}\x{99E2}\x{99ED}\x{99EE}\x{99F1}\x{99F2}\x{99F8}' . +'\x{99FB}\x{99FF}\x{9A01}\x{9A05}\x{9A0E}\x{9A0F}\x{9A12}\x{9A13}\x{9A19}' . +'\x{9A28}\x{9A2B}\x{9A30}\x{9A37}\x{9A3E}\x{9A40}\x{9A42}\x{9A43}\x{9A45}' . +'\x{9A4D}\x{9A55}\x{9A57}\x{9A5A}\x{9A5B}\x{9A5F}\x{9A62}\x{9A64}\x{9A65}' . +'\x{9A69}\x{9A6A}\x{9A6B}\x{9AA8}\x{9AAD}\x{9AB0}\x{9AB8}\x{9ABC}\x{9AC0}' . +'\x{9AC4}\x{9ACF}\x{9AD1}\x{9AD3}\x{9AD4}\x{9AD8}\x{9ADE}\x{9ADF}\x{9AE2}' . +'\x{9AE3}\x{9AE6}\x{9AEA}\x{9AEB}\x{9AED}\x{9AEE}\x{9AEF}\x{9AF1}\x{9AF4}' . +'\x{9AF7}\x{9AFB}\x{9B06}\x{9B18}\x{9B1A}\x{9B1F}\x{9B22}\x{9B23}\x{9B25}' . +'\x{9B27}\x{9B28}\x{9B29}\x{9B2A}\x{9B2E}\x{9B2F}\x{9B31}\x{9B32}\x{9B3B}' . +'\x{9B3C}\x{9B41}\x{9B42}\x{9B43}\x{9B44}\x{9B45}\x{9B4D}\x{9B4E}\x{9B4F}' . +'\x{9B51}\x{9B54}\x{9B58}\x{9B5A}\x{9B6F}\x{9B74}\x{9B83}\x{9B8E}\x{9B91}' . +'\x{9B92}\x{9B93}\x{9B96}\x{9B97}\x{9B9F}\x{9BA0}\x{9BA8}\x{9BAA}\x{9BAB}' . +'\x{9BAD}\x{9BAE}\x{9BB4}\x{9BB9}\x{9BC0}\x{9BC6}\x{9BC9}\x{9BCA}\x{9BCF}' . +'\x{9BD1}\x{9BD2}\x{9BD4}\x{9BD6}\x{9BDB}\x{9BE1}\x{9BE2}\x{9BE3}\x{9BE4}' . +'\x{9BE8}\x{9BF0}\x{9BF1}\x{9BF2}\x{9BF5}\x{9C04}\x{9C06}\x{9C08}\x{9C09}' . +'\x{9C0A}\x{9C0C}\x{9C0D}\x{9C10}\x{9C12}\x{9C13}\x{9C14}\x{9C15}\x{9C1B}' . +'\x{9C21}\x{9C24}\x{9C25}\x{9C2D}\x{9C2E}\x{9C2F}\x{9C30}\x{9C32}\x{9C39}' . +'\x{9C3A}\x{9C3B}\x{9C3E}\x{9C46}\x{9C47}\x{9C48}\x{9C52}\x{9C57}\x{9C5A}' . +'\x{9C60}\x{9C67}\x{9C76}\x{9C78}\x{9CE5}\x{9CE7}\x{9CE9}\x{9CEB}\x{9CEC}' . +'\x{9CF0}\x{9CF3}\x{9CF4}\x{9CF6}\x{9D03}\x{9D06}\x{9D07}\x{9D08}\x{9D09}' . +'\x{9D0E}\x{9D12}\x{9D15}\x{9D1B}\x{9D1F}\x{9D23}\x{9D26}\x{9D28}\x{9D2A}' . +'\x{9D2B}\x{9D2C}\x{9D3B}\x{9D3E}\x{9D3F}\x{9D41}\x{9D44}\x{9D46}\x{9D48}' . +'\x{9D50}\x{9D51}\x{9D59}\x{9D5C}\x{9D5D}\x{9D5E}\x{9D60}\x{9D61}\x{9D64}' . +'\x{9D6C}\x{9D6F}\x{9D72}\x{9D7A}\x{9D87}\x{9D89}\x{9D8F}\x{9D9A}\x{9DA4}' . +'\x{9DA9}\x{9DAB}\x{9DAF}\x{9DB2}\x{9DB4}\x{9DB8}\x{9DBA}\x{9DBB}\x{9DC1}' . +'\x{9DC2}\x{9DC4}\x{9DC6}\x{9DCF}\x{9DD3}\x{9DD9}\x{9DE6}\x{9DED}\x{9DEF}' . +'\x{9DF2}\x{9DF8}\x{9DF9}\x{9DFA}\x{9DFD}\x{9E1A}\x{9E1B}\x{9E1E}\x{9E75}' . +'\x{9E78}\x{9E79}\x{9E7D}\x{9E7F}\x{9E81}\x{9E88}\x{9E8B}\x{9E8C}\x{9E91}' . +'\x{9E92}\x{9E93}\x{9E95}\x{9E97}\x{9E9D}\x{9E9F}\x{9EA5}\x{9EA6}\x{9EA9}' . +'\x{9EAA}\x{9EAD}\x{9EB8}\x{9EB9}\x{9EBA}\x{9EBB}\x{9EBC}\x{9EBE}\x{9EBF}' . +'\x{9EC4}\x{9ECC}\x{9ECD}\x{9ECE}\x{9ECF}\x{9ED0}\x{9ED2}\x{9ED4}\x{9ED8}' . +'\x{9ED9}\x{9EDB}\x{9EDC}\x{9EDD}\x{9EDE}\x{9EE0}\x{9EE5}\x{9EE8}\x{9EEF}' . +'\x{9EF4}\x{9EF6}\x{9EF7}\x{9EF9}\x{9EFB}\x{9EFC}\x{9EFD}\x{9F07}\x{9F08}' . +'\x{9F0E}\x{9F13}\x{9F15}\x{9F20}\x{9F21}\x{9F2C}\x{9F3B}\x{9F3E}\x{9F4A}' . +'\x{9F4B}\x{9F4E}\x{9F4F}\x{9F52}\x{9F54}\x{9F5F}\x{9F60}\x{9F61}\x{9F62}' . +'\x{9F63}\x{9F66}\x{9F67}\x{9F6A}\x{9F6C}\x{9F72}\x{9F76}\x{9F77}\x{9F8D}' . +'\x{9F95}\x{9F9C}\x{9F9D}\x{9FA0}]{1,15}$/iu'); diff --git a/library/vendor/Zend/Validate/Iban.php b/library/vendor/Zend/Validate/Iban.php new file mode 100644 index 000000000..7ff58f275 --- /dev/null +++ b/library/vendor/Zend/Validate/Iban.php @@ -0,0 +1,245 @@ + "Unknown country within the IBAN '%value%'", + self::FALSEFORMAT => "'%value%' has a false IBAN format", + self::CHECKFAILED => "'%value%' has failed the IBAN check", + ); + + /** + * Optional locale + * + * @var string|Zend_Locale|null + */ + protected $_locale; + + /** + * IBAN regexes by region + * + * @var array + */ + protected $_ibanregex = array( + 'AD' => '/^AD[0-9]{2}[0-9]{8}[A-Z0-9]{12}$/', + 'AE' => '/^AE[0-9]{2}[0-9]{3}[0-9]{16}$/', + 'AL' => '/^AL[0-9]{2}[0-9]{8}[A-Z0-9]{16}$/', + 'AT' => '/^AT[0-9]{2}[0-9]{5}[0-9]{11}$/', + 'AZ' => '/^AZ[0-9]{2}[0-9]{4}[A-Z0-9]{20}$/', + 'BA' => '/^BA[0-9]{2}[0-9]{6}[0-9]{10}$/', + 'BE' => '/^BE[0-9]{2}[0-9]{3}[0-9]{9}$/', + 'BG' => '/^BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}$/', + 'BH' => '/^BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}$/', + 'BR' => '/^BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z]{1}[A-Z0-9]{1}$/', + 'CH' => '/^CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}$/', + 'CR' => '/^CR[0-9]{2}[0-9]{3}[0-9]{14}$/', + 'CS' => '/^CS[0-9]{2}[0-9]{3}[0-9]{15}$/', + 'CY' => '/^CY[0-9]{2}[0-9]{8}[A-Z0-9]{16}$/', + 'CZ' => '/^CZ[0-9]{2}[0-9]{4}[0-9]{16}$/', + 'DE' => '/^DE[0-9]{2}[0-9]{8}[0-9]{10}$/', + 'DK' => '/^DK[0-9]{2}[0-9]{4}[0-9]{10}$/', + 'DO' => '/^DO[0-9]{2}[A-Z0-9]{4}[0-9]{20}$/', + 'EE' => '/^EE[0-9]{2}[0-9]{4}[0-9]{12}$/', + 'ES' => '/^ES[0-9]{2}[0-9]{8}[0-9]{12}$/', + 'FR' => '/^FR[0-9]{2}[0-9]{10}[A-Z0-9]{11}[0-9]{2}$/', + 'FI' => '/^FI[0-9]{2}[0-9]{6}[0-9]{8}$/', + 'FO' => '/^FO[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}$/', + 'GB' => '/^GB[0-9]{2}[A-Z]{4}[0-9]{14}$/', + 'GE' => '/^GE[0-9]{2}[A-Z]{2}[0-9]{16}$/', + 'GI' => '/^GI[0-9]{2}[A-Z]{4}[A-Z0-9]{15}$/', + 'GL' => '/^GL[0-9]{2}[0-9]{4}[0-9]{9}[0-9]{1}$/', + 'GR' => '/^GR[0-9]{2}[0-9]{7}[A-Z0-9]{16}$/', + 'GT' => '/^GT[0-9]{2}[A-Z0-9]{4}[A-Z0-9]{20}$/', + 'HR' => '/^HR[0-9]{2}[0-9]{7}[0-9]{10}$/', + 'HU' => '/^HU[0-9]{2}[0-9]{7}[0-9]{1}[0-9]{15}[0-9]{1}$/', + 'IE' => '/^IE[0-9]{2}[A-Z0-9]{4}[0-9]{6}[0-9]{8}$/', + 'IL' => '/^IL[0-9]{2}[0-9]{3}[0-9]{3}[0-9]{13}$/', + 'IS' => '/^IS[0-9]{2}[0-9]{4}[0-9]{18}$/', + 'IT' => '/^IT[0-9]{2}[A-Z]{1}[0-9]{10}[A-Z0-9]{12}$/', + 'KW' => '/^KW[0-9]{2}[A-Z]{4}[0-9]{3}[0-9]{22}$/', + 'KZ' => '/^KZ[A-Z]{2}[0-9]{2}[0-9]{3}[A-Z0-9]{13}$/', + 'LB' => '/^LB[0-9]{2}[0-9]{4}[A-Z0-9]{20}$/', + 'LI' => '/^LI[0-9]{2}[0-9]{5}[A-Z0-9]{12}$/', + 'LU' => '/^LU[0-9]{2}[0-9]{3}[A-Z0-9]{13}$/', + 'LT' => '/^LT[0-9]{2}[0-9]{5}[0-9]{11}$/', + 'LV' => '/^LV[0-9]{2}[A-Z]{4}[A-Z0-9]{13}$/', + 'MC' => '/^MC[0-9]{2}[0-9]{5}[0-9]{5}[A-Z0-9]{11}[0-9]{2}$/', + 'MD' => '/^MD[0-9]{2}[A-Z0-9]{20}$/', + 'ME' => '/^ME[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}$/', + 'MK' => '/^MK[0-9]{2}[A-Z]{3}[A-Z0-9]{10}[0-9]{2}$/', + 'MR' => '/^MR13[0-9]{5}[0-9]{5}[0-9]{11}[0-9]{2}$/', + 'MU' => '/^MU[0-9]{2}[A-Z]{4}[0-9]{2}[0-9]{2}[0-9]{12}[0-9]{3}[A-Z]{2}$/', + 'MT' => '/^MT[0-9]{2}[A-Z]{4}[0-9]{5}[A-Z0-9]{18}$/', + 'NL' => '/^NL[0-9]{2}[A-Z]{4}[0-9]{10}$/', + 'NO' => '/^NO[0-9]{2}[0-9]{4}[0-9]{7}$/', + 'PK' => '/^PK[0-9]{2}[A-Z]{4}[0-9]{16}$/', + 'PL' => '/^PL[0-9]{2}[0-9]{8}[0-9]{16}$/', + 'PS' => '/^PS[0-9]{2}[A-Z]{4}[0-9]{21}$/', + 'PT' => '/^PT[0-9]{2}[0-9]{8}[0-9]{13}$/', + 'RO' => '/^RO[0-9]{2}[A-Z]{4}[A-Z0-9]{16}$/', + 'RS' => '/^RS[0-9]{2}[0-9]{3}[0-9]{13}[0-9]{2}$/', + 'SA' => '/^SA[0-9]{2}[0-9]{2}[A-Z0-9]{18}$/', + 'SE' => '/^SE[0-9]{2}[0-9]{3}[0-9]{17}$/', + 'SI' => '/^SI[0-9]{2}[0-9]{5}[0-9]{8}[0-9]{2}$/', + 'SK' => '/^SK[0-9]{2}[0-9]{4}[0-9]{16}$/', + 'SM' => '/^SM[0-9]{2}[A-Z]{1}[0-9]{5}[0-9]{5}[A-Z0-9]{12}$/', + 'TN' => '/^TN[0-9]{2}[0-9]{5}[0-9]{15}$/', + 'TR' => '/^TR[0-9]{2}[0-9]{5}[A-Z0-9]{17}$/', + 'VG' => '/^VG[0-9]{2}[A-Z]{4}[0-9]{16}$/' + ); + + /** + * Sets validator options + * + * @param string|Zend_Config|Zend_Locale $locale OPTIONAL + * @return void + */ + public function __construct($locale = null) + { + if ($locale instanceof Zend_Config) { + $locale = $locale->toArray(); + } + + if (is_array($locale)) { + if (array_key_exists('locale', $locale)) { + $locale = $locale['locale']; + } else { + $locale = null; + } + } + + if (empty($locale)) { + if (Zend_Registry::isRegistered('Zend_Locale')) { + $locale = Zend_Registry::get('Zend_Locale'); + } + } + + if ($locale !== null) { + $this->setLocale($locale); + } + } + + /** + * Returns the locale option + * + * @return string|Zend_Locale|null + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Sets the locale option + * + * @param string|Zend_Locale $locale + * @return Zend_Validate_Date provides a fluent interface + */ + public function setLocale($locale = null) + { + if ($locale !== false) { + $locale = Zend_Locale::findLocale($locale); + if (strlen($locale) < 4) { + throw new Zend_Validate_Exception('Region must be given for IBAN validation'); + } + } + + $this->_locale = $locale; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if $value is a valid IBAN + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + $value = strtoupper($value); + $this->_setValue($value); + + if (empty($this->_locale)) { + $region = substr($value, 0, 2); + } else { + $region = new Zend_Locale($this->_locale); + $region = $region->getRegion(); + } + + if (!array_key_exists($region, $this->_ibanregex)) { + $this->_setValue($region); + $this->_error(self::NOTSUPPORTED); + return false; + } + + if (!preg_match($this->_ibanregex[$region], $value)) { + $this->_error(self::FALSEFORMAT); + return false; + } + + $format = substr($value, 4) . substr($value, 0, 4); + $format = str_replace( + array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'), + array('10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', + '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'), + $format); + + $temp = intval(substr($format, 0, 1)); + $len = strlen($format); + for ($x = 1; $x < $len; ++$x) { + $temp *= 10; + $temp += intval(substr($format, $x, 1)); + $temp %= 97; + } + + if ($temp != 1) { + $this->_error(self::CHECKFAILED); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Identical.php b/library/vendor/Zend/Validate/Identical.php new file mode 100644 index 000000000..e3fbc9d64 --- /dev/null +++ b/library/vendor/Zend/Validate/Identical.php @@ -0,0 +1,163 @@ + "The two given tokens do not match", + self::MISSING_TOKEN => 'No token was provided to match against', + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'token' => '_tokenString' + ); + + /** + * Original token against which to validate + * @var string + */ + protected $_tokenString; + protected $_token; + protected $_strict = true; + + /** + * Sets validator options + * + * @param mixed $token + * @return void + */ + public function __construct($token = null) + { + if ($token instanceof Zend_Config) { + $token = $token->toArray(); + } + + if (is_array($token) && array_key_exists('token', $token)) { + if (array_key_exists('strict', $token)) { + $this->setStrict($token['strict']); + } + + $this->setToken($token['token']); + } else if (null !== $token) { + $this->setToken($token); + } + } + + /** + * Retrieve token + * + * @return string + */ + public function getToken() + { + return $this->_token; + } + + /** + * Set token against which to compare + * + * @param mixed $token + * @return Zend_Validate_Identical + */ + public function setToken($token) + { + $this->_tokenString = $token; + $this->_token = $token; + return $this; + } + + /** + * Returns the strict parameter + * + * @return boolean + */ + public function getStrict() + { + return $this->_strict; + } + + /** + * Sets the strict parameter + * + * @param Zend_Validate_Identical + */ + public function setStrict($strict) + { + $this->_strict = (boolean) $strict; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if a token has been set and the provided value + * matches that token. + * + * @param mixed $value + * @param array $context + * @return boolean + */ + public function isValid($value, $context = null) + { + $this->_setValue($value); + + if (($context !== null) && isset($context) && array_key_exists($this->getToken(), $context)) { + $token = $context[$this->getToken()]; + } else { + $token = $this->getToken(); + } + + if ($token === null) { + $this->_error(self::MISSING_TOKEN); + return false; + } + + $strict = $this->getStrict(); + if (($strict && ($value !== $token)) || (!$strict && ($value != $token))) { + $this->_error(self::NOT_SAME); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/InArray.php b/library/vendor/Zend/Validate/InArray.php new file mode 100644 index 000000000..9a0e9f35d --- /dev/null +++ b/library/vendor/Zend/Validate/InArray.php @@ -0,0 +1,202 @@ + "'%value%' was not found in the haystack", + ); + + /** + * Haystack of possible values + * + * @var array + */ + protected $_haystack; + + /** + * Whether a strict in_array() invocation is used + * + * @var boolean + */ + protected $_strict = false; + + /** + * Whether a recursive search should be done + * + * @var boolean + */ + protected $_recursive = false; + + /** + * Sets validator options + * + * @param array|Zend_Config $haystack + * @return void + */ + public function __construct($options) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + throw new Zend_Validate_Exception('Array expected as parameter'); + } else { + $count = func_num_args(); + $temp = array(); + if ($count > 1) { + $temp['haystack'] = func_get_arg(0); + $temp['strict'] = func_get_arg(1); + $options = $temp; + } else { + $temp = func_get_arg(0); + if (!array_key_exists('haystack', $options)) { + $options = array(); + $options['haystack'] = $temp; + } else { + $options = $temp; + } + } + } + + $this->setHaystack($options['haystack']); + if (array_key_exists('strict', $options)) { + $this->setStrict($options['strict']); + } + + if (array_key_exists('recursive', $options)) { + $this->setRecursive($options['recursive']); + } + } + + /** + * Returns the haystack option + * + * @return mixed + */ + public function getHaystack() + { + return $this->_haystack; + } + + /** + * Sets the haystack option + * + * @param mixed $haystack + * @return Zend_Validate_InArray Provides a fluent interface + */ + public function setHaystack(array $haystack) + { + $this->_haystack = $haystack; + return $this; + } + + /** + * Returns the strict option + * + * @return boolean + */ + public function getStrict() + { + return $this->_strict; + } + + /** + * Sets the strict option + * + * @param boolean $strict + * @return Zend_Validate_InArray Provides a fluent interface + */ + public function setStrict($strict) + { + $this->_strict = (boolean) $strict; + return $this; + } + + /** + * Returns the recursive option + * + * @return boolean + */ + public function getRecursive() + { + return $this->_recursive; + } + + /** + * Sets the recursive option + * + * @param boolean $recursive + * @return Zend_Validate_InArray Provides a fluent interface + */ + public function setRecursive($recursive) + { + $this->_recursive = (boolean) $recursive; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is contained in the haystack option. If the strict + * option is true, then the type of $value is also checked. + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + if ($this->getRecursive()) { + $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->_haystack)); + foreach($iterator as $element) { + if ($this->_strict) { + if ($element === $value) { + return true; + } + } else if ($element == $value) { + return true; + } + } + } else { + if (in_array($value, $this->_haystack, $this->_strict)) { + return true; + } + } + + $this->_error(self::NOT_IN_ARRAY); + return false; + } +} diff --git a/library/vendor/Zend/Validate/Int.php b/library/vendor/Zend/Validate/Int.php new file mode 100644 index 000000000..0a186d78e --- /dev/null +++ b/library/vendor/Zend/Validate/Int.php @@ -0,0 +1,144 @@ + "Invalid type given. String or integer expected", + self::NOT_INT => "'%value%' does not appear to be an integer", + ); + + protected $_locale; + + /** + * Constructor for the integer validator + * + * @param string|Zend_Config|Zend_Locale $locale + */ + public function __construct($locale = null) + { + if ($locale instanceof Zend_Config) { + $locale = $locale->toArray(); + } + + if (is_array($locale)) { + if (array_key_exists('locale', $locale)) { + $locale = $locale['locale']; + } else { + $locale = null; + } + } + + if (empty($locale)) { + if (Zend_Registry::isRegistered('Zend_Locale')) { + $locale = Zend_Registry::get('Zend_Locale'); + } + } + + if ($locale !== null) { + $this->setLocale($locale); + } + } + + /** + * Returns the set locale + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Sets the locale to use + * + * @param string|Zend_Locale $locale + */ + public function setLocale($locale = null) + { + $this->_locale = Zend_Locale::findLocale($locale); + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a valid integer + * + * @param string|integer $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value)) { + $this->_error(self::INVALID); + return false; + } + + if (is_int($value)) { + return true; + } + + $this->_setValue($value); + if ($this->_locale === null) { + $locale = localeconv(); + $valueFiltered = str_replace($locale['decimal_point'], '.', $value); + $valueFiltered = str_replace($locale['thousands_sep'], '', $valueFiltered); + + if (strval(intval($valueFiltered)) != $valueFiltered) { + $this->_error(self::NOT_INT); + return false; + } + + } else { + try { + if (!Zend_Locale_Format::isInteger($value, array('locale' => $this->_locale))) { + $this->_error(self::NOT_INT); + return false; + } + } catch (Zend_Locale_Exception $e) { + $this->_error(self::NOT_INT); + return false; + } + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Interface.php b/library/vendor/Zend/Validate/Interface.php new file mode 100644 index 000000000..7fb9d4d04 --- /dev/null +++ b/library/vendor/Zend/Validate/Interface.php @@ -0,0 +1,54 @@ + "Invalid type given. String expected", + self::NOT_IP_ADDRESS => "'%value%' does not appear to be a valid IP address", + ); + + /** + * internal options + * + * @var array + */ + protected $_options = array( + 'allowipv6' => true, + 'allowipv4' => true + ); + + /** + * Sets validator options + * + * @param array $options OPTIONAL Options to set, see the manual for all available options + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['allowipv6'] = array_shift($options); + if (!empty($options)) { + $temp['allowipv4'] = array_shift($options); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions($options); + } + + /** + * Returns all set options + * + * @return array + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Sets the options for this validator + * + * @param array $options + * @return Zend_Validate_Ip + */ + public function setOptions($options) + { + if (array_key_exists('allowipv6', $options)) { + $this->_options['allowipv6'] = (boolean) $options['allowipv6']; + } + + if (array_key_exists('allowipv4', $options)) { + $this->_options['allowipv4'] = (boolean) $options['allowipv4']; + } + + if (!$this->_options['allowipv4'] && !$this->_options['allowipv6']) { + throw new Zend_Validate_Exception('Nothing to validate. Check your options'); + } + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a valid IP address + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + if (($this->_options['allowipv4'] && !$this->_options['allowipv6'] && !$this->_validateIPv4($value)) || + (!$this->_options['allowipv4'] && $this->_options['allowipv6'] && !$this->_validateIPv6($value)) || + ($this->_options['allowipv4'] && $this->_options['allowipv6'] && !$this->_validateIPv4($value) && !$this->_validateIPv6($value))) { + $this->_error(self::NOT_IP_ADDRESS); + return false; + } + + return true; + } + + /** + * Validates an IPv4 address + * + * @param string $value + */ + protected function _validateIPv4($value) { + $ip2long = ip2long($value); + if($ip2long === false) { + return false; + } + + return $value == long2ip($ip2long); + } + + /** + * Validates an IPv6 address + * + * @param string $value Value to check against + * @return boolean True when $value is a valid ipv6 address + * False otherwise + */ + protected function _validateIPv6($value) { + if (strlen($value) < 3) { + return $value == '::'; + } + + if (strpos($value, '.')) { + $lastcolon = strrpos($value, ':'); + if (!($lastcolon && $this->_validateIPv4(substr($value, $lastcolon + 1)))) { + return false; + } + + $value = substr($value, 0, $lastcolon) . ':0:0'; + } + + if (strpos($value, '::') === false) { + return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value); + } + + $colonCount = substr_count($value, ':'); + if ($colonCount < 8) { + return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value); + } + + // special case with ending or starting double colon + if ($colonCount == 8) { + return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value); + } + + return false; + } +} diff --git a/library/vendor/Zend/Validate/Isbn.php b/library/vendor/Zend/Validate/Isbn.php new file mode 100644 index 000000000..a501e99e0 --- /dev/null +++ b/library/vendor/Zend/Validate/Isbn.php @@ -0,0 +1,275 @@ + "Invalid type given. String or integer expected", + self::NO_ISBN => "'%value%' is not a valid ISBN number", + ); + + /** + * Allowed type. + * + * @var string + */ + protected $_type = self::AUTO; + + /** + * Separator character. + * + * @var string + */ + protected $_separator = ''; + + /** + * Set up options. + * + * @param Zend_Config|array $options + * @throws Zend_Validate_Exception When $options is not valid + * @return void + */ + public function __construct($options = array()) + { + // prepare options + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + if (!is_array($options)) { + /** + * @see Zend_Validate_Exception + */ + throw new Zend_Validate_Exception('Invalid options provided.'); + } + + // set type + if (array_key_exists('type', $options)) { + $this->setType($options['type']); + } + + // set separator + if (array_key_exists('separator', $options)) { + $this->setSeparator($options['separator']); + } + } + + /** + * Detect input format. + * + * @return string + */ + protected function _detectFormat() + { + // prepare separator and pattern list + $sep = quotemeta($this->_separator); + $patterns = array(); + $lengths = array(); + + // check for ISBN-10 + if ($this->_type == self::ISBN10 || $this->_type == self::AUTO) { + if (empty($sep)) { + $pattern = '/^[0-9]{9}[0-9X]{1}$/'; + $length = 10; + } else { + $pattern = "/^[0-9]{1,7}[{$sep}]{1}[0-9]{1,7}[{$sep}]{1}[0-9]{1,7}[{$sep}]{1}[0-9X]{1}$/"; + $length = 13; + } + + $patterns[$pattern] = self::ISBN10; + $lengths[$pattern] = $length; + } + + // check for ISBN-13 + if ($this->_type == self::ISBN13 || $this->_type == self::AUTO) { + if (empty($sep)) { + $pattern = '/^[0-9]{13}$/'; + $length = 13; + } else { + $pattern = "/^[0-9]{1,9}[{$sep}]{1}[0-9]{1,5}[{$sep}]{1}[0-9]{1,9}[{$sep}]{1}[0-9]{1,9}[{$sep}]{1}[0-9]{1}$/"; + $length = 17; + } + + $patterns[$pattern] = self::ISBN13; + $lengths[$pattern] = $length; + } + + // check pattern list + foreach ($patterns as $pattern => $type) { + if ((strlen($this->_value) == $lengths[$pattern]) && preg_match($pattern, $this->_value)) { + return $type; + } + } + + return null; + } + + /** + * Defined by Zend_Validate_Interface. + * + * Returns true if and only if $value is a valid ISBN. + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value)) { + $this->_error(self::INVALID); + return false; + } + + $value = (string) $value; + $this->_setValue($value); + + switch ($this->_detectFormat()) { + case self::ISBN10: + // sum + $isbn10 = str_replace($this->_separator, '', $value); + $sum = 0; + for ($i = 0; $i < 9; $i++) { + $sum += (10 - $i) * $isbn10{$i}; + } + + // checksum + $checksum = 11 - ($sum % 11); + if ($checksum == 11) { + $checksum = '0'; + } elseif ($checksum == 10) { + $checksum = 'X'; + } + break; + + case self::ISBN13: + // sum + $isbn13 = str_replace($this->_separator, '', $value); + $sum = 0; + for ($i = 0; $i < 12; $i++) { + if ($i % 2 == 0) { + $sum += $isbn13{$i}; + } else { + $sum += 3 * $isbn13{$i}; + } + } + // checksum + $checksum = 10 - ($sum % 10); + if ($checksum == 10) { + $checksum = '0'; + } + break; + + default: + $this->_error(self::NO_ISBN); + return false; + } + + // validate + if (substr($this->_value, -1) != $checksum) { + $this->_error(self::NO_ISBN); + return false; + } + return true; + } + + /** + * Set separator characters. + * + * It is allowed only empty string, hyphen and space. + * + * @param string $separator + * @throws Zend_Validate_Exception When $separator is not valid + * @return Zend_Validate_Isbn Provides a fluent interface + */ + public function setSeparator($separator) + { + // check separator + if (!in_array($separator, array('-', ' ', ''))) { + /** + * @see Zend_Validate_Exception + */ + throw new Zend_Validate_Exception('Invalid ISBN separator.'); + } + + $this->_separator = $separator; + return $this; + } + + /** + * Get separator characters. + * + * @return string + */ + public function getSeparator() + { + return $this->_separator; + } + + /** + * Set allowed ISBN type. + * + * @param string $type + * @throws Zend_Validate_Exception When $type is not valid + * @return Zend_Validate_Isbn Provides a fluent interface + */ + public function setType($type) + { + // check type + if (!in_array($type, array(self::AUTO, self::ISBN10, self::ISBN13))) { + /** + * @see Zend_Validate_Exception + */ + throw new Zend_Validate_Exception('Invalid ISBN type'); + } + + $this->_type = $type; + return $this; + } + + /** + * Get allowed ISBN type. + * + * @return string + */ + public function getType() + { + return $this->_type; + } +} diff --git a/library/vendor/Zend/Validate/Ldap/Dn.php b/library/vendor/Zend/Validate/Ldap/Dn.php new file mode 100644 index 000000000..a784487ed --- /dev/null +++ b/library/vendor/Zend/Validate/Ldap/Dn.php @@ -0,0 +1,64 @@ + 'DN is malformed', + ); + + /** + * Defined by Zend_Validate_Interface. + * + * Returns true if and only if $value is a valid DN. + * + * @param string $value The value to be validated. + * + * @return boolean + */ + public function isValid($value) + { + $valid = Zend_Ldap_Dn::checkDn($value); + if ($valid === false) { + $this->_error(self::MALFORMED); + return false; + } + return true; + } +} diff --git a/library/vendor/Zend/Validate/LessThan.php b/library/vendor/Zend/Validate/LessThan.php new file mode 100644 index 000000000..11885e3c7 --- /dev/null +++ b/library/vendor/Zend/Validate/LessThan.php @@ -0,0 +1,120 @@ + "'%value%' is not less than '%max%'" + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'max' => '_max' + ); + + /** + * Maximum value + * + * @var mixed + */ + protected $_max; + + /** + * Sets validator options + * + * @param mixed|Zend_Config $max + * @return void + */ + public function __construct($max) + { + if ($max instanceof Zend_Config) { + $max = $max->toArray(); + } + + if (is_array($max)) { + if (array_key_exists('max', $max)) { + $max = $max['max']; + } else { + throw new Zend_Validate_Exception("Missing option 'max'"); + } + } + + $this->setMax($max); + } + + /** + * Returns the max option + * + * @return mixed + */ + public function getMax() + { + return $this->_max; + } + + /** + * Sets the max option + * + * @param mixed $max + * @return Zend_Validate_LessThan Provides a fluent interface + */ + public function setMax($max) + { + $this->_max = $max; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is less than max option + * + * @param mixed $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + if ($this->_max <= $value) { + $this->_error(self::NOT_LESS); + return false; + } + return true; + } + +} diff --git a/library/vendor/Zend/Validate/NotEmpty.php b/library/vendor/Zend/Validate/NotEmpty.php new file mode 100644 index 000000000..93f36dbd9 --- /dev/null +++ b/library/vendor/Zend/Validate/NotEmpty.php @@ -0,0 +1,277 @@ + 'boolean', + self::INTEGER => 'integer', + self::FLOAT => 'float', + self::STRING => 'string', + self::ZERO => 'zero', + self::EMPTY_ARRAY => 'array', + self::NULL => 'null', + self::PHP => 'php', + self::SPACE => 'space', + self::OBJECT => 'object', + self::OBJECT_STRING => 'objectstring', + self::OBJECT_COUNT => 'objectcount', + self::ALL => 'all', + ); + + /** + * @var array + */ + protected $_messageTemplates = array( + self::IS_EMPTY => "Value is required and can't be empty", + self::INVALID => "Invalid type given. String, integer, float, boolean or array expected", + ); + + /** + * Internal type to detect + * + * @var integer + */ + protected $_type = 493; + + /** + * Constructor + * + * @param string|array|Zend_Config $options OPTIONAL + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp = array(); + if (!empty($options)) { + $temp['type'] = array_shift($options); + } + + $options = $temp; + } + + if (is_array($options) && array_key_exists('type', $options)) { + $this->setType($options['type']); + } + } + + /** + * Returns the set types + * + * @return array + */ + public function getType() + { + return $this->_type; + } + + /** + * Set the types + * + * @param integer|array $type + * @throws Zend_Validate_Exception + * @return Zend_Validate_NotEmpty + */ + public function setType($type = null) + { + if (is_array($type)) { + $detected = 0; + foreach($type as $value) { + if (is_int($value)) { + $detected += $value; + } else if (in_array($value, $this->_constants)) { + $detected += array_search($value, $this->_constants); + } + } + + $type = $detected; + } else if (is_string($type) && in_array($type, $this->_constants)) { + $type = array_search($type, $this->_constants); + } + + if (!is_int($type) || ($type < 0) || ($type > self::ALL)) { + throw new Zend_Validate_Exception('Unknown type'); + } + + $this->_type = $type; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is not an empty value. + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if ($value !== null && !is_string($value) && !is_int($value) && !is_float($value) && + !is_bool($value) && !is_array($value) && !is_object($value)) { + $this->_error(self::INVALID); + return false; + } + + $type = $this->getType(); + $this->_setValue($value); + $object = false; + + // OBJECT_COUNT (countable object) + if ($type >= self::OBJECT_COUNT) { + $type -= self::OBJECT_COUNT; + $object = true; + + if (is_object($value) && ($value instanceof Countable) && (count($value) == 0)) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // OBJECT_STRING (object's toString) + if ($type >= self::OBJECT_STRING) { + $type -= self::OBJECT_STRING; + $object = true; + + if ((is_object($value) && (!method_exists($value, '__toString'))) || + (is_object($value) && (method_exists($value, '__toString')) && (((string) $value) == ""))) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // OBJECT (object) + if ($type >= self::OBJECT) { + $type -= self::OBJECT; + // fall trough, objects are always not empty + } else if ($object === false) { + // object not allowed but object given -> return false + if (is_object($value)) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // SPACE (' ') + if ($type >= self::SPACE) { + $type -= self::SPACE; + if (is_string($value) && (preg_match('/^\s+$/s', $value))) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // NULL (null) + if ($type >= self::NULL) { + $type -= self::NULL; + if ($value === null) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // EMPTY_ARRAY (array()) + if ($type >= self::EMPTY_ARRAY) { + $type -= self::EMPTY_ARRAY; + if (is_array($value) && ($value == array())) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // ZERO ('0') + if ($type >= self::ZERO) { + $type -= self::ZERO; + if (is_string($value) && ($value == '0')) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // STRING ('') + if ($type >= self::STRING) { + $type -= self::STRING; + if (is_string($value) && ($value == '')) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // FLOAT (0.0) + if ($type >= self::FLOAT) { + $type -= self::FLOAT; + if (is_float($value) && ($value == 0.0)) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // INTEGER (0) + if ($type >= self::INTEGER) { + $type -= self::INTEGER; + if (is_int($value) && ($value == 0)) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + // BOOLEAN (false) + if ($type >= self::BOOLEAN) { + $type -= self::BOOLEAN; + if (is_bool($value) && ($value == false)) { + $this->_error(self::IS_EMPTY); + return false; + } + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/PostCode.php b/library/vendor/Zend/Validate/PostCode.php new file mode 100644 index 000000000..ffcbf1bb5 --- /dev/null +++ b/library/vendor/Zend/Validate/PostCode.php @@ -0,0 +1,202 @@ + "Invalid type given. String or integer expected", + self::NO_MATCH => "'%value%' does not appear to be a postal code", + ); + + /** + * Locale to use + * + * @var string + */ + protected $_locale; + + /** + * Manual postal code format + * + * @var unknown_type + */ + protected $_format; + + /** + * Constructor for the integer validator + * + * Accepts either a string locale, a Zend_Locale object, or an array or + * Zend_Config object containing the keys "locale" and/or "format". + * + * @param string|Zend_Locale|array|Zend_Config $options + * @throws Zend_Validate_Exception On empty format + */ + public function __construct($options = null) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } + + if (empty($options)) { + if (Zend_Registry::isRegistered('Zend_Locale')) { + $this->setLocale(Zend_Registry::get('Zend_Locale')); + } + } elseif (is_array($options)) { + // Received + if (array_key_exists('locale', $options)) { + $this->setLocale($options['locale']); + } + + if (array_key_exists('format', $options)) { + $this->setFormat($options['format']); + } + } elseif ($options instanceof Zend_Locale || is_string($options)) { + // Received Locale object or string locale + $this->setLocale($options); + } + + $format = $this->getFormat(); + if (empty($format)) { + throw new Zend_Validate_Exception("A postcode-format string has to be given for validation"); + } + } + + /** + * Returns the set locale + * + * @return string|Zend_Locale The set locale + */ + public function getLocale() + { + return $this->_locale; + } + + /** + * Sets the locale to use + * + * @param string|Zend_Locale $locale + * @throws Zend_Validate_Exception On unrecognised region + * @throws Zend_Validate_Exception On not detected format + * @return Zend_Validate_PostCode Provides fluid interface + */ + public function setLocale($locale = null) + { + $this->_locale = Zend_Locale::findLocale($locale); + $locale = new Zend_Locale($this->_locale); + $region = $locale->getRegion(); + if (empty($region)) { + throw new Zend_Validate_Exception("Unable to detect a region for the locale '$locale'"); + } + + $format = Zend_Locale::getTranslation( + $locale->getRegion(), + 'postaltoterritory', + $this->_locale + ); + + if (empty($format)) { + throw new Zend_Validate_Exception("Unable to detect a postcode format for the region '{$locale->getRegion()}'"); + } + + $this->setFormat($format); + return $this; + } + + /** + * Returns the set postal code format + * + * @return string + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets a self defined postal format as regex + * + * @param string $format + * @throws Zend_Validate_Exception On empty format + * @return Zend_Validate_PostCode Provides fluid interface + */ + public function setFormat($format) + { + if (empty($format) || !is_string($format)) { + throw new Zend_Validate_Exception("A postcode-format string has to be given for validation"); + } + + if ($format[0] !== '/') { + $format = '/^' . $format; + } + + if ($format[strlen($format) - 1] !== '/') { + $format .= '$/'; + } + + $this->_format = $format; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value is a valid postalcode + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + $this->_setValue($value); + if (!is_string($value) && !is_int($value)) { + $this->_error(self::INVALID); + return false; + } + + $format = $this->getFormat(); + if (!preg_match($format, $value)) { + $this->_error(self::NO_MATCH); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Regex.php b/library/vendor/Zend/Validate/Regex.php new file mode 100644 index 000000000..337e2ab25 --- /dev/null +++ b/library/vendor/Zend/Validate/Regex.php @@ -0,0 +1,144 @@ + "Invalid type given. String, integer or float expected", + self::NOT_MATCH => "'%value%' does not match against pattern '%pattern%'", + self::ERROROUS => "There was an internal error while using the pattern '%pattern%'", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'pattern' => '_pattern' + ); + + /** + * Regular expression pattern + * + * @var string + */ + protected $_pattern; + + /** + * Sets validator options + * + * @param string|Zend_Config $pattern + * @throws Zend_Validate_Exception On missing 'pattern' parameter + * @return void + */ + public function __construct($pattern) + { + if ($pattern instanceof Zend_Config) { + $pattern = $pattern->toArray(); + } + + if (is_array($pattern)) { + if (array_key_exists('pattern', $pattern)) { + $pattern = $pattern['pattern']; + } else { + throw new Zend_Validate_Exception("Missing option 'pattern'"); + } + } + + $this->setPattern($pattern); + } + + /** + * Returns the pattern option + * + * @return string + */ + public function getPattern() + { + return $this->_pattern; + } + + /** + * Sets the pattern option + * + * @param string $pattern + * @throws Zend_Validate_Exception if there is a fatal error in pattern matching + * @return Zend_Validate_Regex Provides a fluent interface + */ + public function setPattern($pattern) + { + $this->_pattern = (string) $pattern; + $status = @preg_match($this->_pattern, "Test"); + + if (false === $status) { + throw new Zend_Validate_Exception("Internal error while using the pattern '$this->_pattern'"); + } + + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if $value matches against the pattern option + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value) && !is_int($value) && !is_float($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + + $status = @preg_match($this->_pattern, $value); + if (false === $status) { + $this->_error(self::ERROROUS); + return false; + } + + if (!$status) { + $this->_error(self::NOT_MATCH); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Sitemap/Changefreq.php b/library/vendor/Zend/Validate/Sitemap/Changefreq.php new file mode 100644 index 000000000..376628094 --- /dev/null +++ b/library/vendor/Zend/Validate/Sitemap/Changefreq.php @@ -0,0 +1,94 @@ + value + * + * @link http://www.sitemaps.org/protocol.php Sitemaps XML format + * + * @category Zend + * @package Zend_Validate + * @subpackage Sitemap + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Validate_Sitemap_Changefreq extends Zend_Validate_Abstract +{ + /** + * Validation key for not valid + * + */ + const NOT_VALID = 'sitemapChangefreqNotValid'; + const INVALID = 'sitemapChangefreqInvalid'; + + /** + * Validation failure message template definitions + * + * @var array + */ + protected $_messageTemplates = array( + self::NOT_VALID => "'%value%' is not a valid sitemap changefreq", + self::INVALID => "Invalid type given. String expected", + ); + + /** + * Valid change frequencies + * + * @var array + */ + protected $_changeFreqs = array( + 'always', 'hourly', 'daily', 'weekly', + 'monthly', 'yearly', 'never' + ); + + /** + * Validates if a string is valid as a sitemap changefreq + * + * @link http://www.sitemaps.org/protocol.php#changefreqdef + * + * @param string $value value to validate + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + if (!is_string($value)) { + return false; + } + + if (!in_array($value, $this->_changeFreqs, true)) { + $this->_error(self::NOT_VALID); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Sitemap/Lastmod.php b/library/vendor/Zend/Validate/Sitemap/Lastmod.php new file mode 100644 index 000000000..a28861336 --- /dev/null +++ b/library/vendor/Zend/Validate/Sitemap/Lastmod.php @@ -0,0 +1,87 @@ + value + * + * @link http://www.sitemaps.org/protocol.php Sitemaps XML format + * + * @category Zend + * @package Zend_Validate + * @subpackage Sitemap + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Validate_Sitemap_Lastmod extends Zend_Validate_Abstract +{ + /** + * Regular expression to use when validating + * + */ + const LASTMOD_REGEX = '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])(T([0-1][0-9]|2[0-3])(:[0-5][0-9])(:[0-5][0-9])?(\\+|-)([0-1][0-9]|2[0-3]):[0-5][0-9])?$/'; + + /** + * Validation key for not valid + * + */ + const NOT_VALID = 'sitemapLastmodNotValid'; + const INVALID = 'sitemapLastmodInvalid'; + + /** + * Validation failure message template definitions + * + * @var array + */ + protected $_messageTemplates = array( + self::NOT_VALID => "'%value%' is not a valid sitemap lastmod", + self::INVALID => "Invalid type given. String expected", + ); + + /** + * Validates if a string is valid as a sitemap lastmod + * + * @link http://www.sitemaps.org/protocol.php#lastmoddef + * + * @param string $value value to validate + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + $result = @preg_match(self::LASTMOD_REGEX, $value); + if ($result != 1) { + $this->_error(self::NOT_VALID); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Sitemap/Loc.php b/library/vendor/Zend/Validate/Sitemap/Loc.php new file mode 100644 index 000000000..03b171246 --- /dev/null +++ b/library/vendor/Zend/Validate/Sitemap/Loc.php @@ -0,0 +1,85 @@ + value + * + * @link http://www.sitemaps.org/protocol.php Sitemaps XML format + * + * @category Zend + * @package Zend_Validate + * @subpackage Sitemap + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Validate_Sitemap_Loc extends Zend_Validate_Abstract +{ + /** + * Validation key for not valid + * + */ + const NOT_VALID = 'sitemapLocNotValid'; + const INVALID = 'sitemapLocInvalid'; + + /** + * Validation failure message template definitions + * + * @var array + */ + protected $_messageTemplates = array( + self::NOT_VALID => "'%value%' is not a valid sitemap location", + self::INVALID => "Invalid type given. String expected", + ); + + /** + * Validates if a string is valid as a sitemap location + * + * @link http://www.sitemaps.org/protocol.php#locdef + * + * @param string $value value to validate + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + $result = Zend_Uri::check($value); + if ($result !== true) { + $this->_error(self::NOT_VALID); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/Sitemap/Priority.php b/library/vendor/Zend/Validate/Sitemap/Priority.php new file mode 100644 index 000000000..ac2d6e098 --- /dev/null +++ b/library/vendor/Zend/Validate/Sitemap/Priority.php @@ -0,0 +1,81 @@ + value + * + * @link http://www.sitemaps.org/protocol.php Sitemaps XML format + * + * @category Zend + * @package Zend_Validate + * @subpackage Sitemap + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Validate_Sitemap_Priority extends Zend_Validate_Abstract +{ + /** + * Validation key for not valid + * + */ + const NOT_VALID = 'sitemapPriorityNotValid'; + const INVALID = 'sitemapPriorityInvalid'; + + /** + * Validation failure message template definitions + * + * @var array + */ + protected $_messageTemplates = array( + self::NOT_VALID => "'%value%' is not a valid sitemap priority", + self::INVALID => "Invalid type given. Numeric string, integer or float expected", + ); + + /** + * Validates if a string is valid as a sitemap priority + * + * @link http://www.sitemaps.org/protocol.php#prioritydef + * + * @param string $value value to validate + * @return boolean + */ + public function isValid($value) + { + if (!is_numeric($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + $value = (float) $value; + if ($value < 0 || $value > 1) { + $this->_error(self::NOT_VALID); + return false; + } + + return true; + } +} diff --git a/library/vendor/Zend/Validate/StringLength.php b/library/vendor/Zend/Validate/StringLength.php new file mode 100644 index 000000000..732df0e30 --- /dev/null +++ b/library/vendor/Zend/Validate/StringLength.php @@ -0,0 +1,259 @@ + "Invalid type given. String expected", + self::TOO_SHORT => "'%value%' is less than %min% characters long", + self::TOO_LONG => "'%value%' is more than %max% characters long", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'min' => '_min', + 'max' => '_max' + ); + + /** + * Minimum length + * + * @var integer + */ + protected $_min; + + /** + * Maximum length + * + * If null, there is no maximum length + * + * @var integer|null + */ + protected $_max; + + /** + * Encoding to use + * + * @var string|null + */ + protected $_encoding; + + /** + * Sets validator options + * + * @param integer|array|Zend_Config $options + * @return void + */ + public function __construct($options = array()) + { + if ($options instanceof Zend_Config) { + $options = $options->toArray(); + } else if (!is_array($options)) { + $options = func_get_args(); + $temp['min'] = array_shift($options); + if (!empty($options)) { + $temp['max'] = array_shift($options); + } + + if (!empty($options)) { + $temp['encoding'] = array_shift($options); + } + + $options = $temp; + } + + if (!array_key_exists('min', $options)) { + $options['min'] = 0; + } + + $this->setMin($options['min']); + if (array_key_exists('max', $options)) { + $this->setMax($options['max']); + } + + if (array_key_exists('encoding', $options)) { + $this->setEncoding($options['encoding']); + } + } + + /** + * Returns the min option + * + * @return integer + */ + public function getMin() + { + return $this->_min; + } + + /** + * Sets the min option + * + * @param integer $min + * @throws Zend_Validate_Exception + * @return Zend_Validate_StringLength Provides a fluent interface + */ + public function setMin($min) + { + if (null !== $this->_max && $min > $this->_max) { + /** + * @see Zend_Validate_Exception + */ + throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum length, but $min >" + . " $this->_max"); + } + $this->_min = max(0, (integer) $min); + return $this; + } + + /** + * Returns the max option + * + * @return integer|null + */ + public function getMax() + { + return $this->_max; + } + + /** + * Sets the max option + * + * @param integer|null $max + * @throws Zend_Validate_Exception + * @return Zend_Validate_StringLength Provides a fluent interface + */ + public function setMax($max) + { + if (null === $max) { + $this->_max = null; + } else if ($max < $this->_min) { + /** + * @see Zend_Validate_Exception + */ + throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum length, but " + . "$max < $this->_min"); + } else { + $this->_max = (integer) $max; + } + + return $this; + } + + /** + * Returns the actual encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Sets a new encoding to use + * + * @param string $encoding + * @return Zend_Validate_StringLength + */ + public function setEncoding($encoding = null) + { + if ($encoding !== null) { + $orig = PHP_VERSION_ID < 50600 + ? iconv_get_encoding('internal_encoding') + : ini_get('default_charset'); + if (PHP_VERSION_ID < 50600) { + $result = iconv_set_encoding('internal_encoding', $encoding); + } else { + $result = ini_set('default_charset', $encoding); + } + if (!$result) { + throw new Zend_Validate_Exception('Given encoding not supported on this OS!'); + } + + if (PHP_VERSION_ID < 50600) { + iconv_set_encoding('internal_encoding', $orig); + } else { + ini_set('default_charset', $orig); + } + } + + $this->_encoding = $encoding; + return $this; + } + + /** + * Defined by Zend_Validate_Interface + * + * Returns true if and only if the string length of $value is at least the min option and + * no greater than the max option (when the max option is not null). + * + * @param string $value + * @return boolean + */ + public function isValid($value) + { + if (!is_string($value)) { + $this->_error(self::INVALID); + return false; + } + + $this->_setValue($value); + if ($this->_encoding !== null) { + $length = iconv_strlen($value, $this->_encoding); + } else { + $length = iconv_strlen($value); + } + + if ($length < $this->_min) { + $this->_error(self::TOO_SHORT); + } + + if (null !== $this->_max && $this->_max < $length) { + $this->_error(self::TOO_LONG); + } + + if (count($this->_messages)) { + return false; + } else { + return true; + } + } +} diff --git a/library/vendor/Zend/Version.php b/library/vendor/Zend/Version.php new file mode 100644 index 000000000..f9a9636bf --- /dev/null +++ b/library/vendor/Zend/Version.php @@ -0,0 +1,81 @@ +_useViewStream = (bool) ini_get('short_open_tag') ? false : true; + if ($this->_useViewStream) { + if (!in_array('zend.view', stream_get_wrappers())) { + stream_wrapper_register('zend.view', 'Zend_View_Stream'); + } + } + + if (array_key_exists('useStreamWrapper', $config)) { + $this->setUseStreamWrapper($config['useStreamWrapper']); + } + + parent::__construct($config); + } + + /** + * Set flag indicating if stream wrapper should be used if short_open_tag is off + * + * @param bool $flag + * @return Zend_View + */ + public function setUseStreamWrapper($flag) + { + $this->_useStreamWrapper = (bool) $flag; + return $this; + } + + /** + * Should the stream wrapper be used if short_open_tag is off? + * + * @return bool + */ + public function useStreamWrapper() + { + return $this->_useStreamWrapper; + } + + /** + * Includes the view script in a scope with only public $this variables. + * + * @param string The view script to execute. + */ + protected function _run() + { + if ($this->_useViewStream && $this->useStreamWrapper()) { + include 'zend.view://' . func_get_arg(0); + } else { + include func_get_arg(0); + } + } +} diff --git a/library/vendor/Zend/View/Abstract.php b/library/vendor/Zend/View/Abstract.php new file mode 100644 index 000000000..571830cf0 --- /dev/null +++ b/library/vendor/Zend/View/Abstract.php @@ -0,0 +1,1186 @@ + array(), + 'helper' => array(), + 'filter' => array(), + ); + + /** + * Script file name to execute + * + * @var string + */ + private $_file = null; + + /** + * Instances of helper objects. + * + * @var array + */ + private $_helper = array(); + + /** + * Map of helper => class pairs to help in determining helper class from + * name + * @var array + */ + private $_helperLoaded = array(); + + /** + * Map of helper => classfile pairs to aid in determining helper classfile + * @var array + */ + private $_helperLoadedDir = array(); + + /** + * Stack of Zend_View_Filter names to apply as filters. + * @var array + */ + private $_filter = array(); + + /** + * Stack of Zend_View_Filter objects that have been loaded + * @var array + */ + private $_filterClass = array(); + + /** + * Map of filter => class pairs to help in determining filter class from + * name + * @var array + */ + private $_filterLoaded = array(); + + /** + * Map of filter => classfile pairs to aid in determining filter classfile + * @var array + */ + private $_filterLoadedDir = array(); + + /** + * Callback for escaping. + * + * @var string + */ + private $_escape = 'htmlspecialchars'; + + /** + * Encoding to use in escaping mechanisms; defaults to utf-8 + * @var string + */ + private $_encoding = 'UTF-8'; + + /** + * Flag indicating whether or not LFI protection for rendering view scripts is enabled + * @var bool + */ + private $_lfiProtectionOn = true; + + /** + * Plugin loaders + * @var array + */ + private $_loaders = array(); + + /** + * Plugin types + * @var array + */ + private $_loaderTypes = array('filter', 'helper'); + + /** + * Strict variables flag; when on, undefined variables accessed in the view + * scripts will trigger notices + * @var boolean + */ + private $_strictVars = false; + + /** + * Constructor. + * + * @param array $config Configuration key-value pairs. + */ + public function __construct($config = array()) + { + // set inital paths and properties + $this->setScriptPath(null); + + // $this->setHelperPath(null); + $this->setFilterPath(null); + + // user-defined escaping callback + if (array_key_exists('escape', $config)) { + $this->setEscape($config['escape']); + } + + // encoding + if (array_key_exists('encoding', $config)) { + $this->setEncoding($config['encoding']); + } + + // base path + if (array_key_exists('basePath', $config)) { + $prefix = 'Zend_View'; + if (array_key_exists('basePathPrefix', $config)) { + $prefix = $config['basePathPrefix']; + } + $this->setBasePath($config['basePath'], $prefix); + } + + // user-defined view script path + if (array_key_exists('scriptPath', $config)) { + $this->addScriptPath($config['scriptPath']); + } + + // user-defined helper path + if (array_key_exists('helperPath', $config)) { + if (is_array($config['helperPath'])) { + foreach ($config['helperPath'] as $prefix => $path) { + $this->addHelperPath($path, $prefix); + } + } else { + $prefix = 'Zend_View_Helper'; + if (array_key_exists('helperPathPrefix', $config)) { + $prefix = $config['helperPathPrefix']; + } + $this->addHelperPath($config['helperPath'], $prefix); + } + } + + // user-defined filter path + if (array_key_exists('filterPath', $config)) { + if (is_array($config['filterPath'])) { + foreach ($config['filterPath'] as $prefix => $path) { + $this->addFilterPath($path, $prefix); + } + } else { + $prefix = 'Zend_View_Filter'; + if (array_key_exists('filterPathPrefix', $config)) { + $prefix = $config['filterPathPrefix']; + } + $this->addFilterPath($config['filterPath'], $prefix); + } + } + + // user-defined filters + if (array_key_exists('filter', $config)) { + $this->addFilter($config['filter']); + } + + // strict vars + if (array_key_exists('strictVars', $config)) { + $this->strictVars($config['strictVars']); + } + + // LFI protection flag + if (array_key_exists('lfiProtectionOn', $config)) { + $this->setLfiProtection($config['lfiProtectionOn']); + } + + if (array_key_exists('assign', $config) + && is_array($config['assign']) + ) { + foreach ($config['assign'] as $key => $value) { + $this->assign($key, $value); + } + } + + $this->init(); + } + + /** + * Return the template engine object + * + * Returns the object instance, as it is its own template engine + * + * @return Zend_View_Abstract + */ + public function getEngine() + { + return $this; + } + + /** + * Allow custom object initialization when extending Zend_View_Abstract or + * Zend_View + * + * Triggered by {@link __construct() the constructor} as its final action. + * + * @return void + */ + public function init() + { + } + + /** + * Prevent E_NOTICE for nonexistent values + * + * If {@link strictVars()} is on, raises a notice. + * + * @param string $key + * @return null + */ + public function __get($key) + { + if ($this->_strictVars) { + trigger_error('Key "' . $key . '" does not exist', E_USER_NOTICE); + } + + return null; + } + + /** + * Allows testing with empty() and isset() to work inside + * templates. + * + * @param string $key + * @return boolean + */ + public function __isset($key) + { + if ('_' != substr($key, 0, 1)) { + return isset($this->$key); + } + + return false; + } + + /** + * Directly assigns a variable to the view script. + * + * Checks first to ensure that the caller is not attempting to set a + * protected or private member (by checking for a prefixed underscore); if + * not, the public member is set; otherwise, an exception is raised. + * + * @param string $key The variable name. + * @param mixed $val The variable value. + * @return void + * @throws Zend_View_Exception if an attempt to set a private or protected + * member is detected + */ + public function __set($key, $val) + { + if ('_' != substr($key, 0, 1)) { + $this->$key = $val; + return; + } + + $e = new Zend_View_Exception('Setting private or protected class members is not allowed'); + $e->setView($this); + throw $e; + } + + /** + * Allows unset() on object properties to work + * + * @param string $key + * @return void + */ + public function __unset($key) + { + if ('_' != substr($key, 0, 1) && isset($this->$key)) { + unset($this->$key); + } + } + + /** + * Accesses a helper object from within a script. + * + * If the helper class has a 'view' property, sets it with the current view + * object. + * + * @param string $name The helper name. + * @param array $args The parameters for the helper. + * @return string The result of the helper output. + */ + public function __call($name, $args) + { + // is the helper already loaded? + $helper = $this->getHelper($name); + + // call the helper method + return call_user_func_array( + array($helper, $name), + $args + ); + } + + /** + * Given a base path, sets the script, helper, and filter paths relative to it + * + * Assumes a directory structure of: + * + * basePath/ + * scripts/ + * helpers/ + * filters/ + * + * + * @param string $path + * @param string $prefix Prefix to use for helper and filter paths + * @return Zend_View_Abstract + */ + public function setBasePath($path, $classPrefix = 'Zend_View') + { + $path = rtrim($path, '/'); + $path = rtrim($path, '\\'); + $path .= DIRECTORY_SEPARATOR; + $classPrefix = rtrim($classPrefix, '_') . '_'; + $this->setScriptPath($path . 'scripts'); + $this->setHelperPath($path . 'helpers', $classPrefix . 'Helper'); + $this->setFilterPath($path . 'filters', $classPrefix . 'Filter'); + return $this; + } + + /** + * Given a base path, add script, helper, and filter paths relative to it + * + * Assumes a directory structure of: + * + * basePath/ + * scripts/ + * helpers/ + * filters/ + * + * + * @param string $path + * @param string $prefix Prefix to use for helper and filter paths + * @return Zend_View_Abstract + */ + public function addBasePath($path, $classPrefix = 'Zend_View') + { + $path = rtrim($path, '/'); + $path = rtrim($path, '\\'); + $path .= DIRECTORY_SEPARATOR; + $classPrefix = rtrim($classPrefix, '_') . '_'; + $this->addScriptPath($path . 'scripts'); + $this->addHelperPath($path . 'helpers', $classPrefix . 'Helper'); + $this->addFilterPath($path . 'filters', $classPrefix . 'Filter'); + return $this; + } + + /** + * Adds to the stack of view script paths in LIFO order. + * + * @param string|array The directory (-ies) to add. + * @return Zend_View_Abstract + */ + public function addScriptPath($path) + { + $this->_addPath('script', $path); + return $this; + } + + /** + * Resets the stack of view script paths. + * + * To clear all paths, use Zend_View::setScriptPath(null). + * + * @param string|array The directory (-ies) to set as the path. + * @return Zend_View_Abstract + */ + public function setScriptPath($path) + { + $this->_path['script'] = array(); + $this->_addPath('script', $path); + return $this; + } + + /** + * Return full path to a view script specified by $name + * + * @param string $name + * @return false|string False if script not found + * @throws Zend_View_Exception if no script directory set + */ + public function getScriptPath($name) + { + try { + $path = $this->_script($name); + return $path; + } catch (Zend_View_Exception $e) { + if (strstr($e->getMessage(), 'no view script directory set')) { + throw $e; + } + + return false; + } + } + + /** + * Returns an array of all currently set script paths + * + * @return array + */ + public function getScriptPaths() + { + return $this->_getPaths('script'); + } + + /** + * Set plugin loader for a particular plugin type + * + * @param Zend_Loader_PluginLoader $loader + * @param string $type + * @return Zend_View_Abstract + */ + public function setPluginLoader(Zend_Loader_PluginLoader $loader, $type) + { + $type = strtolower($type); + if (!in_array($type, $this->_loaderTypes)) { + $e = new Zend_View_Exception(sprintf('Invalid plugin loader type "%s"', $type)); + $e->setView($this); + throw $e; + } + + $this->_loaders[$type] = $loader; + return $this; + } + + /** + * Retrieve plugin loader for a specific plugin type + * + * @param string $type + * @return Zend_Loader_PluginLoader + */ + public function getPluginLoader($type) + { + $type = strtolower($type); + if (!in_array($type, $this->_loaderTypes)) { + $e = new Zend_View_Exception(sprintf('Invalid plugin loader type "%s"; cannot retrieve', $type)); + $e->setView($this); + throw $e; + } + + if (!array_key_exists($type, $this->_loaders)) { + $prefix = 'Zend_View_'; + $pathPrefix = 'Zend/View/'; + + $pType = ucfirst($type); + switch ($type) { + case 'filter': + case 'helper': + default: + $prefix .= $pType; + $pathPrefix .= $pType; + $loader = new Zend_Loader_PluginLoader(array( + $prefix => $pathPrefix + )); + $this->_loaders[$type] = $loader; + break; + } + } + return $this->_loaders[$type]; + } + + /** + * Adds to the stack of helper paths in LIFO order. + * + * @param string|array The directory (-ies) to add. + * @param string $classPrefix Class prefix to use with classes in this + * directory; defaults to Zend_View_Helper + * @return Zend_View_Abstract + */ + public function addHelperPath($path, $classPrefix = 'Zend_View_Helper_') + { + return $this->_addPluginPath('helper', $classPrefix, (array) $path); + } + + /** + * Resets the stack of helper paths. + * + * To clear all paths, use Zend_View::setHelperPath(null). + * + * @param string|array $path The directory (-ies) to set as the path. + * @param string $classPrefix The class prefix to apply to all elements in + * $path; defaults to Zend_View_Helper + * @return Zend_View_Abstract + */ + public function setHelperPath($path, $classPrefix = 'Zend_View_Helper_') + { + unset($this->_loaders['helper']); + return $this->addHelperPath($path, $classPrefix); + } + + /** + * Get full path to a helper class file specified by $name + * + * @param string $name + * @return string|false False on failure, path on success + */ + public function getHelperPath($name) + { + return $this->_getPluginPath('helper', $name); + } + + /** + * Returns an array of all currently set helper paths + * + * @return array + */ + public function getHelperPaths() + { + return $this->getPluginLoader('helper')->getPaths(); + } + + /** + * Registers a helper object, bypassing plugin loader + * + * @param Zend_View_Helper_Abstract|object $helper + * @param string $name + * @return Zend_View_Abstract + * @throws Zend_View_Exception + */ + public function registerHelper($helper, $name) + { + if (!is_object($helper)) { + $e = new Zend_View_Exception('View helper must be an object'); + $e->setView($this); + throw $e; + } + + if (!$helper instanceof Zend_View_Interface) { + if (!method_exists($helper, $name)) { + $e = new Zend_View_Exception( + 'View helper must implement Zend_View_Interface or have a method matching the name provided' + ); + $e->setView($this); + throw $e; + } + } + + if (method_exists($helper, 'setView')) { + $helper->setView($this); + } + + $name = ucfirst($name); + $this->_helper[$name] = $helper; + return $this; + } + + /** + * Get a helper by name + * + * @param string $name + * @return object + */ + public function getHelper($name) + { + return $this->_getPlugin('helper', $name); + } + + /** + * Get array of all active helpers + * + * Only returns those that have already been instantiated. + * + * @return array + */ + public function getHelpers() + { + return $this->_helper; + } + + /** + * Adds to the stack of filter paths in LIFO order. + * + * @param string|array The directory (-ies) to add. + * @param string $classPrefix Class prefix to use with classes in this + * directory; defaults to Zend_View_Filter + * @return Zend_View_Abstract + */ + public function addFilterPath($path, $classPrefix = 'Zend_View_Filter_') + { + return $this->_addPluginPath('filter', $classPrefix, (array) $path); + } + + /** + * Resets the stack of filter paths. + * + * To clear all paths, use Zend_View::setFilterPath(null). + * + * @param string|array The directory (-ies) to set as the path. + * @param string $classPrefix The class prefix to apply to all elements in + * $path; defaults to Zend_View_Filter + * @return Zend_View_Abstract + */ + public function setFilterPath($path, $classPrefix = 'Zend_View_Filter_') + { + unset($this->_loaders['filter']); + return $this->addFilterPath($path, $classPrefix); + } + + /** + * Get full path to a filter class file specified by $name + * + * @param string $name + * @return string|false False on failure, path on success + */ + public function getFilterPath($name) + { + return $this->_getPluginPath('filter', $name); + } + + /** + * Get a filter object by name + * + * @param string $name + * @return object + */ + public function getFilter($name) + { + return $this->_getPlugin('filter', $name); + } + + /** + * Return array of all currently active filters + * + * Only returns those that have already been instantiated. + * + * @return array + */ + public function getFilters() + { + return $this->_filter; + } + + /** + * Returns an array of all currently set filter paths + * + * @return array + */ + public function getFilterPaths() + { + return $this->getPluginLoader('filter')->getPaths(); + } + + /** + * Return associative array of path types => paths + * + * @return array + */ + public function getAllPaths() + { + $paths = $this->_path; + $paths['helper'] = $this->getHelperPaths(); + $paths['filter'] = $this->getFilterPaths(); + return $paths; + } + + /** + * Add one or more filters to the stack in FIFO order. + * + * @param string|array One or more filters to add. + * @return Zend_View_Abstract + */ + public function addFilter($name) + { + foreach ((array) $name as $val) { + $this->_filter[] = $val; + } + return $this; + } + + /** + * Resets the filter stack. + * + * To clear all filters, use Zend_View::setFilter(null). + * + * @param string|array One or more filters to set. + * @return Zend_View_Abstract + */ + public function setFilter($name) + { + $this->_filter = array(); + $this->addFilter($name); + return $this; + } + + /** + * Sets the _escape() callback. + * + * @param mixed $spec The callback for _escape() to use. + * @return Zend_View_Abstract + */ + public function setEscape($spec) + { + $this->_escape = $spec; + return $this; + } + + /** + * Set LFI protection flag + * + * @param bool $flag + * @return Zend_View_Abstract + */ + public function setLfiProtection($flag) + { + $this->_lfiProtectionOn = (bool) $flag; + return $this; + } + + /** + * Return status of LFI protection flag + * + * @return bool + */ + public function isLfiProtectionOn() + { + return $this->_lfiProtectionOn; + } + + /** + * Assigns variables to the view script via differing strategies. + * + * Zend_View::assign('name', $value) assigns a variable called 'name' + * with the corresponding $value. + * + * Zend_View::assign($array) assigns the array keys as variable + * names (with the corresponding array values). + * + * @see __set() + * @param string|array The assignment strategy to use. + * @param mixed (Optional) If assigning a named variable, use this + * as the value. + * @return Zend_View_Abstract Fluent interface + * @throws Zend_View_Exception if $spec is neither a string nor an array, + * or if an attempt to set a private or protected member is detected + */ + public function assign($spec, $value = null) + { + // which strategy to use? + if (is_string($spec)) { + // assign by name and value + if ('_' == substr($spec, 0, 1)) { + $e = new Zend_View_Exception('Setting private or protected class members is not allowed'); + $e->setView($this); + throw $e; + } + $this->$spec = $value; + } elseif (is_array($spec)) { + // assign from associative array + $error = false; + foreach ($spec as $key => $val) { + if ('_' == substr($key, 0, 1)) { + $error = true; + break; + } + $this->$key = $val; + } + if ($error) { + $e = new Zend_View_Exception('Setting private or protected class members is not allowed'); + $e->setView($this); + throw $e; + } + } else { + $e = new Zend_View_Exception('assign() expects a string or array, received ' . gettype($spec)); + $e->setView($this); + throw $e; + } + + return $this; + } + + /** + * Return list of all assigned variables + * + * Returns all public properties of the object. Reflection is not used + * here as testing reflection properties for visibility is buggy. + * + * @return array + */ + public function getVars() + { + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + if ('_' == substr($key, 0, 1)) { + unset($vars[$key]); + } + } + + return $vars; + } + + /** + * Clear all assigned variables + * + * Clears all variables assigned to Zend_View either via {@link assign()} or + * property overloading ({@link __set()}). + * + * @return void + */ + public function clearVars() + { + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + if ('_' != substr($key, 0, 1)) { + unset($this->$key); + } + } + } + + /** + * Processes a view script and returns the output. + * + * @param string $name The script name to process. + * @return string The script output. + */ + public function render($name) + { + // find the script file name using the parent private method + $this->_file = $this->_script($name); + unset($name); // remove $name from local scope + + ob_start(); + $this->_run($this->_file); + + return $this->_filter(ob_get_clean()); // filter output + } + + /** + * Escapes a value for output in a view script. + * + * If escaping mechanism is one of htmlspecialchars or htmlentities, uses + * {@link $_encoding} setting. + * + * @param mixed $var The output to escape. + * @return mixed The escaped value. + */ + public function escape($var) + { + if (in_array($this->_escape, array('htmlspecialchars', 'htmlentities'))) { + return call_user_func($this->_escape, $var, ENT_COMPAT, $this->_encoding); + } + + if (1 == func_num_args()) { + return call_user_func($this->_escape, $var); + } + $args = func_get_args(); + return call_user_func_array($this->_escape, $args); + } + + /** + * Set encoding to use with htmlentities() and htmlspecialchars() + * + * @param string $encoding + * @return Zend_View_Abstract + */ + public function setEncoding($encoding) + { + $this->_encoding = $encoding; + return $this; + } + + /** + * Return current escape encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Enable or disable strict vars + * + * If strict variables are enabled, {@link __get()} will raise a notice + * when a variable is not defined. + * + * Use in conjunction with {@link Zend_View_Helper_DeclareVars the declareVars() helper} + * to enforce strict variable handling in your view scripts. + * + * @param boolean $flag + * @return Zend_View_Abstract + */ + public function strictVars($flag = true) + { + $this->_strictVars = ($flag) ? true : false; + + return $this; + } + + /** + * Finds a view script from the available directories. + * + * @param string $name The base name of the script. + * @return void + */ + protected function _script($name) + { + if ($this->isLfiProtectionOn() && preg_match('#\.\.[\\\/]#', $name)) { + $e = new Zend_View_Exception('Requested scripts may not include parent directory traversal ("../", "..\\" notation)'); + $e->setView($this); + throw $e; + } + + if (0 == count($this->_path['script'])) { + $e = new Zend_View_Exception('no view script directory set; unable to determine location for view script'); + $e->setView($this); + throw $e; + } + + foreach ($this->_path['script'] as $dir) { + if (is_readable($dir . $name)) { + return $dir . $name; + } + } + + $message = "script '$name' not found in path (" + . implode(PATH_SEPARATOR, $this->_path['script']) + . ")"; + $e = new Zend_View_Exception($message); + $e->setView($this); + throw $e; + } + + /** + * Applies the filter callback to a buffer. + * + * @param string $buffer The buffer contents. + * @return string The filtered buffer. + */ + private function _filter($buffer) + { + // loop through each filter class + foreach ($this->_filter as $name) { + // load and apply the filter class + $filter = $this->getFilter($name); + $buffer = call_user_func(array($filter, 'filter'), $buffer); + } + + // done! + return $buffer; + } + + /** + * Adds paths to the path stack in LIFO order. + * + * Zend_View::_addPath($type, 'dirname') adds one directory + * to the path stack. + * + * Zend_View::_addPath($type, $array) adds one directory for + * each array element value. + * + * In the case of filter and helper paths, $prefix should be used to + * specify what class prefix to use with the given path. + * + * @param string $type The path type ('script', 'helper', or 'filter'). + * @param string|array $path The path specification. + * @param string $prefix Class prefix to use with path (helpers and filters + * only) + * @return void + */ + private function _addPath($type, $path, $prefix = null) + { + foreach ((array) $path as $dir) { + // attempt to strip any possible separator and + // append the system directory separator + $dir = rtrim($dir, '/'); + $dir = rtrim($dir, '\\'); + $dir .= '/'; + + switch ($type) { + case 'script': + // add to the top of the stack. + array_unshift($this->_path[$type], $dir); + break; + case 'filter': + case 'helper': + default: + // add as array with prefix and dir keys + array_unshift($this->_path[$type], array('prefix' => $prefix, 'dir' => $dir)); + break; + } + } + } + + /** + * Resets the path stack for helpers and filters. + * + * @param string $type The path type ('helper' or 'filter'). + * @param string|array $path The directory (-ies) to set as the path. + * @param string $classPrefix Class prefix to apply to elements of $path + */ + private function _setPath($type, $path, $classPrefix = null) + { + $dir = DIRECTORY_SEPARATOR . ucfirst($type) . DIRECTORY_SEPARATOR; + + switch ($type) { + case 'script': + $this->_path[$type] = array(dirname(__FILE__) . $dir); + $this->_addPath($type, $path); + break; + case 'filter': + case 'helper': + default: + $this->_path[$type] = array(array( + 'prefix' => 'Zend_View_' . ucfirst($type) . '_', + 'dir' => dirname(__FILE__) . $dir + )); + $this->_addPath($type, $path, $classPrefix); + break; + } + } + + /** + * Return all paths for a given path type + * + * @param string $type The path type ('helper', 'filter', 'script') + * @return array + */ + private function _getPaths($type) + { + return $this->_path[$type]; + } + + /** + * Register helper class as loaded + * + * @param string $name + * @param string $class + * @param string $file path to class file + * @return void + */ + private function _setHelperClass($name, $class, $file) + { + $this->_helperLoadedDir[$name] = $file; + $this->_helperLoaded[$name] = $class; + } + + /** + * Register filter class as loaded + * + * @param string $name + * @param string $class + * @param string $file path to class file + * @return void + */ + private function _setFilterClass($name, $class, $file) + { + $this->_filterLoadedDir[$name] = $file; + $this->_filterLoaded[$name] = $class; + } + + /** + * Add a prefixPath for a plugin type + * + * @param string $type + * @param string $classPrefix + * @param array $paths + * @return Zend_View_Abstract + */ + private function _addPluginPath($type, $classPrefix, array $paths) + { + $loader = $this->getPluginLoader($type); + foreach ($paths as $path) { + $loader->addPrefixPath($classPrefix, $path); + } + return $this; + } + + /** + * Get a path to a given plugin class of a given type + * + * @param string $type + * @param string $name + * @return string|false + */ + private function _getPluginPath($type, $name) + { + $loader = $this->getPluginLoader($type); + if ($loader->isLoaded($name)) { + return $loader->getClassPath($name); + } + + try { + $loader->load($name); + return $loader->getClassPath($name); + } catch (Zend_Loader_Exception $e) { + return false; + } + } + + /** + * Retrieve a plugin object + * + * @param string $type + * @param string $name + * @return object + */ + private function _getPlugin($type, $name) + { + $name = ucfirst($name); + switch ($type) { + case 'filter': + $storeVar = '_filterClass'; + $store = $this->_filterClass; + break; + case 'helper': + $storeVar = '_helper'; + $store = $this->_helper; + break; + } + + if (!isset($store[$name])) { + $class = $this->getPluginLoader($type)->load($name); + $store[$name] = new $class(); + if (method_exists($store[$name], 'setView')) { + $store[$name]->setView($this); + } + } + + $this->$storeVar = $store; + return $store[$name]; + } + + /** + * Use to include the view script in a scope that only allows public + * members. + * + * @return mixed + */ + abstract protected function _run(); +} diff --git a/library/vendor/Zend/View/Exception.php b/library/vendor/Zend/View/Exception.php new file mode 100644 index 000000000..6eabf491c --- /dev/null +++ b/library/vendor/Zend/View/Exception.php @@ -0,0 +1,50 @@ +view = $view; + return $this; + } + + public function getView() + { + return $this->view; + } +} diff --git a/library/vendor/Zend/View/Helper/Abstract.php b/library/vendor/Zend/View/Helper/Abstract.php new file mode 100644 index 000000000..4c2d6f406 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Abstract.php @@ -0,0 +1,63 @@ +view = $view; + return $this; + } + + /** + * Strategy pattern: currently unutilized + * + * @return void + */ + public function direct() + { + } +} diff --git a/library/vendor/Zend/View/Helper/Action.php b/library/vendor/Zend/View/Helper/Action.php new file mode 100644 index 000000000..8bacc41cd --- /dev/null +++ b/library/vendor/Zend/View/Helper/Action.php @@ -0,0 +1,161 @@ +getControllerDirectory(); + if (empty($modules)) { + $e = new Zend_View_Exception('Action helper depends on valid front controller instance'); + $e->setView($this->view); + throw $e; + } + + $request = $front->getRequest(); + $response = $front->getResponse(); + + if (empty($request) || empty($response)) { + $e = new Zend_View_Exception('Action view helper requires both a registered request and response object in the front controller instance'); + $e->setView($this->view); + throw $e; + } + + $this->request = clone $request; + $this->response = clone $response; + $this->dispatcher = clone $front->getDispatcher(); + $this->defaultModule = $front->getDefaultModule(); + } + + /** + * Reset object states + * + * @return void + */ + public function resetObjects() + { + $params = $this->request->getUserParams(); + foreach (array_keys($params) as $key) { + $this->request->setParam($key, null); + } + + $this->response->clearBody(); + $this->response->clearHeaders() + ->clearRawHeaders(); + } + + /** + * Retrieve rendered contents of a controller action + * + * If the action results in a forward or redirect, returns empty string. + * + * @param string $action + * @param string $controller + * @param string $module Defaults to default module + * @param array $params + * @return string + */ + public function action($action, $controller, $module = null, array $params = array()) + { + $this->resetObjects(); + if (null === $module) { + $module = $this->defaultModule; + } + + // clone the view object to prevent over-writing of view variables + $viewRendererObj = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); + Zend_Controller_Action_HelperBroker::addHelper(clone $viewRendererObj); + + $this->request->setParams($params) + ->setModuleName($module) + ->setControllerName($controller) + ->setActionName($action) + ->setDispatched(true); + + $this->dispatcher->dispatch($this->request, $this->response); + + // reset the viewRenderer object to it's original state + Zend_Controller_Action_HelperBroker::addHelper($viewRendererObj); + + + if (!$this->request->isDispatched() + || $this->response->isRedirect()) + { + // forwards and redirects render nothing + return ''; + } + + $return = $this->response->getBody(); + $this->resetObjects(); + return $return; + } + + /** + * Clone the current View + * + * @return Zend_View_Interface + */ + public function cloneView() + { + $view = clone $this->view; + $view->clearVars(); + return $view; + } +} diff --git a/library/vendor/Zend/View/Helper/BaseUrl.php b/library/vendor/Zend/View/Helper/BaseUrl.php new file mode 100644 index 000000000..f42c6a9f2 --- /dev/null +++ b/library/vendor/Zend/View/Helper/BaseUrl.php @@ -0,0 +1,114 @@ +getBaseUrl(); + + // Remove trailing slashes + if (null !== $file) { + $file = '/' . ltrim($file, '/\\'); + } + + return $baseUrl . $file; + } + + /** + * Set BaseUrl + * + * @param string $base + * @return Zend_View_Helper_BaseUrl + */ + public function setBaseUrl($base) + { + $this->_baseUrl = rtrim($base, '/\\'); + return $this; + } + + /** + * Get BaseUrl + * + * @return string + */ + public function getBaseUrl() + { + if ($this->_baseUrl === null) { + /** @see Zend_Controller_Front */ + $baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl(); + + // Remove scriptname, eg. index.php from baseUrl + $baseUrl = $this->_removeScriptName($baseUrl); + + $this->setBaseUrl($baseUrl); + } + + return $this->_baseUrl; + } + + /** + * Remove Script filename from baseurl + * + * @param string $url + * @return string + */ + protected function _removeScriptName($url) + { + if (!isset($_SERVER['SCRIPT_NAME'])) { + // We can't do much now can we? (Well, we could parse out by ".") + return $url; + } + + if (($pos = strripos($url, basename($_SERVER['SCRIPT_NAME']))) !== false) { + $url = substr($url, 0, $pos); + } + + return $url; + } +} diff --git a/library/vendor/Zend/View/Helper/Currency.php b/library/vendor/Zend/View/Helper/Currency.php new file mode 100644 index 000000000..3ce7e3583 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Currency.php @@ -0,0 +1,116 @@ +setCurrency($currency); + } + + /** + * Output a formatted currency + * + * @param integer|float $value Currency value to output + * @param string|Zend_Locale|array $currency OPTIONAL Currency to use for + * this call + * @return string Formatted currency + */ + public function currency($value = null, $currency = null) + { + if ($value === null) { + return $this; + } + + if (is_string($currency) || ($currency instanceof Zend_Locale)) { + if (Zend_Locale::isLocale($currency)) { + $currency = array('locale' => $currency); + } + } + + if (is_string($currency)) { + $currency = array('currency' => $currency); + } + + if (is_array($currency)) { + return $this->_currency->toCurrency($value, $currency); + } + + return $this->_currency->toCurrency($value); + } + + /** + * Sets a currency to use + * + * @param Zend_Currency|String|Zend_Locale $currency Currency to use + * @throws Zend_View_Exception When no or a false currency was set + * @return Zend_View_Helper_Currency + */ + public function setCurrency($currency = null) + { + if (!$currency instanceof Zend_Currency) { + $currency = new Zend_Currency($currency); + } + $this->_currency = $currency; + + return $this; + } + + /** + * Retrieve currency object + * + * @return Zend_Currency|null + */ + public function getCurrency() + { + return $this->_currency; + } +} diff --git a/library/vendor/Zend/View/Helper/Cycle.php b/library/vendor/Zend/View/Helper/Cycle.php new file mode 100644 index 000000000..955251dcf --- /dev/null +++ b/library/vendor/Zend/View/Helper/Cycle.php @@ -0,0 +1,225 @@ +-1) ; + + /** + * Array of values + * + * @var array + */ + protected $_data = array(self::DEFAULT_NAME=>array()); + + /** + * Actual name of cycle + * + * @var string + */ + protected $_name = self::DEFAULT_NAME; + + /** + * Add elements to alternate + * + * @param array $data + * @param string $name + * @return Zend_View_Helper_Cycle + */ + public function cycle(array $data = array(), $name = self::DEFAULT_NAME) + { + if(!empty($data)) + $this->_data[$name] = $data; + + $this->setName($name); + return $this; + } + + /** + * Add elements to alternate + * + * @param array $data + * @param string $name + * @return Zend_View_Helper_Cycle + */ + public function assign(Array $data , $name = self::DEFAULT_NAME) + { + $this->setName($name); + $this->_data[$name] = $data; + $this->rewind(); + return $this; + } + + /** + * Sets actual name of cycle + * + * @param string $name + * @return Zend_View_Helper_Cycle + */ + public function setName($name = self::DEFAULT_NAME) + { + $this->_name = $name; + + if(!isset($this->_data[$this->_name])) + $this->_data[$this->_name] = array(); + + if(!isset($this->_pointers[$this->_name])) + $this->rewind(); + + return $this; + } + + /** + * Gets actual name of cycle + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + + /** + * Return all elements + * + * @return array + */ + public function getAll() + { + return $this->_data[$this->_name]; + } + + /** + * Turn helper into string + * + * @return string + */ + public function toString() + { + return (string) $this->_data[$this->_name][$this->key()]; + } + + /** + * Cast to string + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Move to next value + * + * @return Zend_View_Helper_Cycle + */ + public function next() + { + $count = count($this->_data[$this->_name]); + if ($this->_pointers[$this->_name] == ($count - 1)) + $this->_pointers[$this->_name] = 0; + else + $this->_pointers[$this->_name] = ++$this->_pointers[$this->_name]; + return $this; + } + + /** + * Move to previous value + * + * @return Zend_View_Helper_Cycle + */ + public function prev() + { + $count = count($this->_data[$this->_name]); + if ($this->_pointers[$this->_name] <= 0) + $this->_pointers[$this->_name] = $count - 1; + else + $this->_pointers[$this->_name] = --$this->_pointers[$this->_name]; + return $this; + } + + /** + * Return iteration number + * + * @return int + */ + public function key() + { + if ($this->_pointers[$this->_name] < 0) + return 0; + else + return $this->_pointers[$this->_name]; + } + + /** + * Rewind pointer + * + * @return Zend_View_Helper_Cycle + */ + public function rewind() + { + $this->_pointers[$this->_name] = -1; + return $this; + } + + /** + * Check if element is valid + * + * @return bool + */ + public function valid() + { + return isset($this->_data[$this->_name][$this->key()]); + } + + /** + * Return current element + * + * @return mixed + */ + public function current() + { + return $this->_data[$this->_name][$this->key()]; + } +} diff --git a/library/vendor/Zend/View/Helper/DeclareVars.php b/library/vendor/Zend/View/Helper/DeclareVars.php new file mode 100644 index 000000000..259ffc7be --- /dev/null +++ b/library/vendor/Zend/View/Helper/DeclareVars.php @@ -0,0 +1,94 @@ + + * $this->declareVars( + * 'varName1', + * 'varName2', + * array('varName3' => 'defaultValue', + * 'varName4' => array() + * ) + * ); + * + * + * @param string|array variable number of arguments, all string names of variables to test + * @return void + */ + public function declareVars() + { + $args = func_get_args(); + foreach($args as $key) { + if (is_array($key)) { + foreach ($key as $name => $value) { + $this->_declareVar($name, $value); + } + } else if (!isset($view->$key)) { + $this->_declareVar($key); + } + } + } + + /** + * Set a view variable + * + * Checks to see if a $key is set in the view object; if not, sets it to $value. + * + * @param string $key + * @param string $value Defaults to an empty string + * @return void + */ + protected function _declareVar($key, $value = '') + { + if (!isset($this->view->$key)) { + $this->view->$key = $value; + } + } +} diff --git a/library/vendor/Zend/View/Helper/Doctype.php b/library/vendor/Zend/View/Helper/Doctype.php new file mode 100644 index 000000000..4e9cd0655 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Doctype.php @@ -0,0 +1,239 @@ +_regKey)) { + $this->_registry = new ArrayObject(array( + 'doctypes' => array( + self::XHTML11 => '', + self::XHTML1_STRICT => '', + self::XHTML1_TRANSITIONAL => '', + self::XHTML1_FRAMESET => '', + self::XHTML1_RDFA => '', + self::XHTML1_RDFA11 => '', + self::XHTML_BASIC1 => '', + self::XHTML5 => '', + self::HTML4_STRICT => '', + self::HTML4_LOOSE => '', + self::HTML4_FRAMESET => '', + self::HTML5 => '', + ) + )); + Zend_Registry::set($this->_regKey, $this->_registry); + $this->setDoctype($this->_defaultDoctype); + } else { + $this->_registry = Zend_Registry::get($this->_regKey); + } + } + + /** + * Set or retrieve doctype + * + * @param string $doctype + * @return Zend_View_Helper_Doctype + */ + public function doctype($doctype = null) + { + if (null !== $doctype) { + switch ($doctype) { + case self::XHTML11: + case self::XHTML1_STRICT: + case self::XHTML1_TRANSITIONAL: + case self::XHTML1_FRAMESET: + case self::XHTML_BASIC1: + case self::XHTML1_RDFA: + case self::XHTML1_RDFA11: + case self::XHTML5: + case self::HTML4_STRICT: + case self::HTML4_LOOSE: + case self::HTML4_FRAMESET: + case self::HTML5: + $this->setDoctype($doctype); + break; + default: + if (substr($doctype, 0, 9) != 'setView($this->view); + throw $e; + } + if (stristr($doctype, 'xhtml')) { + $type = self::CUSTOM_XHTML; + } else { + $type = self::CUSTOM; + } + $this->setDoctype($type); + $this->_registry['doctypes'][$type] = $doctype; + break; + } + } + + return $this; + } + + /** + * Set doctype + * + * @param string $doctype + * @return Zend_View_Helper_Doctype + */ + public function setDoctype($doctype) + { + $this->_registry['doctype'] = $doctype; + return $this; + } + + /** + * Retrieve doctype + * + * @return string + */ + public function getDoctype() + { + return $this->_registry['doctype']; + } + + /** + * Get doctype => string mappings + * + * @return array + */ + public function getDoctypes() + { + return $this->_registry['doctypes']; + } + + /** + * Is doctype XHTML? + * + * @return boolean + */ + public function isXhtml() + { + return (stristr($this->getDoctype(), 'xhtml') ? true : false); + } + + /** + * Is doctype strict? + * + * @return boolean + */ + public function isStrict() + { + switch ( $this->getDoctype() ) + { + case self::XHTML1_STRICT: + case self::XHTML11: + case self::HTML4_STRICT: + return true; + default: + return false; + } + } + + /** + * Is doctype HTML5? (HeadMeta uses this for validation) + * + * @return booleean + */ + public function isHtml5() { + return (stristr($this->doctype(), '') ? true : false); + } + + /** + * Is doctype RDFa? + * + * @return booleean + */ + public function isRdfa() { + return (stristr($this->getDoctype(), 'rdfa') ? true : false); + } + + /** + * String representation of doctype + * + * @return string + */ + public function __toString() + { + $doctypes = $this->getDoctypes(); + return $doctypes[$this->getDoctype()]; + } +} diff --git a/library/vendor/Zend/View/Helper/Fieldset.php b/library/vendor/Zend/View/Helper/Fieldset.php new file mode 100644 index 000000000..915c3fdcc --- /dev/null +++ b/library/vendor/Zend/View/Helper/Fieldset.php @@ -0,0 +1,78 @@ +_getInfo($name, $content, $attribs); + extract($info); + + // get legend + $legend = ''; + if (isset($attribs['legend'])) { + $legendString = trim($attribs['legend']); + if (!empty($legendString)) { + $legend = '' + . (($escape) ? $this->view->escape($legendString) : $legendString) + . '' . PHP_EOL; + } + unset($attribs['legend']); + } + + // get id + if (!empty($id)) { + $id = ' id="' . $this->view->escape($id) . '"'; + } else { + $id = ''; + } + + // render fieldset + $xhtml = '_htmlAttribs($attribs) + . '>' + . $legend + . $content + . ''; + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/Form.php b/library/vendor/Zend/View/Helper/Form.php new file mode 100644 index 000000000..1e5dffa32 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Form.php @@ -0,0 +1,85 @@ +_getInfo($name, $content, $attribs); + extract($info); + + if (!empty($id)) { + $id = ' id="' . $this->view->escape($id) . '"'; + } else { + $id = ''; + } + + if (array_key_exists('id', $attribs) && empty($attribs['id'])) { + unset($attribs['id']); + } + + if (!empty($name) && !($this->_isXhtml() && $this->_isStrictDoctype())) { + $name = ' name="' . $this->view->escape($name) . '"'; + } else { + $name = ''; + } + + if ($this->_isHtml5() && array_key_exists('action', $attribs) && !$attribs['action']) { + unset($attribs['action']); + } + + if ( array_key_exists('name', $attribs) && empty($attribs['id'])) { + unset($attribs['id']); + } + + $xhtml = '_htmlAttribs($attribs) + . '>'; + + if (false !== $content) { + $xhtml .= $content + . ''; + } + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormButton.php b/library/vendor/Zend/View/Helper/FormButton.php new file mode 100644 index 000000000..435e16d2d --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormButton.php @@ -0,0 +1,104 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, id, value, attribs, options, listsep, disable, escape + + // Get content + $content = ''; + if (isset($attribs['content'])) { + $content = $attribs['content']; + unset($attribs['content']); + } else { + $content = $value; + } + + // Ensure type is sane + $type = 'button'; + if (isset($attribs['type'])) { + $attribs['type'] = strtolower($attribs['type']); + if (in_array($attribs['type'], array('submit', 'reset', 'button'))) { + $type = $attribs['type']; + } + unset($attribs['type']); + } + + // build the element + if ($disable) { + $attribs['disabled'] = 'disabled'; + } + + $content = ($escape) ? $this->view->escape($content) : $content; + + $xhtml = 'view->escape($value) . '"'; + } + + // add attributes and close start tag + $xhtml .= $this->_htmlAttribs($attribs) . '>'; + + // add content and end tag + $xhtml .= $content . ''; + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormCheckbox.php b/library/vendor/Zend/View/Helper/FormCheckbox.php new file mode 100644 index 000000000..3b9be34e0 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormCheckbox.php @@ -0,0 +1,163 @@ + '1', + 'uncheckedValue' => '0' + ); + + /** + * Generates a 'checkbox' element. + * + * @access public + * + * @param string|array $name If a string, the element name. If an + * array, all other parameters are ignored, and the array elements + * are extracted in place of added parameters. + * @param mixed $value The element value. + * @param array $attribs Attributes for the element tag. + * @return string The element XHTML. + */ + public function formCheckbox($name, $value = null, $attribs = null, array $checkedOptions = null) + { + $info = $this->_getInfo($name, $value, $attribs); + extract($info); // name, id, value, attribs, options, listsep, disable + + $checked = false; + if (isset($attribs['checked']) && $attribs['checked']) { + $checked = true; + unset($attribs['checked']); + } elseif (isset($attribs['checked'])) { + $checked = false; + unset($attribs['checked']); + } + + $checkedOptions = self::determineCheckboxInfo($value, $checked, $checkedOptions); + + // is the element disabled? + $disabled = ''; + if ($disable) { + $disabled = ' disabled="disabled"'; + } + + // build the element + $xhtml = ''; + if ((!$disable && !strstr($name, '[]')) + && (empty($attribs['disableHidden']) || !$attribs['disableHidden']) + ) { + $xhtml = $this->_hidden($name, $checkedOptions['uncheckedValue']); + } + + if (array_key_exists('disableHidden', $attribs)) { + unset($attribs['disableHidden']); + } + + $xhtml .= '_htmlAttribs($attribs) + . $this->getClosingBracket(); + + return $xhtml; + } + + /** + * Determine checkbox information + * + * @param string $value + * @param bool $checked + * @param array|null $checkedOptions + * @return array + */ + public static function determineCheckboxInfo($value, $checked, array $checkedOptions = null) + { + // Checked/unchecked values + $checkedValue = null; + $uncheckedValue = null; + if (is_array($checkedOptions)) { + if (array_key_exists('checkedValue', $checkedOptions)) { + $checkedValue = (string) $checkedOptions['checkedValue']; + unset($checkedOptions['checkedValue']); + } + if (array_key_exists('uncheckedValue', $checkedOptions)) { + $uncheckedValue = (string) $checkedOptions['uncheckedValue']; + unset($checkedOptions['uncheckedValue']); + } + if (null === $checkedValue) { + $checkedValue = (string) array_shift($checkedOptions); + } + if (null === $uncheckedValue) { + $uncheckedValue = (string) array_shift($checkedOptions); + } + } elseif ($value !== null) { + $uncheckedValue = self::$_defaultCheckedOptions['uncheckedValue']; + } else { + $checkedValue = self::$_defaultCheckedOptions['checkedValue']; + $uncheckedValue = self::$_defaultCheckedOptions['uncheckedValue']; + } + + // is the element checked? + $checkedString = ''; + if ($checked || ((string) $value === $checkedValue)) { + $checkedString = ' checked="checked"'; + $checked = true; + } else { + $checked = false; + } + + // Checked value should be value if no checked options provided + if ($checkedValue == null) { + $checkedValue = $value; + } + + return array( + 'checked' => $checked, + 'checkedString' => $checkedString, + 'checkedValue' => $checkedValue, + 'uncheckedValue' => $uncheckedValue, + ); + } +} diff --git a/library/vendor/Zend/View/Helper/FormElement.php b/library/vendor/Zend/View/Helper/FormElement.php new file mode 100644 index 000000000..816018572 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormElement.php @@ -0,0 +1,202 @@ +_translator; + } + + /** + * Set translator + * + * @param Zend_Translate|Zend_Translate_Adapter|null $translator + * @return Zend_View_Helper_FormElement + */ + public function setTranslator($translator = null) + { + if (null === $translator) { + $this->_translator = null; + } elseif ($translator instanceof Zend_Translate_Adapter) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } else { + $e = new Zend_View_Exception('Invalid translator specified'); + $e->setView($this->view); + throw $e; + } + return $this; + } + + /** + * Converts parameter arguments to an element info array. + * + * E.g, formExample($name, $value, $attribs, $options, $listsep) is + * the same thing as formExample(array('name' => ...)). + * + * Note that you cannot pass a 'disable' param; you need to pass + * it as an 'attribs' key. + * + * @access protected + * + * @return array An element info array with keys for name, value, + * attribs, options, listsep, disable, and escape. + */ + protected function _getInfo($name, $value = null, $attribs = null, + $options = null, $listsep = null + ) { + // the baseline info. note that $name serves a dual purpose; + // if an array, it's an element info array that will override + // these baseline values. as such, ignore it for the 'name' + // if it's an array. + $info = array( + 'name' => is_array($name) ? '' : $name, + 'id' => is_array($name) ? '' : $name, + 'value' => $value, + 'attribs' => $attribs, + 'options' => $options, + 'listsep' => $listsep, + 'disable' => false, + 'escape' => true, + ); + + // override with named args + if (is_array($name)) { + // only set keys that are already in info + foreach ($info as $key => $val) { + if (isset($name[$key])) { + $info[$key] = $name[$key]; + } + } + + // If all helper options are passed as an array, attribs may have + // been as well + if (null === $attribs) { + $attribs = $info['attribs']; + } + } + + $attribs = (array)$attribs; + + // Normalize readonly tag + if (array_key_exists('readonly', $attribs)) { + $attribs['readonly'] = 'readonly'; + } + + // Disable attribute + if (array_key_exists('disable', $attribs)) { + if (is_scalar($attribs['disable'])) { + // disable the element + $info['disable'] = (bool)$attribs['disable']; + } else if (is_array($attribs['disable'])) { + $info['disable'] = $attribs['disable']; + } + } + + // Set ID for element + if (array_key_exists('id', $attribs)) { + $info['id'] = (string)$attribs['id']; + } else if ('' !== $info['name']) { + $info['id'] = trim(strtr($info['name'], + array('[' => '-', ']' => '')), '-'); + } + + // Remove NULL name attribute override + if (array_key_exists('name', $attribs) && is_null($attribs['name'])) { + unset($attribs['name']); + } + + // Override name in info if specified in attribs + if (array_key_exists('name', $attribs) && $attribs['name'] != $info['name']) { + $info['name'] = $attribs['name']; + } + + // Determine escaping from attributes + if (array_key_exists('escape', $attribs)) { + $info['escape'] = (bool)$attribs['escape']; + } + + // Determine listsetp from attributes + if (array_key_exists('listsep', $attribs)) { + $info['listsep'] = (string)$attribs['listsep']; + } + + // Remove attribs that might overwrite the other keys. We do this LAST + // because we needed the other attribs values earlier. + foreach ($info as $key => $val) { + if (array_key_exists($key, $attribs)) { + unset($attribs[$key]); + } + } + $info['attribs'] = $attribs; + + // done! + return $info; + } + + /** + * Creates a hidden element. + * + * We have this as a common method because other elements often + * need hidden elements for their operation. + * + * @access protected + * + * @param string $name The element name. + * @param string $value The element value. + * @param array $attribs Attributes for the element. + * + * @return string A hidden element. + */ + protected function _hidden($name, $value = null, $attribs = null) + { + return '_htmlAttribs($attribs) . $this->getClosingBracket(); + } +} diff --git a/library/vendor/Zend/View/Helper/FormErrors.php b/library/vendor/Zend/View/Helper/FormErrors.php new file mode 100644 index 000000000..7ed8d7340 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormErrors.php @@ -0,0 +1,166 @@ +'; + protected $_htmlElementStart = '
            • '; + protected $_htmlElementSeparator = '
            • '; + /**#@-*/ + + /** + * Render form errors + * + * @param string|array $errors Error(s) to render + * @param array $options + * @return string + */ + public function formErrors($errors, array $options = null) + { + $escape = true; + if (isset($options['escape'])) { + $escape = (bool) $options['escape']; + unset($options['escape']); + } + + if (empty($options['class'])) { + $options['class'] = 'errors'; + } + + if (isset($options['elementStart'])) { + $this->setElementStart($options['elementStart']); + } + if (isset($options['elementEnd'])) { + $this->setElementEnd($options['elementEnd']); + } + if (isset($options['elementSeparator'])) { + $this->setElementSeparator($options['elementSeparator']); + } + + $start = $this->getElementStart(); + if (strstr($start, '%s')) { + $attribs = $this->_htmlAttribs($options); + $start = sprintf($start, $attribs); + } + + if ($escape) { + foreach ($errors as $key => $error) { + $errors[$key] = $this->view->escape($error); + } + } + + $html = $start + . implode($this->getElementSeparator(), (array) $errors) + . $this->getElementEnd(); + + return $html; + } + + /** + * Set end string for displaying errors + * + * @param string $string + * @return Zend_View_Helper_FormErrors + */ + public function setElementEnd($string) + { + $this->_htmlElementEnd = (string) $string; + return $this; + } + + /** + * Retrieve end string for displaying errors + * + * @return string + */ + public function getElementEnd() + { + return $this->_htmlElementEnd; + } + + /** + * Set separator string for displaying errors + * + * @param string $string + * @return Zend_View_Helper_FormErrors + */ + public function setElementSeparator($string) + { + $this->_htmlElementSeparator = (string) $string; + return $this; + } + + /** + * Retrieve separator string for displaying errors + * + * @return string + */ + public function getElementSeparator() + { + return $this->_htmlElementSeparator; + } + + /** + * Set start string for displaying errors + * + * @param string $string + * @return Zend_View_Helper_FormErrors + */ + public function setElementStart($string) + { + $this->_htmlElementStart = (string) $string; + return $this; + } + + /** + * Retrieve start string for displaying errors + * + * @return string + */ + public function getElementStart() + { + return $this->_htmlElementStart; + } + +} diff --git a/library/vendor/Zend/View/Helper/FormFile.php b/library/vendor/Zend/View/Helper/FormFile.php new file mode 100644 index 000000000..2a40bd28d --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormFile.php @@ -0,0 +1,74 @@ +_getInfo($name, null, $attribs); + extract($info); // name, id, value, attribs, options, listsep, disable + + // is it disabled? + $disabled = ''; + if ($disable) { + $disabled = ' disabled="disabled"'; + } + + // build the element + $xhtml = '_htmlAttribs($attribs) + . $this->getClosingBracket(); + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormHidden.php b/library/vendor/Zend/View/Helper/FormHidden.php new file mode 100644 index 000000000..cbad00199 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormHidden.php @@ -0,0 +1,65 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable + if (isset($id)) { + if (isset($attribs) && is_array($attribs)) { + $attribs['id'] = $id; + } else { + $attribs = array('id' => $id); + } + } + return $this->_hidden($name, $value, $attribs); + } +} diff --git a/library/vendor/Zend/View/Helper/FormImage.php b/library/vendor/Zend/View/Helper/FormImage.php new file mode 100644 index 000000000..67849949e --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormImage.php @@ -0,0 +1,94 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable + + // Determine if we should use the value or the src attribute + if (isset($attribs['src'])) { + $src = ' src="' . $this->view->escape($attribs['src']) . '"'; + unset($attribs['src']); + } else { + $src = ' src="' . $this->view->escape($value) . '"'; + unset($value); + } + + // Do we have a value? + if (isset($value) && !empty($value)) { + $value = ' value="' . $this->view->escape($value) . '"'; + } else { + $value = ''; + } + + // Disabled? + $disabled = ''; + if ($disable) { + $disabled = ' disabled="disabled"'; + } + + // build the element + $xhtml = '_htmlAttribs($attribs) + . $this->getClosingBracket(); + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormLabel.php b/library/vendor/Zend/View/Helper/FormLabel.php new file mode 100644 index 000000000..ffa25f2ee --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormLabel.php @@ -0,0 +1,71 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable, escape + + // build the element + if ($disable) { + // disabled; display nothing + return ''; + } + + $value = ($escape) ? $this->view->escape($value) : $value; + $for = (empty($attribs['disableFor']) || !$attribs['disableFor']) + ? ' for="' . $this->view->escape($id) . '"' + : ''; + if (array_key_exists('disableFor', $attribs)) { + unset($attribs['disableFor']); + } + + // enabled; display label + $xhtml = '_htmlAttribs($attribs) + . '>' . $value . ''; + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormMultiCheckbox.php b/library/vendor/Zend/View/Helper/FormMultiCheckbox.php new file mode 100644 index 000000000..f19698f52 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormMultiCheckbox.php @@ -0,0 +1,73 @@ +\n") + { + return $this->formRadio($name, $value, $attribs, $options, $listsep); + } +} diff --git a/library/vendor/Zend/View/Helper/FormNote.php b/library/vendor/Zend/View/Helper/FormNote.php new file mode 100644 index 000000000..d1ebc0e6d --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormNote.php @@ -0,0 +1,60 @@ +_getInfo($name, $value); + extract($info); // name, value, attribs, options, listsep, disable + return $value; + } +} diff --git a/library/vendor/Zend/View/Helper/FormPassword.php b/library/vendor/Zend/View/Helper/FormPassword.php new file mode 100644 index 000000000..1359eacbd --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormPassword.php @@ -0,0 +1,88 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable + + // is it disabled? + $disabled = ''; + if ($disable) { + // disabled + $disabled = ' disabled="disabled"'; + } + + // determine the XHTML value + $valueString = ' value=""'; + if (array_key_exists('renderPassword', $attribs)) { + if ($attribs['renderPassword']) { + $valueString = ' value="' . $this->view->escape($value) . '"'; + } + unset($attribs['renderPassword']); + } + + // render the element + $xhtml = '_htmlAttribs($attribs) + . $this->getClosingBracket(); + + return $xhtml; + } + +} diff --git a/library/vendor/Zend/View/Helper/FormRadio.php b/library/vendor/Zend/View/Helper/FormRadio.php new file mode 100644 index 000000000..cc2a52ff1 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormRadio.php @@ -0,0 +1,185 @@ +\n") + { + + $info = $this->_getInfo($name, $value, $attribs, $options, $listsep); + extract($info); // name, value, attribs, options, listsep, disable + + // retrieve attributes for labels (prefixed with 'label_' or 'label') + $label_attribs = array(); + foreach ($attribs as $key => $val) { + $tmp = false; + $keyLen = strlen($key); + if ((6 < $keyLen) && (substr($key, 0, 6) == 'label_')) { + $tmp = substr($key, 6); + } elseif ((5 < $keyLen) && (substr($key, 0, 5) == 'label')) { + $tmp = substr($key, 5); + } + + if ($tmp) { + // make sure first char is lowercase + $tmp[0] = strtolower($tmp[0]); + $label_attribs[$tmp] = $val; + unset($attribs[$key]); + } + } + + $labelPlacement = 'append'; + foreach ($label_attribs as $key => $val) { + switch (strtolower($key)) { + case 'placement': + unset($label_attribs[$key]); + $val = strtolower($val); + if (in_array($val, array('prepend', 'append'))) { + $labelPlacement = $val; + } + break; + } + } + + // the radio button values and labels + $options = (array) $options; + + // build the element + $xhtml = ''; + $list = array(); + + // should the name affect an array collection? + $name = $this->view->escape($name); + if ($this->_isArray && ('[]' != substr($name, -2))) { + $name .= '[]'; + } + + // ensure value is an array to allow matching multiple times + $value = (array) $value; + + // Set up the filter - Alnum + hyphen + underscore + $pattern = @preg_match('/\pL/u', 'a') + ? '/[^\p{L}\p{N}\-\_]/u' // Unicode + : '/[^a-zA-Z0-9\-\_]/'; // No Unicode + $filter = new Zend_Filter_PregReplace($pattern, ""); + + // add radio buttons to the list. + foreach ($options as $opt_value => $opt_label) { + + // Should the label be escaped? + if ($escape) { + $opt_label = $this->view->escape($opt_label); + } + + // is it disabled? + $disabled = ''; + if (true === $disable) { + $disabled = ' disabled="disabled"'; + } elseif (is_array($disable) && in_array($opt_value, $disable)) { + $disabled = ' disabled="disabled"'; + } + + // is it checked? + $checked = ''; + if (in_array($opt_value, $value)) { + $checked = ' checked="checked"'; + } + + // generate ID + $optId = $id . '-' . $filter->filter($opt_value); + + // Wrap the radios in labels + $radio = '_htmlAttribs($label_attribs) . '>' + . (('prepend' == $labelPlacement) ? $opt_label : '') + . '_htmlAttribs($attribs) + . $this->getClosingBracket() + . (('append' == $labelPlacement) ? $opt_label : '') + . ''; + + // add to the array of radio buttons + $list[] = $radio; + } + + // XHTML or HTML for standard list separator? + if (!$this->_isXhtml() && false !== strpos($listsep, '
              ')) { + $listsep = str_replace('
              ', '
              ', $listsep); + } + + // done! + $xhtml .= implode($listsep, $list); + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormReset.php b/library/vendor/Zend/View/Helper/FormReset.php new file mode 100644 index 000000000..6859d985b --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormReset.php @@ -0,0 +1,81 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable + + // check if disabled + $disabled = ''; + if ($disable) { + $disabled = ' disabled="disabled"'; + } + + // Render button + $xhtml = 'view->escape($value) . '"'; + } + + // add attributes, close, and return + $xhtml .= $this->_htmlAttribs($attribs) . $this->getClosingBracket(); + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormSelect.php b/library/vendor/Zend/View/Helper/FormSelect.php new file mode 100644 index 000000000..87460ba74 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormSelect.php @@ -0,0 +1,199 @@ +\n") + { + $info = $this->_getInfo($name, $value, $attribs, $options, $listsep); + extract($info); // name, id, value, attribs, options, listsep, disable + + // force $value to array so we can compare multiple values to multiple + // options; also ensure it's a string for comparison purposes. + $value = array_map('strval', (array) $value); + + // check if element may have multiple values + $multiple = ''; + + if (substr($name, -2) == '[]') { + // multiple implied by the name + $multiple = ' multiple="multiple"'; + } + + if (isset($attribs['multiple'])) { + // Attribute set + if ($attribs['multiple']) { + // True attribute; set multiple attribute + $multiple = ' multiple="multiple"'; + + // Make sure name indicates multiple values are allowed + if (!empty($multiple) && (substr($name, -2) != '[]')) { + $name .= '[]'; + } + } else { + // False attribute; ensure attribute not set + $multiple = ''; + } + unset($attribs['multiple']); + } + + // handle the options classes + $optionClasses = array(); + if (isset($attribs['optionClasses'])) { + $optionClasses = $attribs['optionClasses']; + unset($attribs['optionClasses']); + } + + // now start building the XHTML. + $disabled = ''; + if (true === $disable) { + $disabled = ' disabled="disabled"'; + } + + // Build the surrounding select element first. + $xhtml = '_htmlAttribs($attribs) + . ">\n "; + + // build the list of options + $list = array(); + $translator = $this->getTranslator(); + foreach ((array) $options as $opt_value => $opt_label) { + if (is_array($opt_label)) { + $opt_disable = ''; + if (is_array($disable) && in_array($opt_value, $disable)) { + $opt_disable = ' disabled="disabled"'; + } + if (null !== $translator) { + $opt_value = $translator->translate($opt_value); + } + $opt_id = ' id="' . $this->view->escape($id) . '-optgroup-' + . $this->view->escape($opt_value) . '"'; + $list[] = ''; + foreach ($opt_label as $val => $lab) { + $list[] = $this->_build($val, $lab, $value, $disable, $optionClasses); + } + $list[] = ''; + } else { + $list[] = $this->_build($opt_value, $opt_label, $value, $disable, $optionClasses); + } + } + + // add the options to the xhtml and close the select + $xhtml .= implode("\n ", $list) . "\n"; + + return $xhtml; + } + + /** + * Builds the actual "; + + return $opt; + } + +} diff --git a/library/vendor/Zend/View/Helper/FormSubmit.php b/library/vendor/Zend/View/Helper/FormSubmit.php new file mode 100644 index 000000000..b5b237e3d --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormSubmit.php @@ -0,0 +1,80 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable, id + // check if disabled + $disabled = ''; + if ($disable) { + $disabled = ' disabled="disabled"'; + } + + if ($id) { + $id = ' id="' . $this->view->escape($id) . '"'; + } + + // Render the button. + $xhtml = '_htmlAttribs($attribs) + . $this->getClosingBracket(); + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormText.php b/library/vendor/Zend/View/Helper/FormText.php new file mode 100644 index 000000000..dad1dd06c --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormText.php @@ -0,0 +1,77 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable + + // build the element + $disabled = ''; + if ($disable) { + // disabled + $disabled = ' disabled="disabled"'; + } + + $xhtml = '_htmlAttribs($attribs) + . $this->getClosingBracket(); + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/FormTextarea.php b/library/vendor/Zend/View/Helper/FormTextarea.php new file mode 100644 index 000000000..3556cd530 --- /dev/null +++ b/library/vendor/Zend/View/Helper/FormTextarea.php @@ -0,0 +1,103 @@ +_getInfo($name, $value, $attribs); + extract($info); // name, value, attribs, options, listsep, disable + + // is it disabled? + $disabled = ''; + if ($disable) { + // disabled. + $disabled = ' disabled="disabled"'; + } + + // Make sure that there are 'rows' and 'cols' values + // as required by the spec. noted by Orjan Persson. + if (empty($attribs['rows'])) { + $attribs['rows'] = (int) $this->rows; + } + if (empty($attribs['cols'])) { + $attribs['cols'] = (int) $this->cols; + } + + // build the element + $xhtml = ''; + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/Gravatar.php b/library/vendor/Zend/View/Helper/Gravatar.php new file mode 100644 index 000000000..1afc4cb11 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Gravatar.php @@ -0,0 +1,361 @@ + 80, + 'default_img' => self::DEFAULT_MM, + 'rating' => self::RATING_G, + 'secure' => null, + ); + + /** + * Email Adress + * + * @var string + */ + protected $_email; + + /** + * Attributes for HTML image tag + * + * @var array + */ + protected $_attribs; + + /** + * Returns an avatar from gravatar's service. + * + * $options may include the following: + * - 'img_size' int height of img to return + * - 'default_img' string img to return if email adress has not found + * - 'rating' string rating parameter for avatar + * - 'secure' bool load from the SSL or Non-SSL location + * + * @see http://pl.gravatar.com/site/implement/url + * @see http://pl.gravatar.com/site/implement/url More information about gravatar's service. + * @param string|null $email Email adress. + * @param null|array $options Options + * @param array $attribs Attributes for image tag (title, alt etc.) + * @return Zend_View_Helper_Gravatar + */ + public function gravatar($email = "", $options = array(), $attribs = array()) + { + $this->setEmail($email); + $this->setOptions($options); + $this->setAttribs($attribs); + return $this; + } + + /** + * Configure state + * + * @param array $options + * @return Zend_View_Helper_Gravatar + */ + public function setOptions(array $options) + { + foreach ($options as $key => $value) { + $method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); + if (method_exists($this, $method)) { + $this->{$method}($value); + } + } + return $this; + } + + /** + * Get img size + * + * @return int The img size + */ + public function getImgSize() + { + return $this->_options['img_size']; + } + + /** + * Set img size in pixels + * + * @param int $imgSize Size of img must be between 1 and 512 + * @return Zend_View_Helper_Gravatar + */ + public function setImgSize($imgSize) + { + $this->_options['img_size'] = (int) $imgSize; + return $this; + } + + /** + * Get default img + * + * @return string + */ + public function getDefaultImg() + { + return $this->_options['default_img']; + } + + /** + * Set default img + * + * Can be either an absolute URL to an image, or one of the DEFAULT_* constants + * + * @param string $defaultImg + * @link http://pl.gravatar.com/site/implement/url More information about default image. + * @return Zend_View_Helper_Gravatar + */ + public function setDefaultImg($defaultImg) + { + $this->_options['default_img'] = urlencode($defaultImg); + return $this; + } + + /** + * Set rating value + * + * Must be one of the RATING_* constants + * + * @param string $rating Value for rating. Allowed values are: g, px, r,x + * @link http://pl.gravatar.com/site/implement/url More information about rating. + * @throws Zend_View_Exception + */ + public function setRating($rating) + { + switch ($rating) { + case self::RATING_G: + case self::RATING_PG: + case self::RATING_R: + case self::RATING_X: + $this->_options['rating'] = $rating; + break; + default: + throw new Zend_View_Exception(sprintf( + 'The rating value "%s" is not allowed', + $rating + )); + } + return $this; + } + + /** + * Get rating value + * + * @return string + */ + public function getRating() + { + return $this->_options['rating']; + } + + /** + * Set email adress + * + * @param string $email + * @return Zend_View_Helper_Gravatar + */ + public function setEmail( $email ) + { + $this->_email = $email; + return $this; + } + + /** + * Get email adress + * + * @return string + */ + public function getEmail() + { + return $this->_email; + } + + /** + * Load from an SSL or No-SSL location? + * + * @param bool $flag + * @return Zend_View_Helper_Gravatar + */ + public function setSecure($flag) + { + $this->_options['secure'] = ($flag === null) ? null : (bool) $flag; + return $this; + } + + /** + * Get an SSL or a No-SSL location + * + * @return bool + */ + public function getSecure() + { + if ($this->_options['secure'] === null) { + return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); + } + return $this->_options['secure']; + } + + /** + * Get attribs of image + * + * Warning! + * If you set src attrib, you get it, but this value will be overwritten in + * protected method _setSrcAttribForImg(). And finally your get other src + * value! + * + * @return array + */ + public function getAttribs() + { + return $this->_attribs; + } + + /** + * Set attribs for image tag + * + * Warning! You shouldn't set src attrib for image tag. + * This attrib is overwritten in protected method _setSrcAttribForImg(). + * This method(_setSrcAttribForImg) is called in public method getImgTag(). + + * @param array $attribs + * @return Zend_View_Helper_Gravatar + */ + public function setAttribs(array $attribs) + { + $this->_attribs = $attribs; + return $this; + } + + /** + * Get URL to gravatar's service. + * + * @return string URL + */ + protected function _getGravatarUrl() + { + return ($this->getSecure() === false) ? self::GRAVATAR_URL : self::GRAVATAR_URL_SECURE; + } + + /** + * Get avatar url (including size, rating and default image oprions) + * + * @return string + */ + protected function _getAvatarUrl() + { + $src = $this->_getGravatarUrl() + . '/' + . md5(strtolower(trim($this->getEmail()))) + . '?s=' + . $this->getImgSize() + . '&d=' + . $this->getDefaultImg() + . '&r=' + . $this->getRating(); + return $src; + } + + /** + * Set src attrib for image. + * + * You shouldn't set a own url value! + * It sets value, uses protected method _getAvatarUrl. + * + * If already exsist overwritten. + */ + protected function _setSrcAttribForImg() + { + $attribs = $this->getAttribs(); + $attribs['src'] = $this->_getAvatarUrl(); + $this->setAttribs($attribs); + } + + /** + * Return valid image tag + * + * @return string + */ + public function getImgTag() + { + $this->_setSrcAttribForImg(); + $html = '_htmlAttribs($this->getAttribs()) + . $this->getClosingBracket(); + + return $html; + } + + /** + * Return valid image tag + * + * @return string + */ + public function __toString() + { + return $this->getImgTag(); + + } +} diff --git a/library/vendor/Zend/View/Helper/HeadLink.php b/library/vendor/Zend/View/Helper/HeadLink.php new file mode 100644 index 000000000..355b1b34a --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadLink.php @@ -0,0 +1,460 @@ +setSeparator(PHP_EOL); + } + + /** + * headLink() - View Helper Method + * + * Returns current object instance. Optionally, allows passing array of + * values to build link. + * + * @return Zend_View_Helper_HeadLink + */ + public function headLink(array $attributes = null, $placement = Zend_View_Helper_Placeholder_Container_Abstract::APPEND) + { + if (null !== $attributes) { + $item = $this->createData($attributes); + switch ($placement) { + case Zend_View_Helper_Placeholder_Container_Abstract::SET: + $this->set($item); + break; + case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: + $this->prepend($item); + break; + case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: + default: + $this->append($item); + break; + } + } + return $this; + } + + /** + * Overload method access + * + * Creates the following virtual methods: + * - appendStylesheet($href, $media, $conditionalStylesheet, $extras) + * - offsetSetStylesheet($index, $href, $media, $conditionalStylesheet, $extras) + * - prependStylesheet($href, $media, $conditionalStylesheet, $extras) + * - setStylesheet($href, $media, $conditionalStylesheet, $extras) + * - appendAlternate($href, $type, $title, $extras) + * - offsetSetAlternate($index, $href, $type, $title, $extras) + * - prependAlternate($href, $type, $title, $extras) + * - setAlternate($href, $type, $title, $extras) + * + * Items that may be added in the future: + * - Navigation? need to find docs on this + * - public function appendStart() + * - public function appendContents() + * - public function appendPrev() + * - public function appendNext() + * - public function appendIndex() + * - public function appendEnd() + * - public function appendGlossary() + * - public function appendAppendix() + * - public function appendHelp() + * - public function appendBookmark() + * - Other? + * - public function appendCopyright() + * - public function appendChapter() + * - public function appendSection() + * - public function appendSubsection() + * + * @param mixed $method + * @param mixed $args + * @return void + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(?PStylesheet|Alternate)$/', $method, $matches)) { + $argc = count($args); + $action = $matches['action']; + $type = $matches['type']; + $index = null; + + if ('offsetSet' == $action) { + if (0 < $argc) { + $index = array_shift($args); + --$argc; + } + } + + if (1 > $argc) { + $e = new Zend_View_Exception(sprintf('%s requires at least one argument', $method)); + $e->setView($this->view); + throw $e; + } + + if (is_array($args[0])) { + $item = $this->createData($args[0]); + } else { + $dataMethod = 'createData' . $type; + $item = $this->$dataMethod($args); + } + + if ($item) { + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + } + + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Check if value is valid + * + * @param mixed $value + * @return boolean + */ + protected function _isValid($value) + { + if (!$value instanceof stdClass) { + return false; + } + + $vars = get_object_vars($value); + $keys = array_keys($vars); + $intersection = array_intersect($this->_itemKeys, $keys); + if (empty($intersection)) { + return false; + } + + return true; + } + + /** + * append() + * + * @param array $value + * @return void + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('append() expects a data token; please use one of the custom append*() methods'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * offsetSet() + * + * @param string|int $index + * @param array $value + * @return void + */ + public function offsetSet($index, $value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('offsetSet() expects a data token; please use one of the custom offsetSet*() methods'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->offsetSet($index, $value); + } + + /** + * prepend() + * + * @param array $value + * @return Zend_Layout_ViewHelper_HeadLink + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('prepend() expects a data token; please use one of the custom prepend*() methods'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * set() + * + * @param array $value + * @return Zend_Layout_ViewHelper_HeadLink + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('set() expects a data token; please use one of the custom set*() methods'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->set($value); + } + + + /** + * Create HTML link element from data item + * + * @param stdClass $item + * @return string + */ + public function itemToString(stdClass $item) + { + $attributes = (array) $item; + $link = '_itemKeys as $itemKey) { + if (isset($attributes[$itemKey])) { + if(is_array($attributes[$itemKey])) { + foreach($attributes[$itemKey] as $key => $value) { + $link .= sprintf('%s="%s" ', $key, ($this->_autoEscape) ? $this->_escape($value) : $value); + } + } else { + $link .= sprintf('%s="%s" ', $itemKey, ($this->_autoEscape) ? $this->_escape($attributes[$itemKey]) : $attributes[$itemKey]); + } + } + } + + if ($this->view instanceof Zend_View_Abstract) { + $link .= ($this->view->doctype()->isXhtml()) ? '/>' : '>'; + } else { + $link .= '/>'; + } + + if (($link == '') || ($link == '')) { + return ''; + } + + if (isset($attributes['conditionalStylesheet']) + && !empty($attributes['conditionalStylesheet']) + && is_string($attributes['conditionalStylesheet'])) + { + $link = ''; + } + + return $link; + } + + /** + * Render link elements as string + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + $this->getContainer()->ksort(); + foreach ($this as $item) { + $items[] = $this->itemToString($item); + } + + return $indent . implode($this->_escape($this->getSeparator()) . $indent, $items); + } + + /** + * Create data item for stack + * + * @param array $attributes + * @return stdClass + */ + public function createData(array $attributes) + { + $data = (object) $attributes; + return $data; + } + + /** + * Create item for stylesheet link item + * + * @param array $args + * @return stdClass|false Returns fals if stylesheet is a duplicate + */ + public function createDataStylesheet(array $args) + { + $rel = 'stylesheet'; + $type = 'text/css'; + $media = 'screen'; + $conditionalStylesheet = false; + $href = array_shift($args); + + if ($this->_isDuplicateStylesheet($href)) { + return false; + } + + if (0 < count($args)) { + $media = array_shift($args); + if(is_array($media)) { + $media = implode(',', $media); + } else { + $media = (string) $media; + } + } + if (0 < count($args)) { + $conditionalStylesheet = array_shift($args); + if(!empty($conditionalStylesheet) && is_string($conditionalStylesheet)) { + $conditionalStylesheet = (string) $conditionalStylesheet; + } else { + $conditionalStylesheet = null; + } + } + + if(0 < count($args) && is_array($args[0])) { + $extras = array_shift($args); + $extras = (array) $extras; + } + + $attributes = compact('rel', 'type', 'href', 'media', 'conditionalStylesheet', 'extras'); + return $this->createData($this->_applyExtras($attributes)); + } + + /** + * Is the linked stylesheet a duplicate? + * + * @param string $uri + * @return bool + */ + protected function _isDuplicateStylesheet($uri) + { + foreach ($this->getContainer() as $item) { + if (($item->rel == 'stylesheet') && ($item->href == $uri)) { + return true; + } + } + return false; + } + + /** + * Create item for alternate link item + * + * @param array $args + * @return stdClass + */ + public function createDataAlternate(array $args) + { + if (3 > count($args)) { + $e = new Zend_View_Exception(sprintf('Alternate tags require 3 arguments; %s provided', count($args))); + $e->setView($this->view); + throw $e; + } + + $rel = 'alternate'; + $href = array_shift($args); + $type = array_shift($args); + $title = array_shift($args); + + if(0 < count($args) && is_array($args[0])) { + $extras = array_shift($args); + $extras = (array) $extras; + + if(isset($extras['media']) && is_array($extras['media'])) { + $extras['media'] = implode(',', $extras['media']); + } + } + + $href = (string) $href; + $type = (string) $type; + $title = (string) $title; + + $attributes = compact('rel', 'href', 'type', 'title', 'extras'); + return $this->createData($this->_applyExtras($attributes)); + } + + /** + * Apply any overrides specified in the 'extras' array + * @param array $attributes + * @return array + */ + protected function _applyExtras($attributes) + { + if (isset($attributes['extras'])) { + foreach ($attributes['extras'] as $eKey=>$eVal) { + if (isset($attributes[$eKey])) { + $attributes[$eKey] = $eVal; + unset($attributes['extras'][$eKey]); + } + } + } + return $attributes; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadMeta.php b/library/vendor/Zend/View/Helper/HeadMeta.php new file mode 100644 index 000000000..5df0d79b3 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadMeta.php @@ -0,0 +1,423 @@ +setSeparator(PHP_EOL); + } + + /** + * Retrieve object instance; optionally add meta tag + * + * @param string $content + * @param string $keyValue + * @param string $keyType + * @param array $modifiers + * @param string $placement + * @return Zend_View_Helper_HeadMeta + */ + public function headMeta($content = null, $keyValue = null, $keyType = 'name', $modifiers = array(), $placement = Zend_View_Helper_Placeholder_Container_Abstract::APPEND) + { + if ((null !== $content) && (null !== $keyValue)) { + $item = $this->createData($keyType, $keyValue, $content, $modifiers); + $action = strtolower($placement); + switch ($action) { + case 'append': + case 'prepend': + case 'set': + $this->$action($item); + break; + default: + $this->append($item); + break; + } + } + + return $this; + } + + protected function _normalizeType($type) + { + switch ($type) { + case 'Name': + return 'name'; + case 'HttpEquiv': + return 'http-equiv'; + case 'Property': + return 'property'; + default: + $e = new Zend_View_Exception(sprintf('Invalid type "%s" passed to _normalizeType', $type)); + $e->setView($this->view); + throw $e; + } + } + + /** + * Overload method access + * + * Allows the following 'virtual' methods: + * - appendName($keyValue, $content, $modifiers = array()) + * - offsetGetName($index, $keyValue, $content, $modifers = array()) + * - prependName($keyValue, $content, $modifiers = array()) + * - setName($keyValue, $content, $modifiers = array()) + * - appendHttpEquiv($keyValue, $content, $modifiers = array()) + * - offsetGetHttpEquiv($index, $keyValue, $content, $modifers = array()) + * - prependHttpEquiv($keyValue, $content, $modifiers = array()) + * - setHttpEquiv($keyValue, $content, $modifiers = array()) + * - appendProperty($keyValue, $content, $modifiers = array()) + * - offsetGetProperty($index, $keyValue, $content, $modifiers = array()) + * - prependProperty($keyValue, $content, $modifiers = array()) + * - setProperty($keyValue, $content, $modifiers = array()) + * + * @param string $method + * @param array $args + * @return Zend_View_Helper_HeadMeta + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(pre|ap)pend|offsetSet)(?PName|HttpEquiv|Property)$/', $method, $matches)) { + $action = $matches['action']; + $type = $this->_normalizeType($matches['type']); + $argc = count($args); + $index = null; + + if ('offsetSet' == $action) { + if (0 < $argc) { + $index = array_shift($args); + --$argc; + } + } + + if (2 > $argc) { + $e = new Zend_View_Exception('Too few arguments provided; requires key value, and content'); + $e->setView($this->view); + throw $e; + } + + if (3 > $argc) { + $args[] = array(); + } + + $item = $this->createData($type, $args[0], $args[1], $args[2]); + + if ('offsetSet' == $action) { + return $this->offsetSet($index, $item); + } + + $this->$action($item); + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Create an HTML5-style meta charset tag. Something like + * + * Not valid in a non-HTML5 doctype + * + * @param string $charset + * @return Zend_View_Helper_HeadMeta Provides a fluent interface + */ + public function setCharset($charset) + { + $item = new stdClass; + $item->type = 'charset'; + $item->charset = $charset; + $item->content = null; + $item->modifiers = array(); + $this->set($item); + return $this; + } + + /** + * Determine if item is valid + * + * @param mixed $item + * @return boolean + */ + protected function _isValid($item) + { + if ((!$item instanceof stdClass) + || !isset($item->type) + || !isset($item->modifiers)) + { + return false; + } + + $isHtml5 = is_null($this->view) ? false : $this->view->doctype()->isHtml5(); + + if (!isset($item->content) + && (! $isHtml5 || (! $isHtml5 && $item->type !== 'charset'))) { + return false; + } + + // is only supported with doctype RDFa + if ( !is_null($this->view) && !$this->view->doctype()->isRdfa() + && $item->type === 'property') { + return false; + } + + return true; + } + + /** + * Append + * + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to append; please use appendMeta()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * OffsetSet + * + * @param string|int $index + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function offsetSet($index, $value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetName() or offsetSetHttpEquiv()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->offsetSet($index, $value); + } + + /** + * OffsetUnset + * + * @param string|int $index + * @return void + * @throws Zend_View_Exception + */ + public function offsetUnset($index) + { + if (!in_array($index, $this->getContainer()->getKeys())) { + $e = new Zend_View_Exception('Invalid index passed to offsetUnset()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->offsetUnset($index); + } + + /** + * Prepend + * + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependMeta()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * Set + * + * @param string $value + * @return void + * @throws Zend_View_Exception + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to set; please use setMeta()'); + $e->setView($this->view); + throw $e; + } + + $container = $this->getContainer(); + foreach ($container->getArrayCopy() as $index => $item) { + if ($item->type == $value->type && $item->{$item->type} == $value->{$value->type}) { + $this->offsetUnset($index); + } + } + + return $this->append($value); + } + + /** + * Build meta HTML string + * + * @param string $type + * @param string $typeValue + * @param string $content + * @param array $modifiers + * @return string + */ + public function itemToString(stdClass $item) + { + if (!in_array($item->type, $this->_typeKeys)) { + $e = new Zend_View_Exception(sprintf('Invalid type "%s" provided for meta', $item->type)); + $e->setView($this->view); + throw $e; + } + $type = $item->type; + + $modifiersString = ''; + foreach ($item->modifiers as $key => $value) { + if (!is_null($this->view) && $this->view->doctype()->isHtml5() + && $key == 'scheme') { + throw new Zend_View_Exception('Invalid modifier ' + . '"scheme" provided; not supported by HTML5'); + } + if (!in_array($key, $this->_modifierKeys)) { + continue; + } + $modifiersString .= $key . '="' . $this->_escape($value) . '" '; + } + + if ($this->view instanceof Zend_View_Abstract) { + if ($this->view->doctype()->isHtml5() + && $type == 'charset') { + $tpl = ($this->view->doctype()->isXhtml()) + ? '' + : ''; + } elseif ($this->view->doctype()->isXhtml()) { + $tpl = ''; + } else { + $tpl = ''; + } + } else { + $tpl = ''; + } + + $meta = sprintf( + $tpl, + $type, + $this->_escape($item->$type), + $this->_escape($item->content), + $modifiersString + ); + + if (isset($item->modifiers['conditional']) + && !empty($item->modifiers['conditional']) + && is_string($item->modifiers['conditional'])) + { + $meta = ''; + } + + return $meta; + } + + /** + * Render placeholder as string + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + $this->getContainer()->ksort(); + try { + foreach ($this as $item) { + $items[] = $this->itemToString($item); + } + } catch (Zend_View_Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + return ''; + } + return $indent . implode($this->_escape($this->getSeparator()) . $indent, $items); + } + + /** + * Create data item for inserting into stack + * + * @param string $type + * @param string $typeValue + * @param string $content + * @param array $modifiers + * @return stdClass + */ + public function createData($type, $typeValue, $content, array $modifiers) + { + $data = new stdClass; + $data->type = $type; + $data->$type = $typeValue; + $data->content = $content; + $data->modifiers = $modifiers; + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadScript.php b/library/vendor/Zend/View/Helper/HeadScript.php new file mode 100644 index 000000000..6e62321e5 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadScript.php @@ -0,0 +1,500 @@ +setSeparator(PHP_EOL); + } + + /** + * Return headScript object + * + * Returns headScript helper object; optionally, allows specifying a script + * or script file to include. + * + * @param string $mode Script or file + * @param string $spec Script/url + * @param string $placement Append, prepend, or set + * @param array $attrs Array of script attributes + * @param string $type Script type and/or array of script attributes + * @return Zend_View_Helper_HeadScript + */ + public function headScript($mode = Zend_View_Helper_HeadScript::FILE, $spec = null, $placement = 'APPEND', array $attrs = array(), $type = 'text/javascript') + { + if ((null !== $spec) && is_string($spec)) { + $action = ucfirst(strtolower($mode)); + $placement = strtolower($placement); + switch ($placement) { + case 'set': + case 'prepend': + case 'append': + $action = $placement . $action; + break; + default: + $action = 'append' . $action; + break; + } + $this->$action($spec, $type, $attrs); + } + + return $this; + } + + /** + * Start capture action + * + * @param mixed $captureType + * @param string $typeOrAttrs + * @return void + */ + public function captureStart($captureType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $type = 'text/javascript', $attrs = array()) + { + if ($this->_captureLock) { + $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headScript captures'); + $e->setView($this->view); + throw $e; + } + + $this->_captureLock = true; + $this->_captureType = $captureType; + $this->_captureScriptType = $type; + $this->_captureScriptAttrs = $attrs; + ob_start(); + } + + /** + * End capture action and store + * + * @return void + */ + public function captureEnd() + { + $content = ob_get_clean(); + $type = $this->_captureScriptType; + $attrs = $this->_captureScriptAttrs; + $this->_captureScriptType = null; + $this->_captureScriptAttrs = null; + $this->_captureLock = false; + + switch ($this->_captureType) { + case Zend_View_Helper_Placeholder_Container_Abstract::SET: + case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: + case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: + $action = strtolower($this->_captureType) . 'Script'; + break; + default: + $action = 'appendScript'; + break; + } + $this->$action($content, $type, $attrs); + } + + /** + * Overload method access + * + * Allows the following method calls: + * - appendFile($src, $type = 'text/javascript', $attrs = array()) + * - offsetSetFile($index, $src, $type = 'text/javascript', $attrs = array()) + * - prependFile($src, $type = 'text/javascript', $attrs = array()) + * - setFile($src, $type = 'text/javascript', $attrs = array()) + * - appendScript($script, $type = 'text/javascript', $attrs = array()) + * - offsetSetScript($index, $src, $type = 'text/javascript', $attrs = array()) + * - prependScript($script, $type = 'text/javascript', $attrs = array()) + * - setScript($script, $type = 'text/javascript', $attrs = array()) + * + * @param string $method + * @param array $args + * @return Zend_View_Helper_HeadScript + * @throws Zend_View_Exception if too few arguments or invalid method + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(?PFile|Script)$/', $method, $matches)) { + if (1 > count($args)) { + $e = new Zend_View_Exception(sprintf('Method "%s" requires at least one argument', $method)); + $e->setView($this->view); + throw $e; + } + + $action = $matches['action']; + $mode = strtolower($matches['mode']); + $type = 'text/javascript'; + $attrs = array(); + + if ('offsetSet' == $action) { + $index = array_shift($args); + if (1 > count($args)) { + $e = new Zend_View_Exception(sprintf('Method "%s" requires at least two arguments, an index and source', $method)); + $e->setView($this->view); + throw $e; + } + } + + $content = $args[0]; + + if (isset($args[1])) { + $type = (string) $args[1]; + } + if (isset($args[2])) { + $attrs = (array) $args[2]; + } + + switch ($mode) { + case 'script': + $item = $this->createData($type, $attrs, $content); + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + break; + case 'file': + default: + if (!$this->_isDuplicate($content) || $action=='set') { + $attrs['src'] = $content; + $item = $this->createData($type, $attrs); + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + } + break; + } + + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Is the file specified a duplicate? + * + * @param string $file + * @return bool + */ + protected function _isDuplicate($file) + { + foreach ($this->getContainer() as $item) { + if (($item->source === null) + && array_key_exists('src', $item->attributes) + && ($file == $item->attributes['src'])) + { + return true; + } + } + return false; + } + + /** + * Is the script provided valid? + * + * @param mixed $value + * @param string $method + * @return bool + */ + protected function _isValid($value) + { + if ((!$value instanceof stdClass) + || !isset($value->type) + || (!isset($value->source) && !isset($value->attributes))) + { + return false; + } + + return true; + } + + /** + * Override append + * + * @param string $value + * @return void + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to append(); please use one of the helper methods, appendScript() or appendFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * Override prepend + * + * @param string $value + * @return void + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to prepend(); please use one of the helper methods, prependScript() or prependFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * Override set + * + * @param string $value + * @return void + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to set(); please use one of the helper methods, setScript() or setFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->set($value); + } + + /** + * Override offsetSet + * + * @param string|int $index + * @param mixed $value + * @return void + */ + public function offsetSet($index, $value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid argument passed to offsetSet(); please use one of the helper methods, offsetSetScript() or offsetSetFile()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->offsetSet($index, $value); + } + + /** + * Set flag indicating if arbitrary attributes are allowed + * + * @param bool $flag + * @return Zend_View_Helper_HeadScript + */ + public function setAllowArbitraryAttributes($flag) + { + $this->_arbitraryAttributes = (bool) $flag; + return $this; + } + + /** + * Are arbitrary attributes allowed? + * + * @return bool + */ + public function arbitraryAttributesAllowed() + { + return $this->_arbitraryAttributes; + } + + /** + * Create script HTML + * + * @param string $type + * @param array $attributes + * @param string $content + * @param string|int $indent + * @return string + */ + public function itemToString($item, $indent, $escapeStart, $escapeEnd) + { + $attrString = ''; + if (!empty($item->attributes)) { + foreach ($item->attributes as $key => $value) { + if ((!$this->arbitraryAttributesAllowed() && !in_array($key, $this->_optionalAttributes)) + || in_array($key, array('conditional', 'noescape'))) + { + continue; + } + if ('defer' == $key) { + $value = 'defer'; + } + $attrString .= sprintf(' %s="%s"', $key, ($this->_autoEscape) ? $this->_escape($value) : $value); + } + } + + $addScriptEscape = !(isset($item->attributes['noescape']) && filter_var($item->attributes['noescape'], FILTER_VALIDATE_BOOLEAN)); + + $type = ($this->_autoEscape) ? $this->_escape($item->type) : $item->type; + $html = ''; + + if (isset($item->attributes['conditional']) + && !empty($item->attributes['conditional']) + && is_string($item->attributes['conditional'])) + { + $html = $indent . ''; + } else { + $html = $indent . $html; + } + + return $html; + } + + /** + * Retrieve string representation + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + if ($this->view) { + $useCdata = $this->view->doctype()->isXhtml() ? true : false; + } else { + $useCdata = $this->useCdata ? true : false; + } + $escapeStart = ($useCdata) ? '//' : '//-->'; + + $items = array(); + $this->getContainer()->ksort(); + foreach ($this as $item) { + if (!$this->_isValid($item)) { + continue; + } + + $items[] = $this->itemToString($item, $indent, $escapeStart, $escapeEnd); + } + + $return = implode($this->getSeparator(), $items); + return $return; + } + + /** + * Create data item containing all necessary components of script + * + * @param string $type + * @param array $attributes + * @param string $content + * @return stdClass + */ + public function createData($type, array $attributes, $content = null) + { + $data = new stdClass(); + $data->type = $type; + $data->attributes = $attributes; + $data->source = $content; + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadStyle.php b/library/vendor/Zend/View/Helper/HeadStyle.php new file mode 100644 index 000000000..b5bed9faf --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadStyle.php @@ -0,0 +1,419 @@ +setSeparator(PHP_EOL); + } + + /** + * Return headStyle object + * + * Returns headStyle helper object; optionally, allows specifying + * + * @param string $content Stylesheet contents + * @param string $placement Append, prepend, or set + * @param string|array $attributes Optional attributes to utilize + * @return Zend_View_Helper_HeadStyle + */ + public function headStyle($content = null, $placement = 'APPEND', $attributes = array()) + { + if ((null !== $content) && is_string($content)) { + switch (strtoupper($placement)) { + case 'SET': + $action = 'setStyle'; + break; + case 'PREPEND': + $action = 'prependStyle'; + break; + case 'APPEND': + default: + $action = 'appendStyle'; + break; + } + $this->$action($content, $attributes); + } + + return $this; + } + + /** + * Overload method calls + * + * Allows the following method calls: + * - appendStyle($content, $attributes = array()) + * - offsetSetStyle($index, $content, $attributes = array()) + * - prependStyle($content, $attributes = array()) + * - setStyle($content, $attributes = array()) + * + * @param string $method + * @param array $args + * @return void + * @throws Zend_View_Exception When no $content provided or invalid method + */ + public function __call($method, $args) + { + if (preg_match('/^(?Pset|(ap|pre)pend|offsetSet)(Style)$/', $method, $matches)) { + $index = null; + $argc = count($args); + $action = $matches['action']; + + if ('offsetSet' == $action) { + if (0 < $argc) { + $index = array_shift($args); + --$argc; + } + } + + if (1 > $argc) { + $e = new Zend_View_Exception(sprintf('Method "%s" requires minimally content for the stylesheet', $method)); + $e->setView($this->view); + throw $e; + } + + $content = $args[0]; + $attrs = array(); + if (isset($args[1])) { + $attrs = (array) $args[1]; + } + + $item = $this->createData($content, $attrs); + + if ('offsetSet' == $action) { + $this->offsetSet($index, $item); + } else { + $this->$action($item); + } + + return $this; + } + + return parent::__call($method, $args); + } + + /** + * Determine if a value is a valid style tag + * + * @param mixed $value + * @param string $method + * @return boolean + */ + protected function _isValid($value) + { + if ((!$value instanceof stdClass) + || !isset($value->content) + || !isset($value->attributes)) + { + return false; + } + + return true; + } + + /** + * Override append to enforce style creation + * + * @param mixed $value + * @return void + */ + public function append($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to append; please use appendStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->append($value); + } + + /** + * Override offsetSet to enforce style creation + * + * @param string|int $index + * @param mixed $value + * @return void + */ + public function offsetSet($index, $value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->offsetSet($index, $value); + } + + /** + * Override prepend to enforce style creation + * + * @param mixed $value + * @return void + */ + public function prepend($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->prepend($value); + } + + /** + * Override set to enforce style creation + * + * @param mixed $value + * @return void + */ + public function set($value) + { + if (!$this->_isValid($value)) { + $e = new Zend_View_Exception('Invalid value passed to set; please use setStyle()'); + $e->setView($this->view); + throw $e; + } + + return $this->getContainer()->set($value); + } + + /** + * Start capture action + * + * @param mixed $captureType + * @param string $typeOrAttrs + * @return void + */ + public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $attrs = null) + { + if ($this->_captureLock) { + $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headStyle captures'); + $e->setView($this->view); + throw $e; + } + + $this->_captureLock = true; + $this->_captureAttrs = $attrs; + $this->_captureType = $type; + ob_start(); + } + + /** + * End capture action and store + * + * @return void + */ + public function captureEnd() + { + $content = ob_get_clean(); + $attrs = $this->_captureAttrs; + $this->_captureAttrs = null; + $this->_captureLock = false; + + switch ($this->_captureType) { + case Zend_View_Helper_Placeholder_Container_Abstract::SET: + $this->setStyle($content, $attrs); + break; + case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: + $this->prependStyle($content, $attrs); + break; + case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: + default: + $this->appendStyle($content, $attrs); + break; + } + } + + /** + * Convert content and attributes into valid style tag + * + * @param stdClass $item Item to render + * @param string $indent Indentation to use + * @return string + */ + public function itemToString(stdClass $item, $indent) + { + $attrString = ''; + if (!empty($item->attributes)) { + $enc = 'UTF-8'; + if ($this->view instanceof Zend_View_Interface + && method_exists($this->view, 'getEncoding') + ) { + $enc = $this->view->getEncoding(); + } + foreach ($item->attributes as $key => $value) { + if (!in_array($key, $this->_optionalAttributes)) { + continue; + } + if ('media' == $key) { + if(false === strpos($value, ',')) { + if (!in_array($value, $this->_mediaTypes)) { + continue; + } + } else { + $media_types = explode(',', $value); + $value = ''; + foreach($media_types as $type) { + $type = trim($type); + if (!in_array($type, $this->_mediaTypes)) { + continue; + } + $value .= $type .','; + } + $value = substr($value, 0, -1); + } + } + $attrString .= sprintf(' %s="%s"', $key, htmlspecialchars($value, ENT_COMPAT, $enc)); + } + } + + $escapeStart = $indent . ''. PHP_EOL; + if (isset($item->attributes['conditional']) + && !empty($item->attributes['conditional']) + && is_string($item->attributes['conditional']) + ) { + $escapeStart = null; + $escapeEnd = null; + } + + $html = ''; + + if (null == $escapeStart && null == $escapeEnd) { + $html = ''; + } + + return $html; + } + + /** + * Create string representation of placeholder + * + * @param string|int $indent + * @return string + */ + public function toString($indent = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + $this->getContainer()->ksort(); + foreach ($this as $item) { + if (!$this->_isValid($item)) { + continue; + } + $items[] = $this->itemToString($item, $indent); + } + + $return = $indent . implode($this->getSeparator() . $indent, $items); + $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); + return $return; + } + + /** + * Create data item for use in stack + * + * @param string $content + * @param array $attributes + * @return stdClass + */ + public function createData($content, array $attributes) + { + if (!isset($attributes['media'])) { + $attributes['media'] = 'screen'; + } else if(is_array($attributes['media'])) { + $attributes['media'] = implode(',', $attributes['media']); + } + + $data = new stdClass(); + $data->content = $content; + $data->attributes = $attributes; + + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/HeadTitle.php b/library/vendor/Zend/View/Helper/HeadTitle.php new file mode 100644 index 000000000..7796e13d7 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HeadTitle.php @@ -0,0 +1,218 @@ +getDefaultAttachOrder()) + ? Zend_View_Helper_Placeholder_Container_Abstract::APPEND + : $this->getDefaultAttachOrder(); + } + $title = (string) $title; + if ($title !== '') { + if ($setType == Zend_View_Helper_Placeholder_Container_Abstract::SET) { + $this->set($title); + } elseif ($setType == Zend_View_Helper_Placeholder_Container_Abstract::PREPEND) { + $this->prepend($title); + } else { + $this->append($title); + } + } + + return $this; + } + + /** + * Set a default order to add titles + * + * @param string $setType + */ + public function setDefaultAttachOrder($setType) + { + if (!in_array($setType, array( + Zend_View_Helper_Placeholder_Container_Abstract::APPEND, + Zend_View_Helper_Placeholder_Container_Abstract::SET, + Zend_View_Helper_Placeholder_Container_Abstract::PREPEND + ))) { + throw new Zend_View_Exception("You must use a valid attach order: 'PREPEND', 'APPEND' or 'SET'"); + } + + $this->_defaultAttachOrder = $setType; + return $this; + } + + /** + * Get the default attach order, if any. + * + * @return mixed + */ + public function getDefaultAttachOrder() + { + return $this->_defaultAttachOrder; + } + + /** + * Sets a translation Adapter for translation + * + * @param Zend_Translate|Zend_Translate_Adapter $translate + * @return Zend_View_Helper_HeadTitle + */ + public function setTranslator($translate) + { + if ($translate instanceof Zend_Translate_Adapter) { + $this->_translator = $translate; + } elseif ($translate instanceof Zend_Translate) { + $this->_translator = $translate->getAdapter(); + } else { + $e = new Zend_View_Exception("You must set an instance of Zend_Translate or Zend_Translate_Adapter"); + $e->setView($this->view); + throw $e; + } + return $this; + } + + /** + * Retrieve translation object + * + * If none is currently registered, attempts to pull it from the registry + * using the key 'Zend_Translate'. + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if (null === $this->_translator) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $this->setTranslator(Zend_Registry::get('Zend_Translate')); + } + } + return $this->_translator; + } + + /** + * Enables translation + * + * @return Zend_View_Helper_HeadTitle + */ + public function enableTranslation() + { + $this->_translate = true; + return $this; + } + + /** + * Disables translation + * + * @return Zend_View_Helper_HeadTitle + */ + public function disableTranslation() + { + $this->_translate = false; + return $this; + } + + /** + * Turn helper into string + * + * @param string|null $indent + * @param string|null $locale + * @return string + */ + public function toString($indent = null, $locale = null) + { + $indent = (null !== $indent) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = array(); + + if($this->_translate && $translator = $this->getTranslator()) { + foreach ($this as $item) { + $items[] = $translator->translate($item, $locale); + } + } else { + foreach ($this as $item) { + $items[] = $item; + } + } + + $separator = $this->getSeparator(); + $output = ''; + if(($prefix = $this->getPrefix())) { + $output .= $prefix; + } + $output .= implode($separator, $items); + if(($postfix = $this->getPostfix())) { + $output .= $postfix; + } + + $output = ($this->_autoEscape) ? $this->_escape($output) : $output; + + return $indent . '' . $output . ''; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlElement.php b/library/vendor/Zend/View/Helper/HtmlElement.php new file mode 100644 index 000000000..91a92d1bc --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlElement.php @@ -0,0 +1,165 @@ +_closingBracket) { + if ($this->_isXhtml()) { + $this->_closingBracket = ' />'; + } else { + $this->_closingBracket = '>'; + } + } + + return $this->_closingBracket; + } + + /** + * Is doctype XHTML? + * + * @return boolean + */ + protected function _isXhtml() + { + $doctype = $this->view->doctype(); + return $doctype->isXhtml(); + } + + /** + * Is doctype HTML5? + * + * @return boolean + */ + protected function _isHtml5() + { + $doctype = $this->view->doctype(); + return $doctype->isHtml5(); + } + + /** + * Is doctype strict? + * + * @return boolean + */ + protected function _isStrictDoctype() + { + $doctype = $this->view->doctype(); + return $doctype->isStrict(); + } + + /** + * Converts an associative array to a string of tag attributes. + * + * @access public + * + * @param array $attribs From this array, each key-value pair is + * converted to an attribute name and value. + * + * @return string The XHTML for the attributes. + */ + protected function _htmlAttribs($attribs) + { + $xhtml = ''; + foreach ((array) $attribs as $key => $val) { + $key = $this->view->escape($key); + + if (('on' == substr($key, 0, 2)) || ('constraints' == $key)) { + // Don't escape event attributes; _do_ substitute double quotes with singles + if (!is_scalar($val)) { + // non-scalar data should be cast to JSON first + $val = Zend_Json::encode($val); + } + // Escape single quotes inside event attribute values. + // This will create html, where the attribute value has + // single quotes around it, and escaped single quotes or + // non-escaped double quotes inside of it + $val = str_replace('\'', ''', $val); + } else { + if (is_array($val)) { + $val = implode(' ', $val); + } + $val = $this->view->escape($val); + } + + if ('id' == $key) { + $val = $this->_normalizeId($val); + } + + if (strpos($val, '"') !== false) { + $xhtml .= " $key='$val'"; + } else { + $xhtml .= " $key=\"$val\""; + } + + } + return $xhtml; + } + + /** + * Normalize an ID + * + * @param string $value + * @return string + */ + protected function _normalizeId($value) + { + if (strstr($value, '[')) { + if ('[]' == substr($value, -2)) { + $value = substr($value, 0, strlen($value) - 2); + } + $value = trim($value, ']'); + $value = str_replace('][', '-', $value); + $value = str_replace('[', '-', $value); + } + return $value; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlFlash.php b/library/vendor/Zend/View/Helper/HtmlFlash.php new file mode 100644 index 000000000..1f40d3f7d --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlFlash.php @@ -0,0 +1,59 @@ + $data, + 'quality' => 'high'), $params); + + return $this->htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlList.php b/library/vendor/Zend/View/Helper/HtmlList.php new file mode 100644 index 000000000..255347744 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlList.php @@ -0,0 +1,88 @@ +setView($this->view); + throw $e; + } + + $list = ''; + + foreach ($items as $item) { + if (!is_array($item)) { + if ($escape) { + $item = $this->view->escape($item); + } + $list .= '
            • ' . $item . '
            • ' . self::EOL; + } else { + if (6 < strlen($list)) { + $list = substr($list, 0, strlen($list) - 6) + . $this->htmlList($item, $ordered, $attribs, $escape) . '' . self::EOL; + } else { + $list .= '
            • ' . $this->htmlList($item, $ordered, $attribs, $escape) . '
            • ' . self::EOL; + } + } + } + + if ($attribs) { + $attribs = $this->_htmlAttribs($attribs); + } else { + $attribs = ''; + } + + $tag = 'ul'; + if ($ordered) { + $tag = 'ol'; + } + + return '<' . $tag . $attribs . '>' . self::EOL . $list . '' . self::EOL; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlObject.php b/library/vendor/Zend/View/Helper/HtmlObject.php new file mode 100644 index 000000000..95091b36b --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlObject.php @@ -0,0 +1,79 @@ + $data, + 'type' => $type), $attribs); + + // Params + $paramHtml = array(); + $closingBracket = $this->getClosingBracket(); + + foreach ($params as $param => $options) { + if (is_string($options)) { + $options = array('value' => $options); + } + + $options = array_merge(array('name' => $param), $options); + + $paramHtml[] = '_htmlAttribs($options) . $closingBracket; + } + + // Content + if (is_array($content)) { + $content = implode(self::EOL, $content); + } + + // Object header + $xhtml = '_htmlAttribs($attribs) . '>' . self::EOL + . implode(self::EOL, $paramHtml) . self::EOL + . ($content ? $content . self::EOL : '') + . ''; + + return $xhtml; + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlPage.php b/library/vendor/Zend/View/Helper/HtmlPage.php new file mode 100644 index 000000000..9a1c5a754 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlPage.php @@ -0,0 +1,74 @@ + self::ATTRIB_CLASSID); + + /** + * Output a html object tag + * + * @param string $data The html url + * @param array $attribs Attribs for the object tag + * @param array $params Params for in the object tag + * @param string $content Alternative content + * @return string + */ + public function htmlPage($data, array $attribs = array(), array $params = array(), $content = null) + { + // Attrs + $attribs = array_merge($this->_attribs, $attribs); + + // Params + $params = array_merge(array('data' => $data), $params); + + return $this->htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/vendor/Zend/View/Helper/HtmlQuicktime.php b/library/vendor/Zend/View/Helper/HtmlQuicktime.php new file mode 100644 index 000000000..479493355 --- /dev/null +++ b/library/vendor/Zend/View/Helper/HtmlQuicktime.php @@ -0,0 +1,81 @@ + self::ATTRIB_CLASSID, + 'codebase' => self::ATTRIB_CODEBASE); + + /** + * Output a quicktime movie object tag + * + * @param string $data The quicktime file + * @param array $attribs Attribs for the object tag + * @param array $params Params for in the object tag + * @param string $content Alternative content + * @return string + */ + public function htmlQuicktime($data, array $attribs = array(), array $params = array(), $content = null) + { + // Attrs + $attribs = array_merge($this->_attribs, $attribs); + + // Params + $params = array_merge(array('src' => $data), $params); + + return $this->htmlObject($data, self::TYPE, $attribs, $params, $content); + } +} diff --git a/library/vendor/Zend/View/Helper/InlineScript.php b/library/vendor/Zend/View/Helper/InlineScript.php new file mode 100644 index 000000000..52b29d6f1 --- /dev/null +++ b/library/vendor/Zend/View/Helper/InlineScript.php @@ -0,0 +1,60 @@ +headScript($mode, $spec, $placement, $attrs, $type); + } +} diff --git a/library/vendor/Zend/View/Helper/Interface.php b/library/vendor/Zend/View/Helper/Interface.php new file mode 100644 index 000000000..7f61df96a --- /dev/null +++ b/library/vendor/Zend/View/Helper/Interface.php @@ -0,0 +1,46 @@ +true|false + * this array can contains a 'keepLayout'=>true|false and/or 'encodeData'=>true|false + * that will not be passed to Zend_Json::encode method but will be used here + * @param bool $encodeData + * @return string|void + */ + public function json($data, $keepLayouts = false, $encodeData = true) + { + $options = array(); + if (is_array($keepLayouts)) { + $options = $keepLayouts; + + $keepLayouts = false; + if (array_key_exists('keepLayouts', $options)) { + $keepLayouts = $options['keepLayouts']; + unset($options['keepLayouts']); + } + + if (array_key_exists('encodeData', $options)) { + $encodeData = $options['encodeData']; + unset($options['encodeData']); + } + } + + if ($encodeData) { + $data = Zend_Json::encode($data, null, $options); + } + if (!$keepLayouts) { + $layout = Zend_Layout::getMvcInstance(); + if ($layout instanceof Zend_Layout) { + $layout->disableLayout(); + } + } + + $response = Zend_Controller_Front::getInstance()->getResponse(); + $response->setHeader('Content-Type', 'application/json', true); + return $data; + } +} diff --git a/library/vendor/Zend/View/Helper/Layout.php b/library/vendor/Zend/View/Helper/Layout.php new file mode 100644 index 000000000..cb229ff72 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Layout.php @@ -0,0 +1,79 @@ +_layout) { + $this->_layout = Zend_Layout::getMvcInstance(); + if (null === $this->_layout) { + // Implicitly creates layout object + $this->_layout = new Zend_Layout(); + } + } + + return $this->_layout; + } + + /** + * Set layout object + * + * @param Zend_Layout $layout + * @return Zend_Layout_Controller_Action_Helper_Layout + */ + public function setLayout(Zend_Layout $layout) + { + $this->_layout = $layout; + return $this; + } + + /** + * Return layout object + * + * Usage: $this->layout()->setLayout('alternate'); + * + * @return Zend_Layout + */ + public function layout() + { + return $this->getLayout(); + } +} diff --git a/library/vendor/Zend/View/Helper/Navigation.php b/library/vendor/Zend/View/Helper/Navigation.php new file mode 100644 index 000000000..e58a1ede6 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Navigation.php @@ -0,0 +1,344 @@ +setContainer($container); + } + + return $this; + } + + /** + * Magic overload: Proxy to other navigation helpers or the container + * + * Examples of usage from a view script or layout: + * + * // proxy to Menu helper and render container: + * echo $this->navigation()->menu(); + * + * // proxy to Breadcrumbs helper and set indentation: + * $this->navigation()->breadcrumbs()->setIndent(8); + * + * // proxy to container and find all pages with 'blog' route: + * $blogPages = $this->navigation()->findAllByRoute('blog'); + * + * + * @param string $method helper name or method name in + * container + * @param array $arguments [optional] arguments to pass + * @return mixed returns what the proxied call returns + * @throws Zend_View_Exception if proxying to a helper, and the + * helper is not an instance of the + * interface specified in + * {@link findHelper()} + * @throws Zend_Navigation_Exception if method does not exist in container + */ + public function __call($method, array $arguments = array()) + { + // check if call should proxy to another helper + if ($helper = $this->findHelper($method, false)) { + return call_user_func_array(array($helper, $method), $arguments); + } + + // default behaviour: proxy call to container + return parent::__call($method, $arguments); + } + + /** + * Returns the helper matching $proxy + * + * The helper must implement the interface + * {@link Zend_View_Helper_Navigation_Helper}. + * + * @param string $proxy helper name + * @param bool $strict [optional] whether + * exceptions should be + * thrown if something goes + * wrong. Default is true. + * @return Zend_View_Helper_Navigation_Helper helper instance + * @throws Zend_Loader_PluginLoader_Exception if $strict is true and + * helper cannot be found + * @throws Zend_View_Exception if $strict is true and + * helper does not implement + * the specified interface + */ + public function findHelper($proxy, $strict = true) + { + if (isset($this->_helpers[$proxy])) { + return $this->_helpers[$proxy]; + } + + if (!$this->view->getPluginLoader('helper')->getPaths(self::NS)) { + // Add navigation helper path at the beginning + $paths = $this->view->getHelperPaths(); + $this->view->setHelperPath(null); + + $this->view->addHelperPath( + str_replace('_', '/', self::NS), + self::NS); + + foreach ($paths as $ns => $path) { + $this->view->addHelperPath($path, $ns); + } + } + + if ($strict) { + $helper = $this->view->getHelper($proxy); + } else { + try { + $helper = $this->view->getHelper($proxy); + } catch (Zend_Loader_PluginLoader_Exception $e) { + return null; + } + } + + if (!$helper instanceof Zend_View_Helper_Navigation_Helper) { + if ($strict) { + $e = new Zend_View_Exception(sprintf( + 'Proxy helper "%s" is not an instance of ' . + 'Zend_View_Helper_Navigation_Helper', + get_class($helper))); + $e->setView($this->view); + throw $e; + } + + return null; + } + + $this->_inject($helper); + $this->_helpers[$proxy] = $helper; + + return $helper; + } + + /** + * Injects container, ACL, and translator to the given $helper if this + * helper is configured to do so + * + * @param Zend_View_Helper_Navigation_Helper $helper helper instance + * @return void + */ + protected function _inject(Zend_View_Helper_Navigation_Helper $helper) + { + if ($this->getInjectContainer() && !$helper->hasContainer()) { + $helper->setContainer($this->getContainer()); + } + + if ($this->getInjectAcl()) { + if (!$helper->hasAcl()) { + $helper->setAcl($this->getAcl()); + } + if (!$helper->hasRole()) { + $helper->setRole($this->getRole()); + } + } + + if ($this->getInjectTranslator() && !$helper->hasTranslator()) { + $helper->setTranslator($this->getTranslator()); + } + } + + // Accessors: + + /** + * Sets the default proxy to use in {@link render()} + * + * @param string $proxy default proxy + * @return Zend_View_Helper_Navigation fluent interface, returns self + */ + public function setDefaultProxy($proxy) + { + $this->_defaultProxy = (string) $proxy; + return $this; + } + + /** + * Returns the default proxy to use in {@link render()} + * + * @return string the default proxy to use in {@link render()} + */ + public function getDefaultProxy() + { + return $this->_defaultProxy; + } + + /** + * Sets whether container should be injected when proxying + * + * @param bool $injectContainer [optional] whether container should + * be injected when proxying. Default + * is true. + * @return Zend_View_Helper_Navigation fluent interface, returns self + */ + public function setInjectContainer($injectContainer = true) + { + $this->_injectContainer = (bool) $injectContainer; + return $this; + } + + /** + * Returns whether container should be injected when proxying + * + * @return bool whether container should be injected when proxying + */ + public function getInjectContainer() + { + return $this->_injectContainer; + } + + /** + * Sets whether ACL should be injected when proxying + * + * @param bool $injectAcl [optional] whether ACL should be + * injected when proxying. Default is + * true. + * @return Zend_View_Helper_Navigation fluent interface, returns self + */ + public function setInjectAcl($injectAcl = true) + { + $this->_injectAcl = (bool) $injectAcl; + return $this; + } + + /** + * Returns whether ACL should be injected when proxying + * + * @return bool whether ACL should be injected when proxying + */ + public function getInjectAcl() + { + return $this->_injectAcl; + } + + /** + * Sets whether translator should be injected when proxying + * + * @param bool $injectTranslator [optional] whether translator should + * be injected when proxying. Default + * is true. + * @return Zend_View_Helper_Navigation fluent interface, returns self + */ + public function setInjectTranslator($injectTranslator = true) + { + $this->_injectTranslator = (bool) $injectTranslator; + return $this; + } + + /** + * Returns whether translator should be injected when proxying + * + * @return bool whether translator should be injected when proxying + */ + public function getInjectTranslator() + { + return $this->_injectTranslator; + } + + // Zend_View_Helper_Navigation_Helper: + + /** + * Renders helper + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + * @throws Zend_Loader_PluginLoader_Exception if helper cannot be found + * @throws Zend_View_Exception if helper doesn't implement + * the interface specified in + * {@link findHelper()} + */ + public function render(Zend_Navigation_Container $container = null) + { + $helper = $this->findHelper($this->getDefaultProxy()); + return $helper->render($container); + } +} diff --git a/library/vendor/Zend/View/Helper/Navigation/Breadcrumbs.php b/library/vendor/Zend/View/Helper/Navigation/Breadcrumbs.php new file mode 100644 index 000000000..9c81b420c --- /dev/null +++ b/library/vendor/Zend/View/Helper/Navigation/Breadcrumbs.php @@ -0,0 +1,328 @@ +setContainer($container); + } + + return $this; + } + + // Accessors: + + /** + * Sets breadcrumb separator + * + * @param string $separator separator string + * @return Zend_View_Helper_Navigation_Breadcrumbs fluent interface, + * returns self + */ + public function setSeparator($separator) + { + if (is_string($separator)) { + $this->_separator = $separator; + } + + return $this; + } + + /** + * Returns breadcrumb separator + * + * @return string breadcrumb separator + */ + public function getSeparator() + { + return $this->_separator; + } + + /** + * Sets whether last page in breadcrumbs should be hyperlinked + * + * @param bool $linkLast whether last page should + * be hyperlinked + * @return Zend_View_Helper_Navigation_Breadcrumbs fluent interface, + * returns self + */ + public function setLinkLast($linkLast) + { + $this->_linkLast = (bool) $linkLast; + return $this; + } + + /** + * Returns whether last page in breadcrumbs should be hyperlinked + * + * @return bool whether last page in breadcrumbs should be hyperlinked + */ + public function getLinkLast() + { + return $this->_linkLast; + } + + /** + * Sets which partial view script to use for rendering menu + * + * @param string|array $partial partial view script or + * null. If an array is + * given, it is expected to + * contain two values; + * the partial view script + * to use, and the module + * where the script can be + * found. + * @return Zend_View_Helper_Navigation_Breadcrumbs fluent interface, + * returns self + */ + public function setPartial($partial) + { + if (null === $partial || is_string($partial) || is_array($partial)) { + $this->_partial = $partial; + } + + return $this; + } + + /** + * Returns partial view script to use for rendering menu + * + * @return string|array|null + */ + public function getPartial() + { + return $this->_partial; + } + + // Render methods: + + /** + * Renders breadcrumbs by chaining 'a' elements with the separator + * registered in the helper + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + */ + public function renderStraight(Zend_Navigation_Container $container = null) + { + if (null === $container) { + $container = $this->getContainer(); + } + + // find deepest active + if (!$active = $this->findActive($container)) { + return ''; + } + + $active = $active['page']; + + // put the deepest active page last in breadcrumbs + if ($this->getLinkLast()) { + $html = $this->htmlify($active); + } else { + $html = $active->getLabel(); + if ($this->getUseTranslator() && $t = $this->getTranslator()) { + $html = $t->translate($html); + } + $html = $this->view->escape($html); + } + + // walk back to root + while ($parent = $active->getParent()) { + if ($parent instanceof Zend_Navigation_Page) { + // prepend crumb to html + $html = $this->htmlify($parent) + . $this->getSeparator() + . $html; + } + + if ($parent === $container) { + // at the root of the given container + break; + } + + $active = $parent; + } + + return strlen($html) ? $this->getIndent() . $html : ''; + } + + /** + * Renders the given $container by invoking the partial view helper + * + * The container will simply be passed on as a model to the view script, + * so in the script it will be available in $this->container. + * + * @param Zend_Navigation_Container $container [optional] container to + * pass to view script. + * Default is to use the + * container registered in the + * helper. + * @param string|array $partial [optional] partial view + * script to use. Default is + * to use the partial + * registered in the helper. + * If an array is given, it is + * expected to contain two + * values; the partial view + * script to use, and the + * module where the script can + * be found. + * @return string helper output + */ + public function renderPartial(Zend_Navigation_Container $container = null, + $partial = null) + { + if (null === $container) { + $container = $this->getContainer(); + } + + if (null === $partial) { + $partial = $this->getPartial(); + } + + if (empty($partial)) { + $e = new Zend_View_Exception( + 'Unable to render menu: No partial view script provided' + ); + $e->setView($this->view); + throw $e; + } + + // put breadcrumb pages in model + $model = array('pages' => array()); + if ($active = $this->findActive($container)) { + $active = $active['page']; + $model['pages'][] = $active; + while ($parent = $active->getParent()) { + if ($parent instanceof Zend_Navigation_Page) { + $model['pages'][] = $parent; + } else { + break; + } + + if ($parent === $container) { + // break if at the root of the given container + break; + } + + $active = $parent; + } + $model['pages'] = array_reverse($model['pages']); + } + + if (is_array($partial)) { + if (count($partial) != 2) { + $e = new Zend_View_Exception( + 'Unable to render menu: A view partial supplied as ' + . 'an array must contain two values: partial view ' + . 'script and module where script can be found' + ); + $e->setView($this->view); + throw $e; + } + + return $this->view->partial($partial[0], $partial[1], $model); + } + + return $this->view->partial($partial, null, $model); + } + + // Zend_View_Helper_Navigation_Helper: + + /** + * Renders helper + * + * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + */ + public function render(Zend_Navigation_Container $container = null) + { + if ($partial = $this->getPartial()) { + return $this->renderPartial($container, $partial); + } else { + return $this->renderStraight($container); + } + } +} diff --git a/library/vendor/Zend/View/Helper/Navigation/Helper.php b/library/vendor/Zend/View/Helper/Navigation/Helper.php new file mode 100644 index 000000000..2bb160727 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Navigation/Helper.php @@ -0,0 +1,212 @@ +_container = $container; + return $this; + } + + /** + * Returns the navigation container helper operates on by default + * + * Implements {@link Zend_View_Helper_Navigation_Interface::getContainer()}. + * + * If a helper is not explicitly set in this helper instance by calling + * {@link setContainer()} or by passing it through the helper entry point, + * this method will look in {@link Zend_Registry} for a container by using + * the key 'Zend_Navigation'. + * + * If no container is set, and nothing is found in Zend_Registry, a new + * container will be instantiated and stored in the helper. + * + * @return Zend_Navigation_Container navigation container + */ + public function getContainer() + { + if (null === $this->_container) { + // try to fetch from registry first + if (Zend_Registry::isRegistered('Zend_Navigation')) { + $nav = Zend_Registry::get('Zend_Navigation'); + if ($nav instanceof Zend_Navigation_Container) { + return $this->_container = $nav; + } + } + + // nothing found in registry, create new container + $this->_container = new Zend_Navigation(); + } + + return $this->_container; + } + + /** + * Sets the minimum depth a page must have to be included when rendering + * + * @param int $minDepth [optional] minimum + * depth. Default is + * null, which sets + * no minimum depth. + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setMinDepth($minDepth = null) + { + if (null === $minDepth || is_int($minDepth)) { + $this->_minDepth = $minDepth; + } else { + $this->_minDepth = (int) $minDepth; + } + return $this; + } + + /** + * Returns minimum depth a page must have to be included when rendering + * + * @return int|null minimum depth or null + */ + public function getMinDepth() + { + if (!is_int($this->_minDepth) || $this->_minDepth < 0) { + return 0; + } + return $this->_minDepth; + } + + /** + * Sets the maximum depth a page can have to be included when rendering + * + * @param int $maxDepth [optional] maximum + * depth. Default is + * null, which sets no + * maximum depth. + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setMaxDepth($maxDepth = null) + { + if (null === $maxDepth || is_int($maxDepth)) { + $this->_maxDepth = $maxDepth; + } else { + $this->_maxDepth = (int) $maxDepth; + } + return $this; + } + + /** + * Returns maximum depth a page can have to be included when rendering + * + * @return int|null maximum depth or null + */ + public function getMaxDepth() + { + return $this->_maxDepth; + } + + /** + * Set the indentation string for using in {@link render()}, optionally a + * number of spaces to indent with + * + * @param string|int $indent indentation string or + * number of spaces + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setIndent($indent) + { + $this->_indent = $this->_getWhitespace($indent); + return $this; + } + + /** + * Returns indentation (format output is respected) + * + * @return string indentation string or an empty string + */ + public function getIndent() + { + if (false === $this->getFormatOutput()) { + return ''; + } + + return $this->_indent; + } + + /** + * Returns the EOL character (format output is respected) + * + * @see self::EOL + * @see getFormatOutput() + * + * @return string standard EOL charater or an empty string + */ + public function getEOL() + { + if (false === $this->getFormatOutput()) { + return ''; + } + + return self::EOL; + } + + /** + * Sets whether HTML/XML output should be formatted + * + * @param bool $formatOutput [optional] whether output + * should be formatted. Default + * is true. + * + * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns + * self + */ + public function setFormatOutput($formatOutput = true) + { + $this->_formatOutput = (bool)$formatOutput; + + return $this; + } + + /** + * Returns whether HTML/XML output should be formatted + * + * @return bool whether HTML/XML output should be formatted + */ + public function getFormatOutput() + { + return $this->_formatOutput; + } + + /** + * Sets prefix for IDs when they are normalized + * + * @param string $prefix Prefix for IDs + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, returns self + */ + public function setPrefixForId($prefix) + { + if (is_string($prefix)) { + $this->_prefixForId = trim($prefix); + } + + return $this; + } + + /** + * Returns prefix for IDs when they are normalized + * + * @return string Prefix for + */ + public function getPrefixForId() + { + if (null === $this->_prefixForId) { + $prefix = get_class($this); + $this->_prefixForId = strtolower( + trim(substr($prefix, strrpos($prefix, '_')), '_') + ) . '-'; + } + + return $this->_prefixForId; + } + + /** + * Skip the current prefix for IDs when they are normalized + * + * @param bool $flag + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, returns self + */ + public function skipPrefixForId($flag = true) + { + $this->_skipPrefixForId = (bool) $flag; + return $this; + } + + /** + * Sets translator to use in helper + * + * Implements {@link Zend_View_Helper_Navigation_Helper::setTranslator()}. + * + * @param mixed $translator [optional] translator. + * Expects an object of + * type + * {@link Zend_Translate_Adapter} + * or {@link Zend_Translate}, + * or null. Default is + * null, which sets no + * translator. + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setTranslator($translator = null) + { + if (null == $translator || + $translator instanceof Zend_Translate_Adapter) { + $this->_translator = $translator; + } elseif ($translator instanceof Zend_Translate) { + $this->_translator = $translator->getAdapter(); + } + + return $this; + } + + /** + * Returns translator used in helper + * + * Implements {@link Zend_View_Helper_Navigation_Helper::getTranslator()}. + * + * @return Zend_Translate_Adapter|null translator or null + */ + public function getTranslator() + { + if (null === $this->_translator) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $this->setTranslator(Zend_Registry::get('Zend_Translate')); + } + } + + return $this->_translator; + } + + /** + * Sets ACL to use when iterating pages + * + * Implements {@link Zend_View_Helper_Navigation_Helper::setAcl()}. + * + * @param Zend_Acl $acl [optional] ACL object. + * Default is null. + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setAcl(Zend_Acl $acl = null) + { + $this->_acl = $acl; + return $this; + } + + /** + * Returns ACL or null if it isn't set using {@link setAcl()} or + * {@link setDefaultAcl()} + * + * Implements {@link Zend_View_Helper_Navigation_Helper::getAcl()}. + * + * @return Zend_Acl|null ACL object or null + */ + public function getAcl() + { + if ($this->_acl === null && self::$_defaultAcl !== null) { + return self::$_defaultAcl; + } + + return $this->_acl; + } + + /** + * Sets ACL role(s) to use when iterating pages + * + * Implements {@link Zend_View_Helper_Navigation_Helper::setRole()}. + * + * @param mixed $role [optional] role to + * set. Expects a string, + * an instance of type + * {@link Zend_Acl_Role_Interface}, + * or null. Default is + * null, which will set + * no role. + * @throws Zend_View_Exception if $role is invalid + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setRole($role = null) + { + if (null === $role || is_string($role) || + $role instanceof Zend_Acl_Role_Interface) { + $this->_role = $role; + } else { + $e = new Zend_View_Exception(sprintf( + '$role must be a string, null, or an instance of ' + . 'Zend_Acl_Role_Interface; %s given', + gettype($role) + )); + $e->setView($this->view); + throw $e; + } + + return $this; + } + + /** + * Returns ACL role to use when iterating pages, or null if it isn't set + * using {@link setRole()} or {@link setDefaultRole()} + * + * Implements {@link Zend_View_Helper_Navigation_Helper::getRole()}. + * + * @return string|Zend_Acl_Role_Interface|null role or null + */ + public function getRole() + { + if ($this->_role === null && self::$_defaultRole !== null) { + return self::$_defaultRole; + } + + return $this->_role; + } + + /** + * Sets whether ACL should be used + * + * Implements {@link Zend_View_Helper_Navigation_Helper::setUseAcl()}. + * + * @param bool $useAcl [optional] whether ACL + * should be used. + * Default is true. + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setUseAcl($useAcl = true) + { + $this->_useAcl = (bool) $useAcl; + return $this; + } + + /** + * Returns whether ACL should be used + * + * Implements {@link Zend_View_Helper_Navigation_Helper::getUseAcl()}. + * + * @return bool whether ACL should be used + */ + public function getUseAcl() + { + return $this->_useAcl; + } + + /** + * Return renderInvisible flag + * + * @return bool + */ + public function getRenderInvisible() + { + return $this->_renderInvisible; + } + + /** + * Render invisible items? + * + * @param bool $renderInvisible [optional] boolean flag + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface + * returns self + */ + public function setRenderInvisible($renderInvisible = true) + { + $this->_renderInvisible = (bool) $renderInvisible; + return $this; + } + + /** + * Sets whether translator should be used + * + * Implements {@link Zend_View_Helper_Navigation_Helper::setUseTranslator()}. + * + * @param bool $useTranslator [optional] whether + * translator should be + * used. Default is true. + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setUseTranslator($useTranslator = true) + { + $this->_useTranslator = (bool) $useTranslator; + return $this; + } + + /** + * Returns whether translator should be used + * + * Implements {@link Zend_View_Helper_Navigation_Helper::getUseTranslator()}. + * + * @return bool whether translator should be used + */ + public function getUseTranslator() + { + return $this->_useTranslator; + } + + // Magic overloads: + + /** + * Magic overload: Proxy calls to the navigation container + * + * @param string $method method name in container + * @param array $arguments [optional] arguments to pass + * @return mixed returns what the container returns + * @throws Zend_Navigation_Exception if method does not exist in container + */ + public function __call($method, array $arguments = array()) + { + return call_user_func_array( + array($this->getContainer(), $method), + $arguments); + } + + /** + * Magic overload: Proxy to {@link render()}. + * + * This method will trigger an E_USER_ERROR if rendering the helper causes + * an exception to be thrown. + * + * Implements {@link Zend_View_Helper_Navigation_Helper::__toString()}. + * + * @return string + */ + public function __toString() + { + try { + return $this->render(); + } catch (Exception $e) { + $msg = get_class($e) . ': ' . $e->getMessage(); + trigger_error($msg, E_USER_ERROR); + return ''; + } + } + + // Public methods: + + /** + * Finds the deepest active page in the given container + * + * @param Zend_Navigation_Container $container container to search + * @param int|null $minDepth [optional] minimum depth + * required for page to be + * valid. Default is to use + * {@link getMinDepth()}. A + * null value means no minimum + * depth required. + * @param int|null $minDepth [optional] maximum depth + * a page can have to be + * valid. Default is to use + * {@link getMaxDepth()}. A + * null value means no maximum + * depth required. + * @return array an associative array with + * the values 'depth' and + * 'page', or an empty array + * if not found + */ + public function findActive(Zend_Navigation_Container $container, + $minDepth = null, + $maxDepth = -1) + { + if (!is_int($minDepth)) { + $minDepth = $this->getMinDepth(); + } + if ((!is_int($maxDepth) || $maxDepth < 0) && null !== $maxDepth) { + $maxDepth = $this->getMaxDepth(); + } + + $found = null; + $foundDepth = -1; + $iterator = new RecursiveIteratorIterator($container, + RecursiveIteratorIterator::CHILD_FIRST); + + foreach ($iterator as $page) { + $currDepth = $iterator->getDepth(); + if ($currDepth < $minDepth || !$this->accept($page)) { + // page is not accepted + continue; + } + + if ($page->isActive(false) && $currDepth > $foundDepth) { + // found an active page at a deeper level than before + $found = $page; + $foundDepth = $currDepth; + } + } + + if (is_int($maxDepth) && $foundDepth > $maxDepth) { + while ($foundDepth > $maxDepth) { + if (--$foundDepth < $minDepth) { + $found = null; + break; + } + + $found = $found->getParent(); + if (!$found instanceof Zend_Navigation_Page) { + $found = null; + break; + } + } + } + + if ($found) { + return array('page' => $found, 'depth' => $foundDepth); + } else { + return array(); + } + } + + /** + * Checks if the helper has a container + * + * Implements {@link Zend_View_Helper_Navigation_Helper::hasContainer()}. + * + * @return bool whether the helper has a container or not + */ + public function hasContainer() + { + return null !== $this->_container; + } + + /** + * Checks if the helper has an ACL instance + * + * Implements {@link Zend_View_Helper_Navigation_Helper::hasAcl()}. + * + * @return bool whether the helper has a an ACL instance or not + */ + public function hasAcl() + { + return null !== $this->_acl; + } + + /** + * Checks if the helper has an ACL role + * + * Implements {@link Zend_View_Helper_Navigation_Helper::hasRole()}. + * + * @return bool whether the helper has a an ACL role or not + */ + public function hasRole() + { + return null !== $this->_role; + } + + /** + * Checks if the helper has a translator + * + * Implements {@link Zend_View_Helper_Navigation_Helper::hasTranslator()}. + * + * @return bool whether the helper has a translator or not + */ + public function hasTranslator() + { + return null !== $this->_translator; + } + + /** + * Returns an HTML string containing an 'a' element for the given page + * + * @param Zend_Navigation_Page $page page to generate HTML for + * @return string HTML string for the given page + */ + public function htmlify(Zend_Navigation_Page $page) + { + // get label and title for translating + $label = $page->getLabel(); + $title = $page->getTitle(); + + if ($this->getUseTranslator() && $t = $this->getTranslator()) { + if (is_string($label) && !empty($label)) { + $label = $t->translate($label); + } + if (is_string($title) && !empty($title)) { + $title = $t->translate($title); + } + } + + // get attribs for anchor element + $attribs = array_merge( + array( + 'id' => $page->getId(), + 'title' => $title, + 'class' => $page->getClass(), + 'href' => $page->getHref(), + 'target' => $page->getTarget() + ), + $page->getCustomHtmlAttribs() + ); + + return '_htmlAttribs($attribs) . '>' + . $this->view->escape($label) + . ''; + } + + // Iterator filter methods: + + /** + * Determines whether a page should be accepted when iterating + * + * Rules: + * - If a page is not visible it is not accepted, unless RenderInvisible has + * been set to true. + * - If helper has no ACL, page is accepted + * - If helper has ACL, but no role, page is not accepted + * - If helper has ACL and role: + * - Page is accepted if it has no resource or privilege + * - Page is accepted if ACL allows page's resource or privilege + * - If page is accepted by the rules above and $recursive is true, the page + * will not be accepted if it is the descendant of a non-accepted page. + * + * @param Zend_Navigation_Page $page page to check + * @param bool $recursive [optional] if true, page will not + * be accepted if it is the + * descendant of a page that is not + * accepted. Default is true. + * @return bool whether page should be accepted + */ + public function accept(Zend_Navigation_Page $page, $recursive = true) + { + // accept by default + $accept = true; + + if (!$page->isVisible(false) && !$this->getRenderInvisible()) { + // don't accept invisible pages + $accept = false; + } elseif ($this->getUseAcl() && !$this->_acceptAcl($page)) { + // acl is not amused + $accept = false; + } + + if ($accept && $recursive) { + $parent = $page->getParent(); + if ($parent instanceof Zend_Navigation_Page) { + $accept = $this->accept($parent, true); + } + } + + return $accept; + } + + /** + * Determines whether a page should be accepted by ACL when iterating + * + * Rules: + * - If helper has no ACL, page is accepted + * - If page has a resource or privilege defined, page is accepted + * if the ACL allows access to it using the helper's role + * - If page has no resource or privilege, page is accepted + * + * @param Zend_Navigation_Page $page page to check + * @return bool whether page is accepted by ACL + */ + protected function _acceptAcl(Zend_Navigation_Page $page) + { + if (!$acl = $this->getAcl()) { + // no acl registered means don't use acl + return true; + } + + $role = $this->getRole(); + $resource = $page->getResource(); + $privilege = $page->getPrivilege(); + + if ($resource || $privilege) { + // determine using helper role and page resource/privilege + return $acl->isAllowed($role, $resource, $privilege); + } + + return true; + } + + // Util methods: + + /** + * Retrieve whitespace representation of $indent + * + * @param int|string $indent + * @return string + */ + protected function _getWhitespace($indent) + { + if (is_int($indent)) { + $indent = str_repeat(' ', $indent); + } + + return (string) $indent; + } + + /** + * Converts an associative array to a string of tag attributes. + * + * Overloads {@link Zend_View_Helper_HtmlElement::_htmlAttribs()}. + * + * @param array $attribs an array where each key-value pair is converted + * to an attribute name and value + * @return string an attribute string + */ + protected function _htmlAttribs($attribs) + { + // filter out null values and empty string values + foreach ($attribs as $key => $value) { + if ($value === null || (is_string($value) && !strlen($value))) { + unset($attribs[$key]); + } + } + + return parent::_htmlAttribs($attribs); + } + + /** + * Normalize an ID + * + * Extends {@link Zend_View_Helper_HtmlElement::_normalizeId()}. + * + * @param string $value ID + * @return string Normalized ID + */ + protected function _normalizeId($value) + { + if (false === $this->_skipPrefixForId) { + $prefix = $this->getPrefixForId(); + + if (strlen($prefix)) { + return $prefix . $value; + } + } + + return parent::_normalizeId($value); + } + + // Static methods: + + /** + * Sets default ACL to use if another ACL is not explicitly set + * + * @param Zend_Acl $acl [optional] ACL object. Default is null, which + * sets no ACL object. + * @return void + */ + public static function setDefaultAcl(Zend_Acl $acl = null) + { + self::$_defaultAcl = $acl; + } + + /** + * Sets default ACL role(s) to use when iterating pages if not explicitly + * set later with {@link setRole()} + * + * @param midex $role [optional] role to set. Expects null, + * string, or an instance of + * {@link Zend_Acl_Role_Interface}. + * Default is null, which sets no default + * role. + * @throws Zend_View_Exception if role is invalid + * @return void + */ + public static function setDefaultRole($role = null) + { + if (null === $role || + is_string($role) || + $role instanceof Zend_Acl_Role_Interface) { + self::$_defaultRole = $role; + } else { + throw new Zend_View_Exception( + '$role must be null|string|Zend_Acl_Role_Interface' + ); + } + } +} diff --git a/library/vendor/Zend/View/Helper/Navigation/Links.php b/library/vendor/Zend/View/Helper/Navigation/Links.php new file mode 100644 index 000000000..e600c6d47 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Navigation/Links.php @@ -0,0 +1,780 @@ + elements + * + * @category Zend + * @package Zend_View + * @subpackage Helper + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_View_Helper_Navigation_Links + extends Zend_View_Helper_Navigation_HelperAbstract +{ + /**#@+ + * Constants used for specifying which link types to find and render + * + * @var int + */ + const RENDER_ALTERNATE = 0x0001; + const RENDER_STYLESHEET = 0x0002; + const RENDER_START = 0x0004; + const RENDER_NEXT = 0x0008; + const RENDER_PREV = 0x0010; + const RENDER_CONTENTS = 0x0020; + const RENDER_INDEX = 0x0040; + const RENDER_GLOSSARY = 0x0080; + const RENDER_COPYRIGHT = 0x0100; + const RENDER_CHAPTER = 0x0200; + const RENDER_SECTION = 0x0400; + const RENDER_SUBSECTION = 0x0800; + const RENDER_APPENDIX = 0x1000; + const RENDER_HELP = 0x2000; + const RENDER_BOOKMARK = 0x4000; + const RENDER_CUSTOM = 0x8000; + const RENDER_ALL = 0xffff; + /**#@+**/ + + /** + * Maps render constants to W3C link types + * + * @var array + */ + protected static $_RELATIONS = array( + self::RENDER_ALTERNATE => 'alternate', + self::RENDER_STYLESHEET => 'stylesheet', + self::RENDER_START => 'start', + self::RENDER_NEXT => 'next', + self::RENDER_PREV => 'prev', + self::RENDER_CONTENTS => 'contents', + self::RENDER_INDEX => 'index', + self::RENDER_GLOSSARY => 'glossary', + self::RENDER_COPYRIGHT => 'copyright', + self::RENDER_CHAPTER => 'chapter', + self::RENDER_SECTION => 'section', + self::RENDER_SUBSECTION => 'subsection', + self::RENDER_APPENDIX => 'appendix', + self::RENDER_HELP => 'help', + self::RENDER_BOOKMARK => 'bookmark' + ); + + /** + * The helper's render flag + * + * @see render() + * @see setRenderFlag() + * @var int + */ + protected $_renderFlag = self::RENDER_ALL; + + /** + * Root container + * + * Used for preventing methods to traverse above the container given to + * the {@link render()} method. + * + * @see _findRoot() + * + * @var Zend_Navigation_Container + */ + protected $_root; + + /** + * View helper entry point: + * Retrieves helper and optionally sets container to operate on + * + * @param Zend_Navigation_Container $container [optional] container to + * operate on + * @return Zend_View_Helper_Navigation_Links fluent interface, returns + * self + */ + public function links(Zend_Navigation_Container $container = null) + { + if (null !== $container) { + $this->setContainer($container); + } + + return $this; + } + + /** + * Magic overload: Proxy calls to {@link findRelation()} or container + * + * Examples of finder calls: + * + * // METHOD // SAME AS + * $h->findRelNext($page); // $h->findRelation($page, 'rel', 'next') + * $h->findRevSection($page); // $h->findRelation($page, 'rev', 'section'); + * $h->findRelFoo($page); // $h->findRelation($page, 'rel', 'foo'); + * + * + * @param string $method method name + * @param array $arguments method arguments + * @throws Zend_Navigation_Exception if method does not exist in container + */ + public function __call($method, array $arguments = array()) + { + if (@preg_match('/find(Rel|Rev)(.+)/', $method, $match)) { + return $this->findRelation($arguments[0], + strtolower($match[1]), + strtolower($match[2])); + } + + return parent::__call($method, $arguments); + } + + // Accessors: + + /** + * Sets the helper's render flag + * + * The helper uses the bitwise '&' operator against the hex values of the + * render constants. This means that the flag can is "bitwised" value of + * the render constants. Examples: + * + * // render all links except glossary + * $flag = Zend_View_Helper_Navigation_Links:RENDER_ALL ^ + * Zend_View_Helper_Navigation_Links:RENDER_GLOSSARY; + * $helper->setRenderFlag($flag); + * + * // render only chapters and sections + * $flag = Zend_View_Helper_Navigation_Links:RENDER_CHAPTER | + * Zend_View_Helper_Navigation_Links:RENDER_SECTION; + * $helper->setRenderFlag($flag); + * + * // render only relations that are not native W3C relations + * $helper->setRenderFlag(Zend_View_Helper_Navigation_Links:RENDER_CUSTOM); + * + * // render all relations (default) + * $helper->setRenderFlag(Zend_View_Helper_Navigation_Links:RENDER_ALL); + * + * + * Note that custom relations can also be rendered directly using the + * {@link renderLink()} method. + * + * @param int $renderFlag render flag + * @return Zend_View_Helper_Navigation_Links fluent interface, returns self + */ + public function setRenderFlag($renderFlag) + { + $this->_renderFlag = (int) $renderFlag; + return $this; + } + + /** + * Returns the helper's render flag + * + * @return int render flag + */ + public function getRenderFlag() + { + return $this->_renderFlag; + } + + // Finder methods: + + /** + * Finds all relations (forward and reverse) for the given $page + * + * The form of the returned array: + * + * // $page denotes an instance of Zend_Navigation_Page + * $returned = array( + * 'rel' => array( + * 'alternate' => array($page, $page, $page), + * 'start' => array($page), + * 'next' => array($page), + * 'prev' => array($page), + * 'canonical' => array($page) + * ), + * 'rev' => array( + * 'section' => array($page) + * ) + * ); + * + * + * @param Zend_Navigation_Page $page page to find links for + * @return array related pages + */ + public function findAllRelations(Zend_Navigation_Page $page, + $flag = null) + { + if (!is_int($flag)) { + $flag = self::RENDER_ALL; + } + + $result = array('rel' => array(), 'rev' => array()); + $native = array_values(self::$_RELATIONS); + + foreach (array_keys($result) as $rel) { + $meth = 'getDefined' . ucfirst($rel); + $types = array_merge($native, array_diff($page->$meth(), $native)); + + foreach ($types as $type) { + if (!$relFlag = array_search($type, self::$_RELATIONS)) { + $relFlag = self::RENDER_CUSTOM; + } + if (!($flag & $relFlag)) { + continue; + } + if ($found = $this->findRelation($page, $rel, $type)) { + if (!is_array($found)) { + $found = array($found); + } + $result[$rel][$type] = $found; + } + } + } + + return $result; + } + + /** + * Finds relations of the given $rel=$type from $page + * + * This method will first look for relations in the page instance, then + * by searching the root container if nothing was found in the page. + * + * @param Zend_Navigation_Page $page page to find relations for + * @param string $rel relation, "rel" or "rev" + * @param string $type link type, e.g. 'start', 'next' + * @return Zend_Navigaiton_Page|array|null page(s), or null if not found + * @throws Zend_View_Exception if $rel is not "rel" or "rev" + */ + public function findRelation(Zend_Navigation_Page $page, $rel, $type) + { + if (!in_array($rel, array('rel', 'rev'))) { + $e = new Zend_View_Exception(sprintf( + 'Invalid argument: $rel must be "rel" or "rev"; "%s" given', + $rel)); + $e->setView($this->view); + throw $e; + } + + if (!$result = $this->_findFromProperty($page, $rel, $type)) { + $result = $this->_findFromSearch($page, $rel, $type); + } + + return $result; + } + + /** + * Finds relations of given $type for $page by checking if the + * relation is specified as a property of $page + * + * @param Zend_Navigation_Page $page page to find relations for + * @param string $rel relation, 'rel' or 'rev' + * @param string $type link type, e.g. 'start', 'next' + * @return Zend_Navigation_Page|array|null page(s), or null if not found + */ + protected function _findFromProperty(Zend_Navigation_Page $page, $rel, $type) + { + $method = 'get' . ucfirst($rel); + if ($result = $page->$method($type)) { + if ($result = $this->_convertToPages($result)) { + if (!is_array($result)) { + $result = array($result); + } + + foreach ($result as $key => $page) { + if (!$this->accept($page)) { + unset($result[$key]); + } + } + + return count($result) == 1 ? $result[0] : $result; + } + } + + return null; + } + + /** + * Finds relations of given $rel=$type for $page by using the helper to + * search for the relation in the root container + * + * @param Zend_Navigation_Page $page page to find relations for + * @param string $rel relation, 'rel' or 'rev' + * @param string $type link type, e.g. 'start', 'next', etc + * @return array|null array of pages, or null if not found + */ + protected function _findFromSearch(Zend_Navigation_Page $page, $rel, $type) + { + $found = null; + + $method = 'search' . ucfirst($rel) . ucfirst($type); + if (method_exists($this, $method)) { + $found = $this->$method($page); + } + + return $found; + } + + // Search methods: + + /** + * Searches the root container for the forward 'start' relation of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to the first document in a collection of documents. This link type + * tells search engines which document is considered by the author to be the + * starting point of the collection. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|null page or null + */ + public function searchRelStart(Zend_Navigation_Page $page) + { + $found = $this->_findRoot($page); + if (!$found instanceof Zend_Navigation_Page) { + $found->rewind(); + $found = $found->current(); + } + + if ($found === $page || !$this->accept($found)) { + $found = null; + } + + return $found; + } + + /** + * Searches the root container for the forward 'next' relation of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to the next document in a linear sequence of documents. User + * agents may choose to preload the "next" document, to reduce the perceived + * load time. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|null page(s) or null + */ + public function searchRelNext(Zend_Navigation_Page $page) + { + $found = null; + $break = false; + $iterator = new RecursiveIteratorIterator($this->_findRoot($page), + RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $intermediate) { + if ($intermediate === $page) { + // current page; break at next accepted page + $break = true; + continue; + } + + if ($break && $this->accept($intermediate)) { + $found = $intermediate; + break; + } + } + + return $found; + } + + /** + * Searches the root container for the forward 'prev' relation of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to the previous document in an ordered series of documents. Some + * user agents also support the synonym "Previous". + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|null page or null + */ + public function searchRelPrev(Zend_Navigation_Page $page) + { + $found = null; + $prev = null; + $iterator = new RecursiveIteratorIterator( + $this->_findRoot($page), + RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $intermediate) { + if (!$this->accept($intermediate)) { + continue; + } + if ($intermediate === $page) { + $found = $prev; + break; + } + + $prev = $intermediate; + } + + return $found; + } + + /** + * Searches the root container for forward 'chapter' relations of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a chapter in a collection of documents. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|array|null page(s) or null + */ + public function searchRelChapter(Zend_Navigation_Page $page) + { + $found = array(); + + // find first level of pages + $root = $this->_findRoot($page); + + // find start page(s) + $start = $this->findRelation($page, 'rel', 'start'); + if (!is_array($start)) { + $start = array($start); + } + + foreach ($root as $chapter) { + // exclude self and start page from chapters + if ($chapter !== $page && + !in_array($chapter, $start) && + $this->accept($chapter)) { + $found[] = $chapter; + } + } + + switch (count($found)) { + case 0: + return null; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Searches the root container for forward 'section' relations of the given + * $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a section in a collection of documents. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|array|null page(s) or null + */ + public function searchRelSection(Zend_Navigation_Page $page) + { + $found = array(); + + // check if given page has pages and is a chapter page + if ($page->hasPages() && $this->_findRoot($page)->hasPage($page)) { + foreach ($page as $section) { + if ($this->accept($section)) { + $found[] = $section; + } + } + } + + switch (count($found)) { + case 0: + return null; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Searches the root container for forward 'subsection' relations of the + * given $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a subsection in a collection of + * documents. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|array|null page(s) or null + */ + public function searchRelSubsection(Zend_Navigation_Page $page) + { + $found = array(); + + if ($page->hasPages()) { + // given page has child pages, loop chapters + foreach ($this->_findRoot($page) as $chapter) { + // is page a section? + if ($chapter->hasPage($page)) { + foreach ($page as $subsection) { + if ($this->accept($subsection)) { + $found[] = $subsection; + } + } + } + } + } + + switch (count($found)) { + case 0: + return null; + case 1: + return $found[0]; + default: + return $found; + } + } + + /** + * Searches the root container for the reverse 'section' relation of the + * given $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a section in a collection of documents. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|null page(s) or null + */ + public function searchRevSection(Zend_Navigation_Page $page) + { + $found = null; + + if ($parent = $page->getParent()) { + if ($parent instanceof Zend_Navigation_Page && + $this->_findRoot($page)->hasPage($parent)) { + $found = $parent; + } + } + + return $found; + } + + /** + * Searches the root container for the reverse 'section' relation of the + * given $page + * + * From {@link http://www.w3.org/TR/html4/types.html#type-links}: + * Refers to a document serving as a subsection in a collection of + * documents. + * + * @param Zend_Navigation_Page $page page to find relation for + * @return Zend_Navigation_Page|null page(s) or null + */ + public function searchRevSubsection(Zend_Navigation_Page $page) + { + $found = null; + + if ($parent = $page->getParent()) { + if ($parent instanceof Zend_Navigation_Page) { + $root = $this->_findRoot($page); + foreach ($root as $chapter) { + if ($chapter->hasPage($parent)) { + $found = $parent; + break; + } + } + } + } + + return $found; + } + + // Util methods: + + /** + * Returns the root container of the given page + * + * When rendering a container, the render method still store the given + * container as the root container, and unset it when done rendering. This + * makes sure finder methods will not traverse above the container given + * to the render method. + * + * @param Zend_Navigaiton_Page $page page to find root for + * @return Zend_Navigation_Container the root container of the given page + */ + protected function _findRoot(Zend_Navigation_Page $page) + { + if ($this->_root) { + return $this->_root; + } + + $root = $page; + + while ($parent = $page->getParent()) { + $root = $parent; + if ($parent instanceof Zend_Navigation_Page) { + $page = $parent; + } else { + break; + } + } + + return $root; + } + + /** + * Converts a $mixed value to an array of pages + * + * @param mixed $mixed mixed value to get page(s) from + * @param bool $recursive whether $value should be looped + * if it is an array or a config + * @return Zend_Navigation_Page|array|null empty if unable to convert + */ + protected function _convertToPages($mixed, $recursive = true) + { + if (is_object($mixed)) { + if ($mixed instanceof Zend_Navigation_Page) { + // value is a page instance; return directly + return $mixed; + } elseif ($mixed instanceof Zend_Navigation_Container) { + // value is a container; return pages in it + $pages = array(); + foreach ($mixed as $page) { + $pages[] = $page; + } + return $pages; + } elseif ($mixed instanceof Zend_Config) { + // convert config object to array and extract + return $this->_convertToPages($mixed->toArray(), $recursive); + } + } elseif (is_string($mixed)) { + // value is a string; make an URI page + return Zend_Navigation_Page::factory(array( + 'type' => 'uri', + 'uri' => $mixed + )); + } elseif (is_array($mixed) && !empty($mixed)) { + if ($recursive && is_numeric(key($mixed))) { + // first key is numeric; assume several pages + $pages = array(); + foreach ($mixed as $value) { + if ($value = $this->_convertToPages($value, false)) { + $pages[] = $value; + } + } + return $pages; + } else { + // pass array to factory directly + try { + $page = Zend_Navigation_Page::factory($mixed); + return $page; + } catch (Exception $e) { + } + } + } + + // nothing found + return null; + } + + // Render methods: + + /** + * Renders the given $page as a link element, with $attrib = $relation + * + * @param Zend_Navigation_Page $page the page to render the link for + * @param string $attrib the attribute to use for $type, + * either 'rel' or 'rev' + * @param string $relation relation type, muse be one of; + * alternate, appendix, bookmark, + * chapter, contents, copyright, + * glossary, help, home, index, next, + * prev, section, start, stylesheet, + * subsection + * @return string rendered link element + * @throws Zend_View_Exception if $attrib is invalid + */ + public function renderLink(Zend_Navigation_Page $page, $attrib, $relation) + { + if (!in_array($attrib, array('rel', 'rev'))) { + $e = new Zend_View_Exception(sprintf( + 'Invalid relation attribute "%s", must be "rel" or "rev"', + $attrib)); + $e->setView($this->view); + throw $e; + } + + if (!$href = $page->getHref()) { + return ''; + } + + // TODO: add more attribs + // http://www.w3.org/TR/html401/struct/links.html#h-12.2 + $attribs = array( + $attrib => $relation, + 'href' => $href, + 'title' => $page->getLabel() + ); + + return '_htmlAttribs($attribs) . + $this->getClosingBracket(); + } + + // Zend_View_Helper_Navigation_Helper: + + /** + * Renders helper + * + * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + */ + public function render(Zend_Navigation_Container $container = null) + { + if (null === $container) { + $container = $this->getContainer(); + } + + if ($active = $this->findActive($container)) { + $active = $active['page']; + } else { + // no active page + return ''; + } + + $output = ''; + $indent = $this->getIndent(); + $this->_root = $container; + + $result = $this->findAllRelations($active, $this->getRenderFlag()); + foreach ($result as $attrib => $types) { + foreach ($types as $relation => $pages) { + foreach ($pages as $page) { + if ($r = $this->renderLink($page, $attrib, $relation)) { + $output .= $indent . $r . $this->getEOL(); + } + } + } + } + + $this->_root = null; + + // return output (trim last newline by spec) + return strlen($output) ? rtrim($output, self::EOL) : ''; + } +} diff --git a/library/vendor/Zend/View/Helper/Navigation/Menu.php b/library/vendor/Zend/View/Helper/Navigation/Menu.php new file mode 100644 index 000000000..0405b8887 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Navigation/Menu.php @@ -0,0 +1,1096 @@ +setContainer($container); + } + + return $this; + } + + // Accessors: + + /** + * Sets CSS class to use for the first 'ul' element when rendering + * + * @param string $ulClass CSS class to set + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setUlClass($ulClass) + { + if (is_string($ulClass)) { + $this->_ulClass = $ulClass; + } + + return $this; + } + + /** + * Returns CSS class to use for the first 'ul' element when rendering + * + * @return string CSS class + */ + public function getUlClass() + { + return $this->_ulClass; + } + + /** + * Sets unique identifier (id) to use for the first 'ul' element when + * rendering + * + * @param string|null $ulId Unique identifier (id) to set + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setUlId($ulId) + { + if (is_string($ulId)) { + $this->_ulId = $ulId; + } + + return $this; + } + + /** + * Returns unique identifier (id) to use for the first 'ul' element when + * rendering + * + * @return string|null Unique identifier (id); Default is 'null' + */ + public function getUlId() + { + return $this->_ulId; + } + + /** + * Sets CSS class to use for the active elements when rendering + * + * @param string $activeClass CSS class to set + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setActiveClass($activeClass) + { + if (is_string($activeClass)) { + $this->_activeClass = $activeClass; + } + + return $this; + } + + /** + * Returns CSS class to use for the active elements when rendering + * + * @return string CSS class + */ + public function getActiveClass() + { + return $this->_activeClass; + } + + /** + * Sets CSS class to use for the parent li elements when rendering + * + * @param string $parentClass CSS class to set to parents + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setParentClass($parentClass) + { + if (is_string($parentClass)) { + $this->_parentClass = $parentClass; + } + + return $this; + } + + /** + * Returns CSS class to use for the parent lie elements when rendering + * + * @return string CSS class + */ + public function getParentClass() + { + return $this->_parentClass; + } + + /** + * Enables/disables rendering of parent class to the li element + * + * @param bool $flag [optional] render with parent + * class. Default is true. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setRenderParentClass($flag = true) + { + $this->_renderParentClass = (bool) $flag; + return $this; + } + + /** + * Returns flag indicating whether parent class should be rendered to the li + * element + * + * @return bool whether parent class should be rendered + */ + public function getRenderParentClass() + { + return $this->_renderParentClass; + } + + /** + * Sets a flag indicating whether only active branch should be rendered + * + * @param bool $flag [optional] render only active + * branch. Default is true. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setOnlyActiveBranch($flag = true) + { + $this->_onlyActiveBranch = (bool) $flag; + return $this; + } + + /** + * Returns a flag indicating whether only active branch should be rendered + * + * By default, this value is false, meaning the entire menu will be + * be rendered. + * + * @return bool whether only active branch should be rendered + */ + public function getOnlyActiveBranch() + { + return $this->_onlyActiveBranch; + } + + /** + * Sets a flag indicating whether to expand all sibling nodes of the active branch + * + * @param bool $flag [optional] expand all siblings of + * nodes in the active branch. Default is true. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setExpandSiblingNodesOfActiveBranch($flag = true) + { + $this->_expandSiblingNodesOfActiveBranch = (bool) $flag; + return $this; + } + + /** + * Returns a flag indicating whether to expand all sibling nodes of the active branch + * + * By default, this value is false, meaning the entire menu will be + * be rendered. + * + * @return bool whether siblings of nodes in the active branch should be expanded + */ + public function getExpandSiblingNodesOfActiveBranch() + { + return $this->_expandSiblingNodesOfActiveBranch; + } + + /** + * Enables/disables rendering of parents when only rendering active branch + * + * See {@link setOnlyActiveBranch()} for more information. + * + * @param bool $flag [optional] render parents when + * rendering active branch. + * Default is true. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setRenderParents($flag = true) + { + $this->_renderParents = (bool) $flag; + return $this; + } + + /** + * Returns flag indicating whether parents should be rendered when rendering + * only the active branch + * + * By default, this value is true. + * + * @return bool whether parents should be rendered + */ + public function getRenderParents() + { + return $this->_renderParents; + } + + /** + * Sets which partial view script to use for rendering menu + * + * @param string|array $partial partial view script or null. If + * an array is given, it is + * expected to contain two values; + * the partial view script to use, + * and the module where the script + * can be found. + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function setPartial($partial) + { + if (null === $partial || is_string($partial) || is_array($partial)) { + $this->_partial = $partial; + } + + return $this; + } + + /** + * Returns partial view script to use for rendering menu + * + * @return string|array|null + */ + public function getPartial() + { + return $this->_partial; + } + + /** + * Adds CSS class from page to li element + * + * Before: + * + *
            • + * Bar + *
            • + *
              + * + * After: + * + *
            • + * Bar + *
            • + *
              + * + * @param bool $flag [optional] adds CSS class from + * page to li element + * + * @return Zend_View_Helper_Navigation_Menu fluent interface, returns self + */ + public function addPageClassToLi($flag = true) + { + $this->_addPageClassToLi = (bool) $flag; + + return $this; + } + + /** + * Returns a flag indicating whether the CSS class from page to be added to + * li element + * + * @return bool + */ + public function getAddPageClassToLi() + { + return $this->_addPageClassToLi; + } + + /** + * Set the inner indentation string for using in {@link render()}, optionally + * a number of spaces to indent with + * + * @param string|int $indent indentation string or + * number of spaces + * @return Zend_View_Helper_Navigation_HelperAbstract fluent interface, + * returns self + */ + public function setInnerIndent($indent) + { + $this->_innerIndent = $this->_getWhitespace($indent); + + return $this; + } + + /** + * Returns inner indentation (format output is respected) + * + * @see getFormatOutput() + * + * @return string indentation string or an empty string + */ + public function getInnerIndent() + { + if (false === $this->getFormatOutput()) { + return ''; + } + + return $this->_innerIndent; + } + + // Public methods: + + /** + * Returns an HTML string containing an 'a' element for the given page if + * the page's href is not empty, and a 'span' element if it is empty + * + * Overrides {@link Zend_View_Helper_Navigation_Abstract::htmlify()}. + * + * @param Zend_Navigation_Page $page page to generate HTML for + * @return string HTML string for the given page + */ + public function htmlify(Zend_Navigation_Page $page) + { + // get label and title for translating + $label = $page->getLabel(); + $title = $page->getTitle(); + + // translate label and title? + if ($this->getUseTranslator() && $t = $this->getTranslator()) { + if (is_string($label) && !empty($label)) { + $label = $t->translate($label); + } + if (is_string($title) && !empty($title)) { + $title = $t->translate($title); + } + } + + // get attribs for element + $attribs = array( + 'id' => $page->getId(), + 'title' => $title, + ); + + if (false === $this->getAddPageClassToLi()) { + $attribs['class'] = $page->getClass(); + } + + // does page have a href? + if ($href = $page->getHref()) { + $element = 'a'; + $attribs['href'] = $href; + $attribs['target'] = $page->getTarget(); + $attribs['accesskey'] = $page->getAccessKey(); + } else { + $element = 'span'; + } + + // Add custom HTML attributes + $attribs = array_merge($attribs, $page->getCustomHtmlAttribs()); + + return '<' . $element . $this->_htmlAttribs($attribs) . '>' + . $this->view->escape($label) + . ''; + } + + /** + * Normalizes given render options + * + * @param array $options [optional] options to normalize + * @return array normalized options + */ + protected function _normalizeOptions(array $options = array()) + { + // Ident + if (isset($options['indent'])) { + $options['indent'] = $this->_getWhitespace($options['indent']); + } else { + $options['indent'] = $this->getIndent(); + } + + // Inner ident + if (isset($options['innerIndent'])) { + $options['innerIndent'] = + $this->_getWhitespace($options['innerIndent']); + } else { + $options['innerIndent'] = $this->getInnerIndent(); + } + + // UL class + if (isset($options['ulClass']) && $options['ulClass'] !== null) { + $options['ulClass'] = (string) $options['ulClass']; + } else { + $options['ulClass'] = $this->getUlClass(); + } + + // UL id + if (isset($options['ulId']) && $options['ulId'] !== null) { + $options['ulId'] = (string) $options['ulId']; + } else { + $options['ulId'] = $this->getUlId(); + } + + // Active class + if (isset($options['activeClass']) && $options['activeClass'] !== null + ) { + $options['activeClass'] = (string) $options['activeClass']; + } else { + $options['activeClass'] = $this->getActiveClass(); + } + + // Parent class + if (isset($options['parentClass']) && $options['parentClass'] !== null) { + $options['parentClass'] = (string) $options['parentClass']; + } else { + $options['parentClass'] = $this->getParentClass(); + } + + // Minimum depth + if (array_key_exists('minDepth', $options)) { + if (null !== $options['minDepth']) { + $options['minDepth'] = (int) $options['minDepth']; + } + } else { + $options['minDepth'] = $this->getMinDepth(); + } + + if ($options['minDepth'] < 0 || $options['minDepth'] === null) { + $options['minDepth'] = 0; + } + + // Maximum depth + if (array_key_exists('maxDepth', $options)) { + if (null !== $options['maxDepth']) { + $options['maxDepth'] = (int) $options['maxDepth']; + } + } else { + $options['maxDepth'] = $this->getMaxDepth(); + } + + // Only active branch + if (!isset($options['onlyActiveBranch'])) { + $options['onlyActiveBranch'] = $this->getOnlyActiveBranch(); + } + + // Expand sibling nodes of active branch + if (!isset($options['expandSiblingNodesOfActiveBranch'])) { + $options['expandSiblingNodesOfActiveBranch'] = $this->getExpandSiblingNodesOfActiveBranch(); + } + + // Render parents? + if (!isset($options['renderParents'])) { + $options['renderParents'] = $this->getRenderParents(); + } + + // Render parent class? + if (!isset($options['renderParentClass'])) { + $options['renderParentClass'] = $this->getRenderParentClass(); + } + + // Add page CSS class to LI element + if (!isset($options['addPageClassToLi'])) { + $options['addPageClassToLi'] = $this->getAddPageClassToLi(); + } + + return $options; + } + + // Render methods: + + /** + * Renders the deepest active menu within [$minDepth, $maxDeth], (called + * from {@link renderMenu()}) + * + * @param Zend_Navigation_Container $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param string $innerIndent inner indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param string|null $ulId unique identifier (id) + * for first UL + * @param bool $addPageClassToLi adds CSS class from + * page to li element + * @param string|null $activeClass CSS class for active + * element + * @param string $parentClass CSS class for parent + * li's + * @param bool $renderParentClass Render parent class? + * @return string rendered menu (HTML) + */ + protected function _renderDeepestMenu(Zend_Navigation_Container $container, + $ulClass, + $indent, + $innerIndent, + $minDepth, + $maxDepth, + $ulId, + $addPageClassToLi, + $activeClass, + $parentClass, + $renderParentClass) + { + if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) { + return ''; + } + + // special case if active page is one below minDepth + if ($active['depth'] < $minDepth) { + if (!$active['page']->hasPages()) { + return ''; + } + } else if (!$active['page']->hasPages()) { + // found pages has no children; render siblings + $active['page'] = $active['page']->getParent(); + } else if (is_int($maxDepth) && $active['depth'] + 1 > $maxDepth) { + // children are below max depth; render siblings + $active['page'] = $active['page']->getParent(); + } + + $attribs = array( + 'class' => $ulClass, + 'id' => $ulId, + ); + + // We don't need a prefix for the menu ID (backup) + $skipValue = $this->_skipPrefixForId; + $this->skipPrefixForId(); + + $html = $indent . '_htmlAttribs($attribs) + . '>' + . $this->getEOL(); + + // Reset prefix for IDs + $this->_skipPrefixForId = $skipValue; + + foreach ($active['page'] as $subPage) { + if (!$this->accept($subPage)) { + continue; + } + + $liClass = ''; + if ($subPage->isActive(true) && $addPageClassToLi) { + $liClass = $this->_htmlAttribs( + array('class' => $activeClass . ' ' . $subPage->getClass()) + ); + } else if ($subPage->isActive(true)) { + $liClass = $this->_htmlAttribs(array('class' => $activeClass)); + } else if ($addPageClassToLi) { + $liClass = $this->_htmlAttribs( + array('class' => $subPage->getClass()) + ); + } + $html .= $indent . $innerIndent . '' . $this->getEOL(); + $html .= $indent . str_repeat($innerIndent, 2) . $this->htmlify($subPage) + . $this->getEOL(); + $html .= $indent . $innerIndent . '' . $this->getEOL(); + } + + $html .= $indent . ''; + + return $html; + } + + /** + * Renders a normal menu (called from {@link renderMenu()}) + * + * @param Zend_Navigation_Container $container container to render + * @param string $ulClass CSS class for first UL + * @param string $indent initial indentation + * @param string $innerIndent inner indentation + * @param int|null $minDepth minimum depth + * @param int|null $maxDepth maximum depth + * @param bool $onlyActive render only active branch? + * @param bool $expandSibs render siblings of active + * branch nodes? + * @param string|null $ulId unique identifier (id) + * for first UL + * @param bool $addPageClassToLi adds CSS class from + * page to li element + * @param string|null $activeClass CSS class for active + * element + * @param string $parentClass CSS class for parent + * li's + * @param bool $renderParentClass Render parent class? + * @return string rendered menu (HTML) + */ + protected function _renderMenu(Zend_Navigation_Container $container, + $ulClass, + $indent, + $innerIndent, + $minDepth, + $maxDepth, + $onlyActive, + $expandSibs, + $ulId, + $addPageClassToLi, + $activeClass, + $parentClass, + $renderParentClass) + { + $html = ''; + + // find deepest active + if ($found = $this->findActive($container, $minDepth, $maxDepth)) { + $foundPage = $found['page']; + $foundDepth = $found['depth']; + } else { + $foundPage = null; + } + + // create iterator + $iterator = new RecursiveIteratorIterator($container, + RecursiveIteratorIterator::SELF_FIRST); + if (is_int($maxDepth)) { + $iterator->setMaxDepth($maxDepth); + } + + // iterate container + $prevDepth = -1; + foreach ($iterator as $page) { + $depth = $iterator->getDepth(); + $isActive = $page->isActive(true); + if ($depth < $minDepth || !$this->accept($page)) { + // page is below minDepth or not accepted by acl/visibilty + continue; + } else if ($expandSibs && $depth > $minDepth) { + // page is not active itself, but might be in the active branch + $accept = false; + if ($foundPage) { + if ($foundPage->hasPage($page)) { + // accept if page is a direct child of the active page + $accept = true; + } else if ($page->getParent()->isActive(true)) { + // page is a sibling of the active branch... + $accept = true; + } + } + if (!$isActive && !$accept) { + continue; + } + } else if ($onlyActive && !$isActive) { + // page is not active itself, but might be in the active branch + $accept = false; + if ($foundPage) { + if ($foundPage->hasPage($page)) { + // accept if page is a direct child of the active page + $accept = true; + } else if ($foundPage->getParent()->hasPage($page)) { + // page is a sibling of the active page... + if (!$foundPage->hasPages() || + is_int($maxDepth) && $foundDepth + 1 > $maxDepth) { + // accept if active page has no children, or the + // children are too deep to be rendered + $accept = true; + } + } + } + + if (!$accept) { + continue; + } + } + + // make sure indentation is correct + $depth -= $minDepth; + $myIndent = $indent . str_repeat($innerIndent, $depth * 2); + + if ($depth > $prevDepth) { + $attribs = array(); + + // start new ul tag + if (0 == $depth) { + $attribs = array( + 'class' => $ulClass, + 'id' => $ulId, + ); + } + + // We don't need a prefix for the menu ID (backup) + $skipValue = $this->_skipPrefixForId; + $this->skipPrefixForId(); + + $html .= $myIndent . '_htmlAttribs($attribs) + . '>' + . $this->getEOL(); + + // Reset prefix for IDs + $this->_skipPrefixForId = $skipValue; + } else if ($prevDepth > $depth) { + // close li/ul tags until we're at current depth + for ($i = $prevDepth; $i > $depth; $i--) { + $ind = $indent . str_repeat($innerIndent, $i * 2); + $html .= $ind . $innerIndent . '' . $this->getEOL(); + $html .= $ind . '' . $this->getEOL(); + } + // close previous li tag + $html .= $myIndent . $innerIndent . '' . $this->getEOL(); + } else { + // close previous li tag + $html .= $myIndent . $innerIndent . '' . $this->getEOL(); + } + + // render li tag and page + $liClasses = array(); + // Is page active? + if ($isActive) { + $liClasses[] = $activeClass; + } + // Add CSS class from page to LI? + if ($addPageClassToLi) { + $liClasses[] = $page->getClass(); + } + // Add CSS class for parents to LI? + if ($renderParentClass && $page->hasChildren()) { + // Check max depth + if ((is_int($maxDepth) && ($depth + 1 < $maxDepth)) + || !is_int($maxDepth) + ) { + $liClasses[] = $parentClass; + } + } + + $html .= $myIndent . $innerIndent . '_htmlAttribs(array('class' => implode(' ', $liClasses))) + . '>' . $this->getEOL() + . $myIndent . str_repeat($innerIndent, 2) + . $this->htmlify($page) + . $this->getEOL(); + + // store as previous depth for next iteration + $prevDepth = $depth; + } + + if ($html) { + // done iterating container; close open ul/li tags + for ($i = $prevDepth+1; $i > 0; $i--) { + $myIndent = $indent . str_repeat($innerIndent . $innerIndent, $i - 1); + $html .= $myIndent . $innerIndent . '' . $this->getEOL() + . $myIndent . '' . $this->getEOL(); + } + $html = rtrim($html, $this->getEOL()); + } + + return $html; + } + + /** + * Renders helper + * + * Renders a HTML 'ul' for the given $container. If $container is not given, + * the container registered in the helper will be used. + * + * Available $options: + * + * + * @param Zend_Navigation_Container $container [optional] container to + * create menu from. Default + * is to use the container + * retrieved from + * {@link getContainer()}. + * @param array $options [optional] options for + * controlling rendering + * @return string rendered menu + */ + public function renderMenu(Zend_Navigation_Container $container = null, + array $options = array()) + { + if (null === $container) { + $container = $this->getContainer(); + } + + $options = $this->_normalizeOptions($options); + + if ($options['onlyActiveBranch'] && !$options['renderParents']) { + $html = $this->_renderDeepestMenu( + $container, + $options['ulClass'], + $options['indent'], + $options['innerIndent'], + $options['minDepth'], + $options['maxDepth'], + $options['ulId'], + $options['addPageClassToLi'], + $options['activeClass'], + $options['parentClass'], + $options['renderParentClass'] + ); + } else { + $html = $this->_renderMenu( + $container, + $options['ulClass'], + $options['indent'], + $options['innerIndent'], + $options['minDepth'], + $options['maxDepth'], + $options['onlyActiveBranch'], + $options['expandSiblingNodesOfActiveBranch'], + $options['ulId'], + $options['addPageClassToLi'], + $options['activeClass'], + $options['parentClass'], + $options['renderParentClass'] + ); + } + + return $html; + } + + /** + * Renders the inner-most sub menu for the active page in the $container + * + * This is a convenience method which is equivalent to the following call: + * + * renderMenu($container, array( + * 'indent' => $indent, + * 'ulClass' => $ulClass, + * 'minDepth' => null, + * 'maxDepth' => null, + * 'onlyActiveBranch' => true, + * 'renderParents' => false + * )); + * + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to render + * the container registered in + * the helper. + * @param string|null $ulClass [optional] CSS class to + * use for UL element. Default + * is to use the value from + * {@link getUlClass()}. + * @param string|int $indent [optional] indentation as + * a string or number of + * spaces. Default is to use + * the value retrieved from + * {@link getIndent()}. + * @param string|null $ulId [optional] Unique identifier + * (id) use for UL element + * @param bool $addPageClassToLi adds CSS class from + * page to li element + * @param string|int $innerIndent [optional] inner + * indentation as a string + * or number of spaces. + * Default is to use the + * {@link getInnerIndent()}. + * @return string rendered content + */ + public function renderSubMenu(Zend_Navigation_Container $container = null, + $ulClass = null, + $indent = null, + $ulId = null, + $addPageClassToLi = false, + $innerIndent = null) + { + return $this->renderMenu($container, array( + 'indent' => $indent, + 'innerIndent' => $innerIndent, + 'ulClass' => $ulClass, + 'minDepth' => null, + 'maxDepth' => null, + 'onlyActiveBranch' => true, + 'renderParents' => false, + 'ulId' => $ulId, + 'addPageClassToLi' => $addPageClassToLi, + )); + } + + /** + * Renders the given $container by invoking the partial view helper + * + * The container will simply be passed on as a model to the view script + * as-is, and will be available in the partial script as 'container', e.g. + * echo 'Number of pages: ', count($this->container);. + * + * @param Zend_Navigation_Container $container [optional] container to + * pass to view script. Default + * is to use the container + * registered in the helper. + * @param string|array $partial [optional] partial view + * script to use. Default is to + * use the partial registered + * in the helper. If an array + * is given, it is expected to + * contain two values; the + * partial view script to use, + * and the module where the + * script can be found. + * @return string helper output + * + * @throws Zend_View_Exception When no partial script is set + */ + public function renderPartial(Zend_Navigation_Container $container = null, + $partial = null) + { + if (null === $container) { + $container = $this->getContainer(); + } + + if (null === $partial) { + $partial = $this->getPartial(); + } + + if (empty($partial)) { + $e = new Zend_View_Exception( + 'Unable to render menu: No partial view script provided' + ); + $e->setView($this->view); + throw $e; + } + + $model = array( + 'container' => $container + ); + + if (is_array($partial)) { + if (count($partial) != 2) { + $e = new Zend_View_Exception( + 'Unable to render menu: A view partial supplied as ' + . 'an array must contain two values: partial view ' + . 'script and module where script can be found' + ); + $e->setView($this->view); + throw $e; + } + + return $this->view->partial($partial[0], $partial[1], $model); + } + + return $this->view->partial($partial, null, $model); + } + + // Zend_View_Helper_Navigation_Helper: + + /** + * Renders menu + * + * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. + * + * If a partial view is registered in the helper, the menu will be rendered + * using the given partial script. If no partial is registered, the menu + * will be rendered as an 'ul' element by the helper's internal method. + * + * @see renderPartial() + * @see renderMenu() + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + */ + public function render(Zend_Navigation_Container $container = null) + { + if ($partial = $this->getPartial()) { + return $this->renderPartial($container, $partial); + } else { + return $this->renderMenu($container); + } + } +} diff --git a/library/vendor/Zend/View/Helper/Navigation/Sitemap.php b/library/vendor/Zend/View/Helper/Navigation/Sitemap.php new file mode 100644 index 000000000..a3b71fa2b --- /dev/null +++ b/library/vendor/Zend/View/Helper/Navigation/Sitemap.php @@ -0,0 +1,435 @@ + tag + * + * @var string + */ + const SITEMAP_NS = 'http://www.sitemaps.org/schemas/sitemap/0.9'; + + /** + * Schema URL + * + * @var string + */ + const SITEMAP_XSD = 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'; + + /** + * Whether the XML declaration should be included in XML output + * + * @var bool + */ + protected $_useXmlDeclaration = true; + + /** + * Whether sitemap should be validated using Zend_Validate_Sitemap_* + * + * @var bool + */ + protected $_useSitemapValidators = true; + + /** + * Whether sitemap should be schema validated when generated + * + * @var bool + */ + protected $_useSchemaValidation = false; + + /** + * Server url + * + * @var string + */ + protected $_serverUrl; + + /** + * View helper entry point: + * Retrieves helper and optionally sets container to operate on + * + * @param Zend_Navigation_Container $container [optional] container to + * operate on + * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns + * self + */ + public function sitemap(Zend_Navigation_Container $container = null) + { + if (null !== $container) { + $this->setContainer($container); + } + + return $this; + } + + // Accessors: + + /** + * Sets whether the XML declaration should be used in output + * + * @param bool $useXmlDecl whether XML delcaration + * should be rendered + * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns + * self + */ + public function setUseXmlDeclaration($useXmlDecl) + { + $this->_useXmlDeclaration = (bool) $useXmlDecl; + return $this; + } + + /** + * Returns whether the XML declaration should be used in output + * + * @return bool whether the XML declaration should be used in output + */ + public function getUseXmlDeclaration() + { + return $this->_useXmlDeclaration; + } + + /** + * Sets whether sitemap should be validated using Zend_Validate_Sitemap_* + * + * @param bool $useSitemapValidators whether sitemap validators + * should be used + * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns + * self + */ + public function setUseSitemapValidators($useSitemapValidators) + { + $this->_useSitemapValidators = (bool) $useSitemapValidators; + return $this; + } + + /** + * Returns whether sitemap should be validated using Zend_Validate_Sitemap_* + * + * @return bool whether sitemap should be validated using validators + */ + public function getUseSitemapValidators() + { + return $this->_useSitemapValidators; + } + + /** + * Sets whether sitemap should be schema validated when generated + * + * @param bool $schemaValidation whether sitemap should + * validated using XSD Schema + * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns + * self + */ + public function setUseSchemaValidation($schemaValidation) + { + $this->_useSchemaValidation = (bool) $schemaValidation; + return $this; + } + + /** + * Returns true if sitemap should be schema validated when generated + * + * @return bool + */ + public function getUseSchemaValidation() + { + return $this->_useSchemaValidation; + } + + /** + * Sets server url (scheme and host-related stuff without request URI) + * + * E.g. http://www.example.com + * + * @param string $serverUrl server URL to set (only + * scheme and host) + * @throws Zend_Uri_Exception if invalid server URL + * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns + * self + */ + public function setServerUrl($serverUrl) + { + $uri = Zend_Uri::factory($serverUrl); + $uri->setFragment(''); + $uri->setPath(''); + $uri->setQuery(''); + + if ($uri->valid()) { + $this->_serverUrl = $uri->getUri(); + } else { + $e = new Zend_Uri_Exception(sprintf( + 'Invalid server URL: "%s"', + $serverUrl)); + $e->setView($this->view); + throw $e; + } + + return $this; + } + + /** + * Returns server URL + * + * @return string server URL + */ + public function getServerUrl() + { + if (!isset($this->_serverUrl)) { + $this->_serverUrl = $this->view->serverUrl(); + } + + return $this->_serverUrl; + } + + // Helper methods: + + /** + * Escapes string for XML usage + * + * @param string $string string to escape + * @return string escaped string + */ + protected function _xmlEscape($string) + { + $enc = 'UTF-8'; + if ($this->view instanceof Zend_View_Interface + && method_exists($this->view, 'getEncoding') + ) { + $enc = $this->view->getEncoding(); + } + + // do not encode existing HTML entities + return htmlspecialchars($string, ENT_QUOTES, $enc, false); + } + + // Public methods: + + /** + * Returns an escaped absolute URL for the given page + * + * @param Zend_Navigation_Page $page page to get URL from + * @return string + */ + public function url(Zend_Navigation_Page $page) + { + $href = $page->getHref(); + + if (!isset($href{0})) { + // no href + return ''; + } elseif ($href{0} == '/') { + // href is relative to root; use serverUrl helper + $url = $this->getServerUrl() . $href; + } elseif (preg_match('/^[a-z]+:/im', (string) $href)) { + // scheme is given in href; assume absolute URL already + $url = (string) $href; + } else { + // href is relative to current document; use url helpers + $url = $this->getServerUrl() + . rtrim($this->view->url(), '/') . '/' + . $href; + } + + return $this->_xmlEscape($url); + } + + /** + * Returns a DOMDocument containing the Sitemap XML for the given container + * + * @param Zend_Navigation_Container $container [optional] container to get + * breadcrumbs from, defaults + * to what is registered in the + * helper + * @return DOMDocument DOM representation of the + * container + * @throws Zend_View_Exception if schema validation is on + * and the sitemap is invalid + * according to the sitemap + * schema, or if sitemap + * validators are used and the + * loc element fails validation + */ + public function getDomSitemap(Zend_Navigation_Container $container = null) + { + if (null === $container) { + $container = $this->getContainer(); + } + + // check if we should validate using our own validators + if ($this->getUseSitemapValidators()) { + + // create validators + $locValidator = new Zend_Validate_Sitemap_Loc(); + $lastmodValidator = new Zend_Validate_Sitemap_Lastmod(); + $changefreqValidator = new Zend_Validate_Sitemap_Changefreq(); + $priorityValidator = new Zend_Validate_Sitemap_Priority(); + } + + // create document + $dom = new DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = $this->getFormatOutput(); + + // ...and urlset (root) element + $urlSet = $dom->createElementNS(self::SITEMAP_NS, 'urlset'); + $dom->appendChild($urlSet); + + // create iterator + $iterator = new RecursiveIteratorIterator($container, + RecursiveIteratorIterator::SELF_FIRST); + + $maxDepth = $this->getMaxDepth(); + if (is_int($maxDepth)) { + $iterator->setMaxDepth($maxDepth); + } + $minDepth = $this->getMinDepth(); + if (!is_int($minDepth) || $minDepth < 0) { + $minDepth = 0; + } + + // iterate container + foreach ($iterator as $page) { + if ($iterator->getDepth() < $minDepth || !$this->accept($page)) { + // page should not be included + continue; + } + + // get absolute url from page + if (!$url = $this->url($page)) { + // skip page if it has no url (rare case) + continue; + } + + // create url node for this page + $urlNode = $dom->createElementNS(self::SITEMAP_NS, 'url'); + $urlSet->appendChild($urlNode); + + if ($this->getUseSitemapValidators() && + !$locValidator->isValid($url)) { + $e = new Zend_View_Exception(sprintf( + 'Encountered an invalid URL for Sitemap XML: "%s"', + $url)); + $e->setView($this->view); + throw $e; + } + + // put url in 'loc' element + $urlNode->appendChild($dom->createElementNS(self::SITEMAP_NS, + 'loc', $url)); + + // add 'lastmod' element if a valid lastmod is set in page + if (isset($page->lastmod)) { + $lastmod = strtotime((string) $page->lastmod); + + // prevent 1970-01-01... + if ($lastmod !== false) { + $lastmod = date('c', $lastmod); + } + + if (!$this->getUseSitemapValidators() || + $lastmodValidator->isValid($lastmod)) { + $urlNode->appendChild( + $dom->createElementNS(self::SITEMAP_NS, 'lastmod', + $lastmod) + ); + } + } + + // add 'changefreq' element if a valid changefreq is set in page + if (isset($page->changefreq)) { + $changefreq = $page->changefreq; + if (!$this->getUseSitemapValidators() || + $changefreqValidator->isValid($changefreq)) { + $urlNode->appendChild( + $dom->createElementNS(self::SITEMAP_NS, 'changefreq', + $changefreq) + ); + } + } + + // add 'priority' element if a valid priority is set in page + if (isset($page->priority)) { + $priority = $page->priority; + if (!$this->getUseSitemapValidators() || + $priorityValidator->isValid($priority)) { + $urlNode->appendChild( + $dom->createElementNS(self::SITEMAP_NS, 'priority', + $priority) + ); + } + } + } + + // validate using schema if specified + if ($this->getUseSchemaValidation()) { + if (!@$dom->schemaValidate(self::SITEMAP_XSD)) { + $e = new Zend_View_Exception(sprintf( + 'Sitemap is invalid according to XML Schema at "%s"', + self::SITEMAP_XSD)); + $e->setView($this->view); + throw $e; + } + } + + return $dom; + } + + // Zend_View_Helper_Navigation_Helper: + + /** + * Renders helper + * + * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. + * + * @param Zend_Navigation_Container $container [optional] container to + * render. Default is to + * render the container + * registered in the helper. + * @return string helper output + */ + public function render(Zend_Navigation_Container $container = null) + { + $dom = $this->getDomSitemap($container); + + $xml = $this->getUseXmlDeclaration() ? + $dom->saveXML() : + $dom->saveXML($dom->documentElement); + + return rtrim($xml, self::EOL); + } +} diff --git a/library/vendor/Zend/View/Helper/PaginationControl.php b/library/vendor/Zend/View/Helper/PaginationControl.php new file mode 100644 index 000000000..b12505044 --- /dev/null +++ b/library/vendor/Zend/View/Helper/PaginationControl.php @@ -0,0 +1,142 @@ +view = $view; + return $this; + } + + /** + * Sets the default view partial. + * + * @param string|array $partial View partial + */ + public static function setDefaultViewPartial($partial) + { + self::$_defaultViewPartial = $partial; + } + + /** + * Gets the default view partial + * + * @return string|array + */ + public static function getDefaultViewPartial() + { + return self::$_defaultViewPartial; + } + + /** + * Render the provided pages. This checks if $view->paginator is set and, + * if so, uses that. Also, if no scrolling style or partial are specified, + * the defaults will be used (if set). + * + * @param Zend_Paginator (Optional) $paginator + * @param string $scrollingStyle (Optional) Scrolling style + * @param string $partial (Optional) View partial + * @param array|string $params (Optional) params to pass to the partial + * @return string + * @throws Zend_View_Exception + */ + public function paginationControl(Zend_Paginator $paginator = null, $scrollingStyle = null, $partial = null, $params = null) + { + if ($paginator === null) { + if (isset($this->view->paginator) and $this->view->paginator !== null and $this->view->paginator instanceof Zend_Paginator) { + $paginator = $this->view->paginator; + } else { + /** + * @see Zend_View_Exception + */ + + $e = new Zend_View_Exception('No paginator instance provided or incorrect type'); + $e->setView($this->view); + throw $e; + } + } + + if ($partial === null) { + if (self::$_defaultViewPartial === null) { + /** + * @see Zend_View_Exception + */ + $e = new Zend_View_Exception('No view partial provided and no default set'); + $e->setView($this->view); + throw $e; + } + + $partial = self::$_defaultViewPartial; + } + + $pages = get_object_vars($paginator->getPages($scrollingStyle)); + + if ($params !== null) { + $pages = array_merge($pages, (array) $params); + } + + if (is_array($partial)) { + if (count($partial) != 2) { + /** + * @see Zend_View_Exception + */ + $e = new Zend_View_Exception('A view partial supplied as an array must contain two values: the filename and its module'); + $e->setView($this->view); + throw $e; + } + + if ($partial[1] !== null) { + return $this->view->partial($partial[0], $partial[1], $pages); + } + + $partial = $partial[0]; + } + + return $this->view->partial($partial, $pages); + } +} diff --git a/library/vendor/Zend/View/Helper/Partial.php b/library/vendor/Zend/View/Helper/Partial.php new file mode 100644 index 000000000..b726f3d7a --- /dev/null +++ b/library/vendor/Zend/View/Helper/Partial.php @@ -0,0 +1,150 @@ +cloneView(); + if (isset($this->partialCounter)) { + $view->partialCounter = $this->partialCounter; + } + if (isset($this->partialTotalCount)) { + $view->partialTotalCount = $this->partialTotalCount; + } + + if ((null !== $module) && is_string($module)) { + $moduleDir = Zend_Controller_Front::getInstance()->getControllerDirectory($module); + if (null === $moduleDir) { + $e = new Zend_View_Helper_Partial_Exception('Cannot render partial; module does not exist'); + $e->setView($this->view); + throw $e; + } + $viewsDir = dirname($moduleDir) . '/views'; + $view->addBasePath($viewsDir); + } elseif ((null == $model) && (null !== $module) + && (is_array($module) || is_object($module))) + { + $model = $module; + } + + if (!empty($model)) { + if (is_array($model)) { + $view->assign($model); + } elseif (is_object($model)) { + if (null !== ($objectKey = $this->getObjectKey())) { + $view->assign($objectKey, $model); + } elseif (method_exists($model, 'toArray')) { + $view->assign($model->toArray()); + } else { + $view->assign(get_object_vars($model)); + } + } + } + + return $view->render($name); + } + + /** + * Clone the current View + * + * @return Zend_View_Interface + */ + public function cloneView() + { + $view = clone $this->view; + $view->clearVars(); + return $view; + } + + /** + * Set object key + * + * @param string $key + * @return Zend_View_Helper_Partial + */ + public function setObjectKey($key) + { + if (null === $key) { + $this->_objectKey = null; + } else { + $this->_objectKey = (string) $key; + } + + return $this; + } + + /** + * Retrieve object key + * + * The objectKey is the variable to which an object in the iterator will be + * assigned. + * + * @return null|string + */ + public function getObjectKey() + { + return $this->_objectKey; + } +} diff --git a/library/vendor/Zend/View/Helper/Partial/Exception.php b/library/vendor/Zend/View/Helper/Partial/Exception.php new file mode 100644 index 000000000..a4ed78b28 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Partial/Exception.php @@ -0,0 +1,38 @@ +setView($this->view); + throw $e; + } + + if (is_object($model) + && (!$model instanceof Traversable) + && method_exists($model, 'toArray') + ) { + $model = $model->toArray(); + } + + $content = ''; + // reset the counter if it's call again + $this->partialCounter = 0; + $this->partialTotalCount = count($model); + + foreach ($model as $item) { + // increment the counter variable + $this->partialCounter++; + + $content .= $this->partial($name, $module, $item); + } + + return $content; + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder.php b/library/vendor/Zend/View/Helper/Placeholder.php new file mode 100644 index 000000000..c9122de30 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder.php @@ -0,0 +1,85 @@ +_registry = Zend_View_Helper_Placeholder_Registry::getRegistry(); + } + + + /** + * Placeholder helper + * + * @param string $name + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function placeholder($name) + { + $name = (string) $name; + return $this->_registry->getContainer($name); + } + + /** + * Retrieve the registry + * + * @return Zend_View_Helper_Placeholder_Registry + */ + public function getRegistry() + { + return $this->_registry; + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Container.php b/library/vendor/Zend/View/Helper/Placeholder/Container.php new file mode 100644 index 000000000..56e015d96 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Container.php @@ -0,0 +1,35 @@ +exchangeArray(array($value)); + } + + /** + * Prepend a value to the top of the container + * + * @param mixed $value + * @return void + */ + public function prepend($value) + { + $values = $this->getArrayCopy(); + array_unshift($values, $value); + $this->exchangeArray($values); + } + + /** + * Retrieve container value + * + * If single element registered, returns that element; otherwise, + * serializes to array. + * + * @return mixed + */ + public function getValue() + { + if (1 == count($this)) { + $keys = $this->getKeys(); + $key = array_shift($keys); + return $this[$key]; + } + + return $this->getArrayCopy(); + } + + /** + * Set prefix for __toString() serialization + * + * @param string $prefix + * @return Zend_View_Helper_Placeholder_Container + */ + public function setPrefix($prefix) + { + $this->_prefix = (string) $prefix; + return $this; + } + + /** + * Retrieve prefix + * + * @return string + */ + public function getPrefix() + { + return $this->_prefix; + } + + /** + * Set postfix for __toString() serialization + * + * @param string $postfix + * @return Zend_View_Helper_Placeholder_Container + */ + public function setPostfix($postfix) + { + $this->_postfix = (string) $postfix; + return $this; + } + + /** + * Retrieve postfix + * + * @return string + */ + public function getPostfix() + { + return $this->_postfix; + } + + /** + * Set separator for __toString() serialization + * + * Used to implode elements in container + * + * @param string $separator + * @return Zend_View_Helper_Placeholder_Container + */ + public function setSeparator($separator) + { + $this->_separator = (string) $separator; + return $this; + } + + /** + * Retrieve separator + * + * @return string + */ + public function getSeparator() + { + return $this->_separator; + } + + /** + * Set the indentation string for __toString() serialization, + * optionally, if a number is passed, it will be the number of spaces + * + * @param string|int $indent + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function setIndent($indent) + { + $this->_indent = $this->getWhitespace($indent); + return $this; + } + + /** + * Retrieve indentation + * + * @return string + */ + public function getIndent() + { + return $this->_indent; + } + + /** + * Retrieve whitespace representation of $indent + * + * @param int|string $indent + * @return string + */ + public function getWhitespace($indent) + { + if (is_int($indent)) { + $indent = str_repeat(' ', $indent); + } + + return (string) $indent; + } + + /** + * Start capturing content to push into placeholder + * + * @param int|string $type How to capture content into placeholder; append, prepend, or set + * @param null $key + * @throws Zend_View_Helper_Placeholder_Container_Exception + * @return void + */ + public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $key = null) + { + if ($this->_captureLock) { + $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest placeholder captures for the same placeholder'); + $e->setView($this->view); + throw $e; + } + + $this->_captureLock = true; + $this->_captureType = $type; + if ((null !== $key) && is_scalar($key)) { + $this->_captureKey = (string) $key; + } + ob_start(); + } + + /** + * End content capture + * + * @return void + */ + public function captureEnd() + { + $data = ob_get_clean(); + $key = null; + $this->_captureLock = false; + if (null !== $this->_captureKey) { + $key = $this->_captureKey; + } + switch ($this->_captureType) { + case self::SET: + if (null !== $key) { + $this[$key] = $data; + } else { + $this->exchangeArray(array($data)); + } + break; + case self::PREPEND: + if (null !== $key) { + $array = array($key => $data); + $values = $this->getArrayCopy(); + $final = $array + $values; + $this->exchangeArray($final); + } else { + $this->prepend($data); + } + break; + case self::APPEND: + default: + if (null !== $key) { + if (empty($this[$key])) { + $this[$key] = $data; + } else { + $this[$key] .= $data; + } + } else { + $this[$this->nextIndex()] = $data; + } + break; + } + } + + /** + * Get keys + * + * @return array + */ + public function getKeys() + { + $array = $this->getArrayCopy(); + return array_keys($array); + } + + /** + * Next Index + * + * as defined by the PHP manual + * @return int + */ + public function nextIndex() + { + $keys = $this->getKeys(); + if (0 == count($keys)) { + return 0; + } + + return $nextIndex = max($keys) + 1; + } + + /** + * Render the placeholder + * + * @param null $indent + * @return string + */ + public function toString($indent = null) + { + // Check items + if (0 === $this->count()) { + return ''; + } + + $indent = ($indent !== null) + ? $this->getWhitespace($indent) + : $this->getIndent(); + + $items = $this->getArrayCopy(); + $return = $indent + . $this->getPrefix() + . implode($this->getSeparator(), $items) + . $this->getPostfix(); + $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); + return $return; + } + + /** + * Serialize object to string + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php b/library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php new file mode 100644 index 000000000..ceb40d352 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Container/Exception.php @@ -0,0 +1,38 @@ +setRegistry(Zend_View_Helper_Placeholder_Registry::getRegistry()); + $this->setContainer($this->getRegistry()->getContainer($this->_regKey)); + } + + /** + * Retrieve registry + * + * @return Zend_View_Helper_Placeholder_Registry + */ + public function getRegistry() + { + return $this->_registry; + } + + /** + * Set registry object + * + * @param Zend_View_Helper_Placeholder_Registry $registry + * @return Zend_View_Helper_Placeholder_Container_Standalone + */ + public function setRegistry(Zend_View_Helper_Placeholder_Registry $registry) + { + $this->_registry = $registry; + return $this; + } + + /** + * Set whether or not auto escaping should be used + * + * @param bool $autoEscape whether or not to auto escape output + * @return Zend_View_Helper_Placeholder_Container_Standalone + */ + public function setAutoEscape($autoEscape = true) + { + $this->_autoEscape = ($autoEscape) ? true : false; + return $this; + } + + /** + * Return whether autoEscaping is enabled or disabled + * + * return bool + */ + public function getAutoEscape() + { + return $this->_autoEscape; + } + + /** + * Escape a string + * + * @param string $string + * @return string + */ + protected function _escape($string) + { + $enc = 'UTF-8'; + if ($this->view instanceof Zend_View_Interface + && method_exists($this->view, 'getEncoding') + ) { + $enc = $this->view->getEncoding(); + } + + return htmlspecialchars((string) $string, ENT_COMPAT, $enc); + } + + /** + * Set container on which to operate + * + * @param Zend_View_Helper_Placeholder_Container_Abstract $container + * @return Zend_View_Helper_Placeholder_Container_Standalone + */ + public function setContainer(Zend_View_Helper_Placeholder_Container_Abstract $container) + { + $this->_container = $container; + return $this; + } + + /** + * Retrieve placeholder container + * + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function getContainer() + { + return $this->_container; + } + + /** + * Overloading: set property value + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $container = $this->getContainer(); + $container[$key] = $value; + } + + /** + * Overloading: retrieve property + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + $container = $this->getContainer(); + if (isset($container[$key])) { + return $container[$key]; + } + + return null; + } + + /** + * Overloading: check if property is set + * + * @param string $key + * @return bool + */ + public function __isset($key) + { + $container = $this->getContainer(); + return isset($container[$key]); + } + + /** + * Overloading: unset property + * + * @param string $key + * @return void + */ + public function __unset($key) + { + $container = $this->getContainer(); + if (isset($container[$key])) { + unset($container[$key]); + } + } + + /** + * Overload + * + * Proxy to container methods + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + $container = $this->getContainer(); + if (method_exists($container, $method)) { + $return = call_user_func_array(array($container, $method), $args); + if ($return === $container) { + // If the container is returned, we really want the current object + return $this; + } + return $return; + } + + $e = new Zend_View_Exception('Method "' . $method . '" does not exist'); + $e->setView($this->view); + throw $e; + } + + /** + * String representation + * + * @return string + */ + public function toString() + { + return $this->getContainer()->toString(); + } + + /** + * Cast to string representation + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Countable + * + * @return int + */ + public function count() + { + $container = $this->getContainer(); + return count($container); + } + + /** + * ArrayAccess: offsetExists + * + * @param string|int $offset + * @return bool + */ + public function offsetExists($offset) + { + return $this->getContainer()->offsetExists($offset); + } + + /** + * ArrayAccess: offsetGet + * + * @param string|int $offset + * @return mixed + */ + public function offsetGet($offset) + { + return $this->getContainer()->offsetGet($offset); + } + + /** + * ArrayAccess: offsetSet + * + * @param string|int $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset, $value) + { + return $this->getContainer()->offsetSet($offset, $value); + } + + /** + * ArrayAccess: offsetUnset + * + * @param string|int $offset + * @return void + */ + public function offsetUnset($offset) + { + return $this->getContainer()->offsetUnset($offset); + } + + /** + * IteratorAggregate: get Iterator + * + * @return Iterator + */ + public function getIterator() + { + return $this->getContainer()->getIterator(); + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Registry.php b/library/vendor/Zend/View/Helper/Placeholder/Registry.php new file mode 100644 index 000000000..2e3f9ef34 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Registry.php @@ -0,0 +1,183 @@ +_items[$key] = new $this->_containerClass($value); + return $this->_items[$key]; + } + + /** + * Retrieve a placeholder container + * + * @param string $key + * @return Zend_View_Helper_Placeholder_Container_Abstract + */ + public function getContainer($key) + { + $key = (string) $key; + if (isset($this->_items[$key])) { + return $this->_items[$key]; + } + + $container = $this->createContainer($key); + + return $container; + } + + /** + * Does a particular container exist? + * + * @param string $key + * @return bool + */ + public function containerExists($key) + { + $key = (string) $key; + $return = array_key_exists($key, $this->_items); + return $return; + } + + /** + * Set the container for an item in the registry + * + * @param string $key + * @param Zend_View_Placeholder_Container_Abstract $container + * @return Zend_View_Placeholder_Registry + */ + public function setContainer($key, Zend_View_Helper_Placeholder_Container_Abstract $container) + { + $key = (string) $key; + $this->_items[$key] = $container; + return $this; + } + + /** + * Delete a container + * + * @param string $key + * @return bool + */ + public function deleteContainer($key) + { + $key = (string) $key; + if (isset($this->_items[$key])) { + unset($this->_items[$key]); + return true; + } + + return false; + } + + /** + * Set the container class to use + * + * @param string $name + * @return Zend_View_Helper_Placeholder_Registry + */ + public function setContainerClass($name) + { + if (!class_exists($name)) { + Zend_Loader::loadClass($name); + } + + $reflection = new ReflectionClass($name); + if (!$reflection->isSubclassOf(new ReflectionClass('Zend_View_Helper_Placeholder_Container_Abstract'))) { + $e = new Zend_View_Helper_Placeholder_Registry_Exception('Invalid Container class specified'); + $e->setView($this->view); + throw $e; + } + + $this->_containerClass = $name; + return $this; + } + + /** + * Retrieve the container class + * + * @return string + */ + public function getContainerClass() + { + return $this->_containerClass; + } +} diff --git a/library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php b/library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php new file mode 100644 index 000000000..a96f7ee0d --- /dev/null +++ b/library/vendor/Zend/View/Helper/Placeholder/Registry/Exception.php @@ -0,0 +1,38 @@ +view->placeholder($placeholder)->captureStart(); + echo $this->view->render($script); + $this->view->placeholder($placeholder)->captureEnd(); + } +} diff --git a/library/vendor/Zend/View/Helper/ServerUrl.php b/library/vendor/Zend/View/Helper/ServerUrl.php new file mode 100644 index 000000000..75fabf72f --- /dev/null +++ b/library/vendor/Zend/View/Helper/ServerUrl.php @@ -0,0 +1,148 @@ +setScheme($scheme); + + if (isset($_SERVER['HTTP_HOST']) && !empty($_SERVER['HTTP_HOST'])) { + $this->setHost($_SERVER['HTTP_HOST']); + } else if (isset($_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'])) { + $name = $_SERVER['SERVER_NAME']; + $port = $_SERVER['SERVER_PORT']; + + if (($scheme == 'http' && $port == 80) || + ($scheme == 'https' && $port == 443)) { + $this->setHost($name); + } else { + $this->setHost($name . ':' . $port); + } + } + } + + /** + * View helper entry point: + * Returns the current host's URL like http://site.com + * + * @param string|boolean $requestUri [optional] if true, the request URI + * found in $_SERVER will be appended + * as a path. If a string is given, it + * will be appended as a path. Default + * is to not append any path. + * @return string server url + */ + public function serverUrl($requestUri = null) + { + if ($requestUri === true) { + $path = $_SERVER['REQUEST_URI']; + } else if (is_string($requestUri)) { + $path = $requestUri; + } else { + $path = ''; + } + + return $this->getScheme() . '://' . $this->getHost() . $path; + } + + /** + * Returns host + * + * @return string host + */ + public function getHost() + { + return $this->_host; + } + + /** + * Sets host + * + * @param string $host new host + * @return Zend_View_Helper_ServerUrl fluent interface, returns self + */ + public function setHost($host) + { + $this->_host = $host; + return $this; + } + + /** + * Returns scheme (typically http or https) + * + * @return string scheme (typically http or https) + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * Sets scheme (typically http or https) + * + * @param string $scheme new scheme (typically http or https) + * @return Zend_View_Helper_ServerUrl fluent interface, returns self + */ + public function setScheme($scheme) + { + $this->_scheme = $scheme; + return $this; + } +} diff --git a/library/vendor/Zend/View/Helper/Translate.php b/library/vendor/Zend/View/Helper/Translate.php new file mode 100644 index 000000000..817233f51 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Translate.php @@ -0,0 +1,174 @@ +setTranslator($translate); + } + } + + /** + * Translate a message + * You can give multiple params or an array of params. + * If you want to output another locale just set it as last single parameter + * Example 1: translate('%1\$s + %2\$s', $value1, $value2, $locale); + * Example 2: translate('%1\$s + %2\$s', array($value1, $value2), $locale); + * + * @param string $messageid Id of the message to be translated + * @return string|Zend_View_Helper_Translate Translated message + */ + public function translate($messageid = null) + { + if ($messageid === null) { + return $this; + } + + $translate = $this->getTranslator(); + $options = func_get_args(); + + array_shift($options); + $count = count($options); + $locale = null; + if ($count > 0) { + if (Zend_Locale::isLocale($options[($count - 1)], null, false) !== false) { + $locale = array_pop($options); + } + } + + if ((count($options) === 1) and (is_array($options[0]) === true)) { + $options = $options[0]; + } + + if ($translate !== null) { + $messageid = $translate->translate($messageid, $locale); + } + + if (count($options) === 0) { + return $messageid; + } + + return vsprintf($messageid, $options); + } + + /** + * Sets a translation Adapter for translation + * + * @param Zend_Translate|Zend_Translate_Adapter $translate Instance of Zend_Translate + * @throws Zend_View_Exception When no or a false instance was set + * @return Zend_View_Helper_Translate + */ + public function setTranslator($translate) + { + if ($translate instanceof Zend_Translate_Adapter) { + $this->_translator = $translate; + } else if ($translate instanceof Zend_Translate) { + $this->_translator = $translate->getAdapter(); + } else { + $e = new Zend_View_Exception('You must set an instance of Zend_Translate or Zend_Translate_Adapter'); + $e->setView($this->view); + throw $e; + } + + return $this; + } + + /** + * Retrieve translation object + * + * @return Zend_Translate_Adapter|null + */ + public function getTranslator() + { + if ($this->_translator === null) { + if (Zend_Registry::isRegistered('Zend_Translate')) { + $this->setTranslator(Zend_Registry::get('Zend_Translate')); + } + } + + return $this->_translator; + } + + /** + * Set's an new locale for all further translations + * + * @param string|Zend_Locale $locale New locale to set + * @throws Zend_View_Exception When no Zend_Translate instance was set + * @return Zend_View_Helper_Translate + */ + public function setLocale($locale = null) + { + $translate = $this->getTranslator(); + if ($translate === null) { + $e = new Zend_View_Exception('You must set an instance of Zend_Translate or Zend_Translate_Adapter'); + $e->setView($this->view); + throw $e; + } + + $translate->setLocale($locale); + return $this; + } + + /** + * Returns the set locale for translations + * + * @throws Zend_View_Exception When no Zend_Translate instance was set + * @return string|Zend_Locale + */ + public function getLocale() + { + $translate = $this->getTranslator(); + if ($translate === null) { + $e = new Zend_View_Exception('You must set an instance of Zend_Translate or Zend_Translate_Adapter'); + $e->setView($this->view); + throw $e; + } + + return $translate->getLocale(); + } +} diff --git a/library/vendor/Zend/View/Helper/Url.php b/library/vendor/Zend/View/Helper/Url.php new file mode 100644 index 000000000..a8cf4e022 --- /dev/null +++ b/library/vendor/Zend/View/Helper/Url.php @@ -0,0 +1,50 @@ +getRouter(); + return $router->assemble($urlOptions, $name, $reset, $encode); + } +} diff --git a/library/vendor/Zend/View/Helper/UserAgent.php b/library/vendor/Zend/View/Helper/UserAgent.php new file mode 100644 index 000000000..1c0cae977 --- /dev/null +++ b/library/vendor/Zend/View/Helper/UserAgent.php @@ -0,0 +1,81 @@ +setUserAgent($userAgent); + } + return $this->getUserAgent(); + } + + /** + * Set UserAgent instance + * + * @param Zend_Http_UserAgent $userAgent + * @return Zend_View_Helper_UserAgent + */ + public function setUserAgent(Zend_Http_UserAgent $userAgent) + { + $this->_userAgent = $userAgent; + return $this; + } + + /** + * Retrieve UserAgent instance + * + * If none set, instantiates one using no configuration + * + * @return Zend_Http_UserAgent + */ + public function getUserAgent() + { + if (null === $this->_userAgent) { + $this->setUserAgent(new Zend_Http_UserAgent()); + } + return $this->_userAgent; + } +} diff --git a/library/vendor/Zend/View/Interface.php b/library/vendor/Zend/View/Interface.php new file mode 100644 index 000000000..7ff43b96c --- /dev/null +++ b/library/vendor/Zend/View/Interface.php @@ -0,0 +1,137 @@ + value pairs to set en + * masse. + * + * @see __set() + * @param string|array $spec The assignment strategy to use (key or array of key + * => value pairs) + * @param mixed $value (Optional) If assigning a named variable, use this + * as the value. + * @return void + */ + public function assign($spec, $value = null); + + /** + * Clear all assigned variables + * + * Clears all variables assigned to Zend_View either via {@link assign()} or + * property overloading ({@link __get()}/{@link __set()}). + * + * @return void + */ + public function clearVars(); + + /** + * Processes a view script and returns the output. + * + * @param string $name The script name to process. + * @return string The script output. + */ + public function render($name); +} diff --git a/library/vendor/Zend/View/Stream.php b/library/vendor/Zend/View/Stream.php new file mode 100644 index 000000000..b1467a5d0 --- /dev/null +++ b/library/vendor/Zend/View/Stream.php @@ -0,0 +1,183 @@ +_data = file_get_contents($path); + + /** + * If reading the file failed, update our local stat store + * to reflect the real stat of the file, then return on failure + */ + if ($this->_data === false) { + $this->_stat = stat($path); + return false; + } + + /** + * Convert to long-form and to + * + */ + $this->_data = preg_replace('/\<\?\=/', "_data); + $this->_data = preg_replace('/<\?(?!xml|php)/s', '_data); + + /** + * file_get_contents() won't update PHP's stat cache, so we grab a stat + * of the file to prevent additional reads should the script be + * requested again, which will make include() happy. + */ + $this->_stat = stat($path); + + return true; + } + + /** + * Included so that __FILE__ returns the appropriate info + * + * @return array + */ + public function url_stat() + { + return $this->_stat; + } + + /** + * Reads from the stream. + */ + public function stream_read($count) + { + $ret = substr($this->_data, $this->_pos, $count); + $this->_pos += strlen($ret); + return $ret; + } + + + /** + * Tells the current position in the stream. + */ + public function stream_tell() + { + return $this->_pos; + } + + + /** + * Tells if we are at the end of the stream. + */ + public function stream_eof() + { + return $this->_pos >= strlen($this->_data); + } + + + /** + * Stream statistics. + */ + public function stream_stat() + { + return $this->_stat; + } + + + /** + * Seek to a specific point in the stream. + */ + public function stream_seek($offset, $whence) + { + switch ($whence) { + case SEEK_SET: + if ($offset < strlen($this->_data) && $offset >= 0) { + $this->_pos = $offset; + return true; + } else { + return false; + } + break; + + case SEEK_CUR: + if ($offset >= 0) { + $this->_pos += $offset; + return true; + } else { + return false; + } + break; + + case SEEK_END: + if (strlen($this->_data) + $offset >= 0) { + $this->_pos = strlen($this->_data) + $offset; + return true; + } else { + return false; + } + break; + + default: + return false; + } + } +} diff --git a/library/vendor/Zend/Wildfire/Channel/HttpHeaders.php b/library/vendor/Zend/Wildfire/Channel/HttpHeaders.php new file mode 100644 index 000000000..6a25bcbde --- /dev/null +++ b/library/vendor/Zend/Wildfire/Channel/HttpHeaders.php @@ -0,0 +1,330 @@ +_protocols[$uri])) { + $this->_protocols[$uri] = $this->_initProtocol($uri); + } + + $this->_registerControllerPlugin(); + + return $this->_protocols[$uri]; + } + + /** + * Initialize a new protocol + * + * @param string $uri The URI for the protocol to be initialized + * @return object Returns the new initialized protocol instance + * @throws Zend_Wildfire_Exception + */ + protected function _initProtocol($uri) + { + switch ($uri) { + case Zend_Wildfire_Protocol_JsonStream::PROTOCOL_URI; + return new Zend_Wildfire_Protocol_JsonStream(); + } + throw new Zend_Wildfire_Exception('Tyring to initialize unknown protocol for URI "'.$uri.'".'); + } + + + /** + * Flush all data from all protocols and send all data to response headers. + * + * @return boolean Returns TRUE if data was flushed + */ + public function flush() + { + if (!$this->_protocols || !$this->isReady()) { + return false; + } + + foreach ( $this->_protocols as $protocol ) { + + $payload = $protocol->getPayload($this); + + if ($payload) { + foreach( $payload as $message ) { + + $this->getResponse()->setHeader(self::$_headerPrefix.$message[0], + $message[1], true); + } + } + } + return true; + } + + /** + * Set the index of the plugin in the controller dispatch loop plugin stack + * + * @param integer $index The index of the plugin in the stack + * @return integer The previous index. + */ + public static function setControllerPluginStackIndex($index) + { + $previous = self::$_controllerPluginStackIndex; + self::$_controllerPluginStackIndex = $index; + return $previous; + } + + /** + * Register this object as a controller plugin. + * + * @return void + */ + protected function _registerControllerPlugin() + { + $controller = Zend_Controller_Front::getInstance(); + if (!$controller->hasPlugin(get_class($this))) { + $controller->registerPlugin($this, self::$_controllerPluginStackIndex); + } + } + + + /* + * Zend_Wildfire_Channel_Interface + */ + + /** + * Determine if channel is ready. + * + * The channel is ready as long as the request and response objects are initialized, + * can send headers and the FirePHP header exists in the User-Agent. + * + * If the header does not exist in the User-Agent, no appropriate client + * is making this request and the messages should not be sent. + * + * A timing issue arises when messages are logged before the request/response + * objects are initialized. In this case we do not yet know if the client + * will be able to accept the messages. If we consequently indicate that + * the channel is not ready, these messages will be dropped which is in + * most cases not the intended behaviour. The intent is to send them at the + * end of the request when the request/response objects will be available + * for sure. + * + * If the request/response objects are not yet initialized we assume if messages are + * logged, the client will be able to receive them. As soon as the request/response + * objects are availoable and a message is logged this assumption is challenged. + * If the client cannot accept the messages any further messages are dropped + * and messages sent prior are kept but discarded when the channel is finally + * flushed at the end of the request. + * + * When the channel is flushed the $forceCheckRequest option is used to force + * a check of the request/response objects. This is the last verification to ensure + * messages are only sent when the client can accept them. + * + * @param boolean $forceCheckRequest OPTIONAL Set to TRUE if the request must be checked + * @return boolean Returns TRUE if channel is ready. + */ + public function isReady($forceCheckRequest=false) + { + if (!$forceCheckRequest + && !$this->_request + && !$this->_response + ) { + return true; + } + + if (!($this->getRequest() instanceof Zend_Controller_Request_Http)) { + return false; + } + + return ($this->getResponse()->canSendHeaders() + && (preg_match_all( + '/\s?FirePHP\/([\.\d]*)\s?/si', + $this->getRequest()->getHeader('User-Agent'), + $m + ) || + (($header = $this->getRequest()->getHeader('X-FirePHP-Version')) + && preg_match_all('/^([\.\d]*)$/si', $header, $m) + )) + ); + } + + + /* + * Zend_Controller_Plugin_Abstract + */ + + /** + * Flush messages to headers as late as possible but before headers have been sent. + * + * @return void + */ + public function dispatchLoopShutdown() + { + $this->flush(); + } + + /** + * Get the request object + * + * @return Zend_Controller_Request_Abstract + * @throws Zend_Wildfire_Exception + */ + public function getRequest() + { + if (!$this->_request) { + $controller = Zend_Controller_Front::getInstance(); + $this->setRequest($controller->getRequest()); + } + if (!$this->_request) { + throw new Zend_Wildfire_Exception('Request objects not initialized.'); + } + return $this->_request; + } + + /** + * Get the response object + * + * @return Zend_Controller_Response_Abstract + * @throws Zend_Wildfire_Exception + */ + public function getResponse() + { + if (!$this->_response) { + $response = Zend_Controller_Front::getInstance()->getResponse(); + if ($response) { + $this->setResponse($response); + } + } + if (!$this->_response) { + throw new Zend_Wildfire_Exception('Response objects not initialized.'); + } + return $this->_response; + } +} diff --git a/library/vendor/Zend/Wildfire/Channel/Interface.php b/library/vendor/Zend/Wildfire/Channel/Interface.php new file mode 100644 index 000000000..916282d17 --- /dev/null +++ b/library/vendor/Zend/Wildfire/Channel/Interface.php @@ -0,0 +1,38 @@ + 1, /* The offset in the trace which identifies the source of the message */ + 'maxTraceDepth' => 99, /* Maximum depth for stack traces */ + 'maxObjectDepth' => 10, /* The maximum depth to traverse objects when encoding */ + 'maxArrayDepth' => 20, /* The maximum depth to traverse nested arrays when encoding */ + 'includeLineNumbers' => true /* Whether to include line and file info for each message */ + ); + + /** + * Filters used to exclude object members when encoding + * @var array + */ + protected $_objectFilters = array(); + + /** + * A stack of objects used during encoding to detect recursion + * @var array + */ + protected $_objectStack = array(); + + /** + * Create singleton instance. + * + * @param string $class OPTIONAL Subclass of Zend_Wildfire_Plugin_FirePhp + * @return Zend_Wildfire_Plugin_FirePhp Returns the singleton Zend_Wildfire_Plugin_FirePhp instance + * @throws Zend_Wildfire_Exception + */ + public static function init($class = null) + { + if (self::$_instance !== null) { + throw new Zend_Wildfire_Exception('Singleton instance of Zend_Wildfire_Plugin_FirePhp already exists!'); + } + if ($class !== null) { + if (!is_string($class)) { + throw new Zend_Wildfire_Exception('Third argument is not a class string'); + } + + if (!class_exists($class)) { + Zend_Loader::loadClass($class); + } + self::$_instance = new $class(); + if (!self::$_instance instanceof Zend_Wildfire_Plugin_FirePhp) { + self::$_instance = null; + throw new Zend_Wildfire_Exception('Invalid class to third argument. Must be subclass of Zend_Wildfire_Plugin_FirePhp.'); + } + } else { + self::$_instance = new self(); + } + + return self::$_instance; + } + + /** + * Constructor + * @return void + */ + protected function __construct() + { + $this->_channel = Zend_Wildfire_Channel_HttpHeaders::getInstance(); + $this->_channel->getProtocol(self::PROTOCOL_URI)->registerPlugin($this); + } + + /** + * Get or create singleton instance + * + * @param bool $skipCreate True if an instance should not be created + * @return Zend_Wildfire_Plugin_FirePhp + */ + public static function getInstance($skipCreate=false) + { + if (self::$_instance===null && $skipCreate!==true) { + return self::init(); + } + return self::$_instance; + } + + /** + * Destroys the singleton instance + * + * Primarily used for testing. + * + * @return void + */ + public static function destroyInstance() + { + self::$_instance = null; + } + + /** + * Enable or disable sending of messages to user-agent. + * If disabled all headers to be sent will be removed. + * + * @param boolean $enabled Set to TRUE to enable sending of messages. + * @return boolean The previous value. + */ + public function setEnabled($enabled) + { + $previous = $this->_enabled; + $this->_enabled = $enabled; + if (!$this->_enabled) { + $this->_messages = array(); + $this->_channel->getProtocol(self::PROTOCOL_URI)->clearMessages($this); + } + return $previous; + } + + /** + * Determine if logging to user-agent is enabled. + * + * @return boolean Returns TRUE if logging is enabled. + */ + public function getEnabled() + { + return $this->_enabled; + } + + /** + * Set a single option + * + * @param string $key The name of the option + * @param mixed $value The value of the option + * @return mixed The previous value of the option + */ + public function setOption($key, $value) + { + if (!array_key_exists($key,$this->_options)) { + throw new Zend_Wildfire_Exception('Option with name "'.$key.'" does not exist!'); + } + $previous = $this->_options[$key]; + $this->_options[$key] = $value; + return $previous; + } + + /** + * Retrieve a single option + * + * @param string $key The name of the option + * @return mixed The value of the option + */ + public function getOption($key) + { + if (!array_key_exists($key,$this->_options)) { + throw new Zend_Wildfire_Exception('Option with name "'.$key.'" does not exist!'); + } + return $this->_options[$key]; + } + + /** + * Retrieve all options + * + * @return array All options + */ + public function getOptions() + { + return $this->_options; + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @param string $Class The class name of the object + * @param array $Filter An array of members to exclude + * @return void + */ + public function setObjectFilter($class, $filter) { + $this->_objectFilters[$class] = $filter; + } + + /** + * Starts a group in the Firebug Console + * + * @param string $title The title of the group + * @param array $options OPTIONAL Setting 'Collapsed' to true will initialize group collapsed instead of expanded + * @return TRUE if the group instruction was added to the response headers or buffered. + */ + public static function group($title, $options=array()) + { + return self::send(null, $title, self::GROUP_START, $options); + } + + /** + * Ends a group in the Firebug Console + * + * @return TRUE if the group instruction was added to the response headers or buffered. + */ + public static function groupEnd() + { + return self::send(null, null, self::GROUP_END); + } + + /** + * Logs variables to the Firebug Console + * via HTTP response headers and the FirePHP Firefox Extension. + * + * @param mixed $var The variable to log. + * @param string $label OPTIONAL Label to prepend to the log event. + * @param string $style OPTIONAL Style of the log event. + * @param array $options OPTIONAL Options to change how messages are processed and sent + * @return boolean Returns TRUE if the variable was added to the response headers or buffered. + * @throws Zend_Wildfire_Exception + */ + public static function send($var, $label=null, $style=null, $options=array()) + { + $firephp = self::getInstance(); + + if (!$firephp->getEnabled()) { + return false; + } + + if ($var instanceof Zend_Wildfire_Plugin_FirePhp_Message) { + + if ($var->getBuffered()) { + if (!in_array($var, self::$_instance->_messages)) { + self::$_instance->_messages[] = $var; + } + return true; + } + + if ($var->getDestroy()) { + return false; + } + + $style = $var->getStyle(); + $label = $var->getLabel(); + $options = $var->getOptions(); + $var = $var->getMessage(); + } + + if (!self::$_instance->_channel->isReady()) { + return false; + } + + foreach ($options as $name => $value) { + if ($value===null) { + unset($options[$name]); + } + } + $options = array_merge($firephp->getOptions(), $options); + + $trace = null; + + $skipFinalEncode = false; + + $meta = array(); + $meta['Type'] = $style; + + if ($var instanceof Exception) { + + $eTrace = $var->getTrace(); + $eTrace = array_splice($eTrace, 0, $options['maxTraceDepth']); + + $var = array('Class'=>get_class($var), + 'Message'=>$var->getMessage(), + 'File'=>$var->getFile(), + 'Line'=>$var->getLine(), + 'Type'=>'throw', + 'Trace'=>$firephp->_encodeTrace($eTrace)); + + $meta['Type'] = self::EXCEPTION; + + $skipFinalEncode = true; + + } else + if ($meta['Type']==self::TRACE) { + + if (!$label && $var) { + $label = $var; + $var = null; + } + + if (!$trace) { + $trace = $firephp->_getStackTrace(array_merge($options, + array('maxTraceDepth'=>$options['maxTraceDepth']+1))); + } + + $var = array('Class'=>$trace[0]['class'], + 'Type'=>$trace[0]['type'], + 'Function'=>$trace[0]['function'], + 'Message'=>$label, + 'File'=>isset($trace[0]['file'])?$trace[0]['file']:'', + 'Line'=>isset($trace[0]['line'])?$trace[0]['line']:'', + 'Args'=>isset($trace[0]['args'])?$firephp->_encodeObject($trace[0]['args']):'', + 'Trace'=>$firephp->_encodeTrace(array_splice($trace,1))); + + $skipFinalEncode = true; + + } else + if ($meta['Type']==self::TABLE) { + + $var = $firephp->_encodeTable($var); + + $skipFinalEncode = true; + + } else { + if ($meta['Type']===null) { + $meta['Type'] = self::LOG; + } + } + + if ($label!=null) { + $meta['Label'] = $label; + } + + switch ($meta['Type']) { + case self::LOG: + case self::INFO: + case self::WARN: + case self::ERROR: + case self::EXCEPTION: + case self::TRACE: + case self::TABLE: + case self::DUMP: + case self::GROUP_START: + case self::GROUP_END: + break; + default: + throw new Zend_Wildfire_Exception('Log style "'.$meta['Type'].'" not recognized!'); + break; + } + + if ($meta['Type'] != self::DUMP && $options['includeLineNumbers']) { + if (!isset($meta['File']) || !isset($meta['Line'])) { + + if (!$trace) { + $trace = $firephp->_getStackTrace(array_merge($options, + array('maxTraceDepth'=>$options['maxTraceDepth']+1))); + } + + $meta['File'] = isset($trace[0]['file'])?$trace[0]['file']:''; + $meta['Line'] = isset($trace[0]['line'])?$trace[0]['line']:''; + + } + } else { + unset($meta['File']); + unset($meta['Line']); + } + + if ($meta['Type'] == self::GROUP_START) { + if (isset($options['Collapsed'])) { + $meta['Collapsed'] = ($options['Collapsed'])?'true':'false'; + } + } + + if ($meta['Type'] == self::DUMP) { + + return $firephp->_recordMessage(self::STRUCTURE_URI_DUMP, + array('key'=>$meta['Label'], + 'data'=>$var), + $skipFinalEncode); + + } else { + + return $firephp->_recordMessage(self::STRUCTURE_URI_FIREBUGCONSOLE, + array('data'=>$var, + 'meta'=>$meta), + $skipFinalEncode); + } + } + + /** + * Gets a stack trace + * + * @param array $options Options to change how the stack trace is returned + * @return array The stack trace + */ + protected function _getStackTrace($options) + { + $trace = debug_backtrace(); + + $trace = array_splice($trace, $options['traceOffset']); + + if (!count($trace)) { + return $trace; + } + + if (isset($options['fixZendLogOffsetIfApplicable']) && $options['fixZendLogOffsetIfApplicable']) { + if (count($trace) >=3 && + isset($trace[0]['file']) && substr($trace[0]['file'], -7, 7)=='Log.php' && + isset($trace[1]['function']) && $trace[1]['function']=='__call') { + + $trace = array_splice($trace, 2); + } + } + + return array_splice($trace, 0, $options['maxTraceDepth']); + } + + /** + * Record a message with the given data in the given structure + * + * @param string $structure The structure to be used for the data + * @param array $data The data to be recorded + * @param boolean $skipEncode TRUE if variable encoding should be skipped + * @return boolean Returns TRUE if message was recorded + * @throws Zend_Wildfire_Exception + */ + protected function _recordMessage($structure, $data, $skipEncode=false) + { + switch($structure) { + + case self::STRUCTURE_URI_DUMP: + + if (!isset($data['key'])) { + throw new Zend_Wildfire_Exception('You must supply a key.'); + } + if (!array_key_exists('data',$data)) { + throw new Zend_Wildfire_Exception('You must supply data.'); + } + + $value = $data['data']; + if (!$skipEncode) { + $value = $this->_encodeObject($data['data']); + } + + return $this->_channel->getProtocol(self::PROTOCOL_URI)-> + recordMessage($this, + $structure, + array($data['key']=>$value)); + + case self::STRUCTURE_URI_FIREBUGCONSOLE: + + if (!isset($data['meta']) || + !is_array($data['meta']) || + !array_key_exists('Type',$data['meta'])) { + + throw new Zend_Wildfire_Exception('You must supply a "Type" in the meta information.'); + } + if (!array_key_exists('data',$data)) { + throw new Zend_Wildfire_Exception('You must supply data.'); + } + + $value = $data['data']; + if (!$skipEncode) { + $value = $this->_encodeObject($data['data']); + } + + return $this->_channel->getProtocol(self::PROTOCOL_URI)-> + recordMessage($this, + $structure, + array($data['meta'], + $value)); + + default: + throw new Zend_Wildfire_Exception('Structure of name "'.$structure.'" is not recognized.'); + break; + } + return false; + } + + /** + * Encodes a table by encoding each row and column with _encodeObject() + * + * @param array $Table The table to be encoded + * @return array + */ + protected function _encodeTable($table) + { + if (!$table) { + return $table; + } + for ($i=0 ; $i_encodeObject($table[$i][$j]); + } + } + } + return $table; + } + + /** + * Encodes a trace by encoding all "args" with _encodeObject() + * + * @param array $Trace The trace to be encoded + * @return array The encoded trace + */ + protected function _encodeTrace($trace) + { + if (!$trace) { + return $trace; + } + for ($i=0 ; $i_encodeObject($trace[$i]['args']); + } + } + return $trace; + } + + /** + * Encode an object by generating an array containing all object members. + * + * All private and protected members are included. Some meta info about + * the object class is added. + * + * @param mixed $object The object/array/value to be encoded + * @return array The encoded object + */ + protected function _encodeObject($object, $objectDepth = 1, $arrayDepth = 1) + { + $return = array(); + + if (is_resource($object)) { + + return '** '.(string)$object.' **'; + + } else + if (is_object($object)) { + + if ($objectDepth > $this->_options['maxObjectDepth']) { + return '** Max Object Depth ('.$this->_options['maxObjectDepth'].') **'; + } + + foreach ($this->_objectStack as $refVal) { + if ($refVal === $object) { + return '** Recursion ('.get_class($object).') **'; + } + } + array_push($this->_objectStack, $object); + + $return['__className'] = $class = get_class($object); + + $reflectionClass = new ReflectionClass($class); + $properties = array(); + foreach ( $reflectionClass->getProperties() as $property) { + $properties[$property->getName()] = $property; + } + + $members = (array)$object; + + foreach ($properties as $just_name => $property) { + + $name = $raw_name = $just_name; + + if ($property->isStatic()) { + $name = 'static:'.$name; + } + if ($property->isPublic()) { + $name = 'public:'.$name; + } else + if ($property->isPrivate()) { + $name = 'private:'.$name; + $raw_name = "\0".$class."\0".$raw_name; + } else + if ($property->isProtected()) { + $name = 'protected:'.$name; + $raw_name = "\0".'*'."\0".$raw_name; + } + + if (!(isset($this->_objectFilters[$class]) + && is_array($this->_objectFilters[$class]) + && in_array($just_name,$this->_objectFilters[$class]))) { + + if (array_key_exists($raw_name,$members) + && !$property->isStatic()) { + + $return[$name] = $this->_encodeObject($members[$raw_name], $objectDepth + 1, 1); + + } else { + if (method_exists($property,'setAccessible')) { + $property->setAccessible(true); + $return[$name] = $this->_encodeObject($property->getValue($object), $objectDepth + 1, 1); + } else + if ($property->isPublic()) { + $return[$name] = $this->_encodeObject($property->getValue($object), $objectDepth + 1, 1); + } else { + $return[$name] = '** Need PHP 5.3 to get value **'; + } + } + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + + // Include all members that are not defined in the class + // but exist in the object + foreach($members as $just_name => $value) { + + $name = $raw_name = $just_name; + + if ($name{0} == "\0") { + $parts = explode("\0", $name); + $name = $parts[2]; + } + if (!isset($properties[$name])) { + $name = 'undeclared:'.$name; + + if (!(isset($this->objectFilters[$class]) + && is_array($this->objectFilters[$class]) + && in_array($just_name,$this->objectFilters[$class]))) { + + $return[$name] = $this->_encodeObject($value, $objectDepth + 1, 1); + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + } + + array_pop($this->_objectStack); + + } elseif (is_array($object)) { + + if ($arrayDepth > $this->_options['maxArrayDepth']) { + return '** Max Array Depth ('.$this->_options['maxArrayDepth'].') **'; + } + + foreach ($object as $key => $val) { + + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($key=='GLOBALS' + && is_array($val) + && array_key_exists('GLOBALS',$val)) { + + $val['GLOBALS'] = '** Recursion (GLOBALS) **'; + } + $return[$key] = $this->_encodeObject($val, 1, $arrayDepth + 1); + } + } else { + return $object; + } + return $return; + } + + /* + * Zend_Wildfire_Plugin_Interface + */ + + /** + * Get the unique indentifier for this plugin. + * + * @return string Returns the URI of the plugin. + */ + public function getUri() + { + return self::PLUGIN_URI; + } + + /** + * Flush any buffered data. + * + * @param string $protocolUri The URI of the protocol that should be flushed to + * @return void + */ + public function flushMessages($protocolUri) + { + if (!$this->_messages || $protocolUri!=self::PROTOCOL_URI) { + return; + } + + foreach( $this->_messages as $message ) { + if (!$message->getDestroy()) { + $this->send($message->getMessage(), + $message->getLabel(), + $message->getStyle(), + $message->getOptions()); + } + } + + $this->_messages = array(); + } +} diff --git a/library/vendor/Zend/Wildfire/Plugin/FirePhp/Message.php b/library/vendor/Zend/Wildfire/Plugin/FirePhp/Message.php new file mode 100644 index 000000000..070b02717 --- /dev/null +++ b/library/vendor/Zend/Wildfire/Plugin/FirePhp/Message.php @@ -0,0 +1,246 @@ + null, /* The offset in the trace which identifies the source of the message */ + 'includeLineNumbers' => null /* Whether to include line and file info for this message */ + ); + + /** + * Creates a new message with the given style and message + * + * @param string $style Style of the message. + * @param mixed $message The message + * @return void + */ + function __construct($style, $message) + { + $this->_style = $style; + $this->_message = $message; + $this->_ruid = md5(microtime().mt_rand()); + } + + /** + * Set the label of the message + * + * @param string $label The label to be set + * @return void + */ + public function setLabel($label) + { + $this->_label = $label; + } + + /** + * Get the label of the message + * + * @return string The label of the message + */ + public function getLabel() + { + return $this->_label; + } + + /** + * Enable or disable message buffering + * + * If a message is buffered it can be updated for the duration of the + * request and is only flushed at the end of the request. + * + * @param boolean $buffered TRUE to enable buffering FALSE otherwise + * @return boolean Returns previous buffering value + */ + public function setBuffered($buffered) + { + $previous = $this->_buffered; + $this->_buffered = $buffered; + return $previous; + } + + /** + * Determine if buffering is enabled or disabled + * + * @return boolean Returns TRUE if buffering is enabled, FALSE otherwise. + */ + public function getBuffered() + { + return $this->_buffered; + } + + /** + * Destroy the message to prevent delivery + * + * @param boolean $destroy TRUE to destroy FALSE otherwise + * @return boolean Returns previous destroy value + */ + public function setDestroy($destroy) + { + $previous = $this->_destroy; + $this->_destroy = $destroy; + return $previous; + } + + /** + * Determine if message should be destroyed + * + * @return boolean Returns TRUE if message should be destroyed, FALSE otherwise. + */ + public function getDestroy() + { + return $this->_destroy; + } + + /** + * Set the style of the message + * + * @return void + */ + public function setStyle($style) + { + $this->_style = $style; + } + + /** + * Get the style of the message + * + * @return string The style of the message + */ + public function getStyle() + { + return $this->_style; + } + + /** + * Set the actual message to be sent in its final format. + * + * @return void + */ + public function setMessage($message) + { + $this->_message = $message; + } + + /** + * Get the actual message to be sent in its final format. + * + * @return mixed Returns the message to be sent. + */ + public function getMessage() + { + return $this->_message; + } + + /** + * Set a single option + * + * @param string $key The name of the option + * @param mixed $value The value of the option + * @return mixed The previous value of the option + */ + public function setOption($key, $value) + { + if(!array_key_exists($key,$this->_options)) { + throw new Zend_Wildfire_Exception('Option with name "'.$key.'" does not exist!'); + } + $previous = $this->_options[$key]; + $this->_options[$key] = $value; + return $previous; + } + + /** + * Retrieve a single option + * + * @param string $key The name of the option + * @return mixed The value of the option + */ + public function getOption($key) + { + if(!array_key_exists($key,$this->_options)) { + throw new Zend_Wildfire_Exception('Option with name "'.$key.'" does not exist!'); + } + return $this->_options[$key]; + } + + /** + * Retrieve all options + * + * @return array All options + */ + public function getOptions() + { + return $this->_options; + } +} + diff --git a/library/vendor/Zend/Wildfire/Plugin/FirePhp/TableMessage.php b/library/vendor/Zend/Wildfire/Plugin/FirePhp/TableMessage.php new file mode 100644 index 000000000..101d5632d --- /dev/null +++ b/library/vendor/Zend/Wildfire/Plugin/FirePhp/TableMessage.php @@ -0,0 +1,160 @@ +setLabel($label); + } + + /** + * Set the table header + * + * @param array $header The header columns + * @return void + */ + public function setHeader($header) + { + $this->_header = $header; + } + + /** + * Append a row to the end of the table. + * + * @param array $row An array of column values representing a row. + * @return void + */ + public function addRow($row) + { + $this->_rows[] = $row; + } + + /** + * Get the actual message to be sent in its final format. + * + * @return mixed Returns the message to be sent. + */ + public function getMessage() + { + $table = $this->_rows; + if($this->_header) { + array_unshift($table,$this->_header); + } + return $table; + } + + /** + * Returns the row at the given index + * + * @param integer $index The index of the row + * @return array Returns the row + * @throws Zend_Wildfire_Exception + */ + public function getRowAt($index) + { + $count = $this->getRowCount(); + + if($index < 0 || $index > $count-1) { + throw new Zend_Wildfire_Exception('Row index('.$index.') out of bounds('.$count.')!'); + } + + return $this->_rows[$index]; + } + + /** + * Sets the row on the given index to a new row + * + * @param integer $index The index of the row + * @param array $row The new data for the row + * @throws Zend_Wildfire_Exception + */ + public function setRowAt($index, $row) + { + $count = $this->getRowCount(); + + if($index < 0 || $index > $count-1) { + throw new Zend_Wildfire_Exception('Row index('.$index.') out of bounds('.$count.')!'); + } + + $this->_rows[$index] = $row; + } + + /** + * Returns the number of rows + * + * @return integer + */ + public function getRowCount() + { + return count($this->_rows); + } + + /** + * Returns the last row of the table + * + * @return array Returns the last row + * @throws Zend_Wildfire_Exception + */ + public function getLastRow() + { + $count = $this->getRowCount(); + + if($count==0) { + throw new Zend_Wildfire_Exception('Cannot get last row as no rows exist!'); + } + + return $this->_rows[$count-1]; + } +} diff --git a/library/vendor/Zend/Wildfire/Plugin/Interface.php b/library/vendor/Zend/Wildfire/Plugin/Interface.php new file mode 100644 index 000000000..eb79bec64 --- /dev/null +++ b/library/vendor/Zend/Wildfire/Plugin/Interface.php @@ -0,0 +1,48 @@ +_plugins)) { + return false; + } + $this->_plugins[] = $plugin; + return true; + } + + /** + * Record a message with the given data in the given structure + * + * @param Zend_Wildfire_Plugin_Interface $plugin The plugin recording the message + * @param string $structure The structure to be used for the data + * @param array $data The data to be recorded + * @return boolean Returns TRUE if message was recorded + */ + public function recordMessage(Zend_Wildfire_Plugin_Interface $plugin, $structure, $data) + { + if(!isset($this->_messages[$structure])) { + $this->_messages[$structure] = array(); + } + + $uri = $plugin->getUri(); + + if(!isset($this->_messages[$structure][$uri])) { + $this->_messages[$structure][$uri] = array(); + } + + $this->_messages[$structure][$uri][] = $this->_encode($data); + return true; + } + + /** + * Remove all qued messages + * + * @param Zend_Wildfire_Plugin_Interface $plugin The plugin for which to clear messages + * @return boolean Returns TRUE if messages were present + */ + public function clearMessages(Zend_Wildfire_Plugin_Interface $plugin) + { + $uri = $plugin->getUri(); + + $present = false; + foreach ($this->_messages as $structure => $messages) { + + if(!isset($this->_messages[$structure][$uri])) { + continue; + } + + $present = true; + + unset($this->_messages[$structure][$uri]); + + if (!$this->_messages[$structure]) { + unset($this->_messages[$structure]); + } + } + return $present; + } + + /** + * Get all qued messages + * + * @return mixed Returns qued messages or FALSE if no messages are qued + */ + public function getMessages() + { + if (!$this->_messages) { + return false; + } + return $this->_messages; + } + + /** + * Use the JSON encoding scheme for the value specified + * + * @param mixed $value The value to be encoded + * @return string The encoded value + */ + protected function _encode($value) + { + return Zend_Json::encode($value, true, array('silenceCyclicalExceptions'=>true)); + } + + /** + * Retrieves all formatted data ready to be sent by the channel. + * + * @param Zend_Wildfire_Channel_Interface $channel The instance of the channel that will be transmitting the data + * @return mixed Returns the data to be sent by the channel. + * @throws Zend_Wildfire_Exception + */ + public function getPayload(Zend_Wildfire_Channel_Interface $channel) + { + if (!$channel instanceof Zend_Wildfire_Channel_HttpHeaders) { + throw new Zend_Wildfire_Exception('The '.get_class($channel).' channel is not supported by the '.get_class($this).' protocol.'); + } + + if ($this->_plugins) { + foreach ($this->_plugins as $plugin) { + $plugin->flushMessages(self::PROTOCOL_URI); + } + } + + if (!$this->_messages) { + return false; + } + + $protocol_index = 1; + $structure_index = 1; + $plugin_index = 1; + $message_index = 1; + + $payload = array(); + + $payload[] = array('Protocol-'.$protocol_index, self::PROTOCOL_URI); + + foreach ($this->_messages as $structure_uri => $plugin_messages ) { + + $payload[] = array($protocol_index.'-Structure-'.$structure_index, $structure_uri); + + foreach ($plugin_messages as $plugin_uri => $messages ) { + + $payload[] = array($protocol_index.'-Plugin-'.$plugin_index, $plugin_uri); + + foreach ($messages as $message) { + + $parts = explode("\n",chunk_split($message, 5000, "\n")); + + for ($i=0 ; $i2) { + $msg = (($i==0)?strlen($message):'') + . '|' . $part . '|' + . (($i 99999) { + throw new Zend_Wildfire_Exception('Maximum number (99,999) of messages reached!'); + } + } + } + } + $plugin_index++; + } + $structure_index++; + } + + return $payload; + } + +} + diff --git a/library/vendor/Zend/Xml/Exception.php b/library/vendor/Zend/Xml/Exception.php new file mode 100644 index 000000000..baa0ffcfe --- /dev/null +++ b/library/vendor/Zend/Xml/Exception.php @@ -0,0 +1,35 @@ + 0) { + return true; + } + return false; + } + + /** + * Scan XML string for potential XXE and XEE attacks + * + * @param string $xml + * @param DomDocument $dom + * @throws Zend_Xml_Exception + * @return SimpleXMLElement|DomDocument|boolean + */ + public static function scan($xml, DOMDocument $dom = null) + { + // If running with PHP-FPM we perform an heuristic scan + // We cannot use libxml_disable_entity_loader because of this bug + // @see https://bugs.php.net/bug.php?id=64938 + if (self::isPhpFpm()) { + self::heuristicScan($xml); + } + + if (null === $dom) { + $simpleXml = true; + $dom = new DOMDocument(); + } + + if (!self::isPhpFpm()) { + $loadEntities = libxml_disable_entity_loader(true); + $useInternalXmlErrors = libxml_use_internal_errors(true); + } + + // Load XML with network access disabled (LIBXML_NONET) + // error disabled with @ for PHP-FPM scenario + set_error_handler(array('Zend_Xml_Security', 'loadXmlErrorHandler'), E_WARNING); + + $result = $dom->loadXml($xml, LIBXML_NONET); + restore_error_handler(); + + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + + if (!$result) { + return false; + } + + // Scan for potential XEE attacks using ENTITY, if not PHP-FPM + if (!self::isPhpFpm()) { + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + if ($child->entities->length > 0) { + throw new Zend_Xml_Exception(self::ENTITY_DETECT); + } + } + } + } + + if (isset($simpleXml)) { + $result = simplexml_import_dom($dom); + if (!$result instanceof SimpleXMLElement) { + return false; + } + return $result; + } + return $dom; + } + + /** + * Scan XML file for potential XXE/XEE attacks + * + * @param string $file + * @param DOMDocument $dom + * @throws Zend_Xml_Exception + * @return SimpleXMLElement|DomDocument + */ + public static function scanFile($file, DOMDocument $dom = null) + { + if (!file_exists($file)) { + throw new Zend_Xml_Exception( + "The file $file specified doesn't exist" + ); + } + return self::scan(file_get_contents($file), $dom); + } + + /** + * Return true if PHP is running with PHP-FPM + * + * @return boolean + */ + public static function isPhpFpm() + { + if (substr(php_sapi_name(), 0, 3) === 'fpm') { + return true; + } + return false; + } +} diff --git a/library/vendor/Zend/XmlRpc/Client.php b/library/vendor/Zend/XmlRpc/Client.php new file mode 100644 index 000000000..33901a711 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Client.php @@ -0,0 +1,394 @@ +_httpClient = new Zend_Http_Client(); + } else { + $this->_httpClient = $httpClient; + } + + $this->_introspector = new Zend_XmlRpc_Client_ServerIntrospection($this); + $this->_serverAddress = $server; + } + + + /** + * Sets the HTTP client object to use for connecting the XML-RPC server. + * + * @param Zend_Http_Client $httpClient + * @return Zend_Http_Client + */ + public function setHttpClient(Zend_Http_Client $httpClient) + { + return $this->_httpClient = $httpClient; + } + + + /** + * Gets the HTTP client object. + * + * @return Zend_Http_Client + */ + public function getHttpClient() + { + return $this->_httpClient; + } + + + /** + * Sets the object used to introspect remote servers + * + * @param Zend_XmlRpc_Client_ServerIntrospection + * @return Zend_XmlRpc_Client_ServerIntrospection + */ + public function setIntrospector(Zend_XmlRpc_Client_ServerIntrospection $introspector) + { + return $this->_introspector = $introspector; + } + + + /** + * Gets the introspection object. + * + * @return Zend_XmlRpc_Client_ServerIntrospection + */ + public function getIntrospector() + { + return $this->_introspector; + } + + + /** + * The request of the last method call + * + * @return Zend_XmlRpc_Request + */ + public function getLastRequest() + { + return $this->_lastRequest; + } + + + /** + * The response received from the last method call + * + * @return Zend_XmlRpc_Response + */ + public function getLastResponse() + { + return $this->_lastResponse; + } + + + /** + * Returns a proxy object for more convenient method calls + * + * @param string $namespace Namespace to proxy or empty string for none + * @return Zend_XmlRpc_Client_ServerProxy + */ + public function getProxy($namespace = '') + { + if (empty($this->_proxyCache[$namespace])) { + $proxy = new Zend_XmlRpc_Client_ServerProxy($this, $namespace); + $this->_proxyCache[$namespace] = $proxy; + } + return $this->_proxyCache[$namespace]; + } + + /** + * Set skip system lookup flag + * + * @param bool $flag + * @return Zend_XmlRpc_Client + */ + public function setSkipSystemLookup($flag = true) + { + $this->_skipSystemLookup = (bool) $flag; + return $this; + } + + /** + * Skip system lookup when determining if parameter should be array or struct? + * + * @return bool + */ + public function skipSystemLookup() + { + return $this->_skipSystemLookup; + } + + /** + * Perform an XML-RPC request and return a response. + * + * @param Zend_XmlRpc_Request $request + * @param null|Zend_XmlRpc_Response $response + * @return void + * @throws Zend_XmlRpc_Client_HttpException + */ + public function doRequest($request, $response = null) + { + $this->_lastRequest = $request; + + if (PHP_VERSION_ID < 50600) { + iconv_set_encoding('input_encoding', 'UTF-8'); + iconv_set_encoding('output_encoding', 'UTF-8'); + iconv_set_encoding('internal_encoding', 'UTF-8'); + } else { + ini_set('input_encoding', 'UTF-8'); + ini_set('output_encoding', 'UTF-8'); + ini_set('default_charset', 'UTF-8'); + } + + $http = $this->getHttpClient(); + if($http->getUri() === null) { + $http->setUri($this->_serverAddress); + } + + $http->setHeaders(array( + 'Content-Type: text/xml; charset=utf-8', + 'Accept: text/xml', + )); + + if ($http->getHeader('user-agent') === null) { + $http->setHeaders(array('User-Agent: Zend_XmlRpc_Client')); + } + + $xml = $this->_lastRequest->__toString(); + $http->setRawData($xml); + $httpResponse = $http->request(Zend_Http_Client::POST); + + if (! $httpResponse->isSuccessful()) { + /** + * Exception thrown when an HTTP error occurs + * @see Zend_XmlRpc_Client_HttpException + */ + throw new Zend_XmlRpc_Client_HttpException( + $httpResponse->getMessage(), + $httpResponse->getStatus()); + } + + if ($response === null) { + $response = new Zend_XmlRpc_Response(); + } + $this->_lastResponse = $response; + $this->_lastResponse->loadXml(trim($httpResponse->getBody())); + } + + /** + * Send an XML-RPC request to the service (for a specific method) + * + * @param string $method Name of the method we want to call + * @param array $params Array of parameters for the method + * @return mixed + * @throws Zend_XmlRpc_Client_FaultException + */ + public function call($method, $params=array()) + { + if (!$this->skipSystemLookup() && ('system.' != substr($method, 0, 7))) { + // Ensure empty array/struct params are cast correctly + // If system.* methods are not available, bypass. (ZF-2978) + $success = true; + try { + $signatures = $this->getIntrospector()->getMethodSignature($method); + } catch (Zend_XmlRpc_Exception $e) { + $success = false; + } + if ($success) { + $validTypes = array( + Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY, + Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64, + Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN, + Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME, + Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE, + Zend_XmlRpc_Value::XMLRPC_TYPE_I4, + Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER, + Zend_XmlRpc_Value::XMLRPC_TYPE_NIL, + Zend_XmlRpc_Value::XMLRPC_TYPE_STRING, + Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT, + ); + + if (!is_array($params)) { + $params = array($params); + } + + foreach ($params as $key => $param) + { + if ($param instanceof Zend_XmlRpc_Value) { + continue; + } + + if (count($signatures) > 1) { + $type = Zend_XmlRpc_Value::getXmlRpcTypeByValue($param); + foreach ($signatures as $signature) { + if (!is_array($signature)) { + continue; + } + if (isset($signature['parameters'][$key])) { + if ($signature['parameters'][$key] == $type) { + break; + } + } + } + } elseif (isset($signatures[0]['parameters'][$key])) { + $type = $signatures[0]['parameters'][$key]; + } else { + $type = null; + } + + if (empty($type) || !in_array($type, $validTypes)) { + $type = Zend_XmlRpc_Value::AUTO_DETECT_TYPE; + } + + $params[$key] = Zend_XmlRpc_Value::getXmlRpcValue($param, $type); + } + } + } + + $request = $this->_createRequest($method, $params); + + $this->doRequest($request); + + if ($this->_lastResponse->isFault()) { + $fault = $this->_lastResponse->getFault(); + /** + * Exception thrown when an XML-RPC fault is returned + * @see Zend_XmlRpc_Client_FaultException + */ + throw new Zend_XmlRpc_Client_FaultException($fault->getMessage(), + $fault->getCode()); + } + + return $this->_lastResponse->getReturnValue(); + } + + /** + * Create request object + * + * @return Zend_XmlRpc_Request + */ + protected function _createRequest($method, $params) + { + return new Zend_XmlRpc_Request($method, $params); + } +} diff --git a/library/vendor/Zend/XmlRpc/Client/Exception.php b/library/vendor/Zend/XmlRpc/Client/Exception.php new file mode 100644 index 000000000..96cb7730c --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Client/Exception.php @@ -0,0 +1,39 @@ +_system = $client->getProxy('system'); + } + + /** + * Returns the signature for each method on the server, + * autodetecting whether system.multicall() is supported and + * using it if so. + * + * @return array + */ + public function getSignatureForEachMethod() + { + $methods = $this->listMethods(); + + try { + $signatures = $this->getSignatureForEachMethodByMulticall($methods); + } catch (Zend_XmlRpc_Client_FaultException $e) { + // degrade to looping + } + + if (empty($signatures)) { + $signatures = $this->getSignatureForEachMethodByLooping($methods); + } + + return $signatures; + } + + /** + * Attempt to get the method signatures in one request via system.multicall(). + * This is a boxcar feature of XML-RPC and is found on fewer servers. However, + * can significantly improve performance if present. + * + * @param array $methods + * @return array array(array(return, param, param, param...)) + */ + public function getSignatureForEachMethodByMulticall($methods = null) + { + if ($methods === null) { + $methods = $this->listMethods(); + } + + $multicallParams = array(); + foreach ($methods as $method) { + $multicallParams[] = array('methodName' => 'system.methodSignature', + 'params' => array($method)); + } + + $serverSignatures = $this->_system->multicall($multicallParams); + + if (! is_array($serverSignatures)) { + $type = gettype($serverSignatures); + $error = "Multicall return is malformed. Expected array, got $type"; + throw new Zend_XmlRpc_Client_IntrospectException($error); + } + + if (count($serverSignatures) != count($methods)) { + $error = 'Bad number of signatures received from multicall'; + throw new Zend_XmlRpc_Client_IntrospectException($error); + } + + // Create a new signatures array with the methods name as keys and the signature as value + $signatures = array(); + foreach ($serverSignatures as $i => $signature) { + $signatures[$methods[$i]] = $signature; + } + + return $signatures; + } + + /** + * Get the method signatures for every method by + * successively calling system.methodSignature + * + * @param array $methods + * @return array + */ + public function getSignatureForEachMethodByLooping($methods = null) + { + if ($methods === null) { + $methods = $this->listMethods(); + } + + $signatures = array(); + foreach ($methods as $method) { + $signatures[$method] = $this->getMethodSignature($method); + } + + return $signatures; + } + + /** + * Call system.methodSignature() for the given method + * + * @param array $method + * @return array array(array(return, param, param, param...)) + */ + public function getMethodSignature($method) + { + $signature = $this->_system->methodSignature($method); + if (!is_array($signature)) { + $error = 'Invalid signature for method "' . $method . '"'; + throw new Zend_XmlRpc_Client_IntrospectException($error); + } + return $signature; + } + + /** + * Call system.listMethods() + * + * @param array $method + * @return array array(method, method, method...) + */ + public function listMethods() + { + return $this->_system->listMethods(); + } + +} diff --git a/library/vendor/Zend/XmlRpc/Client/ServerProxy.php b/library/vendor/Zend/XmlRpc/Client/ServerProxy.php new file mode 100644 index 000000000..4973d3c86 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Client/ServerProxy.php @@ -0,0 +1,95 @@ +foo->bar->baz()". + * + * @category Zend + * @package Zend_XmlRpc + * @subpackage Client + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_XmlRpc_Client_ServerProxy +{ + /** + * @var Zend_XmlRpc_Client + */ + private $_client = null; + + /** + * @var string + */ + private $_namespace = ''; + + + /** + * @var array of Zend_XmlRpc_Client_ServerProxy + */ + private $_cache = array(); + + + /** + * Class constructor + * + * @param string $namespace + * @param Zend_XmlRpc_Client $client + */ + public function __construct($client, $namespace = '') + { + $this->_namespace = $namespace; + $this->_client = $client; + } + + + /** + * Get the next successive namespace + * + * @param string $name + * @return Zend_XmlRpc_Client_ServerProxy + */ + public function __get($namespace) + { + $namespace = ltrim("$this->_namespace.$namespace", '.'); + if (!isset($this->_cache[$namespace])) { + $this->_cache[$namespace] = new $this($this->_client, $namespace); + } + return $this->_cache[$namespace]; + } + + + /** + * Call a method in this namespace. + * + * @param string $methodN + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + $method = ltrim("$this->_namespace.$method", '.'); + return $this->_client->call($method, $args); + } +} diff --git a/library/vendor/Zend/XmlRpc/Exception.php b/library/vendor/Zend/XmlRpc/Exception.php new file mode 100644 index 000000000..fa132ea5a --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Exception.php @@ -0,0 +1,36 @@ + messages + * @var array + */ + protected $_internal = array( + 404 => 'Unknown Error', + + // 610 - 619 reflection errors + 610 => 'Invalid method class', + 611 => 'Unable to attach function or callback; not callable', + 612 => 'Unable to load array; not an array', + 613 => 'One or more method records are corrupt or otherwise unusable', + + // 620 - 629 dispatch errors + 620 => 'Method does not exist', + 621 => 'Error instantiating class to invoke method', + 622 => 'Method missing implementation', + 623 => 'Calling parameters do not match signature', + + // 630 - 639 request errors + 630 => 'Unable to read request', + 631 => 'Failed to parse request', + 632 => 'Invalid request, no method passed; request must contain a \'methodName\' tag', + 633 => 'Param must contain a value', + 634 => 'Invalid method name', + 635 => 'Invalid XML provided to request', + 636 => 'Error creating xmlrpc value', + + // 640 - 649 system.* errors + 640 => 'Method does not exist', + + // 650 - 659 response errors + 650 => 'Invalid XML provided for response', + 651 => 'Failed to parse response', + 652 => 'Invalid response', + 653 => 'Invalid XMLRPC value in response', + ); + + /** + * Constructor + * + * @return Zend_XmlRpc_Fault + */ + public function __construct($code = 404, $message = '') + { + $this->setCode($code); + $code = $this->getCode(); + + if (empty($message) && isset($this->_internal[$code])) { + $message = $this->_internal[$code]; + } elseif (empty($message)) { + $message = 'Unknown error'; + } + $this->setMessage($message); + } + + /** + * Set the fault code + * + * @param int $code + * @return Zend_XmlRpc_Fault + */ + public function setCode($code) + { + $this->_code = (int) $code; + return $this; + } + + /** + * Return fault code + * + * @return int + */ + public function getCode() + { + return $this->_code; + } + + /** + * Retrieve fault message + * + * @param string + * @return Zend_XmlRpc_Fault + */ + public function setMessage($message) + { + $this->_message = (string) $message; + return $this; + } + + /** + * Retrieve fault message + * + * @return string + */ + public function getMessage() + { + return $this->_message; + } + + /** + * Set encoding to use in fault response + * + * @param string $encoding + * @return Zend_XmlRpc_Fault + */ + public function setEncoding($encoding) + { + $this->_encoding = $encoding; + Zend_XmlRpc_Value::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current fault encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Load an XMLRPC fault from XML + * + * @param string $fault + * @return boolean Returns true if successfully loaded fault response, false + * if response was not a fault response + * @throws Zend_XmlRpc_Exception if no or faulty XML provided, or if fault + * response does not contain either code or message + */ + public function loadXml($fault) + { + if (!is_string($fault)) { + throw new Zend_XmlRpc_Exception('Invalid XML provided to fault'); + } + + try { + $xml = @new SimpleXMLElement($fault); + } catch (Exception $e) { + // Not valid XML + throw new Zend_XmlRpc_Exception('Failed to parse XML fault: ' . $e->getMessage(), 500, $e); + } + + // Check for fault + if (!$xml->fault) { + // Not a fault + return false; + } + + if (!$xml->fault->value->struct) { + // not a proper fault + throw new Zend_XmlRpc_Exception('Invalid fault structure', 500); + } + + $structXml = $xml->fault->value->asXML(); + $struct = Zend_XmlRpc_Value::getXmlRpcValue($structXml, Zend_XmlRpc_Value::XML_STRING); + $struct = $struct->getValue(); + + if (isset($struct['faultCode'])) { + $code = $struct['faultCode']; + } + if (isset($struct['faultString'])) { + $message = $struct['faultString']; + } + + if (empty($code) && empty($message)) { + throw new Zend_XmlRpc_Exception('Fault code and string required'); + } + + if (empty($code)) { + $code = '404'; + } + + if (empty($message)) { + if (isset($this->_internal[$code])) { + $message = $this->_internal[$code]; + } else { + $message = 'Unknown Error'; + } + } + + $this->setCode($code); + $this->setMessage($message); + + return true; + } + + /** + * Determine if an XML response is an XMLRPC fault + * + * @param string $xml + * @return boolean + */ + public static function isFault($xml) + { + $fault = new self(); + try { + $isFault = $fault->loadXml($xml); + } catch (Zend_XmlRpc_Exception $e) { + $isFault = false; + } + + return $isFault; + } + + /** + * Serialize fault to XML + * + * @return string + */ + public function saveXml() + { + // Create fault value + $faultStruct = array( + 'faultCode' => $this->getCode(), + 'faultString' => $this->getMessage() + ); + $value = Zend_XmlRpc_Value::getXmlRpcValue($faultStruct); + + $generator = Zend_XmlRpc_Value::getGenerator(); + $generator->openElement('methodResponse') + ->openElement('fault'); + $value->generateXml(); + $generator->closeElement('fault') + ->closeElement('methodResponse'); + + return $generator->flush(); + } + + /** + * Return XML fault response + * + * @return string + */ + public function __toString() + { + return $this->saveXML(); + } +} diff --git a/library/vendor/Zend/XmlRpc/Generator/DomDocument.php b/library/vendor/Zend/XmlRpc/Generator/DomDocument.php new file mode 100644 index 000000000..8067804dd --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Generator/DomDocument.php @@ -0,0 +1,100 @@ +_dom->createElement($name); + + $this->_currentElement = $this->_currentElement->appendChild($newElement); + } + + /** + * Write XML text data into the currently opened XML element + * + * @param string $text + */ + protected function _writeTextData($text) + { + $this->_currentElement->appendChild($this->_dom->createTextNode($text)); + } + + /** + * Close an previously opened XML element + * + * Resets $_currentElement to the next parent node in the hierarchy + * + * @param string $name + * @return void + */ + protected function _closeElement($name) + { + if (isset($this->_currentElement->parentNode)) { + $this->_currentElement = $this->_currentElement->parentNode; + } + } + + /** + * Save XML as a string + * + * @return string + */ + public function saveXml() + { + return $this->_dom->saveXml(); + } + + /** + * Initializes internal objects + * + * @return void + */ + protected function _init() + { + $this->_dom = new DOMDocument('1.0', $this->_encoding); + $this->_currentElement = $this->_dom; + } +} diff --git a/library/vendor/Zend/XmlRpc/Generator/GeneratorAbstract.php b/library/vendor/Zend/XmlRpc/Generator/GeneratorAbstract.php new file mode 100644 index 000000000..b5b93ed53 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Generator/GeneratorAbstract.php @@ -0,0 +1,150 @@ +_encoding = $encoding; + $this->_init(); + } + + /** + * Start XML element + * + * Method opens a new XML element with an element name and an optional value + * + * @param string $name XML tag name + * @param string $value Optional value of the XML tag + * @return Zend_XmlRpc_Generator_Abstract Fluent interface + */ + public function openElement($name, $value = null) + { + $this->_openElement($name); + if ($value !== null) { + $this->_writeTextData($value); + } + + return $this; + } + + /** + * End of an XML element + * + * Method marks the end of an XML element + * + * @param string $name XML tag name + * @return Zend_XmlRpc_Generator_Abstract Fluent interface + */ + public function closeElement($name) + { + $this->_closeElement($name); + + return $this; + } + + /** + * Return XML as a string + * + * @return string + */ + abstract public function saveXml(); + + /** + * Return encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Returns the XML as a string and flushes all internal buffers + * + * @return string + */ + public function flush() + { + $xml = $this->saveXml(); + $this->_init(); + return $xml; + } + + /** + * Returns XML without document declaration + * + * @return string + */ + public function __toString() + { + return $this->stripDeclaration($this->saveXml()); + } + + /** + * Removes XML declaration from a string + * + * @param string $xml + * @return string + */ + public function stripDeclaration($xml) + { + return preg_replace('/<\?xml version="1.0"( encoding="[^\"]*")?\?>\n/u', '', $xml); + } + + /** + * Start XML element + * + * @param string $name XML element name + */ + abstract protected function _openElement($name); + + /** + * Write XML text data into the currently opened XML element + * + * @param string $text + */ + abstract protected function _writeTextData($text); + + /** + * End XML element + * + * @param string $name + */ + abstract protected function _closeElement($name); +} diff --git a/library/vendor/Zend/XmlRpc/Generator/XmlWriter.php b/library/vendor/Zend/XmlRpc/Generator/XmlWriter.php new file mode 100644 index 000000000..3683ff6e4 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Generator/XmlWriter.php @@ -0,0 +1,92 @@ +_xmlWriter = new XMLWriter(); + $this->_xmlWriter->openMemory(); + $this->_xmlWriter->startDocument('1.0', $this->_encoding); + } + + + /** + * Open a new XML element + * + * @param string $name XML element name + * @return void + */ + protected function _openElement($name) + { + $this->_xmlWriter->startElement($name); + } + + /** + * Write XML text data into the currently opened XML element + * + * @param string $text XML text data + * @return void + */ + protected function _writeTextData($text) + { + $this->_xmlWriter->text($text); + } + + /** + * Close an previously opened XML element + * + * @param string $name + * @return void + */ + protected function _closeElement($name) + { + $this->_xmlWriter->endElement(); + + return $this; + } + + public function saveXml() + { + $xml = $this->_xmlWriter->flush(false); + return $xml; + } +} diff --git a/library/vendor/Zend/XmlRpc/Request.php b/library/vendor/Zend/XmlRpc/Request.php new file mode 100644 index 000000000..8f4274893 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Request.php @@ -0,0 +1,441 @@ +setMethod($method); + } + + if ($params !== null) { + $this->setParams($params); + } + } + + + /** + * Set encoding to use in request + * + * @param string $encoding + * @return Zend_XmlRpc_Request + */ + public function setEncoding($encoding) + { + $this->_encoding = $encoding; + Zend_XmlRpc_Value::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current request encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set method to call + * + * @param string $method + * @return boolean Returns true on success, false if method name is invalid + */ + public function setMethod($method) + { + if (!is_string($method) || !preg_match('/^[a-z0-9_.:\/]+$/i', $method)) { + $this->_fault = new Zend_XmlRpc_Fault(634, 'Invalid method name ("' . $method . '")'); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + $this->_method = $method; + return true; + } + + /** + * Retrieve call method + * + * @return string + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Add a parameter to the parameter stack + * + * Adds a parameter to the parameter stack, associating it with the type + * $type if provided + * + * @param mixed $value + * @param string $type Optional; type hinting + * @return void + */ + public function addParam($value, $type = null) + { + $this->_params[] = $value; + if (null === $type) { + // Detect type if not provided explicitly + if ($value instanceof Zend_XmlRpc_Value) { + $type = $value->getType(); + } else { + $xmlRpcValue = Zend_XmlRpc_Value::getXmlRpcValue($value); + $type = $xmlRpcValue->getType(); + } + } + $this->_types[] = $type; + $this->_xmlRpcParams[] = array('value' => $value, 'type' => $type); + } + + /** + * Set the parameters array + * + * If called with a single, array value, that array is used to set the + * parameters stack. If called with multiple values or a single non-array + * value, the arguments are used to set the parameters stack. + * + * Best is to call with array of the format, in order to allow type hinting + * when creating the XMLRPC values for each parameter: + * + * $array = array( + * array( + * 'value' => $value, + * 'type' => $type + * )[, ... ] + * ); + * + * + * @access public + * @return void + */ + public function setParams() + { + $argc = func_num_args(); + $argv = func_get_args(); + if (0 == $argc) { + return; + } + + if ((1 == $argc) && is_array($argv[0])) { + $params = array(); + $types = array(); + $wellFormed = true; + foreach ($argv[0] as $arg) { + if (!is_array($arg) || !isset($arg['value'])) { + $wellFormed = false; + break; + } + $params[] = $arg['value']; + + if (!isset($arg['type'])) { + $xmlRpcValue = Zend_XmlRpc_Value::getXmlRpcValue($arg['value']); + $arg['type'] = $xmlRpcValue->getType(); + } + $types[] = $arg['type']; + } + if ($wellFormed) { + $this->_xmlRpcParams = $argv[0]; + $this->_params = $params; + $this->_types = $types; + } else { + $this->_params = $argv[0]; + $this->_types = array(); + $xmlRpcParams = array(); + foreach ($argv[0] as $arg) { + if ($arg instanceof Zend_XmlRpc_Value) { + $type = $arg->getType(); + } else { + $xmlRpcValue = Zend_XmlRpc_Value::getXmlRpcValue($arg); + $type = $xmlRpcValue->getType(); + } + $xmlRpcParams[] = array('value' => $arg, 'type' => $type); + $this->_types[] = $type; + } + $this->_xmlRpcParams = $xmlRpcParams; + } + return; + } + + $this->_params = $argv; + $this->_types = array(); + $xmlRpcParams = array(); + foreach ($argv as $arg) { + if ($arg instanceof Zend_XmlRpc_Value) { + $type = $arg->getType(); + } else { + $xmlRpcValue = Zend_XmlRpc_Value::getXmlRpcValue($arg); + $type = $xmlRpcValue->getType(); + } + $xmlRpcParams[] = array('value' => $arg, 'type' => $type); + $this->_types[] = $type; + } + $this->_xmlRpcParams = $xmlRpcParams; + } + + /** + * Retrieve the array of parameters + * + * @return array + */ + public function getParams() + { + return $this->_params; + } + + /** + * Return parameter types + * + * @return array + */ + public function getTypes() + { + return $this->_types; + } + + /** + * Load XML and parse into request components + * + * @param string $request + * @return boolean True on success, false if an error occurred. + */ + public function loadXml($request) + { + if (!is_string($request)) { + $this->_fault = new Zend_XmlRpc_Fault(635); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + try { + $xml = Zend_Xml_Security::scan($request); + } catch (Zend_Xml_Exception $e) { + // Not valid XML + $this->_fault = new Zend_XmlRpc_Fault(631); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + // Check for method name + if (empty($xml->methodName)) { + // Missing method name + $this->_fault = new Zend_XmlRpc_Fault(632); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + $this->_method = (string) $xml->methodName; + + // Check for parameters + if (!empty($xml->params)) { + $types = array(); + $argv = array(); + foreach ($xml->params->children() as $param) { + if (!isset($param->value)) { + $this->_fault = new Zend_XmlRpc_Fault(633); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + try { + $param = Zend_XmlRpc_Value::getXmlRpcValue($param->value, Zend_XmlRpc_Value::XML_STRING); + $types[] = $param->getType(); + $argv[] = $param->getValue(); + } catch (Exception $e) { + $this->_fault = new Zend_XmlRpc_Fault(636); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + } + + $this->_types = $types; + $this->_params = $argv; + } + + $this->_xml = $request; + + return true; + } + + /** + * Does the current request contain errors and should it return a fault + * response? + * + * @return boolean + */ + public function isFault() + { + return $this->_fault instanceof Zend_XmlRpc_Fault; + } + + /** + * Retrieve the fault response, if any + * + * @return null|Zend_XmlRpc_Fault + */ + public function getFault() + { + return $this->_fault; + } + + /** + * Retrieve method parameters as XMLRPC values + * + * @return array + */ + protected function _getXmlRpcParams() + { + $params = array(); + if (is_array($this->_xmlRpcParams)) { + foreach ($this->_xmlRpcParams as $param) { + $value = $param['value']; + $type = isset($param['type']) ? $param['type'] : Zend_XmlRpc_Value::AUTO_DETECT_TYPE; + + if (!$value instanceof Zend_XmlRpc_Value) { + $value = Zend_XmlRpc_Value::getXmlRpcValue($value, $type); + } + $params[] = $value; + } + } + + return $params; + } + + /** + * Create XML request + * + * @return string + */ + public function saveXml() + { + $args = $this->_getXmlRpcParams(); + $method = $this->getMethod(); + + $generator = Zend_XmlRpc_Value::getGenerator(); + $generator->openElement('methodCall') + ->openElement('methodName', $method) + ->closeElement('methodName'); + + if (is_array($args) && count($args)) { + $generator->openElement('params'); + + foreach ($args as $arg) { + $generator->openElement('param'); + $arg->generateXml(); + $generator->closeElement('param'); + } + $generator->closeElement('params'); + } + $generator->closeElement('methodCall'); + + return $generator->flush(); + } + + /** + * Return XML request + * + * @return string + */ + public function __toString() + { + return $this->saveXML(); + } +} diff --git a/library/vendor/Zend/XmlRpc/Request/Http.php b/library/vendor/Zend/XmlRpc/Request/Http.php new file mode 100644 index 000000000..62990d566 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Request/Http.php @@ -0,0 +1,122 @@ +_fault = new Zend_XmlRpc_Fault(630); + return; + } + + $this->_xml = $xml; + + $this->loadXml($xml); + } + + /** + * Retrieve the raw XML request + * + * @return string + */ + public function getRawRequest() + { + return $this->_xml; + } + + /** + * Get headers + * + * Gets all headers as key => value pairs and returns them. + * + * @return array + */ + public function getHeaders() + { + if (null === $this->_headers) { + $this->_headers = array(); + foreach ($_SERVER as $key => $value) { + if ('HTTP_' == substr($key, 0, 5)) { + $header = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5))))); + $this->_headers[$header] = $value; + } + } + } + + return $this->_headers; + } + + /** + * Retrieve the full HTTP request, including headers and XML + * + * @return string + */ + public function getFullRequest() + { + $request = ''; + foreach ($this->getHeaders() as $key => $value) { + $request .= $key . ': ' . $value . "\n"; + } + + $request .= $this->_xml; + + return $request; + } +} diff --git a/library/vendor/Zend/XmlRpc/Request/Stdin.php b/library/vendor/Zend/XmlRpc/Request/Stdin.php new file mode 100644 index 000000000..783ed2a61 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Request/Stdin.php @@ -0,0 +1,83 @@ +_fault = new Zend_XmlRpc_Server_Exception(630); + return; + } + + $xml = ''; + while (!feof($fh)) { + $xml .= fgets($fh); + } + fclose($fh); + + $this->_xml = $xml; + + $this->loadXml($xml); + } + + /** + * Retrieve the raw XML request + * + * @return string + */ + public function getRawRequest() + { + return $this->_xml; + } +} diff --git a/library/vendor/Zend/XmlRpc/Response.php b/library/vendor/Zend/XmlRpc/Response.php new file mode 100644 index 000000000..b54c6db22 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Response.php @@ -0,0 +1,250 @@ +setReturnValue($return, $type); + } + + /** + * Set encoding to use in response + * + * @param string $encoding + * @return Zend_XmlRpc_Response + */ + public function setEncoding($encoding) + { + $this->_encoding = $encoding; + Zend_XmlRpc_Value::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current response encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Set the return value + * + * Sets the return value, with optional type hinting if provided. + * + * @param mixed $value + * @param string $type + * @return void + */ + public function setReturnValue($value, $type = null) + { + $this->_return = $value; + $this->_type = (string) $type; + } + + /** + * Retrieve the return value + * + * @return mixed + */ + public function getReturnValue() + { + return $this->_return; + } + + /** + * Retrieve the XMLRPC value for the return value + * + * @return Zend_XmlRpc_Value + */ + protected function _getXmlRpcReturn() + { + return Zend_XmlRpc_Value::getXmlRpcValue($this->_return); + } + + /** + * Is the response a fault response? + * + * @return boolean + */ + public function isFault() + { + return $this->_fault instanceof Zend_XmlRpc_Fault; + } + + /** + * Returns the fault, if any. + * + * @return null|Zend_XmlRpc_Fault + */ + public function getFault() + { + return $this->_fault; + } + + /** + * Load a response from an XML response + * + * Attempts to load a response from an XMLRPC response, autodetecting if it + * is a fault response. + * + * @param string $response + * @return boolean True if a valid XMLRPC response, false if a fault + * response or invalid input + */ + public function loadXml($response) + { + if (!is_string($response)) { + $this->_fault = new Zend_XmlRpc_Fault(650); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + try { + $xml = Zend_Xml_Security::scan($response); + } catch (Zend_Xml_Exception $e) { + // Not valid XML + $this->_fault = new Zend_XmlRpc_Fault(651); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + if (!empty($xml->fault)) { + // fault response + $this->_fault = new Zend_XmlRpc_Fault(); + $this->_fault->setEncoding($this->getEncoding()); + $this->_fault->loadXml($response); + return false; + } + + if (empty($xml->params)) { + // Invalid response + $this->_fault = new Zend_XmlRpc_Fault(652); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + try { + if (!isset($xml->params) || !isset($xml->params->param) || !isset($xml->params->param->value)) { + throw new Zend_XmlRpc_Value_Exception('Missing XML-RPC value in XML'); + } + $valueXml = $xml->params->param->value->asXML(); + $value = Zend_XmlRpc_Value::getXmlRpcValue($valueXml, Zend_XmlRpc_Value::XML_STRING); + } catch (Zend_XmlRpc_Value_Exception $e) { + $this->_fault = new Zend_XmlRpc_Fault(653); + $this->_fault->setEncoding($this->getEncoding()); + return false; + } + + $this->setReturnValue($value->getValue()); + return true; + } + + /** + * Return response as XML + * + * @return string + */ + public function saveXml() + { + $value = $this->_getXmlRpcReturn(); + $generator = Zend_XmlRpc_Value::getGenerator(); + $generator->openElement('methodResponse') + ->openElement('params') + ->openElement('param'); + $value->generateXml(); + $generator->closeElement('param') + ->closeElement('params') + ->closeElement('methodResponse'); + + return $generator->flush(); + } + + /** + * Return XML response + * + * @return string + */ + public function __toString() + { + return $this->saveXML(); + } +} diff --git a/library/vendor/Zend/XmlRpc/Response/Http.php b/library/vendor/Zend/XmlRpc/Response/Http.php new file mode 100644 index 000000000..b6ffe754c --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Response/Http.php @@ -0,0 +1,50 @@ +getEncoding())); + } + + return parent::__toString(); + } +} diff --git a/library/vendor/Zend/XmlRpc/Server.php b/library/vendor/Zend/XmlRpc/Server.php new file mode 100644 index 000000000..700e016b5 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Server.php @@ -0,0 +1,586 @@ + + * + * // Instantiate server + * $server = new Zend_XmlRpc_Server(); + * + * // Allow some exceptions to report as fault responses: + * Zend_XmlRpc_Server_Fault::attachFaultException('My_Exception'); + * Zend_XmlRpc_Server_Fault::attachObserver('My_Fault_Observer'); + * + * // Get or build dispatch table: + * if (!Zend_XmlRpc_Server_Cache::get($filename, $server)) { + * + * // Attach Some_Service_Class in 'some' namespace + * $server->setClass('Some_Service_Class', 'some'); + * + * // Attach Another_Service_Class in 'another' namespace + * $server->setClass('Another_Service_Class', 'another'); + * + * // Create dispatch table cache file + * Zend_XmlRpc_Server_Cache::save($filename, $server); + * } + * + * $response = $server->handle(); + * echo $response; + * + * + * @category Zend + * @package Zend_XmlRpc + * @subpackage Server + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_XmlRpc_Server extends Zend_Server_Abstract +{ + /** + * Character encoding + * @var string + */ + protected $_encoding = 'UTF-8'; + + /** + * Request processed + * @var null|Zend_XmlRpc_Request + */ + protected $_request = null; + + /** + * Class to use for responses; defaults to {@link Zend_XmlRpc_Response_Http} + * @var string + */ + protected $_responseClass = 'Zend_XmlRpc_Response_Http'; + + /** + * Dispatch table of name => method pairs + * @var Zend_Server_Definition + */ + protected $_table; + + /** + * PHP types => XML-RPC types + * @var array + */ + protected $_typeMap = array( + 'i4' => 'i4', + 'int' => 'int', + 'integer' => 'int', + 'Zend_Crypt_Math_BigInteger' => 'i8', + 'i8' => 'i8', + 'ex:i8' => 'i8', + 'double' => 'double', + 'float' => 'double', + 'real' => 'double', + 'boolean' => 'boolean', + 'bool' => 'boolean', + 'true' => 'boolean', + 'false' => 'boolean', + 'string' => 'string', + 'str' => 'string', + 'base64' => 'base64', + 'dateTime.iso8601' => 'dateTime.iso8601', + 'date' => 'dateTime.iso8601', + 'time' => 'dateTime.iso8601', + 'time' => 'dateTime.iso8601', + 'Zend_Date' => 'dateTime.iso8601', + 'DateTime' => 'dateTime.iso8601', + 'array' => 'array', + 'struct' => 'struct', + 'null' => 'nil', + 'nil' => 'nil', + 'ex:nil' => 'nil', + 'void' => 'void', + 'mixed' => 'struct', + ); + + /** + * Send arguments to all methods or just constructor? + * + * @var bool + */ + protected $_sendArgumentsToAllMethods = true; + + /** + * Constructor + * + * Creates system.* methods. + * + * @return void + */ + public function __construct() + { + $this->_table = new Zend_Server_Definition(); + $this->_registerSystemMethods(); + } + + /** + * Proxy calls to system object + * + * @param string $method + * @param array $params + * @return mixed + * @throws Zend_XmlRpc_Server_Exception + */ + public function __call($method, $params) + { + $system = $this->getSystem(); + if (!method_exists($system, $method)) { + throw new Zend_XmlRpc_Server_Exception('Unknown instance method called on server: ' . $method); + } + return call_user_func_array(array($system, $method), $params); + } + + /** + * Attach a callback as an XMLRPC method + * + * Attaches a callback as an XMLRPC method, prefixing the XMLRPC method name + * with $namespace, if provided. Reflection is done on the callback's + * docblock to create the methodHelp for the XMLRPC method. + * + * Additional arguments to pass to the function at dispatch may be passed; + * any arguments following the namespace will be aggregated and passed at + * dispatch time. + * + * @param string|array $function Valid callback + * @param string $namespace Optional namespace prefix + * @return void + * @throws Zend_XmlRpc_Server_Exception + */ + public function addFunction($function, $namespace = '') + { + if (!is_string($function) && !is_array($function)) { + throw new Zend_XmlRpc_Server_Exception('Unable to attach function; invalid', 611); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 2); + } + + $function = (array) $function; + foreach ($function as $func) { + if (!is_string($func) || !function_exists($func)) { + throw new Zend_XmlRpc_Server_Exception('Unable to attach function; invalid', 611); + } + $reflection = Zend_Server_Reflection::reflectFunction($func, $argv, $namespace); + $this->_buildSignature($reflection); + } + } + + /** + * Attach class methods as XMLRPC method handlers + * + * $class may be either a class name or an object. Reflection is done on the + * class or object to determine the available public methods, and each is + * attached to the server as an available method; if a $namespace has been + * provided, that namespace is used to prefix the XMLRPC method names. + * + * Any additional arguments beyond $namespace will be passed to a method at + * invocation. + * + * @param string|object $class + * @param string $namespace Optional + * @param mixed $argv Optional arguments to pass to methods + * @return void + * @throws Zend_XmlRpc_Server_Exception on invalid input + */ + public function setClass($class, $namespace = '', $argv = null) + { + if (is_string($class) && !class_exists($class)) { + throw new Zend_XmlRpc_Server_Exception('Invalid method class', 610); + } + + $argv = null; + if (2 < func_num_args()) { + $argv = func_get_args(); + $argv = array_slice($argv, 2); + } + + $dispatchable = Zend_Server_Reflection::reflectClass($class, $argv, $namespace); + foreach ($dispatchable->getMethods() as $reflection) { + $this->_buildSignature($reflection, $class); + } + } + + /** + * Raise an xmlrpc server fault + * + * @param string|Exception $fault + * @param int $code + * @return Zend_XmlRpc_Server_Fault + */ + public function fault($fault = null, $code = 404) + { + if (!$fault instanceof Exception) { + $fault = (string) $fault; + if (empty($fault)) { + $fault = 'Unknown Error'; + } + $fault = new Zend_XmlRpc_Server_Exception($fault, $code); + } + + return Zend_XmlRpc_Server_Fault::getInstance($fault); + } + + /** + * Handle an xmlrpc call + * + * @param Zend_XmlRpc_Request $request Optional + * @return Zend_XmlRpc_Response|Zend_XmlRpc_Fault + */ + public function handle($request = false) + { + // Get request + if ((!$request || !$request instanceof Zend_XmlRpc_Request) + && (null === ($request = $this->getRequest())) + ) { + $request = new Zend_XmlRpc_Request_Http(); + $request->setEncoding($this->getEncoding()); + } + + $this->setRequest($request); + + if ($request->isFault()) { + $response = $request->getFault(); + } else { + try { + $response = $this->_handle($request); + } catch (Exception $e) { + $response = $this->fault($e); + } + } + + // Set output encoding + $response->setEncoding($this->getEncoding()); + + return $response; + } + + /** + * Load methods as returned from {@link getFunctions} + * + * Typically, you will not use this method; it will be called using the + * results pulled from {@link Zend_XmlRpc_Server_Cache::get()}. + * + * @param array|Zend_Server_Definition $definition + * @return void + * @throws Zend_XmlRpc_Server_Exception on invalid input + */ + public function loadFunctions($definition) + { + if (!is_array($definition) && (!$definition instanceof Zend_Server_Definition)) { + if (is_object($definition)) { + $type = get_class($definition); + } else { + $type = gettype($definition); + } + throw new Zend_XmlRpc_Server_Exception('Unable to load server definition; must be an array or Zend_Server_Definition, received ' . $type, 612); + } + + $this->_table->clearMethods(); + $this->_registerSystemMethods(); + + if ($definition instanceof Zend_Server_Definition) { + $definition = $definition->getMethods(); + } + + foreach ($definition as $key => $method) { + if ('system.' == substr($key, 0, 7)) { + continue; + } + $this->_table->addMethod($method, $key); + } + } + + /** + * Set encoding + * + * @param string $encoding + * @return Zend_XmlRpc_Server + */ + public function setEncoding($encoding) + { + $this->_encoding = $encoding; + Zend_XmlRpc_Value::setEncoding($encoding); + return $this; + } + + /** + * Retrieve current encoding + * + * @return string + */ + public function getEncoding() + { + return $this->_encoding; + } + + /** + * Do nothing; persistence is handled via {@link Zend_XmlRpc_Server_Cache} + * + * @param mixed $mode + * @return void + */ + public function setPersistence($mode) + { + } + + /** + * Set the request object + * + * @param string|Zend_XmlRpc_Request $request + * @return Zend_XmlRpc_Server + * @throws Zend_XmlRpc_Server_Exception on invalid request class or object + */ + public function setRequest($request) + { + if (is_string($request) && class_exists($request)) { + $request = new $request(); + if (!$request instanceof Zend_XmlRpc_Request) { + throw new Zend_XmlRpc_Server_Exception('Invalid request class'); + } + $request->setEncoding($this->getEncoding()); + } elseif (!$request instanceof Zend_XmlRpc_Request) { + throw new Zend_XmlRpc_Server_Exception('Invalid request object'); + } + + $this->_request = $request; + return $this; + } + + /** + * Return currently registered request object + * + * @return null|Zend_XmlRpc_Request + */ + public function getRequest() + { + return $this->_request; + } + + /** + * Set the class to use for the response + * + * @param string $class + * @return boolean True if class was set, false if not + */ + public function setResponseClass($class) + { + if (!class_exists($class) or + ($c = new ReflectionClass($class) and !$c->isSubclassOf('Zend_XmlRpc_Response'))) { + + throw new Zend_XmlRpc_Server_Exception('Invalid response class'); + } + $this->_responseClass = $class; + return true; + } + + /** + * Retrieve current response class + * + * @return string + */ + public function getResponseClass() + { + return $this->_responseClass; + } + + /** + * Retrieve dispatch table + * + * @return array + */ + public function getDispatchTable() + { + return $this->_table; + } + + /** + * Returns a list of registered methods + * + * Returns an array of dispatchables (Zend_Server_Reflection_Function, + * _Method, and _Class items). + * + * @return array + */ + public function getFunctions() + { + return $this->_table->toArray(); + } + + /** + * Retrieve system object + * + * @return Zend_XmlRpc_Server_System + */ + public function getSystem() + { + return $this->_system; + } + + /** + * Send arguments to all methods? + * + * If setClass() is used to add classes to the server, this flag defined + * how to handle arguments. If set to true, all methods including constructor + * will receive the arguments. If set to false, only constructor will receive the + * arguments + */ + public function sendArgumentsToAllMethods($flag = null) + { + if ($flag === null) { + return $this->_sendArgumentsToAllMethods; + } + + $this->_sendArgumentsToAllMethods = (bool)$flag; + return $this; + } + + /** + * Map PHP type to XML-RPC type + * + * @param string $type + * @return string + */ + protected function _fixType($type) + { + if (isset($this->_typeMap[$type])) { + return $this->_typeMap[$type]; + } + return 'void'; + } + + /** + * Handle an xmlrpc call (actual work) + * + * @param Zend_XmlRpc_Request $request + * @return Zend_XmlRpc_Response + * @throws Zend_XmlRpcServer_Exception|Exception + * Zend_XmlRpcServer_Exceptions are thrown for internal errors; otherwise, + * any other exception may be thrown by the callback + */ + protected function _handle(Zend_XmlRpc_Request $request) + { + $method = $request->getMethod(); + + // Check for valid method + if (!$this->_table->hasMethod($method)) { + throw new Zend_XmlRpc_Server_Exception('Method "' . $method . '" does not exist', 620); + } + + $info = $this->_table->getMethod($method); + $params = $request->getParams(); + $argv = $info->getInvokeArguments(); + if (0 < count($argv) and $this->sendArgumentsToAllMethods()) { + $params = array_merge($params, $argv); + } + + // Check calling parameters against signatures + $matched = false; + $sigCalled = $request->getTypes(); + + $sigLength = count($sigCalled); + $paramsLen = count($params); + if ($sigLength < $paramsLen) { + for ($i = $sigLength; $i < $paramsLen; ++$i) { + $xmlRpcValue = Zend_XmlRpc_Value::getXmlRpcValue($params[$i]); + $sigCalled[] = $xmlRpcValue->getType(); + } + } + + $signatures = $info->getPrototypes(); + foreach ($signatures as $signature) { + $sigParams = $signature->getParameters(); + if ($sigCalled === $sigParams) { + $matched = true; + break; + } + } + if (!$matched) { + throw new Zend_XmlRpc_Server_Exception('Calling parameters do not match signature', 623); + } + + $return = $this->_dispatch($info, $params); + $responseClass = $this->getResponseClass(); + return new $responseClass($return); + } + + /** + * Register system methods with the server + * + * @return void + */ + protected function _registerSystemMethods() + { + $system = new Zend_XmlRpc_Server_System($this); + $this->_system = $system; + $this->setClass($system, 'system'); + } +} diff --git a/library/vendor/Zend/XmlRpc/Server/Cache.php b/library/vendor/Zend/XmlRpc/Server/Cache.php new file mode 100644 index 000000000..609714441 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Server/Cache.php @@ -0,0 +1,45 @@ + true); + + /** + * @var array Array of fault observers + */ + protected static $_observers = array(); + + /** + * Constructor + * + * @param Exception $e + * @return Zend_XmlRpc_Server_Fault + */ + public function __construct(Exception $e) + { + $this->_exception = $e; + $code = 404; + $message = 'Unknown error'; + $exceptionClass = get_class($e); + + foreach (array_keys(self::$_faultExceptionClasses) as $class) { + if ($e instanceof $class) { + $code = $e->getCode(); + $message = $e->getMessage(); + break; + } + } + + parent::__construct($code, $message); + + // Notify exception observers, if present + if (!empty(self::$_observers)) { + foreach (array_keys(self::$_observers) as $observer) { + call_user_func(array($observer, 'observe'), $this); + } + } + } + + /** + * Return Zend_XmlRpc_Server_Fault instance + * + * @param Exception $e + * @return Zend_XmlRpc_Server_Fault + */ + public static function getInstance(Exception $e) + { + return new self($e); + } + + /** + * Attach valid exceptions that can be used to define xmlrpc faults + * + * @param string|array $classes Class name or array of class names + * @return void + */ + public static function attachFaultException($classes) + { + if (!is_array($classes)) { + $classes = (array) $classes; + } + + foreach ($classes as $class) { + if (is_string($class) && class_exists($class)) { + self::$_faultExceptionClasses[$class] = true; + } + } + } + + /** + * Detach fault exception classes + * + * @param string|array $classes Class name or array of class names + * @return void + */ + public static function detachFaultException($classes) + { + if (!is_array($classes)) { + $classes = (array) $classes; + } + + foreach ($classes as $class) { + if (is_string($class) && isset(self::$_faultExceptionClasses[$class])) { + unset(self::$_faultExceptionClasses[$class]); + } + } + } + + /** + * Attach an observer class + * + * Allows observation of xmlrpc server faults, thus allowing logging or mail + * notification of fault responses on the xmlrpc server. + * + * Expects a valid class name; that class must have a public static method + * 'observe' that accepts an exception as its sole argument. + * + * @param string $class + * @return boolean + */ + public static function attachObserver($class) + { + if (!is_string($class) + || !class_exists($class) + || !is_callable(array($class, 'observe'))) + { + return false; + } + + if (!isset(self::$_observers[$class])) { + self::$_observers[$class] = true; + } + + return true; + } + + /** + * Detach an observer + * + * @param string $class + * @return boolean + */ + public static function detachObserver($class) + { + if (!isset(self::$_observers[$class])) { + return false; + } + + unset(self::$_observers[$class]); + return true; + } + + /** + * Retrieve the exception + * + * @access public + * @return Exception + */ + public function getException() + { + return $this->_exception; + } +} diff --git a/library/vendor/Zend/XmlRpc/Server/System.php b/library/vendor/Zend/XmlRpc/Server/System.php new file mode 100644 index 000000000..15c857937 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Server/System.php @@ -0,0 +1,160 @@ +_server = $server; + } + + /** + * List all available XMLRPC methods + * + * Returns an array of methods. + * + * @return array + */ + public function listMethods() + { + $table = $this->_server->getDispatchTable()->getMethods(); + return array_keys($table); + } + + /** + * Display help message for an XMLRPC method + * + * @param string $method + * @return string + */ + public function methodHelp($method) + { + $table = $this->_server->getDispatchTable(); + if (!$table->hasMethod($method)) { + throw new Zend_XmlRpc_Server_Exception('Method "' . $method . '" does not exist', 640); + } + + return $table->getMethod($method)->getMethodHelp(); + } + + /** + * Return a method signature + * + * @param string $method + * @return array + */ + public function methodSignature($method) + { + $table = $this->_server->getDispatchTable(); + if (!$table->hasMethod($method)) { + throw new Zend_XmlRpc_Server_Exception('Method "' . $method . '" does not exist', 640); + } + $method = $table->getMethod($method)->toArray(); + return $method['prototypes']; + } + + /** + * Multicall - boxcar feature of XML-RPC for calling multiple methods + * in a single request. + * + * Expects a an array of structs representing method calls, each element + * having the keys: + * - methodName + * - params + * + * Returns an array of responses, one for each method called, with the value + * returned by the method. If an error occurs for a given method, returns a + * struct with a fault response. + * + * @see http://www.xmlrpc.com/discuss/msgReader$1208 + * @param array $methods + * @return array + */ + public function multicall($methods) + { + $responses = array(); + foreach ($methods as $method) { + $fault = false; + if (!is_array($method)) { + $fault = $this->_server->fault('system.multicall expects each method to be a struct', 601); + } elseif (!isset($method['methodName'])) { + $fault = $this->_server->fault('Missing methodName: ' . var_export($methods, 1), 602); + } elseif (!isset($method['params'])) { + $fault = $this->_server->fault('Missing params', 603); + } elseif (!is_array($method['params'])) { + $fault = $this->_server->fault('Params must be an array', 604); + } else { + if ('system.multicall' == $method['methodName']) { + // don't allow recursive calls to multicall + $fault = $this->_server->fault('Recursive system.multicall forbidden', 605); + } + } + + if (!$fault) { + try { + $request = new Zend_XmlRpc_Request(); + $request->setMethod($method['methodName']); + $request->setParams($method['params']); + $response = $this->_server->handle($request); + if ($response instanceof Zend_XmlRpc_Fault + || $response->isFault() + ) { + $fault = $response; + } else { + $responses[] = $response->getReturnValue(); + } + } catch (Exception $e) { + $fault = $this->_server->fault($e); + } + } + + if ($fault) { + $responses[] = array( + 'faultCode' => $fault->getCode(), + 'faultString' => $fault->getMessage() + ); + } + } + + return $responses; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value.php b/library/vendor/Zend/XmlRpc/Value.php new file mode 100644 index 000000000..82060de16 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value.php @@ -0,0 +1,490 @@ +_type; + } + + /** + * Get XML generator instance + * + * @return Zend_XmlRpc_Generator_GeneratorAbstract + */ + public static function getGenerator() + { + if (!self::$_generator) { + if (extension_loaded('xmlwriter')) { + self::$_generator = new Zend_XmlRpc_Generator_XmlWriter(); + } else { + self::$_generator = new Zend_XmlRpc_Generator_DomDocument(); + } + } + + return self::$_generator; + } + + /** + * Sets XML generator instance + * + * @param Zend_XmlRpc_Generator_GeneratorAbstract $generator + * @return void + */ + public static function setGenerator(Zend_XmlRpc_Generator_GeneratorAbstract $generator) + { + self::$_generator = $generator; + } + + /** + * Changes the encoding of the generator + * + * @param string $encoding + * @return void + */ + public static function setEncoding($encoding) + { + $generator = self::getGenerator(); + $newGenerator = new $generator($encoding); + self::setGenerator($newGenerator); + } + + /** + * Return the value of this object, convert the XML-RPC native value into a PHP variable + * + * @return mixed + */ + abstract public function getValue(); + + + /** + * Return the XML code that represent a native MXL-RPC value + * + * @return string + */ + public function saveXml() + { + if (!$this->_xml) { + $this->generateXml(); + $this->_xml = (string) $this->getGenerator(); + } + return $this->_xml; + } + + /** + * Generate XML code that represent a native XML/RPC value + * + * @return void + */ + public function generateXml() + { + $this->_generateXml(); + } + + /** + * Creates a Zend_XmlRpc_Value* object, representing a native XML-RPC value + * A XmlRpcValue object can be created in 3 ways: + * 1. Autodetecting the native type out of a PHP variable + * (if $type is not set or equal to Zend_XmlRpc_Value::AUTO_DETECT_TYPE) + * 2. By specifing the native type ($type is one of the Zend_XmlRpc_Value::XMLRPC_TYPE_* constants) + * 3. From a XML string ($type is set to Zend_XmlRpc_Value::XML_STRING) + * + * By default the value type is autodetected according to it's PHP type + * + * @param mixed $value + * @param Zend_XmlRpc_Value::constant $type + * + * @return Zend_XmlRpc_Value + * @static + */ + public static function getXmlRpcValue($value, $type = self::AUTO_DETECT_TYPE) + { + switch ($type) { + case self::AUTO_DETECT_TYPE: + // Auto detect the XML-RPC native type from the PHP type of $value + return self::_phpVarToNativeXmlRpc($value); + + case self::XML_STRING: + // Parse the XML string given in $value and get the XML-RPC value in it + return self::_xmlStringToNativeXmlRpc($value); + + case self::XMLRPC_TYPE_I4: + // fall through to the next case + case self::XMLRPC_TYPE_INTEGER: + return new Zend_XmlRpc_Value_Integer($value); + + case self::XMLRPC_TYPE_I8: + // fall through to the next case + case self::XMLRPC_TYPE_APACHEI8: + return new Zend_XmlRpc_Value_BigInteger($value); + + case self::XMLRPC_TYPE_DOUBLE: + return new Zend_XmlRpc_Value_Double($value); + + case self::XMLRPC_TYPE_BOOLEAN: + return new Zend_XmlRpc_Value_Boolean($value); + + case self::XMLRPC_TYPE_STRING: + return new Zend_XmlRpc_Value_String($value); + + case self::XMLRPC_TYPE_BASE64: + return new Zend_XmlRpc_Value_Base64($value); + + case self::XMLRPC_TYPE_NIL: + // fall through to the next case + case self::XMLRPC_TYPE_APACHENIL: + return new Zend_XmlRpc_Value_Nil(); + + case self::XMLRPC_TYPE_DATETIME: + return new Zend_XmlRpc_Value_DateTime($value); + + case self::XMLRPC_TYPE_ARRAY: + return new Zend_XmlRpc_Value_Array($value); + + case self::XMLRPC_TYPE_STRUCT: + return new Zend_XmlRpc_Value_Struct($value); + + default: + throw new Zend_XmlRpc_Value_Exception('Given type is not a '. __CLASS__ .' constant'); + } + } + + /** + * Get XML-RPC type for a PHP native variable + * + * @static + * @param mixed $value + * @return string + */ + public static function getXmlRpcTypeByValue($value) + { + if (is_object($value)) { + if ($value instanceof Zend_XmlRpc_Value) { + return $value->getType(); + } elseif (($value instanceof Zend_Date) || ($value instanceof DateTime)) { + return self::XMLRPC_TYPE_DATETIME; + } + return self::getXmlRpcTypeByValue(get_object_vars($value)); + } elseif (is_array($value)) { + if (!empty($value) && is_array($value) && (array_keys($value) !== range(0, count($value) - 1))) { + return self::XMLRPC_TYPE_STRUCT; + } + return self::XMLRPC_TYPE_ARRAY; + } elseif (is_int($value)) { + return ($value > PHP_INT_MAX) ? self::XMLRPC_TYPE_I8 : self::XMLRPC_TYPE_INTEGER; + } elseif (is_double($value)) { + return self::XMLRPC_TYPE_DOUBLE; + } elseif (is_bool($value)) { + return self::XMLRPC_TYPE_BOOLEAN; + } elseif (is_null($value)) { + return self::XMLRPC_TYPE_NIL; + } elseif (is_string($value)) { + return self::XMLRPC_TYPE_STRING; + } + throw new Zend_XmlRpc_Value_Exception(sprintf( + 'No matching XMLRPC type found for php type %s.', + gettype($value) + )); + } + + /** + * Transform a PHP native variable into a XML-RPC native value + * + * @param mixed $value The PHP variable for convertion + * + * @return Zend_XmlRpc_Value + * @static + */ + protected static function _phpVarToNativeXmlRpc($value) + { + // @see http://framework.zend.com/issues/browse/ZF-8623 + if (is_object($value)) { + if ($value instanceof Zend_XmlRpc_Value) { + return $value; + } + if ($value instanceof Zend_Crypt_Math_BigInteger) { + throw new Zend_XmlRpc_Value_Exception( + 'Using Zend_Crypt_Math_BigInteger to get an ' . + 'instance of Zend_XmlRpc_Value_BigInteger is not ' . + 'available anymore.' + ); + } + } + + switch (self::getXmlRpcTypeByValue($value)) + { + case self::XMLRPC_TYPE_DATETIME: + return new Zend_XmlRpc_Value_DateTime($value); + + case self::XMLRPC_TYPE_ARRAY: + return new Zend_XmlRpc_Value_Array($value); + + case self::XMLRPC_TYPE_STRUCT: + return new Zend_XmlRpc_Value_Struct($value); + + case self::XMLRPC_TYPE_INTEGER: + return new Zend_XmlRpc_Value_Integer($value); + + case self::XMLRPC_TYPE_DOUBLE: + return new Zend_XmlRpc_Value_Double($value); + + case self::XMLRPC_TYPE_BOOLEAN: + return new Zend_XmlRpc_Value_Boolean($value); + + case self::XMLRPC_TYPE_NIL: + return new Zend_XmlRpc_Value_Nil; + + case self::XMLRPC_TYPE_STRING: + // Fall through to the next case + default: + // If type isn't identified (or identified as string), it treated as string + return new Zend_XmlRpc_Value_String($value); + } + } + + + /** + * Transform an XML string into a XML-RPC native value + * + * @param string|SimpleXMLElement $xml A SimpleXMLElement object represent the XML string + * It can be also a valid XML string for convertion + * + * @return Zend_XmlRpc_Value + * @static + */ + protected static function _xmlStringToNativeXmlRpc($xml) + { + self::_createSimpleXMLElement($xml); + + self::_extractTypeAndValue($xml, $type, $value); + + switch ($type) { + // All valid and known XML-RPC native values + case self::XMLRPC_TYPE_I4: + // Fall through to the next case + case self::XMLRPC_TYPE_INTEGER: + $xmlrpcValue = new Zend_XmlRpc_Value_Integer($value); + break; + case self::XMLRPC_TYPE_APACHEI8: + // Fall through to the next case + case self::XMLRPC_TYPE_I8: + $xmlrpcValue = new Zend_XmlRpc_Value_BigInteger($value); + break; + case self::XMLRPC_TYPE_DOUBLE: + $xmlrpcValue = new Zend_XmlRpc_Value_Double($value); + break; + case self::XMLRPC_TYPE_BOOLEAN: + $xmlrpcValue = new Zend_XmlRpc_Value_Boolean($value); + break; + case self::XMLRPC_TYPE_STRING: + $xmlrpcValue = new Zend_XmlRpc_Value_String($value); + break; + case self::XMLRPC_TYPE_DATETIME: // The value should already be in a iso8601 format + $xmlrpcValue = new Zend_XmlRpc_Value_DateTime($value); + break; + case self::XMLRPC_TYPE_BASE64: // The value should already be base64 encoded + $xmlrpcValue = new Zend_XmlRpc_Value_Base64($value, true); + break; + case self::XMLRPC_TYPE_NIL: + // Fall through to the next case + case self::XMLRPC_TYPE_APACHENIL: + // The value should always be NULL + $xmlrpcValue = new Zend_XmlRpc_Value_Nil(); + break; + case self::XMLRPC_TYPE_ARRAY: + // PHP 5.2.4 introduced a regression in how empty($xml->value) + // returns; need to look for the item specifically + $data = null; + foreach ($value->children() as $key => $value) { + if ('data' == $key) { + $data = $value; + break; + } + } + + if (null === $data) { + throw new Zend_XmlRpc_Value_Exception('Invalid XML for XML-RPC native '. self::XMLRPC_TYPE_ARRAY .' type: ARRAY tag must contain DATA tag'); + } + $values = array(); + // Parse all the elements of the array from the XML string + // (simple xml element) to Zend_XmlRpc_Value objects + foreach ($data->value as $element) { + $values[] = self::_xmlStringToNativeXmlRpc($element); + } + $xmlrpcValue = new Zend_XmlRpc_Value_Array($values); + break; + case self::XMLRPC_TYPE_STRUCT: + $values = array(); + // Parse all the memebers of the struct from the XML string + // (simple xml element) to Zend_XmlRpc_Value objects + foreach ($value->member as $member) { + // @todo? If a member doesn't have a tag, we don't add it to the struct + // Maybe we want to throw an exception here ? + if (!isset($member->value) or !isset($member->name)) { + continue; + //throw new Zend_XmlRpc_Value_Exception('Member of the '. self::XMLRPC_TYPE_STRUCT .' XML-RPC native type must contain a VALUE tag'); + } + $values[(string)$member->name] = self::_xmlStringToNativeXmlRpc($member->value); + } + $xmlrpcValue = new Zend_XmlRpc_Value_Struct($values); + break; + default: + throw new Zend_XmlRpc_Value_Exception('Value type \''. $type .'\' parsed from the XML string is not a known XML-RPC native type'); + break; + } + $xmlrpcValue->_setXML($xml->asXML()); + + return $xmlrpcValue; + } + + protected static function _createSimpleXMLElement(&$xml) + { + if ($xml instanceof SimpleXMLElement) { + return; + } + + try { + $xml = new SimpleXMLElement($xml); + } catch (Exception $e) { + // The given string is not a valid XML + throw new Zend_XmlRpc_Value_Exception('Failed to create XML-RPC value from XML string: ' . $e->getMessage(), $e->getCode(), $e); + } + } + + /** + * Extract XML/RPC type and value from SimpleXMLElement object + * + * @param SimpleXMLElement $xml + * @param string &$type Type bind variable + * @param string &$value Value bind variable + * @return void + */ + protected static function _extractTypeAndValue(SimpleXMLElement $xml, &$type, &$value) + { + list($type, $value) = each($xml); + + if (!$type and $value === null) { + $namespaces = array('ex' => 'http://ws.apache.org/xmlrpc/namespaces/extensions'); + foreach ($namespaces as $namespaceName => $namespaceUri) { + $namespaceXml = $xml->children($namespaceUri); + list($type, $value) = each($namespaceXml); + if ($type !== null) { + $type = $namespaceName . ':' . $type; + break; + } + } + } + + //if there is a child element, try to parse type for it + if (!$type && $value instanceof SimpleXMLElement) { + self::_extractTypeAndValue($value->children(), $type, $value); + } + + // If no type was specified, the default is string + if (!$type) { + $type = self::XMLRPC_TYPE_STRING; + if (preg_match('#^.*$#', $xml->asXML())) { + $value = str_replace(array('', ''), '', $xml->asXML()); + } + } + } + + /** + * @param string $xml + * @return void + */ + protected function _setXML($xml) + { + $this->_xml = $this->getGenerator()->stripDeclaration($xml); + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Array.php b/library/vendor/Zend/XmlRpc/Value/Array.php new file mode 100644 index 000000000..9da17a1e9 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Array.php @@ -0,0 +1,72 @@ +_type = self::XMLRPC_TYPE_ARRAY; + parent::__construct($value); + } + + + /** + * Generate the XML code that represent an array native MXL-RPC value + * + * @return void + */ + protected function _generateXml() + { + $generator = $this->getGenerator(); + $generator->openElement('value') + ->openElement('array') + ->openElement('data'); + + if (is_array($this->_value)) { + foreach ($this->_value as $val) { + $val->generateXml(); + } + } + $generator->closeElement('data') + ->closeElement('array') + ->closeElement('value'); + } +} + diff --git a/library/vendor/Zend/XmlRpc/Value/Base64.php b/library/vendor/Zend/XmlRpc/Value/Base64.php new file mode 100644 index 000000000..0e6224cdf --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Base64.php @@ -0,0 +1,67 @@ +_type = self::XMLRPC_TYPE_BASE64; + + $value = (string)$value; // Make sure this value is string + if (!$alreadyEncoded) { + $value = base64_encode($value); // We encode it in base64 + } + $this->_value = $value; + } + + /** + * Return the value of this object, convert the XML-RPC native base64 value into a PHP string + * We return this value decoded (a normal string) + * + * @return string + */ + public function getValue() + { + return base64_decode($this->_value); + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/BigInteger.php b/library/vendor/Zend/XmlRpc/Value/BigInteger.php new file mode 100644 index 000000000..ce7f3e4b5 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/BigInteger.php @@ -0,0 +1,56 @@ +_value = $integer->init($value); + $this->_type = self::XMLRPC_TYPE_I8; + } + + /** + * Return bigint value + * + * @return string + */ + public function getValue() + { + return $this->_value; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Boolean.php b/library/vendor/Zend/XmlRpc/Value/Boolean.php new file mode 100644 index 000000000..a8234e7b9 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Boolean.php @@ -0,0 +1,62 @@ +_type = self::XMLRPC_TYPE_BOOLEAN; + // Make sure the value is boolean and then convert it into a integer + // The double convertion is because a bug in the ZendOptimizer in PHP version 5.0.4 + $this->_value = (int)(bool)$value; + } + + /** + * Return the value of this object, convert the XML-RPC native boolean value into a PHP boolean + * + * @return bool + */ + public function getValue() + { + return (bool)$this->_value; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Collection.php b/library/vendor/Zend/XmlRpc/Value/Collection.php new file mode 100644 index 000000000..6375a7b8d --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Collection.php @@ -0,0 +1,72 @@ + $value) { + // If the elements of the given array are not Zend_XmlRpc_Value objects, + // we need to convert them as such (using auto-detection from PHP value) + if (!$value instanceof parent) { + $value = self::getXmlRpcValue($value, self::AUTO_DETECT_TYPE); + } + $this->_value[$key] = $value; + } + } + + + /** + * Return the value of this object, convert the XML-RPC native collection values into a PHP array + * + * @return arary + */ + public function getValue() + { + $values = (array)$this->_value; + foreach ($values as $key => $value) { + /* @var $value Zend_XmlRpc_Value */ + $values[$key] = $value->getValue(); + } + return $values; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/DateTime.php b/library/vendor/Zend/XmlRpc/Value/DateTime.php new file mode 100644 index 000000000..3140f48ed --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/DateTime.php @@ -0,0 +1,89 @@ +_type = self::XMLRPC_TYPE_DATETIME; + + if ($value instanceof Zend_Date) { + $this->_value = $value->toString($this->_isoFormatString); + } elseif ($value instanceof DateTime) { + $this->_value = $value->format($this->_phpFormatString); + } elseif (is_numeric($value)) { // The value is numeric, we make sure it is an integer + $this->_value = date($this->_phpFormatString, (int)$value); + } else { + $timestamp = new DateTime($value); + if ($timestamp === false) { // cannot convert the value to a timestamp + throw new Zend_XmlRpc_Value_Exception('Cannot convert given value \''. $value .'\' to a timestamp'); + } + + $this->_value = $timestamp->format($this->_phpFormatString); // Convert the timestamp to iso8601 format + } + } + + /** + * Return the value of this object as iso8601 dateTime value + * + * @return int As a Unix timestamp + */ + public function getValue() + { + return $this->_value; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Double.php b/library/vendor/Zend/XmlRpc/Value/Double.php new file mode 100644 index 000000000..7fba38b55 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Double.php @@ -0,0 +1,61 @@ +_type = self::XMLRPC_TYPE_DOUBLE; + $precision = (int)ini_get('precision'); + $formatString = '%1.' . $precision . 'F'; + $this->_value = rtrim(sprintf($formatString, (float)$value), '0'); + } + + /** + * Return the value of this object, convert the XML-RPC native double value into a PHP float + * + * @return float + */ + public function getValue() + { + return (float)$this->_value; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Exception.php b/library/vendor/Zend/XmlRpc/Value/Exception.php new file mode 100644 index 000000000..0fa593d47 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Exception.php @@ -0,0 +1,38 @@ + PHP_INT_MAX) { + throw new Zend_XmlRpc_Value_Exception('Overlong integer given'); + } + + $this->_type = self::XMLRPC_TYPE_INTEGER; + $this->_value = (int)$value; // Make sure this value is integer + } + + /** + * Return the value of this object, convert the XML-RPC native integer value into a PHP integer + * + * @return int + */ + public function getValue() + { + return $this->_value; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Nil.php b/library/vendor/Zend/XmlRpc/Value/Nil.php new file mode 100644 index 000000000..6b6846d31 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Nil.php @@ -0,0 +1,59 @@ +_type = self::XMLRPC_TYPE_NIL; + $this->_value = null; + } + + /** + * Return the value of this object, convert the XML-RPC native nill value into a PHP NULL + * + * @return null + */ + public function getValue() + { + return null; + } +} + diff --git a/library/vendor/Zend/XmlRpc/Value/Scalar.php b/library/vendor/Zend/XmlRpc/Value/Scalar.php new file mode 100644 index 000000000..54916337e --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Scalar.php @@ -0,0 +1,52 @@ +getGenerator(); + + $generator->openElement('value') + ->openElement($this->_type, $this->_value) + ->closeElement($this->_type) + ->closeElement('value'); + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/String.php b/library/vendor/Zend/XmlRpc/Value/String.php new file mode 100644 index 000000000..923ac06b7 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/String.php @@ -0,0 +1,59 @@ +_type = self::XMLRPC_TYPE_STRING; + + // Make sure this value is string and all XML characters are encoded + $this->_value = (string)$value; + } + + /** + * Return the value of this object, convert the XML-RPC native string value into a PHP string + * + * @return string + */ + public function getValue() + { + return (string)$this->_value; + } +} diff --git a/library/vendor/Zend/XmlRpc/Value/Struct.php b/library/vendor/Zend/XmlRpc/Value/Struct.php new file mode 100644 index 000000000..91b3211d5 --- /dev/null +++ b/library/vendor/Zend/XmlRpc/Value/Struct.php @@ -0,0 +1,74 @@ +_type = self::XMLRPC_TYPE_STRUCT; + parent::__construct($value); + } + + + /** + * Generate the XML code that represent struct native MXL-RPC value + * + * @return void + */ + protected function _generateXML() + { + $generator = $this->getGenerator(); + $generator->openElement('value') + ->openElement('struct'); + + if (is_array($this->_value)) { + foreach ($this->_value as $name => $val) { + /* @var $val Zend_XmlRpc_Value */ + $generator->openElement('member') + ->openElement('name', $name) + ->closeElement('name'); + $val->generateXml(); + $generator->closeElement('member'); + } + } + $generator->closeElement('struct') + ->closeElement('value'); + } +} diff --git a/library/IcingaVendor/lessphp/LICENSE b/library/vendor/lessphp/LICENSE similarity index 100% rename from library/IcingaVendor/lessphp/LICENSE rename to library/vendor/lessphp/LICENSE diff --git a/library/IcingaVendor/lessphp/SOURCE b/library/vendor/lessphp/SOURCE similarity index 100% rename from library/IcingaVendor/lessphp/SOURCE rename to library/vendor/lessphp/SOURCE diff --git a/library/IcingaVendor/lessphp/lessc.inc.php b/library/vendor/lessphp/lessc.inc.php similarity index 100% rename from library/IcingaVendor/lessphp/lessc.inc.php rename to library/vendor/lessphp/lessc.inc.php diff --git a/modules/doc/library/Doc/SectionRenderer.php b/modules/doc/library/Doc/SectionRenderer.php index 938e5ed7b..12f0f2ac4 100644 --- a/modules/doc/library/Doc/SectionRenderer.php +++ b/modules/doc/library/Doc/SectionRenderer.php @@ -4,7 +4,7 @@ namespace Icinga\Module\Doc; -require_once 'IcingaVendor/Parsedown/Parsedown.php'; +require_once 'Parsedown/Parsedown.php'; use DOMDocument; use DOMXPath; diff --git a/modules/doc/module.info b/modules/doc/module.info new file mode 100644 index 000000000..2826d72de --- /dev/null +++ b/modules/doc/module.info @@ -0,0 +1,4 @@ +Module: doc +Version: 2.0.0~alpha4 +Description: Documentation module + Extracts, shows and exports documentation for Icinga Web 2 and it's modules. diff --git a/modules/monitoring/application/controllers/CommandController.php b/modules/monitoring/application/controllers/CommandController.php index 6f45a388b..d2615104a 100644 --- a/modules/monitoring/application/controllers/CommandController.php +++ b/modules/monitoring/application/controllers/CommandController.php @@ -5,8 +5,8 @@ use Icinga\Application\Icinga; use Icinga\Application\Config; use Icinga\Application\Logger; -use Icinga\Module\Monitoring\Form\Command\DisableNotificationWithExpireForm; -use Icinga\Module\Monitoring\Form\Command\SingleArgumentCommandForm; +use Icinga\Module\Monitoring\Forms\Command\DisableNotificationWithExpireForm; +use Icinga\Module\Monitoring\Forms\Command\SingleArgumentCommandForm; use Icinga\Web\Form; use Icinga\Web\Url; use Icinga\Web\Notification; @@ -14,14 +14,14 @@ use Icinga\Module\Monitoring\Controller; use Icinga\Protocol\Commandpipe\CommandPipe; use Icinga\Exception\ConfigurationError; use Icinga\Exception\MissingParameterException; -use Icinga\Module\Monitoring\Form\Command\AcknowledgeForm; -use Icinga\Module\Monitoring\Form\Command\CommentForm; -use Icinga\Module\Monitoring\Form\Command\CommandForm; -use Icinga\Module\Monitoring\Form\Command\CustomNotificationForm; -use Icinga\Module\Monitoring\Form\Command\DelayNotificationForm; -use Icinga\Module\Monitoring\Form\Command\RescheduleNextCheckForm; -use Icinga\Module\Monitoring\Form\Command\ScheduleDowntimeForm; -use Icinga\Module\Monitoring\Form\Command\SubmitPassiveCheckResultForm; +use Icinga\Module\Monitoring\Forms\Command\AcknowledgeForm; +use Icinga\Module\Monitoring\Forms\Command\CommentForm; +use Icinga\Module\Monitoring\Forms\Command\CommandForm; +use Icinga\Module\Monitoring\Forms\Command\CustomNotificationForm; +use Icinga\Module\Monitoring\Forms\Command\DelayNotificationForm; +use Icinga\Module\Monitoring\Forms\Command\RescheduleNextCheckForm; +use Icinga\Module\Monitoring\Forms\Command\ScheduleDowntimeForm; +use Icinga\Module\Monitoring\Forms\Command\SubmitPassiveCheckResultForm; use Icinga\Exception\IcingaException; /** diff --git a/modules/monitoring/application/controllers/ConfigController.php b/modules/monitoring/application/controllers/ConfigController.php index cfdd73360..1e961d26e 100644 --- a/modules/monitoring/application/controllers/ConfigController.php +++ b/modules/monitoring/application/controllers/ConfigController.php @@ -4,11 +4,11 @@ use Icinga\Web\Notification; use Icinga\Data\ResourceFactory; -use Icinga\Form\ConfirmRemovalForm; +use Icinga\Forms\ConfirmRemovalForm; use Icinga\Web\Controller\ModuleActionController; -use Icinga\Module\Monitoring\Form\Config\BackendConfigForm; -use Icinga\Module\Monitoring\Form\Config\InstanceConfigForm; -use Icinga\Module\Monitoring\Form\Config\SecurityConfigForm; +use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm; +use Icinga\Module\Monitoring\Forms\Config\InstanceConfigForm; +use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm; /** * Configuration controller for editing monitoring resources diff --git a/modules/monitoring/application/controllers/HostController.php b/modules/monitoring/application/controllers/HostController.php index f77d11deb..0a4a727ed 100644 --- a/modules/monitoring/application/controllers/HostController.php +++ b/modules/monitoring/application/controllers/HostController.php @@ -2,10 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Icinga\Module\Monitoring\Form\Command\Object\AcknowledgeProblemCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\AddCommentCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleHostCheckCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleHostDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostCheckCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Web\Controller\MonitoredObjectController; diff --git a/modules/monitoring/application/controllers/HostsController.php b/modules/monitoring/application/controllers/HostsController.php index d34a8ba2f..fe34c1d6f 100644 --- a/modules/monitoring/application/controllers/HostsController.php +++ b/modules/monitoring/application/controllers/HostsController.php @@ -4,12 +4,12 @@ use Icinga\Data\Filter\Filter; use Icinga\Module\Monitoring\Controller; -use Icinga\Module\Monitoring\Form\Command\Object\AcknowledgeProblemCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\CheckNowCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ObjectsCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\RemoveAcknowledgementCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleHostCheckCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleHostDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ObjectsCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostCheckCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\HostList; diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 15b90079e..a367687f9 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -4,8 +4,8 @@ use Icinga\Module\Monitoring\Controller; use Icinga\Module\Monitoring\Backend; -use Icinga\Module\Monitoring\Form\Command\Object\DeleteCommentCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\DeleteDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm; use Icinga\Web\Url; use Icinga\Web\Hook; use Icinga\Web\Widget\Tabextension\DashboardAction; @@ -17,8 +17,8 @@ use Icinga\Web\Widget\Chart\HistoryColorGrid; use Icinga\Data\Filter\Filter; use Icinga\Web\Widget; use Icinga\Module\Monitoring\Web\Widget\SelectBox; -use Icinga\Module\Monitoring\Form\StatehistoryForm; -use Icinga\Module\Monitoring\Form\EventOverviewForm; +use Icinga\Module\Monitoring\Forms\StatehistoryForm; +use Icinga\Module\Monitoring\Forms\EventOverviewForm; class Monitoring_ListController extends Controller { @@ -156,6 +156,18 @@ class Monitoring_ListController extends Controller 'host_state' => $this->translate('Hard State') )); $this->view->hosts = $query->paginate(); + + $this->view->stats = $this->backend->select()->from('statusSummary', array( + 'hosts_total', + 'hosts_up', + 'hosts_down', + 'hosts_down_handled', + 'hosts_down_unhandled', + 'hosts_unreachable', + 'hosts_unreachable_handled', + 'hosts_unreachable_unhandled', + 'hosts_pending', + ))->getQuery()->fetchRow(); } /** diff --git a/modules/monitoring/application/controllers/MultiController.php b/modules/monitoring/application/controllers/MultiController.php index 52dfcf07f..52d927ffb 100644 --- a/modules/monitoring/application/controllers/MultiController.php +++ b/modules/monitoring/application/controllers/MultiController.php @@ -4,7 +4,7 @@ use Icinga\Module\Monitoring\Controller; use Icinga\Web\Widget\Chart\InlinePie; -use Icinga\Module\Monitoring\Form\Command\MultiCommandFlagForm; +use Icinga\Module\Monitoring\Forms\Command\MultiCommandFlagForm; use Icinga\Web\Widget; use Icinga\Data\Filter\Filter; diff --git a/modules/monitoring/application/controllers/ProcessController.php b/modules/monitoring/application/controllers/ProcessController.php index 98cba000f..e843d8ecd 100644 --- a/modules/monitoring/application/controllers/ProcessController.php +++ b/modules/monitoring/application/controllers/ProcessController.php @@ -3,8 +3,8 @@ // {{{ICINGA_LICENSE_HEADER}}} use Icinga\Module\Monitoring\Controller; -use Icinga\Module\Monitoring\Form\Command\Instance\DisableNotificationsExpireCommandForm; -use Icinga\Module\Monitoring\Form\Command\Instance\ToggleInstanceFeaturesCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Instance\DisableNotificationsExpireCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Instance\ToggleInstanceFeaturesCommandForm; /** * Display process and performance information of the monitoring host and program-wide commands diff --git a/modules/monitoring/application/controllers/ServiceController.php b/modules/monitoring/application/controllers/ServiceController.php index ea29aa54a..c6d0e4e2f 100644 --- a/modules/monitoring/application/controllers/ServiceController.php +++ b/modules/monitoring/application/controllers/ServiceController.php @@ -2,10 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Icinga\Module\Monitoring\Form\Command\Object\AcknowledgeProblemCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\AddCommentCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleServiceCheckCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleServiceDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm; use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Web\Controller\MonitoredObjectController; diff --git a/modules/monitoring/application/controllers/ServicesController.php b/modules/monitoring/application/controllers/ServicesController.php index 11b983d45..d4b0cef4d 100644 --- a/modules/monitoring/application/controllers/ServicesController.php +++ b/modules/monitoring/application/controllers/ServicesController.php @@ -4,12 +4,12 @@ use Icinga\Data\Filter\Filter; use Icinga\Module\Monitoring\Controller; -use Icinga\Module\Monitoring\Form\Command\Object\AcknowledgeProblemCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\CheckNowCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ObjectsCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\RemoveAcknowledgementCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleServiceCheckCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ScheduleServiceDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ObjectsCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\ServiceList; diff --git a/modules/monitoring/application/forms/Command/CommandForm.php b/modules/monitoring/application/forms/Command/CommandForm.php index da797e60c..807e1e6ca 100644 --- a/modules/monitoring/application/forms/Command/CommandForm.php +++ b/modules/monitoring/application/forms/Command/CommandForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command; +namespace Icinga\Module\Monitoring\Forms\Command; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Module\Monitoring\Command\Transport\CommandTransport; diff --git a/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php b/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php index 272fb6660..5620d4908 100644 --- a/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php @@ -2,16 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Instance; +namespace Icinga\Module\Monitoring\Forms\Command\Instance; use DateTime; use DateInterval; use Icinga\Module\Monitoring\Command\Instance\DisableNotificationsExpireCommand; -use Icinga\Module\Monitoring\Form\Command\CommandForm; -use Icinga\Web\Form\Element\DateTimePicker; -use Icinga\Web\Form\Element\Note; +use Icinga\Module\Monitoring\Forms\Command\CommandForm; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for disabling host and service notifications w/ an optional expire date and time on an Icinga instance @@ -34,27 +31,25 @@ class DisableNotificationsExpireCommandForm extends CommandForm public function createElements(array $formData = array()) { $this->addElement( - new Note( - 'command-info', - array( - 'value' => mt( - 'monitoring', - 'This command is used to disable host and service notifications for a specific time.' - ) + 'note', + 'command-info', + array( + 'value' => mt( + 'monitoring', + 'This command is used to disable host and service notifications for a specific time.' ) ) ); $expireTime = new DateTime(); $expireTime->add(new DateInterval('PT1H')); $this->addElement( - new DateTimePicker( - 'expire_time', - array( - 'required' => true, - 'label' => mt('monitoring', 'Expire Time'), - 'description' => mt('monitoring', 'Set the expire time.'), - 'value' => $expireTime - ) + 'dateTimePicker', + 'expire_time', + array( + 'required' => true, + 'label' => mt('monitoring', 'Expire Time'), + 'description' => mt('monitoring', 'Set the expire time.'), + 'value' => $expireTime ) ); return $this; @@ -64,12 +59,12 @@ class DisableNotificationsExpireCommandForm extends CommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { $disableNotifications = new DisableNotificationsExpireCommand(); $disableNotifications ->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp()); - $this->getTransport($request)->send($disableNotifications); + $this->getTransport($this->request)->send($disableNotifications); Notification::success(mt('monitoring', 'Disabling host and service notifications..')); return true; } diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php index 883a11a35..291619b2f 100644 --- a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Instance; +namespace Icinga\Module\Monitoring\Forms\Command\Instance; use Icinga\Module\Monitoring\Command\Instance\ToggleInstanceFeatureCommand; -use Icinga\Module\Monitoring\Form\Command\CommandForm; +use Icinga\Module\Monitoring\Forms\Command\CommandForm; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for enabling or disabling features of Icinga objects, i.e. hosts or services @@ -190,14 +189,14 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->getValues() as $feature => $enabled) { $toggleFeature = new ToggleInstanceFeatureCommand(); $toggleFeature ->setFeature($feature) ->setEnabled($enabled); - $this->getTransport($request)->send($toggleFeature); + $this->getTransport($this->request)->send($toggleFeature); } Notification::success(mt('monitoring', 'Toggling feature..')); return true; diff --git a/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php index c5b78e25c..9123fddc1 100644 --- a/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php @@ -2,15 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use DateTime; use DateInterval; use Icinga\Module\Monitoring\Command\Object\AcknowledgeProblemCommand; -use Icinga\Web\Form\Element\DateTimePicker; -use Icinga\Web\Form\Element\Note; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for acknowledging host or service problems @@ -35,7 +32,8 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm public function createElements(array $formData = array()) { $this->addElements(array( - new Note( + array( + 'note', 'command-info', array( 'value' => mt( @@ -86,16 +84,15 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm $expireTime = new DateTime(); $expireTime->add(new DateInterval('PT1H')); $this->addElement( - new DateTimePicker( - 'expire_time', - array( - 'label' => mt('monitoring', 'Expire Time'), - 'value' => $expireTime, - 'description' => mt( - 'monitoring', - 'Enter the expire date and time for this acknowledgement here. Icinga will delete the' - . ' acknowledgement after this time expired.' - ) + 'dateTimePicker', + 'expire_time', + array( + 'label' => mt('monitoring', 'Expire Time'), + 'value' => $expireTime, + 'description' => mt( + 'monitoring', + 'Enter the expire date and time for this acknowledgement here. Icinga will delete the' + . ' acknowledgement after this time expired.' ) ) ); @@ -145,7 +142,7 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ @@ -153,14 +150,14 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm $ack ->setObject($object) ->setComment($this->getElement('comment')->getValue()) - ->setAuthor($request->getUser()->getUsername()) + ->setAuthor($this->request->getUser()->getUsername()) ->setPersistent($this->getElement('persistent')->isChecked()) ->setSticky($this->getElement('sticky')->isChecked()) ->setNotify($this->getElement('notify')->isChecked()); if ($this->getElement('expire')->isChecked()) { $ack->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp()); } - $this->getTransport($request)->send($ack); + $this->getTransport($this->request)->send($ack); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php index 1f6f9573e..5d9a71d51 100644 --- a/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php @@ -2,12 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\AddCommentCommand; -use Icinga\Web\Form\Element\Note; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for adding host or service comments @@ -32,7 +30,8 @@ class AddCommentCommandForm extends ObjectsCommandForm public function createElements(array $formData = array()) { $this->addElements(array( - new Note( + array( + 'note', 'command-info', array( 'value' => mt( @@ -76,16 +75,16 @@ class AddCommentCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ $comment = new AddCommentCommand(); $comment->setObject($object); $comment->setComment($this->getElement('comment')->getValue()); - $comment->setAuthor($request->getUser()->getUsername()); + $comment->setAuthor($this->request->getUser()->getUsername()); $comment->setPersistent($this->getElement('persistent')->isChecked()); - $this->getTransport($request)->send($comment); + $this->getTransport($this->request)->send($comment); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php index aa109ff7f..477624bb6 100644 --- a/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php @@ -2,14 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand; use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand; -use Icinga\Web\Form\Element\Button; -use Icinga\Web\Form\Element\Note; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for immediately checking hosts or services @@ -34,19 +31,21 @@ class CheckNowCommandForm extends ObjectsCommandForm $iconUrl = $this->getView()->href('img/icons/refresh_petrol.png'); $this->addElements(array( - new Button( + array( + 'button', 'btn_submit', array( 'ignore' => true, 'type' => 'submit', 'value' => mt('monitoring', 'Check now'), - 'label' => ' ' . mt('monitoring', 'Check now'), + 'label' => ' ' . mt('monitoring', 'Check now'), 'decorators' => array('ViewHelper'), 'escape' => false, 'class' => 'link-like' ) ) )); + return $this; } @@ -54,7 +53,7 @@ class CheckNowCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ @@ -67,7 +66,7 @@ class CheckNowCommandForm extends ObjectsCommandForm ->setObject($object) ->setForced() ->setCheckTime(time()); - $this->getTransport($request)->send($check); + $this->getTransport($this->request)->send($check); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php index 4c7df0141..3d85afcec 100644 --- a/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for deleting host or service comments @@ -67,7 +66,7 @@ class DeleteCommentCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ @@ -75,7 +74,7 @@ class DeleteCommentCommandForm extends ObjectsCommandForm $delComment ->setObject($object) ->setCommentId($this->getElement('comment_id')->getValue()); - $this->getTransport($request)->send($delComment); + $this->getTransport($this->request)->send($delComment); } $redirect = $this->getElement('redirect')->getValue(); if (! empty($redirect)) { diff --git a/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php index ae712eddb..1c7095b82 100644 --- a/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for deleting host or service downtimes @@ -67,7 +66,7 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ @@ -75,7 +74,7 @@ class DeleteDowntimeCommandForm extends ObjectsCommandForm $delDowntime ->setObject($object) ->setDowntimeId($this->getElement('downtime_id')->getValue()); - $this->getTransport($request)->send($delDowntime); + $this->getTransport($this->request)->send($delDowntime); } $redirect = $this->getElement('redirect')->getValue(); if (! empty($redirect)) { diff --git a/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php b/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php index bf603a7b5..1dbf07840 100644 --- a/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php @@ -2,9 +2,9 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; -use Icinga\Module\Monitoring\Form\Command\CommandForm; +use Icinga\Module\Monitoring\Forms\Command\CommandForm; use Icinga\Module\Monitoring\Object\MonitoredObject; /** diff --git a/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php b/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php index 6ccd0633d..189261c94 100644 --- a/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\RemoveAcknowledgementCommand; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for removing host or service problem acknowledgements @@ -37,13 +36,13 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ $removeAck = new RemoveAcknowledgementCommand(); $removeAck->setObject($object); - $this->getTransport($request)->send($removeAck); + $this->getTransport($this->request)->send($removeAck); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php index 89d39716c..82a9b2e52 100644 --- a/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for scheduling host checks @@ -40,7 +39,7 @@ class ScheduleHostCheckCommandForm extends ScheduleServiceCheckCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\Host $object */ @@ -48,7 +47,7 @@ class ScheduleHostCheckCommandForm extends ScheduleServiceCheckCommandForm $check ->setObject($object) ->setOfAllServices($this->getElement('all_services')->isChecked()); - $this->scheduleCheck($check, $request); + $this->scheduleCheck($check, $this->request); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php index 25caa0f20..beb0793ef 100644 --- a/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\PropagateHostDowntimeCommand; use Icinga\Module\Monitoring\Command\Object\ScheduleHostDowntimeCommand; @@ -59,7 +59,7 @@ class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\Host $object */ @@ -79,12 +79,12 @@ class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm foreach ($object->services as $service) { $serviceDowntime = new ScheduleServiceDowntimeCommand(); $serviceDowntime->setObject($service); - $this->scheduleDowntime($serviceDowntime, $request); + $this->scheduleDowntime($serviceDowntime, $this->request); } } } $hostDowntime->setObject($object); - $this->scheduleDowntime($hostDowntime, $request); + $this->scheduleDowntime($hostDowntime, $this->request); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php index 304ccb435..faba7a769 100644 --- a/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php @@ -2,13 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use DateTime; use DateInterval; use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand; -use Icinga\Web\Form\Element\DateTimePicker; -use Icinga\Web\Form\Element\Note; use Icinga\Web\Notification; use Icinga\Web\Request; @@ -37,7 +35,8 @@ class ScheduleServiceCheckCommandForm extends ObjectsCommandForm $checkTime = new DateTime(); $checkTime->add(new DateInterval('PT1H')); $this->addElements(array( - new Note( + array( + 'note', 'command-info', array( 'value' => mt( @@ -47,7 +46,8 @@ class ScheduleServiceCheckCommandForm extends ObjectsCommandForm ) ) ), - new DateTimePicker( + array( + 'dateTimePicker', 'check_time', array( 'required' => true, @@ -90,13 +90,13 @@ class ScheduleServiceCheckCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\Service $object */ $check = new ScheduleServiceCheckCommand(); $check->setObject($object); - $this->scheduleCheck($check, $request); + $this->scheduleCheck($check, $this->request); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php index 58b391d14..18bbd0593 100644 --- a/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php @@ -2,14 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use DateTime; use DateInterval; use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand; -use Icinga\Web\Form\Element\DateTimePicker; -use Icinga\Web\Form\Element\Note; -use Icinga\Web\Form\Element\Number; use Icinga\Web\Notification; use Icinga\Web\Request; @@ -49,7 +46,8 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm $end = clone $start; $end->add(new DateInterval('PT1H')); $this->addElements(array( - new Note( + array( + 'note', 'command-info', array( 'value' => mt( @@ -76,7 +74,8 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm ) ) ), - new DateTimePicker( + array( + 'dateTimePicker', 'start', array( 'required' => true, @@ -85,7 +84,8 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm 'value' => $start ) ), - new DateTimePicker( + array( + 'dateTimePicker', 'end', array( 'required' => true, @@ -134,7 +134,8 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm ); if (isset($formData['type']) && $formData['type'] === self::FLEXIBLE) { $this->addElements(array( - new Number( + array( + 'number', 'hours', array( 'required' => true, @@ -143,7 +144,8 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm 'min' => -1 ) ), - new Number( + array( + 'number', 'minutes', array( 'required' => true, @@ -199,13 +201,13 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\Service $object */ $downtime = new ScheduleServiceDowntimeCommand(); $downtime->setObject($object); - $this->scheduleDowntime($downtime, $request); + $this->scheduleDowntime($downtime, $this->request); } Notification::success(mtp( 'monitoring', diff --git a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php index 8e5e5408c..c33527895 100644 --- a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Command\Object; +namespace Icinga\Module\Monitoring\Forms\Command\Object; use Icinga\Module\Monitoring\Command\Object\ToggleObjectFeatureCommand; use Icinga\Module\Monitoring\Object\MonitoredObject; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for enabling or disabling features of Icinga objects, i.e. hosts or services @@ -106,7 +105,7 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm * (non-PHPDoc) * @see \Icinga\Web\Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ @@ -117,7 +116,7 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm ->setFeature($feature) ->setObject($object) ->setEnabled($enabled); - $this->getTransport($request)->send($toggleFeature); + $this->getTransport($this->request)->send($toggleFeature); } } } diff --git a/modules/monitoring/application/forms/Config/BackendConfigForm.php b/modules/monitoring/application/forms/Config/BackendConfigForm.php index e18e882ca..1f31990cb 100644 --- a/modules/monitoring/application/forms/Config/BackendConfigForm.php +++ b/modules/monitoring/application/forms/Config/BackendConfigForm.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Config; +namespace Icinga\Module\Monitoring\Forms\Config; use InvalidArgumentException; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; @@ -135,9 +134,9 @@ class BackendConfigForm extends ConfigForm * * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { - $monitoringBackend = $request->getQuery('backend'); + $monitoringBackend = $this->request->getQuery('backend'); try { if ($monitoringBackend === null) { // create new backend $this->add($this->getValues()); @@ -165,9 +164,9 @@ class BackendConfigForm extends ConfigForm * * @throws ConfigurationError In case the backend name is missing in the request or is invalid */ - public function onRequest(Request $request) + public function onRequest() { - $monitoringBackend = $request->getQuery('backend'); + $monitoringBackend = $this->request->getQuery('backend'); if ($monitoringBackend !== null) { if ($monitoringBackend === '') { throw new ConfigurationError(mt('monitoring', 'Monitoring backend name missing')); diff --git a/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php b/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php index 029da3d35..ac1139268 100644 --- a/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php +++ b/modules/monitoring/application/forms/Config/Instance/LocalInstanceForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Config\Instance; +namespace Icinga\Module\Monitoring\Forms\Config\Instance; use Icinga\Web\Form; diff --git a/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php b/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php index fbd2ff14b..c93436ab2 100644 --- a/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php +++ b/modules/monitoring/application/forms/Config/Instance/RemoteInstanceForm.php @@ -2,10 +2,9 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Config\Instance; +namespace Icinga\Module\Monitoring\Forms\Config\Instance; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Number; class RemoteInstanceForm extends Form { @@ -36,10 +35,11 @@ class RemoteInstanceForm extends Form ) ) ), - new Number( + array( + 'number', + 'port', array( 'required' => true, - 'name' => 'port', 'label' => mt('monitoring', 'Port'), 'description' => mt('monitoring', 'SSH port to connect to on the remote Icinga instance'), 'value' => 22 diff --git a/modules/monitoring/application/forms/Config/InstanceConfigForm.php b/modules/monitoring/application/forms/Config/InstanceConfigForm.php index 2971cb663..302c0dec3 100644 --- a/modules/monitoring/application/forms/Config/InstanceConfigForm.php +++ b/modules/monitoring/application/forms/Config/InstanceConfigForm.php @@ -2,17 +2,16 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Config; +namespace Icinga\Module\Monitoring\Forms\Config; use InvalidArgumentException; use Icinga\Exception\ConfigurationError; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; use Icinga\Module\Monitoring\Command\Transport\LocalCommandFile; use Icinga\Module\Monitoring\Command\Transport\RemoteCommandFile; -use Icinga\Module\Monitoring\Form\Config\Instance\LocalInstanceForm; -use Icinga\Module\Monitoring\Form\Config\Instance\RemoteInstanceForm; +use Icinga\Module\Monitoring\Forms\Config\Instance\LocalInstanceForm; +use Icinga\Module\Monitoring\Forms\Config\Instance\RemoteInstanceForm; use Icinga\Web\Notification; -use Icinga\Web\Request; /** * Form for modifying/creating monitoring instances @@ -132,9 +131,9 @@ class InstanceConfigForm extends ConfigForm * @see Form::onRequest() For the method documentation. * @throws ConfigurationError In case the instance name is missing or invalid */ - public function onRequest(Request $request) + public function onRequest() { - $instanceName = $request->getQuery('instance'); + $instanceName = $this->request->getQuery('instance'); if ($instanceName !== null) { if (! $instanceName) { throw new ConfigurationError(mt('monitoring', 'Instance name missing')); @@ -153,9 +152,9 @@ class InstanceConfigForm extends ConfigForm * (non-PHPDoc) * @see Form::onSuccess() For the method documentation. */ - public function onSuccess(Request $request) + public function onSuccess() { - $instanceName = $request->getQuery('instance'); + $instanceName = $this->request->getQuery('instance'); try { if ($instanceName === null) { // create new instance $this->add($this->getValues()); diff --git a/modules/monitoring/application/forms/Config/SecurityConfigForm.php b/modules/monitoring/application/forms/Config/SecurityConfigForm.php index c7e8d7efb..de4055802 100644 --- a/modules/monitoring/application/forms/Config/SecurityConfigForm.php +++ b/modules/monitoring/application/forms/Config/SecurityConfigForm.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Config; +namespace Icinga\Module\Monitoring\Forms\Config; -use Icinga\Web\Request; use Icinga\Web\Notification; -use Icinga\Form\ConfigForm; +use Icinga\Forms\ConfigForm; /** * Form for modifying security relevant settings @@ -25,7 +24,7 @@ class SecurityConfigForm extends ConfigForm /** * @see Form::onSuccess() */ - public function onSuccess(Request $request) + public function onSuccess() { $this->config->security = $this->getValues(); @@ -39,7 +38,7 @@ class SecurityConfigForm extends ConfigForm /** * @see Form::onRequest() */ - public function onRequest(Request $request) + public function onRequest() { if (isset($this->config->security)) { $this->populate($this->config->security->toArray()); diff --git a/modules/monitoring/application/forms/Setup/BackendPage.php b/modules/monitoring/application/forms/Setup/BackendPage.php index 097d2586b..4bee056ca 100644 --- a/modules/monitoring/application/forms/Setup/BackendPage.php +++ b/modules/monitoring/application/forms/Setup/BackendPage.php @@ -2,10 +2,9 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Setup; +namespace Icinga\Module\Monitoring\Forms\Setup; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; use Icinga\Application\Platform; class BackendPage extends Form @@ -18,25 +17,23 @@ class BackendPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('monitoring', 'Monitoring Backend', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('monitoring', 'Monitoring Backend', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'monitoring', - 'Please configure below how Icinga Web 2 should retrieve monitoring information.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'monitoring', + 'Please configure below how Icinga Web 2 should retrieve monitoring information.' ) ) ); diff --git a/modules/monitoring/application/forms/Setup/IdoResourcePage.php b/modules/monitoring/application/forms/Setup/IdoResourcePage.php index 3e844027c..189d65fea 100644 --- a/modules/monitoring/application/forms/Setup/IdoResourcePage.php +++ b/modules/monitoring/application/forms/Setup/IdoResourcePage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Setup; +namespace Icinga\Module\Monitoring\Forms\Setup; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\Config\Resource\DbResourceForm; +use Icinga\Forms\Config\Resource\DbResourceForm; class IdoResourcePage extends Form { @@ -26,26 +25,24 @@ class IdoResourcePage extends Form ) ); $this->addElement( - new Note( - 'title', - array( - 'value' => mt('monitoring', 'Monitoring IDO Resource', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('monitoring', 'Monitoring IDO Resource', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'monitoring', - 'Please fill out the connection details below to access' - . ' the IDO database of your monitoring environment.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'monitoring', + 'Please fill out the connection details below to access' + . ' the IDO database of your monitoring environment.' ) ) ); diff --git a/modules/monitoring/application/forms/Setup/InstancePage.php b/modules/monitoring/application/forms/Setup/InstancePage.php index 7398dae1c..dccfd1d91 100644 --- a/modules/monitoring/application/forms/Setup/InstancePage.php +++ b/modules/monitoring/application/forms/Setup/InstancePage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Setup; +namespace Icinga\Module\Monitoring\Forms\Setup; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Module\Monitoring\Form\Config\InstanceConfigForm; +use Icinga\Module\Monitoring\Forms\Config\InstanceConfigForm; class InstancePage extends Form { @@ -18,25 +17,23 @@ class InstancePage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('monitoring', 'Monitoring Instance', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('monitoring', 'Monitoring Instance', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'monitoring', - 'Please define the settings specific to your monitoring instance below.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'monitoring', + 'Please define the settings specific to your monitoring instance below.' ) ) ); diff --git a/modules/monitoring/application/forms/Setup/LivestatusResourcePage.php b/modules/monitoring/application/forms/Setup/LivestatusResourcePage.php index 9ae36aebf..4faa17416 100644 --- a/modules/monitoring/application/forms/Setup/LivestatusResourcePage.php +++ b/modules/monitoring/application/forms/Setup/LivestatusResourcePage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Setup; +namespace Icinga\Module\Monitoring\Forms\Setup; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\Config\Resource\LivestatusResourceForm; +use Icinga\Forms\Config\Resource\LivestatusResourceForm; class LivestatusResourcePage extends Form { @@ -26,26 +25,24 @@ class LivestatusResourcePage extends Form ) ); $this->addElement( - new Note( - 'title', - array( - 'value' => mt('monitoring', 'Monitoring Livestatus Resource', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('monitoring', 'Monitoring Livestatus Resource', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'monitoring', - 'Please fill out the connection details below to access the Livestatus' - . ' socket interface for your monitoring environment.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'monitoring', + 'Please fill out the connection details below to access the Livestatus' + . ' socket interface for your monitoring environment.' ) ) ); diff --git a/modules/monitoring/application/forms/Setup/SecurityPage.php b/modules/monitoring/application/forms/Setup/SecurityPage.php index 70c90c8a3..0c7d3d1de 100644 --- a/modules/monitoring/application/forms/Setup/SecurityPage.php +++ b/modules/monitoring/application/forms/Setup/SecurityPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Setup; +namespace Icinga\Module\Monitoring\Forms\Setup; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Module\Monitoring\Form\Config\SecurityConfigForm; +use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm; class SecurityPage extends Form { @@ -18,25 +17,23 @@ class SecurityPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('monitoring', 'Monitoring Security', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('monitoring', 'Monitoring Security', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'monitoring', - 'To protect your monitoring environment against prying eyes please fill out the settings below.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'monitoring', + 'To protect your monitoring environment against prying eyes please fill out the settings below.' ) ) ); diff --git a/modules/monitoring/application/forms/Setup/WelcomePage.php b/modules/monitoring/application/forms/Setup/WelcomePage.php index be1f35364..d910e2e01 100644 --- a/modules/monitoring/application/forms/Setup/WelcomePage.php +++ b/modules/monitoring/application/forms/Setup/WelcomePage.php @@ -2,10 +2,9 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form\Setup; +namespace Icinga\Module\Monitoring\Forms\Setup; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; class WelcomePage extends Form { @@ -17,39 +16,36 @@ class WelcomePage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'welcome', - array( - 'value' => mt( - 'monitoring', - 'Welcome to the configuration of the monitoring module for Icinga Web 2!' - ), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'welcome', + array( + 'value' => mt( + 'monitoring', + 'Welcome to the configuration of the monitoring module for Icinga Web 2!' + ), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'core_hint', - array( - 'value' => mt('monitoring', 'This is the core module for Icinga Web 2.') - ) + 'note', + 'core_hint', + array( + 'value' => mt('monitoring', 'This is the core module for Icinga Web 2.') ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'monitoring', - 'It offers various status and reporting views with powerful filter capabilities that allow' - . ' you to keep track of the most important events in your monitoring environment.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'monitoring', + 'It offers various status and reporting views with powerful filter capabilities that allow' + . ' you to keep track of the most important events in your monitoring environment.' ) ) ); diff --git a/modules/monitoring/application/forms/StatehistoryForm.php b/modules/monitoring/application/forms/StatehistoryForm.php index 3008724c3..9fa1bdc26 100644 --- a/modules/monitoring/application/forms/StatehistoryForm.php +++ b/modules/monitoring/application/forms/StatehistoryForm.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Monitoring\Form; +namespace Icinga\Module\Monitoring\Forms; use \Zend_Form; use Icinga\Web\Form; diff --git a/modules/monitoring/application/views/helpers/PluginOutput.php b/modules/monitoring/application/views/helpers/PluginOutput.php index b4a6138ba..e3d88b26f 100644 --- a/modules/monitoring/application/views/helpers/PluginOutput.php +++ b/modules/monitoring/application/views/helpers/PluginOutput.php @@ -70,7 +70,10 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract protected function getPurifier() { if (self::$purifier === null) { - require_once 'IcingaVendor/htmlpurifier-4.6.0-lite/library/HTMLPurifier.auto.php'; + require_once 'HTMLPurifier/Bootstrap.php'; + require_once 'HTMLPurifier/HTMLPurifier.php'; + require_once 'HTMLPurifier/HTMLPurifier.autoload.php'; + $config = HTMLPurifier_Config::createDefault(); $config->set('Core.EscapeNonASCIICharacters', true); $config->set('HTML.Allowed', 'p,br,b,a[href],i,table,tr,td[colspan],div[class]'); diff --git a/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml b/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml new file mode 100644 index 000000000..c455d26ae --- /dev/null +++ b/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml @@ -0,0 +1,83 @@ +getRelativeUrl(); + +?> +

              compact ? ' data-base-target="col1"' : '' ?>> + qlink(sprintf($this->translate('%s hosts:'), $this->stats->hosts_total), $selfUrl); ?> + + stats->hosts_up): ?> + + qlink( + $this->stats->hosts_up, + $selfUrl, + array('host_state' => 0), + array('title' => $this->translate('Hosts with state UP')) + ) ?> + + + + stats->hosts_down_unhandled): ?> + + qlink( + $this->stats->hosts_down_unhandled, + $selfUrl, + array('host_state' => 1, 'host_unhandled' => 1), + array('title' => $this->translate('Unhandled hosts with state DOWN')) + ) ?> + + + stats->hosts_down_handled > 0): ?> + + qlink( + $this->stats->hosts_down_handled, + $selfUrl, + array('host_state' => 1, 'host_unhandled' => 0), + array('title' => $this->translate('Handled hosts with state DOWN')) + ) ?> + + + + stats->hosts_down): ?> + + + + stats->hosts_unreachable_unhandled): ?> + + qlink( + $this->stats->hosts_unreachable_unhandled, + $selfUrl, + array('host_state' => 2, 'host_unhandled' => 1), + array('title' => $this->translate('Unhandled hosts with state UNREACHABLE')) + ) ?> + + + stats->hosts_unreachable_handled > 0): ?> + + qlink( + $this->stats->hosts_unreachable_handled, + $selfUrl, + array('host_state' => 2, 'host_unhandled' => 0), + array('title' => $this->translate('Handled hosts with state UNREACHABLE')) + ) ?> + + + + stats->hosts_unreachable): ?> + + + + stats->hosts_pending): ?> + + qlink( + $this->stats->hosts_pending, + $selfUrl, + array('host_state' => 99), + array('title' => $this->translate('Hosts with state PENDING')) + ) ?> + + +

              diff --git a/modules/monitoring/application/views/scripts/list/hosts.phtml b/modules/monitoring/application/views/scripts/list/hosts.phtml index e0fa77d83..c2b932711 100644 --- a/modules/monitoring/application/views/scripts/list/hosts.phtml +++ b/modules/monitoring/application/views/scripts/list/hosts.phtml @@ -7,6 +7,7 @@ if ($this->compact): ?>
              tabs ?>
              + render('list/components/hostssummary.phtml') ?> translate('Sort by') ?> sortControl->render($this) ?> filterEditor): ?> filterPreview ?> diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php index a311feedc..29337e65f 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php @@ -18,6 +18,7 @@ class StatusSummaryQuery extends IdoQuery 'service_description' => 'so.name2', ), 'hoststatussummary' => array( + 'hosts_total' => 'SUM(CASE WHEN object_type = \'host\' THEN 1 ELSE 0 END)', 'hosts_up' => 'SUM(CASE WHEN object_type = \'host\' AND state = 0 THEN 1 ELSE 0 END)', 'hosts_up_not_checked' => 'SUM(CASE WHEN object_type = \'host\' AND state = 0 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)', 'hosts_pending' => 'SUM(CASE WHEN object_type = \'host\' AND state = 99 THEN 1 ELSE 0 END)', diff --git a/modules/monitoring/library/Monitoring/MonitoringWizard.php b/modules/monitoring/library/Monitoring/MonitoringWizard.php index 6ccd4b22b..0ac4c7f63 100644 --- a/modules/monitoring/library/Monitoring/MonitoringWizard.php +++ b/modules/monitoring/library/Monitoring/MonitoringWizard.php @@ -12,13 +12,13 @@ use Icinga\Module\Setup\SetupWizard; use Icinga\Module\Setup\Requirements; use Icinga\Module\Setup\Utils\MakeDirStep; use Icinga\Module\Setup\Utils\EnableModuleStep; -use Icinga\Module\Setup\Form\SummaryPage; -use Icinga\Module\Monitoring\Form\Setup\WelcomePage; -use Icinga\Module\Monitoring\Form\Setup\BackendPage; -use Icinga\Module\Monitoring\Form\Setup\InstancePage; -use Icinga\Module\Monitoring\Form\Setup\SecurityPage; -use Icinga\Module\Monitoring\Form\Setup\IdoResourcePage; -use Icinga\Module\Monitoring\Form\Setup\LivestatusResourcePage; +use Icinga\Module\Setup\Forms\SummaryPage; +use Icinga\Module\Monitoring\Forms\Setup\WelcomePage; +use Icinga\Module\Monitoring\Forms\Setup\BackendPage; +use Icinga\Module\Monitoring\Forms\Setup\InstancePage; +use Icinga\Module\Monitoring\Forms\Setup\SecurityPage; +use Icinga\Module\Monitoring\Forms\Setup\IdoResourcePage; +use Icinga\Module\Monitoring\Forms\Setup\LivestatusResourcePage; /** * Monitoring Module Setup Wizard diff --git a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php index ebfe590aa..4b4dd6e86 100644 --- a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php +++ b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php @@ -5,13 +5,13 @@ namespace Icinga\Module\Monitoring\Web\Controller; use Icinga\Module\Monitoring\Controller; -use Icinga\Module\Monitoring\Form\Command\Object\AcknowledgeProblemCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\CheckNowCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\DeleteCommentCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\DeleteDowntimeCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ObjectsCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\RemoveAcknowledgementCommandForm; -use Icinga\Module\Monitoring\Form\Command\Object\ToggleObjectFeaturesCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ObjectsCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm; +use Icinga\Module\Monitoring\Forms\Command\Object\ToggleObjectFeaturesCommandForm; use Icinga\Web\Hook; use Icinga\Web\Url; use Icinga\Web\Widget\Tabextension\DashboardAction; diff --git a/modules/setup/application/forms/AdminAccountPage.php b/modules/setup/application/forms/AdminAccountPage.php index 38101fe85..f338d9449 100644 --- a/modules/setup/application/forms/AdminAccountPage.php +++ b/modules/setup/application/forms/AdminAccountPage.php @@ -2,14 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Exception; use LogicException; use Icinga\Application\Config; use Icinga\Web\Form; use Icinga\Data\ResourceFactory; -use Icinga\Web\Form\Element\Note; use Icinga\Authentication\Backend\DbUserBackend; use Icinga\Authentication\Backend\LdapUserBackend; @@ -177,28 +176,26 @@ class AdminAccountPage extends Form } $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Administration', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Administration', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => tp( - 'Now it\'s time to configure your first administrative account for Icinga Web 2.' - . ' Please follow the instructions below:', - 'Now it\'s time to configure your first administrative account for Icinga Web 2.' - . ' Below are several options you can choose from. Select one and follow its instructions:', - count($choices) - ) + 'note', + 'description', + array( + 'value' => tp( + 'Now it\'s time to configure your first administrative account for Icinga Web 2.' + . ' Please follow the instructions below:', + 'Now it\'s time to configure your first administrative account for Icinga Web 2.' + . ' Below are several options you can choose from. Select one and follow its instructions:', + count($choices) ) ) ); diff --git a/modules/setup/application/forms/AuthBackendPage.php b/modules/setup/application/forms/AuthBackendPage.php index 89a060a06..0c58906be 100644 --- a/modules/setup/application/forms/AuthBackendPage.php +++ b/modules/setup/application/forms/AuthBackendPage.php @@ -2,14 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\Config\Authentication\DbBackendForm; -use Icinga\Form\Config\Authentication\LdapBackendForm; -use Icinga\Form\Config\Authentication\AutologinBackendForm; +use Icinga\Forms\Config\Authentication\DbBackendForm; +use Icinga\Forms\Config\Authentication\LdapBackendForm; +use Icinga\Forms\Config\Authentication\AutologinBackendForm; /** * Wizard page to define authentication backend specific details @@ -60,14 +59,13 @@ class AuthBackendPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Authentication Backend', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Authentication Backend', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); @@ -93,10 +91,9 @@ class AuthBackendPage extends Form } $this->addElement( - new Note( - 'description', - array('value' => $note) - ) + 'note', + 'description', + array('value' => $note) ); if (isset($formData['skip_validation']) && $formData['skip_validation']) { diff --git a/modules/setup/application/forms/AuthenticationPage.php b/modules/setup/application/forms/AuthenticationPage.php index 345625c94..4b0f9bee7 100644 --- a/modules/setup/application/forms/AuthenticationPage.php +++ b/modules/setup/application/forms/AuthenticationPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; use Icinga\Application\Platform; -use Icinga\Web\Form\Element\Note; /** * Wizard page to choose an authentication backend @@ -27,26 +26,24 @@ class AuthenticationPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Authentication', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Authentication', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'setup', - 'Please choose how you want to authenticate when accessing Icinga Web 2.' - . ' Configuring backend specific details follows in a later step.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'setup', + 'Please choose how you want to authenticate when accessing Icinga Web 2.' + . ' Configuring backend specific details follows in a later step.' ) ) ); diff --git a/modules/setup/application/forms/DatabaseCreationPage.php b/modules/setup/application/forms/DatabaseCreationPage.php index 556e20e28..ec4a77ee1 100644 --- a/modules/setup/application/forms/DatabaseCreationPage.php +++ b/modules/setup/application/forms/DatabaseCreationPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use PDOException; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; use Icinga\Module\Setup\Utils\DbTool; /** @@ -88,27 +87,25 @@ class DatabaseCreationPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Database Setup', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Database Setup', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'setup', - 'It seems that either the database you defined earlier does not yet exist and cannot be created' - . ' using the provided access credentials or the database does not have the required schema to ' - . 'be operated by Icinga Web 2. Please provide appropriate access credentials to solve this.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'setup', + 'It seems that either the database you defined earlier does not yet exist and cannot be created' + . ' using the provided access credentials or the database does not have the required schema to ' + . 'be operated by Icinga Web 2. Please provide appropriate access credentials to solve this.' ) ) ); diff --git a/modules/setup/application/forms/DbResourcePage.php b/modules/setup/application/forms/DbResourcePage.php index 326f9131d..4a6535324 100644 --- a/modules/setup/application/forms/DbResourcePage.php +++ b/modules/setup/application/forms/DbResourcePage.php @@ -2,12 +2,11 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use PDOException; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\Config\Resource\DbResourceForm; +use Icinga\Forms\Config\Resource\DbResourceForm; use Icinga\Module\Setup\Utils\DbTool; /** @@ -37,26 +36,24 @@ class DbResourcePage extends Form ) ); $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Database Resource', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Database Resource', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'setup', - 'Now please configure your database resource. Note that the database itself does not need to' - . ' exist at this time as it is going to be created once the wizard is about to be finished.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'setup', + 'Now please configure your database resource. Note that the database itself does not need to' + . ' exist at this time as it is going to be created once the wizard is about to be finished.' ) ) ); diff --git a/modules/setup/application/forms/GeneralConfigPage.php b/modules/setup/application/forms/GeneralConfigPage.php index 36f138b43..309c1784d 100644 --- a/modules/setup/application/forms/GeneralConfigPage.php +++ b/modules/setup/application/forms/GeneralConfigPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\Config\General\LoggingConfigForm; +use Icinga\Forms\Config\General\LoggingConfigForm; /** * Wizard page to define the application and logging configuration @@ -27,25 +26,23 @@ class GeneralConfigPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Application Configuration', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Application Configuration', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'setup', - 'Now please adjust all application and logging related configuration options to fit your needs.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'setup', + 'Now please adjust all application and logging related configuration options to fit your needs.' ) ) ); diff --git a/modules/setup/application/forms/LdapDiscoveryConfirmPage.php b/modules/setup/application/forms/LdapDiscoveryConfirmPage.php index bd312ca76..a192fac72 100644 --- a/modules/setup/application/forms/LdapDiscoveryConfirmPage.php +++ b/modules/setup/application/forms/LdapDiscoveryConfirmPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Application\Config; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; /** * Wizard page to define the connection details for a LDAP resource @@ -80,39 +79,36 @@ EOT; $html = str_replace('{user_class}', $backend['user_class'], $html); $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'LDAP Discovery Results', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'LDAP Discovery Results', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => sprintf( - mt('setup', 'The following directory service has been found on domain "%s":'), - $this->config['domain'] - ) + 'note', + 'description', + array( + 'value' => sprintf( + mt('setup', 'The following directory service has been found on domain "%s":'), + $this->config['domain'] ) ) ); $this->addElement( - new Note( - 'suggestion', - array( - 'value' => $html, - 'decorators' => array( - 'ViewHelper', - array( - 'HtmlTag', array('tag' => 'div') - ) + 'note', + 'suggestion', + array( + 'value' => $html, + 'decorators' => array( + 'ViewHelper', + array( + 'HtmlTag', array('tag' => 'div') ) ) ) diff --git a/modules/setup/application/forms/LdapDiscoveryPage.php b/modules/setup/application/forms/LdapDiscoveryPage.php index 7fe799d19..ec41842d0 100644 --- a/modules/setup/application/forms/LdapDiscoveryPage.php +++ b/modules/setup/application/forms/LdapDiscoveryPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\LdapDiscoveryForm; +use Icinga\Forms\LdapDiscoveryForm; /** * Wizard page to define the connection details for a LDAP resource @@ -32,26 +31,24 @@ class LdapDiscoveryPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'LDAP Discovery', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'LDAP Discovery', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'setup', - 'You can use this page to discover LDAP or ActiveDirectory servers ' . - ' for authentication. If you don\' want to execute a discovery, just skip this step.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'setup', + 'You can use this page to discover LDAP or ActiveDirectory servers ' . + ' for authentication. If you don\' want to execute a discovery, just skip this step.' ) ) ); diff --git a/modules/setup/application/forms/LdapResourcePage.php b/modules/setup/application/forms/LdapResourcePage.php index 9f08f75e0..49bed69c3 100644 --- a/modules/setup/application/forms/LdapResourcePage.php +++ b/modules/setup/application/forms/LdapResourcePage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; -use Icinga\Web\Form\Element\Note; -use Icinga\Form\Config\Resource\LdapResourceForm; +use Icinga\Forms\Config\Resource\LdapResourceForm; /** * Wizard page to define the connection details for a LDAP resource @@ -35,26 +34,24 @@ class LdapResourcePage extends Form ) ); $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'LDAP Resource', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'LDAP Resource', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt( - 'setup', - 'Now please configure your AD/LDAP resource. This will later ' - . 'be used to authenticate users logging in to Icinga Web 2.' - ) + 'note', + 'description', + array( + 'value' => mt( + 'setup', + 'Now please configure your AD/LDAP resource. This will later ' + . 'be used to authenticate users logging in to Icinga Web 2.' ) ) ); diff --git a/modules/setup/application/forms/ModulePage.php b/modules/setup/application/forms/ModulePage.php index e1e951bcb..5e8927dbc 100644 --- a/modules/setup/application/forms/ModulePage.php +++ b/modules/setup/application/forms/ModulePage.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use InvalidArgumentException; use Icinga\Application\Icinga; @@ -45,7 +45,8 @@ class ModulePage extends Form public function handleRequest(Request $request = null) { - if ($this->wasSent($this->getRequestData($request))) { + $isPost = strtolower($request->getMethod()) === 'post'; + if ($isPost && $this->wasSent($request->getPost())) { if (($newModule = $request->getPost('module')) !== null) { $this->setCurrentModule($newModule); $this->getResponse()->redirectAndExit($this->getRedirectUrl()); @@ -58,7 +59,7 @@ class ModulePage extends Form $wizardPage = $wizard->getCurrentPage(); $wizard->handleRequest($request); - if ($wizard->isFinished() && $wizardPage->wasSent($wizardPage->getRequestData($request))) { + if ($isPost && $wizard->isFinished() && $wizardPage->wasSent($request->getPost())) { $wizards = $this->getWizards(); $newModule = null; diff --git a/modules/setup/application/forms/PreferencesPage.php b/modules/setup/application/forms/PreferencesPage.php index 276bbbff9..9a6f31448 100644 --- a/modules/setup/application/forms/PreferencesPage.php +++ b/modules/setup/application/forms/PreferencesPage.php @@ -2,11 +2,10 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; use Icinga\Application\Platform; -use Icinga\Web\Form\Element\Note; /** * Wizard page to choose a preference backend @@ -45,23 +44,21 @@ class PreferencesPage extends Form public function createElements(array $formData) { $this->addElement( - new Note( - 'title', - array( - 'value' => mt('setup', 'Preferences', 'setup.page.title'), - 'decorators' => array( - 'ViewHelper', - array('HtmlTag', array('tag' => 'h2')) - ) + 'note', + 'title', + array( + 'value' => mt('setup', 'Preferences', 'setup.page.title'), + 'decorators' => array( + 'ViewHelper', + array('HtmlTag', array('tag' => 'h2')) ) ) ); $this->addElement( - new Note( - 'description', - array( - 'value' => mt('setup', 'Please choose how Icinga Web 2 should store user preferences.') - ) + 'note', + 'description', + array( + 'value' => mt('setup', 'Please choose how Icinga Web 2 should store user preferences.') ) ); diff --git a/modules/setup/application/forms/RequirementsPage.php b/modules/setup/application/forms/RequirementsPage.php index 076c2eba0..ec4405459 100644 --- a/modules/setup/application/forms/RequirementsPage.php +++ b/modules/setup/application/forms/RequirementsPage.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; use Icinga\Module\Setup\Requirements; diff --git a/modules/setup/application/forms/SummaryPage.php b/modules/setup/application/forms/SummaryPage.php index 103a7aadf..14ad93c56 100644 --- a/modules/setup/application/forms/SummaryPage.php +++ b/modules/setup/application/forms/SummaryPage.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Web\Form; diff --git a/modules/setup/application/forms/WelcomePage.php b/modules/setup/application/forms/WelcomePage.php index 8f32280eb..5da607683 100644 --- a/modules/setup/application/forms/WelcomePage.php +++ b/modules/setup/application/forms/WelcomePage.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Icinga\Module\Setup\Form; +namespace Icinga\Module\Setup\Forms; use Icinga\Application\Icinga; use Icinga\Web\Form; diff --git a/modules/setup/library/Setup/WebWizard.php b/modules/setup/library/Setup/WebWizard.php index 469f25e02..46dd7624f 100644 --- a/modules/setup/library/Setup/WebWizard.php +++ b/modules/setup/library/Setup/WebWizard.php @@ -10,20 +10,20 @@ use Icinga\Web\Wizard; use Icinga\Web\Request; use Icinga\Application\Config; use Icinga\Application\Platform; -use Icinga\Module\Setup\Form\ModulePage; -use Icinga\Module\Setup\Form\WelcomePage; -use Icinga\Module\Setup\Form\SummaryPage; -use Icinga\Module\Setup\Form\DbResourcePage; -use Icinga\Module\Setup\Form\PreferencesPage; -use Icinga\Module\Setup\Form\AuthBackendPage; -use Icinga\Module\Setup\Form\AdminAccountPage; -use Icinga\Module\Setup\Form\LdapDiscoveryPage; -use Icinga\Module\Setup\Form\LdapDiscoveryConfirmPage; -use Icinga\Module\Setup\Form\LdapResourcePage; -use Icinga\Module\Setup\Form\RequirementsPage; -use Icinga\Module\Setup\Form\GeneralConfigPage; -use Icinga\Module\Setup\Form\AuthenticationPage; -use Icinga\Module\Setup\Form\DatabaseCreationPage; +use Icinga\Module\Setup\Forms\ModulePage; +use Icinga\Module\Setup\Forms\WelcomePage; +use Icinga\Module\Setup\Forms\SummaryPage; +use Icinga\Module\Setup\Forms\DbResourcePage; +use Icinga\Module\Setup\Forms\PreferencesPage; +use Icinga\Module\Setup\Forms\AuthBackendPage; +use Icinga\Module\Setup\Forms\AdminAccountPage; +use Icinga\Module\Setup\Forms\LdapDiscoveryPage; +use Icinga\Module\Setup\Forms\LdapDiscoveryConfirmPage; +use Icinga\Module\Setup\Forms\LdapResourcePage; +use Icinga\Module\Setup\Forms\RequirementsPage; +use Icinga\Module\Setup\Forms\GeneralConfigPage; +use Icinga\Module\Setup\Forms\AuthenticationPage; +use Icinga\Module\Setup\Forms\DatabaseCreationPage; use Icinga\Module\Setup\Steps\DatabaseStep; use Icinga\Module\Setup\Steps\GeneralConfigStep; use Icinga\Module\Setup\Steps\ResourceStep; diff --git a/modules/test/module.info b/modules/test/module.info new file mode 100644 index 000000000..646315156 --- /dev/null +++ b/modules/test/module.info @@ -0,0 +1,5 @@ +Module: test +Version: 2.0.0~alpha4 +Description: Translation module + This module allows developers to run (unit) tests against Icinga Web 2 and + any of it's modules. Usually you do not need to enable this. diff --git a/modules/translation/module.info b/modules/translation/module.info new file mode 100644 index 000000000..9934ec931 --- /dev/null +++ b/modules/translation/module.info @@ -0,0 +1,7 @@ +Module: translation +Version: 2.0.0~alpha4 +Description: Translation module + This module allows developers and translators to translate Icinga Web 2 and + it's modules for multiple languages. You do not need this module to run an + internationalized web frontend. This is only for people who want to contribute + translations or translate just their own moduls. diff --git a/packages/rpm/README.md b/packages/rpm/README.md index 293682a76..6daf41a63 100644 --- a/packages/rpm/README.md +++ b/packages/rpm/README.md @@ -19,21 +19,32 @@ provided by Icinga (2) Core. setenforce 0 -## Webinterface Login +## Webserver Configuration + +Can be generated using the following local icingacli command: + + /usr/share/icingaweb2/bin/icingacli setup config webserver apache + +Pipe the output into `/etc/httpd/conf.d/icingaweb2.conf` or similar, +if not already existing. + +## Setup Wizard + +Navigate to `/icingaweb/setup` and follow the on-screen instructions. -The default credentials using the internal MySQL database are -`icingaadmin:icinga` ## Support Please use one of the listed support channels at https://support.icinga.org -## Internal DB Setup +## Manual Setup + +### Internal DB Setup Decide whether to use MySQL or PostgreSQL. -### MySQL +#### MySQL mysql -u root -p CREATE USER `icingaweb`@`localhost` IDENTIFIED BY 'icingaweb'; @@ -42,9 +53,9 @@ Decide whether to use MySQL or PostgreSQL. FLUSH PRIVILEGES; quit - mysql -u root -p icingaweb < /usr/share/doc/icingaweb2*/schema/mysql.sql + mysql -u root -p icingaweb < /usr/share/doc/icingaweb2*/schema/mysql.schema..sql -### PostgreSQL +#### PostgreSQL sudo su postgres psql @@ -61,16 +72,16 @@ in `/var/lib/pgsql/data/pg_hba.conf` and restart the PostgreSQL server. Now install the `icingaweb` schema - bash$ psql -U icingaweb -a -f /usr/share/doc/icingaweb2*/schema/pgsql.sql + bash$ psql -U icingaweb -a -f /usr/share/doc/icingaweb2*/schema/pgsql.schema.sql -## Configuration +### Configuration -### Module Configuration +#### Module Configuration The monitoring module is enabled by default. -### Backend configuration +#### Backend configuration `/etc/icingaweb2/resources.ini` contains the database backend information. By default the Icinga 2 DB IDO is used by the monitoring module in @@ -80,8 +91,20 @@ The external command pipe is required for sending commands and configured for Icinga 2 in `/etc/icingaweb2/modules/monitoring/instances.ini` -### Authentication configuration +#### Authentication configuration The `/etc/icingaweb2/authentication.ini` file uses the internal database as default. This requires the database being installed properly before allowing users to login via web console. + +#### Default User + +When not using the default setup wizard, you can generate a secure password hash with openssl +and insert that manually like so: + + openssl passwd -1 "yoursecurepassword" + + mysql -uicingaweb -p icingaweb + + mysql> INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, '$yoursecurepassword_hash'); + diff --git a/public/js/icinga/behavior/navigation.js b/public/js/icinga/behavior/navigation.js index 615e5ac08..fde043c01 100644 --- a/public/js/icinga/behavior/navigation.js +++ b/public/js/icinga/behavior/navigation.js @@ -26,7 +26,7 @@ var el = evt.target; if (activeMenuId) { // restore old menu state - $('[role="navigation"] li.active', el).removeClass('active'); + $('#menu li.active', el).removeClass('active'); var $selectedMenu = $('#' + activeMenuId).addClass('active'); var $outerMenu = $selectedMenu.parent().closest('li'); if ($outerMenu.size()) { @@ -34,7 +34,7 @@ } } else { // store menu state - var $menus = $('[role="navigation"] li.active', el); + var $menus = $('#menu li.active', el); if ($menus.size()) { activeMenuId = $menus[0].id; $menus.find('li.active').first().each(function () { diff --git a/public/js/icinga/ui.js b/public/js/icinga/ui.js index ed7cda584..3c03bdcf5 100644 --- a/public/js/icinga/ui.js +++ b/public/js/icinga/ui.js @@ -480,6 +480,11 @@ provideSelectionCount: function() { var $count = $('.selection-info-count'); + if (typeof selectionData === 'undefined' || selectionData === null) { + $count.text(0); + return; + } + if (typeof selectionData === 'string') { $count.text(1); } else if (selectionData.length > 1) { diff --git a/test/php/application/forms/Config/Authentication/DbBackendFormTest.php b/test/php/application/forms/Config/Authentication/DbBackendFormTest.php index 60d5a0506..3157f4e0e 100644 --- a/test/php/application/forms/Config/Authentication/DbBackendFormTest.php +++ b/test/php/application/forms/Config/Authentication/DbBackendFormTest.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Tests\Icinga\Form\Config\Authentication; +namespace Tests\Icinga\Forms\Config\Authentication; // Necessary as some of these tests disable phpunit's preservation // of the global state (e.g. autoloaders are in the global state) @@ -11,7 +11,7 @@ require_once realpath(dirname(__FILE__) . '/../../../../bootstrap.php'); use Mockery; use Icinga\Application\Config; use Icinga\Test\BaseTestCase; -use Icinga\Form\Config\Authentication\DbBackendForm; +use Icinga\Forms\Config\Authentication\DbBackendForm; class DbBackendFormTest extends BaseTestCase { diff --git a/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php b/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php index ac7834489..6126cbb9c 100644 --- a/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php +++ b/test/php/application/forms/Config/Authentication/LdapBackendFormTest.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Tests\Icinga\Form\Config\Authentication; +namespace Tests\Icinga\Forms\Config\Authentication; // Necessary as some of these tests disable phpunit's preservation // of the global state (e.g. autoloaders are in the global state) @@ -11,7 +11,7 @@ require_once realpath(dirname(__FILE__) . '/../../../../bootstrap.php'); use Mockery; use Icinga\Test\BaseTestCase; use Icinga\Application\Config; -use Icinga\Form\Config\Authentication\LdapBackendForm; +use Icinga\Forms\Config\Authentication\LdapBackendForm; use Icinga\Exception\AuthenticationException; class LdapBackendFormTest extends BaseTestCase diff --git a/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php b/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php index c79b12fd9..936bf9366 100644 --- a/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php +++ b/test/php/application/forms/Config/AuthenticationBackendReorderFormTest.php @@ -2,12 +2,12 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Tests\Icinga\Form\Config; +namespace Tests\Icinga\Forms\Config; use Icinga\Test\BaseTestCase; use Icinga\Application\Config; -use Icinga\Form\Config\AuthenticationBackendConfigForm; -use Icinga\Form\Config\AuthenticationBackendReorderForm; +use Icinga\Forms\Config\AuthenticationBackendConfigForm; +use Icinga\Forms\Config\AuthenticationBackendReorderForm; class AuthenticationBackendConfigFormWithoutSave extends AuthenticationBackendConfigForm { diff --git a/test/php/application/forms/Config/Resource/DbResourceFormTest.php b/test/php/application/forms/Config/Resource/DbResourceFormTest.php index 1ee39a4fa..d6e7fc447 100644 --- a/test/php/application/forms/Config/Resource/DbResourceFormTest.php +++ b/test/php/application/forms/Config/Resource/DbResourceFormTest.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Tests\Icinga\Form\Config\Resource; +namespace Tests\Icinga\Forms\Config\Resource; // Necessary as some of these tests disable phpunit's preservation // of the global state (e.g. autoloaders are in the global state) @@ -10,7 +10,7 @@ require_once realpath(dirname(__FILE__) . '/../../../../bootstrap.php'); use Mockery; use Icinga\Test\BaseTestCase; -use Icinga\Form\Config\Resource\DbResourceForm; +use Icinga\Forms\Config\Resource\DbResourceForm; class DbResourceFormTest extends BaseTestCase { diff --git a/test/php/application/forms/Config/Resource/LdapResourceFormTest.php b/test/php/application/forms/Config/Resource/LdapResourceFormTest.php index 66f274b30..211b9bb02 100644 --- a/test/php/application/forms/Config/Resource/LdapResourceFormTest.php +++ b/test/php/application/forms/Config/Resource/LdapResourceFormTest.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Tests\Icinga\Form\Config\Resource; +namespace Tests\Icinga\Forms\Config\Resource; // Necessary as some of these tests disable phpunit's preservation // of the global state (e.g. autoloaders are in the global state) @@ -10,7 +10,7 @@ require_once realpath(dirname(__FILE__) . '/../../../../bootstrap.php'); use Mockery; use Icinga\Test\BaseTestCase; -use Icinga\Form\Config\Resource\LdapResourceForm; +use Icinga\Forms\Config\Resource\LdapResourceForm; class LdapResourceFormTest extends BaseTestCase { diff --git a/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php b/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php index 556a0fd27..f6fae6b08 100644 --- a/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php +++ b/test/php/application/forms/Config/Resource/LivestatusResourceFormTest.php @@ -2,7 +2,7 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -namespace Tests\Icinga\Form\Config\Resource; +namespace Tests\Icinga\Forms\Config\Resource; // Necessary as some of these tests disable phpunit's preservation // of the global state (e.g. autoloaders are in the global state) @@ -10,7 +10,7 @@ require_once realpath(dirname(__FILE__) . '/../../../../bootstrap.php'); use Mockery; use Icinga\Test\BaseTestCase; -use Icinga\Form\Config\Resource\LivestatusResourceForm; +use Icinga\Forms\Config\Resource\LivestatusResourceForm; class LivestatusResourceFormTest extends BaseTestCase { diff --git a/test/php/bootstrap.php b/test/php/bootstrap.php index fd74e49d6..a692d2be4 100644 --- a/test/php/bootstrap.php +++ b/test/php/bootstrap.php @@ -29,7 +29,7 @@ require_once($libraryPath . '/Icinga/Application/Loader.php'); $loader = new Icinga\Application\Loader(); $loader->registerNamespace('Tests', $testLibraryPath); $loader->registerNamespace('Icinga', $libraryPath . '/Icinga'); -$loader->registerNamespace('Icinga\\Form', $applicationPath . '/forms'); +$loader->registerNamespace('Icinga\\Forms', $applicationPath . '/forms'); $modules = scandir($modulePath); foreach ($modules as $module) { @@ -51,7 +51,7 @@ foreach ($modules as $module) { $moduleFormPath = $modulePath . '/' . $module . '/application/forms'; if (is_dir($moduleFormPath)) { - $loader->registerNamespace($moduleNamespace . '\\Form', $moduleFormPath); + $loader->registerNamespace($moduleNamespace . '\\Forms', $moduleFormPath); } } diff --git a/test/php/library/Icinga/Web/FormTest.php b/test/php/library/Icinga/Web/FormTest.php index a2fc9c8b1..de880f070 100644 --- a/test/php/library/Icinga/Web/FormTest.php +++ b/test/php/library/Icinga/Web/FormTest.php @@ -11,7 +11,7 @@ use Icinga\Test\BaseTestCase; class SuccessfulForm extends Form { - public function onSuccess(Request $request) + public function onSuccess() { return true; } @@ -238,24 +238,6 @@ class FormTest extends BaseTestCase ); } - public function testWhetherGetRequestDataOnlyReturnsFormRelevantData() - { - $form = new Form(); - $form->setMethod('POST'); - - $expectedResult = array('expected_key' => 'expected_value'); - $request = $this->getRequestMock(); - $request->shouldReceive('getMethod')->andReturn('POST') - ->shouldReceive('isPost')->andReturn(true) - ->shouldReceive('getPost')->andReturn($expectedResult); - - $this->assertEquals( - $expectedResult, - $form->getRequestData($request), - 'Form::getRequestData() does not (only) return form relevant data' - ); - } - /** * @expectedException LogicException */ @@ -273,7 +255,7 @@ class FormTest extends BaseTestCase { $request = new Request(); $form = new Form(array( - 'onSuccess' => function ($req) { $req->setParam('test', 'tset'); return false; } + 'onSuccess' => function ($form) { $form->getRequest()->setParam('test', 'tset'); return false; } )); $form->setTokenDisabled(); $form->setUidDisabled();